📄 smtp.c
字号:
smtp_send (stream,"QUIT",NIL); if (stream->netstream) /* could have been closed during "QUIT" */ net_close (stream->netstream); } /* clean up */ if (stream->host) fs_give ((void **) &stream->host); if (stream->reply) fs_give ((void **) &stream->reply); if (ESMTP.dsn.envid) fs_give ((void **) &ESMTP.dsn.envid); if (ESMTP.atrn.domains) fs_give ((void **) &ESMTP.atrn.domains); fs_give ((void **) &stream);/* flush the stream */ } return NIL;}/* Mail Transfer Protocol deliver mail * Accepts: SEND stream * delivery option (MAIL, SEND, SAML, SOML) * message envelope * message body * Returns: T on success, NIL on failure */long smtp_mail (SENDSTREAM *stream,char *type,ENVELOPE *env,BODY *body){ RFC822BUFFER buf; char tmp[SENDBUFLEN+1]; long error = NIL; long retry = NIL; buf.f = smtp_soutr; /* initialize buffer */ buf.s = stream->netstream; buf.end = (buf.beg = buf.cur = tmp) + SENDBUFLEN; tmp[SENDBUFLEN] = '\0'; /* must have additional null guard byte */ if (!(env->to || env->cc || env->bcc)) { /* no recipients in request */ smtp_seterror (stream,SMTPHARDERROR,"No recipients specified"); return NIL; } do { /* make sure stream is in good shape */ smtp_send (stream,"RSET",NIL); if (retry) { /* need to retry with authentication? */ NETMBX mb; /* yes, build remote name for authentication */ sprintf (tmp,"{%.200s/smtp%s}<none>", (long) mail_parameters (NIL,GET_TRUSTDNS,NIL) ? ((long) mail_parameters (NIL,GET_SASLUSESPTRNAME,NIL) ? net_remotehost (stream->netstream) : net_host (stream->netstream)) : stream->host, (stream->netstream->dtb == (NETDRIVER *) mail_parameters (NIL,GET_SSLDRIVER,NIL)) ? "/ssl" : ""); mail_valid_net_parse (tmp,&mb); if (!smtp_auth (stream,&mb,tmp)) return NIL; retry = NIL; /* no retry at this point */ } strcpy (tmp,"FROM:<"); /* compose "MAIL FROM:<return-path>" */#ifdef RFC2821 if (env->return_path && env->return_path->host && !((strlen (env->return_path->mailbox) > SMTPMAXLOCALPART) || (strlen (env->return_path->host) > SMTPMAXDOMAIN))) { rfc822_cat (tmp,env->return_path->mailbox,NIL); sprintf (tmp + strlen (tmp),"@%s",env->return_path->host); }#else /* old code with A-D-L support */ 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);#endif 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"); if (ESMTP.dsn.envid) sprintf (tmp + strlen (tmp)," ENVID=%.100s",ESMTP.dsn.envid); } } /* send "MAIL FROM" command */ switch (smtp_send (stream,type,tmp)) { case SMTPUNAVAIL: /* mailbox unavailable? */ case SMTPWANTAUTH: /* wants authentication? */ case SMTPWANTAUTH2: if (ESMTP.auth) retry = T;/* yes, retry with authentication */ case SMTPOK: /* looks good */ break; default: /* other failure */ return NIL; } /* negotiate the recipients */ if (!retry && env->to) retry = smtp_rcpt (stream,env->to,&error); if (!retry && env->cc) retry = smtp_rcpt (stream,env->cc,&error); if (!retry && env->bcc) retry = smtp_rcpt (stream,env->bcc,&error); if (!retry && error) { /* any recipients failed? */ smtp_send (stream,"RSET",NIL); smtp_seterror (stream,SMTPHARDERROR,"One or more recipients failed"); return NIL; } } while (retry); /* negotiate data command */ if (!(smtp_send (stream,"DATA",NIL) == SMTPREADY)) return NIL; /* send message data */ if (!rfc822_output_full (&buf,env,body, ESMTP.eightbit.ok && ESMTP.eightbit.want)) { smtp_fake (stream,"SMTP connection broken (message data)"); return NIL; /* can't do much else here */ } /* send trailing dot */ return (smtp_send (stream,".",NIL) == SMTPOK) ? LONGT : NIL;}/* Simple Mail Transfer Protocol send VERBose * Accepts: SMTP stream * Returns: T if successful, else NIL * * Descriptive text formerly in [al]pine sources: * At worst, this command may cause the SMTP connection to get nuked. Modern * sendmail's recognize it, and possibly other SMTP implementations (the "ON" * arg is for PMDF). What's more, if it works, the reply code and accompanying * text may vary from server to server. */long smtp_verbose (SENDSTREAM *stream){ /* accept any 2xx reply code */ return ((smtp_send (stream,"VERB","ON") / (long) 100) == 2) ? LONGT : NIL;}/* Internal routines *//* Simple Mail Transfer Protocol send recipient * Accepts: SMTP stream * address list * pointer to error flag * Returns: T if should retry, else NIL */long smtp_rcpt (SENDSTREAM *stream,ADDRESS *adr,long *error){ char *s,tmp[2*MAILTMPLEN],orcpt[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 (strlen (adr->mailbox) > MAXLOCALPART) { adr->error = cpystr ("501 Recipient name too long"); *error = T; } else if ((strlen (adr->host) > SMTPMAXDOMAIN)) { adr->error = cpystr ("501 Recipient domain too long"); *error = T; }#ifndef RFC2821 /* old code with A-D-L support */ else if (adr->adl && (strlen (adr->adl) > SMTPMAXPATH)) { adr->error = cpystr ("501 Path too long"); *error = T; }#endif else { strcpy (tmp,"TO:<"); /* compose "RCPT TO:<return-path>" */#ifdef RFC2821 rfc822_cat (tmp,adr->mailbox,NIL); sprintf (tmp + strlen (tmp),"@%s>",adr->host);#else /* old code with A-D-L support */ rfc822_address (tmp,adr); strcat (tmp,">");#endif /* 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"); if (adr->orcpt.addr) { sprintf (orcpt,"%.498s;%.498s", adr->orcpt.type ? adr->orcpt.type : "rfc822", adr->orcpt.addr); sprintf (tmp + strlen (tmp)," ORCPT=%.500s",orcpt); } } switch (smtp_send (stream,"RCPT",tmp)) { case SMTPOK: /* looks good */ break; case SMTPUNAVAIL: /* mailbox unavailable? */ case SMTPWANTAUTH: /* wants authentication? */ case SMTPWANTAUTH2: if (ESMTP.auth) return T; default: /* other failure */ *error = T; /* note that an error occurred */ adr->error = cpystr (stream->reply); } } } adr = adr->next; /* do any subsequent recipients */ } return NIL; /* no retry called for */}/* Simple Mail Transfer Protocol send command * Accepts: SEND stream * text * Returns: reply code */long smtp_send (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) mail_dlog (s,stream->sensitive); strcat (s,"\015\012"); /* send the command */ if (stream->netstream && net_soutr (stream->netstream,s)) { do stream->replycode = smtp_reply (stream); while ((stream->replycode < 100) || (stream->reply[3] == '-')); ret = stream->replycode; } else ret = smtp_fake (stream,"SMTP connection broken (command)"); fs_give ((void **) &s); return ret;}/* 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->netstream && (stream->reply = net_getline (stream->netstream))) { if (stream->debug) mm_dlog (stream->reply); /* return response code */ reply = atol (stream->reply); if (pv && (reply < 100)) (*pv) (stream->reply); } else reply = smtp_fake (stream,"SMTP connection broken (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,j; long flags = (mb->secflag ? AU_SECURE : NIL) | (mb->authuser[0] ? AU_AUTHUSER : NIL); char *s,*t,*r,tmp[MAILTMPLEN]; /* clear ESMTP data */ memset (&ESMTP,0,sizeof (ESMTP)); if (mb->loser) return 500; /* never do EHLO if a loser */ 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,"SMTP connection broken (EHLO)"); /* got an OK reply? */ do if ((i = smtp_reply (stream)) == SMTPOK) { /* hack for AUTH= */ if (stream->reply[4] && stream->reply[5] && stream->reply[6] && stream->reply[7] && (stream->reply[8] == '=')) stream->reply[8] = ' '; /* get option code */ if (!(s = strtok_r (stream->reply+4," ",&r))); /* have option, does it have a value */ else if ((t = strtok_r (NIL," ",&r)) && *t) { /* EHLO options which take arguments */ if (!compare_cstring (s,"SIZE")) { if (isdigit (*t)) ESMTP.size.limit = strtoul (t,&t,10); ESMTP.size.ok = T; } else if (!compare_cstring (s,"DELIVERBY")) { if (isdigit (*t)) ESMTP.deliverby.minby = strtoul (t,&t,10); ESMTP.deliverby.ok = T; } else if (!compare_cstring (s,"ATRN")) { ESMTP.atrn.domains = cpystr (t); ESMTP.atrn.ok = T; } else if (!compare_cstring (s,"AUTH")) do if ((j = mail_lookup_auth_name (t,flags)) && (--j < MAXAUTHENTICATORS)) ESMTP.auth |= (1 << j); while ((t = strtok_r (NIL," ",&r)) && *t); } /* EHLO options which do not take arguments */ else if (!compare_cstring (s,"SIZE")) ESMTP.size.ok = T; else if (!compare_cstring (s,"8BITMIME")) ESMTP.eightbit.ok = T; else if (!compare_cstring (s,"DSN")) ESMTP.dsn.ok = T; else if (!compare_cstring (s,"ATRN")) ESMTP.atrn.ok = T; else if (!compare_cstring (s,"SEND")) ESMTP.service.send = T; else if (!compare_cstring (s,"SOML")) ESMTP.service.soml = T; else if (!compare_cstring (s,"SAML")) ESMTP.service.saml = T; else if (!compare_cstring (s,"EXPN")) ESMTP.service.expn = T; else if (!compare_cstring (s,"HELP")) ESMTP.service.help = T; else if (!compare_cstring (s,"TURN")) ESMTP.service.turn = T; else if (!compare_cstring (s,"ETRN")) ESMTP.service.etrn = T; else if (!compare_cstring (s,"STARTTLS")) ESMTP.service.starttls = T; else if (!compare_cstring (s,"RELAY")) ESMTP.service.relay = T; else if (!compare_cstring (s,"PIPELINING")) ESMTP.service.pipe = T; else if (!compare_cstring (s,"ENHANCEDSTATUSCODES")) ESMTP.service.ensc = T; else if (!compare_cstring (s,"BINARYMIME")) ESMTP.service.bmime = T; else if (!compare_cstring (s,"CHUNKING")) ESMTP.service.chunk = T; } while ((i < 100) || (stream->reply[3] == '-')); /* disable LOGIN if PLAIN also advertised */ if ((j = mail_lookup_auth_name ("PLAIN",NIL)) && (--j < MAXAUTHENTICATORS) && (ESMTP.auth & (1 << j)) && (j = mail_lookup_auth_name ("LOGIN",NIL)) && (--j < MAXAUTHENTICATORS)) ESMTP.auth &= ~(1 << j); return i; /* return the response code */}/* Simple Mail Transfer Protocol set fake error and abort * Accepts: SMTP stream * error text * Returns: SMTPSOFTFATAL, always */long smtp_fake (SENDSTREAM *stream,char *text){ if (stream->netstream) { /* close net connection if still open */ net_close (stream->netstream); stream->netstream = NIL; } /* set last error */ return smtp_seterror (stream,SMTPSOFTFATAL,text);}/* Simple Mail Transfer Protocol set error * Accepts: SMTP stream * SMTP error code * error text * Returns: error code */static long smtp_seterror (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 + -