00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <string.h>
00029 #include <curl/curl.h>
00030
00031
00032
00033
00034
00035
00036
00037
00038 #define FROM "<sender@example.com>"
00039 #define TO "<recipient@example.com>"
00040 #define CC "<info@example.com>"
00041
00042 #define MULTI_PERFORM_HANG_TIMEOUT 60 * 1000
00043
00044 static const char *payload_text[] = {
00045 "Date: Mon, 29 Nov 2010 21:54:29 +1100\r\n",
00046 "To: " TO "\r\n",
00047 "From: " FROM "(Example User)\r\n",
00048 "Cc: " CC "(Another example User)\r\n",
00049 "Message-ID: <dcd7cb36-11db-487a-9f3a-e652a9458efd@"
00050 "rfcpedant.example.org>\r\n",
00051 "Subject: SMTP multi example message\r\n",
00052 "\r\n",
00053 "The body of the message starts here.\r\n",
00054 "\r\n",
00055 "It could be a lot of lines, could be MIME encoded, whatever.\r\n",
00056 "Check RFC5322.\r\n",
00057 NULL
00058 };
00059
00060 struct upload_status {
00061 int lines_read;
00062 };
00063
00064 static size_t payload_source(void *ptr, size_t size, size_t nmemb, void *userp)
00065 {
00066 struct upload_status *upload_ctx = (struct upload_status *)userp;
00067 const char *data;
00068
00069 if((size == 0) || (nmemb == 0) || ((size*nmemb) < 1)) {
00070 return 0;
00071 }
00072
00073 data = payload_text[upload_ctx->lines_read];
00074
00075 if(data) {
00076 size_t len = strlen(data);
00077 memcpy(ptr, data, len);
00078 upload_ctx->lines_read++;
00079
00080 return len;
00081 }
00082
00083 return 0;
00084 }
00085
00086 static struct timeval tvnow(void)
00087 {
00088 struct timeval now;
00089
00090
00091 now.tv_sec = (long)time(NULL);
00092 now.tv_usec = 0;
00093
00094 return now;
00095 }
00096
00097 static long tvdiff(struct timeval newer, struct timeval older)
00098 {
00099 return (newer.tv_sec - older.tv_sec) * 1000 +
00100 (newer.tv_usec - older.tv_usec) / 1000;
00101 }
00102
00103 int main(void)
00104 {
00105 CURL *curl;
00106 CURLM *mcurl;
00107 int still_running = 1;
00108 struct timeval mp_start;
00109 struct curl_slist *recipients = NULL;
00110 struct upload_status upload_ctx;
00111
00112 upload_ctx.lines_read = 0;
00113
00114 curl_global_init(CURL_GLOBAL_DEFAULT);
00115
00116 curl = curl_easy_init();
00117 if(!curl)
00118 return 1;
00119
00120 mcurl = curl_multi_init();
00121 if(!mcurl)
00122 return 2;
00123
00124
00125 curl_easy_setopt(curl, CURLOPT_URL, "smtp://mail.example.com");
00126
00127
00128
00129
00130
00131
00132
00133 curl_easy_setopt(curl, CURLOPT_MAIL_FROM, FROM);
00134
00135
00136
00137
00138 recipients = curl_slist_append(recipients, TO);
00139 recipients = curl_slist_append(recipients, CC);
00140 curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
00141
00142
00143
00144
00145 curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_source);
00146 curl_easy_setopt(curl, CURLOPT_READDATA, &upload_ctx);
00147 curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
00148
00149
00150 curl_multi_add_handle(mcurl, curl);
00151
00152
00153 mp_start = tvnow();
00154
00155
00156 curl_multi_perform(mcurl, &still_running);
00157
00158 while(still_running) {
00159 struct timeval timeout;
00160 fd_set fdread;
00161 fd_set fdwrite;
00162 fd_set fdexcep;
00163 int maxfd = -1;
00164 int rc;
00165 CURLMcode mc;
00166
00167 long curl_timeo = -1;
00168
00169
00170 FD_ZERO(&fdread);
00171 FD_ZERO(&fdwrite);
00172 FD_ZERO(&fdexcep);
00173
00174
00175 timeout.tv_sec = 1;
00176 timeout.tv_usec = 0;
00177
00178 curl_multi_timeout(mcurl, &curl_timeo);
00179 if(curl_timeo >= 0) {
00180 timeout.tv_sec = curl_timeo / 1000;
00181 if(timeout.tv_sec > 1)
00182 timeout.tv_sec = 1;
00183 else
00184 timeout.tv_usec = (curl_timeo % 1000) * 1000;
00185 }
00186
00187
00188 mc = curl_multi_fdset(mcurl, &fdread, &fdwrite, &fdexcep, &maxfd);
00189
00190 if(mc != CURLM_OK) {
00191 fprintf(stderr, "curl_multi_fdset() failed, code %d.\n", mc);
00192 break;
00193 }
00194
00195
00196
00197
00198
00199
00200
00201 if(maxfd == -1) {
00202 #ifdef _WIN32
00203 Sleep(100);
00204 rc = 0;
00205 #else
00206
00207 struct timeval wait = { 0, 100 * 1000 };
00208 rc = select(0, NULL, NULL, NULL, &wait);
00209 #endif
00210 }
00211 else {
00212
00213
00214 rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
00215 }
00216
00217 if(tvdiff(tvnow(), mp_start) > MULTI_PERFORM_HANG_TIMEOUT) {
00218 fprintf(stderr,
00219 "ABORTING: Since it seems that we would have run forever.\n");
00220 break;
00221 }
00222
00223 switch(rc) {
00224 case -1:
00225 break;
00226 case 0:
00227 default:
00228 curl_multi_perform(mcurl, &still_running);
00229 break;
00230 }
00231 }
00232
00233
00234 curl_slist_free_all(recipients);
00235
00236
00237 curl_multi_remove_handle(mcurl, curl);
00238 curl_multi_cleanup(mcurl);
00239 curl_easy_cleanup(curl);
00240 curl_global_cleanup();
00241
00242 return 0;
00243 }