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*58412Seric static char sccsid[] = "@(#)srvrsmtp.c 6.23 (Berkeley) 03/03/93 (with SMTP)"; 1433731Sbostic #else 15*58412Seric static char sccsid[] = "@(#)srvrsmtp.c 6.23 (Berkeley) 03/03/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]; 1117124Seric extern char Version[]; 11211151Seric extern char *macvalue(); 11312612Seric extern ADDRESS *recipient(); 11424943Seric extern ENVELOPE BlankEnvelope; 11524943Seric extern ENVELOPE *newenvelope(); 1164549Seric 1177363Seric if (OutChannel != stdout) 1187363Seric { 1197363Seric /* arrange for debugging output to go to remote host */ 1207363Seric (void) close(1); 1217363Seric (void) dup(fileno(OutChannel)); 1227363Seric } 12355012Seric settime(e); 12457642Seric CurHostName = RealHostName; 12557642Seric setproctitle("srvrsmtp %s", CurHostName); 12658050Seric expand("\201e", inp, &inp[sizeof inp], e); 12758151Seric message("220 %s", inp); 12824943Seric SmtpPhase = "startup"; 12930448Seric sendinghost = NULL; 13058330Seric protocol = NULL; 13158082Seric gothello = FALSE; 13258330Seric gotmail = FALSE; 1334549Seric for (;;) 1344549Seric { 13512612Seric /* arrange for backout */ 13612612Seric if (setjmp(TopFrame) > 0 && InChild) 13712612Seric finis(); 13812612Seric QuickAbort = FALSE; 13912612Seric HoldErrs = FALSE; 14051951Seric LogUsrErrs = FALSE; 14158092Seric e->e_flags &= ~EF_VRFYONLY; 14212612Seric 1437356Seric /* setup for the read */ 14455012Seric e->e_to = NULL; 1454577Seric Errors = 0; 1467275Seric (void) fflush(stdout); 1477356Seric 1487356Seric /* read the input line */ 14958109Seric p = sfgets(inp, sizeof inp, InChannel, TimeOuts.to_nextcommand); 1507356Seric 1517685Seric /* handle errors */ 1527356Seric if (p == NULL) 1537356Seric { 1544549Seric /* end of file, just die */ 15558151Seric message("421 %s Lost input channel from %s", 15625050Seric MyHostName, CurHostName); 15755464Seric #ifdef LOG 15858020Seric if (LogLevel > 1) 15955464Seric syslog(LOG_NOTICE, "lost input channel from %s", 16055464Seric CurHostName); 16155464Seric #endif 16258069Seric if (InChild) 16358069Seric ExitStat = EX_QUIT; 1644549Seric finis(); 1654549Seric } 1664549Seric 1674549Seric /* clean up end of line */ 1684558Seric fixcrlf(inp, TRUE); 1694549Seric 1704713Seric /* echo command to transcript */ 17155012Seric if (e->e_xfp != NULL) 17255012Seric fprintf(e->e_xfp, "<<< %s\n", inp); 1734713Seric 1744549Seric /* break off command */ 17558050Seric for (p = inp; isascii(*p) && isspace(*p); p++) 1764549Seric continue; 17757232Seric cmd = cmdbuf; 17858050Seric while (*p != '\0' && 17958050Seric !(isascii(*p) && isspace(*p)) && 18058050Seric cmd < &cmdbuf[sizeof cmdbuf - 2]) 18124981Seric *cmd++ = *p++; 18224981Seric *cmd = '\0'; 1834549Seric 18425691Seric /* throw away leading whitespace */ 18558050Seric while (isascii(*p) && isspace(*p)) 18625691Seric p++; 18725691Seric 1884549Seric /* decode command */ 1894549Seric for (c = CmdTab; c->cmdname != NULL; c++) 1904549Seric { 19133725Sbostic if (!strcasecmp(c->cmdname, cmdbuf)) 1924549Seric break; 1934549Seric } 1944549Seric 19551954Seric /* reset errors */ 19651954Seric errno = 0; 19751954Seric 1984549Seric /* process command */ 1994549Seric switch (c->cmdcode) 2004549Seric { 2014976Seric case CMDHELO: /* hello -- introduce yourself */ 20258323Seric case CMDEHLO: /* extended hello */ 20358323Seric if (c->cmdcode == CMDEHLO) 20458323Seric { 20558323Seric protocol = "ESMTP"; 20658323Seric SmtpPhase = "EHLO"; 20758323Seric } 20858323Seric else 20958323Seric { 21058323Seric protocol = "SMTP"; 21158323Seric SmtpPhase = "HELO"; 21258323Seric } 21325050Seric setproctitle("%s: %s", CurHostName, inp); 21458109Seric if (strcasecmp(p, MyHostName) == 0) 21514877Seric { 21636230Skarels /* 21758109Seric ** Didn't know about alias or MX, 21858109Seric ** or connected to an echo server 21958109Seric */ 22058109Seric 22158151Seric message("553 %s config error: mail loops back to myself", 22247570Seric MyHostName); 22314877Seric break; 22414877Seric } 22558308Seric if (strcasecmp(p, RealHostName) != 0) 22611146Seric { 22724981Seric char hostbuf[MAXNAME]; 22811146Seric 22924981Seric (void) sprintf(hostbuf, "%s (%s)", p, RealHostName); 23030448Seric sendinghost = newstr(hostbuf); 23111146Seric } 23211146Seric else 23330448Seric sendinghost = newstr(p); 23458323Seric 23558323Seric /* send ext. message -- old systems must ignore */ 23658323Seric message("250-%s Hello %s, pleased to meet you", 23736230Skarels MyHostName, sendinghost); 23858323Seric if (!bitset(PRIV_NOEXPN, PrivacyFlags)) 23958323Seric message("250-EXPN"); 24058338Seric message("250-SIZE"); 24158323Seric message("250 HELP"); 24258082Seric gothello = TRUE; 2434976Seric break; 2444976Seric 2454549Seric case CMDMAIL: /* mail -- designate sender */ 24624943Seric SmtpPhase = "MAIL"; 24724943Seric 24811151Seric /* force a sending host even if no HELO given */ 24958064Seric if (sendinghost == NULL && macvalue('s', e) == NULL) 25030448Seric sendinghost = RealHostName; 25111151Seric 2529314Seric /* check for validity of this command */ 25358082Seric if (!gothello && bitset(PRIV_NEEDMAILHELO, PrivacyFlags)) 25458082Seric { 25558151Seric message("503 Polite people say HELO first"); 25658082Seric break; 25758082Seric } 25858109Seric if (gotmail) 2594558Seric { 26058151Seric message("503 Sender already specified"); 2614558Seric break; 2624558Seric } 2639339Seric if (InChild) 2649339Seric { 26536230Skarels errno = 0; 26658151Seric syserr("503 Nested MAIL command: MAIL %s", p); 26758069Seric finis(); 2689339Seric } 2699339Seric 2709339Seric /* fork a subprocess to process this command */ 27155012Seric if (runinchild("SMTP-MAIL", e) > 0) 2729339Seric break; 27358064Seric if (sendinghost != NULL) 27458064Seric define('s', sendinghost, e); 27558323Seric if (protocol == NULL) 27658323Seric protocol = "SMTP"; 27758323Seric define('r', protocol, e); 27855012Seric initsys(e); 27957389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 2809339Seric 2819339Seric /* child -- go do the processing */ 2824549Seric p = skipword(p, "from"); 2834549Seric if (p == NULL) 2844549Seric break; 28557977Seric if (setjmp(TopFrame) > 0) 28658147Seric { 28758147Seric /* this failed -- undo work */ 28858147Seric if (InChild) 28958147Seric finis(); 29057977Seric break; 29158147Seric } 29257977Seric QuickAbort = TRUE; 29358333Seric 29458333Seric /* must parse sender first */ 29558333Seric delimptr = NULL; 29658333Seric setsender(p, e, &delimptr); 29758333Seric p = delimptr; 29858333Seric if (p != NULL && *p != '\0') 29958333Seric *p++ = '\0'; 30058333Seric 30158333Seric /* now parse ESMTP arguments */ 30258333Seric msize = 0; 30358333Seric for (; p != NULL && *p != '\0'; p++) 30458333Seric { 30558333Seric char *kp; 30658333Seric char *vp; 30758333Seric 30858333Seric /* locate the beginning of the keyword */ 30958333Seric while (isascii(*p) && isspace(*p)) 31058333Seric p++; 31158333Seric if (*p == '\0') 31258333Seric break; 31358333Seric kp = p; 31458333Seric 31558333Seric /* skip to the value portion */ 31658333Seric while (isascii(*p) && isalnum(*p) || *p == '-') 31758333Seric p++; 31858333Seric if (*p == '=') 31958333Seric { 32058333Seric *p++ = '\0'; 32158333Seric vp = p; 32258333Seric 32358333Seric /* skip to the end of the value */ 32458333Seric while (*p != '\0' && *p != ' ' && 32558333Seric !(isascii(*p) && iscntrl(*p)) && 32658333Seric *p != '=') 32758333Seric p++; 32858333Seric } 32958333Seric 33058333Seric if (*p != '\0') 33158333Seric *p++ = '\0'; 33258333Seric 33358333Seric if (tTd(19, 1)) 33458333Seric printf("MAIL: got arg %s=%s\n", kp, 33558333Seric vp == NULL ? "<null>" : vp); 33658333Seric 33758333Seric if (strcasecmp(kp, "size") == 0) 33858333Seric { 33958333Seric if (kp == NULL) 34058333Seric { 34158333Seric usrerr("501 SIZE requires a value"); 34258333Seric /* NOTREACHED */ 34358333Seric } 34458333Seric msize = atol(vp); 34558333Seric } 34658333Seric else 34758333Seric { 34858333Seric usrerr("501 %s parameter unrecognized", kp); 34958333Seric /* NOTREACHED */ 35058333Seric } 35158333Seric } 35258333Seric 35358333Seric if (!enoughspace(msize)) 35458333Seric { 35558333Seric message("452 Insufficient disk space; try again later"); 35658333Seric break; 35758333Seric } 35858151Seric message("250 Sender ok"); 35958147Seric gotmail = TRUE; 3604549Seric break; 3614549Seric 3624976Seric case CMDRCPT: /* rcpt -- designate recipient */ 36324943Seric SmtpPhase = "RCPT"; 36457389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 36512612Seric if (setjmp(TopFrame) > 0) 36614785Seric { 36755012Seric e->e_flags &= ~EF_FATALERRS; 36812612Seric break; 36914785Seric } 37012612Seric QuickAbort = TRUE; 37151951Seric LogUsrErrs = TRUE; 37258093Seric 37358093Seric /* optimization -- if queueing, don't expand aliases */ 37458093Seric if (SendMode == SM_QUEUE) 37558093Seric e->e_flags |= EF_VRFYONLY; 37658093Seric 3774549Seric p = skipword(p, "to"); 3784549Seric if (p == NULL) 3794549Seric break; 38058333Seric a = parseaddr(p, (ADDRESS *) NULL, 1, ' ', NULL, e); 38112612Seric if (a == NULL) 38212612Seric break; 38316886Seric a->q_flags |= QPRIMARY; 38455012Seric a = recipient(a, &e->e_sendqueue, e); 38512612Seric if (Errors != 0) 38612612Seric break; 38712612Seric 38812612Seric /* no errors during parsing, but might be a duplicate */ 38955012Seric e->e_to = p; 39012612Seric if (!bitset(QBADADDR, a->q_flags)) 39158151Seric message("250 Recipient ok"); 39212612Seric else 3934549Seric { 39412612Seric /* punt -- should keep message in ADDRESS.... */ 39558151Seric message("550 Addressee unknown"); 3964549Seric } 39755012Seric e->e_to = NULL; 3984549Seric break; 3994549Seric 4004549Seric case CMDDATA: /* data -- text of mail */ 40124943Seric SmtpPhase = "DATA"; 40258109Seric if (!gotmail) 4034549Seric { 40458151Seric message("503 Need MAIL command"); 4054976Seric break; 4064549Seric } 40755012Seric else if (e->e_nrcpts <= 0) 4084549Seric { 40958151Seric message("503 Need RCPT (recipient)"); 4104976Seric break; 4114549Seric } 4124976Seric 4134976Seric /* collect the text of the message */ 41424943Seric SmtpPhase = "collect"; 41557389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 41655012Seric collect(TRUE, e); 4174976Seric if (Errors != 0) 4184976Seric break; 4194976Seric 4208238Seric /* 4218238Seric ** Arrange to send to everyone. 4228238Seric ** If sending to multiple people, mail back 4238238Seric ** errors rather than reporting directly. 4248238Seric ** In any case, don't mail back errors for 4258238Seric ** anything that has happened up to 4268238Seric ** now (the other end will do this). 42710197Seric ** Truncate our transcript -- the mail has gotten 42810197Seric ** to us successfully, and if we have 42910197Seric ** to mail this back, it will be easier 43010197Seric ** on the reader. 4318238Seric ** Then send to everyone. 4328238Seric ** Finally give a reply code. If an error has 4338238Seric ** already been given, don't mail a 4348238Seric ** message back. 4359339Seric ** We goose error returns by clearing error bit. 4368238Seric */ 4378238Seric 43824943Seric SmtpPhase = "delivery"; 43955012Seric if (e->e_nrcpts != 1) 4409378Seric { 4419378Seric HoldErrs = TRUE; 44216886Seric ErrorMode = EM_MAIL; 4439378Seric } 44455012Seric e->e_flags &= ~EF_FATALERRS; 44555012Seric e->e_xfp = freopen(queuename(e, 'x'), "w", e->e_xfp); 4464976Seric 4474976Seric /* send to all recipients */ 44855012Seric sendall(e, SM_DEFAULT); 44955012Seric e->e_to = NULL; 4504976Seric 45123516Seric /* save statistics */ 45255012Seric markstats(e, (ADDRESS *) NULL); 45323516Seric 4548238Seric /* issue success if appropriate and reset */ 4558238Seric if (Errors == 0 || HoldErrs) 45658151Seric message("250 Ok"); 4578238Seric else 45855012Seric e->e_flags &= ~EF_FATALERRS; 4599339Seric 4609339Seric /* if in a child, pop back to our parent */ 4619339Seric if (InChild) 4629339Seric finis(); 46324943Seric 46424943Seric /* clean up a bit */ 46558109Seric gotmail = FALSE; 46655012Seric dropenvelope(e); 46758179Seric CurEnv = e = newenvelope(e, CurEnv); 46855012Seric e->e_flags = BlankEnvelope.e_flags; 4694549Seric break; 4704549Seric 4714549Seric case CMDRSET: /* rset -- reset state */ 47258151Seric message("250 Reset state"); 4739339Seric if (InChild) 4749339Seric finis(); 47558109Seric 47658109Seric /* clean up a bit */ 47758109Seric gotmail = FALSE; 47858109Seric dropenvelope(e); 47958179Seric CurEnv = e = newenvelope(e, CurEnv); 4809339Seric break; 4814549Seric 4824549Seric case CMDVRFY: /* vrfy -- verify address */ 48358092Seric case CMDEXPN: /* expn -- expand address */ 48458092Seric vrfy = c->cmdcode == CMDVRFY; 48558092Seric if (bitset(vrfy ? PRIV_NOVRFY : PRIV_NOEXPN, 48658092Seric PrivacyFlags)) 48758082Seric { 488*58412Seric if (vrfy) 489*58412Seric message("252 Who's to say?"); 490*58412Seric else 491*58412Seric message("502 That's none of your business"); 49258082Seric break; 49358082Seric } 49458082Seric else if (!gothello && 49558092Seric bitset(vrfy ? PRIV_NEEDVRFYHELO : PRIV_NEEDEXPNHELO, 49658092Seric PrivacyFlags)) 49758082Seric { 49858151Seric message("503 I demand that you introduce yourself first"); 49958082Seric break; 50058082Seric } 50158092Seric if (runinchild(vrfy ? "SMTP-VRFY" : "SMTP-EXPN", e) > 0) 5029339Seric break; 50325050Seric setproctitle("%s: %s", CurHostName, inp); 50455173Seric #ifdef LOG 50558020Seric if (LogLevel > 5) 50655173Seric syslog(LOG_INFO, "%s: %s", CurHostName, inp); 50755173Seric #endif 5085003Seric vrfyqueue = NULL; 5097762Seric QuickAbort = TRUE; 51058092Seric if (vrfy) 51158092Seric e->e_flags |= EF_VRFYONLY; 51258082Seric (void) sendtolist(p, (ADDRESS *) NULL, &vrfyqueue, e); 5137762Seric if (Errors != 0) 5149339Seric { 5159339Seric if (InChild) 5169339Seric finis(); 5177762Seric break; 5189339Seric } 5195003Seric while (vrfyqueue != NULL) 5205003Seric { 5215003Seric register ADDRESS *a = vrfyqueue->q_next; 5225003Seric char *code; 5235003Seric 5247685Seric while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags)) 5255003Seric a = a->q_next; 5265003Seric 5277685Seric if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags)) 52858151Seric printvrfyaddr(vrfyqueue, a == NULL); 5295003Seric else if (a == NULL) 53058151Seric message("554 Self destructive alias loop"); 5315003Seric vrfyqueue = a; 5325003Seric } 5339339Seric if (InChild) 5349339Seric finis(); 5354549Seric break; 5364549Seric 5374549Seric case CMDHELP: /* help -- give user info */ 5384577Seric help(p); 5394549Seric break; 5404549Seric 5414549Seric case CMDNOOP: /* noop -- do nothing */ 54258151Seric message("200 OK"); 5434549Seric break; 5444549Seric 5454549Seric case CMDQUIT: /* quit -- leave mail */ 54658151Seric message("221 %s closing connection", MyHostName); 5479339Seric if (InChild) 5489339Seric ExitStat = EX_QUIT; 5494549Seric finis(); 5504549Seric 5518544Seric case CMDVERB: /* set verbose mode */ 5528544Seric Verbose = TRUE; 55325025Seric SendMode = SM_DELIVER; 55458151Seric message("200 Verbose mode"); 5558544Seric break; 5568544Seric 5579314Seric case CMDONEX: /* doing one transaction only */ 5589378Seric OneXact = TRUE; 55958151Seric message("200 Only one transaction"); 5609314Seric break; 5619314Seric 56236230Skarels # ifdef SMTPDEBUG 5639339Seric case CMDDBGQSHOW: /* show queues */ 5646907Seric printf("Send Queue="); 56555012Seric printaddr(e->e_sendqueue, TRUE); 5665003Seric break; 5677275Seric 5687275Seric case CMDDBGDEBUG: /* set debug mode */ 5697676Seric tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); 5707676Seric tTflag(p); 57158151Seric message("200 Debug set"); 5727275Seric break; 5737275Seric 57436230Skarels # else /* not SMTPDEBUG */ 57524945Seric 57636230Skarels case CMDDBGQSHOW: /* show queues */ 57736230Skarels case CMDDBGDEBUG: /* set debug mode */ 57836233Skarels # ifdef LOG 57958308Seric if (LogLevel > 0) 58036230Skarels syslog(LOG_NOTICE, 58158020Seric "\"%s\" command from %s (%s)", 58236230Skarels c->cmdname, RealHostName, 58336230Skarels inet_ntoa(RealHostAddr.sin_addr)); 58436233Skarels # endif 58536230Skarels /* FALL THROUGH */ 58636230Skarels # endif /* SMTPDEBUG */ 58736230Skarels 5884549Seric case CMDERROR: /* unknown command */ 58958151Seric message("500 Command unrecognized"); 5904549Seric break; 5914549Seric 5924549Seric default: 59336230Skarels errno = 0; 59458151Seric syserr("500 smtp: unknown code %d", c->cmdcode); 5954549Seric break; 5964549Seric } 5974549Seric } 5984549Seric } 5994549Seric /* 6004549Seric ** SKIPWORD -- skip a fixed word. 6014549Seric ** 6024549Seric ** Parameters: 6034549Seric ** p -- place to start looking. 6044549Seric ** w -- word to skip. 6054549Seric ** 6064549Seric ** Returns: 6074549Seric ** p following w. 6084549Seric ** NULL on error. 6094549Seric ** 6104549Seric ** Side Effects: 6114549Seric ** clobbers the p data area. 6124549Seric */ 6134549Seric 6144549Seric static char * 6154549Seric skipword(p, w) 6164549Seric register char *p; 6174549Seric char *w; 6184549Seric { 6194549Seric register char *q; 6204549Seric 6214549Seric /* find beginning of word */ 62258050Seric while (isascii(*p) && isspace(*p)) 6234549Seric p++; 6244549Seric q = p; 6254549Seric 6264549Seric /* find end of word */ 62758050Seric while (*p != '\0' && *p != ':' && !(isascii(*p) && isspace(*p))) 6284549Seric p++; 62958050Seric while (isascii(*p) && isspace(*p)) 6304549Seric *p++ = '\0'; 6314549Seric if (*p != ':') 6324549Seric { 6334549Seric syntax: 63458151Seric message("501 Syntax error"); 6354549Seric Errors++; 6364549Seric return (NULL); 6374549Seric } 6384549Seric *p++ = '\0'; 63958050Seric while (isascii(*p) && isspace(*p)) 6404549Seric p++; 6414549Seric 6424549Seric /* see if the input word matches desired word */ 64333725Sbostic if (strcasecmp(q, w)) 6444549Seric goto syntax; 6454549Seric 6464549Seric return (p); 6474549Seric } 6484577Seric /* 64958151Seric ** PRINTVRFYADDR -- print an entry in the verify queue 65058151Seric ** 65158151Seric ** Parameters: 65258151Seric ** a -- the address to print 65358151Seric ** last -- set if this is the last one. 65458151Seric ** 65558151Seric ** Returns: 65658151Seric ** none. 65758151Seric ** 65858151Seric ** Side Effects: 65958151Seric ** Prints the appropriate 250 codes. 66058151Seric */ 66158151Seric 66258151Seric printvrfyaddr(a, last) 66358151Seric register ADDRESS *a; 66458151Seric bool last; 66558151Seric { 66658151Seric char fmtbuf[20]; 66758151Seric 66858151Seric strcpy(fmtbuf, "250"); 66958151Seric fmtbuf[3] = last ? ' ' : '-'; 67058151Seric 67158151Seric if (strchr(a->q_paddr, '<') != NULL) 67258151Seric strcpy(&fmtbuf[4], "%s"); 67358151Seric else if (a->q_fullname == NULL) 67458151Seric strcpy(&fmtbuf[4], "<%s>"); 67558151Seric else 67658151Seric { 67758151Seric strcpy(&fmtbuf[4], "%s <%s>"); 67858151Seric message(fmtbuf, a->q_fullname, a->q_paddr); 67958151Seric return; 68058151Seric } 68158151Seric message(fmtbuf, a->q_paddr); 68258151Seric } 68358151Seric /* 6844577Seric ** HELP -- implement the HELP command. 6854577Seric ** 6864577Seric ** Parameters: 6874577Seric ** topic -- the topic we want help for. 6884577Seric ** 6894577Seric ** Returns: 6904577Seric ** none. 6914577Seric ** 6924577Seric ** Side Effects: 6934577Seric ** outputs the help file to message output. 6944577Seric */ 6954577Seric 6964577Seric help(topic) 6974577Seric char *topic; 6984577Seric { 6994577Seric register FILE *hf; 7004577Seric int len; 7014577Seric char buf[MAXLINE]; 7024577Seric bool noinfo; 7034577Seric 7048269Seric if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL) 7054577Seric { 7064577Seric /* no help */ 70711931Seric errno = 0; 70858151Seric message("502 HELP not implemented"); 7094577Seric return; 7104577Seric } 7114577Seric 71249669Seric if (topic == NULL || *topic == '\0') 71349669Seric topic = "smtp"; 71449669Seric else 71549669Seric makelower(topic); 71649669Seric 7174577Seric len = strlen(topic); 7184577Seric noinfo = TRUE; 7194577Seric 7204577Seric while (fgets(buf, sizeof buf, hf) != NULL) 7214577Seric { 7224577Seric if (strncmp(buf, topic, len) == 0) 7234577Seric { 7244577Seric register char *p; 7254577Seric 72656795Seric p = strchr(buf, '\t'); 7274577Seric if (p == NULL) 7284577Seric p = buf; 7294577Seric else 7304577Seric p++; 7314577Seric fixcrlf(p, TRUE); 73258151Seric message("214-%s", p); 7334577Seric noinfo = FALSE; 7344577Seric } 7354577Seric } 7364577Seric 7374577Seric if (noinfo) 73858151Seric message("504 HELP topic unknown"); 7394577Seric else 74058151Seric message("214 End of HELP info"); 7414628Seric (void) fclose(hf); 7424577Seric } 7438544Seric /* 7449339Seric ** RUNINCHILD -- return twice -- once in the child, then in the parent again 7459339Seric ** 7469339Seric ** Parameters: 7479339Seric ** label -- a string used in error messages 7489339Seric ** 7499339Seric ** Returns: 7509339Seric ** zero in the child 7519339Seric ** one in the parent 7529339Seric ** 7539339Seric ** Side Effects: 7549339Seric ** none. 7559339Seric */ 7568544Seric 75755012Seric runinchild(label, e) 7589339Seric char *label; 75955012Seric register ENVELOPE *e; 7609339Seric { 7619339Seric int childpid; 7629339Seric 76316158Seric if (!OneXact) 7649339Seric { 76516158Seric childpid = dofork(); 76616158Seric if (childpid < 0) 76716158Seric { 76816158Seric syserr("%s: cannot fork", label); 76916158Seric return (1); 77016158Seric } 77116158Seric if (childpid > 0) 77216158Seric { 77316158Seric auto int st; 7749339Seric 77516158Seric /* parent -- wait for child to complete */ 77616158Seric st = waitfor(childpid); 77716158Seric if (st == -1) 77816158Seric syserr("%s: lost child", label); 7799339Seric 78016158Seric /* if we exited on a QUIT command, complete the process */ 78116158Seric if (st == (EX_QUIT << 8)) 78216158Seric finis(); 7839339Seric 78416158Seric return (1); 78516158Seric } 78616158Seric else 78716158Seric { 78816158Seric /* child */ 78916158Seric InChild = TRUE; 79025050Seric QuickAbort = FALSE; 79155012Seric clearenvelope(e, FALSE); 79216158Seric } 7939339Seric } 79415256Seric 79516158Seric /* open alias database */ 79655012Seric initaliases(AliasFile, FALSE, e); 79716158Seric 79816158Seric return (0); 7999339Seric } 8009339Seric 80156795Seric # endif /* SMTP */ 802