1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2011, 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 http://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/* This is an example application source code sending SMTP mail using the 23 * multi interface. 24 */ 25 26#include <string.h> 27#include <curl/curl.h> 28 29/* 30 * This is the list of basic details you need to tweak to get things right. 31 */ 32#define USERNAME "user@example.com" 33#define PASSWORD "123qwerty" 34#define SMTPSERVER "smtp.example.com" 35#define SMTPPORT ":587" /* it is a colon+port string, but you can set it 36 to "" to use the default port */ 37#define RECIPIENT "<recipient@example.com>" 38#define MAILFROM "<realuser@example.com>" 39 40#define MULTI_PERFORM_HANG_TIMEOUT 60 * 1000 41 42/* Note that you should include the actual meta data headers here as well if 43 you want the mail to have a Subject, another From:, show a To: or whatever 44 you think your mail should feature! */ 45static const char *text[]={ 46 "one\n", 47 "two\n", 48 "three\n", 49 " Hello, this is CURL email SMTP\n", 50 NULL 51}; 52 53struct WriteThis { 54 int counter; 55}; 56 57static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *userp) 58{ 59 struct WriteThis *pooh = (struct WriteThis *)userp; 60 const char *data; 61 62 if(size*nmemb < 1) 63 return 0; 64 65 data = text[pooh->counter]; 66 67 if(data) { 68 size_t len = strlen(data); 69 memcpy(ptr, data, len); 70 pooh->counter++; /* advance pointer */ 71 return len; 72 } 73 return 0; /* no more data left to deliver */ 74} 75 76static struct timeval tvnow(void) 77{ 78 /* 79 ** time() returns the value of time in seconds since the Epoch. 80 */ 81 struct timeval now; 82 now.tv_sec = (long)time(NULL); 83 now.tv_usec = 0; 84 return now; 85} 86 87static long tvdiff(struct timeval newer, struct timeval older) 88{ 89 return (newer.tv_sec-older.tv_sec)*1000+ 90 (newer.tv_usec-older.tv_usec)/1000; 91} 92 93int main(void) 94{ 95 CURL *curl; 96 CURLM *mcurl; 97 int still_running = 1; 98 struct timeval mp_start; 99 struct WriteThis pooh; 100 struct curl_slist* rcpt_list = NULL; 101 102 pooh.counter = 0; 103 104 curl_global_init(CURL_GLOBAL_DEFAULT); 105 106 curl = curl_easy_init(); 107 if(!curl) 108 return 1; 109 110 mcurl = curl_multi_init(); 111 if(!mcurl) 112 return 2; 113 114 rcpt_list = curl_slist_append(rcpt_list, RECIPIENT); 115 /* more addresses can be added here 116 rcpt_list = curl_slist_append(rcpt_list, "<others@example.com>"); 117 */ 118 119 curl_easy_setopt(curl, CURLOPT_URL, "smtp://" SMTPSERVER SMTPPORT); 120 curl_easy_setopt(curl, CURLOPT_USERNAME, USERNAME); 121 curl_easy_setopt(curl, CURLOPT_PASSWORD, PASSWORD); 122 curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback); 123 curl_easy_setopt(curl, CURLOPT_MAIL_FROM, MAILFROM); 124 curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, rcpt_list); 125 curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL); 126 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); 127 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); 128 curl_easy_setopt(curl, CURLOPT_READDATA, &pooh); 129 curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); 130 curl_easy_setopt(curl, CURLOPT_SSLVERSION, 0L); 131 curl_easy_setopt(curl, CURLOPT_SSL_SESSIONID_CACHE, 0L); 132 curl_multi_add_handle(mcurl, curl); 133 134 mp_start = tvnow(); 135 136 /* we start some action by calling perform right away */ 137 curl_multi_perform(mcurl, &still_running); 138 139 while(still_running) { 140 struct timeval timeout; 141 int rc; /* select() return code */ 142 143 fd_set fdread; 144 fd_set fdwrite; 145 fd_set fdexcep; 146 int maxfd = -1; 147 148 long curl_timeo = -1; 149 150 FD_ZERO(&fdread); 151 FD_ZERO(&fdwrite); 152 FD_ZERO(&fdexcep); 153 154 /* set a suitable timeout to play around with */ 155 timeout.tv_sec = 1; 156 timeout.tv_usec = 0; 157 158 curl_multi_timeout(mcurl, &curl_timeo); 159 if(curl_timeo >= 0) { 160 timeout.tv_sec = curl_timeo / 1000; 161 if(timeout.tv_sec > 1) 162 timeout.tv_sec = 1; 163 else 164 timeout.tv_usec = (curl_timeo % 1000) * 1000; 165 } 166 167 /* get file descriptors from the transfers */ 168 curl_multi_fdset(mcurl, &fdread, &fdwrite, &fdexcep, &maxfd); 169 170 /* In a real-world program you OF COURSE check the return code of the 171 function calls. On success, the value of maxfd is guaranteed to be 172 greater or equal than -1. We call select(maxfd + 1, ...), specially in 173 case of (maxfd == -1), we call select(0, ...), which is basically equal 174 to sleep. */ 175 176 rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout); 177 178 if (tvdiff(tvnow(), mp_start) > MULTI_PERFORM_HANG_TIMEOUT) { 179 fprintf(stderr, "ABORTING TEST, since it seems " 180 "that it would have run forever.\n"); 181 break; 182 } 183 184 switch(rc) { 185 case -1: 186 /* select error */ 187 break; 188 case 0: /* timeout */ 189 default: /* action */ 190 curl_multi_perform(mcurl, &still_running); 191 break; 192 } 193 } 194 195 curl_slist_free_all(rcpt_list); 196 curl_multi_remove_handle(mcurl, curl); 197 curl_multi_cleanup(mcurl); 198 curl_easy_cleanup(curl); 199 curl_global_cleanup(); 200 return 0; 201} 202 203 204