smtp.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. /*
  2. * SMTP support for libwebsockets
  3. *
  4. * Copyright (C) 2016 Andy Green <andy@warmcat.com>
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation:
  9. * version 2.1 of the License.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  19. * MA 02110-1301 USA
  20. */
  21. #include "private-libwebsockets.h"
  22. static unsigned int
  23. lwsgs_now_secs(void)
  24. {
  25. struct timeval tv;
  26. gettimeofday(&tv, NULL);
  27. return tv.tv_sec;
  28. }
  29. static void
  30. ccb(uv_handle_t* handle)
  31. {
  32. }
  33. static void
  34. alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf)
  35. {
  36. struct lws_email *email = (struct lws_email *)handle->data;
  37. *buf = uv_buf_init(email->email_buf, sizeof(email->email_buf) - 1);
  38. }
  39. static void
  40. on_write_end(uv_write_t *req, int status) {
  41. lwsl_notice("%s\n", __func__);
  42. if (status == -1) {
  43. fprintf(stderr, "error on_write_end");
  44. return;
  45. }
  46. }
  47. static void
  48. lwsgs_email_read(struct uv_stream_s *s, ssize_t nread, const uv_buf_t *buf)
  49. {
  50. struct lws_email *email = (struct lws_email *)s->data;
  51. static const short retcodes[] = {
  52. 0, /* idle */
  53. 0, /* connecting */
  54. 220, /* connected */
  55. 250, /* helo */
  56. 250, /* from */
  57. 250, /* to */
  58. 354, /* data */
  59. 250, /* body */
  60. 221, /* quit */
  61. };
  62. uv_write_t write_req;
  63. uv_buf_t wbuf;
  64. int n;
  65. if (nread >= 0)
  66. email->email_buf[nread] = '\0';
  67. lwsl_notice("%s: %s\n", __func__, buf->base);
  68. if (nread == -1) {
  69. lwsl_err("%s: failed\n", __func__);
  70. return;
  71. }
  72. n = atoi(buf->base);
  73. if (n != retcodes[email->estate]) {
  74. lwsl_err("%s: bad response from server\n", __func__);
  75. goto close_conn;
  76. }
  77. switch (email->estate) {
  78. case LGSSMTP_CONNECTED:
  79. n = sprintf(email->content, "HELO %s\n", email->email_helo);
  80. email->estate = LGSSMTP_SENT_HELO;
  81. break;
  82. case LGSSMTP_SENT_HELO:
  83. n = sprintf(email->content, "MAIL FROM: <%s>\n", email->email_from);
  84. email->estate = LGSSMTP_SENT_FROM;
  85. break;
  86. case LGSSMTP_SENT_FROM:
  87. n = sprintf(email->content, "RCPT TO: <%s>\n", email->email_to);
  88. email->estate = LGSSMTP_SENT_TO;
  89. break;
  90. case LGSSMTP_SENT_TO:
  91. n = sprintf(email->content, "DATA\n");
  92. email->estate = LGSSMTP_SENT_DATA;
  93. break;
  94. case LGSSMTP_SENT_DATA:
  95. if (email->on_get_body(email, email->content, email->max_content_size))
  96. return;
  97. n = strlen(email->content);
  98. email->estate = LGSSMTP_SENT_BODY;
  99. break;
  100. case LGSSMTP_SENT_BODY:
  101. n = sprintf(email->content, "quit\n");
  102. email->estate = LGSSMTP_SENT_QUIT;
  103. break;
  104. case LGSSMTP_SENT_QUIT:
  105. lwsl_notice("%s: done\n", __func__);
  106. email->on_sent(email);
  107. email->estate = LGSSMTP_IDLE;
  108. goto close_conn;
  109. default:
  110. return;
  111. }
  112. puts(email->content);
  113. wbuf = uv_buf_init(email->content, n);
  114. uv_write(&write_req, s, &wbuf, 1, on_write_end);
  115. return;
  116. close_conn:
  117. uv_close((uv_handle_t *)s, ccb);
  118. }
  119. static void
  120. lwsgs_email_on_connect(uv_connect_t *req, int status)
  121. {
  122. struct lws_email *email = (struct lws_email *)req->data;
  123. lwsl_notice("%s\n", __func__);
  124. if (status == -1) {
  125. lwsl_err("%s: failed\n", __func__);
  126. return;
  127. }
  128. uv_read_start(req->handle, alloc_buffer, lwsgs_email_read);
  129. email->estate = LGSSMTP_CONNECTED;
  130. }
  131. static void
  132. uv_timeout_cb_email(uv_timer_t *w
  133. #if UV_VERSION_MAJOR == 0
  134. , int status
  135. #endif
  136. )
  137. {
  138. struct lws_email *email = lws_container_of(w, struct lws_email,
  139. timeout_email);
  140. time_t now = lwsgs_now_secs();
  141. struct sockaddr_in req_addr;
  142. switch (email->estate) {
  143. case LGSSMTP_IDLE:
  144. if (email->on_next(email))
  145. break;
  146. email->estate = LGSSMTP_CONNECTING;
  147. uv_tcp_init(email->loop, &email->email_client);
  148. if (uv_ip4_addr(email->email_smtp_ip, 25, &req_addr)) {
  149. lwsl_err("Unable to convert mailserver ads\n");
  150. return;
  151. }
  152. lwsl_notice("LGSSMTP_IDLE: connecting\n");
  153. email->email_connect_started = now;
  154. email->email_connect_req.data = email;
  155. email->email_client.data = email;
  156. uv_tcp_connect(&email->email_connect_req, &email->email_client,
  157. (struct sockaddr *)&req_addr,
  158. lwsgs_email_on_connect);
  159. uv_timer_start(&email->timeout_email,
  160. uv_timeout_cb_email, 5000, 0);
  161. break;
  162. case LGSSMTP_CONNECTING:
  163. if (email->email_connect_started - now > 5) {
  164. lwsl_err("mail session timed out\n");
  165. /* !!! kill the connection */
  166. uv_close((uv_handle_t *) &email->email_connect_req, ccb);
  167. email->estate = LGSSMTP_IDLE;
  168. }
  169. break;
  170. default:
  171. break;
  172. }
  173. }
  174. LWS_VISIBLE LWS_EXTERN int
  175. lws_email_init(struct lws_email *email, uv_loop_t *loop, int max_content)
  176. {
  177. email->content = lws_malloc(max_content);
  178. if (!email->content)
  179. return 1;
  180. email->max_content_size = max_content;
  181. uv_timer_init(loop, &email->timeout_email);
  182. email->loop = loop;
  183. /* trigger him one time in a bit */
  184. uv_timer_start(&email->timeout_email, uv_timeout_cb_email, 2000, 0);
  185. return 0;
  186. }
  187. LWS_VISIBLE LWS_EXTERN void
  188. lws_email_check(struct lws_email *email)
  189. {
  190. uv_timer_start(&email->timeout_email, uv_timeout_cb_email, 1000, 0);
  191. }
  192. LWS_VISIBLE LWS_EXTERN void
  193. lws_email_destroy(struct lws_email *email)
  194. {
  195. if (email->content)
  196. lws_free_set_NULL(email->content);
  197. uv_timer_stop(&email->timeout_email);
  198. uv_close((uv_handle_t *)&email->timeout_email, NULL);
  199. }