14549Seric # include "sendmail.h" 24549Seric 3*4976Seric static char SccsId[] = "@(#)srvrsmtp.c 3.8 11/21/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 */ 28*4976Seric # define CMDRCPT 2 /* rcpt -- designate recipient */ 294549Seric # define CMDDATA 3 /* data -- send message text */ 304549Seric # define CMDRSET 5 /* rset -- reset state */ 314549Seric # define CMDVRFY 6 /* vrfy -- verify address */ 324549Seric # define CMDHELP 7 /* help -- give usage info */ 334549Seric # define CMDNOOP 8 /* noop -- do nothing */ 344549Seric # define CMDQUIT 9 /* quit -- close connection and die */ 354577Seric # define CMDMRSQ 10 /* mrsq -- for old mtp compat only */ 36*4976Seric # define CMDHELO 11 /* helo -- be polite */ 374549Seric 384549Seric static struct cmd CmdTab[] = 394549Seric { 404549Seric "mail", CMDMAIL, 41*4976Seric "rcpt", CMDRCPT, 42*4976Seric "mrcp", CMDRCPT, /* for old MTP compatability */ 434549Seric "data", CMDDATA, 444549Seric "rset", CMDRSET, 454549Seric "vrfy", CMDVRFY, 464549Seric "help", CMDHELP, 474549Seric "noop", CMDNOOP, 484549Seric "quit", CMDQUIT, 494577Seric "mrsq", CMDMRSQ, 50*4976Seric "helo", CMDHELO, 514549Seric NULL, CMDERROR, 524549Seric }; 534549Seric 544549Seric smtp() 554549Seric { 564549Seric char inp[MAXLINE]; 574549Seric register char *p; 584549Seric struct cmd *c; 594549Seric char *cmd; 604549Seric extern char *skipword(); 614549Seric extern bool sameword(); 624549Seric bool hasmail; /* mail command received */ 634713Seric int rcps; /* number of recipients */ 644549Seric bool hasdata; /* has mail data */ 654549Seric 664713Seric hasmail = hasdata = FALSE; 674713Seric rcps = 0; 684549Seric message("220", "%s Sendmail at your service", HostName); 694549Seric for (;;) 704549Seric { 714549Seric To = NULL; 724577Seric Errors = 0; 734549Seric if (fgets(inp, sizeof inp, InChannel) == NULL) 744549Seric { 754549Seric /* end of file, just die */ 764558Seric message("421", "%s Lost input channel", HostName); 774549Seric finis(); 784549Seric } 794549Seric 804549Seric /* clean up end of line */ 814558Seric fixcrlf(inp, TRUE); 824549Seric 834713Seric /* echo command to transcript */ 844713Seric fprintf(Xscript, "*** %s\n", inp); 854713Seric 864549Seric /* break off command */ 874549Seric for (p = inp; isspace(*p); p++) 884549Seric continue; 894549Seric cmd = p; 904549Seric while (*++p != '\0' && !isspace(*p)) 914549Seric continue; 924549Seric if (*p != '\0') 934549Seric *p++ = '\0'; 944549Seric 954549Seric /* decode command */ 964549Seric for (c = CmdTab; c->cmdname != NULL; c++) 974549Seric { 984549Seric if (sameword(c->cmdname, cmd)) 994549Seric break; 1004549Seric } 1014549Seric 1024549Seric /* process command */ 1034549Seric switch (c->cmdcode) 1044549Seric { 105*4976Seric case CMDHELO: /* hello -- introduce yourself */ 106*4976Seric message("250", "%s Pleased to meet you", HostName); 107*4976Seric break; 108*4976Seric 1094549Seric case CMDMAIL: /* mail -- designate sender */ 1104558Seric if (hasmail) 1114558Seric { 1124558Seric message("503", "Sender already specified"); 1134558Seric break; 1144558Seric } 1154549Seric p = skipword(p, "from"); 1164549Seric if (p == NULL) 1174549Seric break; 1184549Seric if (index(p, ',') != NULL) 1194549Seric { 1204549Seric message("501", "Source routing not implemented"); 1214549Seric Errors++; 1224549Seric break; 1234549Seric } 1244549Seric setsender(p); 1254577Seric if (Errors == 0) 1264549Seric { 1274549Seric message("250", "Sender ok"); 1284549Seric hasmail = TRUE; 1294549Seric } 1304549Seric break; 1314549Seric 132*4976Seric case CMDRCPT: /* rcpt -- designate recipient */ 1334549Seric p = skipword(p, "to"); 1344549Seric if (p == NULL) 1354549Seric break; 1364549Seric if (index(p, ',') != NULL) 1374549Seric { 1384549Seric message("501", "Source routing not implemented"); 1394549Seric Errors++; 1404549Seric break; 1414549Seric } 1424628Seric sendto(p, 1, (ADDRESS *) NULL); 1434577Seric if (Errors == 0) 1444549Seric { 1454549Seric message("250", "Recipient ok"); 1464713Seric rcps++; 1474549Seric } 1484549Seric break; 1494549Seric 1504549Seric case CMDDATA: /* data -- text of mail */ 151*4976Seric if (!hasmail) 1524549Seric { 153*4976Seric message("503", "Need MAIL command"); 154*4976Seric break; 1554549Seric } 1564713Seric else if (rcps <= 0) 1574549Seric { 158*4976Seric message("503", "Need RCPT (recipient)"); 159*4976Seric break; 1604549Seric } 161*4976Seric 162*4976Seric /* collect the text of the message */ 163*4976Seric collect(TRUE); 164*4976Seric if (Errors != 0) 165*4976Seric break; 166*4976Seric 167*4976Seric /* if sending to multiple people, mail back errors */ 168*4976Seric if (rcps != 1) 169*4976Seric HoldErrs = MailBack = TRUE; 170*4976Seric 171*4976Seric /* send to all recipients */ 172*4976Seric sendall(FALSE); 173*4976Seric 174*4976Seric /* reset strange modes */ 175*4976Seric HoldErrs = FALSE; 176*4976Seric To = NULL; 177*4976Seric 178*4976Seric /* issue success if appropriate */ 179*4976Seric if (Errors == 0 || rcps != 1) 180*4976Seric message("250", "Sent"); 1814549Seric break; 1824549Seric 1834549Seric case CMDRSET: /* rset -- reset state */ 1844549Seric message("250", "Reset state"); 1854549Seric finis(); 1864549Seric 1874549Seric case CMDVRFY: /* vrfy -- verify address */ 1884628Seric sendto(p, 1, (ADDRESS *) NULL); 1894577Seric if (Errors == 0) 1904549Seric message("250", "user ok"); 1914549Seric break; 1924549Seric 1934549Seric case CMDHELP: /* help -- give user info */ 1944577Seric if (*p == '\0') 1954577Seric p = "SMTP"; 1964577Seric help(p); 1974549Seric break; 1984549Seric 1994549Seric case CMDNOOP: /* noop -- do nothing */ 2004549Seric message("200", "OK"); 2014549Seric break; 2024549Seric 2034549Seric case CMDQUIT: /* quit -- leave mail */ 2044549Seric message("221", "%s closing connection", HostName); 2054549Seric finis(); 2064549Seric 2074577Seric case CMDMRSQ: /* mrsq -- negotiate protocol */ 2084577Seric if (*p == 'R' || *p == 'T') 2094577Seric { 2104577Seric /* recipients first or text first */ 2114577Seric message("200", "%c ok, please continue", *p); 2124577Seric } 2134577Seric else if (*p == '?') 2144577Seric { 2154577Seric /* what do I prefer? anything, anytime */ 2164577Seric message("215", "R Recipients first is my choice"); 2174577Seric } 2184577Seric else if (*p == '\0') 2194577Seric { 2204577Seric /* no meaningful scheme */ 2214577Seric message("200", "okey dokie boobie"); 2224577Seric } 2234577Seric else 2244577Seric { 2254577Seric /* bad argument */ 2264577Seric message("504", "Scheme unknown"); 2274577Seric } 2284577Seric break; 2294577Seric 2304549Seric case CMDERROR: /* unknown command */ 2314549Seric message("500", "Command unrecognized"); 2324549Seric break; 2334549Seric 2344549Seric default: 2354549Seric syserr("smtp: unknown code %d", c->cmdcode); 2364549Seric break; 2374549Seric } 2384549Seric } 2394549Seric } 2404549Seric /* 2414549Seric ** SKIPWORD -- skip a fixed word. 2424549Seric ** 2434549Seric ** Parameters: 2444549Seric ** p -- place to start looking. 2454549Seric ** w -- word to skip. 2464549Seric ** 2474549Seric ** Returns: 2484549Seric ** p following w. 2494549Seric ** NULL on error. 2504549Seric ** 2514549Seric ** Side Effects: 2524549Seric ** clobbers the p data area. 2534549Seric */ 2544549Seric 2554549Seric static char * 2564549Seric skipword(p, w) 2574549Seric register char *p; 2584549Seric char *w; 2594549Seric { 2604549Seric register char *q; 2614549Seric extern bool sameword(); 2624549Seric 2634549Seric /* find beginning of word */ 2644549Seric while (isspace(*p)) 2654549Seric p++; 2664549Seric q = p; 2674549Seric 2684549Seric /* find end of word */ 2694549Seric while (*p != '\0' && *p != ':' && !isspace(*p)) 2704549Seric p++; 2714549Seric while (isspace(*p)) 2724549Seric *p++ = '\0'; 2734549Seric if (*p != ':') 2744549Seric { 2754549Seric syntax: 2764549Seric message("501", "Syntax error"); 2774549Seric Errors++; 2784549Seric return (NULL); 2794549Seric } 2804549Seric *p++ = '\0'; 2814549Seric while (isspace(*p)) 2824549Seric p++; 2834549Seric 2844549Seric /* see if the input word matches desired word */ 2854549Seric if (!sameword(q, w)) 2864549Seric goto syntax; 2874549Seric 2884549Seric return (p); 2894549Seric } 2904577Seric /* 2914577Seric ** HELP -- implement the HELP command. 2924577Seric ** 2934577Seric ** Parameters: 2944577Seric ** topic -- the topic we want help for. 2954577Seric ** 2964577Seric ** Returns: 2974577Seric ** none. 2984577Seric ** 2994577Seric ** Side Effects: 3004577Seric ** outputs the help file to message output. 3014577Seric */ 3024577Seric 3034577Seric help(topic) 3044577Seric char *topic; 3054577Seric { 3064577Seric register FILE *hf; 3074577Seric int len; 3084577Seric char buf[MAXLINE]; 3094577Seric bool noinfo; 3104582Seric extern char *HelpFile; 3114577Seric 3124582Seric hf = fopen(HelpFile, "r"); 3134577Seric if (hf == NULL) 3144577Seric { 3154577Seric /* no help */ 3164577Seric message("502", "HELP not implemented"); 3174577Seric return; 3184577Seric } 3194577Seric 3204577Seric len = strlen(topic); 3214577Seric makelower(topic); 3224577Seric noinfo = TRUE; 3234577Seric 3244577Seric while (fgets(buf, sizeof buf, hf) != NULL) 3254577Seric { 3264577Seric if (strncmp(buf, topic, len) == 0) 3274577Seric { 3284577Seric register char *p; 3294577Seric 3304577Seric p = index(buf, '\t'); 3314577Seric if (p == NULL) 3324577Seric p = buf; 3334577Seric else 3344577Seric p++; 3354577Seric fixcrlf(p, TRUE); 3364577Seric message("214-", p); 3374577Seric noinfo = FALSE; 3384577Seric } 3394577Seric } 3404577Seric 3414577Seric if (noinfo) 3424577Seric message("504", "HELP topic unknown"); 3434577Seric else 3444577Seric message("214", "End of HELP info"); 3454628Seric (void) fclose(hf); 3464577Seric } 347