14549Seric # include "sendmail.h" 24549Seric 3*4577Seric static char SccsId[] = "@(#)srvrsmtp.c 3.4 10/22/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 */ 36*4577Seric # 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, 49*4577Seric "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 */ 624549Seric bool hasmrcp; /* has a recipient */ 634549Seric bool hasdata; /* has mail data */ 644549Seric 654549Seric hasmail = hasmrcp = hasdata = FALSE; 664549Seric message("220", "%s Sendmail at your service", HostName); 674549Seric for (;;) 684549Seric { 694549Seric To = NULL; 70*4577Seric Errors = 0; 714549Seric if (fgets(inp, sizeof inp, InChannel) == NULL) 724549Seric { 734549Seric /* end of file, just die */ 744558Seric message("421", "%s Lost input channel", HostName); 754549Seric finis(); 764549Seric } 774549Seric 784549Seric /* clean up end of line */ 794558Seric fixcrlf(inp, TRUE); 804549Seric 814549Seric /* break off command */ 824549Seric for (p = inp; isspace(*p); p++) 834549Seric continue; 844549Seric cmd = p; 854549Seric while (*++p != '\0' && !isspace(*p)) 864549Seric continue; 874549Seric if (*p != '\0') 884549Seric *p++ = '\0'; 894549Seric 904549Seric /* decode command */ 914549Seric for (c = CmdTab; c->cmdname != NULL; c++) 924549Seric { 934549Seric if (sameword(c->cmdname, cmd)) 944549Seric break; 954549Seric } 964549Seric 974549Seric /* process command */ 984549Seric switch (c->cmdcode) 994549Seric { 1004549Seric case CMDMAIL: /* mail -- designate sender */ 1014558Seric if (hasmail) 1024558Seric { 1034558Seric message("503", "Sender already specified"); 1044558Seric break; 1054558Seric } 1064549Seric p = skipword(p, "from"); 1074549Seric if (p == NULL) 1084549Seric break; 1094549Seric if (index(p, ',') != NULL) 1104549Seric { 1114549Seric message("501", "Source routing not implemented"); 1124549Seric Errors++; 1134549Seric break; 1144549Seric } 1154549Seric setsender(p); 116*4577Seric if (Errors == 0) 1174549Seric { 1184549Seric message("250", "Sender ok"); 1194549Seric hasmail = TRUE; 1204549Seric } 1214549Seric break; 1224549Seric 1234549Seric case CMDMRCP: /* mrcp -- designate recipient */ 1244549Seric p = skipword(p, "to"); 1254549Seric if (p == NULL) 1264549Seric break; 1274549Seric if (index(p, ',') != NULL) 1284549Seric { 1294549Seric message("501", "Source routing not implemented"); 1304549Seric Errors++; 1314549Seric break; 1324549Seric } 1334549Seric sendto(p, 1, NULL); 134*4577Seric if (Errors == 0) 1354549Seric { 1364549Seric message("250", "Recipient ok"); 1374549Seric hasmrcp = TRUE; 1384549Seric } 1394549Seric break; 1404549Seric 1414549Seric case CMDDATA: /* data -- text of mail */ 1424549Seric message("354", "Enter mail, end with dot"); 1434549Seric collect(); 144*4577Seric if (Errors == 0) 1454549Seric { 1464549Seric message("250", "Message stored"); 1474549Seric hasdata = TRUE; 1484549Seric } 1494549Seric break; 1504549Seric 1514549Seric case CMDDOIT: /* doit -- actually send everything */ 1524549Seric if (!hasmail) 1534549Seric message("503", "Need MAIL command"); 1544549Seric else if (!hasmrcp) 1554549Seric message("503", "Need MRCP (recipient)"); 1564549Seric else if (!hasdata) 1574549Seric message("503", "No message, use DATA"); 1584549Seric else 1594549Seric { 1604549Seric sendall(FALSE); 161*4577Seric if (Errors == 0) 1624549Seric message("250", "Sent"); 1634549Seric } 1644549Seric break; 1654549Seric 1664549Seric case CMDRSET: /* rset -- reset state */ 1674549Seric message("250", "Reset state"); 1684549Seric finis(); 1694549Seric 1704549Seric case CMDVRFY: /* vrfy -- verify address */ 1714549Seric sendto(p, 1, NULL); 172*4577Seric if (Errors == 0) 1734549Seric message("250", "user ok"); 1744549Seric break; 1754549Seric 1764549Seric case CMDHELP: /* help -- give user info */ 177*4577Seric if (*p == '\0') 178*4577Seric p = "SMTP"; 179*4577Seric help(p); 1804549Seric break; 1814549Seric 1824549Seric case CMDNOOP: /* noop -- do nothing */ 1834549Seric message("200", "OK"); 1844549Seric break; 1854549Seric 1864549Seric case CMDQUIT: /* quit -- leave mail */ 1874549Seric message("221", "%s closing connection", HostName); 1884549Seric finis(); 1894549Seric 190*4577Seric case CMDMRSQ: /* mrsq -- negotiate protocol */ 191*4577Seric if (*p == 'R' || *p == 'T') 192*4577Seric { 193*4577Seric /* recipients first or text first */ 194*4577Seric message("200", "%c ok, please continue", *p); 195*4577Seric } 196*4577Seric else if (*p == '?') 197*4577Seric { 198*4577Seric /* what do I prefer? anything, anytime */ 199*4577Seric message("215", "R Recipients first is my choice"); 200*4577Seric } 201*4577Seric else if (*p == '\0') 202*4577Seric { 203*4577Seric /* no meaningful scheme */ 204*4577Seric message("200", "okey dokie boobie"); 205*4577Seric } 206*4577Seric else 207*4577Seric { 208*4577Seric /* bad argument */ 209*4577Seric message("504", "Scheme unknown"); 210*4577Seric } 211*4577Seric break; 212*4577Seric 2134549Seric case CMDERROR: /* unknown command */ 2144549Seric message("500", "Command unrecognized"); 2154549Seric break; 2164549Seric 2174549Seric default: 2184549Seric syserr("smtp: unknown code %d", c->cmdcode); 2194549Seric break; 2204549Seric } 2214549Seric } 2224549Seric } 2234549Seric /* 2244549Seric ** SKIPWORD -- skip a fixed word. 2254549Seric ** 2264549Seric ** Parameters: 2274549Seric ** p -- place to start looking. 2284549Seric ** w -- word to skip. 2294549Seric ** 2304549Seric ** Returns: 2314549Seric ** p following w. 2324549Seric ** NULL on error. 2334549Seric ** 2344549Seric ** Side Effects: 2354549Seric ** clobbers the p data area. 2364549Seric */ 2374549Seric 2384549Seric static char * 2394549Seric skipword(p, w) 2404549Seric register char *p; 2414549Seric char *w; 2424549Seric { 2434549Seric register char *q; 2444549Seric extern bool sameword(); 2454549Seric 2464549Seric /* find beginning of word */ 2474549Seric while (isspace(*p)) 2484549Seric p++; 2494549Seric q = p; 2504549Seric 2514549Seric /* find end of word */ 2524549Seric while (*p != '\0' && *p != ':' && !isspace(*p)) 2534549Seric p++; 2544549Seric while (isspace(*p)) 2554549Seric *p++ = '\0'; 2564549Seric if (*p != ':') 2574549Seric { 2584549Seric syntax: 2594549Seric message("501", "Syntax error"); 2604549Seric Errors++; 2614549Seric return (NULL); 2624549Seric } 2634549Seric *p++ = '\0'; 2644549Seric while (isspace(*p)) 2654549Seric p++; 2664549Seric 2674549Seric /* see if the input word matches desired word */ 2684549Seric if (!sameword(q, w)) 2694549Seric goto syntax; 2704549Seric 2714549Seric return (p); 2724549Seric } 273*4577Seric /* 274*4577Seric ** HELP -- implement the HELP command. 275*4577Seric ** 276*4577Seric ** Parameters: 277*4577Seric ** topic -- the topic we want help for. 278*4577Seric ** 279*4577Seric ** Returns: 280*4577Seric ** none. 281*4577Seric ** 282*4577Seric ** Side Effects: 283*4577Seric ** outputs the help file to message output. 284*4577Seric */ 285*4577Seric 286*4577Seric help(topic) 287*4577Seric char *topic; 288*4577Seric { 289*4577Seric register FILE *hf; 290*4577Seric int len; 291*4577Seric char buf[MAXLINE]; 292*4577Seric bool noinfo; 293*4577Seric 294*4577Seric hf = fopen("/usr/lib/sendmail.hf", "r"); 295*4577Seric if (hf == NULL) 296*4577Seric { 297*4577Seric /* no help */ 298*4577Seric message("502", "HELP not implemented"); 299*4577Seric return; 300*4577Seric } 301*4577Seric 302*4577Seric len = strlen(topic); 303*4577Seric makelower(topic); 304*4577Seric noinfo = TRUE; 305*4577Seric 306*4577Seric while (fgets(buf, sizeof buf, hf) != NULL) 307*4577Seric { 308*4577Seric if (strncmp(buf, topic, len) == 0) 309*4577Seric { 310*4577Seric register char *p; 311*4577Seric 312*4577Seric p = index(buf, '\t'); 313*4577Seric if (p == NULL) 314*4577Seric p = buf; 315*4577Seric else 316*4577Seric p++; 317*4577Seric fixcrlf(p, TRUE); 318*4577Seric message("214-", p); 319*4577Seric noinfo = FALSE; 320*4577Seric } 321*4577Seric } 322*4577Seric 323*4577Seric if (noinfo) 324*4577Seric message("504", "HELP topic unknown"); 325*4577Seric else 326*4577Seric message("214", "End of HELP info"); 327*4577Seric fclose(hf); 328*4577Seric } 329