smtpcommands.c
上传用户:knt0001
上传日期:2022-01-28
资源大小:264k
文件大小:15k
源码类别:

Email客户端

开发平台:

C/C++

  1. #if HAVE_CONFIG_H
  2. #include "config.h"
  3. #endif
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <stdarg.h>
  7. #include <unistd.h>
  8. #include <string.h>
  9. #include <assert.h>
  10. #include <termios.h>
  11. #include <sys/select.h>
  12. #include <sys/ioctl.h>
  13. #include "dnet.h"
  14. #include "dstrbuf.h"
  15. #include "email.h"
  16. #include "mimeutils.h"
  17. static dstrbuf *errorstr;
  18. /** 
  19.  * Figures out the screen width and prints the message to fit the screen.
  20.  */
  21. void printProgress(const char *msg)
  22. {
  23. uint i=0;
  24. char *buf=NULL;
  25. struct winsize win_size;
  26. if (!Mopts.verbose) {
  27. return;
  28. }
  29. if (!isatty(STDOUT_FILENO)) {
  30. return;
  31. }
  32. if (ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&win_size) < 0) {
  33. return;
  34. }
  35. buf = xmalloc(win_size.ws_col+1);
  36. memset(buf, ' ', win_size.ws_col);
  37. for (i=0; i < win_size.ws_col; i++) {
  38. if (*msg == '') {
  39. break;
  40. }
  41. buf[i] = *msg++;
  42. }
  43. printf("r%s", buf);
  44. fflush(stdout);
  45. free(buf);
  46. }
  47. /**
  48.  * Will generate a string from an error code and return
  49.  * that string as a return value.
  50.  */
  51. char *
  52. smtpGetErr(void)
  53. {
  54. return errorstr->str;
  55. }
  56. /**
  57.  * Simple interface to copy over buffer into error string
  58.  */
  59. static void
  60. smtpSetErr(const char *buf)
  61. {
  62. if (!errorstr) {
  63. errorstr = DSB_NEW;
  64. }
  65. dsbClear(errorstr);
  66. dsbCopy(errorstr, buf);
  67. }
  68. /**
  69.  * Reads a line from the smtp server using sgets().
  70.  * It will continue to read the response until the 4th character
  71.  * in the line is found to be a space.    Per the RFC 821 this means
  72.  * that this will be the last line of response from the SMTP server
  73.  * and the appropirate return value response.
  74.  */
  75. static int
  76. readResponse(dsocket *sd, dstrbuf *buf)
  77. {
  78. int retval=ERROR;
  79. dstrbuf *tmpbuf = DSB_NEW;
  80. struct timeval tv;
  81. fd_set rfds;
  82. char *timeout = getConfValue("TIMEOUT");
  83. FD_ZERO(&rfds);
  84. FD_SET(dnetGetSock(sd), &rfds);
  85. if (timeout) {
  86. tv.tv_sec = atoi(timeout);
  87. } else {
  88. tv.tv_sec = 10;
  89. }
  90. tv.tv_usec = 0;
  91. (void) select(dnetGetSock(sd)+1, &rfds, NULL, NULL, &tv);
  92. if (FD_ISSET(dnetGetSock(sd), &rfds)) {
  93. do {
  94. dsbClear(tmpbuf);
  95. dnetReadline(sd, tmpbuf);
  96. if (dnetErr(sd)) {
  97. smtpSetErr("Lost connection with SMTP server");
  98. retval = ERROR;
  99. break;
  100. }
  101. dsbCat(buf, tmpbuf->str);
  102. retval = SUCCESS;
  103. /* The last line of a response has a space in the 4th column */
  104. } while (tmpbuf->str[3] != ' ');
  105. } else {
  106. smtpSetErr("Timeout(10) while trying to read from SMTP server");
  107. retval = ERROR;
  108. }
  109. if (retval != ERROR) {
  110. retval = atoi(tmpbuf->str);
  111. }
  112. dsbDestroy(tmpbuf);
  113. return retval;
  114. }
  115. static int
  116. writeResponse(dsocket *sd, char *line, ...)
  117. {
  118. va_list vp;
  119. int sval, size=MAXBUF, bytes=0;
  120. struct timeval tv;
  121. fd_set wfds;
  122. char *buf = xmalloc(size+1);
  123. char *timeout = getConfValue("TIMEOUT");
  124. while (true) {
  125. va_start(vp, line);
  126. bytes = vsnprintf(buf, size, line, vp);
  127. va_end(vp);
  128. if (bytes > -1 && bytes < size) {
  129. /* String written properly */
  130. break;
  131. }
  132. if (bytes > -1) {
  133. size += 1;
  134. } else { 
  135. size *= 2;
  136. }
  137. buf = xrealloc(buf, size+1);
  138. }
  139. FD_ZERO(&wfds);
  140. FD_SET(dnetGetSock(sd), &wfds);
  141. if (timeout) {
  142. tv.tv_sec = atoi(timeout);
  143. } else {
  144. tv.tv_sec = 10;
  145. }
  146. tv.tv_usec = 0;
  147. sval = select(dnetGetSock(sd)+1, NULL, &wfds, NULL, &tv);
  148. if (sval == -1) {
  149. smtpSetErr("writeResponse: select error");
  150. bytes = ERROR;
  151. } else if (sval) {
  152. dnetWrite(sd, buf, bytes);
  153. if (dnetErr(sd)) {
  154. smtpSetErr(dnetGetErr(sd));
  155. bytes = ERROR;
  156. }
  157. } else {
  158. smtpSetErr("Timeout(10) trying to write to SMTP server.");
  159. bytes = ERROR;
  160. }
  161. xfree(buf);
  162. return bytes;
  163. }
  164. static int
  165. helo(dsocket *sd, const char *domain)
  166. {
  167. int retval;
  168. dstrbuf *rbuf = DSB_NEW;
  169. /*
  170.  * We will be calling this function after ehlo() has already
  171.  * been called.  Since ehlo() already grabs the header, go
  172.  * straight into sending the HELO
  173.  */
  174. if (writeResponse(sd, "HELO %srn", domain) < 0) {
  175. smtpSetErr("Lost connection to SMTP server");
  176. retval = ERROR;
  177. goto end;
  178. }
  179. #ifdef DEBUG_SMTP
  180. printf("--> HELOn");
  181. fflush(stdout);
  182. #endif
  183. retval = readResponse(sd, rbuf);
  184. if (retval != 250) {
  185. if (retval != ERROR) {
  186. smtpSetErr(rbuf->str);
  187. }
  188. goto end;
  189. }
  190. #ifdef DEBUG_SMTP
  191. printf("<-- %sn", rbuf->str);
  192. fflush(stdout);
  193. #endif
  194. end:
  195. dsbDestroy(rbuf);
  196. return retval;
  197. }
  198. static int
  199. ehlo(dsocket *sd, const char *domain)
  200. {
  201. int retval;
  202. dstrbuf *rbuf = DSB_NEW;
  203. /* This initiates the connection, so let's read the header first */
  204. retval = readResponse(sd, rbuf);
  205. if (retval != 220) {
  206. if (retval != ERROR) {
  207. smtpSetErr(rbuf->str);
  208. }
  209. goto end;
  210. }
  211. #ifdef DEBUG_SMTP
  212. printf("rn<-- %s", rbuf->str);
  213. fflush(stdout);
  214. #endif
  215. if (writeResponse(sd, "EHLO %srn", domain) < 0) {
  216. smtpSetErr("Lost connection to SMTP server");
  217. retval = ERROR;
  218. goto end;
  219. }
  220. #ifdef DEBUG_SMTP
  221. printf("rn--> EHLO %srn", domain);
  222. fflush(stdout);
  223. #endif
  224. retval = readResponse(sd, rbuf);
  225. if (retval != 250) {
  226. if (retval != ERROR) {
  227. smtpSetErr(rbuf->str);
  228. }
  229. retval = ERROR;
  230. goto end;
  231. }
  232. #ifdef DEBUG_SMTP
  233. printf("rn<-- %s", rbuf->str);
  234. fflush(stdout);
  235. #endif
  236. end:
  237. dsbDestroy(rbuf);
  238. return retval;
  239. }
  240. /** 
  241.  * Send the MAIL FROM: command to the smtp server 
  242.  */
  243. static int
  244. mailFrom(dsocket *sd, const char *email)
  245. {
  246. int retval = 0;
  247. dstrbuf *rbuf = DSB_NEW;
  248. /* Create the MAIL FROM: command */
  249. if (writeResponse(sd, "MAIL FROM:<%s>rn", email) < 0) {
  250. smtpSetErr("Lost connection with SMTP server");
  251. retval = ERROR;
  252. goto end;
  253. }
  254. #ifdef DEBUG_SMTP
  255. printf("rn--> MAIL FROM:<%s>rn", email);
  256. #endif
  257. /* read return message and let's return it's code */
  258. retval = readResponse(sd, rbuf);
  259. if (retval != 250) {
  260. if (retval != ERROR) {
  261. smtpSetErr(rbuf->str);
  262. }
  263. retval = ERROR;
  264. goto end;
  265. }
  266. #ifdef DEBUG_SMTP
  267. printf("rn<-- %s", rbuf->str);
  268. #endif
  269. end:
  270. dsbDestroy(rbuf);
  271. return retval;
  272. }
  273. /**
  274.  * Send the RCPT TO: command to the smtp server
  275.  */
  276. static int
  277. rcpt(dsocket *sd, const char *email)
  278. {
  279. int retval = 0;
  280. dstrbuf *rbuf = DSB_NEW;
  281. if (writeResponse(sd, "RCPT TO: <%s>rn", email) < 0) {
  282. smtpSetErr("Lost connection with SMTP server");
  283. retval = ERROR;
  284. goto end;
  285. }
  286. #ifdef DEBUG_SMTP
  287. printf("rn--> RCPT TO: <%s>rn", email);
  288. fflush(stdout);
  289. #endif
  290. /* Read return message and let's return it's code */
  291. retval = readResponse(sd, rbuf);
  292. if ((retval != 250) && (retval != 251)) {
  293. if (retval != ERROR) {
  294. smtpSetErr(rbuf->str);
  295. }
  296. retval = ERROR;
  297. goto end;
  298. }
  299. #ifdef DEBUG_SMTP
  300. printf("rn<-- %s", rbuf->str);
  301. fflush(stdout);
  302. #endif
  303. end:
  304. dsbDestroy(rbuf);
  305. return retval;
  306. }
  307. /**
  308.  * Send the QUIT command
  309.  */
  310. static int
  311. quit(dsocket *sd)
  312. {
  313. int retval = 0;
  314. dstrbuf *rbuf = DSB_NEW;
  315. /* Create QUIT command and send it */
  316. if (writeResponse(sd, "QUITrn") < 0) {
  317. smtpSetErr("Lost Connection with SMTP server: Quit()");
  318. retval = ERROR;
  319. goto end;
  320. }
  321. #ifdef DEBUG_SMTP
  322. printf("--> QUITrn");
  323. #endif
  324. retval = readResponse(sd, rbuf);
  325. if (retval != 221) {
  326. if (retval != ERROR) {
  327. smtpSetErr(rbuf->str);
  328. }
  329. retval = ERROR;
  330. goto end;
  331. }
  332. #ifdef DEBUG_SMTP
  333. printf("<-- %s", rbuf->str);
  334. #endif
  335. end:
  336. dsbDestroy(rbuf);
  337. return retval;
  338. }
  339. int
  340. data(dsocket *sd)
  341. {
  342. int retval = 0;
  343. dstrbuf *rbuf = DSB_NEW;
  344. /* Create the DATA command and send it */
  345. if (writeResponse(sd, "DATArn") < 0) {
  346. smtpSetErr("Lost connection with SMTP server");
  347. retval = ERROR;
  348. goto end;
  349. }
  350. #ifdef DEBUG_SMTP
  351. printf("rn--> DATArn");
  352. #endif
  353. /* Read return message and let's return it's code */
  354. retval = readResponse(sd, rbuf);
  355. if (retval != 354) {
  356. if (retval != ERROR) {
  357. smtpSetErr(rbuf->str);
  358. }
  359. retval = ERROR;
  360. goto end;
  361. }
  362. #ifdef DEBUG_SMTP
  363. printf("<-- %s", rbuf->str);
  364. #endif
  365. end:
  366. dsbDestroy(rbuf);
  367. return retval;
  368. }
  369. /**
  370.  * Send the RSET command. 
  371.  */
  372. static int
  373. rset(dsocket *sd)
  374. {
  375. int retval = 0;
  376. dstrbuf *rbuf = DSB_NEW;
  377. /* Send the RSET command */
  378. if (writeResponse(sd, "RSETrn") < 0) {
  379. smtpSetErr("Socket write error: rset");
  380. retval = ERROR;
  381. goto end;
  382. }
  383. #ifdef DEBUG_SMTP
  384. printf("--> RSETn");
  385. fflush(stdout);
  386. #endif
  387. retval = readResponse(sd, rbuf);
  388. if (retval != 250) {
  389. if (retval != ERROR) {
  390. smtpSetErr(rbuf->str);
  391. }
  392. retval = ERROR;
  393. goto end;
  394. }
  395. #ifdef DEBUG_SMTP
  396. printf("<-- %sn", rbuf->str);
  397. fflush(stdout);
  398. #endif
  399. end:
  400. dsbDestroy(rbuf);
  401. return retval;
  402. }
  403. /** 
  404.  * SMTP AUTH login.
  405.  */
  406. static int
  407. smtpAuthLogin(dsocket *sd, const char *user, const char *pass)
  408. {
  409. int retval = 0;
  410. dstrbuf *data;
  411. dstrbuf *rbuf = DSB_NEW;
  412. data = mimeB64EncodeString((u_char *)user, strlen(user), false);
  413. if (writeResponse(sd, "AUTH LOGIN %srn", data->str) < 0) {
  414. smtpSetErr("Socket write error: smtp_auth_login");
  415. retval = ERROR;
  416. goto end;
  417. }
  418. #ifdef DEBUG_SMTP
  419. printf("--> AUTH LOGINn");
  420. fflush(stdout);
  421. #endif
  422. retval = readResponse(sd, rbuf);
  423. if (retval != 334) {
  424. if (retval != ERROR) {
  425. smtpSetErr(rbuf->str);
  426. }
  427. retval = ERROR;
  428. goto end;
  429. }
  430. #ifdef DEBUG_SMTP
  431. printf("<-- %sn", rbuf->str);
  432. fflush(stdout);
  433. #endif
  434. /* Encode the password */
  435. dsbDestroy(data);
  436. data = mimeB64EncodeString((u_char *)pass, strlen(pass), false);
  437. if (writeResponse(sd, "%srn", data->str) < 0) {
  438. smtpSetErr("Socket write error: smtp_auth_login");
  439. retval = ERROR;
  440. goto end;
  441. }
  442. #ifdef DEBUG_SMTP
  443. printf("--> %sn", data->str);
  444. fflush(stdout);
  445. #endif
  446. dsbDestroy(data);
  447. /* Read back "OK" from server */
  448. retval = readResponse(sd, rbuf);
  449. if (retval != 235) {
  450. if (retval != ERROR) {
  451. smtpSetErr(rbuf->str);
  452. }
  453. retval = ERROR;
  454. goto end;
  455. }
  456. #ifdef DEBUG_SMTP
  457. printf("<-- %sn", rbuf->str);
  458. fflush(stdout);
  459. #endif
  460. end:
  461. dsbDestroy(rbuf);
  462. return retval;
  463. }
  464. static int
  465. smtpAuthPlain(dsocket *sd, const char *user, const char *pass)
  466. {
  467. int retval = 0;
  468. dstrbuf *data=NULL;
  469. dstrbuf *up = DSB_NEW;
  470. dstrbuf *rbuf = DSB_NEW;
  471. if (writeResponse(sd, "AUTH PLAINrn") < 0) {
  472. smtpSetErr("Socket write error: smtp_auth_plain");
  473. retval = ERROR;
  474. goto end;
  475. }
  476. #ifdef DEBUG_SMTP
  477. printf("--> AUTH PLAINn");
  478. fflush(stdout);
  479. #endif
  480. retval = readResponse(sd, rbuf);
  481. if (retval != 334) {
  482. if (retval != ERROR) {
  483. smtpSetErr(rbuf->str);
  484. }
  485. retval = ERROR;
  486. goto end;
  487. }
  488. #ifdef DEBUG_SMTP
  489. printf("<-- %sn", rbuf->str);
  490. fflush(stdout);
  491. #endif
  492. dsbPrintf(up, "%c%s%c%s", '', user, '', pass);
  493. data = mimeB64EncodeString((u_char *)up->str, up->len, false);
  494. if (writeResponse(sd, "%srn", data->str) < 0) {
  495. smtpSetErr("Socket write error: smtp_auth_plain");
  496. retval = ERROR;
  497. goto end;
  498. }
  499. #ifdef DEBUG_SMTP
  500. printf("--> %sn", data->str);
  501. fflush(stdout);
  502. #endif
  503. dsbClear(rbuf);
  504. retval = readResponse(sd, rbuf);
  505. if (retval != 235) {
  506. if (retval != ERROR) {
  507. smtpSetErr(rbuf->str);
  508. }
  509. retval = ERROR;
  510. goto end;
  511. }
  512. #ifdef DEBUG_SMTP
  513. printf("<-- %sn", rbuf->str);
  514. fflush(stdout);
  515. #endif
  516. end:
  517. dsbDestroy(up);
  518. dsbDestroy(data);
  519. dsbDestroy(rbuf);
  520. return retval;
  521. }
  522. /**
  523.  * Initializes the SMTP communications with SMTP_AUTH.
  524.  *
  525.  * Params
  526.  *  sd - Socket descriptor
  527.  *  auth - LOGIN or PLAIN 
  528.  *  user - Username of the SMTP server
  529.  *  pass - Password for the Username
  530.  *
  531.  * Return
  532.  *  - ERROR
  533.  *  - SUCCESS
  534.  */
  535. int
  536. smtpInitAuth(dsocket *sd, const char *auth, const char *user, const char *pass)
  537. {
  538. int retval=ERROR;
  539. if (strcasecmp(auth, "LOGIN") == 0) {
  540. retval = smtpAuthLogin(sd, user, pass);
  541. } else if (strcasecmp(auth, "PLAIN") == 0) {
  542. retval = smtpAuthPlain(sd, user, pass);
  543. return retval;
  544. }
  545. /**
  546.  * Initializes the SMTP communications by sending the EHLO
  547.  * If EHLO errors out, it will try the HELO command.
  548.  *
  549.  * Params
  550.  *  sd - Socket descriptor
  551.  *  domain - Your domain name.
  552.  *
  553.  * Return
  554.  *  - ERROR
  555.  *  - SUCCESS
  556.  */
  557. int
  558. smtpInit(dsocket *sd, const char *domain)
  559. {
  560. int retval;
  561. printProgress("Greeting the SMTP server...");
  562. retval = ehlo(sd, domain);
  563. if (retval == ERROR) {
  564. /*
  565.  * Per RFC, if ehlo error's out, you can
  566.  * ignore the error, RSET and try a 
  567.  * regular helo.
  568.  */
  569. rset(sd);
  570. retval = helo(sd, domain);
  571. }
  572. return retval;
  573. }
  574. int
  575. smtpStartTls(dsocket *sd)
  576. {
  577.         int retval=SUCCESS;
  578. #ifdef HAVE_LIBSSL
  579.         dstrbuf *sb=DSB_NEW;
  580. printProgress("Starting TLS Communications...");
  581.         if (writeResponse(sd, "STARTTLSrn") < 0) {
  582.                 smtpSetErr("Lost connection to SMTP Server");
  583.                 retval = ERROR;
  584.                 goto end;
  585.         }
  586. #ifdef DEBUG_SMTP
  587. printf("--> STARTTLSn");
  588. fflush(stdout);
  589. #endif
  590.         retval = readResponse(sd, sb);
  591.         if (retval != 220) {
  592.                 smtpSetErr(sb->str);
  593.                 retval = ERROR;
  594.         }
  595. #ifdef DEBUG_SMTP
  596. printf("<-- %sn", sb->str);
  597. fflush(stdout);
  598. #endif
  599. end:
  600.         dsbDestroy(sb);
  601. #else
  602. sd = sd;
  603. #endif
  604.         return retval;
  605. }
  606. /**
  607.  * Sets who the message is from.  Basically runs the 
  608.  * MAIL FROM: SMTP command
  609.  *
  610.  * Params
  611.  *  sd - Socket descriptor
  612.  *  email - From Email
  613.  *
  614.  * Return
  615.  *  - ERROR
  616.  *  - SUCCESS
  617.  */
  618. int
  619. smtpSetMailFrom(dsocket *sd, const char *email)
  620. {
  621. return mailFrom(sd, email);
  622. }
  623. /**
  624.  * Sets all the recipients with the RCPT command
  625.  * to the smtp server. Multiple calls to this function
  626.  * are expected if you have multiple To, CC and BCC 
  627.  * recipients.
  628.  *
  629.  * Params
  630.  *  sd - Socket descriptor
  631.  *  to - An e-mail address to send the message to
  632.  *
  633.  * Return
  634.  *  - ERROR
  635.  *  - SUCCESS
  636.  */
  637. int
  638. smtpSetRcpt(dsocket *sd, const char *to)
  639. {
  640. return rcpt(sd, to);
  641. }
  642. /** 
  643.  * Send the DATA command to the smtp server (no data, just the command)
  644.  *
  645.  * Params
  646.  *  sd - Socket descriptor
  647.  *
  648.  * Return
  649.  *  - ERROR
  650.  *  - SUCCESS
  651.  */
  652. int
  653. smtpStartData(dsocket *sd)
  654. {
  655. return data(sd);
  656. }
  657. /**
  658.  * Sends data to the smtp server. You can try and send the
  659.  * whole chunk at once, or it may be a better idea to break
  660.  * up the data into smaller chunks.
  661.  *
  662.  * Params
  663.  *  sd - Socket descriptor
  664.  *  data - A chunk of data.
  665.  *  len - The length of the data to send
  666.  *
  667.  * Return
  668.  *  - ERROR
  669.  *  - SUCCESS
  670.  */
  671. int
  672. smtpSendData(dsocket *sd, const char *data, size_t len)
  673. {
  674. int retval = SUCCESS;
  675. assert(data != NULL);
  676. assert(sd != NULL);
  677. /* Write the data to the socket. */
  678. dnetWrite(sd, data, len);
  679. if (dnetErr(sd)) {
  680. smtpSetErr("Error writing to socket.");
  681. retval = ERROR;
  682. }
  683. return retval;
  684. }
  685. /**
  686.  * Let's the SMTP server know it's the end of the data stream.
  687.  *
  688.  * Params
  689.  *  sd - Socket descriptor
  690.  *
  691.  * Return
  692.  *  - ERROR
  693.  *  - SUCCESS
  694.  */
  695. int 
  696. smtpEndData(dsocket *sd)
  697. {
  698. int retval=ERROR;
  699. dstrbuf *rbuf = DSB_NEW;
  700. printProgress("Ending Data...");
  701. if (writeResponse(sd, "rn.rn") != ERROR) {
  702. retval = readResponse(sd, rbuf);
  703. if (retval != 250) {
  704. if (retval != ERROR) {
  705. smtpSetErr(rbuf->str);
  706. retval = ERROR;
  707. }
  708. }
  709. } else {
  710. smtpSetErr("Lost Connection with SMTP server: smtpEndData()");
  711. retval = ERROR;
  712. }
  713. dsbDestroy(rbuf);
  714. return retval;
  715. }
  716. /**
  717.  * Sends the QUITrn signal to the smtp server.
  718.  *
  719.  * Params
  720.  *  sd - Socket Descriptor
  721.  *
  722.  * Return
  723.  *  - ERROR
  724.  *  - SUCCESS
  725.  */
  726. int
  727. smtpQuit(dsocket *sd)
  728. {
  729. int retval=0;
  730. printProgress("Sending QUIT...");
  731. retval = quit(sd);
  732. dsbDestroy(errorstr);
  733. return retval;
  734. }