📄 srvrsmtp.c
字号:
if (p == NULL) break; a = parseaddr(p, NULLADDR, RF_COPYALL, ' ', NULL, e); if (a == NULL) break; a->q_flags |= QPRIMARY; a = recipient(a, &e->e_sendqueue, e); if (Errors != 0) break; /* no errors during parsing, but might be a duplicate */ e->e_to = p; if (!bitset(QBADADDR, a->q_flags)) { message("250 Recipient ok%s", bitset(QQUEUEUP, a->q_flags) ? " (will queue)" : ""); nrcpts++; } else { /* punt -- should keep message in ADDRESS.... */ message("550 Addressee unknown"); } e->e_to = NULL; break; case CMDDATA: /* data -- text of mail */ SmtpPhase = "server DATA"; if (!gotmail) { message("503 Need MAIL command"); break; } else if (nrcpts <= 0) { message("503 Need RCPT (recipient)"); break; } /* check to see if we need to re-expand aliases */ /* also reset QBADADDR on already-diagnosted addrs */ doublequeue = FALSE; for (a = e->e_sendqueue; a != NULL; a = a->q_next) { if (bitset(QVERIFIED, a->q_flags)) { /* need to re-expand aliases */ doublequeue = TRUE; } if (bitset(QBADADDR, a->q_flags)) { /* make this "go away" */ a->q_flags |= QDONTSEND; a->q_flags &= ~QBADADDR; } } /* collect the text of the message */ SmtpPhase = "collect"; collect(TRUE, doublequeue, e); if (Errors != 0) goto abortmessage; HoldErrs = TRUE; /* ** Arrange to send to everyone. ** If sending to multiple people, mail back ** errors rather than reporting directly. ** In any case, don't mail back errors for ** anything that has happened up to ** now (the other end will do this). ** Truncate our transcript -- the mail has gotten ** to us successfully, and if we have ** to mail this back, it will be easier ** on the reader. ** Then send to everyone. ** Finally give a reply code. If an error has ** already been given, don't mail a ** message back. ** We goose error returns by clearing error bit. */ SmtpPhase = "delivery"; if (nrcpts != 1 && !doublequeue) { HoldErrs = TRUE; e->e_errormode = EM_MAIL; } e->e_xfp = freopen(queuename(e, 'x'), "w", e->e_xfp); id = e->e_id; /* send to all recipients */ sendall(e, doublequeue ? SM_QUEUE : SM_DEFAULT); e->e_to = NULL; /* issue success if appropriate and reset */ if (Errors == 0 || HoldErrs) message("250 %s Message accepted for delivery", id); if (bitset(EF_FATALERRS, e->e_flags) && !HoldErrs) { /* avoid sending back an extra message */ e->e_flags &= ~EF_FATALERRS; e->e_flags |= EF_CLRQUEUE; } else { /* from now on, we have to operate silently */ HoldErrs = TRUE; e->e_errormode = EM_MAIL; /* if we just queued, poke it */ if (doublequeue && e->e_sendmode != SM_QUEUE) { extern pid_t dowork(); unlockqueue(e); (void) dowork(id, TRUE, TRUE, e); } } abortmessage: /* if in a child, pop back to our parent */ if (InChild) finis(); /* clean up a bit */ gotmail = FALSE; dropenvelope(e); CurEnv = e = newenvelope(e, CurEnv); e->e_flags = BlankEnvelope.e_flags; break; case CMDRSET: /* rset -- reset state */ message("250 Reset state"); e->e_flags |= EF_CLRQUEUE; if (InChild) finis(); /* clean up a bit */ gotmail = FALSE; dropenvelope(e); CurEnv = e = newenvelope(e, CurEnv); break; case CMDVRFY: /* vrfy -- verify address */ case CMDEXPN: /* expn -- expand address */ vrfy = c->cmdcode == CMDVRFY; if (bitset(vrfy ? PRIV_NOVRFY : PRIV_NOEXPN, PrivacyFlags)) { if (vrfy) message("252 Who's to say?"); else message("502 Sorry, we do not allow this operation");#ifdef LOG if (LogLevel > 5) syslog(LOG_INFO, "%s: %s [rejected]", CurSmtpClient, inp);#endif break; } else if (!gothello && bitset(vrfy ? PRIV_NEEDVRFYHELO : PRIV_NEEDEXPNHELO, PrivacyFlags)) { message("503 I demand that you introduce yourself first"); break; } if (runinchild(vrfy ? "SMTP-VRFY" : "SMTP-EXPN", e) > 0) break;#ifdef LOG if (LogLevel > 5) syslog(LOG_INFO, "%s: %s", CurSmtpClient, inp);#endif vrfyqueue = NULL; QuickAbort = TRUE; if (vrfy) e->e_flags |= EF_VRFYONLY; while (*p != '\0' && isascii(*p) && isspace(*p)) *p++; if (*p == '\0') { message("501 Argument required"); Errors++; } else { (void) sendtolist(p, NULLADDR, &vrfyqueue, e); } if (Errors != 0) { if (InChild) finis(); break; } if (vrfyqueue == NULL) { message("554 Nothing to %s", vrfy ? "VRFY" : "EXPN"); } while (vrfyqueue != NULL) { a = vrfyqueue; while ((a = a->q_next) != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags)) continue; if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags)) printvrfyaddr(vrfyqueue, a == NULL); vrfyqueue = vrfyqueue->q_next; } if (InChild) finis(); break; case CMDHELP: /* help -- give user info */ help(p); break; case CMDNOOP: /* noop -- do nothing */ message("250 OK"); break; case CMDQUIT: /* quit -- leave mail */ message("221 %s closing connection", MyHostName);doquit: /* avoid future 050 messages */ disconnect(1, e); if (InChild) ExitStat = EX_QUIT; finis(); case CMDVERB: /* set verbose mode */ if (bitset(PRIV_NOEXPN, PrivacyFlags)) { /* this would give out the same info */ message("502 Verbose unavailable"); break; } Verbose = TRUE; e->e_sendmode = SM_DELIVER; message("250 Verbose mode"); break; case CMDONEX: /* doing one transaction only */ OneXact = TRUE; message("250 Only one transaction"); break;# ifdef SMTPDEBUG case CMDDBGQSHOW: /* show queues */ printf("Send Queue="); printaddr(e->e_sendqueue, TRUE); break; case CMDDBGDEBUG: /* set debug mode */ tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); tTflag(p); message("200 Debug set"); break;# else /* not SMTPDEBUG */ case CMDDBGQSHOW: /* show queues */ case CMDDBGDEBUG: /* set debug mode */# endif /* SMTPDEBUG */ case CMDLOGBOGUS: /* bogus command */# ifdef LOG if (LogLevel > 0) syslog(LOG_CRIT, "\"%s\" command from %s (%s)", c->cmdname, peerhostname, anynet_ntoa(&RealHostAddr));# endif /* FALL THROUGH */ case CMDERROR: /* unknown command */ if (++badcommands > MAXBADCOMMANDS) { message("421 %s Too many bad commands; closing connection", MyHostName); goto doquit; } message("500 Command unrecognized"); break; default: errno = 0; syserr("500 smtp: unknown code %d", c->cmdcode); break; } }}/*** SKIPWORD -- skip a fixed word.**** Parameters:** p -- place to start looking.** w -- word to skip.**** Returns:** p following w.** NULL on error.**** Side Effects:** clobbers the p data area.*/static char *skipword(p, w) register char *p; char *w;{ register char *q; char *firstp = p; /* find beginning of word */ while (isascii(*p) && isspace(*p)) p++; q = p; /* find end of word */ while (*p != '\0' && *p != ':' && !(isascii(*p) && isspace(*p))) p++; while (isascii(*p) && isspace(*p)) *p++ = '\0'; if (*p != ':') { syntax: message("501 Syntax error in parameters scanning \"%s\"", firstp); Errors++; return (NULL); } *p++ = '\0'; while (isascii(*p) && isspace(*p)) p++; if (*p == '\0') goto syntax; /* see if the input word matches desired word */ if (strcasecmp(q, w)) goto syntax; return (p);}/*** PRINTVRFYADDR -- print an entry in the verify queue**** Parameters:** a -- the address to print** last -- set if this is the last one.**** Returns:** none.**** Side Effects:** Prints the appropriate 250 codes.*/printvrfyaddr(a, last) register ADDRESS *a; bool last;{ char fmtbuf[20]; strcpy(fmtbuf, "250"); fmtbuf[3] = last ? ' ' : '-'; if (a->q_fullname == NULL) { if (strchr(a->q_user, '@') == NULL) strcpy(&fmtbuf[4], "<%s@%s>"); else strcpy(&fmtbuf[4], "<%s>"); message(fmtbuf, a->q_user, MyHostName); } else { if (strchr(a->q_user, '@') == NULL) strcpy(&fmtbuf[4], "%s <%s@%s>"); else strcpy(&fmtbuf[4], "%s <%s>"); message(fmtbuf, a->q_fullname, a->q_user, MyHostName); }}/*** HELP -- implement the HELP command.**** Parameters:** topic -- the topic we want help for.**** Returns:** none.**** Side Effects:** outputs the help file to message output.*/help(topic) char *topic;{ register FILE *hf; int len; char buf[MAXLINE]; bool noinfo; if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL) { /* no help */ errno = 0; message("502 HELP not implemented"); return; } if (topic == NULL || *topic == '\0') topic = "smtp"; else makelower(topic); len = strlen(topic); noinfo = TRUE; while (fgets(buf, sizeof buf, hf) != NULL) { if (strncmp(buf, topic, len) == 0) { register char *p; p = strchr(buf, '\t'); if (p == NULL) p = buf; else p++; fixcrlf(p, TRUE); message("214-%s", p); noinfo = FALSE; } } if (noinfo) message("504 HELP topic unknown"); else message("214 End of HELP info"); (void) fclose(hf);}/*** RUNINCHILD -- return twice -- once in the child, then in the parent again**** Parameters:** label -- a string used in error messages**** Returns:** zero in the child** one in the parent**** Side Effects:** none.*/runinchild(label, e) char *label; register ENVELOPE *e;{ int childpid; if (!OneXact) { childpid = dofork(); if (childpid < 0) { syserr("%s: cannot fork", label); return (1); } if (childpid > 0) { auto int st; /* parent -- wait for child to complete */ setproctitle("server %s child wait", CurHostName); st = waitfor(childpid); if (st == -1) syserr("%s: lost child", label); else if (!WIFEXITED(st)) syserr("%s: died on signal %d", label, st & 0177); /* if we exited on a QUIT command, complete the process */ if (WEXITSTATUS(st) == EX_QUIT) { disconnect(1, e); finis(); } return (1); } else { /* child */ InChild = TRUE; QuickAbort = FALSE; clearenvelope(e, FALSE); } } /* open alias database */ initmaps(FALSE, e); return (0);}# endif /* SMTP */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -