123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241 |
- /*
- * SMTP support for libwebsockets
- *
- * Copyright (C) 2016 Andy Green <andy@warmcat.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation:
- * version 2.1 of the License.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301 USA
- */
- #include "private-libwebsockets.h"
- static unsigned int
- lwsgs_now_secs(void)
- {
- struct timeval tv;
- gettimeofday(&tv, NULL);
- return tv.tv_sec;
- }
- static void
- ccb(uv_handle_t* handle)
- {
- }
- static void
- alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf)
- {
- struct lws_email *email = (struct lws_email *)handle->data;
- *buf = uv_buf_init(email->email_buf, sizeof(email->email_buf) - 1);
- }
- static void
- on_write_end(uv_write_t *req, int status) {
- lwsl_notice("%s\n", __func__);
- if (status == -1) {
- fprintf(stderr, "error on_write_end");
- return;
- }
- }
- static void
- lwsgs_email_read(struct uv_stream_s *s, ssize_t nread, const uv_buf_t *buf)
- {
- struct lws_email *email = (struct lws_email *)s->data;
- static const short retcodes[] = {
- 0, /* idle */
- 0, /* connecting */
- 220, /* connected */
- 250, /* helo */
- 250, /* from */
- 250, /* to */
- 354, /* data */
- 250, /* body */
- 221, /* quit */
- };
- uv_write_t write_req;
- uv_buf_t wbuf;
- int n;
- if (nread >= 0)
- email->email_buf[nread] = '\0';
- lwsl_notice("%s: %s\n", __func__, buf->base);
- if (nread == -1) {
- lwsl_err("%s: failed\n", __func__);
- return;
- }
- n = atoi(buf->base);
- if (n != retcodes[email->estate]) {
- lwsl_err("%s: bad response from server\n", __func__);
- goto close_conn;
- }
- switch (email->estate) {
- case LGSSMTP_CONNECTED:
- n = sprintf(email->content, "HELO %s\n", email->email_helo);
- email->estate = LGSSMTP_SENT_HELO;
- break;
- case LGSSMTP_SENT_HELO:
- n = sprintf(email->content, "MAIL FROM: <%s>\n", email->email_from);
- email->estate = LGSSMTP_SENT_FROM;
- break;
- case LGSSMTP_SENT_FROM:
- n = sprintf(email->content, "RCPT TO: <%s>\n", email->email_to);
- email->estate = LGSSMTP_SENT_TO;
- break;
- case LGSSMTP_SENT_TO:
- n = sprintf(email->content, "DATA\n");
- email->estate = LGSSMTP_SENT_DATA;
- break;
- case LGSSMTP_SENT_DATA:
- if (email->on_get_body(email, email->content, email->max_content_size))
- return;
- n = strlen(email->content);
- email->estate = LGSSMTP_SENT_BODY;
- break;
- case LGSSMTP_SENT_BODY:
- n = sprintf(email->content, "quit\n");
- email->estate = LGSSMTP_SENT_QUIT;
- break;
- case LGSSMTP_SENT_QUIT:
- lwsl_notice("%s: done\n", __func__);
- email->on_sent(email);
- email->estate = LGSSMTP_IDLE;
- goto close_conn;
- default:
- return;
- }
- puts(email->content);
- wbuf = uv_buf_init(email->content, n);
- uv_write(&write_req, s, &wbuf, 1, on_write_end);
- return;
- close_conn:
- uv_close((uv_handle_t *)s, ccb);
- }
- static void
- lwsgs_email_on_connect(uv_connect_t *req, int status)
- {
- struct lws_email *email = (struct lws_email *)req->data;
- lwsl_notice("%s\n", __func__);
- if (status == -1) {
- lwsl_err("%s: failed\n", __func__);
- return;
- }
- uv_read_start(req->handle, alloc_buffer, lwsgs_email_read);
- email->estate = LGSSMTP_CONNECTED;
- }
- static void
- uv_timeout_cb_email(uv_timer_t *w
- #if UV_VERSION_MAJOR == 0
- , int status
- #endif
- )
- {
- struct lws_email *email = lws_container_of(w, struct lws_email,
- timeout_email);
- time_t now = lwsgs_now_secs();
- struct sockaddr_in req_addr;
- switch (email->estate) {
- case LGSSMTP_IDLE:
- if (email->on_next(email))
- break;
- email->estate = LGSSMTP_CONNECTING;
- uv_tcp_init(email->loop, &email->email_client);
- if (uv_ip4_addr(email->email_smtp_ip, 25, &req_addr)) {
- lwsl_err("Unable to convert mailserver ads\n");
- return;
- }
- lwsl_notice("LGSSMTP_IDLE: connecting\n");
- email->email_connect_started = now;
- email->email_connect_req.data = email;
- email->email_client.data = email;
- uv_tcp_connect(&email->email_connect_req, &email->email_client,
- (struct sockaddr *)&req_addr,
- lwsgs_email_on_connect);
- uv_timer_start(&email->timeout_email,
- uv_timeout_cb_email, 5000, 0);
- break;
- case LGSSMTP_CONNECTING:
- if (email->email_connect_started - now > 5) {
- lwsl_err("mail session timed out\n");
- /* !!! kill the connection */
- uv_close((uv_handle_t *) &email->email_connect_req, ccb);
- email->estate = LGSSMTP_IDLE;
- }
- break;
- default:
- break;
- }
- }
- LWS_VISIBLE LWS_EXTERN int
- lws_email_init(struct lws_email *email, uv_loop_t *loop, int max_content)
- {
- email->content = lws_malloc(max_content);
- if (!email->content)
- return 1;
- email->max_content_size = max_content;
- uv_timer_init(loop, &email->timeout_email);
- email->loop = loop;
- /* trigger him one time in a bit */
- uv_timer_start(&email->timeout_email, uv_timeout_cb_email, 2000, 0);
- return 0;
- }
- LWS_VISIBLE LWS_EXTERN void
- lws_email_check(struct lws_email *email)
- {
- uv_timer_start(&email->timeout_email, uv_timeout_cb_email, 1000, 0);
- }
- LWS_VISIBLE LWS_EXTERN void
- lws_email_destroy(struct lws_email *email)
- {
- if (email->content)
- lws_free_set_NULL(email->content);
- uv_timer_stop(&email->timeout_email);
- uv_close((uv_handle_t *)&email->timeout_email, NULL);
- }
|