ReactOS 0.4.16-dev-833-g4bc97ad
smtp.c
Go to the documentation of this file.
1
57#include "lwip/apps/smtp.h"
58
59#if LWIP_TCP && LWIP_CALLBACK_API
60#include "lwip/sys.h"
61#include "lwip/sockets.h"
62#include "lwip/altcp.h"
63#include "lwip/dns.h"
64#include "lwip/mem.h"
65#include "lwip/altcp_tcp.h"
66#include "lwip/altcp_tls.h"
67
68#include <string.h> /* strlen, memcpy */
69#include <stdlib.h>
70
72#define SMTP_POLL_INTERVAL 4
75#define SMTP_TIMEOUT_DATABLOCK ( 3 * 60 * SMTP_POLL_INTERVAL / 2)
78#define SMTP_TIMEOUT_DATATERM (10 * 60 * SMTP_POLL_INTERVAL / 2)
83#define SMTP_TIMEOUT ( 2 * 60 * SMTP_POLL_INTERVAL / 2)
84
85/* the various debug levels for this file */
86#define SMTP_DEBUG_TRACE (SMTP_DEBUG | LWIP_DBG_TRACE)
87#define SMTP_DEBUG_STATE (SMTP_DEBUG | LWIP_DBG_STATE)
88#define SMTP_DEBUG_WARN (SMTP_DEBUG | LWIP_DBG_LEVEL_WARNING)
89#define SMTP_DEBUG_WARN_STATE (SMTP_DEBUG | LWIP_DBG_LEVEL_WARNING | LWIP_DBG_STATE)
90#define SMTP_DEBUG_SERIOUS (SMTP_DEBUG | LWIP_DBG_LEVEL_SERIOUS)
91
92
93#define SMTP_RX_BUF_LEN 255
94#define SMTP_TX_BUF_LEN 255
95#define SMTP_CRLF "\r\n"
96#define SMTP_CRLF_LEN 2
97
98#define SMTP_RESP_220 "220"
99#define SMTP_RESP_235 "235"
100#define SMTP_RESP_250 "250"
101#define SMTP_RESP_334 "334"
102#define SMTP_RESP_354 "354"
103#define SMTP_RESP_LOGIN_UNAME "VXNlcm5hbWU6"
104#define SMTP_RESP_LOGIN_PASS "UGFzc3dvcmQ6"
105
106#define SMTP_KEYWORD_AUTH_SP "AUTH "
107#define SMTP_KEYWORD_AUTH_EQ "AUTH="
108#define SMTP_KEYWORD_AUTH_LEN 5
109#define SMTP_AUTH_PARAM_PLAIN "PLAIN"
110#define SMTP_AUTH_PARAM_LOGIN "LOGIN"
111
112#define SMTP_CMD_EHLO_1 "EHLO ["
113#define SMTP_CMD_EHLO_1_LEN 6
114#define SMTP_CMD_EHLO_2 "]\r\n"
115#define SMTP_CMD_EHLO_2_LEN 3
116#define SMTP_CMD_AUTHPLAIN_1 "AUTH PLAIN "
117#define SMTP_CMD_AUTHPLAIN_1_LEN 11
118#define SMTP_CMD_AUTHPLAIN_2 "\r\n"
119#define SMTP_CMD_AUTHPLAIN_2_LEN 2
120#define SMTP_CMD_AUTHLOGIN "AUTH LOGIN\r\n"
121#define SMTP_CMD_AUTHLOGIN_LEN 12
122#define SMTP_CMD_MAIL_1 "MAIL FROM: <"
123#define SMTP_CMD_MAIL_1_LEN 12
124#define SMTP_CMD_MAIL_2 ">\r\n"
125#define SMTP_CMD_MAIL_2_LEN 3
126#define SMTP_CMD_RCPT_1 "RCPT TO: <"
127#define SMTP_CMD_RCPT_1_LEN 10
128#define SMTP_CMD_RCPT_2 ">\r\n"
129#define SMTP_CMD_RCPT_2_LEN 3
130#define SMTP_CMD_DATA "DATA\r\n"
131#define SMTP_CMD_DATA_LEN 6
132#define SMTP_CMD_HEADER_1 "From: <"
133#define SMTP_CMD_HEADER_1_LEN 7
134#define SMTP_CMD_HEADER_2 ">\r\nTo: <"
135#define SMTP_CMD_HEADER_2_LEN 8
136#define SMTP_CMD_HEADER_3 ">\r\nSubject: "
137#define SMTP_CMD_HEADER_3_LEN 12
138#define SMTP_CMD_HEADER_4 "\r\n\r\n"
139#define SMTP_CMD_HEADER_4_LEN 4
140#define SMTP_CMD_BODY_FINISHED "\r\n.\r\n"
141#define SMTP_CMD_BODY_FINISHED_LEN 5
142#define SMTP_CMD_QUIT "QUIT\r\n"
143#define SMTP_CMD_QUIT_LEN 6
144
145#if defined(SMTP_STAT_TX_BUF_MAX) && SMTP_STAT_TX_BUF_MAX
146#define SMTP_TX_BUF_MAX(len) LWIP_MACRO(if((len) > smtp_tx_buf_len_max) smtp_tx_buf_len_max = (len);)
147#else /* SMTP_STAT_TX_BUF_MAX */
148#define SMTP_TX_BUF_MAX(len)
149#endif /* SMTP_STAT_TX_BUF_MAX */
150
151#if SMTP_COPY_AUTHDATA
152#define SMTP_USERNAME(session) (session)->username
153#define SMTP_PASS(session) (session)->pass
154#define SMTP_AUTH_PLAIN_DATA(session) (session)->auth_plain
155#define SMTP_AUTH_PLAIN_LEN(session) (session)->auth_plain_len
156#else /* SMTP_COPY_AUTHDATA */
157#define SMTP_USERNAME(session) smtp_username
158#define SMTP_PASS(session) smtp_pass
159#define SMTP_AUTH_PLAIN_DATA(session) smtp_auth_plain
160#define SMTP_AUTH_PLAIN_LEN(session) smtp_auth_plain_len
161#endif /* SMTP_COPY_AUTHDATA */
162
163#if SMTP_BODYDH
164#ifndef SMTP_BODYDH_MALLOC
165#define SMTP_BODYDH_MALLOC(size) mem_malloc(size)
166#define SMTP_BODYDH_FREE(ptr) mem_free(ptr)
167#endif
168
169/* Some internal state return values */
170#define BDHALLDATASENT 2
171#define BDHSOMEDATASENT 1
172
173enum bdh_handler_state {
174 BDH_SENDING, /* Serving the user function generating body content */
175 BDH_STOP /* User function stopped, closing */
176};
177#endif
178
180enum smtp_session_state {
181 SMTP_NULL,
182 SMTP_HELO,
183 SMTP_AUTH_PLAIN,
184 SMTP_AUTH_LOGIN_UNAME,
185 SMTP_AUTH_LOGIN_PASS,
186 SMTP_AUTH_LOGIN,
187 SMTP_MAIL,
188 SMTP_RCPT,
189 SMTP_DATA,
190 SMTP_BODY,
191 SMTP_QUIT,
192 SMTP_CLOSED
193};
194
195#ifdef LWIP_DEBUG
197static const char *smtp_state_str[] = {
198 "SMTP_NULL",
199 "SMTP_HELO",
200 "SMTP_AUTH_PLAIN",
201 "SMTP_AUTH_LOGIN_UNAME",
202 "SMTP_AUTH_LOGIN_PASS",
203 "SMTP_AUTH_LOGIN",
204 "SMTP_MAIL",
205 "SMTP_RCPT",
206 "SMTP_DATA",
207 "SMTP_BODY",
208 "SMTP_QUIT",
209 "SMTP_CLOSED",
210};
211
212static const char *smtp_result_strs[] = {
213 "SMTP_RESULT_OK",
214 "SMTP_RESULT_ERR_UNKNOWN",
215 "SMTP_RESULT_ERR_CONNECT",
216 "SMTP_RESULT_ERR_HOSTNAME",
217 "SMTP_RESULT_ERR_CLOSED",
218 "SMTP_RESULT_ERR_TIMEOUT",
219 "SMTP_RESULT_ERR_SVR_RESP",
220 "SMTP_RESULT_ERR_MEM"
221};
222#endif /* LWIP_DEBUG */
223
224#if SMTP_BODYDH
225struct smtp_bodydh_state {
226 smtp_bodycback_fn callback_fn; /* The function to call (again) */
227 u16_t state;
228 struct smtp_bodydh exposed; /* the user function structure */
229};
230#endif /* SMTP_BODYDH */
231
233struct smtp_session {
235 enum smtp_session_state state;
237 u16_t timer;
239 char tx_buf[SMTP_TX_BUF_LEN + 1];
240 struct pbuf* p;
242 const char* from;
244 u16_t from_len;
246 const char* to;
248 u16_t to_len;
250 const char *subject;
252 u16_t subject_len;
254 const char* body;
256 u16_t body_len;
258 u16_t body_sent;
260 smtp_result_fn callback_fn;
262 void *callback_arg;
263#if SMTP_COPY_AUTHDATA
265 char *username;
267 char *pass;
269 char auth_plain[SMTP_MAX_USERNAME_LEN + SMTP_MAX_PASS_LEN + 3];
271 size_t auth_plain_len;
272#endif /* SMTP_COPY_AUTHDATA */
273#if SMTP_BODYDH
274 struct smtp_bodydh_state *bodydh;
275#endif /* SMTP_BODYDH */
276};
277
279static char smtp_server[SMTP_MAX_SERVERNAME_LEN + 1];
281static u16_t smtp_server_port = SMTP_DEFAULT_PORT;
282#if LWIP_ALTCP && LWIP_ALTCP_TLS
284static struct altcp_tls_config *smtp_server_tls_config;
285#endif
287static char *smtp_username;
289static char *smtp_pass;
291static char smtp_auth_plain[SMTP_MAX_USERNAME_LEN + SMTP_MAX_PASS_LEN + 3];
293static size_t smtp_auth_plain_len;
294
295#if SMTP_CHECK_DATA
296static err_t smtp_verify(const char *data, size_t data_len, u8_t linebreaks_allowed);
297#endif /* SMTP_CHECK_DATA */
298static err_t smtp_tcp_recv(void *arg, struct altcp_pcb *pcb, struct pbuf *p, err_t err);
299static void smtp_tcp_err(void *arg, err_t err);
300static err_t smtp_tcp_poll(void *arg, struct altcp_pcb *pcb);
301static err_t smtp_tcp_sent(void *arg, struct altcp_pcb *pcb, u16_t len);
302static err_t smtp_tcp_connected(void *arg, struct altcp_pcb *pcb, err_t err);
303#if LWIP_DNS
304static void smtp_dns_found(const char* hostname, const ip_addr_t *ipaddr, void *arg);
305#endif /* LWIP_DNS */
306#if SMTP_SUPPORT_AUTH_PLAIN || SMTP_SUPPORT_AUTH_LOGIN
307static size_t smtp_base64_encode(char* target, size_t target_len, const char* source, size_t source_len);
308#endif /* SMTP_SUPPORT_AUTH_PLAIN || SMTP_SUPPORT_AUTH_LOGIN */
309static enum smtp_session_state smtp_prepare_mail(struct smtp_session *s, u16_t *tx_buf_len);
310static void smtp_send_body(struct smtp_session *s, struct altcp_pcb *pcb);
311static void smtp_process(void *arg, struct altcp_pcb *pcb, struct pbuf *p);
312#if SMTP_BODYDH
313static void smtp_send_body_data_handler(struct smtp_session *s, struct altcp_pcb *pcb);
314#endif /* SMTP_BODYDH */
315
316
317#ifdef LWIP_DEBUG
319const char*
320smtp_result_str(u8_t smtp_result)
321{
322 if (smtp_result >= LWIP_ARRAYSIZE(smtp_result_strs)) {
323 return "UNKNOWN";
324 }
325 return smtp_result_strs[smtp_result];
326}
327
332static const char*
333smtp_pbuf_str(struct pbuf* p)
334{
335 if ((p == NULL) || (p->len == 0)) {
336 return "";
337 }
338 ((char*)p->payload)[p->len] = 0;
339 return (const char*)p->payload;
340}
341#endif /* LWIP_DEBUG */
342
348err_t
349smtp_set_server_addr(const char* server)
350{
351 size_t len = 0;
352
354
355 if (server != NULL) {
356 /* strlen: returns length WITHOUT terminating 0 byte */
357 len = strlen(server);
358 }
360 return ERR_MEM;
361 }
362 if (len != 0) {
363 MEMCPY(smtp_server, server, len);
364 }
365 smtp_server[len] = 0; /* always OK because of smtp_server[SMTP_MAX_SERVERNAME_LEN + 1] */
366 return ERR_OK;
367}
368
374void
376{
378 smtp_server_port = port;
379}
380
381#if LWIP_ALTCP && LWIP_ALTCP_TLS
387void
388smtp_set_tls_config(struct altcp_tls_config *tls_config)
389{
391 smtp_server_tls_config = tls_config;
392}
393#endif
394
401err_t
402smtp_set_auth(const char* username, const char* pass)
403{
404 size_t uname_len = 0;
405 size_t pass_len = 0;
406
408
409 memset(smtp_auth_plain, 0xfa, 64);
410 if (username != NULL) {
411 uname_len = strlen(username);
412 if (uname_len > SMTP_MAX_USERNAME_LEN) {
413 LWIP_DEBUGF(SMTP_DEBUG_SERIOUS, ("Username is too long, %d instead of %d\n",
414 (int)uname_len, SMTP_MAX_USERNAME_LEN));
415 return ERR_ARG;
416 }
417 }
418 if (pass != NULL) {
419#if SMTP_SUPPORT_AUTH_LOGIN || SMTP_SUPPORT_AUTH_PLAIN
420 pass_len = strlen(pass);
421 if (pass_len > SMTP_MAX_PASS_LEN) {
422 LWIP_DEBUGF(SMTP_DEBUG_SERIOUS, ("Password is too long, %d instead of %d\n",
423 (int)uname_len, SMTP_MAX_USERNAME_LEN));
424 return ERR_ARG;
425 }
426#else /* SMTP_SUPPORT_AUTH_LOGIN || SMTP_SUPPORT_AUTH_PLAIN */
427 LWIP_DEBUGF(SMTP_DEBUG_WARN, ("Password not supported as no authentication methods are activated\n"));
428#endif /* SMTP_SUPPORT_AUTH_LOGIN || SMTP_SUPPORT_AUTH_PLAIN */
429 }
430 *smtp_auth_plain = 0;
431 if (username != NULL) {
432 smtp_username = smtp_auth_plain + 1;
433 strcpy(smtp_username, username);
434 }
435 if (pass != NULL) {
436 smtp_pass = smtp_auth_plain + uname_len + 2;
437 strcpy(smtp_pass, pass);
438 }
439 smtp_auth_plain_len = uname_len + pass_len + 2;
440
441 return ERR_OK;
442}
443
444#if SMTP_BODYDH
445static void smtp_free_struct(struct smtp_session *s)
446{
447 if (s->bodydh != NULL) {
448 SMTP_BODYDH_FREE(s->bodydh);
449 }
451}
452#else /* SMTP_BODYDH */
453#define smtp_free_struct(x) SMTP_STATE_FREE(x)
454#endif /* SMTP_BODYDH */
455
456static struct altcp_pcb*
457smtp_setup_pcb(struct smtp_session *s, const ip_addr_t* remote_ip)
458{
459 struct altcp_pcb* pcb;
460 LWIP_UNUSED_ARG(remote_ip);
461
462#if LWIP_ALTCP && LWIP_ALTCP_TLS
463 if (smtp_server_tls_config) {
464 pcb = altcp_tls_new(smtp_server_tls_config, IP_GET_TYPE(remote_ip));
465 } else
466#endif
467 {
468 pcb = altcp_tcp_new_ip_type(IP_GET_TYPE(remote_ip));
469 }
470 if (pcb != NULL) {
471 altcp_arg(pcb, s);
472 altcp_recv(pcb, smtp_tcp_recv);
473 altcp_err(pcb, smtp_tcp_err);
474 altcp_poll(pcb, smtp_tcp_poll, SMTP_POLL_INTERVAL);
475 altcp_sent(pcb, smtp_tcp_sent);
476 }
477 return pcb;
478}
479
483static err_t
484smtp_send_mail_alloced(struct smtp_session *s)
485{
486 err_t err;
487 struct altcp_pcb* pcb = NULL;
489
490 LWIP_ASSERT("no smtp_session supplied", s != NULL);
491
492#if SMTP_CHECK_DATA
493 /* check that body conforms to RFC:
494 * - convert all single-CR or -LF in body to CRLF
495 * - only 7-bit ASCII is allowed
496 */
497 if (smtp_verify(s->to, s->to_len, 0) != ERR_OK) {
498 err = ERR_ARG;
499 goto leave;
500 }
501 if (smtp_verify(s->from, s->from_len, 0) != ERR_OK) {
502 err = ERR_ARG;
503 goto leave;
504 }
505 if (smtp_verify(s->subject, s->subject_len, 0) != ERR_OK) {
506 err = ERR_ARG;
507 goto leave;
508 }
509#if SMTP_BODYDH
510 if (s->bodydh == NULL)
511#endif /* SMTP_BODYDH */
512 {
513 if (smtp_verify(s->body, s->body_len, 0) != ERR_OK) {
514 err = ERR_ARG;
515 goto leave;
516 }
517 }
518#endif /* SMTP_CHECK_DATA */
519
520#if SMTP_COPY_AUTHDATA
521 /* copy auth data, ensuring the first byte is always zero */
522 MEMCPY(s->auth_plain + 1, smtp_auth_plain + 1, smtp_auth_plain_len - 1);
523 s->auth_plain_len = smtp_auth_plain_len;
524 /* default username and pass is empty string */
525 s->username = s->auth_plain;
526 s->pass = s->auth_plain;
527 if (smtp_username != NULL) {
528 s->username += smtp_username - smtp_auth_plain;
529 }
530 if (smtp_pass != NULL) {
531 s->pass += smtp_pass - smtp_auth_plain;
532 }
533#endif /* SMTP_COPY_AUTHDATA */
534
535 s->state = SMTP_NULL;
536 s->timer = SMTP_TIMEOUT;
537
538#if LWIP_DNS
539 err = dns_gethostbyname(smtp_server, &addr, smtp_dns_found, s);
540#else /* LWIP_DNS */
541 err = ipaddr_aton(smtp_server, &addr) ? ERR_OK : ERR_ARG;
542#endif /* LWIP_DNS */
543 if (err == ERR_OK) {
544 pcb = smtp_setup_pcb(s, &addr);
545 if (pcb == NULL) {
546 err = ERR_MEM;
547 goto leave;
548 }
549 err = altcp_connect(pcb, &addr, smtp_server_port, smtp_tcp_connected);
550 if (err != ERR_OK) {
551 LWIP_DEBUGF(SMTP_DEBUG_WARN_STATE, ("tcp_connect failed: %d\n", (int)err));
552 goto deallocate_and_leave;
553 }
554 } else if (err != ERR_INPROGRESS) {
555 LWIP_DEBUGF(SMTP_DEBUG_WARN_STATE, ("dns_gethostbyname failed: %d\n", (int)err));
556 goto deallocate_and_leave;
557 }
558 return ERR_OK;
559
560deallocate_and_leave:
561 if (pcb != NULL) {
562 altcp_arg(pcb, NULL);
563 altcp_close(pcb);
564 }
565leave:
566 smtp_free_struct(s);
567 /* no need to call the callback here since we return != ERR_OK */
568 return err;
569}
570
584err_t
585smtp_send_mail(const char* from, const char* to, const char* subject, const char* body,
586 smtp_result_fn callback_fn, void* callback_arg)
587{
588 struct smtp_session* s;
589 size_t from_len = strlen(from);
590 size_t to_len = strlen(to);
591 size_t subject_len = strlen(subject);
592 size_t body_len = strlen(body);
593 size_t mem_len = sizeof(struct smtp_session);
594 char *sfrom, *sto, *ssubject, *sbody;
595
597
598 mem_len += from_len + to_len + subject_len + body_len + 4;
599 if (mem_len > 0xffff) {
600 /* too long! */
601 return ERR_MEM;
602 }
603
604 /* Allocate memory to keep this email's session state */
605 s = (struct smtp_session *)SMTP_STATE_MALLOC((mem_size_t)mem_len);
606 if (s == NULL) {
607 return ERR_MEM;
608 }
609 /* initialize the structure */
610 memset(s, 0, mem_len);
611 s->from = sfrom = (char*)s + sizeof(struct smtp_session);
612 s->from_len = (u16_t)from_len;
613 s->to = sto = sfrom + from_len + 1;
614 s->to_len = (u16_t)to_len;
615 s->subject = ssubject = sto + to_len + 1;
616 s->subject_len = (u16_t)subject_len;
617 s->body = sbody = ssubject + subject_len + 1;
618 s->body_len = (u16_t)body_len;
619 /* copy source and target email address */
620 /* cast to size_t is a hack to cast away constness */
621 MEMCPY(sfrom, from, from_len + 1);
622 MEMCPY(sto, to, to_len + 1);
623 MEMCPY(ssubject, subject, subject_len + 1);
624 MEMCPY(sbody, body, body_len + 1);
625
626 s->callback_fn = callback_fn;
627 s->callback_arg = callback_arg;
628
629 /* call the actual implementation of this function */
630 return smtp_send_mail_alloced(s);
631}
632
639err_t
640smtp_send_mail_static(const char *from, const char* to, const char* subject,
641 const char* body, smtp_result_fn callback_fn, void* callback_arg)
642{
643 struct smtp_session* s;
644 size_t len;
645
647
648 s = (struct smtp_session*)SMTP_STATE_MALLOC(sizeof(struct smtp_session));
649 if (s == NULL) {
650 return ERR_MEM;
651 }
652 memset(s, 0, sizeof(struct smtp_session));
653 /* initialize the structure */
654 s->from = from;
655 len = strlen(from);
656 LWIP_ASSERT("string is too long", len <= 0xffff);
657 s->from_len = (u16_t)len;
658 s->to = to;
659 len = strlen(to);
660 LWIP_ASSERT("string is too long", len <= 0xffff);
661 s->to_len = (u16_t)len;
662 s->subject = subject;
663 len = strlen(subject);
664 LWIP_ASSERT("string is too long", len <= 0xffff);
665 s->subject_len = (u16_t)len;
666 s->body = body;
667 len = strlen(body);
668 LWIP_ASSERT("string is too long", len <= 0xffff);
669 s->body_len = (u16_t)len;
670 s->callback_fn = callback_fn;
671 s->callback_arg = callback_arg;
672 /* call the actual implementation of this function */
673 return smtp_send_mail_alloced(s);
674}
675
676
694void
696{
697 struct smtp_send_request *req = (struct smtp_send_request*)arg;
698 err_t err;
699
701 LWIP_ASSERT("smtp_send_mail_int: no argument given", arg != NULL);
702
703 if (req->static_data) {
704 err = smtp_send_mail_static(req->from, req->to, req->subject, req->body,
705 req->callback_fn, req->callback_arg);
706 } else {
707 err = smtp_send_mail(req->from, req->to, req->subject, req->body,
708 req->callback_fn, req->callback_arg);
709 }
710 if ((err != ERR_OK) && (req->callback_fn != NULL)) {
712 }
713}
714
715#if SMTP_CHECK_DATA
720static err_t
721smtp_verify(const char *data, size_t data_len, u8_t linebreaks_allowed)
722{
723 size_t i;
724 u8_t last_was_cr = 0;
725 for (i = 0; i < data_len; i++) {
726 char current = data[i];
727 if ((current & 0x80) != 0) {
728 LWIP_DEBUGF(SMTP_DEBUG_WARN, ("smtp_verify: no 8-bit data supported: %s\n", data));
729 return ERR_ARG;
730 }
731 if (current == '\r') {
732 if (!linebreaks_allowed) {
733 LWIP_DEBUGF(SMTP_DEBUG_WARN, ("smtp_verify: found CR where no linebreaks allowed: %s\n", data));
734 return ERR_ARG;
735 }
736 if (last_was_cr) {
737 LWIP_DEBUGF(SMTP_DEBUG_WARN, ("smtp_verify: found double CR: %s\n", data));
738 return ERR_ARG;
739 }
740 last_was_cr = 1;
741 } else {
742 if (current == '\n') {
743 if (!last_was_cr) {
744 LWIP_DEBUGF(SMTP_DEBUG_WARN, ("smtp_verify: found LF without CR before: %s\n", data));
745 return ERR_ARG;
746 }
747 }
748 last_was_cr = 0;
749 }
750 }
751 return ERR_OK;
752}
753#endif /* SMTP_CHECK_DATA */
754
756static void
757smtp_free(struct smtp_session *s, u8_t result, u16_t srv_err, err_t err)
758{
759 smtp_result_fn fn = s->callback_fn;
760 void *arg = s->callback_arg;
761 if (s->p != NULL) {
762 pbuf_free(s->p);
763 }
764 smtp_free_struct(s);
765 if (fn != NULL) {
766 fn(arg, result, srv_err, err);
767 }
768}
769
771static void
772smtp_close(struct smtp_session *s, struct altcp_pcb *pcb, u8_t result,
773 u16_t srv_err, err_t err)
774{
775 if (pcb != NULL) {
776 altcp_arg(pcb, NULL);
777 if (altcp_close(pcb) == ERR_OK) {
778 if (s != NULL) {
779 smtp_free(s, result, srv_err, err);
780 }
781 } else {
782 /* close failed, set back arg */
783 altcp_arg(pcb, s);
784 }
785 } else {
786 if (s != NULL) {
787 smtp_free(s, result, srv_err, err);
788 }
789 }
790}
791
793static void
794smtp_tcp_err(void *arg, err_t err)
795{
797 if (arg != NULL) {
798 LWIP_DEBUGF(SMTP_DEBUG_WARN_STATE, ("smtp_tcp_err: connection reset by remote host\n"));
799 smtp_free((struct smtp_session*)arg, SMTP_RESULT_ERR_CLOSED, 0, err);
800 }
801}
802
804static err_t
805smtp_tcp_poll(void *arg, struct altcp_pcb *pcb)
806{
807 if (arg != NULL) {
808 struct smtp_session *s = (struct smtp_session*)arg;
809 if (s->timer != 0) {
810 s->timer--;
811 }
812 }
813 smtp_process(arg, pcb, NULL);
814 return ERR_OK;
815}
816
818static err_t
819smtp_tcp_sent(void *arg, struct altcp_pcb *pcb, u16_t len)
820{
822
823 smtp_process(arg, pcb, NULL);
824
825 return ERR_OK;
826}
827
829static err_t
830smtp_tcp_recv(void *arg, struct altcp_pcb *pcb, struct pbuf *p, err_t err)
831{
833 if (p != NULL) {
834 altcp_recved(pcb, p->tot_len);
835 smtp_process(arg, pcb, p);
836 } else {
837 LWIP_DEBUGF(SMTP_DEBUG_WARN_STATE, ("smtp_tcp_recv: connection closed by remote host\n"));
838 smtp_close((struct smtp_session*)arg, pcb, SMTP_RESULT_ERR_CLOSED, 0, err);
839 }
840 return ERR_OK;
841}
842
843static err_t
844smtp_tcp_connected(void *arg, struct altcp_pcb *pcb, err_t err)
845{
847
848 if (err == ERR_OK) {
849 LWIP_DEBUGF(SMTP_DEBUG_STATE, ("smtp_connected: Waiting for 220\n"));
850 } else {
851 /* shouldn't happen, but we still check 'err', only to be sure */
852 LWIP_DEBUGF(SMTP_DEBUG_WARN, ("smtp_connected: %d\n", (int)err));
853 smtp_close((struct smtp_session*)arg, pcb, SMTP_RESULT_ERR_CONNECT, 0, err);
854 }
855 return ERR_OK;
856}
857
858#if LWIP_DNS
862static void
863smtp_dns_found(const char* hostname, const ip_addr_t *ipaddr, void *arg)
864{
865 struct smtp_session *s = (struct smtp_session*)arg;
866 struct altcp_pcb *pcb;
867 err_t err;
868 u8_t result;
869
871
872 if (ipaddr != NULL) {
873 pcb = smtp_setup_pcb(s, ipaddr);
874 if (pcb != NULL) {
875 LWIP_DEBUGF(SMTP_DEBUG_STATE, ("smtp_dns_found: hostname resolved, connecting\n"));
876 err = altcp_connect(pcb, ipaddr, smtp_server_port, smtp_tcp_connected);
877 if (err == ERR_OK) {
878 return;
879 }
880 LWIP_DEBUGF(SMTP_DEBUG_WARN_STATE, ("tcp_connect failed: %d\n", (int)err));
882 } else {
883 LWIP_DEBUGF(SMTP_DEBUG_STATE, ("smtp_dns_found: failed to allocate tcp pcb\n"));
885 err = ERR_MEM;
886 }
887 } else {
888 LWIP_DEBUGF(SMTP_DEBUG_WARN_STATE, ("smtp_dns_found: failed to resolve hostname: %s\n",
889 hostname));
890 pcb = NULL;
892 err = ERR_ARG;
893 }
894 smtp_close(s, pcb, result, 0, err);
895}
896#endif /* LWIP_DNS */
897
898#if SMTP_SUPPORT_AUTH_PLAIN || SMTP_SUPPORT_AUTH_LOGIN
899
901static const char base64_table[] = {
902 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
903 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
904 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
905 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
906 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
907 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
908 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
909 '+', '/'
910};
911
913static size_t
914smtp_base64_encode(char* target, size_t target_len, const char* source, size_t source_len)
915{
916 size_t i;
917 s8_t j;
918 size_t target_idx = 0;
919 size_t longer = (source_len % 3) ? (3 - (source_len % 3)) : 0;
920 size_t source_len_b64 = source_len + longer;
921 size_t len = (((source_len_b64) * 4) / 3);
922 u8_t x = 5;
923 u8_t current = 0;
924 LWIP_UNUSED_ARG(target_len);
925
926 LWIP_ASSERT("target_len is too short", target_len >= len);
927
928 for (i = 0; i < source_len_b64; i++) {
929 u8_t b = (i < source_len ? (u8_t)source[i] : 0);
930 for (j = 7; j >= 0; j--, x--) {
931 if ((b & (1 << j)) != 0) {
932 current = (u8_t)(current | (1U << x));
933 }
934 if (x == 0) {
935 target[target_idx++] = base64_table[current];
936 x = 6;
937 current = 0;
938 }
939 }
940 }
941 for (i = len - longer; i < len; i++) {
942 target[i] = '=';
943 }
944 return len;
945}
946#endif /* SMTP_SUPPORT_AUTH_PLAIN || SMTP_SUPPORT_AUTH_LOGIN */
947
954static u16_t
955smtp_is_response(struct smtp_session *s)
956{
957 char digits[4];
958 long num;
959
960 if (s->p == NULL) {
961 return 0;
962 }
963 /* copy three digits and convert them to int */
964 if (pbuf_copy_partial(s->p, digits, 3, 0) != 3) {
965 /* pbuf was too short */
966 return 0;
967 }
968 digits[3] = 0;
969 num = strtol(digits, NULL, 10);
970 if ((num <= 0) || (num >= 1000)) {
971 /* failed to find response code at start of line */
972 return 0;
973 }
974 return (u16_t)num;
975}
976
986static err_t
987smtp_is_response_finished(struct smtp_session *s)
988{
989 u8_t sp;
990 u16_t crlf;
992
993 if (s->p == NULL) {
994 return ERR_VAL;
995 }
996 offset = 0;
997again:
998 /* We could check the response number here, but we trust the
999 * protocol definition which says the client can rely on it being
1000 * the same on every line. */
1001
1002 /* find CRLF */
1003 if (offset > 0xFFFF - 4) {
1004 /* would overflow */
1005 return ERR_VAL;
1006 }
1007 crlf = pbuf_memfind(s->p, SMTP_CRLF, SMTP_CRLF_LEN, (u16_t)(offset + 4));
1008 if (crlf == 0xFFFF) {
1009 /* no CRLF found */
1010 return ERR_VAL;
1011 }
1012 sp = pbuf_get_at(s->p, (u16_t)(offset + 3));
1013 if (sp == '-') {
1014 /* no space after response code -> try next line */
1015 offset = (u16_t)(crlf + 2);
1016 if (offset < crlf) {
1017 /* overflow */
1018 return ERR_VAL;
1019 }
1020 goto again;
1021 } else if (sp == ' ') {
1022 /* CRLF found after response code + space -> valid response */
1023 return ERR_OK;
1024 }
1025 /* sp contains invalid character */
1026 return ERR_VAL;
1027}
1028
1030static enum smtp_session_state
1031smtp_prepare_helo(struct smtp_session *s, u16_t *tx_buf_len, struct altcp_pcb *pcb)
1032{
1033 size_t ipa_len;
1034 const char *ipa = ipaddr_ntoa(altcp_get_ip(pcb, 1));
1035 LWIP_ASSERT("ipaddr_ntoa returned NULL", ipa != NULL);
1036 ipa_len = strlen(ipa);
1037 LWIP_ASSERT("string too long", ipa_len <= (SMTP_TX_BUF_LEN-SMTP_CMD_EHLO_1_LEN-SMTP_CMD_EHLO_2_LEN));
1038
1039 *tx_buf_len = (u16_t)(SMTP_CMD_EHLO_1_LEN + (u16_t)ipa_len + SMTP_CMD_EHLO_2_LEN);
1040 LWIP_ASSERT("tx_buf overflow detected", *tx_buf_len <= SMTP_TX_BUF_LEN);
1041
1042 SMEMCPY(s->tx_buf, SMTP_CMD_EHLO_1, SMTP_CMD_EHLO_1_LEN);
1043 MEMCPY(&s->tx_buf[SMTP_CMD_EHLO_1_LEN], ipa, ipa_len);
1044 SMEMCPY(&s->tx_buf[SMTP_CMD_EHLO_1_LEN + ipa_len], SMTP_CMD_EHLO_2, SMTP_CMD_EHLO_2_LEN);
1045 return SMTP_HELO;
1046}
1047
1048#if SMTP_SUPPORT_AUTH_PLAIN || SMTP_SUPPORT_AUTH_LOGIN
1053static enum smtp_session_state
1054smtp_prepare_auth_or_mail(struct smtp_session *s, u16_t *tx_buf_len)
1055{
1056 /* check response for supported authentication method */
1057 u16_t auth = pbuf_strstr(s->p, SMTP_KEYWORD_AUTH_SP);
1058 if (auth == 0xFFFF) {
1059 auth = pbuf_strstr(s->p, SMTP_KEYWORD_AUTH_EQ);
1060 }
1061 if (auth != 0xFFFF) {
1062 u16_t crlf = pbuf_memfind(s->p, SMTP_CRLF, SMTP_CRLF_LEN, auth);
1063 if ((crlf != 0xFFFF) && (crlf > auth)) {
1064 /* use tx_buf temporarily */
1065 u16_t copied = pbuf_copy_partial(s->p, s->tx_buf, (u16_t)(crlf - auth), auth);
1066 if (copied != 0) {
1067 char *sep = s->tx_buf + SMTP_KEYWORD_AUTH_LEN;
1068 s->tx_buf[copied] = 0;
1069#if SMTP_SUPPORT_AUTH_PLAIN
1070 /* favour PLAIN over LOGIN since it involves less requests */
1071 if (strstr(sep, SMTP_AUTH_PARAM_PLAIN) != NULL) {
1072 size_t auth_len;
1073 /* server supports AUTH PLAIN */
1074 SMEMCPY(s->tx_buf, SMTP_CMD_AUTHPLAIN_1, SMTP_CMD_AUTHPLAIN_1_LEN);
1075
1076 /* add base64-encoded string "\0username\0password" */
1077 auth_len = smtp_base64_encode(&s->tx_buf[SMTP_CMD_AUTHPLAIN_1_LEN],
1078 SMTP_TX_BUF_LEN - SMTP_CMD_AUTHPLAIN_1_LEN, SMTP_AUTH_PLAIN_DATA(s),
1079 SMTP_AUTH_PLAIN_LEN(s));
1080 LWIP_ASSERT("string too long", auth_len <= (SMTP_TX_BUF_LEN-SMTP_CMD_AUTHPLAIN_1_LEN-SMTP_CMD_AUTHPLAIN_2_LEN));
1081 *tx_buf_len = (u16_t)(SMTP_CMD_AUTHPLAIN_1_LEN + SMTP_CMD_AUTHPLAIN_2_LEN + (u16_t)auth_len);
1082 SMEMCPY(&s->tx_buf[SMTP_CMD_AUTHPLAIN_1_LEN + auth_len], SMTP_CMD_AUTHPLAIN_2,
1083 SMTP_CMD_AUTHPLAIN_2_LEN);
1084 return SMTP_AUTH_PLAIN;
1085 } else
1086#endif /* SMTP_SUPPORT_AUTH_PLAIN */
1087 {
1088#if SMTP_SUPPORT_AUTH_LOGIN
1089 if (strstr(sep, SMTP_AUTH_PARAM_LOGIN) != NULL) {
1090 /* server supports AUTH LOGIN */
1091 *tx_buf_len = SMTP_CMD_AUTHLOGIN_LEN;
1092 SMEMCPY(s->tx_buf, SMTP_CMD_AUTHLOGIN, SMTP_CMD_AUTHLOGIN_LEN);
1093 return SMTP_AUTH_LOGIN_UNAME;
1094 }
1095#endif /* SMTP_SUPPORT_AUTH_LOGIN */
1096 }
1097 }
1098 }
1099 }
1100 /* server didnt's send correct keywords for AUTH, try sending directly */
1101 return smtp_prepare_mail(s, tx_buf_len);
1102}
1103#endif /* SMTP_SUPPORT_AUTH_PLAIN || SMTP_SUPPORT_AUTH_LOGIN */
1104
1105#if SMTP_SUPPORT_AUTH_LOGIN
1107static enum smtp_session_state
1108smtp_prepare_auth_login_uname(struct smtp_session *s, u16_t *tx_buf_len)
1109{
1110 size_t base64_len = smtp_base64_encode(s->tx_buf, SMTP_TX_BUF_LEN,
1111 SMTP_USERNAME(s), strlen(SMTP_USERNAME(s)));
1112 /* @todo: support base64-encoded longer than 64k */
1113 LWIP_ASSERT("string too long", base64_len <= 0xffff);
1114 LWIP_ASSERT("tx_buf overflow detected", base64_len <= SMTP_TX_BUF_LEN - SMTP_CRLF_LEN);
1115 *tx_buf_len = (u16_t)(base64_len + SMTP_CRLF_LEN);
1116
1117 SMEMCPY(&s->tx_buf[base64_len], SMTP_CRLF, SMTP_CRLF_LEN);
1118 s->tx_buf[*tx_buf_len] = 0;
1119 return SMTP_AUTH_LOGIN_PASS;
1120}
1121
1123static enum smtp_session_state
1124smtp_prepare_auth_login_pass(struct smtp_session *s, u16_t *tx_buf_len)
1125{
1126 size_t base64_len = smtp_base64_encode(s->tx_buf, SMTP_TX_BUF_LEN,
1127 SMTP_PASS(s), strlen(SMTP_PASS(s)));
1128 /* @todo: support base64-encoded longer than 64k */
1129 LWIP_ASSERT("string too long", base64_len <= 0xffff);
1130 LWIP_ASSERT("tx_buf overflow detected", base64_len <= SMTP_TX_BUF_LEN - SMTP_CRLF_LEN);
1131 *tx_buf_len = (u16_t)(base64_len + SMTP_CRLF_LEN);
1132
1133 SMEMCPY(&s->tx_buf[base64_len], SMTP_CRLF, SMTP_CRLF_LEN);
1134 s->tx_buf[*tx_buf_len] = 0;
1135 return SMTP_AUTH_LOGIN;
1136}
1137#endif /* SMTP_SUPPORT_AUTH_LOGIN */
1138
1140static enum smtp_session_state
1141smtp_prepare_mail(struct smtp_session *s, u16_t *tx_buf_len)
1142{
1143 char *target = s->tx_buf;
1144 LWIP_ASSERT("tx_buf overflow detected", s->from_len <= (SMTP_TX_BUF_LEN - SMTP_CMD_MAIL_1_LEN - SMTP_CMD_MAIL_2_LEN));
1145 *tx_buf_len = (u16_t)(SMTP_CMD_MAIL_1_LEN + SMTP_CMD_MAIL_2_LEN + s->from_len);
1146 target[*tx_buf_len] = 0;
1147
1148 SMEMCPY(target, SMTP_CMD_MAIL_1, SMTP_CMD_MAIL_1_LEN);
1149 target += SMTP_CMD_MAIL_1_LEN;
1150 MEMCPY(target, s->from, s->from_len);
1151 target += s->from_len;
1152 SMEMCPY(target, SMTP_CMD_MAIL_2, SMTP_CMD_MAIL_2_LEN);
1153 return SMTP_MAIL;
1154}
1155
1157static enum smtp_session_state
1158smtp_prepare_rcpt(struct smtp_session *s, u16_t *tx_buf_len)
1159{
1160 char *target = s->tx_buf;
1161 LWIP_ASSERT("tx_buf overflow detected", s->to_len <= (SMTP_TX_BUF_LEN - SMTP_CMD_RCPT_1_LEN - SMTP_CMD_RCPT_2_LEN));
1162 *tx_buf_len = (u16_t)(SMTP_CMD_RCPT_1_LEN + SMTP_CMD_RCPT_2_LEN + s->to_len);
1163 target[*tx_buf_len] = 0;
1164
1165 SMEMCPY(target, SMTP_CMD_RCPT_1, SMTP_CMD_RCPT_1_LEN);
1166 target += SMTP_CMD_RCPT_1_LEN;
1167 MEMCPY(target, s->to, s->to_len);
1168 target += s->to_len;
1169 SMEMCPY(target, SMTP_CMD_RCPT_2, SMTP_CMD_RCPT_2_LEN);
1170 return SMTP_RCPT;
1171}
1172
1174static enum smtp_session_state
1175smtp_prepare_header(struct smtp_session *s, u16_t *tx_buf_len)
1176{
1177 char *target = s->tx_buf;
1178 int len = SMTP_CMD_HEADER_1_LEN + SMTP_CMD_HEADER_2_LEN +
1179 SMTP_CMD_HEADER_3_LEN + SMTP_CMD_HEADER_4_LEN + s->from_len + s->to_len +
1180 s->subject_len;
1181 LWIP_ASSERT("tx_buf overflow detected", len > 0 && len <= SMTP_TX_BUF_LEN);
1182 *tx_buf_len = (u16_t)len;
1183 target[*tx_buf_len] = 0;
1184
1185 SMEMCPY(target, SMTP_CMD_HEADER_1, SMTP_CMD_HEADER_1_LEN);
1186 target += SMTP_CMD_HEADER_1_LEN;
1187 MEMCPY(target, s->from, s->from_len);
1188 target += s->from_len;
1189 SMEMCPY(target, SMTP_CMD_HEADER_2, SMTP_CMD_HEADER_2_LEN);
1190 target += SMTP_CMD_HEADER_2_LEN;
1191 MEMCPY(target, s->to, s->to_len);
1192 target += s->to_len;
1193 SMEMCPY(target, SMTP_CMD_HEADER_3, SMTP_CMD_HEADER_3_LEN);
1194 target += SMTP_CMD_HEADER_3_LEN;
1195 MEMCPY(target, s->subject, s->subject_len);
1196 target += s->subject_len;
1197 SMEMCPY(target, SMTP_CMD_HEADER_4, SMTP_CMD_HEADER_4_LEN);
1198
1199 return SMTP_BODY;
1200}
1201
1203static enum smtp_session_state
1204smtp_prepare_quit(struct smtp_session *s, u16_t *tx_buf_len)
1205{
1206 *tx_buf_len = SMTP_CMD_QUIT_LEN;
1207 s->tx_buf[*tx_buf_len] = 0;
1208 SMEMCPY(s->tx_buf, SMTP_CMD_QUIT, SMTP_CMD_QUIT_LEN);
1209 LWIP_ASSERT("tx_buf overflow detected", *tx_buf_len <= SMTP_TX_BUF_LEN);
1210 return SMTP_CLOSED;
1211}
1212
1214static void
1215smtp_send_body(struct smtp_session *s, struct altcp_pcb *pcb)
1216{
1217 err_t err;
1218
1219 if (s->state == SMTP_BODY) {
1220#if SMTP_BODYDH
1221 if (s->bodydh) {
1222 smtp_send_body_data_handler(s, pcb);
1223 } else
1224#endif /* SMTP_BODYDH */
1225 {
1226 u16_t send_len = (u16_t)(s->body_len - s->body_sent);
1227 if (send_len > 0) {
1228 u16_t snd_buf = altcp_sndbuf(pcb);
1229 if (send_len > snd_buf) {
1230 send_len = snd_buf;
1231 }
1232 if (send_len > 0) {
1233 /* try to send something out */
1234 err = altcp_write(pcb, &s->body[s->body_sent], (u16_t)send_len, TCP_WRITE_FLAG_COPY);
1235 if (err == ERR_OK) {
1236 s->timer = SMTP_TIMEOUT_DATABLOCK;
1237 s->body_sent = (u16_t)(s->body_sent + send_len);
1238 if (s->body_sent < s->body_len) {
1239 LWIP_DEBUGF(SMTP_DEBUG_STATE, ("smtp_send_body: %d of %d bytes written\n",
1240 s->body_sent, s->body_len));
1241 }
1242 }
1243 }
1244 }
1245 }
1246 if (s->body_sent == s->body_len) {
1247 /* the whole body has been written, write last line */
1248 LWIP_DEBUGF(SMTP_DEBUG_STATE, ("smtp_send_body: body completely written (%d bytes), appending end-of-body\n",
1249 s->body_len));
1250 err = altcp_write(pcb, SMTP_CMD_BODY_FINISHED, SMTP_CMD_BODY_FINISHED_LEN, 0);
1251 if (err == ERR_OK) {
1252 s->timer = SMTP_TIMEOUT_DATATERM;
1253 LWIP_DEBUGF(SMTP_DEBUG_STATE, ("smtp_send_body: end-of-body written, changing state to %s\n",
1254 smtp_state_str[SMTP_QUIT]));
1255 /* last line written, change state, wait for confirmation */
1256 s->state = SMTP_QUIT;
1257 }
1258 }
1259 }
1260}
1261
1264static void
1265smtp_process(void *arg, struct altcp_pcb *pcb, struct pbuf *p)
1266{
1267 struct smtp_session* s = (struct smtp_session*)arg;
1268 u16_t response_code = 0;
1269 u16_t tx_buf_len = 0;
1270 enum smtp_session_state next_state;
1271
1272 if (arg == NULL) {
1273 /* already closed SMTP connection */
1274 if (p != NULL) {
1275 LWIP_DEBUGF(SMTP_DEBUG_TRACE, ("Received %d bytes after closing: %s\n",
1276 p->tot_len, smtp_pbuf_str(p)));
1277 pbuf_free(p);
1278 }
1279 return;
1280 }
1281
1282 next_state = s->state;
1283
1284 if (p != NULL) {
1285 /* received data */
1286 if (s->p == NULL) {
1287 s->p = p;
1288 } else {
1289 pbuf_cat(s->p, p);
1290 }
1291 } else {
1292 /* idle timer, close connection if timed out */
1293 if (s->timer == 0) {
1294 LWIP_DEBUGF(SMTP_DEBUG_WARN_STATE, ("smtp_process: connection timed out, closing\n"));
1295 smtp_close(s, pcb, SMTP_RESULT_ERR_TIMEOUT, 0, ERR_TIMEOUT);
1296 return;
1297 }
1298 if (s->state == SMTP_BODY) {
1299 smtp_send_body(s, pcb);
1300 return;
1301 }
1302 }
1303 response_code = smtp_is_response(s);
1304 if (response_code) {
1305 LWIP_DEBUGF(SMTP_DEBUG_TRACE, ("smtp_process: received response code: %d\n", response_code));
1306 if (smtp_is_response_finished(s) != ERR_OK) {
1307 LWIP_DEBUGF(SMTP_DEBUG_TRACE, ("smtp_process: partly received response code: %d\n", response_code));
1308 /* wait for next packet to complete the respone */
1309 return;
1310 }
1311 } else {
1312 if (s->p != NULL) {
1313 LWIP_DEBUGF(SMTP_DEBUG_WARN, ("smtp_process: unknown data received (%s)\n",
1314 smtp_pbuf_str(s->p)));
1315 pbuf_free(s->p);
1316 s->p = NULL;
1317 }
1318 return;
1319 }
1320
1321 switch(s->state)
1322 {
1323 case(SMTP_NULL):
1324 /* wait for 220 */
1325 if (response_code == 220) {
1326 /* then send EHLO */
1327 next_state = smtp_prepare_helo(s, &tx_buf_len, pcb);
1328 }
1329 break;
1330 case(SMTP_HELO):
1331 /* wait for 250 */
1332 if (response_code == 250) {
1333#if SMTP_SUPPORT_AUTH_PLAIN || SMTP_SUPPORT_AUTH_LOGIN
1334 /* then send AUTH or MAIL */
1335 next_state = smtp_prepare_auth_or_mail(s, &tx_buf_len);
1336 }
1337 break;
1338 case(SMTP_AUTH_LOGIN):
1339 case(SMTP_AUTH_PLAIN):
1340 /* wait for 235 */
1341 if (response_code == 235) {
1342#endif /* SMTP_SUPPORT_AUTH_PLAIN || SMTP_SUPPORT_AUTH_LOGIN */
1343 /* send MAIL */
1344 next_state = smtp_prepare_mail(s, &tx_buf_len);
1345 }
1346 break;
1347#if SMTP_SUPPORT_AUTH_LOGIN
1348 case(SMTP_AUTH_LOGIN_UNAME):
1349 /* wait for 334 Username */
1350 if (response_code == 334) {
1351 if (pbuf_strstr(s->p, SMTP_RESP_LOGIN_UNAME) != 0xFFFF) {
1352 /* send username */
1353 next_state = smtp_prepare_auth_login_uname(s, &tx_buf_len);
1354 }
1355 }
1356 break;
1357 case(SMTP_AUTH_LOGIN_PASS):
1358 /* wait for 334 Password */
1359 if (response_code == 334) {
1360 if (pbuf_strstr(s->p, SMTP_RESP_LOGIN_PASS) != 0xFFFF) {
1361 /* send username */
1362 next_state = smtp_prepare_auth_login_pass(s, &tx_buf_len);
1363 }
1364 }
1365 break;
1366#endif /* SMTP_SUPPORT_AUTH_LOGIN */
1367 case(SMTP_MAIL):
1368 /* wait for 250 */
1369 if (response_code == 250) {
1370 /* send RCPT */
1371 next_state = smtp_prepare_rcpt(s, &tx_buf_len);
1372 }
1373 break;
1374 case(SMTP_RCPT):
1375 /* wait for 250 */
1376 if (response_code == 250) {
1377 /* send DATA */
1378 SMEMCPY(s->tx_buf, SMTP_CMD_DATA, SMTP_CMD_DATA_LEN);
1379 tx_buf_len = SMTP_CMD_DATA_LEN;
1380 next_state = SMTP_DATA;
1381 }
1382 break;
1383 case(SMTP_DATA):
1384 /* wait for 354 */
1385 if (response_code == 354) {
1386 /* send email header */
1387 next_state = smtp_prepare_header(s, &tx_buf_len);
1388 }
1389 break;
1390 case(SMTP_BODY):
1391 /* nothing to be done here, handled somewhere else */
1392 break;
1393 case(SMTP_QUIT):
1394 /* wait for 250 */
1395 if (response_code == 250) {
1396 /* send QUIT */
1397 next_state = smtp_prepare_quit(s, &tx_buf_len);
1398 }
1399 break;
1400 case(SMTP_CLOSED):
1401 /* nothing to do, wait for connection closed from server */
1402 return;
1403 default:
1404 LWIP_DEBUGF(SMTP_DEBUG_SERIOUS, ("Invalid state: %d/%s\n", (int)s->state,
1405 smtp_state_str[s->state]));
1406 break;
1407 }
1408 if (s->state == next_state) {
1409 LWIP_DEBUGF(SMTP_DEBUG_WARN_STATE, ("smtp_process[%s]: unexpected response_code, closing: %d (%s)\n",
1410 smtp_state_str[s->state], response_code, smtp_pbuf_str(s->p)));
1411 /* close connection */
1412 smtp_close(s, pcb, SMTP_RESULT_ERR_SVR_RESP, response_code, ERR_OK);
1413 return;
1414 }
1415 if (tx_buf_len > 0) {
1416 SMTP_TX_BUF_MAX(tx_buf_len);
1417 if (altcp_write(pcb, s->tx_buf, tx_buf_len, TCP_WRITE_FLAG_COPY) == ERR_OK) {
1418 LWIP_DEBUGF(SMTP_DEBUG_TRACE, ("smtp_process[%s]: received command %d (%s)\n",
1419 smtp_state_str[s->state], response_code, smtp_pbuf_str(s->p)));
1420 LWIP_DEBUGF(SMTP_DEBUG_TRACE, ("smtp_process[%s]: sent %"U16_F" bytes: \"%s\"\n",
1421 smtp_state_str[s->state], tx_buf_len, s->tx_buf));
1422 s->timer = SMTP_TIMEOUT;
1423 pbuf_free(s->p);
1424 s->p = NULL;
1425 LWIP_DEBUGF(SMTP_DEBUG_STATE, ("smtp_process: changing state from %s to %s\n",
1426 smtp_state_str[s->state], smtp_state_str[next_state]));
1427 s->state = next_state;
1428 if (next_state == SMTP_BODY) {
1429 /* try to stream-send body data right now */
1430 smtp_send_body(s, pcb);
1431 } else if (next_state == SMTP_CLOSED) {
1432 /* sent out all data, delete structure */
1433 altcp_arg(pcb, NULL);
1434 smtp_free(s, SMTP_RESULT_OK, 0, ERR_OK);
1435 }
1436 }
1437 }
1438}
1439
1440#if SMTP_BODYDH
1447static int
1448smtp_send_bodyh_data(struct altcp_pcb *pcb, const char **from, u16_t *howmany)
1449{
1450 err_t err;
1451 u16_t len = *howmany;
1452
1453 len = (u16_t)LWIP_MIN(len, altcp_sndbuf(pcb));
1454 err = altcp_write(pcb, *from, len, TCP_WRITE_FLAG_COPY);
1455 if (err == ERR_OK) {
1456 *from += len;
1457 if ((*howmany -= len) > 0) {
1458 return BDHSOMEDATASENT;
1459 }
1460 return BDHALLDATASENT;
1461 }
1462 return 0;
1463}
1464
1467err_t
1468smtp_send_mail_bodycback(const char *from, const char* to, const char* subject,
1469 smtp_bodycback_fn bodycback_fn, smtp_result_fn callback_fn, void* callback_arg)
1470{
1471 struct smtp_session* s;
1472 size_t len;
1473
1475
1476 s = (struct smtp_session*)SMTP_STATE_MALLOC(sizeof(struct smtp_session));
1477 if (s == NULL) {
1478 return ERR_MEM;
1479 }
1480 memset(s, 0, sizeof(struct smtp_session));
1481 s->bodydh = (struct smtp_bodydh_state*)SMTP_BODYDH_MALLOC(sizeof(struct smtp_bodydh_state));
1482 if (s->bodydh == NULL) {
1484 return ERR_MEM;
1485 }
1486 memset(s->bodydh, 0, sizeof(struct smtp_bodydh_state));
1487 /* initialize the structure */
1488 s->from = from;
1489 len = strlen(from);
1490 LWIP_ASSERT("string is too long", len <= 0xffff);
1491 s->from_len = (u16_t)len;
1492 s->to = to;
1493 len = strlen(to);
1494 LWIP_ASSERT("string is too long", len <= 0xffff);
1495 s->to_len = (u16_t)len;
1496 s->subject = subject;
1497 len = strlen(subject);
1498 LWIP_ASSERT("string is too long", len <= 0xffff);
1499 s->subject_len = (u16_t)len;
1500 s->body = NULL;
1501 s->callback_fn = callback_fn;
1502 s->callback_arg = callback_arg;
1503 s->bodydh->callback_fn = bodycback_fn;
1504 s->bodydh->state = BDH_SENDING;
1505 /* call the actual implementation of this function */
1506 return smtp_send_mail_alloced(s);
1507}
1508
1509static void
1510smtp_send_body_data_handler(struct smtp_session *s, struct altcp_pcb *pcb)
1511{
1512 struct smtp_bodydh_state *bdh;
1513 int res = 0, ret;
1514 LWIP_ASSERT("s != NULL", s != NULL);
1515 bdh = s->bodydh;
1516 LWIP_ASSERT("bodydh != NULL", bdh != NULL);
1517
1518 /* resume any leftovers from prior memory constraints */
1519 if (s->body_len) {
1520 LWIP_DEBUGF(SMTP_DEBUG_TRACE, ("smtp_send_body_data_handler: resume\n"));
1521 if((res = smtp_send_bodyh_data(pcb, (const char **)&s->body, &s->body_len))
1522 != BDHALLDATASENT) {
1523 s->body_sent = s->body_len - 1;
1524 return;
1525 }
1526 }
1527 ret = res;
1528 /* all data on buffer has been queued, resume execution */
1529 if (bdh->state == BDH_SENDING) {
1530 LWIP_DEBUGF(SMTP_DEBUG_TRACE, ("smtp_send_body_data_handler: run\n"));
1531 do {
1532 ret |= res; /* remember if we once queued something to send */
1533 bdh->exposed.length = 0;
1534 if (bdh->callback_fn(s->callback_arg, &bdh->exposed) == BDH_DONE) {
1535 bdh->state = BDH_STOP;
1536 }
1537 s->body = bdh->exposed.buffer;
1538 s->body_len = bdh->exposed.length;
1539 LWIP_DEBUGF(SMTP_DEBUG_TRACE, ("smtp_send_body_data_handler: trying to send %u bytes\n", (unsigned int)s->body_len));
1540 } while (s->body_len &&
1541 ((res = smtp_send_bodyh_data(pcb, (const char **)&s->body, &s->body_len)) == BDHALLDATASENT)
1542 && (bdh->state != BDH_STOP));
1543 }
1544 if ((bdh->state != BDH_SENDING) && (ret != BDHSOMEDATASENT)) {
1545 LWIP_DEBUGF(SMTP_DEBUG_TRACE, ("smtp_send_body_data_handler: stop\n"));
1546 s->body_sent = s->body_len;
1547 } else {
1548 LWIP_DEBUGF(SMTP_DEBUG_TRACE, ("smtp_send_body_data_handler: pause\n"));
1549 s->body_sent = s->body_len - 1;
1550 }
1551}
1552#endif /* SMTP_BODYDH */
1553
1554#endif /* LWIP_TCP && LWIP_CALLBACK_API */
char * strstr(char *String1, char *String2)
Definition: utclib.c:653
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
#define altcp_write
Definition: altcp.h:187
#define altcp_get_ip(pcb, local)
Definition: altcp.h:199
#define altcp_arg
Definition: altcp.h:168
#define altcp_connect
Definition: altcp.h:177
#define altcp_sndbuf
Definition: altcp.h:191
#define altcp_poll
Definition: altcp.h:172
#define altcp_sent
Definition: altcp.h:171
#define altcp_err
Definition: altcp.h:173
#define altcp_recv
Definition: altcp.h:170
#define altcp_pcb
Definition: altcp.h:159
#define altcp_close
Definition: altcp.h:184
#define altcp_recved
Definition: altcp.h:175
#define altcp_tcp_new_ip_type
Definition: altcp.h:160
static int state
Definition: maze.c:121
char * hostname
Definition: ftp.c:88
#define leave
Definition: btrfs_drv.h:138
#define LWIP_ARRAYSIZE(x)
Definition: def.h:69
#define LWIP_MIN(x, y)
Definition: def.h:66
#define NULL
Definition: types.h:112
static const WCHAR crlf[]
Definition: object.c:1018
USHORT port
Definition: uri.c:228
#define U16_F
Definition: cc.h:19
#define LWIP_DEBUGF(debug, message)
Definition: debug.h:158
#define LWIP_ASSERT(message, assertion)
Definition: debug.h:116
u16_t mem_size_t
Definition: mem.h:67
#define ERR_MEM
Definition: fontsub.h:52
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
GLdouble s
Definition: gl.h:2039
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLuint res
Definition: glext.h:9613
GLintptr offset
Definition: glext.h:5920
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
GLenum const GLvoid * addr
Definition: glext.h:9621
GLuint64EXT * result
Definition: glext.h:11304
GLfloat GLfloat p
Definition: glext.h:8902
GLuint GLuint num
Definition: glext.h:9618
GLenum GLsizei len
Definition: glext.h:6722
GLenum target
Definition: glext.h:7315
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
uint8_t u8_t
Definition: arch.h:125
#define LWIP_UNUSED_ARG(x)
Definition: arch.h:373
uint16_t u16_t
Definition: arch.h:127
int8_t s8_t
Definition: arch.h:126
s8_t err_t
Definition: err.h:96
@ ERR_INPROGRESS
Definition: err.h:65
@ ERR_OK
Definition: err.h:55
@ ERR_VAL
Definition: err.h:67
@ ERR_ARG
Definition: err.h:88
@ ERR_TIMEOUT
Definition: err.h:61
#define LWIP_ASSERT_CORE_LOCKED()
Definition: opt.h:227
#define SMEMCPY(dst, src, len)
Definition: opt.h:145
u16_t pbuf_memfind(const struct pbuf *p, const void *mem, u16_t mem_len, u16_t start_offset)
Definition: pbuf.c:1507
u8_t pbuf_get_at(const struct pbuf *p, u16_t offset)
Definition: pbuf.c:1402
void pbuf_cat(struct pbuf *h, struct pbuf *t)
Definition: pbuf.c:855
u8_t pbuf_free(struct pbuf *p)
Definition: pbuf.c:727
u16_t pbuf_copy_partial(const struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
Definition: pbuf.c:1058
#define SMTP_MAX_PASS_LEN
Definition: smtp_opts.h:39
#define SMTP_STATE_MALLOC(size)
Definition: smtp_opts.h:68
#define SMTP_MAX_SERVERNAME_LEN
Definition: smtp_opts.h:29
#define SMTP_MAX_USERNAME_LEN
Definition: smtp_opts.h:34
#define SMTP_STATE_FREE(ptr)
Definition: smtp_opts.h:69
_Check_return_ long __cdecl strtol(_In_z_ const char *_Str, _Out_opt_ _Deref_post_z_ char **_EndPtr, _In_ int _Radix)
ip6_addr_t ip_addr_t
Definition: ip_addr.h:344
#define ipaddr_aton(cp, addr)
Definition: ip_addr.h:387
#define IP_GET_TYPE(ipaddr)
Definition: ip_addr.h:354
#define ipaddr_ntoa(ipaddr)
Definition: ip_addr.h:385
static const int digits[]
Definition: decode.c:71
#define MEMCPY(DST, SRC, BYTES)
Definition: macros.h:231
struct task_struct * current
Definition: linux.c:32
static const WCHAR sp[]
Definition: suminfo.c:287
static WCHAR username[]
Definition: url.c:32
#define howmany(x, y)
Definition: multi.c:45
u16_t pbuf_strstr(const struct pbuf *p, const char *substr)
Definition: pbuf.c:1534
#define err(...)
strcpy
Definition: string.h:131
static const void * body(MD5_CTX *ctx, const void *data, unsigned long size)
Definition: md5.c:100
#define memset(x, y, z)
Definition: compat.h:39
err_t smtp_send_mail_static(const char *from, const char *to, const char *subject, const char *body, smtp_result_fn callback_fn, void *callback_arg)
err_t smtp_set_server_addr(const char *server)
#define SMTP_RESULT_ERR_CLOSED
Definition: smtp.h:26
void smtp_set_server_port(u16_t port)
#define SMTP_RESULT_OK
Definition: smtp.h:18
#define SMTP_RESULT_ERR_HOSTNAME
Definition: smtp.h:24
err_t smtp_set_auth(const char *username, const char *pass)
#define SMTP_RESULT_ERR_CONNECT
Definition: smtp.h:22
#define SMTP_RESULT_ERR_MEM
Definition: smtp.h:32
#define SMTP_DEFAULT_PORT
Definition: smtp.h:13
void(* smtp_result_fn)(void *arg, u8_t smtp_result, u16_t srv_err, err_t err)
Definition: smtp.h:42
#define SMTP_RESULT_ERR_UNKNOWN
Definition: smtp.h:20
void smtp_send_mail_int(void *arg)
#define SMTP_RESULT_ERR_TIMEOUT
Definition: smtp.h:28
#define SMTP_RESULT_ERR_SVR_RESP
Definition: smtp.h:30
err_t smtp_send_mail(const char *from, const char *to, const char *subject, const char *body, smtp_result_fn callback_fn, void *callback_arg)
CardRegion * from
Definition: spigame.cpp:19
Definition: pbuf.h:186
smtp_result_fn callback_fn
Definition: smtp.h:59
const char * body
Definition: smtp.h:58
const char * to
Definition: smtp.h:56
const char * from
Definition: smtp.h:55
u8_t static_data
Definition: smtp.h:65
void * callback_arg
Definition: smtp.h:60
const char * subject
Definition: smtp.h:57
pass
Definition: typegen.h:25
static rfbScreenInfoPtr server
Definition: vnc.c:74
int ret
static GLenum _GLUfuncptr fn
Definition: wgl_font.c:159