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*58093Seric static char sccsid[] = "@(#)srvrsmtp.c 6.13 (Berkeley) 02/20/93 (with SMTP)"; 1433731Sbostic #else 15*58093Seric static char sccsid[] = "@(#)srvrsmtp.c 6.13 (Berkeley) 02/20/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 */ 5658092Seric /* non-standard commands */ 5758092Seric # define CMDONEX 16 /* onex -- sending one transaction only */ 5858092Seric # define CMDVERB 17 /* verb -- go into verbose mode */ 5936230Skarels /* debugging-only commands, only enabled if SMTPDEBUG is defined */ 6058092Seric # define CMDDBGQSHOW 24 /* showq -- show send queue */ 6158092Seric # define CMDDBGDEBUG 25 /* debug -- set debug mode */ 624549Seric 634549Seric static struct cmd CmdTab[] = 644549Seric { 654549Seric "mail", CMDMAIL, 664976Seric "rcpt", CMDRCPT, 674549Seric "data", CMDDATA, 684549Seric "rset", CMDRSET, 694549Seric "vrfy", CMDVRFY, 7058092Seric "expn", CMDEXPN, 714549Seric "help", CMDHELP, 724549Seric "noop", CMDNOOP, 734549Seric "quit", CMDQUIT, 744976Seric "helo", CMDHELO, 758544Seric "verb", CMDVERB, 769314Seric "onex", CMDONEX, 7736230Skarels /* 7836230Skarels * remaining commands are here only 7936230Skarels * to trap and log attempts to use them 8036230Skarels */ 819339Seric "showq", CMDDBGQSHOW, 828544Seric "debug", CMDDBGDEBUG, 834549Seric NULL, CMDERROR, 844549Seric }; 854549Seric 869339Seric bool InChild = FALSE; /* true if running in a subprocess */ 879378Seric bool OneXact = FALSE; /* one xaction only this run */ 8811146Seric 899339Seric #define EX_QUIT 22 /* special code for QUIT command */ 908544Seric 9155012Seric smtp(e) 9255012Seric register ENVELOPE *e; 934549Seric { 944549Seric register char *p; 958544Seric register struct cmd *c; 964549Seric char *cmd; 9746928Sbostic static char *skipword(); 985003Seric auto ADDRESS *vrfyqueue; 9912612Seric ADDRESS *a; 10030448Seric char *sendinghost; 10158092Seric bool hasmail; /* mail command received */ 10258092Seric bool gothello; /* helo command received */ 10358092Seric bool vrfy; /* set if this is a vrfy command */ 1048544Seric char inp[MAXLINE]; 10557232Seric char cmdbuf[MAXLINE]; 1067124Seric extern char Version[]; 10711151Seric extern char *macvalue(); 10812612Seric extern ADDRESS *recipient(); 10924943Seric extern ENVELOPE BlankEnvelope; 11024943Seric extern ENVELOPE *newenvelope(); 1114549Seric 1125003Seric hasmail = FALSE; 1137363Seric if (OutChannel != stdout) 1147363Seric { 1157363Seric /* arrange for debugging output to go to remote host */ 1167363Seric (void) close(1); 1177363Seric (void) dup(fileno(OutChannel)); 1187363Seric } 11955012Seric settime(e); 12057642Seric if (RealHostName == NULL) 12157642Seric RealHostName = MyHostName; 12257642Seric CurHostName = RealHostName; 12357642Seric setproctitle("srvrsmtp %s", CurHostName); 12458050Seric expand("\201e", inp, &inp[sizeof inp], e); 12555360Seric message("220", "%s", inp); 12624943Seric SmtpPhase = "startup"; 12730448Seric sendinghost = NULL; 12858082Seric gothello = FALSE; 1294549Seric for (;;) 1304549Seric { 13112612Seric /* arrange for backout */ 13212612Seric if (setjmp(TopFrame) > 0 && InChild) 13312612Seric finis(); 13412612Seric QuickAbort = FALSE; 13512612Seric HoldErrs = FALSE; 13651951Seric LogUsrErrs = FALSE; 13758092Seric e->e_flags &= ~EF_VRFYONLY; 13812612Seric 1397356Seric /* setup for the read */ 14055012Seric e->e_to = NULL; 1414577Seric Errors = 0; 1427275Seric (void) fflush(stdout); 1437356Seric 1447356Seric /* read the input line */ 14557389Seric p = sfgets(inp, sizeof inp, InChannel, ReadTimeout); 1467356Seric 1477685Seric /* handle errors */ 1487356Seric if (p == NULL) 1497356Seric { 1504549Seric /* end of file, just die */ 15136230Skarels message("421", "%s Lost input channel from %s", 15225050Seric MyHostName, CurHostName); 15355464Seric #ifdef LOG 15458020Seric if (LogLevel > 1) 15555464Seric syslog(LOG_NOTICE, "lost input channel from %s", 15655464Seric CurHostName); 15755464Seric #endif 15858069Seric if (InChild) 15958069Seric ExitStat = EX_QUIT; 1604549Seric finis(); 1614549Seric } 1624549Seric 1634549Seric /* clean up end of line */ 1644558Seric fixcrlf(inp, TRUE); 1654549Seric 1664713Seric /* echo command to transcript */ 16755012Seric if (e->e_xfp != NULL) 16855012Seric fprintf(e->e_xfp, "<<< %s\n", inp); 1694713Seric 1704549Seric /* break off command */ 17158050Seric for (p = inp; isascii(*p) && isspace(*p); p++) 1724549Seric continue; 17357232Seric cmd = cmdbuf; 17458050Seric while (*p != '\0' && 17558050Seric !(isascii(*p) && isspace(*p)) && 17658050Seric cmd < &cmdbuf[sizeof cmdbuf - 2]) 17724981Seric *cmd++ = *p++; 17824981Seric *cmd = '\0'; 1794549Seric 18025691Seric /* throw away leading whitespace */ 18158050Seric while (isascii(*p) && isspace(*p)) 18225691Seric p++; 18325691Seric 1844549Seric /* decode command */ 1854549Seric for (c = CmdTab; c->cmdname != NULL; c++) 1864549Seric { 18733725Sbostic if (!strcasecmp(c->cmdname, cmdbuf)) 1884549Seric break; 1894549Seric } 1904549Seric 19151954Seric /* reset errors */ 19251954Seric errno = 0; 19351954Seric 1944549Seric /* process command */ 1954549Seric switch (c->cmdcode) 1964549Seric { 1974976Seric case CMDHELO: /* hello -- introduce yourself */ 19824943Seric SmtpPhase = "HELO"; 19925050Seric setproctitle("%s: %s", CurHostName, inp); 20033725Sbostic if (!strcasecmp(p, MyHostName)) 20114877Seric { 20236230Skarels /* 20336230Skarels * didn't know about alias, 20436230Skarels * or connected to an echo server 20536230Skarels */ 20647570Seric message("553", "%s config error: mail loops back to myself", 20747570Seric MyHostName); 20814877Seric break; 20914877Seric } 21033725Sbostic if (RealHostName != NULL && strcasecmp(p, RealHostName)) 21111146Seric { 21224981Seric char hostbuf[MAXNAME]; 21311146Seric 21424981Seric (void) sprintf(hostbuf, "%s (%s)", p, RealHostName); 21530448Seric sendinghost = newstr(hostbuf); 21611146Seric } 21711146Seric else 21830448Seric sendinghost = newstr(p); 2194997Seric message("250", "%s Hello %s, pleased to meet you", 22036230Skarels MyHostName, sendinghost); 22158082Seric gothello = TRUE; 2224976Seric break; 2234976Seric 2244549Seric case CMDMAIL: /* mail -- designate sender */ 22524943Seric SmtpPhase = "MAIL"; 22624943Seric 22711151Seric /* force a sending host even if no HELO given */ 22858064Seric if (sendinghost == NULL && macvalue('s', e) == NULL) 22930448Seric sendinghost = RealHostName; 23011151Seric 2319314Seric /* check for validity of this command */ 23258082Seric if (!gothello && bitset(PRIV_NEEDMAILHELO, PrivacyFlags)) 23358082Seric { 23458082Seric message("503", "Polite people say HELO first"); 23558082Seric break; 23658082Seric } 2374558Seric if (hasmail) 2384558Seric { 2394558Seric message("503", "Sender already specified"); 2404558Seric break; 2414558Seric } 2429339Seric if (InChild) 2439339Seric { 24436230Skarels errno = 0; 24558008Seric syserr("Nested MAIL command: MAIL %s", p); 24658069Seric finis(); 2479339Seric } 24858082Seric if (!enoughspace()) 24958082Seric { 25058082Seric message("452", "Insufficient disk space; try again later"); 25158082Seric break; 25258082Seric } 2539339Seric 2549339Seric /* fork a subprocess to process this command */ 25555012Seric if (runinchild("SMTP-MAIL", e) > 0) 2569339Seric break; 25758064Seric if (sendinghost != NULL) 25858064Seric define('s', sendinghost, e); 25955012Seric define('r', "SMTP", e); 26055012Seric initsys(e); 26157389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 2629339Seric 2639339Seric /* child -- go do the processing */ 2644549Seric p = skipword(p, "from"); 2654549Seric if (p == NULL) 2664549Seric break; 26757977Seric if (setjmp(TopFrame) > 0) 26857977Seric break; 26957977Seric QuickAbort = TRUE; 27055012Seric setsender(p, e); 2714577Seric if (Errors == 0) 2724549Seric { 2734549Seric message("250", "Sender ok"); 2744549Seric hasmail = TRUE; 2754549Seric } 2769339Seric else if (InChild) 2779339Seric finis(); 2784549Seric break; 2794549Seric 2804976Seric case CMDRCPT: /* rcpt -- designate recipient */ 28124943Seric SmtpPhase = "RCPT"; 28257389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 28312612Seric if (setjmp(TopFrame) > 0) 28414785Seric { 28555012Seric e->e_flags &= ~EF_FATALERRS; 28612612Seric break; 28714785Seric } 28812612Seric QuickAbort = TRUE; 28951951Seric LogUsrErrs = TRUE; 290*58093Seric 291*58093Seric /* optimization -- if queueing, don't expand aliases */ 292*58093Seric if (SendMode == SM_QUEUE) 293*58093Seric e->e_flags |= EF_VRFYONLY; 294*58093Seric 2954549Seric p = skipword(p, "to"); 2964549Seric if (p == NULL) 2974549Seric break; 29855012Seric a = parseaddr(p, (ADDRESS *) NULL, 1, '\0', e); 29912612Seric if (a == NULL) 30012612Seric break; 30116886Seric a->q_flags |= QPRIMARY; 30255012Seric a = recipient(a, &e->e_sendqueue, e); 30312612Seric if (Errors != 0) 30412612Seric break; 30512612Seric 30612612Seric /* no errors during parsing, but might be a duplicate */ 30755012Seric e->e_to = p; 30812612Seric if (!bitset(QBADADDR, a->q_flags)) 30912612Seric message("250", "Recipient ok"); 31012612Seric else 3114549Seric { 31212612Seric /* punt -- should keep message in ADDRESS.... */ 31312612Seric message("550", "Addressee unknown"); 3144549Seric } 31555012Seric e->e_to = NULL; 3164549Seric break; 3174549Seric 3184549Seric case CMDDATA: /* data -- text of mail */ 31924943Seric SmtpPhase = "DATA"; 3204976Seric if (!hasmail) 3214549Seric { 3224976Seric message("503", "Need MAIL command"); 3234976Seric break; 3244549Seric } 32555012Seric else if (e->e_nrcpts <= 0) 3264549Seric { 3274976Seric message("503", "Need RCPT (recipient)"); 3284976Seric break; 3294549Seric } 3304976Seric 3314976Seric /* collect the text of the message */ 33224943Seric SmtpPhase = "collect"; 33357389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 33455012Seric collect(TRUE, e); 3354976Seric if (Errors != 0) 3364976Seric break; 3374976Seric 3388238Seric /* 3398238Seric ** Arrange to send to everyone. 3408238Seric ** If sending to multiple people, mail back 3418238Seric ** errors rather than reporting directly. 3428238Seric ** In any case, don't mail back errors for 3438238Seric ** anything that has happened up to 3448238Seric ** now (the other end will do this). 34510197Seric ** Truncate our transcript -- the mail has gotten 34610197Seric ** to us successfully, and if we have 34710197Seric ** to mail this back, it will be easier 34810197Seric ** on the reader. 3498238Seric ** Then send to everyone. 3508238Seric ** Finally give a reply code. If an error has 3518238Seric ** already been given, don't mail a 3528238Seric ** message back. 3539339Seric ** We goose error returns by clearing error bit. 3548238Seric */ 3558238Seric 35624943Seric SmtpPhase = "delivery"; 35755012Seric if (e->e_nrcpts != 1) 3589378Seric { 3599378Seric HoldErrs = TRUE; 36016886Seric ErrorMode = EM_MAIL; 3619378Seric } 36255012Seric e->e_flags &= ~EF_FATALERRS; 36355012Seric e->e_xfp = freopen(queuename(e, 'x'), "w", e->e_xfp); 3644976Seric 3654976Seric /* send to all recipients */ 36655012Seric sendall(e, SM_DEFAULT); 36755012Seric e->e_to = NULL; 3684976Seric 36923516Seric /* save statistics */ 37055012Seric markstats(e, (ADDRESS *) NULL); 37123516Seric 3728238Seric /* issue success if appropriate and reset */ 3738238Seric if (Errors == 0 || HoldErrs) 3749283Seric message("250", "Ok"); 3758238Seric else 37655012Seric e->e_flags &= ~EF_FATALERRS; 3779339Seric 3789339Seric /* if in a child, pop back to our parent */ 3799339Seric if (InChild) 3809339Seric finis(); 38124943Seric 38224943Seric /* clean up a bit */ 38358008Seric hasmail = FALSE; 38455012Seric dropenvelope(e); 38555012Seric CurEnv = e = newenvelope(e); 38655012Seric e->e_flags = BlankEnvelope.e_flags; 3874549Seric break; 3884549Seric 3894549Seric case CMDRSET: /* rset -- reset state */ 3904549Seric message("250", "Reset state"); 3919339Seric if (InChild) 3929339Seric finis(); 3939339Seric break; 3944549Seric 3954549Seric case CMDVRFY: /* vrfy -- verify address */ 39658092Seric case CMDEXPN: /* expn -- expand address */ 39758092Seric vrfy = c->cmdcode == CMDVRFY; 39858092Seric if (bitset(vrfy ? PRIV_NOVRFY : PRIV_NOEXPN, 39958092Seric PrivacyFlags)) 40058082Seric { 40158082Seric message("502", "That's none of your business"); 40258082Seric break; 40358082Seric } 40458082Seric else if (!gothello && 40558092Seric bitset(vrfy ? PRIV_NEEDVRFYHELO : PRIV_NEEDEXPNHELO, 40658092Seric PrivacyFlags)) 40758082Seric { 40858082Seric message("503", "I demand that you introduce yourself first"); 40958082Seric break; 41058082Seric } 41158092Seric if (runinchild(vrfy ? "SMTP-VRFY" : "SMTP-EXPN", e) > 0) 4129339Seric break; 41325050Seric setproctitle("%s: %s", CurHostName, inp); 41455173Seric #ifdef LOG 41558020Seric if (LogLevel > 5) 41655173Seric syslog(LOG_INFO, "%s: %s", CurHostName, inp); 41755173Seric #endif 4185003Seric vrfyqueue = NULL; 4197762Seric QuickAbort = TRUE; 42058092Seric if (vrfy) 42158092Seric e->e_flags |= EF_VRFYONLY; 42258082Seric (void) sendtolist(p, (ADDRESS *) NULL, &vrfyqueue, e); 4237762Seric if (Errors != 0) 4249339Seric { 4259339Seric if (InChild) 4269339Seric finis(); 4277762Seric break; 4289339Seric } 4295003Seric while (vrfyqueue != NULL) 4305003Seric { 4315003Seric register ADDRESS *a = vrfyqueue->q_next; 4325003Seric char *code; 4335003Seric 4347685Seric while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags)) 4355003Seric a = a->q_next; 4365003Seric 4377685Seric if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags)) 4385003Seric { 4395003Seric if (a != NULL) 4405003Seric code = "250-"; 4415003Seric else 4425003Seric code = "250"; 44358010Seric if (strchr(vrfyqueue->q_paddr, '<') != NULL) 44458010Seric message(code, "%s", vrfyqueue->q_paddr); 44558010Seric else if (vrfyqueue->q_fullname == NULL) 4465003Seric message(code, "<%s>", vrfyqueue->q_paddr); 4475003Seric else 4485003Seric message(code, "%s <%s>", 4495003Seric vrfyqueue->q_fullname, vrfyqueue->q_paddr); 4505003Seric } 4515003Seric else if (a == NULL) 4525003Seric message("554", "Self destructive alias loop"); 4535003Seric vrfyqueue = a; 4545003Seric } 4559339Seric if (InChild) 4569339Seric finis(); 4574549Seric break; 4584549Seric 4594549Seric case CMDHELP: /* help -- give user info */ 4604577Seric help(p); 4614549Seric break; 4624549Seric 4634549Seric case CMDNOOP: /* noop -- do nothing */ 4644549Seric message("200", "OK"); 4654549Seric break; 4664549Seric 4674549Seric case CMDQUIT: /* quit -- leave mail */ 46825050Seric message("221", "%s closing connection", MyHostName); 4699339Seric if (InChild) 4709339Seric ExitStat = EX_QUIT; 4714549Seric finis(); 4724549Seric 4738544Seric case CMDVERB: /* set verbose mode */ 4748544Seric Verbose = TRUE; 47525025Seric SendMode = SM_DELIVER; 4768544Seric message("200", "Verbose mode"); 4778544Seric break; 4788544Seric 4799314Seric case CMDONEX: /* doing one transaction only */ 4809378Seric OneXact = TRUE; 4819314Seric message("200", "Only one transaction"); 4829314Seric break; 4839314Seric 48436230Skarels # ifdef SMTPDEBUG 4859339Seric case CMDDBGQSHOW: /* show queues */ 4866907Seric printf("Send Queue="); 48755012Seric printaddr(e->e_sendqueue, TRUE); 4885003Seric break; 4897275Seric 4907275Seric case CMDDBGDEBUG: /* set debug mode */ 4917676Seric tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); 4927676Seric tTflag(p); 4937676Seric message("200", "Debug set"); 4947275Seric break; 4957275Seric 49636230Skarels # else /* not SMTPDEBUG */ 49724945Seric 49836230Skarels case CMDDBGQSHOW: /* show queues */ 49936230Skarels case CMDDBGDEBUG: /* set debug mode */ 50036233Skarels # ifdef LOG 50136233Skarels if (RealHostName != NULL && LogLevel > 0) 50236230Skarels syslog(LOG_NOTICE, 50358020Seric "\"%s\" command from %s (%s)", 50436230Skarels c->cmdname, RealHostName, 50536230Skarels inet_ntoa(RealHostAddr.sin_addr)); 50636233Skarels # endif 50736230Skarels /* FALL THROUGH */ 50836230Skarels # endif /* SMTPDEBUG */ 50936230Skarels 5104549Seric case CMDERROR: /* unknown command */ 5114549Seric message("500", "Command unrecognized"); 5124549Seric break; 5134549Seric 5144549Seric default: 51536230Skarels errno = 0; 5164549Seric syserr("smtp: unknown code %d", c->cmdcode); 5174549Seric break; 5184549Seric } 5194549Seric } 5204549Seric } 5214549Seric /* 5224549Seric ** SKIPWORD -- skip a fixed word. 5234549Seric ** 5244549Seric ** Parameters: 5254549Seric ** p -- place to start looking. 5264549Seric ** w -- word to skip. 5274549Seric ** 5284549Seric ** Returns: 5294549Seric ** p following w. 5304549Seric ** NULL on error. 5314549Seric ** 5324549Seric ** Side Effects: 5334549Seric ** clobbers the p data area. 5344549Seric */ 5354549Seric 5364549Seric static char * 5374549Seric skipword(p, w) 5384549Seric register char *p; 5394549Seric char *w; 5404549Seric { 5414549Seric register char *q; 5424549Seric 5434549Seric /* find beginning of word */ 54458050Seric while (isascii(*p) && isspace(*p)) 5454549Seric p++; 5464549Seric q = p; 5474549Seric 5484549Seric /* find end of word */ 54958050Seric while (*p != '\0' && *p != ':' && !(isascii(*p) && isspace(*p))) 5504549Seric p++; 55158050Seric while (isascii(*p) && isspace(*p)) 5524549Seric *p++ = '\0'; 5534549Seric if (*p != ':') 5544549Seric { 5554549Seric syntax: 5564549Seric message("501", "Syntax error"); 5574549Seric Errors++; 5584549Seric return (NULL); 5594549Seric } 5604549Seric *p++ = '\0'; 56158050Seric while (isascii(*p) && isspace(*p)) 5624549Seric p++; 5634549Seric 5644549Seric /* see if the input word matches desired word */ 56533725Sbostic if (strcasecmp(q, w)) 5664549Seric goto syntax; 5674549Seric 5684549Seric return (p); 5694549Seric } 5704577Seric /* 5714577Seric ** HELP -- implement the HELP command. 5724577Seric ** 5734577Seric ** Parameters: 5744577Seric ** topic -- the topic we want help for. 5754577Seric ** 5764577Seric ** Returns: 5774577Seric ** none. 5784577Seric ** 5794577Seric ** Side Effects: 5804577Seric ** outputs the help file to message output. 5814577Seric */ 5824577Seric 5834577Seric help(topic) 5844577Seric char *topic; 5854577Seric { 5864577Seric register FILE *hf; 5874577Seric int len; 5884577Seric char buf[MAXLINE]; 5894577Seric bool noinfo; 5904577Seric 5918269Seric if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL) 5924577Seric { 5934577Seric /* no help */ 59411931Seric errno = 0; 5954577Seric message("502", "HELP not implemented"); 5964577Seric return; 5974577Seric } 5984577Seric 59949669Seric if (topic == NULL || *topic == '\0') 60049669Seric topic = "smtp"; 60149669Seric else 60249669Seric makelower(topic); 60349669Seric 6044577Seric len = strlen(topic); 6054577Seric noinfo = TRUE; 6064577Seric 6074577Seric while (fgets(buf, sizeof buf, hf) != NULL) 6084577Seric { 6094577Seric if (strncmp(buf, topic, len) == 0) 6104577Seric { 6114577Seric register char *p; 6124577Seric 61356795Seric p = strchr(buf, '\t'); 6144577Seric if (p == NULL) 6154577Seric p = buf; 6164577Seric else 6174577Seric p++; 6184577Seric fixcrlf(p, TRUE); 6194577Seric message("214-", p); 6204577Seric noinfo = FALSE; 6214577Seric } 6224577Seric } 6234577Seric 6244577Seric if (noinfo) 6254577Seric message("504", "HELP topic unknown"); 6264577Seric else 6274577Seric message("214", "End of HELP info"); 6284628Seric (void) fclose(hf); 6294577Seric } 6308544Seric /* 6319339Seric ** RUNINCHILD -- return twice -- once in the child, then in the parent again 6329339Seric ** 6339339Seric ** Parameters: 6349339Seric ** label -- a string used in error messages 6359339Seric ** 6369339Seric ** Returns: 6379339Seric ** zero in the child 6389339Seric ** one in the parent 6399339Seric ** 6409339Seric ** Side Effects: 6419339Seric ** none. 6429339Seric */ 6438544Seric 64455012Seric runinchild(label, e) 6459339Seric char *label; 64655012Seric register ENVELOPE *e; 6479339Seric { 6489339Seric int childpid; 6499339Seric 65016158Seric if (!OneXact) 6519339Seric { 65216158Seric childpid = dofork(); 65316158Seric if (childpid < 0) 65416158Seric { 65516158Seric syserr("%s: cannot fork", label); 65616158Seric return (1); 65716158Seric } 65816158Seric if (childpid > 0) 65916158Seric { 66016158Seric auto int st; 6619339Seric 66216158Seric /* parent -- wait for child to complete */ 66316158Seric st = waitfor(childpid); 66416158Seric if (st == -1) 66516158Seric syserr("%s: lost child", label); 6669339Seric 66716158Seric /* if we exited on a QUIT command, complete the process */ 66816158Seric if (st == (EX_QUIT << 8)) 66916158Seric finis(); 6709339Seric 67116158Seric return (1); 67216158Seric } 67316158Seric else 67416158Seric { 67516158Seric /* child */ 67616158Seric InChild = TRUE; 67725050Seric QuickAbort = FALSE; 67855012Seric clearenvelope(e, FALSE); 67916158Seric } 6809339Seric } 68115256Seric 68216158Seric /* open alias database */ 68355012Seric initaliases(AliasFile, FALSE, e); 68416158Seric 68516158Seric return (0); 6869339Seric } 6879339Seric 68856795Seric # endif /* SMTP */ 689