14549Seric # include "sendmail.h" 24549Seric 3*4713Seric static char SccsId[] = "@(#)srvrsmtp.c 3.7 10/31/81"; 44556Seric 54549Seric /* 64549Seric ** SMTP -- run the SMTP protocol. 74549Seric ** 84549Seric ** Parameters: 94549Seric ** none. 104549Seric ** 114549Seric ** Returns: 124549Seric ** never. 134549Seric ** 144549Seric ** Side Effects: 154549Seric ** Reads commands from the input channel and processes 164549Seric ** them. 174549Seric */ 184549Seric 194549Seric struct cmd 204549Seric { 214549Seric char *cmdname; /* command name */ 224549Seric int cmdcode; /* internal code, see below */ 234549Seric }; 244549Seric 254549Seric /* values for cmdcode */ 264549Seric # define CMDERROR 0 /* bad command */ 274549Seric # define CMDMAIL 1 /* mail -- designate sender */ 284549Seric # define CMDMRCP 2 /* mrcp -- designate recipient */ 294549Seric # define CMDDATA 3 /* data -- send message text */ 304549Seric # define CMDDOIT 4 /* doit -- actually do delivery */ 314549Seric # define CMDRSET 5 /* rset -- reset state */ 324549Seric # define CMDVRFY 6 /* vrfy -- verify address */ 334549Seric # define CMDHELP 7 /* help -- give usage info */ 344549Seric # define CMDNOOP 8 /* noop -- do nothing */ 354549Seric # define CMDQUIT 9 /* quit -- close connection and die */ 364577Seric # define CMDMRSQ 10 /* mrsq -- for old mtp compat only */ 374549Seric 384549Seric static struct cmd CmdTab[] = 394549Seric { 404549Seric "mail", CMDMAIL, 414549Seric "mrcp", CMDMRCP, 424549Seric "data", CMDDATA, 434549Seric "doit", CMDDOIT, 444549Seric "rset", CMDRSET, 454549Seric "vrfy", CMDVRFY, 464549Seric "help", CMDHELP, 474549Seric "noop", CMDNOOP, 484549Seric "quit", CMDQUIT, 494577Seric "mrsq", CMDMRSQ, 504549Seric NULL, CMDERROR, 514549Seric }; 524549Seric 534549Seric smtp() 544549Seric { 554549Seric char inp[MAXLINE]; 564549Seric register char *p; 574549Seric struct cmd *c; 584549Seric char *cmd; 594549Seric extern char *skipword(); 604549Seric extern bool sameword(); 614549Seric bool hasmail; /* mail command received */ 62*4713Seric int rcps; /* number of recipients */ 634549Seric bool hasdata; /* has mail data */ 644549Seric 65*4713Seric hasmail = hasdata = FALSE; 66*4713Seric rcps = 0; 674549Seric message("220", "%s Sendmail at your service", HostName); 684549Seric for (;;) 694549Seric { 704549Seric To = NULL; 714577Seric Errors = 0; 724549Seric if (fgets(inp, sizeof inp, InChannel) == NULL) 734549Seric { 744549Seric /* end of file, just die */ 754558Seric message("421", "%s Lost input channel", HostName); 764549Seric finis(); 774549Seric } 784549Seric 794549Seric /* clean up end of line */ 804558Seric fixcrlf(inp, TRUE); 814549Seric 82*4713Seric /* echo command to transcript */ 83*4713Seric fprintf(Xscript, "*** %s\n", inp); 84*4713Seric 854549Seric /* break off command */ 864549Seric for (p = inp; isspace(*p); p++) 874549Seric continue; 884549Seric cmd = p; 894549Seric while (*++p != '\0' && !isspace(*p)) 904549Seric continue; 914549Seric if (*p != '\0') 924549Seric *p++ = '\0'; 934549Seric 944549Seric /* decode command */ 954549Seric for (c = CmdTab; c->cmdname != NULL; c++) 964549Seric { 974549Seric if (sameword(c->cmdname, cmd)) 984549Seric break; 994549Seric } 1004549Seric 1014549Seric /* process command */ 1024549Seric switch (c->cmdcode) 1034549Seric { 1044549Seric case CMDMAIL: /* mail -- designate sender */ 1054558Seric if (hasmail) 1064558Seric { 1074558Seric message("503", "Sender already specified"); 1084558Seric break; 1094558Seric } 1104549Seric p = skipword(p, "from"); 1114549Seric if (p == NULL) 1124549Seric break; 1134549Seric if (index(p, ',') != NULL) 1144549Seric { 1154549Seric message("501", "Source routing not implemented"); 1164549Seric Errors++; 1174549Seric break; 1184549Seric } 1194549Seric setsender(p); 1204577Seric if (Errors == 0) 1214549Seric { 1224549Seric message("250", "Sender ok"); 1234549Seric hasmail = TRUE; 1244549Seric } 1254549Seric break; 1264549Seric 1274549Seric case CMDMRCP: /* mrcp -- designate recipient */ 1284549Seric p = skipword(p, "to"); 1294549Seric if (p == NULL) 1304549Seric break; 1314549Seric if (index(p, ',') != NULL) 1324549Seric { 1334549Seric message("501", "Source routing not implemented"); 1344549Seric Errors++; 1354549Seric break; 1364549Seric } 1374628Seric sendto(p, 1, (ADDRESS *) NULL); 1384577Seric if (Errors == 0) 1394549Seric { 1404549Seric message("250", "Recipient ok"); 141*4713Seric rcps++; 1424549Seric } 1434549Seric break; 1444549Seric 1454549Seric case CMDDATA: /* data -- text of mail */ 146*4713Seric collect(TRUE); 1474577Seric if (Errors == 0) 1484549Seric { 1494549Seric message("250", "Message stored"); 1504549Seric hasdata = TRUE; 1514549Seric } 1524549Seric break; 1534549Seric 1544549Seric case CMDDOIT: /* doit -- actually send everything */ 1554549Seric if (!hasmail) 1564549Seric message("503", "Need MAIL command"); 157*4713Seric else if (rcps <= 0) 1584549Seric message("503", "Need MRCP (recipient)"); 1594549Seric else if (!hasdata) 1604549Seric message("503", "No message, use DATA"); 1614549Seric else 1624549Seric { 163*4713Seric if (rcps != 1) 164*4713Seric HoldErrs = MailBack = TRUE; 1654549Seric sendall(FALSE); 166*4713Seric HoldErrs = FALSE; 167*4713Seric To = NULL; 168*4713Seric if (Errors == 0 || rcps != 1) 1694549Seric message("250", "Sent"); 1704549Seric } 1714549Seric break; 1724549Seric 1734549Seric case CMDRSET: /* rset -- reset state */ 1744549Seric message("250", "Reset state"); 1754549Seric finis(); 1764549Seric 1774549Seric case CMDVRFY: /* vrfy -- verify address */ 1784628Seric sendto(p, 1, (ADDRESS *) NULL); 1794577Seric if (Errors == 0) 1804549Seric message("250", "user ok"); 1814549Seric break; 1824549Seric 1834549Seric case CMDHELP: /* help -- give user info */ 1844577Seric if (*p == '\0') 1854577Seric p = "SMTP"; 1864577Seric help(p); 1874549Seric break; 1884549Seric 1894549Seric case CMDNOOP: /* noop -- do nothing */ 1904549Seric message("200", "OK"); 1914549Seric break; 1924549Seric 1934549Seric case CMDQUIT: /* quit -- leave mail */ 1944549Seric message("221", "%s closing connection", HostName); 1954549Seric finis(); 1964549Seric 1974577Seric case CMDMRSQ: /* mrsq -- negotiate protocol */ 1984577Seric if (*p == 'R' || *p == 'T') 1994577Seric { 2004577Seric /* recipients first or text first */ 2014577Seric message("200", "%c ok, please continue", *p); 2024577Seric } 2034577Seric else if (*p == '?') 2044577Seric { 2054577Seric /* what do I prefer? anything, anytime */ 2064577Seric message("215", "R Recipients first is my choice"); 2074577Seric } 2084577Seric else if (*p == '\0') 2094577Seric { 2104577Seric /* no meaningful scheme */ 2114577Seric message("200", "okey dokie boobie"); 2124577Seric } 2134577Seric else 2144577Seric { 2154577Seric /* bad argument */ 2164577Seric message("504", "Scheme unknown"); 2174577Seric } 2184577Seric break; 2194577Seric 2204549Seric case CMDERROR: /* unknown command */ 2214549Seric message("500", "Command unrecognized"); 2224549Seric break; 2234549Seric 2244549Seric default: 2254549Seric syserr("smtp: unknown code %d", c->cmdcode); 2264549Seric break; 2274549Seric } 2284549Seric } 2294549Seric } 2304549Seric /* 2314549Seric ** SKIPWORD -- skip a fixed word. 2324549Seric ** 2334549Seric ** Parameters: 2344549Seric ** p -- place to start looking. 2354549Seric ** w -- word to skip. 2364549Seric ** 2374549Seric ** Returns: 2384549Seric ** p following w. 2394549Seric ** NULL on error. 2404549Seric ** 2414549Seric ** Side Effects: 2424549Seric ** clobbers the p data area. 2434549Seric */ 2444549Seric 2454549Seric static char * 2464549Seric skipword(p, w) 2474549Seric register char *p; 2484549Seric char *w; 2494549Seric { 2504549Seric register char *q; 2514549Seric extern bool sameword(); 2524549Seric 2534549Seric /* find beginning of word */ 2544549Seric while (isspace(*p)) 2554549Seric p++; 2564549Seric q = p; 2574549Seric 2584549Seric /* find end of word */ 2594549Seric while (*p != '\0' && *p != ':' && !isspace(*p)) 2604549Seric p++; 2614549Seric while (isspace(*p)) 2624549Seric *p++ = '\0'; 2634549Seric if (*p != ':') 2644549Seric { 2654549Seric syntax: 2664549Seric message("501", "Syntax error"); 2674549Seric Errors++; 2684549Seric return (NULL); 2694549Seric } 2704549Seric *p++ = '\0'; 2714549Seric while (isspace(*p)) 2724549Seric p++; 2734549Seric 2744549Seric /* see if the input word matches desired word */ 2754549Seric if (!sameword(q, w)) 2764549Seric goto syntax; 2774549Seric 2784549Seric return (p); 2794549Seric } 2804577Seric /* 2814577Seric ** HELP -- implement the HELP command. 2824577Seric ** 2834577Seric ** Parameters: 2844577Seric ** topic -- the topic we want help for. 2854577Seric ** 2864577Seric ** Returns: 2874577Seric ** none. 2884577Seric ** 2894577Seric ** Side Effects: 2904577Seric ** outputs the help file to message output. 2914577Seric */ 2924577Seric 2934577Seric help(topic) 2944577Seric char *topic; 2954577Seric { 2964577Seric register FILE *hf; 2974577Seric int len; 2984577Seric char buf[MAXLINE]; 2994577Seric bool noinfo; 3004582Seric extern char *HelpFile; 3014577Seric 3024582Seric hf = fopen(HelpFile, "r"); 3034577Seric if (hf == NULL) 3044577Seric { 3054577Seric /* no help */ 3064577Seric message("502", "HELP not implemented"); 3074577Seric return; 3084577Seric } 3094577Seric 3104577Seric len = strlen(topic); 3114577Seric makelower(topic); 3124577Seric noinfo = TRUE; 3134577Seric 3144577Seric while (fgets(buf, sizeof buf, hf) != NULL) 3154577Seric { 3164577Seric if (strncmp(buf, topic, len) == 0) 3174577Seric { 3184577Seric register char *p; 3194577Seric 3204577Seric p = index(buf, '\t'); 3214577Seric if (p == NULL) 3224577Seric p = buf; 3234577Seric else 3244577Seric p++; 3254577Seric fixcrlf(p, TRUE); 3264577Seric message("214-", p); 3274577Seric noinfo = FALSE; 3284577Seric } 3294577Seric } 3304577Seric 3314577Seric if (noinfo) 3324577Seric message("504", "HELP topic unknown"); 3334577Seric else 3344577Seric message("214", "End of HELP info"); 3354628Seric (void) fclose(hf); 3364577Seric } 337