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*58330Seric static char sccsid[] = "@(#)srvrsmtp.c 6.20 (Berkeley) 03/01/93 (with SMTP)"; 1433731Sbostic #else 15*58330Seric static char sccsid[] = "@(#)srvrsmtp.c 6.20 (Berkeley) 03/01/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 */ 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 1157363Seric if (OutChannel != stdout) 1167363Seric { 1177363Seric /* arrange for debugging output to go to remote host */ 1187363Seric (void) close(1); 1197363Seric (void) dup(fileno(OutChannel)); 1207363Seric } 12155012Seric settime(e); 12257642Seric CurHostName = RealHostName; 12357642Seric setproctitle("srvrsmtp %s", CurHostName); 12458050Seric expand("\201e", inp, &inp[sizeof inp], e); 12558151Seric message("220 %s", inp); 12624943Seric SmtpPhase = "startup"; 12730448Seric sendinghost = NULL; 128*58330Seric protocol = NULL; 12958082Seric gothello = FALSE; 130*58330Seric gotmail = FALSE; 1314549Seric for (;;) 1324549Seric { 13312612Seric /* arrange for backout */ 13412612Seric if (setjmp(TopFrame) > 0 && InChild) 13512612Seric finis(); 13612612Seric QuickAbort = FALSE; 13712612Seric HoldErrs = FALSE; 13851951Seric LogUsrErrs = FALSE; 13958092Seric e->e_flags &= ~EF_VRFYONLY; 14012612Seric 1417356Seric /* setup for the read */ 14255012Seric e->e_to = NULL; 1434577Seric Errors = 0; 1447275Seric (void) fflush(stdout); 1457356Seric 1467356Seric /* read the input line */ 14758109Seric p = sfgets(inp, sizeof inp, InChannel, TimeOuts.to_nextcommand); 1487356Seric 1497685Seric /* handle errors */ 1507356Seric if (p == NULL) 1517356Seric { 1524549Seric /* end of file, just die */ 15358151Seric message("421 %s Lost input channel from %s", 15425050Seric MyHostName, CurHostName); 15555464Seric #ifdef LOG 15658020Seric if (LogLevel > 1) 15755464Seric syslog(LOG_NOTICE, "lost input channel from %s", 15855464Seric CurHostName); 15955464Seric #endif 16058069Seric if (InChild) 16158069Seric ExitStat = EX_QUIT; 1624549Seric finis(); 1634549Seric } 1644549Seric 1654549Seric /* clean up end of line */ 1664558Seric fixcrlf(inp, TRUE); 1674549Seric 1684713Seric /* echo command to transcript */ 16955012Seric if (e->e_xfp != NULL) 17055012Seric fprintf(e->e_xfp, "<<< %s\n", inp); 1714713Seric 1724549Seric /* break off command */ 17358050Seric for (p = inp; isascii(*p) && isspace(*p); p++) 1744549Seric continue; 17557232Seric cmd = cmdbuf; 17658050Seric while (*p != '\0' && 17758050Seric !(isascii(*p) && isspace(*p)) && 17858050Seric cmd < &cmdbuf[sizeof cmdbuf - 2]) 17924981Seric *cmd++ = *p++; 18024981Seric *cmd = '\0'; 1814549Seric 18225691Seric /* throw away leading whitespace */ 18358050Seric while (isascii(*p) && isspace(*p)) 18425691Seric p++; 18525691Seric 1864549Seric /* decode command */ 1874549Seric for (c = CmdTab; c->cmdname != NULL; c++) 1884549Seric { 18933725Sbostic if (!strcasecmp(c->cmdname, cmdbuf)) 1904549Seric break; 1914549Seric } 1924549Seric 19351954Seric /* reset errors */ 19451954Seric errno = 0; 19551954Seric 1964549Seric /* process command */ 1974549Seric switch (c->cmdcode) 1984549Seric { 1994976Seric case CMDHELO: /* hello -- introduce yourself */ 20058323Seric case CMDEHLO: /* extended hello */ 20158323Seric if (c->cmdcode == CMDEHLO) 20258323Seric { 20358323Seric protocol = "ESMTP"; 20458323Seric SmtpPhase = "EHLO"; 20558323Seric } 20658323Seric else 20758323Seric { 20858323Seric protocol = "SMTP"; 20958323Seric SmtpPhase = "HELO"; 21058323Seric } 21125050Seric setproctitle("%s: %s", CurHostName, inp); 21258109Seric if (strcasecmp(p, MyHostName) == 0) 21314877Seric { 21436230Skarels /* 21558109Seric ** Didn't know about alias or MX, 21658109Seric ** or connected to an echo server 21758109Seric */ 21858109Seric 21958151Seric message("553 %s config error: mail loops back to myself", 22047570Seric MyHostName); 22114877Seric break; 22214877Seric } 22358308Seric if (strcasecmp(p, RealHostName) != 0) 22411146Seric { 22524981Seric char hostbuf[MAXNAME]; 22611146Seric 22724981Seric (void) sprintf(hostbuf, "%s (%s)", p, RealHostName); 22830448Seric sendinghost = newstr(hostbuf); 22911146Seric } 23011146Seric else 23130448Seric sendinghost = newstr(p); 23258323Seric 23358323Seric /* send ext. message -- old systems must ignore */ 23458323Seric message("250-%s Hello %s, pleased to meet you", 23536230Skarels MyHostName, sendinghost); 23658323Seric if (!bitset(PRIV_NOEXPN, PrivacyFlags)) 23758323Seric message("250-EXPN"); 23858323Seric message("250 HELP"); 23958082Seric gothello = TRUE; 2404976Seric break; 2414976Seric 2424549Seric case CMDMAIL: /* mail -- designate sender */ 24324943Seric SmtpPhase = "MAIL"; 24424943Seric 24511151Seric /* force a sending host even if no HELO given */ 24658064Seric if (sendinghost == NULL && macvalue('s', e) == NULL) 24730448Seric sendinghost = RealHostName; 24811151Seric 2499314Seric /* check for validity of this command */ 25058082Seric if (!gothello && bitset(PRIV_NEEDMAILHELO, PrivacyFlags)) 25158082Seric { 25258151Seric message("503 Polite people say HELO first"); 25358082Seric break; 25458082Seric } 25558109Seric if (gotmail) 2564558Seric { 25758151Seric message("503 Sender already specified"); 2584558Seric break; 2594558Seric } 2609339Seric if (InChild) 2619339Seric { 26236230Skarels errno = 0; 26358151Seric syserr("503 Nested MAIL command: MAIL %s", p); 26458069Seric finis(); 2659339Seric } 26658082Seric if (!enoughspace()) 26758082Seric { 26858151Seric message("452 Insufficient disk space; try again later"); 26958082Seric break; 27058082Seric } 2719339Seric 2729339Seric /* fork a subprocess to process this command */ 27355012Seric if (runinchild("SMTP-MAIL", e) > 0) 2749339Seric break; 27558064Seric if (sendinghost != NULL) 27658064Seric define('s', sendinghost, e); 27758323Seric if (protocol == NULL) 27858323Seric protocol = "SMTP"; 27958323Seric define('r', protocol, e); 28055012Seric initsys(e); 28157389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 2829339Seric 2839339Seric /* child -- go do the processing */ 2844549Seric p = skipword(p, "from"); 2854549Seric if (p == NULL) 2864549Seric break; 28757977Seric if (setjmp(TopFrame) > 0) 28858147Seric { 28958147Seric /* this failed -- undo work */ 29058147Seric if (InChild) 29158147Seric finis(); 29257977Seric break; 29358147Seric } 29457977Seric QuickAbort = TRUE; 29555012Seric setsender(p, e); 29658151Seric message("250 Sender ok"); 29758147Seric gotmail = TRUE; 2984549Seric break; 2994549Seric 3004976Seric case CMDRCPT: /* rcpt -- designate recipient */ 30124943Seric SmtpPhase = "RCPT"; 30257389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 30312612Seric if (setjmp(TopFrame) > 0) 30414785Seric { 30555012Seric e->e_flags &= ~EF_FATALERRS; 30612612Seric break; 30714785Seric } 30812612Seric QuickAbort = TRUE; 30951951Seric LogUsrErrs = TRUE; 31058093Seric 31158093Seric /* optimization -- if queueing, don't expand aliases */ 31258093Seric if (SendMode == SM_QUEUE) 31358093Seric e->e_flags |= EF_VRFYONLY; 31458093Seric 3154549Seric p = skipword(p, "to"); 3164549Seric if (p == NULL) 3174549Seric break; 31858323Seric a = parseaddr(p, (ADDRESS *) NULL, 1, ' ', e); 31912612Seric if (a == NULL) 32012612Seric break; 32116886Seric a->q_flags |= QPRIMARY; 32255012Seric a = recipient(a, &e->e_sendqueue, e); 32312612Seric if (Errors != 0) 32412612Seric break; 32512612Seric 32612612Seric /* no errors during parsing, but might be a duplicate */ 32755012Seric e->e_to = p; 32812612Seric if (!bitset(QBADADDR, a->q_flags)) 32958151Seric message("250 Recipient ok"); 33012612Seric else 3314549Seric { 33212612Seric /* punt -- should keep message in ADDRESS.... */ 33358151Seric message("550 Addressee unknown"); 3344549Seric } 33555012Seric e->e_to = NULL; 3364549Seric break; 3374549Seric 3384549Seric case CMDDATA: /* data -- text of mail */ 33924943Seric SmtpPhase = "DATA"; 34058109Seric if (!gotmail) 3414549Seric { 34258151Seric message("503 Need MAIL command"); 3434976Seric break; 3444549Seric } 34555012Seric else if (e->e_nrcpts <= 0) 3464549Seric { 34758151Seric message("503 Need RCPT (recipient)"); 3484976Seric break; 3494549Seric } 3504976Seric 3514976Seric /* collect the text of the message */ 35224943Seric SmtpPhase = "collect"; 35357389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 35455012Seric collect(TRUE, e); 3554976Seric if (Errors != 0) 3564976Seric break; 3574976Seric 3588238Seric /* 3598238Seric ** Arrange to send to everyone. 3608238Seric ** If sending to multiple people, mail back 3618238Seric ** errors rather than reporting directly. 3628238Seric ** In any case, don't mail back errors for 3638238Seric ** anything that has happened up to 3648238Seric ** now (the other end will do this). 36510197Seric ** Truncate our transcript -- the mail has gotten 36610197Seric ** to us successfully, and if we have 36710197Seric ** to mail this back, it will be easier 36810197Seric ** on the reader. 3698238Seric ** Then send to everyone. 3708238Seric ** Finally give a reply code. If an error has 3718238Seric ** already been given, don't mail a 3728238Seric ** message back. 3739339Seric ** We goose error returns by clearing error bit. 3748238Seric */ 3758238Seric 37624943Seric SmtpPhase = "delivery"; 37755012Seric if (e->e_nrcpts != 1) 3789378Seric { 3799378Seric HoldErrs = TRUE; 38016886Seric ErrorMode = EM_MAIL; 3819378Seric } 38255012Seric e->e_flags &= ~EF_FATALERRS; 38355012Seric e->e_xfp = freopen(queuename(e, 'x'), "w", e->e_xfp); 3844976Seric 3854976Seric /* send to all recipients */ 38655012Seric sendall(e, SM_DEFAULT); 38755012Seric e->e_to = NULL; 3884976Seric 38923516Seric /* save statistics */ 39055012Seric markstats(e, (ADDRESS *) NULL); 39123516Seric 3928238Seric /* issue success if appropriate and reset */ 3938238Seric if (Errors == 0 || HoldErrs) 39458151Seric message("250 Ok"); 3958238Seric else 39655012Seric e->e_flags &= ~EF_FATALERRS; 3979339Seric 3989339Seric /* if in a child, pop back to our parent */ 3999339Seric if (InChild) 4009339Seric finis(); 40124943Seric 40224943Seric /* clean up a bit */ 40358109Seric gotmail = FALSE; 40455012Seric dropenvelope(e); 40558179Seric CurEnv = e = newenvelope(e, CurEnv); 40655012Seric e->e_flags = BlankEnvelope.e_flags; 4074549Seric break; 4084549Seric 4094549Seric case CMDRSET: /* rset -- reset state */ 41058151Seric message("250 Reset state"); 4119339Seric if (InChild) 4129339Seric finis(); 41358109Seric 41458109Seric /* clean up a bit */ 41558109Seric gotmail = FALSE; 41658109Seric dropenvelope(e); 41758179Seric CurEnv = e = newenvelope(e, CurEnv); 4189339Seric break; 4194549Seric 4204549Seric case CMDVRFY: /* vrfy -- verify address */ 42158092Seric case CMDEXPN: /* expn -- expand address */ 42258092Seric vrfy = c->cmdcode == CMDVRFY; 42358092Seric if (bitset(vrfy ? PRIV_NOVRFY : PRIV_NOEXPN, 42458092Seric PrivacyFlags)) 42558082Seric { 42658151Seric message("502 That's none of your business"); 42758082Seric break; 42858082Seric } 42958082Seric else if (!gothello && 43058092Seric bitset(vrfy ? PRIV_NEEDVRFYHELO : PRIV_NEEDEXPNHELO, 43158092Seric PrivacyFlags)) 43258082Seric { 43358151Seric message("503 I demand that you introduce yourself first"); 43458082Seric break; 43558082Seric } 43658092Seric if (runinchild(vrfy ? "SMTP-VRFY" : "SMTP-EXPN", e) > 0) 4379339Seric break; 43825050Seric setproctitle("%s: %s", CurHostName, inp); 43955173Seric #ifdef LOG 44058020Seric if (LogLevel > 5) 44155173Seric syslog(LOG_INFO, "%s: %s", CurHostName, inp); 44255173Seric #endif 4435003Seric vrfyqueue = NULL; 4447762Seric QuickAbort = TRUE; 44558092Seric if (vrfy) 44658092Seric e->e_flags |= EF_VRFYONLY; 44758082Seric (void) sendtolist(p, (ADDRESS *) NULL, &vrfyqueue, e); 4487762Seric if (Errors != 0) 4499339Seric { 4509339Seric if (InChild) 4519339Seric finis(); 4527762Seric break; 4539339Seric } 4545003Seric while (vrfyqueue != NULL) 4555003Seric { 4565003Seric register ADDRESS *a = vrfyqueue->q_next; 4575003Seric char *code; 4585003Seric 4597685Seric while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags)) 4605003Seric a = a->q_next; 4615003Seric 4627685Seric if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags)) 46358151Seric printvrfyaddr(vrfyqueue, a == NULL); 4645003Seric else if (a == NULL) 46558151Seric message("554 Self destructive alias loop"); 4665003Seric vrfyqueue = a; 4675003Seric } 4689339Seric if (InChild) 4699339Seric finis(); 4704549Seric break; 4714549Seric 4724549Seric case CMDHELP: /* help -- give user info */ 4734577Seric help(p); 4744549Seric break; 4754549Seric 4764549Seric case CMDNOOP: /* noop -- do nothing */ 47758151Seric message("200 OK"); 4784549Seric break; 4794549Seric 4804549Seric case CMDQUIT: /* quit -- leave mail */ 48158151Seric message("221 %s closing connection", MyHostName); 4829339Seric if (InChild) 4839339Seric ExitStat = EX_QUIT; 4844549Seric finis(); 4854549Seric 4868544Seric case CMDVERB: /* set verbose mode */ 4878544Seric Verbose = TRUE; 48825025Seric SendMode = SM_DELIVER; 48958151Seric message("200 Verbose mode"); 4908544Seric break; 4918544Seric 4929314Seric case CMDONEX: /* doing one transaction only */ 4939378Seric OneXact = TRUE; 49458151Seric message("200 Only one transaction"); 4959314Seric break; 4969314Seric 49736230Skarels # ifdef SMTPDEBUG 4989339Seric case CMDDBGQSHOW: /* show queues */ 4996907Seric printf("Send Queue="); 50055012Seric printaddr(e->e_sendqueue, TRUE); 5015003Seric break; 5027275Seric 5037275Seric case CMDDBGDEBUG: /* set debug mode */ 5047676Seric tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); 5057676Seric tTflag(p); 50658151Seric message("200 Debug set"); 5077275Seric break; 5087275Seric 50936230Skarels # else /* not SMTPDEBUG */ 51024945Seric 51136230Skarels case CMDDBGQSHOW: /* show queues */ 51236230Skarels case CMDDBGDEBUG: /* set debug mode */ 51336233Skarels # ifdef LOG 51458308Seric if (LogLevel > 0) 51536230Skarels syslog(LOG_NOTICE, 51658020Seric "\"%s\" command from %s (%s)", 51736230Skarels c->cmdname, RealHostName, 51836230Skarels inet_ntoa(RealHostAddr.sin_addr)); 51936233Skarels # endif 52036230Skarels /* FALL THROUGH */ 52136230Skarels # endif /* SMTPDEBUG */ 52236230Skarels 5234549Seric case CMDERROR: /* unknown command */ 52458151Seric message("500 Command unrecognized"); 5254549Seric break; 5264549Seric 5274549Seric default: 52836230Skarels errno = 0; 52958151Seric syserr("500 smtp: unknown code %d", c->cmdcode); 5304549Seric break; 5314549Seric } 5324549Seric } 5334549Seric } 5344549Seric /* 5354549Seric ** SKIPWORD -- skip a fixed word. 5364549Seric ** 5374549Seric ** Parameters: 5384549Seric ** p -- place to start looking. 5394549Seric ** w -- word to skip. 5404549Seric ** 5414549Seric ** Returns: 5424549Seric ** p following w. 5434549Seric ** NULL on error. 5444549Seric ** 5454549Seric ** Side Effects: 5464549Seric ** clobbers the p data area. 5474549Seric */ 5484549Seric 5494549Seric static char * 5504549Seric skipword(p, w) 5514549Seric register char *p; 5524549Seric char *w; 5534549Seric { 5544549Seric register char *q; 5554549Seric 5564549Seric /* find beginning of word */ 55758050Seric while (isascii(*p) && isspace(*p)) 5584549Seric p++; 5594549Seric q = p; 5604549Seric 5614549Seric /* find end of word */ 56258050Seric while (*p != '\0' && *p != ':' && !(isascii(*p) && isspace(*p))) 5634549Seric p++; 56458050Seric while (isascii(*p) && isspace(*p)) 5654549Seric *p++ = '\0'; 5664549Seric if (*p != ':') 5674549Seric { 5684549Seric syntax: 56958151Seric message("501 Syntax error"); 5704549Seric Errors++; 5714549Seric return (NULL); 5724549Seric } 5734549Seric *p++ = '\0'; 57458050Seric while (isascii(*p) && isspace(*p)) 5754549Seric p++; 5764549Seric 5774549Seric /* see if the input word matches desired word */ 57833725Sbostic if (strcasecmp(q, w)) 5794549Seric goto syntax; 5804549Seric 5814549Seric return (p); 5824549Seric } 5834577Seric /* 58458151Seric ** PRINTVRFYADDR -- print an entry in the verify queue 58558151Seric ** 58658151Seric ** Parameters: 58758151Seric ** a -- the address to print 58858151Seric ** last -- set if this is the last one. 58958151Seric ** 59058151Seric ** Returns: 59158151Seric ** none. 59258151Seric ** 59358151Seric ** Side Effects: 59458151Seric ** Prints the appropriate 250 codes. 59558151Seric */ 59658151Seric 59758151Seric printvrfyaddr(a, last) 59858151Seric register ADDRESS *a; 59958151Seric bool last; 60058151Seric { 60158151Seric char fmtbuf[20]; 60258151Seric 60358151Seric strcpy(fmtbuf, "250"); 60458151Seric fmtbuf[3] = last ? ' ' : '-'; 60558151Seric 60658151Seric if (strchr(a->q_paddr, '<') != NULL) 60758151Seric strcpy(&fmtbuf[4], "%s"); 60858151Seric else if (a->q_fullname == NULL) 60958151Seric strcpy(&fmtbuf[4], "<%s>"); 61058151Seric else 61158151Seric { 61258151Seric strcpy(&fmtbuf[4], "%s <%s>"); 61358151Seric message(fmtbuf, a->q_fullname, a->q_paddr); 61458151Seric return; 61558151Seric } 61658151Seric message(fmtbuf, a->q_paddr); 61758151Seric } 61858151Seric /* 6194577Seric ** HELP -- implement the HELP command. 6204577Seric ** 6214577Seric ** Parameters: 6224577Seric ** topic -- the topic we want help for. 6234577Seric ** 6244577Seric ** Returns: 6254577Seric ** none. 6264577Seric ** 6274577Seric ** Side Effects: 6284577Seric ** outputs the help file to message output. 6294577Seric */ 6304577Seric 6314577Seric help(topic) 6324577Seric char *topic; 6334577Seric { 6344577Seric register FILE *hf; 6354577Seric int len; 6364577Seric char buf[MAXLINE]; 6374577Seric bool noinfo; 6384577Seric 6398269Seric if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL) 6404577Seric { 6414577Seric /* no help */ 64211931Seric errno = 0; 64358151Seric message("502 HELP not implemented"); 6444577Seric return; 6454577Seric } 6464577Seric 64749669Seric if (topic == NULL || *topic == '\0') 64849669Seric topic = "smtp"; 64949669Seric else 65049669Seric makelower(topic); 65149669Seric 6524577Seric len = strlen(topic); 6534577Seric noinfo = TRUE; 6544577Seric 6554577Seric while (fgets(buf, sizeof buf, hf) != NULL) 6564577Seric { 6574577Seric if (strncmp(buf, topic, len) == 0) 6584577Seric { 6594577Seric register char *p; 6604577Seric 66156795Seric p = strchr(buf, '\t'); 6624577Seric if (p == NULL) 6634577Seric p = buf; 6644577Seric else 6654577Seric p++; 6664577Seric fixcrlf(p, TRUE); 66758151Seric message("214-%s", p); 6684577Seric noinfo = FALSE; 6694577Seric } 6704577Seric } 6714577Seric 6724577Seric if (noinfo) 67358151Seric message("504 HELP topic unknown"); 6744577Seric else 67558151Seric message("214 End of HELP info"); 6764628Seric (void) fclose(hf); 6774577Seric } 6788544Seric /* 6799339Seric ** RUNINCHILD -- return twice -- once in the child, then in the parent again 6809339Seric ** 6819339Seric ** Parameters: 6829339Seric ** label -- a string used in error messages 6839339Seric ** 6849339Seric ** Returns: 6859339Seric ** zero in the child 6869339Seric ** one in the parent 6879339Seric ** 6889339Seric ** Side Effects: 6899339Seric ** none. 6909339Seric */ 6918544Seric 69255012Seric runinchild(label, e) 6939339Seric char *label; 69455012Seric register ENVELOPE *e; 6959339Seric { 6969339Seric int childpid; 6979339Seric 69816158Seric if (!OneXact) 6999339Seric { 70016158Seric childpid = dofork(); 70116158Seric if (childpid < 0) 70216158Seric { 70316158Seric syserr("%s: cannot fork", label); 70416158Seric return (1); 70516158Seric } 70616158Seric if (childpid > 0) 70716158Seric { 70816158Seric auto int st; 7099339Seric 71016158Seric /* parent -- wait for child to complete */ 71116158Seric st = waitfor(childpid); 71216158Seric if (st == -1) 71316158Seric syserr("%s: lost child", label); 7149339Seric 71516158Seric /* if we exited on a QUIT command, complete the process */ 71616158Seric if (st == (EX_QUIT << 8)) 71716158Seric finis(); 7189339Seric 71916158Seric return (1); 72016158Seric } 72116158Seric else 72216158Seric { 72316158Seric /* child */ 72416158Seric InChild = TRUE; 72525050Seric QuickAbort = FALSE; 72655012Seric clearenvelope(e, FALSE); 72716158Seric } 7289339Seric } 72915256Seric 73016158Seric /* open alias database */ 73155012Seric initaliases(AliasFile, FALSE, e); 73216158Seric 73316158Seric return (0); 7349339Seric } 7359339Seric 73656795Seric # endif /* SMTP */ 737