test-server-http: no need to complete transaction early since FILE_COMPLETION will...
[platform/upstream/libwebsockets.git] / lib / smtp.c
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
22 #include "private-libwebsockets.h"
23
24 static unsigned int
25 lwsgs_now_secs(void)
26 {
27         struct timeval tv;
28
29         gettimeofday(&tv, NULL);
30
31         return tv.tv_sec;
32 }
33
34 static void
35 ccb(uv_handle_t* handle)
36 {
37
38 }
39
40 static void
41 alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf)
42 {
43         struct lws_email *email = (struct lws_email *)handle->data;
44
45         *buf = uv_buf_init(email->email_buf, sizeof(email->email_buf) - 1);
46 }
47
48 static void
49 on_write_end(uv_write_t *req, int status) {
50         lwsl_notice("%s\n", __func__);
51         if (status == -1) {
52                 fprintf(stderr, "error on_write_end");
53                 return;
54         }
55 }
56
57 static void
58 lwsgs_email_read(struct uv_stream_s *s, ssize_t nread, const uv_buf_t *buf)
59 {
60         struct lws_email *email = (struct lws_email *)s->data;
61         static const short retcodes[] = {
62                 0,      /* idle */
63                 0,      /* connecting */
64                 220,    /* connected */
65                 250,    /* helo */
66                 250,    /* from */
67                 250,    /* to */
68                 354,    /* data */
69                 250,    /* body */
70                 221,    /* quit */
71         };
72         uv_write_t write_req;
73         uv_buf_t wbuf;
74         int n;
75
76         if (nread >= 0)
77                 email->email_buf[nread] = '\0';
78         lwsl_notice("%s: %s\n", __func__, buf->base);
79         if (nread == -1) {
80                 lwsl_err("%s: failed\n", __func__);
81                 return;
82         }
83
84         n = atoi(buf->base);
85         if (n != retcodes[email->estate]) {
86                 lwsl_err("%s: bad response from server\n", __func__);
87                 goto close_conn;
88         }
89
90         switch (email->estate) {
91         case LGSSMTP_CONNECTED:
92                 n = sprintf(email->content, "HELO %s\n", email->email_helo);
93                 email->estate = LGSSMTP_SENT_HELO;
94                 break;
95         case LGSSMTP_SENT_HELO:
96                 n = sprintf(email->content, "MAIL FROM: <%s>\n", email->email_from);
97                 email->estate = LGSSMTP_SENT_FROM;
98                 break;
99         case LGSSMTP_SENT_FROM:
100                 n = sprintf(email->content, "RCPT TO: <%s>\n", email->email_to);
101                 email->estate = LGSSMTP_SENT_TO;
102                 break;
103         case LGSSMTP_SENT_TO:
104                 n = sprintf(email->content, "DATA\n");
105                 email->estate = LGSSMTP_SENT_DATA;
106                 break;
107         case LGSSMTP_SENT_DATA:
108                 if (email->on_get_body(email, email->content, email->max_content_size))
109                         return;
110                 n = strlen(email->content);
111                 email->estate = LGSSMTP_SENT_BODY;
112                 break;
113         case LGSSMTP_SENT_BODY:
114                 n = sprintf(email->content, "quit\n");
115                 email->estate = LGSSMTP_SENT_QUIT;
116                 break;
117         case LGSSMTP_SENT_QUIT:
118                 lwsl_notice("%s: done\n", __func__);
119                 email->on_sent(email);
120                 email->estate = LGSSMTP_IDLE;
121                 goto close_conn;
122         default:
123                 return;
124         }
125
126         puts(email->content);
127         wbuf = uv_buf_init(email->content, n);
128         uv_write(&write_req, s, &wbuf, 1, on_write_end);
129
130         return;
131
132 close_conn:
133
134         uv_close((uv_handle_t *)s, ccb);
135 }
136
137 static void
138 lwsgs_email_on_connect(uv_connect_t *req, int status)
139 {
140         struct lws_email *email = (struct lws_email *)req->data;
141
142         lwsl_notice("%s\n", __func__);
143
144         if (status == -1) {
145                 lwsl_err("%s: failed\n", __func__);
146                 return;
147         }
148
149         uv_read_start(req->handle, alloc_buffer, lwsgs_email_read);
150         email->estate = LGSSMTP_CONNECTED;
151 }
152
153
154 static void
155 uv_timeout_cb_email(uv_timer_t *w
156 #if UV_VERSION_MAJOR == 0
157                 , int status
158 #endif
159 )
160 {
161         struct lws_email *email = lws_container_of(w, struct lws_email,
162                                                    timeout_email);
163         time_t now = lwsgs_now_secs();
164         struct sockaddr_in req_addr;
165
166         switch (email->estate) {
167         case LGSSMTP_IDLE:
168
169                 if (email->on_next(email))
170                         break;
171
172                 email->estate = LGSSMTP_CONNECTING;
173
174                 uv_tcp_init(email->loop, &email->email_client);
175                 if (uv_ip4_addr(email->email_smtp_ip, 25, &req_addr)) {
176                         lwsl_err("Unable to convert mailserver ads\n");
177                         return;
178                 }
179
180                 lwsl_notice("LGSSMTP_IDLE: connecting\n");
181
182                 email->email_connect_started = now;
183                 email->email_connect_req.data = email;
184                 email->email_client.data = email;
185                 uv_tcp_connect(&email->email_connect_req, &email->email_client,
186                                (struct sockaddr *)&req_addr,
187                                lwsgs_email_on_connect);
188
189                 uv_timer_start(&email->timeout_email,
190                                uv_timeout_cb_email, 5000, 0);
191
192                 break;
193
194         case LGSSMTP_CONNECTING:
195                 if (email->email_connect_started - now > 5) {
196                         lwsl_err("mail session timed out\n");
197                         /* !!! kill the connection */
198                         uv_close((uv_handle_t *) &email->email_connect_req, ccb);
199                         email->estate = LGSSMTP_IDLE;
200                 }
201                 break;
202
203         default:
204                 break;
205         }
206 }
207
208 LWS_VISIBLE LWS_EXTERN int
209 lws_email_init(struct lws_email *email, uv_loop_t *loop, int max_content)
210 {
211         email->content = lws_malloc(max_content);
212         if (!email->content)
213                 return 1;
214
215         email->max_content_size = max_content;
216         uv_timer_init(loop, &email->timeout_email);
217
218         email->loop = loop;
219
220         /* trigger him one time in a bit */
221         uv_timer_start(&email->timeout_email, uv_timeout_cb_email, 2000, 0);
222
223         return 0;
224 }
225
226 LWS_VISIBLE LWS_EXTERN void
227 lws_email_check(struct lws_email *email)
228 {
229         uv_timer_start(&email->timeout_email, uv_timeout_cb_email, 1000, 0);
230 }
231
232 LWS_VISIBLE LWS_EXTERN void
233 lws_email_destroy(struct lws_email *email)
234 {
235         if (email->content)
236                 lws_free_set_NULL(email->content);
237
238         uv_timer_stop(&email->timeout_email);
239         uv_close((uv_handle_t *)&email->timeout_email, NULL);
240 }
241