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*58151Seric static char sccsid[] = "@(#)srvrsmtp.c 6.16 (Berkeley) 02/23/93 (with SMTP)"; 1433731Sbostic #else 15*58151Seric static char sccsid[] = "@(#)srvrsmtp.c 6.16 (Berkeley) 02/23/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; 10158109Seric bool gotmail; /* 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 11258109Seric gotmail = 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); 125*58151Seric 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 */ 14558109Seric p = sfgets(inp, sizeof inp, InChannel, TimeOuts.to_nextcommand); 1467356Seric 1477685Seric /* handle errors */ 1487356Seric if (p == NULL) 1497356Seric { 1504549Seric /* end of file, just die */ 151*58151Seric 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); 20058109Seric if (strcasecmp(p, MyHostName) == 0) 20114877Seric { 20236230Skarels /* 20358109Seric ** Didn't know about alias or MX, 20458109Seric ** or connected to an echo server 20558109Seric */ 20658109Seric 207*58151Seric message("553 %s config error: mail loops back to myself", 20847570Seric MyHostName); 20914877Seric break; 21014877Seric } 21158109Seric if (RealHostName != NULL && strcasecmp(p, RealHostName) != 0) 21211146Seric { 21324981Seric char hostbuf[MAXNAME]; 21411146Seric 21524981Seric (void) sprintf(hostbuf, "%s (%s)", p, RealHostName); 21630448Seric sendinghost = newstr(hostbuf); 21711146Seric } 21811146Seric else 21930448Seric sendinghost = newstr(p); 220*58151Seric message("250 %s Hello %s, pleased to meet you", 22136230Skarels MyHostName, sendinghost); 22258082Seric gothello = TRUE; 2234976Seric break; 2244976Seric 2254549Seric case CMDMAIL: /* mail -- designate sender */ 22624943Seric SmtpPhase = "MAIL"; 22724943Seric 22811151Seric /* force a sending host even if no HELO given */ 22958064Seric if (sendinghost == NULL && macvalue('s', e) == NULL) 23030448Seric sendinghost = RealHostName; 23111151Seric 2329314Seric /* check for validity of this command */ 23358082Seric if (!gothello && bitset(PRIV_NEEDMAILHELO, PrivacyFlags)) 23458082Seric { 235*58151Seric message("503 Polite people say HELO first"); 23658082Seric break; 23758082Seric } 23858109Seric if (gotmail) 2394558Seric { 240*58151Seric message("503 Sender already specified"); 2414558Seric break; 2424558Seric } 2439339Seric if (InChild) 2449339Seric { 24536230Skarels errno = 0; 246*58151Seric syserr("503 Nested MAIL command: MAIL %s", p); 24758069Seric finis(); 2489339Seric } 24958082Seric if (!enoughspace()) 25058082Seric { 251*58151Seric message("452 Insufficient disk space; try again later"); 25258082Seric break; 25358082Seric } 2549339Seric 2559339Seric /* fork a subprocess to process this command */ 25655012Seric if (runinchild("SMTP-MAIL", e) > 0) 2579339Seric break; 25858064Seric if (sendinghost != NULL) 25958064Seric define('s', sendinghost, e); 26055012Seric define('r', "SMTP", e); 26155012Seric initsys(e); 26257389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 2639339Seric 2649339Seric /* child -- go do the processing */ 2654549Seric p = skipword(p, "from"); 2664549Seric if (p == NULL) 2674549Seric break; 26857977Seric if (setjmp(TopFrame) > 0) 26958147Seric { 27058147Seric /* this failed -- undo work */ 27158147Seric if (InChild) 27258147Seric finis(); 27357977Seric break; 27458147Seric } 27557977Seric QuickAbort = TRUE; 27655012Seric setsender(p, e); 277*58151Seric message("250 Sender ok"); 27858147Seric gotmail = TRUE; 2794549Seric break; 2804549Seric 2814976Seric case CMDRCPT: /* rcpt -- designate recipient */ 28224943Seric SmtpPhase = "RCPT"; 28357389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 28412612Seric if (setjmp(TopFrame) > 0) 28514785Seric { 28655012Seric e->e_flags &= ~EF_FATALERRS; 28712612Seric break; 28814785Seric } 28912612Seric QuickAbort = TRUE; 29051951Seric LogUsrErrs = TRUE; 29158093Seric 29258093Seric /* optimization -- if queueing, don't expand aliases */ 29358093Seric if (SendMode == SM_QUEUE) 29458093Seric e->e_flags |= EF_VRFYONLY; 29558093Seric 2964549Seric p = skipword(p, "to"); 2974549Seric if (p == NULL) 2984549Seric break; 29955012Seric a = parseaddr(p, (ADDRESS *) NULL, 1, '\0', e); 30012612Seric if (a == NULL) 30112612Seric break; 30216886Seric a->q_flags |= QPRIMARY; 30355012Seric a = recipient(a, &e->e_sendqueue, e); 30412612Seric if (Errors != 0) 30512612Seric break; 30612612Seric 30712612Seric /* no errors during parsing, but might be a duplicate */ 30855012Seric e->e_to = p; 30912612Seric if (!bitset(QBADADDR, a->q_flags)) 310*58151Seric message("250 Recipient ok"); 31112612Seric else 3124549Seric { 31312612Seric /* punt -- should keep message in ADDRESS.... */ 314*58151Seric message("550 Addressee unknown"); 3154549Seric } 31655012Seric e->e_to = NULL; 3174549Seric break; 3184549Seric 3194549Seric case CMDDATA: /* data -- text of mail */ 32024943Seric SmtpPhase = "DATA"; 32158109Seric if (!gotmail) 3224549Seric { 323*58151Seric message("503 Need MAIL command"); 3244976Seric break; 3254549Seric } 32655012Seric else if (e->e_nrcpts <= 0) 3274549Seric { 328*58151Seric message("503 Need RCPT (recipient)"); 3294976Seric break; 3304549Seric } 3314976Seric 3324976Seric /* collect the text of the message */ 33324943Seric SmtpPhase = "collect"; 33457389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 33555012Seric collect(TRUE, e); 3364976Seric if (Errors != 0) 3374976Seric break; 3384976Seric 3398238Seric /* 3408238Seric ** Arrange to send to everyone. 3418238Seric ** If sending to multiple people, mail back 3428238Seric ** errors rather than reporting directly. 3438238Seric ** In any case, don't mail back errors for 3448238Seric ** anything that has happened up to 3458238Seric ** now (the other end will do this). 34610197Seric ** Truncate our transcript -- the mail has gotten 34710197Seric ** to us successfully, and if we have 34810197Seric ** to mail this back, it will be easier 34910197Seric ** on the reader. 3508238Seric ** Then send to everyone. 3518238Seric ** Finally give a reply code. If an error has 3528238Seric ** already been given, don't mail a 3538238Seric ** message back. 3549339Seric ** We goose error returns by clearing error bit. 3558238Seric */ 3568238Seric 35724943Seric SmtpPhase = "delivery"; 35855012Seric if (e->e_nrcpts != 1) 3599378Seric { 3609378Seric HoldErrs = TRUE; 36116886Seric ErrorMode = EM_MAIL; 3629378Seric } 36355012Seric e->e_flags &= ~EF_FATALERRS; 36455012Seric e->e_xfp = freopen(queuename(e, 'x'), "w", e->e_xfp); 3654976Seric 3664976Seric /* send to all recipients */ 36755012Seric sendall(e, SM_DEFAULT); 36855012Seric e->e_to = NULL; 3694976Seric 37023516Seric /* save statistics */ 37155012Seric markstats(e, (ADDRESS *) NULL); 37223516Seric 3738238Seric /* issue success if appropriate and reset */ 3748238Seric if (Errors == 0 || HoldErrs) 375*58151Seric message("250 Ok"); 3768238Seric else 37755012Seric e->e_flags &= ~EF_FATALERRS; 3789339Seric 3799339Seric /* if in a child, pop back to our parent */ 3809339Seric if (InChild) 3819339Seric finis(); 38224943Seric 38324943Seric /* clean up a bit */ 38458109Seric gotmail = FALSE; 38555012Seric dropenvelope(e); 38655012Seric CurEnv = e = newenvelope(e); 38755012Seric e->e_flags = BlankEnvelope.e_flags; 3884549Seric break; 3894549Seric 3904549Seric case CMDRSET: /* rset -- reset state */ 391*58151Seric message("250 Reset state"); 3929339Seric if (InChild) 3939339Seric finis(); 39458109Seric 39558109Seric /* clean up a bit */ 39658109Seric gotmail = FALSE; 39758109Seric dropenvelope(e); 39858109Seric CurEnv = e = newenvelope(e); 3999339Seric break; 4004549Seric 4014549Seric case CMDVRFY: /* vrfy -- verify address */ 40258092Seric case CMDEXPN: /* expn -- expand address */ 40358092Seric vrfy = c->cmdcode == CMDVRFY; 40458092Seric if (bitset(vrfy ? PRIV_NOVRFY : PRIV_NOEXPN, 40558092Seric PrivacyFlags)) 40658082Seric { 407*58151Seric message("502 That's none of your business"); 40858082Seric break; 40958082Seric } 41058082Seric else if (!gothello && 41158092Seric bitset(vrfy ? PRIV_NEEDVRFYHELO : PRIV_NEEDEXPNHELO, 41258092Seric PrivacyFlags)) 41358082Seric { 414*58151Seric message("503 I demand that you introduce yourself first"); 41558082Seric break; 41658082Seric } 41758092Seric if (runinchild(vrfy ? "SMTP-VRFY" : "SMTP-EXPN", e) > 0) 4189339Seric break; 41925050Seric setproctitle("%s: %s", CurHostName, inp); 42055173Seric #ifdef LOG 42158020Seric if (LogLevel > 5) 42255173Seric syslog(LOG_INFO, "%s: %s", CurHostName, inp); 42355173Seric #endif 4245003Seric vrfyqueue = NULL; 4257762Seric QuickAbort = TRUE; 42658092Seric if (vrfy) 42758092Seric e->e_flags |= EF_VRFYONLY; 42858082Seric (void) sendtolist(p, (ADDRESS *) NULL, &vrfyqueue, e); 4297762Seric if (Errors != 0) 4309339Seric { 4319339Seric if (InChild) 4329339Seric finis(); 4337762Seric break; 4349339Seric } 4355003Seric while (vrfyqueue != NULL) 4365003Seric { 4375003Seric register ADDRESS *a = vrfyqueue->q_next; 4385003Seric char *code; 4395003Seric 4407685Seric while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags)) 4415003Seric a = a->q_next; 4425003Seric 4437685Seric if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags)) 444*58151Seric printvrfyaddr(vrfyqueue, a == NULL); 4455003Seric else if (a == NULL) 446*58151Seric message("554 Self destructive alias loop"); 4475003Seric vrfyqueue = a; 4485003Seric } 4499339Seric if (InChild) 4509339Seric finis(); 4514549Seric break; 4524549Seric 4534549Seric case CMDHELP: /* help -- give user info */ 4544577Seric help(p); 4554549Seric break; 4564549Seric 4574549Seric case CMDNOOP: /* noop -- do nothing */ 458*58151Seric message("200 OK"); 4594549Seric break; 4604549Seric 4614549Seric case CMDQUIT: /* quit -- leave mail */ 462*58151Seric message("221 %s closing connection", MyHostName); 4639339Seric if (InChild) 4649339Seric ExitStat = EX_QUIT; 4654549Seric finis(); 4664549Seric 4678544Seric case CMDVERB: /* set verbose mode */ 4688544Seric Verbose = TRUE; 46925025Seric SendMode = SM_DELIVER; 470*58151Seric message("200 Verbose mode"); 4718544Seric break; 4728544Seric 4739314Seric case CMDONEX: /* doing one transaction only */ 4749378Seric OneXact = TRUE; 475*58151Seric message("200 Only one transaction"); 4769314Seric break; 4779314Seric 47836230Skarels # ifdef SMTPDEBUG 4799339Seric case CMDDBGQSHOW: /* show queues */ 4806907Seric printf("Send Queue="); 48155012Seric printaddr(e->e_sendqueue, TRUE); 4825003Seric break; 4837275Seric 4847275Seric case CMDDBGDEBUG: /* set debug mode */ 4857676Seric tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); 4867676Seric tTflag(p); 487*58151Seric message("200 Debug set"); 4887275Seric break; 4897275Seric 49036230Skarels # else /* not SMTPDEBUG */ 49124945Seric 49236230Skarels case CMDDBGQSHOW: /* show queues */ 49336230Skarels case CMDDBGDEBUG: /* set debug mode */ 49436233Skarels # ifdef LOG 49536233Skarels if (RealHostName != NULL && LogLevel > 0) 49636230Skarels syslog(LOG_NOTICE, 49758020Seric "\"%s\" command from %s (%s)", 49836230Skarels c->cmdname, RealHostName, 49936230Skarels inet_ntoa(RealHostAddr.sin_addr)); 50036233Skarels # endif 50136230Skarels /* FALL THROUGH */ 50236230Skarels # endif /* SMTPDEBUG */ 50336230Skarels 5044549Seric case CMDERROR: /* unknown command */ 505*58151Seric message("500 Command unrecognized"); 5064549Seric break; 5074549Seric 5084549Seric default: 50936230Skarels errno = 0; 510*58151Seric syserr("500 smtp: unknown code %d", c->cmdcode); 5114549Seric break; 5124549Seric } 5134549Seric } 5144549Seric } 5154549Seric /* 5164549Seric ** SKIPWORD -- skip a fixed word. 5174549Seric ** 5184549Seric ** Parameters: 5194549Seric ** p -- place to start looking. 5204549Seric ** w -- word to skip. 5214549Seric ** 5224549Seric ** Returns: 5234549Seric ** p following w. 5244549Seric ** NULL on error. 5254549Seric ** 5264549Seric ** Side Effects: 5274549Seric ** clobbers the p data area. 5284549Seric */ 5294549Seric 5304549Seric static char * 5314549Seric skipword(p, w) 5324549Seric register char *p; 5334549Seric char *w; 5344549Seric { 5354549Seric register char *q; 5364549Seric 5374549Seric /* find beginning of word */ 53858050Seric while (isascii(*p) && isspace(*p)) 5394549Seric p++; 5404549Seric q = p; 5414549Seric 5424549Seric /* find end of word */ 54358050Seric while (*p != '\0' && *p != ':' && !(isascii(*p) && isspace(*p))) 5444549Seric p++; 54558050Seric while (isascii(*p) && isspace(*p)) 5464549Seric *p++ = '\0'; 5474549Seric if (*p != ':') 5484549Seric { 5494549Seric syntax: 550*58151Seric message("501 Syntax error"); 5514549Seric Errors++; 5524549Seric return (NULL); 5534549Seric } 5544549Seric *p++ = '\0'; 55558050Seric while (isascii(*p) && isspace(*p)) 5564549Seric p++; 5574549Seric 5584549Seric /* see if the input word matches desired word */ 55933725Sbostic if (strcasecmp(q, w)) 5604549Seric goto syntax; 5614549Seric 5624549Seric return (p); 5634549Seric } 5644577Seric /* 565*58151Seric ** PRINTVRFYADDR -- print an entry in the verify queue 566*58151Seric ** 567*58151Seric ** Parameters: 568*58151Seric ** a -- the address to print 569*58151Seric ** last -- set if this is the last one. 570*58151Seric ** 571*58151Seric ** Returns: 572*58151Seric ** none. 573*58151Seric ** 574*58151Seric ** Side Effects: 575*58151Seric ** Prints the appropriate 250 codes. 576*58151Seric */ 577*58151Seric 578*58151Seric printvrfyaddr(a, last) 579*58151Seric register ADDRESS *a; 580*58151Seric bool last; 581*58151Seric { 582*58151Seric char fmtbuf[20]; 583*58151Seric 584*58151Seric strcpy(fmtbuf, "250"); 585*58151Seric fmtbuf[3] = last ? ' ' : '-'; 586*58151Seric 587*58151Seric if (strchr(a->q_paddr, '<') != NULL) 588*58151Seric strcpy(&fmtbuf[4], "%s"); 589*58151Seric else if (a->q_fullname == NULL) 590*58151Seric strcpy(&fmtbuf[4], "<%s>"); 591*58151Seric else 592*58151Seric { 593*58151Seric strcpy(&fmtbuf[4], "%s <%s>"); 594*58151Seric message(fmtbuf, a->q_fullname, a->q_paddr); 595*58151Seric return; 596*58151Seric } 597*58151Seric message(fmtbuf, a->q_paddr); 598*58151Seric } 599*58151Seric /* 6004577Seric ** HELP -- implement the HELP command. 6014577Seric ** 6024577Seric ** Parameters: 6034577Seric ** topic -- the topic we want help for. 6044577Seric ** 6054577Seric ** Returns: 6064577Seric ** none. 6074577Seric ** 6084577Seric ** Side Effects: 6094577Seric ** outputs the help file to message output. 6104577Seric */ 6114577Seric 6124577Seric help(topic) 6134577Seric char *topic; 6144577Seric { 6154577Seric register FILE *hf; 6164577Seric int len; 6174577Seric char buf[MAXLINE]; 6184577Seric bool noinfo; 6194577Seric 6208269Seric if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL) 6214577Seric { 6224577Seric /* no help */ 62311931Seric errno = 0; 624*58151Seric message("502 HELP not implemented"); 6254577Seric return; 6264577Seric } 6274577Seric 62849669Seric if (topic == NULL || *topic == '\0') 62949669Seric topic = "smtp"; 63049669Seric else 63149669Seric makelower(topic); 63249669Seric 6334577Seric len = strlen(topic); 6344577Seric noinfo = TRUE; 6354577Seric 6364577Seric while (fgets(buf, sizeof buf, hf) != NULL) 6374577Seric { 6384577Seric if (strncmp(buf, topic, len) == 0) 6394577Seric { 6404577Seric register char *p; 6414577Seric 64256795Seric p = strchr(buf, '\t'); 6434577Seric if (p == NULL) 6444577Seric p = buf; 6454577Seric else 6464577Seric p++; 6474577Seric fixcrlf(p, TRUE); 648*58151Seric message("214-%s", p); 6494577Seric noinfo = FALSE; 6504577Seric } 6514577Seric } 6524577Seric 6534577Seric if (noinfo) 654*58151Seric message("504 HELP topic unknown"); 6554577Seric else 656*58151Seric message("214 End of HELP info"); 6574628Seric (void) fclose(hf); 6584577Seric } 6598544Seric /* 6609339Seric ** RUNINCHILD -- return twice -- once in the child, then in the parent again 6619339Seric ** 6629339Seric ** Parameters: 6639339Seric ** label -- a string used in error messages 6649339Seric ** 6659339Seric ** Returns: 6669339Seric ** zero in the child 6679339Seric ** one in the parent 6689339Seric ** 6699339Seric ** Side Effects: 6709339Seric ** none. 6719339Seric */ 6728544Seric 67355012Seric runinchild(label, e) 6749339Seric char *label; 67555012Seric register ENVELOPE *e; 6769339Seric { 6779339Seric int childpid; 6789339Seric 67916158Seric if (!OneXact) 6809339Seric { 68116158Seric childpid = dofork(); 68216158Seric if (childpid < 0) 68316158Seric { 68416158Seric syserr("%s: cannot fork", label); 68516158Seric return (1); 68616158Seric } 68716158Seric if (childpid > 0) 68816158Seric { 68916158Seric auto int st; 6909339Seric 69116158Seric /* parent -- wait for child to complete */ 69216158Seric st = waitfor(childpid); 69316158Seric if (st == -1) 69416158Seric syserr("%s: lost child", label); 6959339Seric 69616158Seric /* if we exited on a QUIT command, complete the process */ 69716158Seric if (st == (EX_QUIT << 8)) 69816158Seric finis(); 6999339Seric 70016158Seric return (1); 70116158Seric } 70216158Seric else 70316158Seric { 70416158Seric /* child */ 70516158Seric InChild = TRUE; 70625050Seric QuickAbort = FALSE; 70755012Seric clearenvelope(e, FALSE); 70816158Seric } 7099339Seric } 71015256Seric 71116158Seric /* open alias database */ 71255012Seric initaliases(AliasFile, FALSE, e); 71316158Seric 71416158Seric return (0); 7159339Seric } 7169339Seric 71756795Seric # endif /* SMTP */ 718