122712Sdist /* 234921Sbostic * Copyright (c) 1983 Eric P. Allman 333731Sbostic * Copyright (c) 1988 Regents of the University of California. 433731Sbostic * All rights reserved. 533731Sbostic * 642829Sbostic * %sccs.include.redist.c% 733731Sbostic */ 822712Sdist 933731Sbostic # include "sendmail.h" 1022712Sdist 1133731Sbostic #ifndef lint 1233731Sbostic #ifdef SMTP 13*58704Seric static char sccsid[] = "@(#)srvrsmtp.c 6.25 (Berkeley) 03/18/93 (with SMTP)"; 1433731Sbostic #else 15*58704Seric static char sccsid[] = "@(#)srvrsmtp.c 6.25 (Berkeley) 03/18/93 (without SMTP)"; 1633731Sbostic #endif 1733731Sbostic #endif /* not lint */ 1833731Sbostic 199339Seric # include <errno.h> 2011728Seric # include <signal.h> 214549Seric 2233731Sbostic # ifdef SMTP 234556Seric 244549Seric /* 254549Seric ** SMTP -- run the SMTP protocol. 264549Seric ** 274549Seric ** Parameters: 284549Seric ** none. 294549Seric ** 304549Seric ** Returns: 314549Seric ** never. 324549Seric ** 334549Seric ** Side Effects: 344549Seric ** Reads commands from the input channel and processes 354549Seric ** them. 364549Seric */ 374549Seric 384549Seric struct cmd 394549Seric { 404549Seric char *cmdname; /* command name */ 414549Seric int cmdcode; /* internal code, see below */ 424549Seric }; 434549Seric 444549Seric /* values for cmdcode */ 454549Seric # define CMDERROR 0 /* bad command */ 464549Seric # define CMDMAIL 1 /* mail -- designate sender */ 474976Seric # define CMDRCPT 2 /* rcpt -- designate recipient */ 484549Seric # define CMDDATA 3 /* data -- send message text */ 499339Seric # define CMDRSET 4 /* rset -- reset state */ 509339Seric # define CMDVRFY 5 /* vrfy -- verify address */ 5158092Seric # define CMDEXPN 6 /* expn -- expand address */ 529339Seric # define CMDNOOP 7 /* noop -- do nothing */ 539339Seric # define CMDQUIT 8 /* quit -- close connection and die */ 549339Seric # define CMDHELO 9 /* helo -- be polite */ 5558092Seric # define CMDHELP 10 /* help -- give usage info */ 5658323Seric # define CMDEHLO 11 /* ehlo -- extended helo (RFC 1425) */ 5758092Seric /* non-standard commands */ 5858092Seric # define CMDONEX 16 /* onex -- sending one transaction only */ 5958092Seric # define CMDVERB 17 /* verb -- go into verbose mode */ 6036230Skarels /* debugging-only commands, only enabled if SMTPDEBUG is defined */ 6158092Seric # define CMDDBGQSHOW 24 /* showq -- show send queue */ 6258092Seric # define CMDDBGDEBUG 25 /* debug -- set debug mode */ 634549Seric 644549Seric static struct cmd CmdTab[] = 654549Seric { 664549Seric "mail", CMDMAIL, 674976Seric "rcpt", CMDRCPT, 684549Seric "data", CMDDATA, 694549Seric "rset", CMDRSET, 704549Seric "vrfy", CMDVRFY, 7158092Seric "expn", CMDEXPN, 724549Seric "help", CMDHELP, 734549Seric "noop", CMDNOOP, 744549Seric "quit", CMDQUIT, 754976Seric "helo", CMDHELO, 7658323Seric "ehlo", CMDEHLO, 778544Seric "verb", CMDVERB, 789314Seric "onex", CMDONEX, 7936230Skarels /* 8036230Skarels * remaining commands are here only 8136230Skarels * to trap and log attempts to use them 8236230Skarels */ 839339Seric "showq", CMDDBGQSHOW, 848544Seric "debug", CMDDBGDEBUG, 854549Seric NULL, CMDERROR, 864549Seric }; 874549Seric 889339Seric bool InChild = FALSE; /* true if running in a subprocess */ 899378Seric bool OneXact = FALSE; /* one xaction only this run */ 9011146Seric 919339Seric #define EX_QUIT 22 /* special code for QUIT command */ 928544Seric 9355012Seric smtp(e) 9455012Seric register ENVELOPE *e; 954549Seric { 964549Seric register char *p; 978544Seric register struct cmd *c; 984549Seric char *cmd; 9946928Sbostic static char *skipword(); 1005003Seric auto ADDRESS *vrfyqueue; 10112612Seric ADDRESS *a; 10230448Seric char *sendinghost; 10358109Seric bool gotmail; /* mail command received */ 10458092Seric bool gothello; /* helo command received */ 10558092Seric bool vrfy; /* set if this is a vrfy command */ 10658323Seric char *protocol; /* sending protocol */ 10758333Seric long msize; /* approximate maximum message size */ 10858333Seric auto char *delimptr; 1098544Seric char inp[MAXLINE]; 11057232Seric char cmdbuf[MAXLINE]; 11158512Seric char hostbuf[MAXNAME]; 1127124Seric extern char Version[]; 11311151Seric extern char *macvalue(); 11412612Seric extern ADDRESS *recipient(); 11524943Seric extern ENVELOPE BlankEnvelope; 11624943Seric extern ENVELOPE *newenvelope(); 11758512Seric extern char *inet_ntoa(); 1184549Seric 1197363Seric if (OutChannel != stdout) 1207363Seric { 1217363Seric /* arrange for debugging output to go to remote host */ 1227363Seric (void) close(1); 1237363Seric (void) dup(fileno(OutChannel)); 1247363Seric } 12555012Seric settime(e); 12657642Seric CurHostName = RealHostName; 12757642Seric setproctitle("srvrsmtp %s", CurHostName); 12858050Seric expand("\201e", inp, &inp[sizeof inp], e); 12958151Seric message("220 %s", inp); 13024943Seric SmtpPhase = "startup"; 13130448Seric sendinghost = NULL; 13258330Seric protocol = NULL; 13358082Seric gothello = FALSE; 13458330Seric gotmail = FALSE; 1354549Seric for (;;) 1364549Seric { 13712612Seric /* arrange for backout */ 13812612Seric if (setjmp(TopFrame) > 0 && InChild) 13912612Seric finis(); 14012612Seric QuickAbort = FALSE; 14112612Seric HoldErrs = FALSE; 14251951Seric LogUsrErrs = FALSE; 14358092Seric e->e_flags &= ~EF_VRFYONLY; 14412612Seric 1457356Seric /* setup for the read */ 14655012Seric e->e_to = NULL; 1474577Seric Errors = 0; 1487275Seric (void) fflush(stdout); 1497356Seric 1507356Seric /* read the input line */ 15158109Seric p = sfgets(inp, sizeof inp, InChannel, TimeOuts.to_nextcommand); 1527356Seric 1537685Seric /* handle errors */ 1547356Seric if (p == NULL) 1557356Seric { 1564549Seric /* end of file, just die */ 15758151Seric message("421 %s Lost input channel from %s", 15825050Seric MyHostName, CurHostName); 15955464Seric #ifdef LOG 16058020Seric if (LogLevel > 1) 16155464Seric syslog(LOG_NOTICE, "lost input channel from %s", 16255464Seric CurHostName); 16355464Seric #endif 16458069Seric if (InChild) 16558069Seric ExitStat = EX_QUIT; 1664549Seric finis(); 1674549Seric } 1684549Seric 1694549Seric /* clean up end of line */ 1704558Seric fixcrlf(inp, TRUE); 1714549Seric 1724713Seric /* echo command to transcript */ 17355012Seric if (e->e_xfp != NULL) 17455012Seric fprintf(e->e_xfp, "<<< %s\n", inp); 1754713Seric 1764549Seric /* break off command */ 17758050Seric for (p = inp; isascii(*p) && isspace(*p); p++) 1784549Seric continue; 17957232Seric cmd = cmdbuf; 18058050Seric while (*p != '\0' && 18158050Seric !(isascii(*p) && isspace(*p)) && 18258050Seric cmd < &cmdbuf[sizeof cmdbuf - 2]) 18324981Seric *cmd++ = *p++; 18424981Seric *cmd = '\0'; 1854549Seric 18625691Seric /* throw away leading whitespace */ 18758050Seric while (isascii(*p) && isspace(*p)) 18825691Seric p++; 18925691Seric 1904549Seric /* decode command */ 1914549Seric for (c = CmdTab; c->cmdname != NULL; c++) 1924549Seric { 19333725Sbostic if (!strcasecmp(c->cmdname, cmdbuf)) 1944549Seric break; 1954549Seric } 1964549Seric 19751954Seric /* reset errors */ 19851954Seric errno = 0; 19951954Seric 2004549Seric /* process command */ 2014549Seric switch (c->cmdcode) 2024549Seric { 2034976Seric case CMDHELO: /* hello -- introduce yourself */ 20458323Seric case CMDEHLO: /* extended hello */ 20558323Seric if (c->cmdcode == CMDEHLO) 20658323Seric { 20758323Seric protocol = "ESMTP"; 20858323Seric SmtpPhase = "EHLO"; 20958323Seric } 21058323Seric else 21158323Seric { 21258323Seric protocol = "SMTP"; 21358323Seric SmtpPhase = "HELO"; 21458323Seric } 21525050Seric setproctitle("%s: %s", CurHostName, inp); 21658109Seric if (strcasecmp(p, MyHostName) == 0) 21714877Seric { 21836230Skarels /* 21958109Seric ** Didn't know about alias or MX, 22058109Seric ** or connected to an echo server 22158109Seric */ 22258109Seric 22358151Seric message("553 %s config error: mail loops back to myself", 22447570Seric MyHostName); 22514877Seric break; 22614877Seric } 22758512Seric (void) strcpy(hostbuf, p); 22858512Seric (void) strcat(hostbuf, " ("); 22958512Seric (void) strcat(hostbuf, inet_ntoa(RealHostAddr.sin_addr)); 23058308Seric if (strcasecmp(p, RealHostName) != 0) 23111146Seric { 23258512Seric (void) strcat(hostbuf, "; "); 23358512Seric (void) strcat(hostbuf, RealHostName); 23411146Seric } 23558512Seric (void) strcat(hostbuf, ")"); 23658512Seric sendinghost = newstr(hostbuf); 23758323Seric 23858323Seric /* send ext. message -- old systems must ignore */ 23958323Seric message("250-%s Hello %s, pleased to meet you", 24036230Skarels MyHostName, sendinghost); 24158323Seric if (!bitset(PRIV_NOEXPN, PrivacyFlags)) 24258323Seric message("250-EXPN"); 24358338Seric message("250-SIZE"); 24458323Seric message("250 HELP"); 24558082Seric gothello = TRUE; 2464976Seric break; 2474976Seric 2484549Seric case CMDMAIL: /* mail -- designate sender */ 24924943Seric SmtpPhase = "MAIL"; 25024943Seric 25111151Seric /* force a sending host even if no HELO given */ 25258064Seric if (sendinghost == NULL && macvalue('s', e) == NULL) 25330448Seric sendinghost = RealHostName; 25411151Seric 2559314Seric /* check for validity of this command */ 25658082Seric if (!gothello && bitset(PRIV_NEEDMAILHELO, PrivacyFlags)) 25758082Seric { 25858151Seric message("503 Polite people say HELO first"); 25958082Seric break; 26058082Seric } 26158109Seric if (gotmail) 2624558Seric { 26358151Seric message("503 Sender already specified"); 2644558Seric break; 2654558Seric } 2669339Seric if (InChild) 2679339Seric { 26836230Skarels errno = 0; 26958151Seric syserr("503 Nested MAIL command: MAIL %s", p); 27058069Seric finis(); 2719339Seric } 2729339Seric 2739339Seric /* fork a subprocess to process this command */ 27455012Seric if (runinchild("SMTP-MAIL", e) > 0) 2759339Seric break; 27658064Seric if (sendinghost != NULL) 27758064Seric define('s', sendinghost, e); 27858323Seric if (protocol == NULL) 27958323Seric protocol = "SMTP"; 28058323Seric define('r', protocol, e); 28155012Seric initsys(e); 28257389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 2839339Seric 2849339Seric /* child -- go do the processing */ 2854549Seric p = skipword(p, "from"); 2864549Seric if (p == NULL) 2874549Seric break; 28857977Seric if (setjmp(TopFrame) > 0) 28958147Seric { 29058147Seric /* this failed -- undo work */ 29158147Seric if (InChild) 29258147Seric finis(); 29357977Seric break; 29458147Seric } 29557977Seric QuickAbort = TRUE; 29658333Seric 29758333Seric /* must parse sender first */ 29858333Seric delimptr = NULL; 299*58704Seric setsender(p, e, &delimptr, FALSE); 30058333Seric p = delimptr; 30158333Seric if (p != NULL && *p != '\0') 30258333Seric *p++ = '\0'; 30358333Seric 30458333Seric /* now parse ESMTP arguments */ 30558333Seric msize = 0; 30658333Seric for (; p != NULL && *p != '\0'; p++) 30758333Seric { 30858333Seric char *kp; 30958333Seric char *vp; 31058333Seric 31158333Seric /* locate the beginning of the keyword */ 31258333Seric while (isascii(*p) && isspace(*p)) 31358333Seric p++; 31458333Seric if (*p == '\0') 31558333Seric break; 31658333Seric kp = p; 31758333Seric 31858333Seric /* skip to the value portion */ 31958333Seric while (isascii(*p) && isalnum(*p) || *p == '-') 32058333Seric p++; 32158333Seric if (*p == '=') 32258333Seric { 32358333Seric *p++ = '\0'; 32458333Seric vp = p; 32558333Seric 32658333Seric /* skip to the end of the value */ 32758333Seric while (*p != '\0' && *p != ' ' && 32858333Seric !(isascii(*p) && iscntrl(*p)) && 32958333Seric *p != '=') 33058333Seric p++; 33158333Seric } 33258333Seric 33358333Seric if (*p != '\0') 33458333Seric *p++ = '\0'; 33558333Seric 33658333Seric if (tTd(19, 1)) 33758333Seric printf("MAIL: got arg %s=%s\n", kp, 33858333Seric vp == NULL ? "<null>" : vp); 33958333Seric 34058333Seric if (strcasecmp(kp, "size") == 0) 34158333Seric { 34258333Seric if (kp == NULL) 34358333Seric { 34458333Seric usrerr("501 SIZE requires a value"); 34558333Seric /* NOTREACHED */ 34658333Seric } 34758333Seric msize = atol(vp); 34858333Seric } 34958333Seric else 35058333Seric { 35158333Seric usrerr("501 %s parameter unrecognized", kp); 35258333Seric /* NOTREACHED */ 35358333Seric } 35458333Seric } 35558333Seric 35658333Seric if (!enoughspace(msize)) 35758333Seric { 35858333Seric message("452 Insufficient disk space; try again later"); 35958333Seric break; 36058333Seric } 36158151Seric message("250 Sender ok"); 36258147Seric gotmail = TRUE; 3634549Seric break; 3644549Seric 3654976Seric case CMDRCPT: /* rcpt -- designate recipient */ 36624943Seric SmtpPhase = "RCPT"; 36757389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 36812612Seric if (setjmp(TopFrame) > 0) 36914785Seric { 37055012Seric e->e_flags &= ~EF_FATALERRS; 37112612Seric break; 37214785Seric } 37312612Seric QuickAbort = TRUE; 37451951Seric LogUsrErrs = TRUE; 37558093Seric 37658093Seric /* optimization -- if queueing, don't expand aliases */ 37758093Seric if (SendMode == SM_QUEUE) 37858093Seric e->e_flags |= EF_VRFYONLY; 37958093Seric 3804549Seric p = skipword(p, "to"); 3814549Seric if (p == NULL) 3824549Seric break; 38358333Seric a = parseaddr(p, (ADDRESS *) NULL, 1, ' ', NULL, e); 38412612Seric if (a == NULL) 38512612Seric break; 38616886Seric a->q_flags |= QPRIMARY; 38755012Seric a = recipient(a, &e->e_sendqueue, e); 38812612Seric if (Errors != 0) 38912612Seric break; 39012612Seric 39112612Seric /* no errors during parsing, but might be a duplicate */ 39255012Seric e->e_to = p; 39312612Seric if (!bitset(QBADADDR, a->q_flags)) 39458151Seric message("250 Recipient ok"); 39512612Seric else 3964549Seric { 39712612Seric /* punt -- should keep message in ADDRESS.... */ 39858151Seric message("550 Addressee unknown"); 3994549Seric } 40055012Seric e->e_to = NULL; 4014549Seric break; 4024549Seric 4034549Seric case CMDDATA: /* data -- text of mail */ 40424943Seric SmtpPhase = "DATA"; 40558109Seric if (!gotmail) 4064549Seric { 40758151Seric message("503 Need MAIL command"); 4084976Seric break; 4094549Seric } 41055012Seric else if (e->e_nrcpts <= 0) 4114549Seric { 41258151Seric message("503 Need RCPT (recipient)"); 4134976Seric break; 4144549Seric } 4154976Seric 4164976Seric /* collect the text of the message */ 41724943Seric SmtpPhase = "collect"; 41857389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 41955012Seric collect(TRUE, e); 4204976Seric if (Errors != 0) 4214976Seric break; 4224976Seric 4238238Seric /* 4248238Seric ** Arrange to send to everyone. 4258238Seric ** If sending to multiple people, mail back 4268238Seric ** errors rather than reporting directly. 4278238Seric ** In any case, don't mail back errors for 4288238Seric ** anything that has happened up to 4298238Seric ** now (the other end will do this). 43010197Seric ** Truncate our transcript -- the mail has gotten 43110197Seric ** to us successfully, and if we have 43210197Seric ** to mail this back, it will be easier 43310197Seric ** on the reader. 4348238Seric ** Then send to everyone. 4358238Seric ** Finally give a reply code. If an error has 4368238Seric ** already been given, don't mail a 4378238Seric ** message back. 4389339Seric ** We goose error returns by clearing error bit. 4398238Seric */ 4408238Seric 44124943Seric SmtpPhase = "delivery"; 44255012Seric if (e->e_nrcpts != 1) 4439378Seric { 4449378Seric HoldErrs = TRUE; 44516886Seric ErrorMode = EM_MAIL; 4469378Seric } 44755012Seric e->e_flags &= ~EF_FATALERRS; 44855012Seric e->e_xfp = freopen(queuename(e, 'x'), "w", e->e_xfp); 4494976Seric 4504976Seric /* send to all recipients */ 45155012Seric sendall(e, SM_DEFAULT); 45255012Seric e->e_to = NULL; 4534976Seric 45423516Seric /* save statistics */ 45555012Seric markstats(e, (ADDRESS *) NULL); 45623516Seric 4578238Seric /* issue success if appropriate and reset */ 4588238Seric if (Errors == 0 || HoldErrs) 45958151Seric message("250 Ok"); 4608238Seric else 46155012Seric e->e_flags &= ~EF_FATALERRS; 4629339Seric 4639339Seric /* if in a child, pop back to our parent */ 4649339Seric if (InChild) 4659339Seric finis(); 46624943Seric 46724943Seric /* clean up a bit */ 46858109Seric gotmail = FALSE; 46955012Seric dropenvelope(e); 47058179Seric CurEnv = e = newenvelope(e, CurEnv); 47155012Seric e->e_flags = BlankEnvelope.e_flags; 4724549Seric break; 4734549Seric 4744549Seric case CMDRSET: /* rset -- reset state */ 47558151Seric message("250 Reset state"); 4769339Seric if (InChild) 4779339Seric finis(); 47858109Seric 47958109Seric /* clean up a bit */ 48058109Seric gotmail = FALSE; 48158109Seric dropenvelope(e); 48258179Seric CurEnv = e = newenvelope(e, CurEnv); 4839339Seric break; 4844549Seric 4854549Seric case CMDVRFY: /* vrfy -- verify address */ 48658092Seric case CMDEXPN: /* expn -- expand address */ 48758092Seric vrfy = c->cmdcode == CMDVRFY; 48858092Seric if (bitset(vrfy ? PRIV_NOVRFY : PRIV_NOEXPN, 48958092Seric PrivacyFlags)) 49058082Seric { 49158412Seric if (vrfy) 49258412Seric message("252 Who's to say?"); 49358412Seric else 49458412Seric message("502 That's none of your business"); 49558082Seric break; 49658082Seric } 49758082Seric else if (!gothello && 49858092Seric bitset(vrfy ? PRIV_NEEDVRFYHELO : PRIV_NEEDEXPNHELO, 49958092Seric PrivacyFlags)) 50058082Seric { 50158151Seric message("503 I demand that you introduce yourself first"); 50258082Seric break; 50358082Seric } 50458092Seric if (runinchild(vrfy ? "SMTP-VRFY" : "SMTP-EXPN", e) > 0) 5059339Seric break; 50625050Seric setproctitle("%s: %s", CurHostName, inp); 50755173Seric #ifdef LOG 50858020Seric if (LogLevel > 5) 50955173Seric syslog(LOG_INFO, "%s: %s", CurHostName, inp); 51055173Seric #endif 5115003Seric vrfyqueue = NULL; 5127762Seric QuickAbort = TRUE; 51358092Seric if (vrfy) 51458092Seric e->e_flags |= EF_VRFYONLY; 51558082Seric (void) sendtolist(p, (ADDRESS *) NULL, &vrfyqueue, e); 5167762Seric if (Errors != 0) 5179339Seric { 5189339Seric if (InChild) 5199339Seric finis(); 5207762Seric break; 5219339Seric } 5225003Seric while (vrfyqueue != NULL) 5235003Seric { 5245003Seric register ADDRESS *a = vrfyqueue->q_next; 5255003Seric char *code; 5265003Seric 5277685Seric while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags)) 5285003Seric a = a->q_next; 5295003Seric 5307685Seric if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags)) 53158151Seric printvrfyaddr(vrfyqueue, a == NULL); 5325003Seric else if (a == NULL) 53358151Seric message("554 Self destructive alias loop"); 5345003Seric vrfyqueue = a; 5355003Seric } 5369339Seric if (InChild) 5379339Seric finis(); 5384549Seric break; 5394549Seric 5404549Seric case CMDHELP: /* help -- give user info */ 5414577Seric help(p); 5424549Seric break; 5434549Seric 5444549Seric case CMDNOOP: /* noop -- do nothing */ 54558151Seric message("200 OK"); 5464549Seric break; 5474549Seric 5484549Seric case CMDQUIT: /* quit -- leave mail */ 54958151Seric message("221 %s closing connection", MyHostName); 5509339Seric if (InChild) 5519339Seric ExitStat = EX_QUIT; 5524549Seric finis(); 5534549Seric 5548544Seric case CMDVERB: /* set verbose mode */ 5558544Seric Verbose = TRUE; 55625025Seric SendMode = SM_DELIVER; 55758151Seric message("200 Verbose mode"); 5588544Seric break; 5598544Seric 5609314Seric case CMDONEX: /* doing one transaction only */ 5619378Seric OneXact = TRUE; 56258151Seric message("200 Only one transaction"); 5639314Seric break; 5649314Seric 56536230Skarels # ifdef SMTPDEBUG 5669339Seric case CMDDBGQSHOW: /* show queues */ 5676907Seric printf("Send Queue="); 56855012Seric printaddr(e->e_sendqueue, TRUE); 5695003Seric break; 5707275Seric 5717275Seric case CMDDBGDEBUG: /* set debug mode */ 5727676Seric tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); 5737676Seric tTflag(p); 57458151Seric message("200 Debug set"); 5757275Seric break; 5767275Seric 57736230Skarels # else /* not SMTPDEBUG */ 57824945Seric 57936230Skarels case CMDDBGQSHOW: /* show queues */ 58036230Skarels case CMDDBGDEBUG: /* set debug mode */ 58136233Skarels # ifdef LOG 58258308Seric if (LogLevel > 0) 58336230Skarels syslog(LOG_NOTICE, 58458020Seric "\"%s\" command from %s (%s)", 58536230Skarels c->cmdname, RealHostName, 58636230Skarels inet_ntoa(RealHostAddr.sin_addr)); 58736233Skarels # endif 58836230Skarels /* FALL THROUGH */ 58936230Skarels # endif /* SMTPDEBUG */ 59036230Skarels 5914549Seric case CMDERROR: /* unknown command */ 59258151Seric message("500 Command unrecognized"); 5934549Seric break; 5944549Seric 5954549Seric default: 59636230Skarels errno = 0; 59758151Seric syserr("500 smtp: unknown code %d", c->cmdcode); 5984549Seric break; 5994549Seric } 6004549Seric } 6014549Seric } 6024549Seric /* 6034549Seric ** SKIPWORD -- skip a fixed word. 6044549Seric ** 6054549Seric ** Parameters: 6064549Seric ** p -- place to start looking. 6074549Seric ** w -- word to skip. 6084549Seric ** 6094549Seric ** Returns: 6104549Seric ** p following w. 6114549Seric ** NULL on error. 6124549Seric ** 6134549Seric ** Side Effects: 6144549Seric ** clobbers the p data area. 6154549Seric */ 6164549Seric 6174549Seric static char * 6184549Seric skipword(p, w) 6194549Seric register char *p; 6204549Seric char *w; 6214549Seric { 6224549Seric register char *q; 6234549Seric 6244549Seric /* find beginning of word */ 62558050Seric while (isascii(*p) && isspace(*p)) 6264549Seric p++; 6274549Seric q = p; 6284549Seric 6294549Seric /* find end of word */ 63058050Seric while (*p != '\0' && *p != ':' && !(isascii(*p) && isspace(*p))) 6314549Seric p++; 63258050Seric while (isascii(*p) && isspace(*p)) 6334549Seric *p++ = '\0'; 6344549Seric if (*p != ':') 6354549Seric { 6364549Seric syntax: 63758151Seric message("501 Syntax error"); 6384549Seric Errors++; 6394549Seric return (NULL); 6404549Seric } 6414549Seric *p++ = '\0'; 64258050Seric while (isascii(*p) && isspace(*p)) 6434549Seric p++; 6444549Seric 6454549Seric /* see if the input word matches desired word */ 64633725Sbostic if (strcasecmp(q, w)) 6474549Seric goto syntax; 6484549Seric 6494549Seric return (p); 6504549Seric } 6514577Seric /* 65258151Seric ** PRINTVRFYADDR -- print an entry in the verify queue 65358151Seric ** 65458151Seric ** Parameters: 65558151Seric ** a -- the address to print 65658151Seric ** last -- set if this is the last one. 65758151Seric ** 65858151Seric ** Returns: 65958151Seric ** none. 66058151Seric ** 66158151Seric ** Side Effects: 66258151Seric ** Prints the appropriate 250 codes. 66358151Seric */ 66458151Seric 66558151Seric printvrfyaddr(a, last) 66658151Seric register ADDRESS *a; 66758151Seric bool last; 66858151Seric { 66958151Seric char fmtbuf[20]; 67058151Seric 67158151Seric strcpy(fmtbuf, "250"); 67258151Seric fmtbuf[3] = last ? ' ' : '-'; 67358151Seric 67458151Seric if (strchr(a->q_paddr, '<') != NULL) 67558151Seric strcpy(&fmtbuf[4], "%s"); 67658151Seric else if (a->q_fullname == NULL) 67758151Seric strcpy(&fmtbuf[4], "<%s>"); 67858151Seric else 67958151Seric { 68058151Seric strcpy(&fmtbuf[4], "%s <%s>"); 68158151Seric message(fmtbuf, a->q_fullname, a->q_paddr); 68258151Seric return; 68358151Seric } 68458151Seric message(fmtbuf, a->q_paddr); 68558151Seric } 68658151Seric /* 6874577Seric ** HELP -- implement the HELP command. 6884577Seric ** 6894577Seric ** Parameters: 6904577Seric ** topic -- the topic we want help for. 6914577Seric ** 6924577Seric ** Returns: 6934577Seric ** none. 6944577Seric ** 6954577Seric ** Side Effects: 6964577Seric ** outputs the help file to message output. 6974577Seric */ 6984577Seric 6994577Seric help(topic) 7004577Seric char *topic; 7014577Seric { 7024577Seric register FILE *hf; 7034577Seric int len; 7044577Seric char buf[MAXLINE]; 7054577Seric bool noinfo; 7064577Seric 7078269Seric if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL) 7084577Seric { 7094577Seric /* no help */ 71011931Seric errno = 0; 71158151Seric message("502 HELP not implemented"); 7124577Seric return; 7134577Seric } 7144577Seric 71549669Seric if (topic == NULL || *topic == '\0') 71649669Seric topic = "smtp"; 71749669Seric else 71849669Seric makelower(topic); 71949669Seric 7204577Seric len = strlen(topic); 7214577Seric noinfo = TRUE; 7224577Seric 7234577Seric while (fgets(buf, sizeof buf, hf) != NULL) 7244577Seric { 7254577Seric if (strncmp(buf, topic, len) == 0) 7264577Seric { 7274577Seric register char *p; 7284577Seric 72956795Seric p = strchr(buf, '\t'); 7304577Seric if (p == NULL) 7314577Seric p = buf; 7324577Seric else 7334577Seric p++; 7344577Seric fixcrlf(p, TRUE); 73558151Seric message("214-%s", p); 7364577Seric noinfo = FALSE; 7374577Seric } 7384577Seric } 7394577Seric 7404577Seric if (noinfo) 74158151Seric message("504 HELP topic unknown"); 7424577Seric else 74358151Seric message("214 End of HELP info"); 7444628Seric (void) fclose(hf); 7454577Seric } 7468544Seric /* 7479339Seric ** RUNINCHILD -- return twice -- once in the child, then in the parent again 7489339Seric ** 7499339Seric ** Parameters: 7509339Seric ** label -- a string used in error messages 7519339Seric ** 7529339Seric ** Returns: 7539339Seric ** zero in the child 7549339Seric ** one in the parent 7559339Seric ** 7569339Seric ** Side Effects: 7579339Seric ** none. 7589339Seric */ 7598544Seric 76055012Seric runinchild(label, e) 7619339Seric char *label; 76255012Seric register ENVELOPE *e; 7639339Seric { 7649339Seric int childpid; 7659339Seric 76616158Seric if (!OneXact) 7679339Seric { 76816158Seric childpid = dofork(); 76916158Seric if (childpid < 0) 77016158Seric { 77116158Seric syserr("%s: cannot fork", label); 77216158Seric return (1); 77316158Seric } 77416158Seric if (childpid > 0) 77516158Seric { 77616158Seric auto int st; 7779339Seric 77816158Seric /* parent -- wait for child to complete */ 77916158Seric st = waitfor(childpid); 78016158Seric if (st == -1) 78116158Seric syserr("%s: lost child", label); 7829339Seric 78316158Seric /* if we exited on a QUIT command, complete the process */ 78416158Seric if (st == (EX_QUIT << 8)) 78516158Seric finis(); 7869339Seric 78716158Seric return (1); 78816158Seric } 78916158Seric else 79016158Seric { 79116158Seric /* child */ 79216158Seric InChild = TRUE; 79325050Seric QuickAbort = FALSE; 79455012Seric clearenvelope(e, FALSE); 79516158Seric } 7969339Seric } 79715256Seric 79816158Seric /* open alias database */ 79955012Seric initaliases(AliasFile, FALSE, e); 80016158Seric 80116158Seric return (0); 8029339Seric } 8039339Seric 80456795Seric # endif /* SMTP */ 805