14549Seric # include "sendmail.h" 24549Seric 3*4582Seric static char SccsId[] = "@(#)srvrsmtp.c 3.5 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 */ 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 */ 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; 704577Seric 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); 1164577Seric 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); 1344577Seric 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(); 1444577Seric 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); 1614577Seric 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); 1724577Seric if (Errors == 0) 1734549Seric message("250", "user ok"); 1744549Seric break; 1754549Seric 1764549Seric case CMDHELP: /* help -- give user info */ 1774577Seric if (*p == '\0') 1784577Seric p = "SMTP"; 1794577Seric 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 1904577Seric case CMDMRSQ: /* mrsq -- negotiate protocol */ 1914577Seric if (*p == 'R' || *p == 'T') 1924577Seric { 1934577Seric /* recipients first or text first */ 1944577Seric message("200", "%c ok, please continue", *p); 1954577Seric } 1964577Seric else if (*p == '?') 1974577Seric { 1984577Seric /* what do I prefer? anything, anytime */ 1994577Seric message("215", "R Recipients first is my choice"); 2004577Seric } 2014577Seric else if (*p == '\0') 2024577Seric { 2034577Seric /* no meaningful scheme */ 2044577Seric message("200", "okey dokie boobie"); 2054577Seric } 2064577Seric else 2074577Seric { 2084577Seric /* bad argument */ 2094577Seric message("504", "Scheme unknown"); 2104577Seric } 2114577Seric break; 2124577Seric 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 } 2734577Seric /* 2744577Seric ** HELP -- implement the HELP command. 2754577Seric ** 2764577Seric ** Parameters: 2774577Seric ** topic -- the topic we want help for. 2784577Seric ** 2794577Seric ** Returns: 2804577Seric ** none. 2814577Seric ** 2824577Seric ** Side Effects: 2834577Seric ** outputs the help file to message output. 2844577Seric */ 2854577Seric 2864577Seric help(topic) 2874577Seric char *topic; 2884577Seric { 2894577Seric register FILE *hf; 2904577Seric int len; 2914577Seric char buf[MAXLINE]; 2924577Seric bool noinfo; 293*4582Seric extern char *HelpFile; 2944577Seric 295*4582Seric hf = fopen(HelpFile, "r"); 2964577Seric if (hf == NULL) 2974577Seric { 2984577Seric /* no help */ 2994577Seric message("502", "HELP not implemented"); 3004577Seric return; 3014577Seric } 3024577Seric 3034577Seric len = strlen(topic); 3044577Seric makelower(topic); 3054577Seric noinfo = TRUE; 3064577Seric 3074577Seric while (fgets(buf, sizeof buf, hf) != NULL) 3084577Seric { 3094577Seric if (strncmp(buf, topic, len) == 0) 3104577Seric { 3114577Seric register char *p; 3124577Seric 3134577Seric p = index(buf, '\t'); 3144577Seric if (p == NULL) 3154577Seric p = buf; 3164577Seric else 3174577Seric p++; 3184577Seric fixcrlf(p, TRUE); 3194577Seric message("214-", p); 3204577Seric noinfo = FALSE; 3214577Seric } 3224577Seric } 3234577Seric 3244577Seric if (noinfo) 3254577Seric message("504", "HELP topic unknown"); 3264577Seric else 3274577Seric message("214", "End of HELP info"); 3284577Seric fclose(hf); 3294577Seric } 330