Return to smtp-multi.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / docs / examples |
1.1 ! misho 1: /*************************************************************************** ! 2: * _ _ ____ _ ! 3: * Project ___| | | | _ \| | ! 4: * / __| | | | |_) | | ! 5: * | (__| |_| | _ <| |___ ! 6: * \___|\___/|_| \_\_____| ! 7: * ! 8: * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. ! 9: * ! 10: * This software is licensed as described in the file COPYING, which ! 11: * you should have received as part of this distribution. The terms ! 12: * are also available at https://curl.haxx.se/docs/copyright.html. ! 13: * ! 14: * You may opt to use, copy, modify, merge, publish, distribute and/or sell ! 15: * copies of the Software, and permit persons to whom the Software is ! 16: * furnished to do so, under the terms of the COPYING file. ! 17: * ! 18: * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY ! 19: * KIND, either express or implied. ! 20: * ! 21: ***************************************************************************/ ! 22: ! 23: /* <DESC> ! 24: * SMTP example using the multi interface ! 25: * </DESC> ! 26: */ ! 27: ! 28: #include <string.h> ! 29: #include <curl/curl.h> ! 30: ! 31: /* This is an example showing how to send mail using libcurl's SMTP ! 32: * capabilities. It builds on the smtp-mail.c example to demonstrate how to use ! 33: * libcurl's multi interface. ! 34: * ! 35: * Note that this example requires libcurl 7.20.0 or above. ! 36: */ ! 37: ! 38: #define FROM "<sender@example.com>" ! 39: #define TO "<recipient@example.com>" ! 40: #define CC "<info@example.com>" ! 41: ! 42: #define MULTI_PERFORM_HANG_TIMEOUT 60 * 1000 ! 43: ! 44: static const char *payload_text[] = { ! 45: "Date: Mon, 29 Nov 2010 21:54:29 +1100\r\n", ! 46: "To: " TO "\r\n", ! 47: "From: " FROM " (Example User)\r\n", ! 48: "Cc: " CC " (Another example User)\r\n", ! 49: "Message-ID: <dcd7cb36-11db-487a-9f3a-e652a9458efd@" ! 50: "rfcpedant.example.org>\r\n", ! 51: "Subject: SMTP multi example message\r\n", ! 52: "\r\n", /* empty line to divide headers from body, see RFC5322 */ ! 53: "The body of the message starts here.\r\n", ! 54: "\r\n", ! 55: "It could be a lot of lines, could be MIME encoded, whatever.\r\n", ! 56: "Check RFC5322.\r\n", ! 57: NULL ! 58: }; ! 59: ! 60: struct upload_status { ! 61: int lines_read; ! 62: }; ! 63: ! 64: static size_t payload_source(void *ptr, size_t size, size_t nmemb, void *userp) ! 65: { ! 66: struct upload_status *upload_ctx = (struct upload_status *)userp; ! 67: const char *data; ! 68: ! 69: if((size == 0) || (nmemb == 0) || ((size*nmemb) < 1)) { ! 70: return 0; ! 71: } ! 72: ! 73: data = payload_text[upload_ctx->lines_read]; ! 74: ! 75: if(data) { ! 76: size_t len = strlen(data); ! 77: memcpy(ptr, data, len); ! 78: upload_ctx->lines_read++; ! 79: ! 80: return len; ! 81: } ! 82: ! 83: return 0; ! 84: } ! 85: ! 86: static struct timeval tvnow(void) ! 87: { ! 88: struct timeval now; ! 89: ! 90: /* time() returns the value of time in seconds since the epoch */ ! 91: now.tv_sec = (long)time(NULL); ! 92: now.tv_usec = 0; ! 93: ! 94: return now; ! 95: } ! 96: ! 97: static long tvdiff(struct timeval newer, struct timeval older) ! 98: { ! 99: return (newer.tv_sec - older.tv_sec) * 1000 + ! 100: (newer.tv_usec - older.tv_usec) / 1000; ! 101: } ! 102: ! 103: int main(void) ! 104: { ! 105: CURL *curl; ! 106: CURLM *mcurl; ! 107: int still_running = 1; ! 108: struct timeval mp_start; ! 109: struct curl_slist *recipients = NULL; ! 110: struct upload_status upload_ctx; ! 111: ! 112: upload_ctx.lines_read = 0; ! 113: ! 114: curl_global_init(CURL_GLOBAL_DEFAULT); ! 115: ! 116: curl = curl_easy_init(); ! 117: if(!curl) ! 118: return 1; ! 119: ! 120: mcurl = curl_multi_init(); ! 121: if(!mcurl) ! 122: return 2; ! 123: ! 124: /* This is the URL for your mailserver */ ! 125: curl_easy_setopt(curl, CURLOPT_URL, "smtp://mail.example.com"); ! 126: ! 127: /* Note that this option isn't strictly required, omitting it will result in ! 128: * libcurl sending the MAIL FROM command with empty sender data. All ! 129: * autoresponses should have an empty reverse-path, and should be directed ! 130: * to the address in the reverse-path which triggered them. Otherwise, they ! 131: * could cause an endless loop. See RFC 5321 Section 4.5.5 for more details. ! 132: */ ! 133: curl_easy_setopt(curl, CURLOPT_MAIL_FROM, FROM); ! 134: ! 135: /* Add two recipients, in this particular case they correspond to the ! 136: * To: and Cc: addressees in the header, but they could be any kind of ! 137: * recipient. */ ! 138: recipients = curl_slist_append(recipients, TO); ! 139: recipients = curl_slist_append(recipients, CC); ! 140: curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients); ! 141: ! 142: /* We're using a callback function to specify the payload (the headers and ! 143: * body of the message). You could just use the CURLOPT_READDATA option to ! 144: * specify a FILE pointer to read from. */ ! 145: curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_source); ! 146: curl_easy_setopt(curl, CURLOPT_READDATA, &upload_ctx); ! 147: curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); ! 148: ! 149: /* Tell the multi stack about our easy handle */ ! 150: curl_multi_add_handle(mcurl, curl); ! 151: ! 152: /* Record the start time which we can use later */ ! 153: mp_start = tvnow(); ! 154: ! 155: /* We start some action by calling perform right away */ ! 156: curl_multi_perform(mcurl, &still_running); ! 157: ! 158: while(still_running) { ! 159: struct timeval timeout; ! 160: fd_set fdread; ! 161: fd_set fdwrite; ! 162: fd_set fdexcep; ! 163: int maxfd = -1; ! 164: int rc; ! 165: CURLMcode mc; /* curl_multi_fdset() return code */ ! 166: ! 167: long curl_timeo = -1; ! 168: ! 169: /* Initialise the file descriptors */ ! 170: FD_ZERO(&fdread); ! 171: FD_ZERO(&fdwrite); ! 172: FD_ZERO(&fdexcep); ! 173: ! 174: /* Set a suitable timeout to play around with */ ! 175: timeout.tv_sec = 1; ! 176: timeout.tv_usec = 0; ! 177: ! 178: curl_multi_timeout(mcurl, &curl_timeo); ! 179: if(curl_timeo >= 0) { ! 180: timeout.tv_sec = curl_timeo / 1000; ! 181: if(timeout.tv_sec > 1) ! 182: timeout.tv_sec = 1; ! 183: else ! 184: timeout.tv_usec = (curl_timeo % 1000) * 1000; ! 185: } ! 186: ! 187: /* get file descriptors from the transfers */ ! 188: mc = curl_multi_fdset(mcurl, &fdread, &fdwrite, &fdexcep, &maxfd); ! 189: ! 190: if(mc != CURLM_OK) { ! 191: fprintf(stderr, "curl_multi_fdset() failed, code %d.\n", mc); ! 192: break; ! 193: } ! 194: ! 195: /* On success the value of maxfd is guaranteed to be >= -1. We call ! 196: select(maxfd + 1, ...); specially in case of (maxfd == -1) there are ! 197: no fds ready yet so we call select(0, ...) --or Sleep() on Windows-- ! 198: to sleep 100ms, which is the minimum suggested value in the ! 199: curl_multi_fdset() doc. */ ! 200: ! 201: if(maxfd == -1) { ! 202: #ifdef _WIN32 ! 203: Sleep(100); ! 204: rc = 0; ! 205: #else ! 206: /* Portable sleep for platforms other than Windows. */ ! 207: struct timeval wait = { 0, 100 * 1000 }; /* 100ms */ ! 208: rc = select(0, NULL, NULL, NULL, &wait); ! 209: #endif ! 210: } ! 211: else { ! 212: /* Note that on some platforms 'timeout' may be modified by select(). ! 213: If you need access to the original value save a copy beforehand. */ ! 214: rc = select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout); ! 215: } ! 216: ! 217: if(tvdiff(tvnow(), mp_start) > MULTI_PERFORM_HANG_TIMEOUT) { ! 218: fprintf(stderr, ! 219: "ABORTING: Since it seems that we would have run forever.\n"); ! 220: break; ! 221: } ! 222: ! 223: switch(rc) { ! 224: case -1: /* select error */ ! 225: break; ! 226: case 0: /* timeout */ ! 227: default: /* action */ ! 228: curl_multi_perform(mcurl, &still_running); ! 229: break; ! 230: } ! 231: } ! 232: ! 233: /* Free the list of recipients */ ! 234: curl_slist_free_all(recipients); ! 235: ! 236: /* Always cleanup */ ! 237: curl_multi_remove_handle(mcurl, curl); ! 238: curl_multi_cleanup(mcurl); ! 239: curl_easy_cleanup(curl); ! 240: curl_global_cleanup(); ! 241: ! 242: return 0; ! 243: }