📄 smtp.c
字号:
* Returns: T on success, NIL on failure */long smtp_mail (SENDSTREAM *stream,char *type,ENVELOPE *env,BODY *body){ /* Note: This assumes that the envelope will never generate a header of * more than 8K. If your client generates godzilla headers, you will * need to install your own rfc822out_t routine via SET_RFC822OUTPUT * to use in place of this. */ char tmp[8*MAILTMPLEN]; long error = NIL; if (!(env->to || env->cc || env->bcc)) { /* no recipients in request */ smtp_fake (stream,SMTPHARDERROR,"No recipients specified"); return NIL; } smtp_send (stream,"RSET",NIL);/* make sure stream is in good shape */ strcpy (tmp,"FROM:<"); /* compose "MAIL FROM:<return-path>" */ if (env->return_path && env->return_path->host && !((env->return_path->adl && (strlen (env->return_path->adl) > SMTPMAXPATH)) || (strlen (env->return_path->mailbox) > SMTPMAXLOCALPART) || (strlen (env->return_path->host) > SMTPMAXDOMAIN))) rfc822_address (tmp,env->return_path); strcat (tmp,">"); if (ESMTP.ok) { if (ESMTP.eightbit.ok && ESMTP.eightbit.want) strcat(tmp," BODY=8BITMIME"); if (ESMTP.dsn.ok && ESMTP.dsn.want) strcat (tmp,ESMTP.dsn.full ? " RET=FULL" : " RET=HDRS"); } /* send "MAIL FROM" command */ if (!(smtp_send (stream,type,tmp) == SMTPOK)) return NIL; /* negotiate the recipients */ if (env->to) smtp_rcpt (stream,env->to,&error); if (env->cc) smtp_rcpt (stream,env->cc,&error); if (env->bcc) smtp_rcpt (stream,env->bcc,&error); if (error) { /* any recipients failed? */ /* reset the stream */ smtp_send (stream,"RSET",NIL); smtp_fake (stream,SMTPHARDERROR,"One or more recipients failed"); return NIL; } /* negotiate data command */ if (!(smtp_send (stream,"DATA",NIL) == SMTPREADY)) return NIL; /* set up error in case failure */ smtp_fake (stream,SMTPSOFTFATAL,"SMTP connection went away!"); /* output data, return success status */ return rfc822_output (tmp,env,body,smtp_soutr,stream->netstream, ESMTP.eightbit.ok && ESMTP.eightbit.want) && (smtp_send (stream,".",NIL) == SMTPOK);}/* Internal routines *//* Simple Mail Transfer Protocol send recipient * Accepts: SMTP stream * address list * pointer to error flag */void smtp_rcpt (SENDSTREAM *stream,ADDRESS *adr,long *error){ char *s,tmp[MAILTMPLEN]; while (adr) { /* for each address on the list */ /* clear any former error */ if (adr->error) fs_give ((void **) &adr->error); if (adr->host) { /* ignore group syntax */ /* enforce SMTP limits to protect the buffer */ if (adr->adl && (strlen (adr->adl) > SMTPMAXPATH)) { adr->error = cpystr ("501 Path too long"); *error = T; } else if (strlen (adr->mailbox) > MAXLOCALPART) { adr->error = cpystr ("501 Recipient name too long"); *error = T; } if ((strlen (adr->host) > SMTPMAXDOMAIN)) { adr->error = cpystr ("501 Recipient domain too long"); *error = T; } else { strcpy (tmp,"TO:<"); /* compose "RCPT TO:<return-path>" */ rfc822_address (tmp,adr); strcat (tmp,">"); /* want notifications */ if (ESMTP.ok && ESMTP.dsn.ok && ESMTP.dsn.want) { /* yes, start with prefix */ strcat (tmp," NOTIFY="); s = tmp + strlen (tmp); if (ESMTP.dsn.notify.failure) strcat (s,"FAILURE,"); if (ESMTP.dsn.notify.delay) strcat (s,"DELAY,"); if (ESMTP.dsn.notify.success) strcat (s,"SUCCESS,"); /* tie off last comma */ if (*s) s[strlen (s) - 1] = '\0'; else strcat (tmp,"NEVER"); } /* send "RCPT TO" command */ if (!(smtp_send (stream,"RCPT",tmp) == SMTPOK)) { *error = T; /* note that an error occurred */ adr->error = cpystr (stream->reply); } } } adr = adr->next; /* do any subsequent recipients */ }}/* Simple Mail Transfer Protocol send command * Accepts: SMTP stream * text * Returns: reply code */long smtp_send (SENDSTREAM *stream,char *command,char *args){ long ret; do ret = smtp_send_work (stream,command,args); while (ESMTP.auth && smtp_send_auth (stream,ret)); return ret;}/* SMTP send command worker routine * Accepts: SEND stream * text * Returns: reply code */long smtp_send_work (SENDSTREAM *stream,char *command,char *args){ long ret; char *s = (char *) fs_get (strlen (command) + (args ? strlen (args) + 1 : 0) + 3); /* build the complete command */ if (args) sprintf (s,"%s %s",command,args); else strcpy (s,command); if (stream->debug) mm_dlog (s); strcat (s,"\015\012"); /* send the command */ if (!net_soutr (stream->netstream,s)) ret = smtp_fake (stream,SMTPSOFTFATAL,"SMTP connection broken (command)"); else { do stream->replycode = smtp_reply (stream); while ((stream->replycode < 100) || (stream->reply[3] == '-')); ret = stream->replycode; } fs_give ((void **) &s); return ret;}/* SMTP send authentication if needed * Accepts: SEND stream * code from previous command * Returns: T if need to redo command, NIL otherwise */long smtp_send_auth (SENDSTREAM *stream,long code){ NETMBX mb; char tmp[MAILTMPLEN]; switch (code) { case SMTPWANTAUTH: case SMTPWANTAUTH2: sprintf (tmp,"{%.200s/smtp",net_host (stream->netstream)); if (stream->netstream->dtb == (NETDRIVER *) mail_parameters (NIL,GET_ALTDRIVER,NIL)) sprintf (tmp + strlen (tmp),"/%.200s", (char *) mail_parameters (NIL,GET_ALTDRIVERNAME,NIL)); strcat (tmp,"}<none>"); mail_valid_net_parse (tmp,&mb); return smtp_auth (stream,&mb,tmp); } return NIL; /* no auth needed */}/* Simple Mail Transfer Protocol get reply * Accepts: SMTP stream * Returns: reply code */long smtp_reply (SENDSTREAM *stream){ smtpverbose_t pv = (smtpverbose_t) mail_parameters (NIL,GET_SMTPVERBOSE,NIL); long reply; /* flush old reply */ if (stream->reply) fs_give ((void **) &stream->reply); /* get reply */ if (!(stream->reply = net_getline (stream->netstream))) return smtp_fake (stream,SMTPSOFTFATAL,"SMTP connection went away!"); if (stream->debug) mm_dlog (stream->reply); reply = atol (stream->reply); /* return response code */ if (pv && (reply < 100)) (*pv) (stream->reply); return reply;}/* Simple Mail Transfer Protocol send EHLO * Accepts: SMTP stream * host name to use in EHLO * NETMBX structure * Returns: reply code */long smtp_ehlo (SENDSTREAM *stream,char *host,NETMBX *mb){ unsigned long i; unsigned int j; long flags = (mb->secflag ? AU_SECURE : NIL) | (mb->authuser[0] ? AU_AUTHUSER : NIL); char *s,tmp[MAILTMPLEN]; sprintf (tmp,"EHLO %s",host); /* build the complete command */ if (stream->debug) mm_dlog (tmp); strcat (tmp,"\015\012"); /* send the command */ if (!net_soutr (stream->netstream,tmp)) return smtp_fake (stream,SMTPSOFTFATAL,"SMTP connection broken (EHLO)"); /* got an OK reply? */ do if ((i = smtp_reply (stream)) == SMTPOK) { ucase (strncpy (tmp,stream->reply+4,MAILTMPLEN-1)); tmp[MAILTMPLEN-1] = '\0'; /* note EHLO options */ if ((tmp[0] == '8') && (tmp[1] == 'B') && (tmp[2] == 'I') && (tmp[3] == 'T') && (tmp[4] == 'M') && (tmp[5] == 'I') && (tmp[6] == 'M') && (tmp[7] == 'E') && !tmp[8]) ESMTP.eightbit.ok = T; else if ((tmp[0] == 'S') && (tmp[1] == 'I') && (tmp[2] == 'Z') && (tmp[3] == 'E') && (!tmp[4] || tmp[4] == ' ')) { if (tmp[4]) ESMTP.size.limit = atoi (tmp+5); ESMTP.size.ok = T; } else if ((tmp[0] == 'A') && (tmp[1] == 'U') && (tmp[2] == 'T') && (tmp[3] == 'H') && ((tmp[4] == ' ') || (tmp[4] == '='))) { for (s = strtok (tmp+5," "); s && *s; s = strtok (NIL," ")) if ((j = mail_lookup_auth_name (s,flags)) && (--j < (8 * sizeof (ESMTP.auth)))) ESMTP.auth |= (1 << j); } else if ((tmp[0] == 'D') && (tmp[1] == 'S') && (tmp[2] == 'N') && !tmp[3]) ESMTP.dsn.ok = T; else if ((tmp[0] == 'S') && (tmp[1] == 'E') && (tmp[2] == 'N') && (tmp[3] == 'D') && !tmp[4]) ESMTP.service.send = T; else if ((tmp[0] == 'S') && (tmp[1] == 'O') && (tmp[2] == 'M') && (tmp[3] == 'L') && !tmp[4]) ESMTP.service.soml = T; else if ((tmp[0] == 'S') && (tmp[1] == 'A') && (tmp[2] == 'M') && (tmp[3] == 'L') && !tmp[4]) ESMTP.service.saml = T; else if ((tmp[0] == 'E') && (tmp[1] == 'X') && (tmp[2] == 'P') && (tmp[3] == 'N') && !tmp[4]) ESMTP.service.expn = T; else if ((tmp[0] == 'H') && (tmp[1] == 'E') && (tmp[2] == 'L') && (tmp[3] == 'P') && !tmp[4]) ESMTP.service.help = T; else if ((tmp[0] == 'T') && (tmp[1] == 'U') && (tmp[2] == 'R') && (tmp[3] == 'N') && !tmp[4]) ESMTP.service.turn = T; else if ((tmp[0] == 'E') && (tmp[1] == 'T') && (tmp[2] == 'R') && (tmp[3] == 'N') && !tmp[4]) ESMTP.service.etrn = T; else if ((tmp[0] == 'R') && (tmp[1] == 'E') && (tmp[2] == 'L') && (tmp[3] == 'A') && (tmp[4] == 'Y') && !tmp[5]) ESMTP.service.relay = T; else if ((tmp[0] == 'P') && (tmp[1] == 'I') && (tmp[2] == 'P') && (tmp[3] == 'E') && (tmp[4] == 'L') && (tmp[5] == 'I') && (tmp[6] == 'N') && (tmp[7] == 'I') && (tmp[8] == 'N') && (tmp[9] == 'G') && !tmp[10]) ESMTP.service.pipe = T; else if ((tmp[0] == 'E') && (tmp[1] == 'N') && (tmp[2] == 'H') && (tmp[3] == 'A') && (tmp[4] == 'N') && (tmp[5] == 'C') && (tmp[6] == 'E') && (tmp[7] == 'D') && (tmp[8] == 'S') && (tmp[9] == 'T') && (tmp[10] == 'A') && (tmp[11] == 'T') && (tmp[12] == 'U') && (tmp[13] == 'S') && (tmp[14] == 'C') && (tmp[15] == 'O') && (tmp[16] == 'D') && (tmp[17] == 'E') && (tmp[18] == 'S') && !tmp[19]) ESMTP.service.ensc = T; } while ((i < 100) || (stream->reply[3] == '-')); return i; /* return the response code */}/* Simple Mail Transfer Protocol set fake error * Accepts: SMTP stream * SMTP error code * error text * Returns: error code */long smtp_fake (SENDSTREAM *stream,long code,char *text){ /* flush any old reply */ if (stream->reply ) fs_give ((void **) &stream->reply); /* set up pseudo-reply string */ stream->reply = (char *) fs_get (20+strlen (text)); sprintf (stream->reply,"%ld %s",code,text); return code; /* return error code */}/* Simple Mail Transfer Protocol filter mail * Accepts: stream * string * Returns: T on success, NIL on failure */long smtp_soutr (void *stream,char *s){ char c,*t; /* "." on first line */ if (s[0] == '.') net_sout (stream,".",1); /* find lines beginning with a "." */ while (t = strstr (s,"\015\012.")) { c = *(t += 3); /* remember next character after "." */ *t = '\0'; /* tie off string */ /* output prefix */ if (!net_sout (stream,s,t-s)) return NIL; *t = c; /* restore delimiter */ s = t - 1; /* push pointer up to the "." */ } /* output remainder of text */ return *s ? net_soutr (stream,s) : T;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -