00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044 #include <sys/nutdebug.h>
00045 #include <sys/confnet.h>
00046 #include <sys/socket.h>
00047
00048 #include <arpa/inet.h>
00049 #include <pro/rfctime.h>
00050
00051 #include <memdebug.h>
00052 #include <string.h>
00053
00054 #include <pro/smtpc.h>
00055
00060
00061 #ifndef SMTP_TIMEOUT
00062 #define SMTP_TIMEOUT 600000
00063 #endif
00064
00087 static void NutBase64Encode(CONST uint8_t * sptr, size_t slen, char *dptr)
00088 {
00089 static CONST char base64set[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00090 uint_fast8_t i;
00091 uint32_t blk;
00092 uint_fast8_t pad = 0;
00093
00094
00095 NUTASSERT(sptr != NULL);
00096 NUTASSERT(dptr != NULL);
00097
00098 while (slen) {
00099 blk = (uint32_t) (*sptr++) << 16;
00100 if (slen > 1) {
00101 blk |= (uint32_t) (*sptr++) << 8;
00102 if (slen > 2) {
00103 blk |= *sptr++;
00104 } else {
00105 pad = 1;
00106 }
00107 } else {
00108 pad = 2;
00109 }
00110 for (i = pad; i < 4; i++) {
00111 *dptr++ = base64set[(blk >> 18) & 63];
00112 blk <<= 6;
00113 }
00114 for (i = 0; i < pad; i++) {
00115 *dptr++ = '=';
00116 }
00117 slen -= 3 - pad;
00118 }
00119 *dptr = '\0';
00120 }
00121
00129 CONST char *NutSmtpReceiveResponse(SMTPCLIENTSESSION * si)
00130 {
00131 char *cp;
00132
00133
00134 NUTASSERT(si != NULL);
00135
00136 if (fgets(si->smtp_buff, sizeof(si->smtp_buff), si->smtp_stream)) {
00137 cp = strchr(si->smtp_buff, '\r');
00138 if (cp == NULL) {
00139 cp = strchr(si->smtp_buff, '\n');
00140 }
00141 if (cp) {
00142 *cp = '\0';
00143 return si->smtp_buff;
00144 }
00145
00146 }
00147 return NULL;
00148 }
00149
00159 CONST char *NutSmtpSendCommand(SMTPCLIENTSESSION * si, CONST char *fmt, ...)
00160 {
00161 va_list ap;
00162
00163
00164 NUTASSERT(si != NULL);
00165 NUTASSERT(fmt != NULL);
00166
00167 va_start(ap, fmt);
00168 vfprintf(si->smtp_stream, (char *) fmt, ap);
00169 va_end(ap);
00170 fputs("\r\n", si->smtp_stream);
00171 fflush(si->smtp_stream);
00172
00173 return NutSmtpReceiveResponse(si);
00174 }
00175
00184 void NutSmtpDisconnect(SMTPCLIENTSESSION * si)
00185 {
00186
00187 NUTASSERT(si != NULL);
00188
00189 if (si->smtp_sock) {
00190 if (si->smtp_stream) {
00191 NutSmtpSendCommand(si, "QUIT");
00192 fclose(si->smtp_stream);
00193 }
00194 NutTcpCloseSocket(si->smtp_sock);
00195 }
00196 free(si);
00197 }
00198
00209 SMTPCLIENTSESSION *NutSmtpConnect(uint32_t ip, uint16_t port)
00210 {
00211 SMTPCLIENTSESSION *si;
00212
00213 si = calloc(1, sizeof(SMTPCLIENTSESSION));
00214 if (si) {
00215 si->smtp_sock = NutTcpCreateSocket();
00216 if (si->smtp_sock && NutTcpConnect(si->smtp_sock, ip, port) == 0) {
00217 uint32_t tmo = SMTP_TIMEOUT;
00218 NutTcpSetSockOpt(si->smtp_sock, SO_RCVTIMEO, &tmo, sizeof(tmo));
00219 si->smtp_stream = _fdopen((int) ((intptr_t) si->smtp_sock), "r+b");
00220 if (si->smtp_stream && *NutSmtpReceiveResponse(si) == '2') {
00221 return si;
00222 }
00223 }
00224 NutSmtpDisconnect(si);
00225 }
00226 return NULL;
00227 }
00228
00239 static CONST char *SayHello(SMTPCLIENTSESSION * si, char *cmd, char *host)
00240 {
00241 if (host) {
00242 return NutSmtpSendCommand(si, "%s %s", cmd, host);
00243 }
00244 return NutSmtpSendCommand(si, "%s [%s]", cmd, inet_ntoa(confnet.cdn_ip_addr));
00245 }
00246
00258 int NutSmtpLogin(SMTPCLIENTSESSION * si, char *host, char *user, char *pass)
00259 {
00260 CONST char *rsp;
00261
00262
00263 NUTASSERT(si != NULL);
00264
00265
00266 rsp = SayHello(si, "EHLO", host);
00267 if (rsp && *rsp == '5') {
00268
00269 si->smtp_feat |= SMTPFEAT_VINTAGE;
00270 rsp = SayHello(si, "HELO", host);
00271 }
00272 if (rsp && *rsp == '2') {
00273 if ((si->smtp_feat & SMTPFEAT_VINTAGE) != SMTPFEAT_VINTAGE) {
00274 for (;;) {
00275 if (strncmp(rsp + 4, "AUTH ", 5) == 0) {
00276 if (strstr(rsp + 9, "LOGIN")) {
00277 si->smtp_feat |= SMTPFEAT_AUTH_LOGIN;
00278 }
00279 if (strstr(rsp + 9, "PLAIN")) {
00280 si->smtp_feat |= SMTPFEAT_AUTH_PLAIN;
00281 }
00282 }
00283 if (*(rsp + 3) != '-') {
00284 break;
00285 }
00286 rsp = NutSmtpReceiveResponse(si);
00287 if (rsp == NULL) {
00288 break;
00289 }
00290 }
00291 }
00292 if (user == NULL) {
00293
00294 return 0;
00295 }
00296 if (si->smtp_feat & SMTPFEAT_AUTH_PLAIN) {
00297 int lu = strlen(user);
00298 int lp = strlen(pass);
00299 uint8_t *auth = malloc(lu + lp + 3);
00300
00301 *auth = '\0';
00302 memcpy(auth + 1, user, lu + 1);
00303 memcpy(auth + 1 + lu + 1, pass, lp);
00304
00305 NutBase64Encode(auth, lu + lp + 2, si->smtp_buff);
00306 rsp = NutSmtpSendCommand(si, "AUTH PLAIN %s", si->smtp_buff);
00307 if (rsp && *rsp == '2') {
00308 return 0;
00309 }
00310 } else if (si->smtp_feat & SMTPFEAT_AUTH_LOGIN) {
00311 }
00312 }
00313 return -1;
00314 }
00315
00328 int NutSmtpSendMailRequest(SMTPCLIENTSESSION * si, MAILENVELOPE * me)
00329 {
00330 int rc = 0;
00331 CONST char *rsp;
00332
00333
00334 NUTASSERT(me != NULL);
00335
00336 rsp = NutSmtpSendCommand(si, "MAIL FROM:%s", me->mail_from);
00337 if (rsp && *rsp == '2') {
00338 int i;
00339
00340 for (i = 0; i < MAX_MAIL_RCPTS; i++) {
00341
00342 if (me->mail_rcpt[i] && (me->mail_rcpt_stat[i] & MAIL_RCPT_DONE) == 0) {
00343 rsp = NutSmtpSendCommand(si, "RCPT TO:%s", me->mail_rcpt[i]);
00344 if (rsp) {
00345 if (*rsp == '2') {
00346
00347 me->mail_rcpt_stat[i] |= MAIL_RCPT_ACPT;
00348 rc++;
00349 } else {
00350
00351 me->mail_rcpt_stat[i] &= ~MAIL_RCPT_ACPT;
00352 if (*rsp == '5') {
00353
00354 me->mail_rcpt_stat[i] |= MAIL_RCPT_FAIL;
00355 }
00356 }
00357 }
00358 }
00359 }
00360 }
00361 return rc;
00362 }
00363
00371 static int SendMailHeaderRecipient(FILE *stream, MAILENVELOPE * me, uint8_t type)
00372 {
00373 uint_fast8_t i;
00374 int cnt;
00375
00376
00377 for (i = 0, cnt = 0; i < MAX_MAIL_RCPTS; i++) {
00378
00379 if ((me->mail_rcpt_stat[i] & MAIL_RCPT_TYPE) == type) {
00380 if (cnt) {
00381
00382 fputs(",\r\n ", stream);
00383 } else {
00384
00385 fputs(type == MAIL_RCPT_TO ? "To: " : "CC: ", stream);
00386 }
00387 fputs(me->mail_rcpt_header[i], stream);
00388 cnt++;
00389 }
00390 }
00391 if (cnt) {
00392 fputs("\r\n", stream);
00393 }
00394 return 0;
00395 }
00396
00423 int NutSmtpSendMailHeader(SMTPCLIENTSESSION * si, MAILENVELOPE * me)
00424 {
00425
00426 NUTASSERT(si != NULL);
00427 NUTASSERT(si->smtp_stream != NULL);
00428 NUTASSERT(me != NULL);
00429
00430 if (me->mail_date) {
00431 fprintf(si->smtp_stream, "Date: %s\r\n", Rfc1123TimeString(gmtime(&me->mail_date)));
00432 }
00433 fprintf(si->smtp_stream, "From: %s\r\n", me->mail_from_header);
00434 fprintf(si->smtp_stream, "Subject: %s\r\n", me->mail_subj);
00435 SendMailHeaderRecipient(si->smtp_stream, me, MAIL_RCPT_TO);
00436 SendMailHeaderRecipient(si->smtp_stream, me, MAIL_RCPT_CC);
00437
00438 return 0;
00439 }
00440
00459 int NutSmtpSendEncodedLines(SMTPCLIENTSESSION * si, CONST char *text)
00460 {
00461
00462 NUTASSERT(si != NULL);
00463 NUTASSERT(text != NULL);
00464
00465 while (*text) {
00466 char *bufp = si->smtp_buff;
00467 int i;
00468
00469
00470 for (i = 0; *text && i < SMTP_BUFSIZ; text++) {
00471
00472 if (*text != '\r') {
00473
00474 if (*text == '\n' || *text == '\0') {
00475
00476 i++;
00477 text++;
00478 break;
00479 } else {
00480
00481 *bufp++ = *text;
00482 i++;
00483 }
00484 }
00485 }
00486 if (i) {
00487 *bufp = '\0';
00488
00489 if (si->smtp_buff[0] == '.') {
00490 fputc('.', si->smtp_stream);
00491 }
00492
00493 fputs(si->smtp_buff, si->smtp_stream);
00494 if (fputs("\r\n", si->smtp_stream) == EOF) {
00495
00496 return -1;
00497 }
00498 }
00499 }
00500 return 0;
00501 }
00502
00540 CONST char *NutSmtpSendMail(SMTPCLIENTSESSION * si, MAILENVELOPE * me)
00541 {
00542 CONST char *rsp = NULL;
00543
00544
00545 NUTASSERT(si != NULL);
00546 NUTASSERT(me != NULL);
00547
00548
00549
00550 if (NutSmtpSendMailRequest(si, me) > 0) {
00551
00552 rsp = NutSmtpSendCommand(si, "DATA");
00553
00554 if (rsp && *rsp == '3') {
00555
00556 NutSmtpSendMailHeader(si, me);
00557 fputs("\r\n", si->smtp_stream);
00558
00559 if (me->mail_body) {
00560 NutSmtpSendEncodedLines(si, me->mail_body);
00561 }
00562 fputs(".\r\n", si->smtp_stream);
00563 fflush(si->smtp_stream);
00564
00565 rsp = NutSmtpReceiveResponse(si);
00566
00567
00568 if (rsp && *rsp == '2') {
00569 uint_fast8_t i;
00570 for (i = 0; i < MAX_MAIL_RCPTS; i++) {
00571 if (me->mail_rcpt[i]) {
00572 if ((me->mail_rcpt_stat[i] & MAIL_RCPT_ACPT) == MAIL_RCPT_ACPT) {
00573 me->mail_rcpt_stat[i] |= MAIL_RCPT_SENT;
00574 }
00575 }
00576 }
00577 }
00578 }
00579 }
00580 return rsp;
00581 }
00582