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*58323Seric static char sccsid[] = "@(#)srvrsmtp.c 6.19 (Berkeley) 02/28/93 (with SMTP)"; 1433731Sbostic #else 15*58323Seric static char sccsid[] = "@(#)srvrsmtp.c 6.19 (Berkeley) 02/28/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 */ 56*58323Seric # 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, 76*58323Seric "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 */ 106*58323Seric char *protocol; /* sending protocol */ 1078544Seric char inp[MAXLINE]; 10857232Seric char cmdbuf[MAXLINE]; 1097124Seric extern char Version[]; 11011151Seric extern char *macvalue(); 11112612Seric extern ADDRESS *recipient(); 11224943Seric extern ENVELOPE BlankEnvelope; 11324943Seric extern ENVELOPE *newenvelope(); 1144549Seric 11558109Seric gotmail = FALSE; 1167363Seric if (OutChannel != stdout) 1177363Seric { 1187363Seric /* arrange for debugging output to go to remote host */ 1197363Seric (void) close(1); 1207363Seric (void) dup(fileno(OutChannel)); 1217363Seric } 12255012Seric settime(e); 12357642Seric CurHostName = RealHostName; 12457642Seric setproctitle("srvrsmtp %s", CurHostName); 12558050Seric expand("\201e", inp, &inp[sizeof inp], e); 12658151Seric message("220 %s", inp); 12724943Seric SmtpPhase = "startup"; 12830448Seric sendinghost = NULL; 12958082Seric gothello = FALSE; 1304549Seric for (;;) 1314549Seric { 13212612Seric /* arrange for backout */ 13312612Seric if (setjmp(TopFrame) > 0 && InChild) 13412612Seric finis(); 13512612Seric QuickAbort = FALSE; 13612612Seric HoldErrs = FALSE; 13751951Seric LogUsrErrs = FALSE; 13858092Seric e->e_flags &= ~EF_VRFYONLY; 13912612Seric 1407356Seric /* setup for the read */ 14155012Seric e->e_to = NULL; 1424577Seric Errors = 0; 1437275Seric (void) fflush(stdout); 1447356Seric 1457356Seric /* read the input line */ 14658109Seric p = sfgets(inp, sizeof inp, InChannel, TimeOuts.to_nextcommand); 1477356Seric 1487685Seric /* handle errors */ 1497356Seric if (p == NULL) 1507356Seric { 1514549Seric /* end of file, just die */ 15258151Seric message("421 %s Lost input channel from %s", 15325050Seric MyHostName, CurHostName); 15455464Seric #ifdef LOG 15558020Seric if (LogLevel > 1) 15655464Seric syslog(LOG_NOTICE, "lost input channel from %s", 15755464Seric CurHostName); 15855464Seric #endif 15958069Seric if (InChild) 16058069Seric ExitStat = EX_QUIT; 1614549Seric finis(); 1624549Seric } 1634549Seric 1644549Seric /* clean up end of line */ 1654558Seric fixcrlf(inp, TRUE); 1664549Seric 1674713Seric /* echo command to transcript */ 16855012Seric if (e->e_xfp != NULL) 16955012Seric fprintf(e->e_xfp, "<<< %s\n", inp); 1704713Seric 1714549Seric /* break off command */ 17258050Seric for (p = inp; isascii(*p) && isspace(*p); p++) 1734549Seric continue; 17457232Seric cmd = cmdbuf; 17558050Seric while (*p != '\0' && 17658050Seric !(isascii(*p) && isspace(*p)) && 17758050Seric cmd < &cmdbuf[sizeof cmdbuf - 2]) 17824981Seric *cmd++ = *p++; 17924981Seric *cmd = '\0'; 1804549Seric 18125691Seric /* throw away leading whitespace */ 18258050Seric while (isascii(*p) && isspace(*p)) 18325691Seric p++; 18425691Seric 1854549Seric /* decode command */ 1864549Seric for (c = CmdTab; c->cmdname != NULL; c++) 1874549Seric { 18833725Sbostic if (!strcasecmp(c->cmdname, cmdbuf)) 1894549Seric break; 1904549Seric } 1914549Seric 19251954Seric /* reset errors */ 19351954Seric errno = 0; 19451954Seric 1954549Seric /* process command */ 1964549Seric switch (c->cmdcode) 1974549Seric { 1984976Seric case CMDHELO: /* hello -- introduce yourself */ 199*58323Seric case CMDEHLO: /* extended hello */ 200*58323Seric if (c->cmdcode == CMDEHLO) 201*58323Seric { 202*58323Seric protocol = "ESMTP"; 203*58323Seric SmtpPhase = "EHLO"; 204*58323Seric } 205*58323Seric else 206*58323Seric { 207*58323Seric protocol = "SMTP"; 208*58323Seric SmtpPhase = "HELO"; 209*58323Seric } 21025050Seric setproctitle("%s: %s", CurHostName, inp); 21158109Seric if (strcasecmp(p, MyHostName) == 0) 21214877Seric { 21336230Skarels /* 21458109Seric ** Didn't know about alias or MX, 21558109Seric ** or connected to an echo server 21658109Seric */ 21758109Seric 21858151Seric message("553 %s config error: mail loops back to myself", 21947570Seric MyHostName); 22014877Seric break; 22114877Seric } 22258308Seric if (strcasecmp(p, RealHostName) != 0) 22311146Seric { 22424981Seric char hostbuf[MAXNAME]; 22511146Seric 22624981Seric (void) sprintf(hostbuf, "%s (%s)", p, RealHostName); 22730448Seric sendinghost = newstr(hostbuf); 22811146Seric } 22911146Seric else 23030448Seric sendinghost = newstr(p); 231*58323Seric 232*58323Seric /* send ext. message -- old systems must ignore */ 233*58323Seric message("250-%s Hello %s, pleased to meet you", 23436230Skarels MyHostName, sendinghost); 235*58323Seric if (!bitset(PRIV_NOEXPN, PrivacyFlags)) 236*58323Seric message("250-EXPN"); 237*58323Seric message("250 HELP"); 23858082Seric gothello = TRUE; 2394976Seric break; 2404976Seric 2414549Seric case CMDMAIL: /* mail -- designate sender */ 24224943Seric SmtpPhase = "MAIL"; 24324943Seric 24411151Seric /* force a sending host even if no HELO given */ 24558064Seric if (sendinghost == NULL && macvalue('s', e) == NULL) 24630448Seric sendinghost = RealHostName; 24711151Seric 2489314Seric /* check for validity of this command */ 24958082Seric if (!gothello && bitset(PRIV_NEEDMAILHELO, PrivacyFlags)) 25058082Seric { 25158151Seric message("503 Polite people say HELO first"); 25258082Seric break; 25358082Seric } 25458109Seric if (gotmail) 2554558Seric { 25658151Seric message("503 Sender already specified"); 2574558Seric break; 2584558Seric } 2599339Seric if (InChild) 2609339Seric { 26136230Skarels errno = 0; 26258151Seric syserr("503 Nested MAIL command: MAIL %s", p); 26358069Seric finis(); 2649339Seric } 26558082Seric if (!enoughspace()) 26658082Seric { 26758151Seric message("452 Insufficient disk space; try again later"); 26858082Seric break; 26958082Seric } 2709339Seric 2719339Seric /* fork a subprocess to process this command */ 27255012Seric if (runinchild("SMTP-MAIL", e) > 0) 2739339Seric break; 27458064Seric if (sendinghost != NULL) 27558064Seric define('s', sendinghost, e); 276*58323Seric if (protocol == NULL) 277*58323Seric protocol = "SMTP"; 278*58323Seric define('r', protocol, e); 27955012Seric initsys(e); 28057389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 2819339Seric 2829339Seric /* child -- go do the processing */ 2834549Seric p = skipword(p, "from"); 2844549Seric if (p == NULL) 2854549Seric break; 28657977Seric if (setjmp(TopFrame) > 0) 28758147Seric { 28858147Seric /* this failed -- undo work */ 28958147Seric if (InChild) 29058147Seric finis(); 29157977Seric break; 29258147Seric } 29357977Seric QuickAbort = TRUE; 29455012Seric setsender(p, e); 29558151Seric message("250 Sender ok"); 29658147Seric gotmail = TRUE; 2974549Seric break; 2984549Seric 2994976Seric case CMDRCPT: /* rcpt -- designate recipient */ 30024943Seric SmtpPhase = "RCPT"; 30157389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 30212612Seric if (setjmp(TopFrame) > 0) 30314785Seric { 30455012Seric e->e_flags &= ~EF_FATALERRS; 30512612Seric break; 30614785Seric } 30712612Seric QuickAbort = TRUE; 30851951Seric LogUsrErrs = TRUE; 30958093Seric 31058093Seric /* optimization -- if queueing, don't expand aliases */ 31158093Seric if (SendMode == SM_QUEUE) 31258093Seric e->e_flags |= EF_VRFYONLY; 31358093Seric 3144549Seric p = skipword(p, "to"); 3154549Seric if (p == NULL) 3164549Seric break; 317*58323Seric a = parseaddr(p, (ADDRESS *) NULL, 1, ' ', e); 31812612Seric if (a == NULL) 31912612Seric break; 32016886Seric a->q_flags |= QPRIMARY; 32155012Seric a = recipient(a, &e->e_sendqueue, e); 32212612Seric if (Errors != 0) 32312612Seric break; 32412612Seric 32512612Seric /* no errors during parsing, but might be a duplicate */ 32655012Seric e->e_to = p; 32712612Seric if (!bitset(QBADADDR, a->q_flags)) 32858151Seric message("250 Recipient ok"); 32912612Seric else 3304549Seric { 33112612Seric /* punt -- should keep message in ADDRESS.... */ 33258151Seric message("550 Addressee unknown"); 3334549Seric } 33455012Seric e->e_to = NULL; 3354549Seric break; 3364549Seric 3374549Seric case CMDDATA: /* data -- text of mail */ 33824943Seric SmtpPhase = "DATA"; 33958109Seric if (!gotmail) 3404549Seric { 34158151Seric message("503 Need MAIL command"); 3424976Seric break; 3434549Seric } 34455012Seric else if (e->e_nrcpts <= 0) 3454549Seric { 34658151Seric message("503 Need RCPT (recipient)"); 3474976Seric break; 3484549Seric } 3494976Seric 3504976Seric /* collect the text of the message */ 35124943Seric SmtpPhase = "collect"; 35257389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 35355012Seric collect(TRUE, e); 3544976Seric if (Errors != 0) 3554976Seric break; 3564976Seric 3578238Seric /* 3588238Seric ** Arrange to send to everyone. 3598238Seric ** If sending to multiple people, mail back 3608238Seric ** errors rather than reporting directly. 3618238Seric ** In any case, don't mail back errors for 3628238Seric ** anything that has happened up to 3638238Seric ** now (the other end will do this). 36410197Seric ** Truncate our transcript -- the mail has gotten 36510197Seric ** to us successfully, and if we have 36610197Seric ** to mail this back, it will be easier 36710197Seric ** on the reader. 3688238Seric ** Then send to everyone. 3698238Seric ** Finally give a reply code. If an error has 3708238Seric ** already been given, don't mail a 3718238Seric ** message back. 3729339Seric ** We goose error returns by clearing error bit. 3738238Seric */ 3748238Seric 37524943Seric SmtpPhase = "delivery"; 37655012Seric if (e->e_nrcpts != 1) 3779378Seric { 3789378Seric HoldErrs = TRUE; 37916886Seric ErrorMode = EM_MAIL; 3809378Seric } 38155012Seric e->e_flags &= ~EF_FATALERRS; 38255012Seric e->e_xfp = freopen(queuename(e, 'x'), "w", e->e_xfp); 3834976Seric 3844976Seric /* send to all recipients */ 38555012Seric sendall(e, SM_DEFAULT); 38655012Seric e->e_to = NULL; 3874976Seric 38823516Seric /* save statistics */ 38955012Seric markstats(e, (ADDRESS *) NULL); 39023516Seric 3918238Seric /* issue success if appropriate and reset */ 3928238Seric if (Errors == 0 || HoldErrs) 39358151Seric message("250 Ok"); 3948238Seric else 39555012Seric e->e_flags &= ~EF_FATALERRS; 3969339Seric 3979339Seric /* if in a child, pop back to our parent */ 3989339Seric if (InChild) 3999339Seric finis(); 40024943Seric 40124943Seric /* clean up a bit */ 40258109Seric gotmail = FALSE; 40355012Seric dropenvelope(e); 40458179Seric CurEnv = e = newenvelope(e, CurEnv); 40555012Seric e->e_flags = BlankEnvelope.e_flags; 4064549Seric break; 4074549Seric 4084549Seric case CMDRSET: /* rset -- reset state */ 40958151Seric message("250 Reset state"); 4109339Seric if (InChild) 4119339Seric finis(); 41258109Seric 41358109Seric /* clean up a bit */ 41458109Seric gotmail = FALSE; 41558109Seric dropenvelope(e); 41658179Seric CurEnv = e = newenvelope(e, CurEnv); 4179339Seric break; 4184549Seric 4194549Seric case CMDVRFY: /* vrfy -- verify address */ 42058092Seric case CMDEXPN: /* expn -- expand address */ 42158092Seric vrfy = c->cmdcode == CMDVRFY; 42258092Seric if (bitset(vrfy ? PRIV_NOVRFY : PRIV_NOEXPN, 42358092Seric PrivacyFlags)) 42458082Seric { 42558151Seric message("502 That's none of your business"); 42658082Seric break; 42758082Seric } 42858082Seric else if (!gothello && 42958092Seric bitset(vrfy ? PRIV_NEEDVRFYHELO : PRIV_NEEDEXPNHELO, 43058092Seric PrivacyFlags)) 43158082Seric { 43258151Seric message("503 I demand that you introduce yourself first"); 43358082Seric break; 43458082Seric } 43558092Seric if (runinchild(vrfy ? "SMTP-VRFY" : "SMTP-EXPN", e) > 0) 4369339Seric break; 43725050Seric setproctitle("%s: %s", CurHostName, inp); 43855173Seric #ifdef LOG 43958020Seric if (LogLevel > 5) 44055173Seric syslog(LOG_INFO, "%s: %s", CurHostName, inp); 44155173Seric #endif 4425003Seric vrfyqueue = NULL; 4437762Seric QuickAbort = TRUE; 44458092Seric if (vrfy) 44558092Seric e->e_flags |= EF_VRFYONLY; 44658082Seric (void) sendtolist(p, (ADDRESS *) NULL, &vrfyqueue, e); 4477762Seric if (Errors != 0) 4489339Seric { 4499339Seric if (InChild) 4509339Seric finis(); 4517762Seric break; 4529339Seric } 4535003Seric while (vrfyqueue != NULL) 4545003Seric { 4555003Seric register ADDRESS *a = vrfyqueue->q_next; 4565003Seric char *code; 4575003Seric 4587685Seric while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags)) 4595003Seric a = a->q_next; 4605003Seric 4617685Seric if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags)) 46258151Seric printvrfyaddr(vrfyqueue, a == NULL); 4635003Seric else if (a == NULL) 46458151Seric message("554 Self destructive alias loop"); 4655003Seric vrfyqueue = a; 4665003Seric } 4679339Seric if (InChild) 4689339Seric finis(); 4694549Seric break; 4704549Seric 4714549Seric case CMDHELP: /* help -- give user info */ 4724577Seric help(p); 4734549Seric break; 4744549Seric 4754549Seric case CMDNOOP: /* noop -- do nothing */ 47658151Seric message("200 OK"); 4774549Seric break; 4784549Seric 4794549Seric case CMDQUIT: /* quit -- leave mail */ 48058151Seric message("221 %s closing connection", MyHostName); 4819339Seric if (InChild) 4829339Seric ExitStat = EX_QUIT; 4834549Seric finis(); 4844549Seric 4858544Seric case CMDVERB: /* set verbose mode */ 4868544Seric Verbose = TRUE; 48725025Seric SendMode = SM_DELIVER; 48858151Seric message("200 Verbose mode"); 4898544Seric break; 4908544Seric 4919314Seric case CMDONEX: /* doing one transaction only */ 4929378Seric OneXact = TRUE; 49358151Seric message("200 Only one transaction"); 4949314Seric break; 4959314Seric 49636230Skarels # ifdef SMTPDEBUG 4979339Seric case CMDDBGQSHOW: /* show queues */ 4986907Seric printf("Send Queue="); 49955012Seric printaddr(e->e_sendqueue, TRUE); 5005003Seric break; 5017275Seric 5027275Seric case CMDDBGDEBUG: /* set debug mode */ 5037676Seric tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); 5047676Seric tTflag(p); 50558151Seric message("200 Debug set"); 5067275Seric break; 5077275Seric 50836230Skarels # else /* not SMTPDEBUG */ 50924945Seric 51036230Skarels case CMDDBGQSHOW: /* show queues */ 51136230Skarels case CMDDBGDEBUG: /* set debug mode */ 51236233Skarels # ifdef LOG 51358308Seric if (LogLevel > 0) 51436230Skarels syslog(LOG_NOTICE, 51558020Seric "\"%s\" command from %s (%s)", 51636230Skarels c->cmdname, RealHostName, 51736230Skarels inet_ntoa(RealHostAddr.sin_addr)); 51836233Skarels # endif 51936230Skarels /* FALL THROUGH */ 52036230Skarels # endif /* SMTPDEBUG */ 52136230Skarels 5224549Seric case CMDERROR: /* unknown command */ 52358151Seric message("500 Command unrecognized"); 5244549Seric break; 5254549Seric 5264549Seric default: 52736230Skarels errno = 0; 52858151Seric syserr("500 smtp: unknown code %d", c->cmdcode); 5294549Seric break; 5304549Seric } 5314549Seric } 5324549Seric } 5334549Seric /* 5344549Seric ** SKIPWORD -- skip a fixed word. 5354549Seric ** 5364549Seric ** Parameters: 5374549Seric ** p -- place to start looking. 5384549Seric ** w -- word to skip. 5394549Seric ** 5404549Seric ** Returns: 5414549Seric ** p following w. 5424549Seric ** NULL on error. 5434549Seric ** 5444549Seric ** Side Effects: 5454549Seric ** clobbers the p data area. 5464549Seric */ 5474549Seric 5484549Seric static char * 5494549Seric skipword(p, w) 5504549Seric register char *p; 5514549Seric char *w; 5524549Seric { 5534549Seric register char *q; 5544549Seric 5554549Seric /* find beginning of word */ 55658050Seric while (isascii(*p) && isspace(*p)) 5574549Seric p++; 5584549Seric q = p; 5594549Seric 5604549Seric /* find end of word */ 56158050Seric while (*p != '\0' && *p != ':' && !(isascii(*p) && isspace(*p))) 5624549Seric p++; 56358050Seric while (isascii(*p) && isspace(*p)) 5644549Seric *p++ = '\0'; 5654549Seric if (*p != ':') 5664549Seric { 5674549Seric syntax: 56858151Seric message("501 Syntax error"); 5694549Seric Errors++; 5704549Seric return (NULL); 5714549Seric } 5724549Seric *p++ = '\0'; 57358050Seric while (isascii(*p) && isspace(*p)) 5744549Seric p++; 5754549Seric 5764549Seric /* see if the input word matches desired word */ 57733725Sbostic if (strcasecmp(q, w)) 5784549Seric goto syntax; 5794549Seric 5804549Seric return (p); 5814549Seric } 5824577Seric /* 58358151Seric ** PRINTVRFYADDR -- print an entry in the verify queue 58458151Seric ** 58558151Seric ** Parameters: 58658151Seric ** a -- the address to print 58758151Seric ** last -- set if this is the last one. 58858151Seric ** 58958151Seric ** Returns: 59058151Seric ** none. 59158151Seric ** 59258151Seric ** Side Effects: 59358151Seric ** Prints the appropriate 250 codes. 59458151Seric */ 59558151Seric 59658151Seric printvrfyaddr(a, last) 59758151Seric register ADDRESS *a; 59858151Seric bool last; 59958151Seric { 60058151Seric char fmtbuf[20]; 60158151Seric 60258151Seric strcpy(fmtbuf, "250"); 60358151Seric fmtbuf[3] = last ? ' ' : '-'; 60458151Seric 60558151Seric if (strchr(a->q_paddr, '<') != NULL) 60658151Seric strcpy(&fmtbuf[4], "%s"); 60758151Seric else if (a->q_fullname == NULL) 60858151Seric strcpy(&fmtbuf[4], "<%s>"); 60958151Seric else 61058151Seric { 61158151Seric strcpy(&fmtbuf[4], "%s <%s>"); 61258151Seric message(fmtbuf, a->q_fullname, a->q_paddr); 61358151Seric return; 61458151Seric } 61558151Seric message(fmtbuf, a->q_paddr); 61658151Seric } 61758151Seric /* 6184577Seric ** HELP -- implement the HELP command. 6194577Seric ** 6204577Seric ** Parameters: 6214577Seric ** topic -- the topic we want help for. 6224577Seric ** 6234577Seric ** Returns: 6244577Seric ** none. 6254577Seric ** 6264577Seric ** Side Effects: 6274577Seric ** outputs the help file to message output. 6284577Seric */ 6294577Seric 6304577Seric help(topic) 6314577Seric char *topic; 6324577Seric { 6334577Seric register FILE *hf; 6344577Seric int len; 6354577Seric char buf[MAXLINE]; 6364577Seric bool noinfo; 6374577Seric 6388269Seric if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL) 6394577Seric { 6404577Seric /* no help */ 64111931Seric errno = 0; 64258151Seric message("502 HELP not implemented"); 6434577Seric return; 6444577Seric } 6454577Seric 64649669Seric if (topic == NULL || *topic == '\0') 64749669Seric topic = "smtp"; 64849669Seric else 64949669Seric makelower(topic); 65049669Seric 6514577Seric len = strlen(topic); 6524577Seric noinfo = TRUE; 6534577Seric 6544577Seric while (fgets(buf, sizeof buf, hf) != NULL) 6554577Seric { 6564577Seric if (strncmp(buf, topic, len) == 0) 6574577Seric { 6584577Seric register char *p; 6594577Seric 66056795Seric p = strchr(buf, '\t'); 6614577Seric if (p == NULL) 6624577Seric p = buf; 6634577Seric else 6644577Seric p++; 6654577Seric fixcrlf(p, TRUE); 66658151Seric message("214-%s", p); 6674577Seric noinfo = FALSE; 6684577Seric } 6694577Seric } 6704577Seric 6714577Seric if (noinfo) 67258151Seric message("504 HELP topic unknown"); 6734577Seric else 67458151Seric message("214 End of HELP info"); 6754628Seric (void) fclose(hf); 6764577Seric } 6778544Seric /* 6789339Seric ** RUNINCHILD -- return twice -- once in the child, then in the parent again 6799339Seric ** 6809339Seric ** Parameters: 6819339Seric ** label -- a string used in error messages 6829339Seric ** 6839339Seric ** Returns: 6849339Seric ** zero in the child 6859339Seric ** one in the parent 6869339Seric ** 6879339Seric ** Side Effects: 6889339Seric ** none. 6899339Seric */ 6908544Seric 69155012Seric runinchild(label, e) 6929339Seric char *label; 69355012Seric register ENVELOPE *e; 6949339Seric { 6959339Seric int childpid; 6969339Seric 69716158Seric if (!OneXact) 6989339Seric { 69916158Seric childpid = dofork(); 70016158Seric if (childpid < 0) 70116158Seric { 70216158Seric syserr("%s: cannot fork", label); 70316158Seric return (1); 70416158Seric } 70516158Seric if (childpid > 0) 70616158Seric { 70716158Seric auto int st; 7089339Seric 70916158Seric /* parent -- wait for child to complete */ 71016158Seric st = waitfor(childpid); 71116158Seric if (st == -1) 71216158Seric syserr("%s: lost child", label); 7139339Seric 71416158Seric /* if we exited on a QUIT command, complete the process */ 71516158Seric if (st == (EX_QUIT << 8)) 71616158Seric finis(); 7179339Seric 71816158Seric return (1); 71916158Seric } 72016158Seric else 72116158Seric { 72216158Seric /* child */ 72316158Seric InChild = TRUE; 72425050Seric QuickAbort = FALSE; 72555012Seric clearenvelope(e, FALSE); 72616158Seric } 7279339Seric } 72815256Seric 72916158Seric /* open alias database */ 73055012Seric initaliases(AliasFile, FALSE, e); 73116158Seric 73216158Seric return (0); 7339339Seric } 7349339Seric 73556795Seric # endif /* SMTP */ 736