[email protected]#smtp#@! clean

Download Raw Clone


  1. /*
  2. compile: (requires libcurl+mimetic w ./configure --prefix=`pwd`/bins in Downloads/mime on an OSX)
  3. g++ -o smtp2 smtp.cxx -lcurl -lc++ -lpthread -I/Users/name/Downloads/mutt/mimetic-0.9.8 -L/Users/name/Downloads/mutt/mimetic-0.9.8/bins/lib -lmimetic -ggdb
  4. smtp important files
  5. # message - email, source - from, emails - list, subject = subject, mx/ ips for MX, attachments files to include wiht the message
  6. */
  7. // original from curl
  8. #include <stdio.h>
  9. #include <unistd.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <curl/curl.h>
  13. #include <sys/stat.h>
  14. #include <pthread.h>
  15. #include <iostream>
  16. #include <mimetic/mimetic.h>
  17. #include <time.h>
  18. using namespace std;
  19. using namespace mimetic;
  20. // thread coding (or structure for storing information) starts here...
  21. #define MAX_TH 500
  22. // structure for each thread determined by its ID for whether its busy, its mutex, or thread handle.. and whether it was success
  23. typedef struct _thread_info {
  24. pthread_t thread[MAX_TH];
  25. pthread_mutex_t mutex[MAX_TH];
  26. int busy[MAX_TH];
  27. int success[MAX_TH];
  28. int good;
  29. int bad;
  30. } ThreadInfo;
  31. // global variable for that thread information
  32. ThreadInfo *tinfo = NULL;
  33. typedef struct _taskinfo {
  34. struct _taskinfo *next;
  35. char *from;
  36. char *to;
  37. char *subject;
  38. int thread_id;
  39. char **payload_data;
  40. int payload_data_size;
  41. int completed;
  42. } TaskInfo;
  43. typedef struct _queue {
  44. struct _queue *next;
  45. char *name;
  46. int started;
  47. int ts;
  48. int completed;
  49. TaskInfo *info;
  50. int good;
  51. int bad;
  52. } Queue;
  53. // attachments list from 'attachments' file to be used when building emails
  54. typedef struct _attach {
  55. struct _attach *next;
  56. char *fname;
  57. char *buf;
  58. int size;
  59. } Attachments;
  60. Attachments *attach_list = NULL;
  61. int queue_setup(char *file) {
  62. Queue *qptr = NULL;
  63. return 0;
  64. }
  65. // globals (ugely.. wrote extremely quick without much care for engineering)
  66. pthread_key_t id_payload;
  67. // these are for reporting to the main thread of successes, or writing to files for various reasons..
  68. pthread_mutex_t m_write;
  69. int good = 0;
  70. // bad fd
  71. FILE *bfd = NULL;
  72. // good fd?
  73. FILE *ofd = NULL;
  74. // debug fd
  75. FILE *dfd = NULL;
  76. // no mx fd
  77. FILE *mxfd = NULL;
  78. // end globals
  79. char *load_all_attachments(char *filename, char *message);
  80. int verify_email(char *mx, char *address);
  81. // structure for information being distributed to each individual thread for a particular email transmission or verification (VRFY of address)
  82. typedef struct _email_param {
  83. char ip[16];
  84. char src[256];
  85. char dst[256];
  86. int thread_id;
  87. int verify;
  88. char **payload_data;
  89. int payload_data_size;
  90. } EmailParam;
  91. // reads a single line of a file into a buffer (useful for pulling the IP address of MX for a domain from pre-looked up tables into files)
  92. char *read_line(char *file) {
  93. char *ret = NULL;
  94. char buf[1024];
  95. char *sptr = NULL;
  96. FILE *fd = NULL;
  97. if ((fd = fopen(file,"r")) == NULL) goto end;
  98. fgets(buf,1024,fd);
  99. ret = strdup(buf);
  100. if (ret) {
  101. if ((sptr = strchr(ret, '\r')) != NULL) *sptr = 0;
  102. if ((sptr = strchr(ret, '\n')) != NULL) *sptr = 0;
  103. }
  104. end:;
  105. if (fd) fclose(fd);
  106. return ret;
  107. }
  108. // generate message ID for email (or close enough?)
  109. void msgid(char *dst) {
  110. srand(time(0));
  111. int i = 0;
  112. int r = 0;
  113. int n = 30;
  114. char buf[1024];
  115. char base36[] = "0123456789abcdefghijklmnopqrstuvwxyz";
  116. if (dst == NULL) return;
  117. memset(buf,0,1024);
  118. n = n + (rand()%10);
  119. for (i = 0; i < n; i++) {
  120. if ((i && (i % 9)==0)) {
  121. r = '-';
  122. } else {
  123. r = base36[rand()%(sizeof(base36)-1)];
  124. }
  125. buf[i] = r;
  126. }
  127. strcpy(dst, buf);
  128. }
  129. // begins the payload of an email... date, to, from, subject.. preparing for the attachments (email as plain, and other files)
  130. int begin_payload(EmailParam *info, char *to, char *from, char *subject) {
  131. char *buf = NULL;
  132. char *sptr = NULL;
  133. char *from_domain = NULL;
  134. char id[1024];
  135. time_t rawtime;
  136. struct tm * timeinfo;
  137. time (&rawtime);
  138. timeinfo = localtime (&rawtime);
  139. memset(id,0,1024);
  140. if ((sptr = strchr(from, '@')) == NULL) {
  141. return -1;
  142. } else {
  143. from_domain = sptr+1;
  144. }
  145. if ((buf = (char *)calloc(1,1024)) == NULL) return -1;
  146. strftime(buf, 1024, "Date: %a, %e %b %G %T %z\r\n", timeinfo);
  147. info->payload_data[info->payload_data_size++] = buf;
  148. if (to) {
  149. if ((buf = (char *)calloc(1,1024)) == NULL) return -1;
  150. sprintf(buf, "To: %s\r\n", to);
  151. info->payload_data[info->payload_data_size++] = buf;
  152. }
  153. if (from) {
  154. if ((buf = (char *)calloc(1,1024)) == NULL) return -1;
  155. sprintf(buf, "From: %s\r\n", from);
  156. info->payload_data[info->payload_data_size++] = buf;
  157. }
  158. if ((buf = (char *)calloc(1,1024)) == NULL) return -1;
  159. msgid((char *)&id);
  160. sprintf(buf, "Message-ID: <%[email protected]%s>\r\n", id,from_domain);
  161. info->payload_data[info->payload_data_size++] = buf;
  162. if (subject) {
  163. if ((buf = (char *)calloc(1,1024)) == NULL) return -1;
  164. sprintf(buf, "Subject: %s\r\n", subject);
  165. info->payload_data[info->payload_data_size++] = buf;
  166. }
  167. return 1;
  168. }
  169. // from libcurl example...so the thread knows which information is to be transmitted next
  170. struct upload_status {
  171. int lines_read;
  172. };
  173. // load the payload file into a buffer.. ugly could use a generic one but i transformed this app over night into threadable, etc
  174. char *payload_load(char *filename) {
  175. struct stat stv;
  176. FILE *fd = NULL;
  177. char *line = NULL;
  178. char *ret = NULL;
  179. char *buf = NULL;
  180. if (stat(filename, &stv) != 0) goto end;
  181. if (stv.st_size <= 0) goto end;
  182. if ((buf = (char *)calloc(1,stv.st_size)) == NULL) goto end;
  183. if ((fd = fopen(filename, "rb")) == NULL) goto end;
  184. fread(buf,1,stv.st_size, fd);
  185. ret = buf;
  186. end:;
  187. if (fd) fclose(fd);
  188. if (buf && !ret) free(buf);
  189. return ret;
  190. }
  191. // libcurl callable function for determining which data is to be transmitted next to the SMTP server.. it happens in lines..
  192. // so it updates the line for the next (from libcurl smtp example modified for threads here)
  193. static size_t payload_source(void *ptr, size_t size, size_t nmemb, void *userp) {
  194. struct upload_status *upload_ctx = (struct upload_status *)userp;
  195. const char *data;
  196. EmailParam *info = (EmailParam *)pthread_getspecific(id_payload);
  197. if((size == 0) || (nmemb == 0) || ((size*nmemb) < 1)) {
  198. return 0;
  199. }
  200. data = (char *)info->payload_data[upload_ctx->lines_read];
  201. if(data) {
  202. size_t len = strlen(data);
  203. memcpy(ptr, data, len);
  204. upload_ctx->lines_read++;
  205. return len;
  206. }
  207. return 0;
  208. }
  209. // send a single email to an IP with a source/dest address (from libcurl example)
  210. int email(char *ip, char *src, char *dst) {
  211. CURL *curl = NULL;
  212. CURLcode res = CURLE_OK;
  213. struct curl_slist *recipients = NULL;
  214. struct upload_status upload_ctx;
  215. char buf[1024];
  216. int ret = 0;
  217. upload_ctx.lines_read = 0;
  218. curl = curl_easy_init();
  219. if(curl) {
  220. /* This is the URL for your mailserver */
  221. curl_easy_setopt(curl, CURLOPT_TIMEOUT, (long) 60*2);
  222. sprintf(buf, "smtp://%s", ip);
  223. curl_easy_setopt(curl, CURLOPT_URL, buf);
  224. /* Note that this option isn't strictly required, omitting it will result
  225. * in libcurl sending the MAIL FROM command with empty sender data. All
  226. * autoresponses should have an empty reverse-path, and should be directed
  227. * to the address in the reverse-path which triggered them. Otherwise,
  228. * they could cause an endless loop. See RFC 5321 Section 4.5.5 for more
  229. * details.
  230. */
  231. curl_easy_setopt(curl, CURLOPT_MAIL_FROM, src);
  232. /* Add two recipients, in this particular case they correspond to the
  233. * To: and Cc: addressees in the header, but they could be any kind of
  234. * recipient. */
  235. recipients = curl_slist_append(recipients, dst);
  236. //recipients = curl_slist_append(recipients, CC_ADDR);
  237. curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
  238. /* We're using a callback function to specify the payload (the headers and
  239. * body of the message). You could just use the CURLOPT_READDATA option to
  240. * specify a FILE pointer to read from. */
  241. curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_source);
  242. curl_easy_setopt(curl, CURLOPT_READDATA, &upload_ctx);
  243. curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
  244. curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
  245. /* Send the message */
  246. res = curl_easy_perform(curl);
  247. /* Check for errors */
  248. ret = (res == CURLE_OK);
  249. pthread_mutex_lock(&m_write);
  250. if (ret == 0) {
  251. if (dfd)
  252. fprintf(dfd, "%s: %s\n", dst, curl_easy_strerror(res));
  253. if (bfd)
  254. fprintf(bfd, "%s\n", dst);
  255. } else {
  256. if (ofd)
  257. fprintf(ofd, "%s\n", dst);
  258. }
  259. pthread_mutex_unlock(&m_write);
  260. /* Free the list of recipients */
  261. curl_slist_free_all(recipients);
  262. /* curl won't send the QUIT command until you call cleanup, so you should
  263. * be able to re-use this connection for additional messages (setting
  264. * CURLOPT_MAIL_FROM and CURLOPT_MAIL_RCPT as required, and calling
  265. * curl_easy_perform() again. It may not be a good idea to keep the
  266. * connection open for a very long time though (more than a few minutes
  267. * may result in the server timing out the connection), and you do want to
  268. * clean up in the end.
  269. */
  270. curl_easy_cleanup(curl);
  271. }
  272. return ret;
  273. }
  274. int is_busy(int thread_id) {
  275. int ret = 0;
  276. pthread_mutex_lock(&tinfo->mutex[thread_id]);
  277. ret = tinfo->busy[thread_id];
  278. pthread_mutex_unlock(&tinfo->mutex[thread_id]);
  279. return ret;
  280. }
  281. void set_busy(int thread_id, int is_busy) {
  282. pthread_mutex_lock(&tinfo->mutex[thread_id]);
  283. tinfo->busy[thread_id] = is_busy;
  284. pthread_mutex_unlock(&tinfo->mutex[thread_id]);
  285. }
  286. void *email_thread(void *param) {
  287. int i = 0;
  288. int success = 0;
  289. EmailParam *info = (EmailParam *)param;
  290. if (info != NULL) {
  291. // set the thread specific TLS value of this threads pointer for info.. so i dont have to pass around abunch of
  292. // pointers to get into libcurl's callback for the data line during SMTP transmission
  293. pthread_setspecific(id_payload, (void *)info);
  294. // are we trying to VRFY (test) or send a real message?
  295. if (info->verify == 0) {
  296. success = email(info->ip, info->src, info->dst);
  297. } else {
  298. success = verify_email(info->ip, info->dst);
  299. }
  300. // so original task/queue knows the success of each individual transfer
  301. tinfo->success[info->thread_id] = success;
  302. // free memory which gave thread the information for the smtp functions
  303. free(info->payload_data);
  304. free(param);
  305. // set so it knows this thread is ready ('joinable')
  306. set_busy(info->thread_id, 2);
  307. }
  308. // exit thread without giving any real exit code which matters
  309. pthread_exit(0);
  310. }
  311. // join all threads marked as completed/joinable
  312. int join_threads() {
  313. int i = 0, c = 0;
  314. for (i = 0; i < MAX_TH; i++) {
  315. if (is_busy(i) == 2) {
  316. // join the pthread (to ensure it frees up particular internal memory)
  317. pthread_join(tinfo->thread[i], NULL);
  318. // thread no lnger busy.. ready for another
  319. set_busy(i,0);
  320. // was this thread successful? we only check during joining at the end once.. since the threads get reused
  321. if (tinfo->success[i] == 1) tinfo->good++; else tinfo->bad++;
  322. } else {
  323. // count of all threads completed.. so the app knows its done
  324. c++;
  325. }
  326. }
  327. return c;
  328. }
  329. int start_thread(int verify, char *ip, char *src, char *dst, char *subject, char *attachments, char *msg) {
  330. EmailParam *info = NULL;
  331. int ret = 0;
  332. int i = 0;
  333. // allocate memory for this particular threads email message
  334. if ((info = (EmailParam *)calloc(1,sizeof(EmailParam))) == NULL) return -1;
  335. // allocate memory for each particular line of the email.. its static at 4096 pointers (lines or around 40 chars for each base64 encoded).. can adjust another time
  336. // roughly 40kb (def need to update this to 5-8megabytes)
  337. info->payload_data = (char **)calloc(1,sizeof(char *)*4096);
  338. strcpy(info->ip, ip);
  339. strcpy(info->src, src);
  340. strcpy(info->dst, dst);
  341. // is this just a VRFY, or real transfer?
  342. info->verify = verify;
  343. // initialize the payload for libcurls functions
  344. begin_payload(info, dst, src, subject);
  345. if (attachments && msg) load_all_attachments(attachments, msg);
  346. // sit and wait for some thread to complete so we can continue the transfer...
  347. while (ret == 0) {
  348. // try to join all joinable/completed threads
  349. join_threads();
  350. // loop to find the first available thread
  351. for (i = 0; i < MAX_TH; i++) {
  352. if (is_busy(i) == 0) {
  353. // set thread ID in its particular instructions to the thread chosen
  354. info->thread_id = i;
  355. // ensure we know its busy for the next email
  356. set_busy(i,1);
  357. // thread off this process to begin transmissions
  358. pthread_create(&tinfo->thread[i], NULL, email_thread, (void *)info);
  359. // so our loop breaks, and the calling function knows it was successful
  360. ret = 1;
  361. break;
  362. }
  363. }
  364. if (ret) break;
  365. sleep(1);
  366. }
  367. return ret;
  368. }
  369. // turning domains (from email list) into IP addresses for final send.. or VRFY.. double check each command.. should be fine but worse case the 3rd/4th are
  370. // needing some change in the field/delim for cut
  371. // mkdir -p mx;cd mx/
  372. // for i in `cat ../emails|cut [email protected] -f2|sort -u`;do host -t MX $i > $i.mx;done
  373. //for i in *.mx;do A=`echo $i|rev|cut -d. -f2-|rev`;host -t A $A > $i.ip.raw;done
  374. //for i in *.raw;do A=`echo $i|rev|cut -d. -f2-|rev`;cat $A.raw|grep address|cut -d" " -f4 > $A.ip;done
  375. char *mx(char *domain) {
  376. FILE *fd = NULL;
  377. char buf[1024];
  378. char *ret = NULL;
  379. char *sptr = NULL;
  380. sprintf(buf, "mx/%s.mx.ip", domain);
  381. if ((ret = read_line(buf)) == NULL) {
  382. printf("no MX ip for %s\n", domain);
  383. fprintf(mxfd, "%s\n", domain);
  384. fflush(mxfd);
  385. }
  386. return ret;
  387. }
  388. int verify_email(char *mx, char *address) {
  389. CURL *curl = NULL;
  390. CURLcode res;
  391. struct curl_slist *recipients = NULL;
  392. char buf[1024];
  393. int ret = -1;
  394. sprintf(buf, "smtp://%s", mx);
  395. if ((curl = curl_easy_init()) != NULL) {
  396. /* This is the URL for your mailserver */
  397. curl_easy_setopt(curl, CURLOPT_URL, buf);
  398. curl_easy_setopt(curl, CURLOPT_TIMEOUT, (long) 60);
  399. /* Note that the CURLOPT_MAIL_RCPT takes a list, not a char array */
  400. recipients = curl_slist_append(recipients, address);
  401. curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
  402. res = curl_easy_perform(curl);
  403. /* Check for errors */
  404. ret = (res == CURLE_OK);
  405. pthread_mutex_lock(&m_write);
  406. if (ret == 0) {
  407. if (dfd)
  408. fprintf(dfd, "%s: %s\n", address, curl_easy_strerror(res));
  409. if (bfd)
  410. fprintf(bfd, "%s\n", address);
  411. } else {
  412. if (ofd)
  413. fprintf(ofd, "%s\n", address);
  414. }
  415. pthread_mutex_unlock(&m_write);
  416. /* Free the list of recipients */
  417. curl_slist_free_all(recipients);
  418. curl_easy_cleanup(curl);
  419. }
  420. return ret;
  421. }
  422. // ensure we can open the attachment file, and read atleast 1 byte
  423. int attachment_check(char *file) {
  424. FILE *fd = NULL;
  425. struct stat stv;
  426. char buf[1];
  427. int ret = -1;
  428. if (stat(file, &stv) != 0) goto end;
  429. if ((fd = fopen(file, "rb")) == NULL) goto end;
  430. if (fread(buf,1,1,fd) != 1) goto end;
  431. ret = 1;
  432. end:;
  433. if (fd) fclose(fd);
  434. return ret;
  435. }
  436. // turns a particular pulled data buffer into a libcurl-usable payload style... (from whatever example i begain with)
  437. int attach_to_libcurl_payload(char *data) {
  438. char *saveptr = NULL;
  439. char *ptr = NULL;
  440. int lines = 0;
  441. EmailParam *info = (EmailParam *)pthread_getspecific(id_payload);
  442. info->payload_data[info->payload_data_size++] = strdup("MIME-Version: 1.0\n");
  443. while (ptr = strtok_r(ptr == NULL ? data : NULL, "\n", &saveptr)) {
  444. info->payload_data[info->payload_data_size++] = strdup(ptr);
  445. lines++;
  446. }
  447. info->payload_data[info->payload_data_size++] = strdup("\r\n\r\n");
  448. return lines;
  449. }
  450. // load all attachments from file into this particular email message..
  451. // this could be cached but i don't want to mess with mimetic much (it allows loading attachment here by file name with ctor in Attachment::)
  452. char *load_all_attachments(char *filename, char *message) {
  453. FILE *fd = NULL;
  454. char buf[1024];
  455. char *sptr = NULL;
  456. int r = 0;
  457. char *ret = NULL;
  458. int lines = 0;
  459. MimeEntity *mm = new MultipartMixed;
  460. TextPlain *tp = new TextPlain(std::string(message));
  461. mm->body().parts().push_back(tp);
  462. if ((fd = fopen(filename, "r")) == NULL) return NULL;
  463. while (fgets(buf,1024,fd)) {
  464. if ((sptr = strchr(buf,'\r')) != NULL) *sptr = 0;
  465. if ((sptr = strchr(buf,'\n')) != NULL) *sptr = 0;
  466. printf("Loading attachment: \"%s\"\n", buf);
  467. // change this to check if exist...
  468. if (attachment_check(buf) != 1) {
  469. printf("error loading attachment: %s\n", buf);
  470. exit(-1);
  471. } else {
  472. // *** need to load a different type for the 'plain text' (email message) here...
  473. // the rest is actual attachments..
  474. Attachment* pA = new Attachment(std::string(buf));
  475. mm->body().parts().push_back(pA);
  476. r++;
  477. }
  478. }
  479. fclose(fd);
  480. // c++ trickery... using various bullshit/examples together to pull it through without much effort
  481. // mimetic was designed like this...
  482. std::ostringstream ostr;
  483. ostr << *mm << endl;
  484. std::string final(ostr.str());
  485. ret = strdup(final.c_str());
  486. if (ret) {
  487. // turn attachments into payload_data way
  488. lines = attach_to_libcurl_payload(ret);
  489. free(ret);
  490. }
  491. return NULL;
  492. }
  493. char *ofiles[] = { "good", "bad", "nomx", "debug", NULL };
  494. FILE *output_file(int which, int action) {
  495. char buf[1024];
  496. sprintf(buf, "%s.%d", ofiles[which], action);
  497. return fopen(buf, "a");
  498. }
  499. int main(int argc, char *argv[]) {
  500. // ton of random functions.. wont deal with explaining all
  501. FILE *fd = NULL;
  502. char buf[1024];
  503. char *src = NULL;
  504. char dst[256];
  505. char ip[16];
  506. char *user;
  507. char *domain = NULL;
  508. char *sptr = NULL;
  509. char *mxdomain = NULL;
  510. int check = 0;
  511. int action = -1;
  512. int c = 0;
  513. char *files = NULL;
  514. char *message = NULL;
  515. char *subject = NULL;
  516. char *from = NULL;
  517. int i = 0;
  518. struct rlimit limit;
  519. limit.rlim_cur = MAX_TH * 4;
  520. limit.rlim_max = MAX_TH * 4;
  521. if (setrlimit(RLIMIT_NOFILE, &limit) != 0) {
  522. printf("setrlimit() failed with errno=%d\n", errno);
  523. return 1;
  524. }
  525. // allocate pthread identifier for its thread information
  526. pthread_key_create(&id_payload, NULL);
  527. // allocate enough space for all thread information
  528. if ((tinfo = (ThreadInfo *)calloc(1,sizeof(ThreadInfo))) == NULL) {
  529. printf("Error alloc memory\n");
  530. exit(-1);
  531. }
  532. // action is the argument to the app... 0 - verify, 1 - send email, 2 - testing of code
  533. if (argc > 1)
  534. action = atoi(argv[1]);
  535. // if it doesnt fall within one of these actions then we are complete
  536. if (action > 2 || action < 0) {
  537. printf("%s <0/1>\n0 - vrfy, 1 - send\n", argv[0]);
  538. exit(-1);
  539. }
  540. if ((src = read_line("source")) == NULL) { printf("coudlnt open source email file\n"); exit(0); }
  541. if ((subject = read_line("subject")) == NULL) { printf("couldnt open subject file\n"); exit(0); }
  542. if ((message = payload_load("message")) == NULL) { printf("error loading email message\n"); exit(0); }
  543. // 2 was just to test loading things...
  544. if (action == 2) exit(0);
  545. if ((fd = fopen("emails","r")) == NULL) {
  546. fprintf(stderr, "cannot open file\n");
  547. exit(-1);
  548. }
  549. ofd = output_file(0,action);
  550. bfd = output_file(1, action);
  551. mxfd = output_file(2, action);
  552. dfd = output_file(3, action);
  553. while (fgets(buf,1024,fd)) {
  554. if ((sptr = strchr(buf, '\r')) != NULL) *sptr = 0;
  555. if ((sptr = strchr(buf, '\n')) != NULL) *sptr = 0;
  556. // break email into [email protected]
  557. if (strlen(buf) > 4) {
  558. for (i = 0; i < strlen(buf); i++) buf[i] = tolower(buf[i]);
  559. if ((sptr = strchr(buf, '@')) != NULL) {
  560. *sptr = 0;
  561. user = strdup(buf);
  562. *sptr = '@';
  563. if (user) {
  564. domain = sptr + 1;
  565. // now find the MX ip for this domain (should have been put into files by scripts)
  566. if ((mxdomain = mx(domain)) != NULL) {
  567. if (action == 0) {
  568. // VRFY email address
  569. check = start_thread(1,mxdomain, src, buf, NULL, NULL, NULL);
  570. } else {
  571. // send real email
  572. check = start_thread(0,mxdomain, src, buf, subject, "attachments", message);
  573. }
  574. printf("user: %s domain: %s MX: %s check: %d\n", user, domain, mxdomain,check);
  575. free(mxdomain);
  576. }
  577. free(user);
  578. }
  579. }
  580. }
  581. }
  582. fclose(fd);
  583. // wait for all threads to complete before we exit..
  584. do {
  585. c = join_threads();
  586. sleep(1);
  587. } while (c != (MAX_TH));
  588. if (ofd) fclose(ofd);
  589. if (bfd) fclose(bfd);
  590. if (mxfd) fclose(mxfd);
  591. printf("Success? %d Fail? %d\n", tinfo->good, tinfo->bad);
  592. if (tinfo) free(tinfo);
  593. exit(0);
  594. }

Raw paste data: