int sendmail_main(int argc, char *argv[]) { struct in_addr addr; #if defined(CONFIG_EXAMPLES_SENDMAIL_NOMAC) uint8_t mac[IFHWADDRLEN]; #endif void *handle; printf("sendmail: To: %s\n", g_recipient); printf("sendmail: From: %s\n", g_sender); printf("sendmail: Subject: %s\n", g_subject); printf("sendmail: Body: %s\n", g_msg_body); /* Many embedded network interfaces must have a software assigned MAC */ #ifdef CONFIG_EXAMPLES_SENDMAIL_NOMAC mac[0] = 0x00; mac[1] = 0xe0; mac[2] = 0xde; mac[3] = 0xad; mac[4] = 0xbe; mac[5] = 0xef; netlib_setmacaddr("eth0", mac); #endif /* Set up our host address */ addr.s_addr = HTONL(CONFIG_EXAMPLES_SENDMAIL_IPADDR); netlib_sethostaddr("eth0", &addr); /* Set up the default router address */ addr.s_addr = HTONL(CONFIG_EXAMPLES_SENDMAIL_DRIPADDR); netlib_setdraddr("eth0", &addr); /* Setup the subnet mask */ addr.s_addr = HTONL(CONFIG_EXAMPLES_SENDMAIL_NETMASK); netlib_setnetmask("eth0", &addr); /* Then send the mail */ net_ipaddr(addr.s_addr, 127, 0, 0, 1); handle = smtp_open(); if (handle) { smtp_configure(handle, g_host_name, &addr.s_addr); smtp_send(handle, g_recipient, NULL, g_sender, g_subject, g_msg_body, strlen(g_msg_body)); smtp_close(handle); } return 0; }
static err_t smtp_tcp_connected(void *arg, struct tcp_pcb *pcb, err_t err) { LWIP_UNUSED_ARG(arg); if (err == ERR_OK) { LWIP_DEBUGF(SMTP_DEBUG_STATE, ("smtp_connected: Waiting for 220\n")); } else { LWIP_DEBUGF(SMTP_DEBUG_WARN, ("smtp_connected: %d\n", (int)err)); smtp_close(arg, pcb, SMTP_RESULT_ERR_CONNECT, 0, err); } return ERR_OK; }
/** Raw API TCP recv callback */ static err_t smtp_tcp_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) { LWIP_UNUSED_ARG(err); if (p != NULL) { tcp_recved(pcb, p->tot_len); smtp_process(arg, pcb, p); } else { LWIP_DEBUGF(SMTP_DEBUG_WARN_STATE, ("smtp_tcp_recv: connection closed by remote host\n")); smtp_close(arg, pcb, SMTP_RESULT_ERR_CLOSED, 0, err); } return ERR_OK; }
static err_t smtp_tcp_connected(void *arg, struct altcp_pcb *pcb, err_t err) { LWIP_UNUSED_ARG(arg); if (err == ERR_OK) { LWIP_DEBUGF(SMTP_DEBUG_STATE, ("smtp_connected: Waiting for 220\n")); } else { /* shouldn't happen, but we still check 'err', only to be sure */ LWIP_DEBUGF(SMTP_DEBUG_WARN, ("smtp_connected: %d\n", (int)err)); smtp_close((struct smtp_session*)arg, pcb, SMTP_RESULT_ERR_CONNECT, 0, err); } return ERR_OK; }
void smtp_client::close() { if (client_) { // 将 SMTP_CLIENT 对象的流置空,以避免内部再次释放, // 因为该流对象会在下面 stream_.close() 时被释放 client_->conn = NULL; smtp_close(client_); client_ = NULL; } // 当 socket 流对象打开着,则关闭之,同时将依附于其的 SSL 对象释放 if (stream_.opened()) stream_.close(); // 重置连接是否被重用的状态 reuse_ = false; }
int return_mail(FILE *fp, email_hdr_t *eh, int flags, char *errstr) { int i; int len; FILE *nfp; char *p; char *incl; char *bincl; char *subj; char **sig; char **body; char *copy_addr; char *rtn_addr; char *tret; char *echo; char buf[CDDBBUFSIZ]; char subj_buf[CDDBBUFSIZ]; struct stat sbuf; int charset = -1; /* Create a temporary file for the mail. */ tret = cddbd_mktemp(); if(flags & MF_FAIL) { strncpy(buf, errstr, sizeof(buf)); buf[sizeof(buf) - 1] = '\0'; if((p = (char *)strchr(buf, '\n')) != NULL) *p = '\0'; } /* Return address is currently always the admin. */ rtn_addr = admin_email; switch(eh->eh_class) { case EC_COMMAND: /* Command response. */ if(flags & MF_FAIL) { cddbd_log(LOG_ERR | LOG_MAIL, "Email command failed: %s", buf); cddbd_snprintf(subj_buf, sizeof(subj_buf), cmd_rej_subj, eh->eh_serial); sig = gen_rej_sig; body = gen_rej_body; incl = gen_incl; bincl = gen_incl_blank; copy_addr = bounce_email; } else { cddbd_snprintf(subj_buf, sizeof(subj_buf), cmd_ok_subj, eh->eh_serial); sig = 0; body = 0; incl = null_incl; bincl = null_incl_blank; copy_addr = 0; } subj = subj_buf; break; case EC_SUBMIT: /* We only send mail for rejections and test submissions. */ if(flags & MF_FAIL) { if(flags & MF_TEST) { cddbd_log(LOG_ERR | LOG_MAIL, "Test email submission failed: %s", buf); subj = test_rej_subj; } else { cddbd_log(LOG_ERR | LOG_MAIL, "Email submission failed: %s", buf); subj = sub_rej_subj; } sig = gen_rej_sig; body = sub_rej_body; copy_addr = bounce_email; } else { sig = test_ok_sig; body = test_ok_body; subj = test_ok_subj; copy_addr = test_email; } incl = gen_incl; bincl = gen_incl_blank; charset = eh->eh_charset; break; default: /* subj = gen_rej_subj; body = gen_rej_body; sig = gen_rej_sig; incl = gen_incl; bincl = gen_incl_blank; copy_addr = bounce_email; break; */ /* Because of the increasing spam problem, we shouldn't be sending people all this mail which responds to spam sent to the freedb submission address. */ cddbd_freetemp(tret); return EE_OK; } if(eh->eh_flags & EH_ECHO) echo = eh->eh_echo; else echo = 0; if((nfp = fopen(tret, "w+")) == NULL) { cddbd_log(LOG_ERR | LOG_MAIL, "Can't create mail tmp file %s (%d)", tret, errno); return EE_ERROR; } /* Write out the note string. */ if(eh->eh_flags & EH_NOTE) { if(fprintf(nfp, note, eh->eh_note) == EOF) { cddbd_log(LOG_ERR | LOG_MAIL, "Can't write mail tmp file %s (%d)", tret, errno); fclose(nfp); cddbd_freetemp(tret); return EE_ERROR; } } /* Write out the err string. */ for(i = 0; body && body[i]; i++) { if(fprintf(nfp, body[i], errstr) == EOF) { cddbd_log(LOG_ERR | LOG_MAIL, "Can't write mail tmp file %s (%d)", tret, errno); fclose(nfp); cddbd_freetemp(tret); return EE_ERROR; } } rewind(fp); /* Write out the mail body. */ while(fgets(buf, sizeof(buf), fp) != NULL) { strip_crlf(buf); /* remove blank lines, skip nfp write */ if(is_blank(buf, 0)) p = bincl; else p = incl; /* zeke - remove the ## comment lines, exit - we are done */ if(is_DblHash(buf)) break; if(fprintf(nfp, p, buf) == EOF) { cddbd_log(LOG_ERR | LOG_MAIL, "Can't write mail tmp file %s (%d)", tret, errno); fclose(nfp); cddbd_freetemp(tret); return EE_ERROR; } } /*!zeke - correct comment follows ???? */ /* Write out the err string. */ for(i = 0; sig && sig[i]; i++) { if(fprintf(nfp, sig[i], admin_email) == EOF) { cddbd_log(LOG_ERR | LOG_MAIL, "Can't write mail tmp file %s (%d)", tret, errno); fclose(nfp); cddbd_freetemp(tret); return EE_ERROR; } } fflush(nfp); if(fstat(fileno(nfp), &sbuf)) len = 0; else len = sbuf.st_size; rewind(nfp); /* Figure out if we need to encode the mail. */ if(!(flags & (MF_ENC | MF_MULTI))) { while(fgets(buf, sizeof(buf), nfp) != NULL) { if(is_rfc_1521_mappable((unsigned char *)buf, 1, 0)) { flags |= MF_ENC; break; } } } rewind(nfp); if(!smtp_open()) { fclose(nfp); cddbd_freetemp(tret); return EE_ERROR; } if(!smtp_transmit(nfp, charset, subj, eh->eh_rcpt, eh->eh_to, rtn_addr, echo, flags, len, 0)) { fclose(nfp); cddbd_freetemp(tret); return EE_ERROR; } if(copy_addr != 0 && copy_addr[0] != '\0') { rewind(nfp); cddbd_snprintf(buf, sizeof(buf), "%s (fwd)", subj); if(!smtp_transmit(nfp, charset, buf, copy_addr, copy_addr, rtn_addr, echo, flags, len, 0)) { fclose(nfp); cddbd_freetemp(tret); return EE_ERROR; } } smtp_close(); fclose(nfp); cddbd_freetemp(tret); return EE_OK; }
/** State machine-like implementation of an SMTP client. */ static void smtp_process(void *arg, struct tcp_pcb *pcb, struct pbuf *p) { struct smtp_session* s = arg; u16_t response_code = 0; u16_t tx_buf_len = 0; enum smtp_session_state next_state; if (arg == NULL) { /* already closed SMTP connection */ if (p != NULL) { LWIP_DEBUGF(SMTP_DEBUG_TRACE, ("Received %d bytes after closing: %s\n", p->tot_len, smtp_pbuf_str(p))); pbuf_free(p); } return; } next_state = s->state; if (p != NULL) { /* received data */ if (s->p == NULL) { s->p = p; } else { pbuf_cat(s->p, p); } } else { /* idle timer, close connection if timed out */ if (s->timer == 0) { LWIP_DEBUGF(SMTP_DEBUG_WARN_STATE, ("smtp_process: connection timed out, closing\n")); smtp_close(s, pcb, SMTP_RESULT_ERR_TIMEOUT, 0, ERR_TIMEOUT); return; } if (s->state == SMTP_BODY) { smtp_send_body(s, pcb); return; } } response_code = smtp_is_response(s); if (response_code) { LWIP_DEBUGF(SMTP_DEBUG_TRACE, ("smtp_process: received response code: %d\n", response_code)); if (smtp_is_response_finished(s) != ERR_OK) { LWIP_DEBUGF(SMTP_DEBUG_TRACE, ("smtp_process: partly received response code: %d\n", response_code)); /* wait for next packet to complete the respone */ return; } } else { if (s->p != NULL) { LWIP_DEBUGF(SMTP_DEBUG_WARN, ("smtp_process: unknown data received (%s)\n", smtp_pbuf_str(s->p))); pbuf_free(s->p); s->p = NULL; } return; } switch(s->state) { case(SMTP_NULL): /* wait for 220 */ if (response_code == 220) { /* then send EHLO */ next_state = smtp_prepare_helo(s, &tx_buf_len, pcb); } break; case(SMTP_HELO): /* wait for 250 */ if (response_code == 250) { #if SMTP_SUPPORT_AUTH_AUTH || SMTP_SUPPORT_AUTH_LOGIN /* then send AUTH or MAIL */ next_state = smtp_prepare_auth_or_mail(s, &tx_buf_len); } break; case(SMTP_AUTH_LOGIN): case(SMTP_AUTH_PLAIN): /* wait for 235 */ if (response_code == 235) { #endif /* SMTP_SUPPORT_AUTH_AUTH || SMTP_SUPPORT_AUTH_LOGIN */ /* send MAIL */ next_state = smtp_prepare_mail(s, &tx_buf_len); } break; #if SMTP_SUPPORT_AUTH_LOGIN case(SMTP_AUTH_LOGIN_UNAME): /* wait for 334 Username */ if (response_code == 334) { if (pbuf_strstr(s->p, SMTP_RESP_LOGIN_UNAME) != 0xFFFF) { /* send username */ next_state = smtp_prepare_auth_login_uname(s, &tx_buf_len); } } break; case(SMTP_AUTH_LOGIN_PASS): /* wait for 334 Password */ if (response_code == 334) { if (pbuf_strstr(s->p, SMTP_RESP_LOGIN_PASS) != 0xFFFF) { /* send username */ next_state = smtp_prepare_auth_login_pass(s, &tx_buf_len); } } break; #endif /* SMTP_SUPPORT_AUTH_LOGIN */ case(SMTP_MAIL): /* wait for 250 */ if (response_code == 250) { /* send RCPT */ next_state = smtp_prepare_rcpt(s, &tx_buf_len); } break; case(SMTP_RCPT): /* wait for 250 */ if (response_code == 250) { /* send DATA */ SMEMCPY(s->tx_buf, SMTP_CMD_DATA, SMTP_CMD_DATA_LEN); tx_buf_len = SMTP_CMD_DATA_LEN; next_state = SMTP_DATA; } break; case(SMTP_DATA): /* wait for 354 */ if (response_code == 354) { /* send email header */ next_state = smtp_prepare_header(s, &tx_buf_len); } break; case(SMTP_BODY): /* nothing to be done here, handled somewhere else */ break; case(SMTP_QUIT): /* wait for 250 */ if (response_code == 250) { /* send QUIT */ next_state = smtp_prepare_quit(s, &tx_buf_len); } break; case(SMTP_CLOSED): /* nothing to do, wait for connection closed from server */ return; default: LWIP_DEBUGF(SMTP_DEBUG_SERIOUS, ("Invalid state: %d/%s\n", (int)s->state, smtp_state_str[s->state])); break; } if (s->state == next_state) { LWIP_DEBUGF(SMTP_DEBUG_WARN_STATE, ("smtp_process[%s]: unexpected response_code, closing: %d (%s)\n", smtp_state_str[s->state], response_code, smtp_pbuf_str(s->p))); /* close connection */ smtp_close(s, pcb, SMTP_RESULT_ERR_SVR_RESP, response_code, ERR_OK); return; } if (tx_buf_len > 0) { SMTP_TX_BUF_MAX(tx_buf_len); if (tcp_write(pcb, s->tx_buf, tx_buf_len, TCP_WRITE_FLAG_COPY) == ERR_OK) { LWIP_DEBUGF(SMTP_DEBUG_TRACE, ("smtp_process[%s]: received command %d (%s)\n", smtp_state_str[s->state], response_code, smtp_pbuf_str(s->p))); LWIP_DEBUGF(SMTP_DEBUG_TRACE, ("smtp_process[%s]: sent %"U16_F" bytes: \"%s\"\n", smtp_state_str[s->state], tx_buf_len, s->tx_buf)); s->timer = SMTP_TIMEOUT; pbuf_free(s->p); s->p = NULL; LWIP_DEBUGF(SMTP_DEBUG_STATE, ("smtp_process: changing state from %s to %s\n", smtp_state_str[s->state], smtp_state_str[next_state])); s->state = next_state; if (next_state == SMTP_BODY) { /* try to stream-send body data right now */ smtp_send_body(s, pcb); } else if (next_state == SMTP_CLOSED) { /* sent out all data, delete structure */ tcp_arg(pcb, NULL); smtp_free(s, SMTP_RESULT_OK, 0, ERR_OK); } } } }
SENDSTREAM *smtp_open_full (NETDRIVER *dv,char **hostlist,char *service, unsigned long port,long options) { SENDSTREAM *stream = NIL; long reply; char *s,tmp[MAILTMPLEN]; NETSTREAM *netstream; NETMBX mb; if (!(hostlist && *hostlist)) mm_log ("Missing SMTP service host",ERROR); /* maximum domain name is 64 characters */ else do if (strlen (*hostlist) < SMTPMAXDOMAIN) { sprintf (tmp,"{%.1000s}",*hostlist); if (!mail_valid_net_parse_work (tmp,&mb,service ? service : "smtp") || mb.anoflag || mb.readonlyflag) { sprintf (tmp,"Invalid host specifier: %.80s",*hostlist); mm_log (tmp,ERROR); } else { /* light tryssl flag if requested */ mb.trysslflag = (options & SOP_TRYSSL) ? T : NIL; /* explicit port overrides all */ if (mb.port) port = mb.port; /* else /submit overrides port argument */ else if (!compare_cstring (mb.service,"submit")) { port = SUBMITTCPPORT; /* override port, use IANA name */ strcpy (mb.service,"submission"); } /* else port argument overrides SMTP port */ else if (!port) port = smtp_port ? smtp_port : SMTPTCPPORT; if (netstream = /* try to open ordinary connection */ net_open (&mb,dv,port, (NETDRIVER *) mail_parameters (NIL,GET_SSLDRIVER,NIL), "*smtps",smtp_sslport ? smtp_sslport : SMTPSSLPORT)) { stream = (SENDSTREAM *) memset (fs_get (sizeof (SENDSTREAM)),0, sizeof (SENDSTREAM)); stream->netstream = netstream; stream->host = cpystr ((long) mail_parameters (NIL,GET_TRUSTDNS,NIL) ? net_host (netstream) : mb.host); stream->debug = (mb.dbgflag || (options & OP_DEBUG)) ? T : NIL; if (options & SOP_SECURE) mb.secflag = T; /* get name of local host to use */ s = compare_cstring ("localhost",mb.host) ? net_localhost (netstream) : "localhost"; do reply = smtp_reply (stream); while ((reply < 100) || (stream->reply[3] == '-')); if (reply != SMTPGREET){/* get SMTP greeting */ sprintf (tmp,"SMTP greeting failure: %.80s",stream->reply); mm_log (tmp,ERROR); stream = smtp_close (stream); } /* try EHLO first, then HELO */ else if (((reply = smtp_ehlo (stream,s,&mb)) != SMTPOK) && ((reply = smtp_send (stream,"HELO",s)) != SMTPOK)) { sprintf (tmp,"SMTP hello failure: %.80s",stream->reply); mm_log (tmp,ERROR); stream = smtp_close (stream); } else { NETDRIVER *ssld =(NETDRIVER *)mail_parameters(NIL,GET_SSLDRIVER,NIL); sslstart_t stls = (sslstart_t) mail_parameters(NIL,GET_SSLSTART,NIL); ESMTP.ok = T; /* ESMTP server, start TLS if present */ if (!dv && stls && ESMTP.service.starttls && !mb.sslflag && !mb.notlsflag && (smtp_send (stream,"STARTTLS",NIL) == SMTPGREET)) { mb.tlsflag = T; /* TLS OK, get into TLS at this end */ stream->netstream->dtb = ssld; /* TLS started, negotiate it */ if (!(stream->netstream->stream = (*stls) (stream->netstream->stream,mb.host, (mb.tlssslv23 ? NIL : NET_TLSCLIENT) | (mb.novalidate ? NET_NOVALIDATECERT:NIL)))){ /* TLS negotiation failed after STARTTLS */ sprintf (tmp,"Unable to negotiate TLS with this server: %.80s", mb.host); mm_log (tmp,ERROR); /* close without doing QUIT */ if (stream->netstream) net_close (stream->netstream); stream->netstream = NIL; stream = smtp_close (stream); } /* TLS OK, re-negotiate EHLO */ else if ((reply = smtp_ehlo (stream,s,&mb)) != SMTPOK) { sprintf (tmp,"SMTP EHLO failure after STARTTLS: %.80s", stream->reply); mm_log (tmp,ERROR); stream = smtp_close (stream); } else ESMTP.ok = T; /* TLS OK and EHLO successful */ } else if (mb.tlsflag) {/* user specified /tls but can't do it */ sprintf (tmp,"TLS unavailable with this server: %.80s",mb.host); mm_log (tmp,ERROR); stream = smtp_close (stream); } /* remote name for authentication */ if (stream && ((mb.secflag || mb.user[0]))) { if (ESMTP.auth) { /* use authenticator? */ if ((long) mail_parameters (NIL,GET_TRUSTDNS,NIL)) { /* remote name for authentication */ strncpy (mb.host, (long) mail_parameters (NIL,GET_SASLUSESPTRNAME,NIL) ? net_remotehost (netstream) : net_host (netstream), NETMAXHOST-1); mb.host[NETMAXHOST-1] = '\0'; } if (!smtp_auth (stream,&mb,tmp)) stream = smtp_close (stream); } else { /* no available authenticators? */ sprintf (tmp,"%sSMTP authentication not available: %.80s", mb.secflag ? "Secure " : "",mb.host); mm_log (tmp,ERROR); stream = smtp_close (stream); } } } } } } while (!stream && *++hostlist); if (stream) { /* set stream options if have a stream */ if (options &(SOP_DSN | SOP_DSN_NOTIFY_FAILURE | SOP_DSN_NOTIFY_DELAY | SOP_DSN_NOTIFY_SUCCESS | SOP_DSN_RETURN_FULL)) { ESMTP.dsn.want = T; if (options & SOP_DSN_NOTIFY_FAILURE) ESMTP.dsn.notify.failure = T; if (options & SOP_DSN_NOTIFY_DELAY) ESMTP.dsn.notify.delay = T; if (options & SOP_DSN_NOTIFY_SUCCESS) ESMTP.dsn.notify.success = T; if (options & SOP_DSN_RETURN_FULL) ESMTP.dsn.full = T; } if (options & SOP_8BITMIME) ESMTP.eightbit.want = T; } return stream; }