14549Seric # include "sendmail.h" 24549Seric 3*4556Seric static char SccsId[] = "@(#)srvrsmtp.c 3.2 10/20/81"; 4*4556Seric 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 */ 364549Seric 374549Seric static struct cmd CmdTab[] = 384549Seric { 394549Seric "mail", CMDMAIL, 404549Seric "mrcp", CMDMRCP, 414549Seric "data", CMDDATA, 424549Seric "doit", CMDDOIT, 434549Seric "rset", CMDRSET, 444549Seric "vrfy", CMDVRFY, 454549Seric "help", CMDHELP, 464549Seric "noop", CMDNOOP, 474549Seric "quit", CMDQUIT, 484549Seric NULL, CMDERROR, 494549Seric }; 504549Seric 514549Seric smtp() 524549Seric { 534549Seric char inp[MAXLINE]; 544549Seric register char *p; 554549Seric struct cmd *c; 564549Seric char *cmd; 574549Seric extern char *skipword(); 584549Seric extern bool sameword(); 594549Seric bool hasmail; /* mail command received */ 604549Seric bool hasmrcp; /* has a recipient */ 614549Seric bool hasdata; /* has mail data */ 624549Seric 634549Seric /*%%%*/ HostName = "XYZZY"; 644549Seric hasmail = hasmrcp = hasdata = FALSE; 654549Seric message("220", "%s Sendmail at your service", HostName); 664549Seric for (;;) 674549Seric { 684549Seric To = NULL; 694549Seric Errors = 0; 704549Seric if (fgets(inp, sizeof inp, InChannel) == NULL) 714549Seric { 724549Seric /* end of file, just die */ 734549Seric message("421", "Lost input channel"); 744549Seric finis(); 754549Seric } 764549Seric 774549Seric /* clean up end of line */ 784549Seric p = index(inp, '\n'); 794549Seric if (p != NULL) 804549Seric *p = '\0'; 814549Seric p = index(inp, '\r'); 824549Seric if (p != NULL) 834549Seric *p = '\0'; 844549Seric 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 */ 1054549Seric p = skipword(p, "from"); 1064549Seric if (p == NULL) 1074549Seric break; 1084549Seric if (index(p, ',') != NULL) 1094549Seric { 1104549Seric message("501", "Source routing not implemented"); 1114549Seric Errors++; 1124549Seric break; 1134549Seric } 1144549Seric setsender(p); 1154549Seric if (Errors == 0) 1164549Seric { 1174549Seric message("250", "Sender ok"); 1184549Seric hasmail = TRUE; 1194549Seric } 1204549Seric break; 1214549Seric 1224549Seric case CMDMRCP: /* mrcp -- designate recipient */ 1234549Seric p = skipword(p, "to"); 1244549Seric if (p == NULL) 1254549Seric break; 1264549Seric if (index(p, ',') != NULL) 1274549Seric { 1284549Seric message("501", "Source routing not implemented"); 1294549Seric Errors++; 1304549Seric break; 1314549Seric } 1324549Seric sendto(p, 1, NULL); 1334549Seric if (Errors == 0) 1344549Seric { 1354549Seric message("250", "Recipient ok"); 1364549Seric hasmrcp = TRUE; 1374549Seric } 1384549Seric break; 1394549Seric 1404549Seric case CMDDATA: /* data -- text of mail */ 1414549Seric message("354", "Enter mail, end with dot"); 1424549Seric collect(); 1434549Seric if (Errors == 0) 1444549Seric { 1454549Seric message("250", "Message stored"); 1464549Seric hasdata = TRUE; 1474549Seric } 1484549Seric break; 1494549Seric 1504549Seric case CMDDOIT: /* doit -- actually send everything */ 1514549Seric if (!hasmail) 1524549Seric message("503", "Need MAIL command"); 1534549Seric else if (!hasmrcp) 1544549Seric message("503", "Need MRCP (recipient)"); 1554549Seric else if (!hasdata) 1564549Seric message("503", "No message, use DATA"); 1574549Seric else 1584549Seric { 1594549Seric sendall(FALSE); 1604549Seric if (Errors == 0) 1614549Seric message("250", "Sent"); 1624549Seric } 1634549Seric break; 1644549Seric 1654549Seric case CMDRSET: /* rset -- reset state */ 1664549Seric message("250", "Reset state"); 1674549Seric finis(); 1684549Seric 1694549Seric case CMDVRFY: /* vrfy -- verify address */ 1704549Seric sendto(p, 1, NULL); 1714549Seric if (Errors == 0) 1724549Seric message("250", "user ok"); 1734549Seric break; 1744549Seric 1754549Seric case CMDHELP: /* help -- give user info */ 1764549Seric message("502", "HELP not implemented"); 1774549Seric break; 1784549Seric 1794549Seric case CMDNOOP: /* noop -- do nothing */ 1804549Seric message("200", "OK"); 1814549Seric break; 1824549Seric 1834549Seric case CMDQUIT: /* quit -- leave mail */ 1844549Seric message("221", "%s closing connection", HostName); 1854549Seric finis(); 1864549Seric 1874549Seric case CMDERROR: /* unknown command */ 1884549Seric message("500", "Command unrecognized"); 1894549Seric break; 1904549Seric 1914549Seric default: 1924549Seric syserr("smtp: unknown code %d", c->cmdcode); 1934549Seric break; 1944549Seric } 1954549Seric } 1964549Seric } 1974549Seric /* 1984549Seric ** SKIPWORD -- skip a fixed word. 1994549Seric ** 2004549Seric ** Parameters: 2014549Seric ** p -- place to start looking. 2024549Seric ** w -- word to skip. 2034549Seric ** 2044549Seric ** Returns: 2054549Seric ** p following w. 2064549Seric ** NULL on error. 2074549Seric ** 2084549Seric ** Side Effects: 2094549Seric ** clobbers the p data area. 2104549Seric */ 2114549Seric 2124549Seric static char * 2134549Seric skipword(p, w) 2144549Seric register char *p; 2154549Seric char *w; 2164549Seric { 2174549Seric register char *q; 2184549Seric extern bool sameword(); 2194549Seric 2204549Seric /* find beginning of word */ 2214549Seric while (isspace(*p)) 2224549Seric p++; 2234549Seric q = p; 2244549Seric 2254549Seric /* find end of word */ 2264549Seric while (*p != '\0' && *p != ':' && !isspace(*p)) 2274549Seric p++; 2284549Seric while (isspace(*p)) 2294549Seric *p++ = '\0'; 2304549Seric if (*p != ':') 2314549Seric { 2324549Seric syntax: 2334549Seric message("501", "Syntax error"); 2344549Seric Errors++; 2354549Seric return (NULL); 2364549Seric } 2374549Seric *p++ = '\0'; 2384549Seric while (isspace(*p)) 2394549Seric p++; 2404549Seric 2414549Seric /* see if the input word matches desired word */ 2424549Seric if (!sameword(q, w)) 2434549Seric goto syntax; 2444549Seric 2454549Seric return (p); 2464549Seric } 247