14549Seric # include "sendmail.h" 24549Seric 3*4558Seric static char SccsId[] = "@(#)srvrsmtp.c 3.3 10/20/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 */ 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 */ 62*4558Seric int baseerrs; 634549Seric 644549Seric hasmail = hasmrcp = hasdata = FALSE; 654549Seric message("220", "%s Sendmail at your service", HostName); 664549Seric for (;;) 674549Seric { 684549Seric To = NULL; 69*4558Seric baseerrs = Errors; 704549Seric if (fgets(inp, sizeof inp, InChannel) == NULL) 714549Seric { 724549Seric /* end of file, just die */ 73*4558Seric message("421", "%s Lost input channel", HostName); 744549Seric finis(); 754549Seric } 764549Seric 774549Seric /* clean up end of line */ 78*4558Seric fixcrlf(inp, TRUE); 794549Seric 804549Seric /* break off command */ 814549Seric for (p = inp; isspace(*p); p++) 824549Seric continue; 834549Seric cmd = p; 844549Seric while (*++p != '\0' && !isspace(*p)) 854549Seric continue; 864549Seric if (*p != '\0') 874549Seric *p++ = '\0'; 884549Seric 894549Seric /* decode command */ 904549Seric for (c = CmdTab; c->cmdname != NULL; c++) 914549Seric { 924549Seric if (sameword(c->cmdname, cmd)) 934549Seric break; 944549Seric } 954549Seric 964549Seric /* process command */ 974549Seric switch (c->cmdcode) 984549Seric { 994549Seric case CMDMAIL: /* mail -- designate sender */ 100*4558Seric if (hasmail) 101*4558Seric { 102*4558Seric message("503", "Sender already specified"); 103*4558Seric break; 104*4558Seric } 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); 115*4558Seric if (Errors == baseerrs) 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); 133*4558Seric if (Errors == baseerrs) 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(); 143*4558Seric if (Errors == baseerrs) 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); 160*4558Seric if (Errors == baseerrs) 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); 171*4558Seric if (Errors == baseerrs) 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