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*58755Seric static char sccsid[] = "@(#)srvrsmtp.c 6.28 (Berkeley) 03/19/93 (with SMTP)"; 1433731Sbostic #else 15*58755Seric static char sccsid[] = "@(#)srvrsmtp.c 6.28 (Berkeley) 03/19/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 */ 10758333Seric long msize; /* approximate maximum message size */ 10858333Seric auto char *delimptr; 10958714Seric char *id; 1108544Seric char inp[MAXLINE]; 11157232Seric char cmdbuf[MAXLINE]; 11258512Seric char hostbuf[MAXNAME]; 1137124Seric extern char Version[]; 11411151Seric extern char *macvalue(); 11512612Seric extern ADDRESS *recipient(); 11624943Seric extern ENVELOPE BlankEnvelope; 11724943Seric extern ENVELOPE *newenvelope(); 118*58755Seric extern char *anynet_ntoa(); 1194549Seric 1207363Seric if (OutChannel != stdout) 1217363Seric { 1227363Seric /* arrange for debugging output to go to remote host */ 1237363Seric (void) close(1); 1247363Seric (void) dup(fileno(OutChannel)); 1257363Seric } 12655012Seric settime(e); 12757642Seric CurHostName = RealHostName; 12857642Seric setproctitle("srvrsmtp %s", CurHostName); 12958050Seric expand("\201e", inp, &inp[sizeof inp], e); 13058151Seric message("220 %s", inp); 13124943Seric SmtpPhase = "startup"; 13230448Seric sendinghost = NULL; 13358330Seric protocol = NULL; 13458082Seric gothello = FALSE; 13558330Seric gotmail = FALSE; 1364549Seric for (;;) 1374549Seric { 13812612Seric /* arrange for backout */ 13912612Seric if (setjmp(TopFrame) > 0 && InChild) 14012612Seric finis(); 14112612Seric QuickAbort = FALSE; 14212612Seric HoldErrs = FALSE; 14351951Seric LogUsrErrs = FALSE; 14458092Seric e->e_flags &= ~EF_VRFYONLY; 14512612Seric 1467356Seric /* setup for the read */ 14755012Seric e->e_to = NULL; 1484577Seric Errors = 0; 1497275Seric (void) fflush(stdout); 1507356Seric 1517356Seric /* read the input line */ 15258109Seric p = sfgets(inp, sizeof inp, InChannel, TimeOuts.to_nextcommand); 1537356Seric 1547685Seric /* handle errors */ 1557356Seric if (p == NULL) 1567356Seric { 1574549Seric /* end of file, just die */ 15858151Seric message("421 %s Lost input channel from %s", 15925050Seric MyHostName, CurHostName); 16055464Seric #ifdef LOG 16158020Seric if (LogLevel > 1) 16255464Seric syslog(LOG_NOTICE, "lost input channel from %s", 16355464Seric CurHostName); 16455464Seric #endif 16558069Seric if (InChild) 16658069Seric ExitStat = EX_QUIT; 1674549Seric finis(); 1684549Seric } 1694549Seric 1704549Seric /* clean up end of line */ 1714558Seric fixcrlf(inp, TRUE); 1724549Seric 1734713Seric /* echo command to transcript */ 17455012Seric if (e->e_xfp != NULL) 17555012Seric fprintf(e->e_xfp, "<<< %s\n", inp); 1764713Seric 1774549Seric /* break off command */ 17858050Seric for (p = inp; isascii(*p) && isspace(*p); p++) 1794549Seric continue; 18057232Seric cmd = cmdbuf; 18158050Seric while (*p != '\0' && 18258050Seric !(isascii(*p) && isspace(*p)) && 18358050Seric cmd < &cmdbuf[sizeof cmdbuf - 2]) 18424981Seric *cmd++ = *p++; 18524981Seric *cmd = '\0'; 1864549Seric 18725691Seric /* throw away leading whitespace */ 18858050Seric while (isascii(*p) && isspace(*p)) 18925691Seric p++; 19025691Seric 1914549Seric /* decode command */ 1924549Seric for (c = CmdTab; c->cmdname != NULL; c++) 1934549Seric { 19433725Sbostic if (!strcasecmp(c->cmdname, cmdbuf)) 1954549Seric break; 1964549Seric } 1974549Seric 19851954Seric /* reset errors */ 19951954Seric errno = 0; 20051954Seric 2014549Seric /* process command */ 2024549Seric switch (c->cmdcode) 2034549Seric { 2044976Seric case CMDHELO: /* hello -- introduce yourself */ 20558323Seric case CMDEHLO: /* extended hello */ 20658323Seric if (c->cmdcode == CMDEHLO) 20758323Seric { 20858323Seric protocol = "ESMTP"; 20958323Seric SmtpPhase = "EHLO"; 21058323Seric } 21158323Seric else 21258323Seric { 21358323Seric protocol = "SMTP"; 21458323Seric SmtpPhase = "HELO"; 21558323Seric } 21625050Seric setproctitle("%s: %s", CurHostName, inp); 21758109Seric if (strcasecmp(p, MyHostName) == 0) 21814877Seric { 21936230Skarels /* 22058109Seric ** Didn't know about alias or MX, 22158109Seric ** or connected to an echo server 22258109Seric */ 22358109Seric 22458151Seric message("553 %s config error: mail loops back to myself", 22547570Seric MyHostName); 22614877Seric break; 22714877Seric } 22858512Seric (void) strcpy(hostbuf, p); 22958512Seric (void) strcat(hostbuf, " ("); 230*58755Seric (void) strcat(hostbuf, anynet_ntoa(&RealHostAddr)); 23158308Seric if (strcasecmp(p, RealHostName) != 0) 23211146Seric { 23358512Seric (void) strcat(hostbuf, "; "); 23458512Seric (void) strcat(hostbuf, RealHostName); 23511146Seric } 23658512Seric (void) strcat(hostbuf, ")"); 23758512Seric sendinghost = newstr(hostbuf); 23858323Seric 23958323Seric /* send ext. message -- old systems must ignore */ 24058323Seric message("250-%s Hello %s, pleased to meet you", 24136230Skarels MyHostName, sendinghost); 24258323Seric if (!bitset(PRIV_NOEXPN, PrivacyFlags)) 24358323Seric message("250-EXPN"); 24458338Seric message("250-SIZE"); 24558323Seric message("250 HELP"); 24658082Seric gothello = TRUE; 2474976Seric break; 2484976Seric 2494549Seric case CMDMAIL: /* mail -- designate sender */ 25024943Seric SmtpPhase = "MAIL"; 25124943Seric 25211151Seric /* force a sending host even if no HELO given */ 25358064Seric if (sendinghost == NULL && macvalue('s', e) == NULL) 25430448Seric sendinghost = RealHostName; 25511151Seric 2569314Seric /* check for validity of this command */ 25758082Seric if (!gothello && bitset(PRIV_NEEDMAILHELO, PrivacyFlags)) 25858082Seric { 25958151Seric message("503 Polite people say HELO first"); 26058082Seric break; 26158082Seric } 26258109Seric if (gotmail) 2634558Seric { 26458151Seric message("503 Sender already specified"); 2654558Seric break; 2664558Seric } 2679339Seric if (InChild) 2689339Seric { 26936230Skarels errno = 0; 27058151Seric syserr("503 Nested MAIL command: MAIL %s", p); 27158069Seric finis(); 2729339Seric } 2739339Seric 2749339Seric /* fork a subprocess to process this command */ 27555012Seric if (runinchild("SMTP-MAIL", e) > 0) 2769339Seric break; 27758064Seric if (sendinghost != NULL) 27858064Seric define('s', sendinghost, e); 27958323Seric if (protocol == NULL) 28058323Seric protocol = "SMTP"; 28158323Seric define('r', protocol, e); 28255012Seric initsys(e); 28357389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 2849339Seric 2859339Seric /* child -- go do the processing */ 2864549Seric p = skipword(p, "from"); 2874549Seric if (p == NULL) 2884549Seric break; 28957977Seric if (setjmp(TopFrame) > 0) 29058147Seric { 29158147Seric /* this failed -- undo work */ 29258147Seric if (InChild) 29358147Seric finis(); 29457977Seric break; 29558147Seric } 29657977Seric QuickAbort = TRUE; 29758333Seric 29858333Seric /* must parse sender first */ 29958333Seric delimptr = NULL; 30058704Seric setsender(p, e, &delimptr, FALSE); 30158333Seric p = delimptr; 30258333Seric if (p != NULL && *p != '\0') 30358333Seric *p++ = '\0'; 30458333Seric 30558333Seric /* now parse ESMTP arguments */ 30658333Seric msize = 0; 30758333Seric for (; p != NULL && *p != '\0'; p++) 30858333Seric { 30958333Seric char *kp; 31058333Seric char *vp; 31158333Seric 31258333Seric /* locate the beginning of the keyword */ 31358333Seric while (isascii(*p) && isspace(*p)) 31458333Seric p++; 31558333Seric if (*p == '\0') 31658333Seric break; 31758333Seric kp = p; 31858333Seric 31958333Seric /* skip to the value portion */ 32058333Seric while (isascii(*p) && isalnum(*p) || *p == '-') 32158333Seric p++; 32258333Seric if (*p == '=') 32358333Seric { 32458333Seric *p++ = '\0'; 32558333Seric vp = p; 32658333Seric 32758333Seric /* skip to the end of the value */ 32858333Seric while (*p != '\0' && *p != ' ' && 32958333Seric !(isascii(*p) && iscntrl(*p)) && 33058333Seric *p != '=') 33158333Seric p++; 33258333Seric } 33358333Seric 33458333Seric if (*p != '\0') 33558333Seric *p++ = '\0'; 33658333Seric 33758333Seric if (tTd(19, 1)) 33858333Seric printf("MAIL: got arg %s=%s\n", kp, 33958333Seric vp == NULL ? "<null>" : vp); 34058333Seric 34158333Seric if (strcasecmp(kp, "size") == 0) 34258333Seric { 34358333Seric if (kp == NULL) 34458333Seric { 34558333Seric usrerr("501 SIZE requires a value"); 34658333Seric /* NOTREACHED */ 34758333Seric } 34858333Seric msize = atol(vp); 34958333Seric } 35058333Seric else 35158333Seric { 35258333Seric usrerr("501 %s parameter unrecognized", kp); 35358333Seric /* NOTREACHED */ 35458333Seric } 35558333Seric } 35658333Seric 35758333Seric if (!enoughspace(msize)) 35858333Seric { 35958333Seric message("452 Insufficient disk space; try again later"); 36058333Seric break; 36158333Seric } 36258151Seric message("250 Sender ok"); 36358147Seric gotmail = TRUE; 3644549Seric break; 3654549Seric 3664976Seric case CMDRCPT: /* rcpt -- designate recipient */ 36724943Seric SmtpPhase = "RCPT"; 36857389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 36912612Seric if (setjmp(TopFrame) > 0) 37014785Seric { 37155012Seric e->e_flags &= ~EF_FATALERRS; 37212612Seric break; 37314785Seric } 37412612Seric QuickAbort = TRUE; 37551951Seric LogUsrErrs = TRUE; 37658093Seric 37758093Seric /* optimization -- if queueing, don't expand aliases */ 37858734Seric if (e->e_sendmode == SM_QUEUE) 37958093Seric e->e_flags |= EF_VRFYONLY; 38058093Seric 3814549Seric p = skipword(p, "to"); 3824549Seric if (p == NULL) 3834549Seric break; 38458333Seric a = parseaddr(p, (ADDRESS *) NULL, 1, ' ', NULL, e); 38512612Seric if (a == NULL) 38612612Seric break; 38716886Seric a->q_flags |= QPRIMARY; 38855012Seric a = recipient(a, &e->e_sendqueue, e); 38912612Seric if (Errors != 0) 39012612Seric break; 39112612Seric 39212612Seric /* no errors during parsing, but might be a duplicate */ 39355012Seric e->e_to = p; 39412612Seric if (!bitset(QBADADDR, a->q_flags)) 39558151Seric message("250 Recipient ok"); 39612612Seric else 3974549Seric { 39812612Seric /* punt -- should keep message in ADDRESS.... */ 39958151Seric message("550 Addressee unknown"); 4004549Seric } 40155012Seric e->e_to = NULL; 4024549Seric break; 4034549Seric 4044549Seric case CMDDATA: /* data -- text of mail */ 40524943Seric SmtpPhase = "DATA"; 40658109Seric if (!gotmail) 4074549Seric { 40858151Seric message("503 Need MAIL command"); 4094976Seric break; 4104549Seric } 41155012Seric else if (e->e_nrcpts <= 0) 4124549Seric { 41358151Seric message("503 Need RCPT (recipient)"); 4144976Seric break; 4154549Seric } 4164976Seric 4174976Seric /* collect the text of the message */ 41824943Seric SmtpPhase = "collect"; 41957389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 42055012Seric collect(TRUE, e); 4214976Seric if (Errors != 0) 4224976Seric break; 4234976Seric 4248238Seric /* 4258238Seric ** Arrange to send to everyone. 4268238Seric ** If sending to multiple people, mail back 4278238Seric ** errors rather than reporting directly. 4288238Seric ** In any case, don't mail back errors for 4298238Seric ** anything that has happened up to 4308238Seric ** now (the other end will do this). 43110197Seric ** Truncate our transcript -- the mail has gotten 43210197Seric ** to us successfully, and if we have 43310197Seric ** to mail this back, it will be easier 43410197Seric ** on the reader. 4358238Seric ** Then send to everyone. 4368238Seric ** Finally give a reply code. If an error has 4378238Seric ** already been given, don't mail a 4388238Seric ** message back. 4399339Seric ** We goose error returns by clearing error bit. 4408238Seric */ 4418238Seric 44224943Seric SmtpPhase = "delivery"; 44355012Seric if (e->e_nrcpts != 1) 4449378Seric { 4459378Seric HoldErrs = TRUE; 44658734Seric e->e_errormode = EM_MAIL; 4479378Seric } 44855012Seric e->e_flags &= ~EF_FATALERRS; 44955012Seric e->e_xfp = freopen(queuename(e, 'x'), "w", e->e_xfp); 45058714Seric id = e->e_id; 4514976Seric 4524976Seric /* send to all recipients */ 45355012Seric sendall(e, SM_DEFAULT); 45455012Seric e->e_to = NULL; 4554976Seric 45623516Seric /* save statistics */ 45755012Seric markstats(e, (ADDRESS *) NULL); 45823516Seric 4598238Seric /* issue success if appropriate and reset */ 4608238Seric if (Errors == 0 || HoldErrs) 46158714Seric message("250 %s OK", id); 4628238Seric else 46355012Seric e->e_flags &= ~EF_FATALERRS; 4649339Seric 4659339Seric /* if in a child, pop back to our parent */ 4669339Seric if (InChild) 4679339Seric finis(); 46824943Seric 46924943Seric /* clean up a bit */ 47058109Seric gotmail = FALSE; 47155012Seric dropenvelope(e); 47258179Seric CurEnv = e = newenvelope(e, CurEnv); 47355012Seric e->e_flags = BlankEnvelope.e_flags; 4744549Seric break; 4754549Seric 4764549Seric case CMDRSET: /* rset -- reset state */ 47758151Seric message("250 Reset state"); 4789339Seric if (InChild) 4799339Seric finis(); 48058109Seric 48158109Seric /* clean up a bit */ 48258109Seric gotmail = FALSE; 48358109Seric dropenvelope(e); 48458179Seric CurEnv = e = newenvelope(e, CurEnv); 4859339Seric break; 4864549Seric 4874549Seric case CMDVRFY: /* vrfy -- verify address */ 48858092Seric case CMDEXPN: /* expn -- expand address */ 48958092Seric vrfy = c->cmdcode == CMDVRFY; 49058092Seric if (bitset(vrfy ? PRIV_NOVRFY : PRIV_NOEXPN, 49158092Seric PrivacyFlags)) 49258082Seric { 49358412Seric if (vrfy) 49458412Seric message("252 Who's to say?"); 49558412Seric else 49658412Seric message("502 That's none of your business"); 49758082Seric break; 49858082Seric } 49958082Seric else if (!gothello && 50058092Seric bitset(vrfy ? PRIV_NEEDVRFYHELO : PRIV_NEEDEXPNHELO, 50158092Seric PrivacyFlags)) 50258082Seric { 50358151Seric message("503 I demand that you introduce yourself first"); 50458082Seric break; 50558082Seric } 50658092Seric if (runinchild(vrfy ? "SMTP-VRFY" : "SMTP-EXPN", e) > 0) 5079339Seric break; 50825050Seric setproctitle("%s: %s", CurHostName, inp); 50955173Seric #ifdef LOG 51058020Seric if (LogLevel > 5) 51155173Seric syslog(LOG_INFO, "%s: %s", CurHostName, inp); 51255173Seric #endif 5135003Seric vrfyqueue = NULL; 5147762Seric QuickAbort = TRUE; 51558092Seric if (vrfy) 51658092Seric e->e_flags |= EF_VRFYONLY; 51758082Seric (void) sendtolist(p, (ADDRESS *) NULL, &vrfyqueue, e); 5187762Seric if (Errors != 0) 5199339Seric { 5209339Seric if (InChild) 5219339Seric finis(); 5227762Seric break; 5239339Seric } 5245003Seric while (vrfyqueue != NULL) 5255003Seric { 5265003Seric register ADDRESS *a = vrfyqueue->q_next; 5275003Seric char *code; 5285003Seric 5297685Seric while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags)) 5305003Seric a = a->q_next; 5315003Seric 5327685Seric if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags)) 53358151Seric printvrfyaddr(vrfyqueue, a == NULL); 5345003Seric else if (a == NULL) 53558151Seric message("554 Self destructive alias loop"); 5365003Seric vrfyqueue = a; 5375003Seric } 5389339Seric if (InChild) 5399339Seric finis(); 5404549Seric break; 5414549Seric 5424549Seric case CMDHELP: /* help -- give user info */ 5434577Seric help(p); 5444549Seric break; 5454549Seric 5464549Seric case CMDNOOP: /* noop -- do nothing */ 54758151Seric message("200 OK"); 5484549Seric break; 5494549Seric 5504549Seric case CMDQUIT: /* quit -- leave mail */ 55158151Seric message("221 %s closing connection", MyHostName); 5529339Seric if (InChild) 5539339Seric ExitStat = EX_QUIT; 5544549Seric finis(); 5554549Seric 5568544Seric case CMDVERB: /* set verbose mode */ 5578544Seric Verbose = TRUE; 55858734Seric e->e_sendmode = SM_DELIVER; 55958151Seric message("200 Verbose mode"); 5608544Seric break; 5618544Seric 5629314Seric case CMDONEX: /* doing one transaction only */ 5639378Seric OneXact = TRUE; 56458151Seric message("200 Only one transaction"); 5659314Seric break; 5669314Seric 56736230Skarels # ifdef SMTPDEBUG 5689339Seric case CMDDBGQSHOW: /* show queues */ 5696907Seric printf("Send Queue="); 57055012Seric printaddr(e->e_sendqueue, TRUE); 5715003Seric break; 5727275Seric 5737275Seric case CMDDBGDEBUG: /* set debug mode */ 5747676Seric tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); 5757676Seric tTflag(p); 57658151Seric message("200 Debug set"); 5777275Seric break; 5787275Seric 57936230Skarels # else /* not SMTPDEBUG */ 58024945Seric 58136230Skarels case CMDDBGQSHOW: /* show queues */ 58236230Skarels case CMDDBGDEBUG: /* set debug mode */ 58336233Skarels # ifdef LOG 58458308Seric if (LogLevel > 0) 58536230Skarels syslog(LOG_NOTICE, 58658020Seric "\"%s\" command from %s (%s)", 58736230Skarels c->cmdname, RealHostName, 588*58755Seric anynet_ntoa(&RealHostAddr)); 58936233Skarels # endif 59036230Skarels /* FALL THROUGH */ 59136230Skarels # endif /* SMTPDEBUG */ 59236230Skarels 5934549Seric case CMDERROR: /* unknown command */ 59458151Seric message("500 Command unrecognized"); 5954549Seric break; 5964549Seric 5974549Seric default: 59836230Skarels errno = 0; 59958151Seric syserr("500 smtp: unknown code %d", c->cmdcode); 6004549Seric break; 6014549Seric } 6024549Seric } 6034549Seric } 6044549Seric /* 6054549Seric ** SKIPWORD -- skip a fixed word. 6064549Seric ** 6074549Seric ** Parameters: 6084549Seric ** p -- place to start looking. 6094549Seric ** w -- word to skip. 6104549Seric ** 6114549Seric ** Returns: 6124549Seric ** p following w. 6134549Seric ** NULL on error. 6144549Seric ** 6154549Seric ** Side Effects: 6164549Seric ** clobbers the p data area. 6174549Seric */ 6184549Seric 6194549Seric static char * 6204549Seric skipword(p, w) 6214549Seric register char *p; 6224549Seric char *w; 6234549Seric { 6244549Seric register char *q; 6254549Seric 6264549Seric /* find beginning of word */ 62758050Seric while (isascii(*p) && isspace(*p)) 6284549Seric p++; 6294549Seric q = p; 6304549Seric 6314549Seric /* find end of word */ 63258050Seric while (*p != '\0' && *p != ':' && !(isascii(*p) && isspace(*p))) 6334549Seric p++; 63458050Seric while (isascii(*p) && isspace(*p)) 6354549Seric *p++ = '\0'; 6364549Seric if (*p != ':') 6374549Seric { 6384549Seric syntax: 63958151Seric message("501 Syntax error"); 6404549Seric Errors++; 6414549Seric return (NULL); 6424549Seric } 6434549Seric *p++ = '\0'; 64458050Seric while (isascii(*p) && isspace(*p)) 6454549Seric p++; 6464549Seric 6474549Seric /* see if the input word matches desired word */ 64833725Sbostic if (strcasecmp(q, w)) 6494549Seric goto syntax; 6504549Seric 6514549Seric return (p); 6524549Seric } 6534577Seric /* 65458151Seric ** PRINTVRFYADDR -- print an entry in the verify queue 65558151Seric ** 65658151Seric ** Parameters: 65758151Seric ** a -- the address to print 65858151Seric ** last -- set if this is the last one. 65958151Seric ** 66058151Seric ** Returns: 66158151Seric ** none. 66258151Seric ** 66358151Seric ** Side Effects: 66458151Seric ** Prints the appropriate 250 codes. 66558151Seric */ 66658151Seric 66758151Seric printvrfyaddr(a, last) 66858151Seric register ADDRESS *a; 66958151Seric bool last; 67058151Seric { 67158151Seric char fmtbuf[20]; 67258151Seric 67358151Seric strcpy(fmtbuf, "250"); 67458151Seric fmtbuf[3] = last ? ' ' : '-'; 67558151Seric 67658151Seric if (strchr(a->q_paddr, '<') != NULL) 67758151Seric strcpy(&fmtbuf[4], "%s"); 67858151Seric else if (a->q_fullname == NULL) 67958151Seric strcpy(&fmtbuf[4], "<%s>"); 68058151Seric else 68158151Seric { 68258151Seric strcpy(&fmtbuf[4], "%s <%s>"); 68358151Seric message(fmtbuf, a->q_fullname, a->q_paddr); 68458151Seric return; 68558151Seric } 68658151Seric message(fmtbuf, a->q_paddr); 68758151Seric } 68858151Seric /* 6894577Seric ** HELP -- implement the HELP command. 6904577Seric ** 6914577Seric ** Parameters: 6924577Seric ** topic -- the topic we want help for. 6934577Seric ** 6944577Seric ** Returns: 6954577Seric ** none. 6964577Seric ** 6974577Seric ** Side Effects: 6984577Seric ** outputs the help file to message output. 6994577Seric */ 7004577Seric 7014577Seric help(topic) 7024577Seric char *topic; 7034577Seric { 7044577Seric register FILE *hf; 7054577Seric int len; 7064577Seric char buf[MAXLINE]; 7074577Seric bool noinfo; 7084577Seric 7098269Seric if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL) 7104577Seric { 7114577Seric /* no help */ 71211931Seric errno = 0; 71358151Seric message("502 HELP not implemented"); 7144577Seric return; 7154577Seric } 7164577Seric 71749669Seric if (topic == NULL || *topic == '\0') 71849669Seric topic = "smtp"; 71949669Seric else 72049669Seric makelower(topic); 72149669Seric 7224577Seric len = strlen(topic); 7234577Seric noinfo = TRUE; 7244577Seric 7254577Seric while (fgets(buf, sizeof buf, hf) != NULL) 7264577Seric { 7274577Seric if (strncmp(buf, topic, len) == 0) 7284577Seric { 7294577Seric register char *p; 7304577Seric 73156795Seric p = strchr(buf, '\t'); 7324577Seric if (p == NULL) 7334577Seric p = buf; 7344577Seric else 7354577Seric p++; 7364577Seric fixcrlf(p, TRUE); 73758151Seric message("214-%s", p); 7384577Seric noinfo = FALSE; 7394577Seric } 7404577Seric } 7414577Seric 7424577Seric if (noinfo) 74358151Seric message("504 HELP topic unknown"); 7444577Seric else 74558151Seric message("214 End of HELP info"); 7464628Seric (void) fclose(hf); 7474577Seric } 7488544Seric /* 7499339Seric ** RUNINCHILD -- return twice -- once in the child, then in the parent again 7509339Seric ** 7519339Seric ** Parameters: 7529339Seric ** label -- a string used in error messages 7539339Seric ** 7549339Seric ** Returns: 7559339Seric ** zero in the child 7569339Seric ** one in the parent 7579339Seric ** 7589339Seric ** Side Effects: 7599339Seric ** none. 7609339Seric */ 7618544Seric 76255012Seric runinchild(label, e) 7639339Seric char *label; 76455012Seric register ENVELOPE *e; 7659339Seric { 7669339Seric int childpid; 7679339Seric 76816158Seric if (!OneXact) 7699339Seric { 77016158Seric childpid = dofork(); 77116158Seric if (childpid < 0) 77216158Seric { 77316158Seric syserr("%s: cannot fork", label); 77416158Seric return (1); 77516158Seric } 77616158Seric if (childpid > 0) 77716158Seric { 77816158Seric auto int st; 7799339Seric 78016158Seric /* parent -- wait for child to complete */ 78116158Seric st = waitfor(childpid); 78216158Seric if (st == -1) 78316158Seric syserr("%s: lost child", label); 7849339Seric 78516158Seric /* if we exited on a QUIT command, complete the process */ 78616158Seric if (st == (EX_QUIT << 8)) 78716158Seric finis(); 7889339Seric 78916158Seric return (1); 79016158Seric } 79116158Seric else 79216158Seric { 79316158Seric /* child */ 79416158Seric InChild = TRUE; 79525050Seric QuickAbort = FALSE; 79655012Seric clearenvelope(e, FALSE); 79716158Seric } 7989339Seric } 79915256Seric 80016158Seric /* open alias database */ 80155012Seric initaliases(AliasFile, FALSE, e); 80216158Seric 80316158Seric return (0); 8049339Seric } 8059339Seric 80656795Seric # endif /* SMTP */ 807