| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- #include "smtp.h"
- #include "hsocket.h"
- #include "herr.h"
- #include "base64.h"
- const char* smtp_command_str(enum smtp_command cmd) {
- switch (cmd) {
- #define XX(name, string) case SMTP_##name: return #string;
- SMTP_COMMAND_MAP(XX)
- #undef XX
- default: return "<unknown>";
- }
- }
- const char* smtp_status_str(enum smtp_status status) {
- switch (status) {
- #define XXX(code, name, string) case SMTP_STATUS_##name: return #string;
- SMTP_STATUS_MAP(XXX)
- #undef XXX
- default: return "<unknown>";
- }
- }
- int smtp_build_command(enum smtp_command cmd, const char* param, char* buf, int buflen) {
- switch (cmd) {
- // unary
- case SMTP_DATA:
- case SMTP_QUIT:
- return snprintf(buf, buflen, "%s\r\n", smtp_command_str(cmd));
- // <address>
- case SMTP_MAIL:
- case SMTP_RCPT:
- return snprintf(buf, buflen, "%s <%s>\r\n", smtp_command_str(cmd), param);
- default:
- return snprintf(buf, buflen, "%s %s\r\n", smtp_command_str(cmd), param);
- }
- }
- // EHLO => AUTH PLAIN => MAIL => RCPT => DATA => data => EOB => QUIT
- int sendmail(const char* smtp_server,
- const char* username,
- const char* password,
- mail_t* mail) {
- char buf[1024] = {0};
- int buflen = sizeof(buf);
- int cmdlen = 0;
- int status_code = 0;
- char basic[256];
- int basiclen;
- int sockfd = ConnectTimeout(smtp_server, SMTP_PORT, DEFAULT_CONNECT_TIMEOUT);
- if (sockfd < 0) {
- return sockfd;
- }
- so_sndtimeo(sockfd, 5000);
- so_rcvtimeo(sockfd, 5000);
- int ret, nsend, nrecv;
- nrecv = recv(sockfd, buf, buflen, 0);
- if (nrecv <= 0) {
- ret = ERR_RECV;
- goto error;
- }
- status_code = atoi(buf);
- if (status_code != SMTP_STATUS_READY) {
- ret = status_code;
- goto error;
- }
- // EHLO smtp.xxx.com\r\n
- cmdlen = smtp_build_command(SMTP_EHLO, smtp_server, buf, buflen);
- nsend = send(sockfd, buf, cmdlen, 0);
- if (nsend != cmdlen) {
- ret = ERR_SEND;
- goto error;
- }
- nrecv = recv(sockfd, buf, buflen, 0);
- if (nrecv <= 0) {
- ret = ERR_RECV;
- goto error;
- }
- status_code = atoi(buf);
- if (status_code != SMTP_STATUS_OK) {
- ret = status_code;
- goto error;
- }
- // AUTH PLAIN\r\n
- cmdlen = smtp_build_command(SMTP_AUTH, "PLAIN", buf, buflen);
- nsend = send(sockfd, buf, cmdlen, 0);
- if (nsend != cmdlen) {
- ret = ERR_SEND;
- goto error;
- }
- nrecv = recv(sockfd, buf, buflen, 0);
- if (nrecv <= 0) {
- ret = ERR_RECV;
- goto error;
- }
- status_code = atoi(buf);
- if (status_code != SMTP_STATUS_AUTH) {
- ret = status_code;
- goto error;
- }
- {
- // BASE64 \0username\0password
- int usernamelen = strlen(username);
- int passwordlen = strlen(password);
- basic[0] = '\0';
- memcpy(basic+1, username, usernamelen);
- basic[1+usernamelen] = '\0';
- memcpy(basic+1+usernamelen+1, password, passwordlen);
- basiclen = 1 + usernamelen + 1 + passwordlen;
- }
- hv_base64_encode((unsigned char*)basic, basiclen, buf);
- cmdlen = BASE64_ENCODE_OUT_SIZE(basiclen);
- buf[cmdlen] = '\r';
- buf[cmdlen+1] = '\n';
- cmdlen += 2;
- nsend = send(sockfd, buf, cmdlen, 0);
- if (nsend != cmdlen) {
- ret = ERR_SEND;
- goto error;
- }
- nrecv = recv(sockfd, buf, buflen, 0);
- if (nrecv <= 0) {
- ret = ERR_RECV;
- goto error;
- }
- status_code = atoi(buf);
- if (status_code != SMTP_STATUS_AUTH_SUCCESS) {
- ret = status_code;
- goto error;
- }
- // MAIL FROM: <from>\r\n
- cmdlen = smtp_build_command(SMTP_MAIL, mail->from, buf, buflen);
- nsend = send(sockfd, buf, cmdlen, 0);
- if (nsend != cmdlen) {
- ret = ERR_SEND;
- goto error;
- }
- nrecv = recv(sockfd, buf, buflen, 0);
- if (nrecv <= 0) {
- ret = ERR_RECV;
- goto error;
- }
- status_code = atoi(buf);
- if (status_code != SMTP_STATUS_OK) {
- ret = status_code;
- goto error;
- }
- // RCPT TO: <to>\r\n
- cmdlen = smtp_build_command(SMTP_RCPT, mail->to, buf, buflen);
- nsend = send(sockfd, buf, cmdlen, 0);
- if (nsend != cmdlen) {
- ret = ERR_SEND;
- goto error;
- }
- nrecv = recv(sockfd, buf, buflen, 0);
- if (nrecv <= 0) {
- ret = ERR_RECV;
- goto error;
- }
- status_code = atoi(buf);
- if (status_code != SMTP_STATUS_OK) {
- ret = status_code;
- goto error;
- }
- // DATA\r\n
- cmdlen = smtp_build_command(SMTP_DATA, NULL, buf, buflen);
- nsend = send(sockfd, buf, cmdlen, 0);
- if (nsend != cmdlen) {
- ret = ERR_SEND;
- goto error;
- }
- nrecv = recv(sockfd, buf, buflen, 0);
- if (nrecv <= 0) {
- ret = ERR_RECV;
- goto error;
- }
- status_code = atoi(buf);
- // SMTP_STATUS_DATA
- if (status_code >= 400) {
- ret = status_code;
- goto error;
- }
- // From:
- cmdlen = snprintf(buf, buflen, "From:%s\r\n", mail->from);
- nsend = send(sockfd, buf, cmdlen, 0);
- if (nsend != cmdlen) {
- ret = ERR_SEND;
- goto error;
- }
- // To:
- cmdlen = snprintf(buf, buflen, "To:%s\r\n", mail->to);
- nsend = send(sockfd, buf, cmdlen, 0);
- if (nsend != cmdlen) {
- ret = ERR_SEND;
- goto error;
- }
- // Subject:
- cmdlen = snprintf(buf, buflen, "Subject:%s\r\n\r\n", mail->subject);
- nsend = send(sockfd, buf, cmdlen, 0);
- if (nsend != cmdlen) {
- ret = ERR_SEND;
- goto error;
- }
- // body
- cmdlen = strlen(mail->body);
- nsend = send(sockfd, mail->body, cmdlen, 0);
- if (nsend != cmdlen) {
- ret = ERR_SEND;
- goto error;
- }
- // EOB
- nsend = send(sockfd, SMTP_EOB, SMTP_EOB_LEN, 0);
- if (nsend != SMTP_EOB_LEN) {
- ret = ERR_SEND;
- goto error;
- }
- nrecv = recv(sockfd, buf, buflen, 0);
- if (nrecv <= 0) {
- ret = ERR_SEND;
- goto error;
- }
- status_code = atoi(buf);
- if (status_code != SMTP_STATUS_OK) {
- ret = status_code;
- goto error;
- }
- // QUIT\r\n
- cmdlen = smtp_build_command(SMTP_QUIT, NULL, buf, buflen);
- nsend = send(sockfd, buf, cmdlen, 0);
- if (nsend != cmdlen) {
- ret = ERR_SEND;
- goto error;
- }
- nrecv = recv(sockfd, buf, buflen, 0);
- if (nrecv <= 0) {
- ret = ERR_RECV;
- goto error;
- }
- /*
- status_code = atoi(buf);
- if (status_code != SMTP_STATUS_BYE) {
- ret = status_code;
- goto error;
- }
- */
- ret = SMTP_STATUS_OK;
- error:
- if (sockfd != INVALID_SOCKET) {
- closesocket(sockfd);
- }
- return ret;
- }
|