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*58333Seric static char sccsid[] = "@(#)srvrsmtp.c 6.21 (Berkeley) 03/01/93 (with SMTP)"; 1433731Sbostic #else 15*58333Seric static char sccsid[] = "@(#)srvrsmtp.c 6.21 (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 */ 107*58333Seric long msize; /* approximate maximum message size */ 108*58333Seric auto char *delimptr; 1098544Seric char inp[MAXLINE]; 11057232Seric char cmdbuf[MAXLINE]; 1117124Seric extern char Version[]; 11211151Seric extern char *macvalue(); 11312612Seric extern ADDRESS *recipient(); 11424943Seric extern ENVELOPE BlankEnvelope; 11524943Seric extern ENVELOPE *newenvelope(); 1164549Seric 1177363Seric if (OutChannel != stdout) 1187363Seric { 1197363Seric /* arrange for debugging output to go to remote host */ 1207363Seric (void) close(1); 1217363Seric (void) dup(fileno(OutChannel)); 1227363Seric } 12355012Seric settime(e); 12457642Seric CurHostName = RealHostName; 12557642Seric setproctitle("srvrsmtp %s", CurHostName); 12658050Seric expand("\201e", inp, &inp[sizeof inp], e); 12758151Seric message("220 %s", inp); 12824943Seric SmtpPhase = "startup"; 12930448Seric sendinghost = NULL; 13058330Seric protocol = NULL; 13158082Seric gothello = FALSE; 13258330Seric gotmail = FALSE; 1334549Seric for (;;) 1344549Seric { 13512612Seric /* arrange for backout */ 13612612Seric if (setjmp(TopFrame) > 0 && InChild) 13712612Seric finis(); 13812612Seric QuickAbort = FALSE; 13912612Seric HoldErrs = FALSE; 14051951Seric LogUsrErrs = FALSE; 14158092Seric e->e_flags &= ~EF_VRFYONLY; 14212612Seric 1437356Seric /* setup for the read */ 14455012Seric e->e_to = NULL; 1454577Seric Errors = 0; 1467275Seric (void) fflush(stdout); 1477356Seric 1487356Seric /* read the input line */ 14958109Seric p = sfgets(inp, sizeof inp, InChannel, TimeOuts.to_nextcommand); 1507356Seric 1517685Seric /* handle errors */ 1527356Seric if (p == NULL) 1537356Seric { 1544549Seric /* end of file, just die */ 15558151Seric message("421 %s Lost input channel from %s", 15625050Seric MyHostName, CurHostName); 15755464Seric #ifdef LOG 15858020Seric if (LogLevel > 1) 15955464Seric syslog(LOG_NOTICE, "lost input channel from %s", 16055464Seric CurHostName); 16155464Seric #endif 16258069Seric if (InChild) 16358069Seric ExitStat = EX_QUIT; 1644549Seric finis(); 1654549Seric } 1664549Seric 1674549Seric /* clean up end of line */ 1684558Seric fixcrlf(inp, TRUE); 1694549Seric 1704713Seric /* echo command to transcript */ 17155012Seric if (e->e_xfp != NULL) 17255012Seric fprintf(e->e_xfp, "<<< %s\n", inp); 1734713Seric 1744549Seric /* break off command */ 17558050Seric for (p = inp; isascii(*p) && isspace(*p); p++) 1764549Seric continue; 17757232Seric cmd = cmdbuf; 17858050Seric while (*p != '\0' && 17958050Seric !(isascii(*p) && isspace(*p)) && 18058050Seric cmd < &cmdbuf[sizeof cmdbuf - 2]) 18124981Seric *cmd++ = *p++; 18224981Seric *cmd = '\0'; 1834549Seric 18425691Seric /* throw away leading whitespace */ 18558050Seric while (isascii(*p) && isspace(*p)) 18625691Seric p++; 18725691Seric 1884549Seric /* decode command */ 1894549Seric for (c = CmdTab; c->cmdname != NULL; c++) 1904549Seric { 19133725Sbostic if (!strcasecmp(c->cmdname, cmdbuf)) 1924549Seric break; 1934549Seric } 1944549Seric 19551954Seric /* reset errors */ 19651954Seric errno = 0; 19751954Seric 1984549Seric /* process command */ 1994549Seric switch (c->cmdcode) 2004549Seric { 2014976Seric case CMDHELO: /* hello -- introduce yourself */ 20258323Seric case CMDEHLO: /* extended hello */ 20358323Seric if (c->cmdcode == CMDEHLO) 20458323Seric { 20558323Seric protocol = "ESMTP"; 20658323Seric SmtpPhase = "EHLO"; 20758323Seric } 20858323Seric else 20958323Seric { 21058323Seric protocol = "SMTP"; 21158323Seric SmtpPhase = "HELO"; 21258323Seric } 21325050Seric setproctitle("%s: %s", CurHostName, inp); 21458109Seric if (strcasecmp(p, MyHostName) == 0) 21514877Seric { 21636230Skarels /* 21758109Seric ** Didn't know about alias or MX, 21858109Seric ** or connected to an echo server 21958109Seric */ 22058109Seric 22158151Seric message("553 %s config error: mail loops back to myself", 22247570Seric MyHostName); 22314877Seric break; 22414877Seric } 22558308Seric if (strcasecmp(p, RealHostName) != 0) 22611146Seric { 22724981Seric char hostbuf[MAXNAME]; 22811146Seric 22924981Seric (void) sprintf(hostbuf, "%s (%s)", p, RealHostName); 23030448Seric sendinghost = newstr(hostbuf); 23111146Seric } 23211146Seric else 23330448Seric sendinghost = newstr(p); 23458323Seric 23558323Seric /* send ext. message -- old systems must ignore */ 23658323Seric message("250-%s Hello %s, pleased to meet you", 23736230Skarels MyHostName, sendinghost); 23858323Seric if (!bitset(PRIV_NOEXPN, PrivacyFlags)) 23958323Seric message("250-EXPN"); 24058323Seric message("250 HELP"); 24158082Seric gothello = TRUE; 2424976Seric break; 2434976Seric 2444549Seric case CMDMAIL: /* mail -- designate sender */ 24524943Seric SmtpPhase = "MAIL"; 24624943Seric 24711151Seric /* force a sending host even if no HELO given */ 24858064Seric if (sendinghost == NULL && macvalue('s', e) == NULL) 24930448Seric sendinghost = RealHostName; 25011151Seric 2519314Seric /* check for validity of this command */ 25258082Seric if (!gothello && bitset(PRIV_NEEDMAILHELO, PrivacyFlags)) 25358082Seric { 25458151Seric message("503 Polite people say HELO first"); 25558082Seric break; 25658082Seric } 25758109Seric if (gotmail) 2584558Seric { 25958151Seric message("503 Sender already specified"); 2604558Seric break; 2614558Seric } 2629339Seric if (InChild) 2639339Seric { 26436230Skarels errno = 0; 26558151Seric syserr("503 Nested MAIL command: MAIL %s", p); 26658069Seric finis(); 2679339Seric } 2689339Seric 2699339Seric /* fork a subprocess to process this command */ 27055012Seric if (runinchild("SMTP-MAIL", e) > 0) 2719339Seric break; 27258064Seric if (sendinghost != NULL) 27358064Seric define('s', sendinghost, e); 27458323Seric if (protocol == NULL) 27558323Seric protocol = "SMTP"; 27658323Seric define('r', protocol, e); 27755012Seric initsys(e); 27857389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 2799339Seric 2809339Seric /* child -- go do the processing */ 2814549Seric p = skipword(p, "from"); 2824549Seric if (p == NULL) 2834549Seric break; 28457977Seric if (setjmp(TopFrame) > 0) 28558147Seric { 28658147Seric /* this failed -- undo work */ 28758147Seric if (InChild) 28858147Seric finis(); 28957977Seric break; 29058147Seric } 29157977Seric QuickAbort = TRUE; 292*58333Seric 293*58333Seric /* must parse sender first */ 294*58333Seric delimptr = NULL; 295*58333Seric setsender(p, e, &delimptr); 296*58333Seric p = delimptr; 297*58333Seric if (p != NULL && *p != '\0') 298*58333Seric *p++ = '\0'; 299*58333Seric 300*58333Seric /* now parse ESMTP arguments */ 301*58333Seric msize = 0; 302*58333Seric for (; p != NULL && *p != '\0'; p++) 303*58333Seric { 304*58333Seric char *kp; 305*58333Seric char *vp; 306*58333Seric 307*58333Seric /* locate the beginning of the keyword */ 308*58333Seric while (isascii(*p) && isspace(*p)) 309*58333Seric p++; 310*58333Seric if (*p == '\0') 311*58333Seric break; 312*58333Seric kp = p; 313*58333Seric 314*58333Seric /* skip to the value portion */ 315*58333Seric while (isascii(*p) && isalnum(*p) || *p == '-') 316*58333Seric p++; 317*58333Seric if (*p == '=') 318*58333Seric { 319*58333Seric *p++ = '\0'; 320*58333Seric vp = p; 321*58333Seric 322*58333Seric /* skip to the end of the value */ 323*58333Seric while (*p != '\0' && *p != ' ' && 324*58333Seric !(isascii(*p) && iscntrl(*p)) && 325*58333Seric *p != '=') 326*58333Seric p++; 327*58333Seric } 328*58333Seric 329*58333Seric if (*p != '\0') 330*58333Seric *p++ = '\0'; 331*58333Seric 332*58333Seric if (tTd(19, 1)) 333*58333Seric printf("MAIL: got arg %s=%s\n", kp, 334*58333Seric vp == NULL ? "<null>" : vp); 335*58333Seric 336*58333Seric if (strcasecmp(kp, "size") == 0) 337*58333Seric { 338*58333Seric if (kp == NULL) 339*58333Seric { 340*58333Seric usrerr("501 SIZE requires a value"); 341*58333Seric /* NOTREACHED */ 342*58333Seric } 343*58333Seric msize = atol(vp); 344*58333Seric } 345*58333Seric else 346*58333Seric { 347*58333Seric usrerr("501 %s parameter unrecognized", kp); 348*58333Seric /* NOTREACHED */ 349*58333Seric } 350*58333Seric } 351*58333Seric 352*58333Seric if (!enoughspace(msize)) 353*58333Seric { 354*58333Seric message("452 Insufficient disk space; try again later"); 355*58333Seric break; 356*58333Seric } 35758151Seric message("250 Sender ok"); 35858147Seric gotmail = TRUE; 3594549Seric break; 3604549Seric 3614976Seric case CMDRCPT: /* rcpt -- designate recipient */ 36224943Seric SmtpPhase = "RCPT"; 36357389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 36412612Seric if (setjmp(TopFrame) > 0) 36514785Seric { 36655012Seric e->e_flags &= ~EF_FATALERRS; 36712612Seric break; 36814785Seric } 36912612Seric QuickAbort = TRUE; 37051951Seric LogUsrErrs = TRUE; 37158093Seric 37258093Seric /* optimization -- if queueing, don't expand aliases */ 37358093Seric if (SendMode == SM_QUEUE) 37458093Seric e->e_flags |= EF_VRFYONLY; 37558093Seric 3764549Seric p = skipword(p, "to"); 3774549Seric if (p == NULL) 3784549Seric break; 379*58333Seric a = parseaddr(p, (ADDRESS *) NULL, 1, ' ', NULL, e); 38012612Seric if (a == NULL) 38112612Seric break; 38216886Seric a->q_flags |= QPRIMARY; 38355012Seric a = recipient(a, &e->e_sendqueue, e); 38412612Seric if (Errors != 0) 38512612Seric break; 38612612Seric 38712612Seric /* no errors during parsing, but might be a duplicate */ 38855012Seric e->e_to = p; 38912612Seric if (!bitset(QBADADDR, a->q_flags)) 39058151Seric message("250 Recipient ok"); 39112612Seric else 3924549Seric { 39312612Seric /* punt -- should keep message in ADDRESS.... */ 39458151Seric message("550 Addressee unknown"); 3954549Seric } 39655012Seric e->e_to = NULL; 3974549Seric break; 3984549Seric 3994549Seric case CMDDATA: /* data -- text of mail */ 40024943Seric SmtpPhase = "DATA"; 40158109Seric if (!gotmail) 4024549Seric { 40358151Seric message("503 Need MAIL command"); 4044976Seric break; 4054549Seric } 40655012Seric else if (e->e_nrcpts <= 0) 4074549Seric { 40858151Seric message("503 Need RCPT (recipient)"); 4094976Seric break; 4104549Seric } 4114976Seric 4124976Seric /* collect the text of the message */ 41324943Seric SmtpPhase = "collect"; 41457389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 41555012Seric collect(TRUE, e); 4164976Seric if (Errors != 0) 4174976Seric break; 4184976Seric 4198238Seric /* 4208238Seric ** Arrange to send to everyone. 4218238Seric ** If sending to multiple people, mail back 4228238Seric ** errors rather than reporting directly. 4238238Seric ** In any case, don't mail back errors for 4248238Seric ** anything that has happened up to 4258238Seric ** now (the other end will do this). 42610197Seric ** Truncate our transcript -- the mail has gotten 42710197Seric ** to us successfully, and if we have 42810197Seric ** to mail this back, it will be easier 42910197Seric ** on the reader. 4308238Seric ** Then send to everyone. 4318238Seric ** Finally give a reply code. If an error has 4328238Seric ** already been given, don't mail a 4338238Seric ** message back. 4349339Seric ** We goose error returns by clearing error bit. 4358238Seric */ 4368238Seric 43724943Seric SmtpPhase = "delivery"; 43855012Seric if (e->e_nrcpts != 1) 4399378Seric { 4409378Seric HoldErrs = TRUE; 44116886Seric ErrorMode = EM_MAIL; 4429378Seric } 44355012Seric e->e_flags &= ~EF_FATALERRS; 44455012Seric e->e_xfp = freopen(queuename(e, 'x'), "w", e->e_xfp); 4454976Seric 4464976Seric /* send to all recipients */ 44755012Seric sendall(e, SM_DEFAULT); 44855012Seric e->e_to = NULL; 4494976Seric 45023516Seric /* save statistics */ 45155012Seric markstats(e, (ADDRESS *) NULL); 45223516Seric 4538238Seric /* issue success if appropriate and reset */ 4548238Seric if (Errors == 0 || HoldErrs) 45558151Seric message("250 Ok"); 4568238Seric else 45755012Seric e->e_flags &= ~EF_FATALERRS; 4589339Seric 4599339Seric /* if in a child, pop back to our parent */ 4609339Seric if (InChild) 4619339Seric finis(); 46224943Seric 46324943Seric /* clean up a bit */ 46458109Seric gotmail = FALSE; 46555012Seric dropenvelope(e); 46658179Seric CurEnv = e = newenvelope(e, CurEnv); 46755012Seric e->e_flags = BlankEnvelope.e_flags; 4684549Seric break; 4694549Seric 4704549Seric case CMDRSET: /* rset -- reset state */ 47158151Seric message("250 Reset state"); 4729339Seric if (InChild) 4739339Seric finis(); 47458109Seric 47558109Seric /* clean up a bit */ 47658109Seric gotmail = FALSE; 47758109Seric dropenvelope(e); 47858179Seric CurEnv = e = newenvelope(e, CurEnv); 4799339Seric break; 4804549Seric 4814549Seric case CMDVRFY: /* vrfy -- verify address */ 48258092Seric case CMDEXPN: /* expn -- expand address */ 48358092Seric vrfy = c->cmdcode == CMDVRFY; 48458092Seric if (bitset(vrfy ? PRIV_NOVRFY : PRIV_NOEXPN, 48558092Seric PrivacyFlags)) 48658082Seric { 48758151Seric message("502 That's none of your business"); 48858082Seric break; 48958082Seric } 49058082Seric else if (!gothello && 49158092Seric bitset(vrfy ? PRIV_NEEDVRFYHELO : PRIV_NEEDEXPNHELO, 49258092Seric PrivacyFlags)) 49358082Seric { 49458151Seric message("503 I demand that you introduce yourself first"); 49558082Seric break; 49658082Seric } 49758092Seric if (runinchild(vrfy ? "SMTP-VRFY" : "SMTP-EXPN", e) > 0) 4989339Seric break; 49925050Seric setproctitle("%s: %s", CurHostName, inp); 50055173Seric #ifdef LOG 50158020Seric if (LogLevel > 5) 50255173Seric syslog(LOG_INFO, "%s: %s", CurHostName, inp); 50355173Seric #endif 5045003Seric vrfyqueue = NULL; 5057762Seric QuickAbort = TRUE; 50658092Seric if (vrfy) 50758092Seric e->e_flags |= EF_VRFYONLY; 50858082Seric (void) sendtolist(p, (ADDRESS *) NULL, &vrfyqueue, e); 5097762Seric if (Errors != 0) 5109339Seric { 5119339Seric if (InChild) 5129339Seric finis(); 5137762Seric break; 5149339Seric } 5155003Seric while (vrfyqueue != NULL) 5165003Seric { 5175003Seric register ADDRESS *a = vrfyqueue->q_next; 5185003Seric char *code; 5195003Seric 5207685Seric while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags)) 5215003Seric a = a->q_next; 5225003Seric 5237685Seric if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags)) 52458151Seric printvrfyaddr(vrfyqueue, a == NULL); 5255003Seric else if (a == NULL) 52658151Seric message("554 Self destructive alias loop"); 5275003Seric vrfyqueue = a; 5285003Seric } 5299339Seric if (InChild) 5309339Seric finis(); 5314549Seric break; 5324549Seric 5334549Seric case CMDHELP: /* help -- give user info */ 5344577Seric help(p); 5354549Seric break; 5364549Seric 5374549Seric case CMDNOOP: /* noop -- do nothing */ 53858151Seric message("200 OK"); 5394549Seric break; 5404549Seric 5414549Seric case CMDQUIT: /* quit -- leave mail */ 54258151Seric message("221 %s closing connection", MyHostName); 5439339Seric if (InChild) 5449339Seric ExitStat = EX_QUIT; 5454549Seric finis(); 5464549Seric 5478544Seric case CMDVERB: /* set verbose mode */ 5488544Seric Verbose = TRUE; 54925025Seric SendMode = SM_DELIVER; 55058151Seric message("200 Verbose mode"); 5518544Seric break; 5528544Seric 5539314Seric case CMDONEX: /* doing one transaction only */ 5549378Seric OneXact = TRUE; 55558151Seric message("200 Only one transaction"); 5569314Seric break; 5579314Seric 55836230Skarels # ifdef SMTPDEBUG 5599339Seric case CMDDBGQSHOW: /* show queues */ 5606907Seric printf("Send Queue="); 56155012Seric printaddr(e->e_sendqueue, TRUE); 5625003Seric break; 5637275Seric 5647275Seric case CMDDBGDEBUG: /* set debug mode */ 5657676Seric tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); 5667676Seric tTflag(p); 56758151Seric message("200 Debug set"); 5687275Seric break; 5697275Seric 57036230Skarels # else /* not SMTPDEBUG */ 57124945Seric 57236230Skarels case CMDDBGQSHOW: /* show queues */ 57336230Skarels case CMDDBGDEBUG: /* set debug mode */ 57436233Skarels # ifdef LOG 57558308Seric if (LogLevel > 0) 57636230Skarels syslog(LOG_NOTICE, 57758020Seric "\"%s\" command from %s (%s)", 57836230Skarels c->cmdname, RealHostName, 57936230Skarels inet_ntoa(RealHostAddr.sin_addr)); 58036233Skarels # endif 58136230Skarels /* FALL THROUGH */ 58236230Skarels # endif /* SMTPDEBUG */ 58336230Skarels 5844549Seric case CMDERROR: /* unknown command */ 58558151Seric message("500 Command unrecognized"); 5864549Seric break; 5874549Seric 5884549Seric default: 58936230Skarels errno = 0; 59058151Seric syserr("500 smtp: unknown code %d", c->cmdcode); 5914549Seric break; 5924549Seric } 5934549Seric } 5944549Seric } 5954549Seric /* 5964549Seric ** SKIPWORD -- skip a fixed word. 5974549Seric ** 5984549Seric ** Parameters: 5994549Seric ** p -- place to start looking. 6004549Seric ** w -- word to skip. 6014549Seric ** 6024549Seric ** Returns: 6034549Seric ** p following w. 6044549Seric ** NULL on error. 6054549Seric ** 6064549Seric ** Side Effects: 6074549Seric ** clobbers the p data area. 6084549Seric */ 6094549Seric 6104549Seric static char * 6114549Seric skipword(p, w) 6124549Seric register char *p; 6134549Seric char *w; 6144549Seric { 6154549Seric register char *q; 6164549Seric 6174549Seric /* find beginning of word */ 61858050Seric while (isascii(*p) && isspace(*p)) 6194549Seric p++; 6204549Seric q = p; 6214549Seric 6224549Seric /* find end of word */ 62358050Seric while (*p != '\0' && *p != ':' && !(isascii(*p) && isspace(*p))) 6244549Seric p++; 62558050Seric while (isascii(*p) && isspace(*p)) 6264549Seric *p++ = '\0'; 6274549Seric if (*p != ':') 6284549Seric { 6294549Seric syntax: 63058151Seric message("501 Syntax error"); 6314549Seric Errors++; 6324549Seric return (NULL); 6334549Seric } 6344549Seric *p++ = '\0'; 63558050Seric while (isascii(*p) && isspace(*p)) 6364549Seric p++; 6374549Seric 6384549Seric /* see if the input word matches desired word */ 63933725Sbostic if (strcasecmp(q, w)) 6404549Seric goto syntax; 6414549Seric 6424549Seric return (p); 6434549Seric } 6444577Seric /* 64558151Seric ** PRINTVRFYADDR -- print an entry in the verify queue 64658151Seric ** 64758151Seric ** Parameters: 64858151Seric ** a -- the address to print 64958151Seric ** last -- set if this is the last one. 65058151Seric ** 65158151Seric ** Returns: 65258151Seric ** none. 65358151Seric ** 65458151Seric ** Side Effects: 65558151Seric ** Prints the appropriate 250 codes. 65658151Seric */ 65758151Seric 65858151Seric printvrfyaddr(a, last) 65958151Seric register ADDRESS *a; 66058151Seric bool last; 66158151Seric { 66258151Seric char fmtbuf[20]; 66358151Seric 66458151Seric strcpy(fmtbuf, "250"); 66558151Seric fmtbuf[3] = last ? ' ' : '-'; 66658151Seric 66758151Seric if (strchr(a->q_paddr, '<') != NULL) 66858151Seric strcpy(&fmtbuf[4], "%s"); 66958151Seric else if (a->q_fullname == NULL) 67058151Seric strcpy(&fmtbuf[4], "<%s>"); 67158151Seric else 67258151Seric { 67358151Seric strcpy(&fmtbuf[4], "%s <%s>"); 67458151Seric message(fmtbuf, a->q_fullname, a->q_paddr); 67558151Seric return; 67658151Seric } 67758151Seric message(fmtbuf, a->q_paddr); 67858151Seric } 67958151Seric /* 6804577Seric ** HELP -- implement the HELP command. 6814577Seric ** 6824577Seric ** Parameters: 6834577Seric ** topic -- the topic we want help for. 6844577Seric ** 6854577Seric ** Returns: 6864577Seric ** none. 6874577Seric ** 6884577Seric ** Side Effects: 6894577Seric ** outputs the help file to message output. 6904577Seric */ 6914577Seric 6924577Seric help(topic) 6934577Seric char *topic; 6944577Seric { 6954577Seric register FILE *hf; 6964577Seric int len; 6974577Seric char buf[MAXLINE]; 6984577Seric bool noinfo; 6994577Seric 7008269Seric if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL) 7014577Seric { 7024577Seric /* no help */ 70311931Seric errno = 0; 70458151Seric message("502 HELP not implemented"); 7054577Seric return; 7064577Seric } 7074577Seric 70849669Seric if (topic == NULL || *topic == '\0') 70949669Seric topic = "smtp"; 71049669Seric else 71149669Seric makelower(topic); 71249669Seric 7134577Seric len = strlen(topic); 7144577Seric noinfo = TRUE; 7154577Seric 7164577Seric while (fgets(buf, sizeof buf, hf) != NULL) 7174577Seric { 7184577Seric if (strncmp(buf, topic, len) == 0) 7194577Seric { 7204577Seric register char *p; 7214577Seric 72256795Seric p = strchr(buf, '\t'); 7234577Seric if (p == NULL) 7244577Seric p = buf; 7254577Seric else 7264577Seric p++; 7274577Seric fixcrlf(p, TRUE); 72858151Seric message("214-%s", p); 7294577Seric noinfo = FALSE; 7304577Seric } 7314577Seric } 7324577Seric 7334577Seric if (noinfo) 73458151Seric message("504 HELP topic unknown"); 7354577Seric else 73658151Seric message("214 End of HELP info"); 7374628Seric (void) fclose(hf); 7384577Seric } 7398544Seric /* 7409339Seric ** RUNINCHILD -- return twice -- once in the child, then in the parent again 7419339Seric ** 7429339Seric ** Parameters: 7439339Seric ** label -- a string used in error messages 7449339Seric ** 7459339Seric ** Returns: 7469339Seric ** zero in the child 7479339Seric ** one in the parent 7489339Seric ** 7499339Seric ** Side Effects: 7509339Seric ** none. 7519339Seric */ 7528544Seric 75355012Seric runinchild(label, e) 7549339Seric char *label; 75555012Seric register ENVELOPE *e; 7569339Seric { 7579339Seric int childpid; 7589339Seric 75916158Seric if (!OneXact) 7609339Seric { 76116158Seric childpid = dofork(); 76216158Seric if (childpid < 0) 76316158Seric { 76416158Seric syserr("%s: cannot fork", label); 76516158Seric return (1); 76616158Seric } 76716158Seric if (childpid > 0) 76816158Seric { 76916158Seric auto int st; 7709339Seric 77116158Seric /* parent -- wait for child to complete */ 77216158Seric st = waitfor(childpid); 77316158Seric if (st == -1) 77416158Seric syserr("%s: lost child", label); 7759339Seric 77616158Seric /* if we exited on a QUIT command, complete the process */ 77716158Seric if (st == (EX_QUIT << 8)) 77816158Seric finis(); 7799339Seric 78016158Seric return (1); 78116158Seric } 78216158Seric else 78316158Seric { 78416158Seric /* child */ 78516158Seric InChild = TRUE; 78625050Seric QuickAbort = FALSE; 78755012Seric clearenvelope(e, FALSE); 78816158Seric } 7899339Seric } 79015256Seric 79116158Seric /* open alias database */ 79255012Seric initaliases(AliasFile, FALSE, e); 79316158Seric 79416158Seric return (0); 7959339Seric } 7969339Seric 79756795Seric # endif /* SMTP */ 798