14549Seric # include "sendmail.h" 24549Seric 35181Seric # ifndef SMTP 4*5187Seric static char SccsId[] = "@(#)srvrsmtp.c 3.12 12/05/81 (no SMTP)"; 55181Seric # else SMTP 64556Seric 7*5187Seric static char SccsId[] = "@(#)srvrsmtp.c 3.12 12/05/81"; 85181Seric 94549Seric /* 104549Seric ** SMTP -- run the SMTP protocol. 114549Seric ** 124549Seric ** Parameters: 134549Seric ** none. 144549Seric ** 154549Seric ** Returns: 164549Seric ** never. 174549Seric ** 184549Seric ** Side Effects: 194549Seric ** Reads commands from the input channel and processes 204549Seric ** them. 214549Seric */ 224549Seric 234549Seric struct cmd 244549Seric { 254549Seric char *cmdname; /* command name */ 264549Seric int cmdcode; /* internal code, see below */ 274549Seric }; 284549Seric 294549Seric /* values for cmdcode */ 304549Seric # define CMDERROR 0 /* bad command */ 314549Seric # define CMDMAIL 1 /* mail -- designate sender */ 324976Seric # define CMDRCPT 2 /* rcpt -- designate recipient */ 334549Seric # define CMDDATA 3 /* data -- send message text */ 344549Seric # define CMDRSET 5 /* rset -- reset state */ 354549Seric # define CMDVRFY 6 /* vrfy -- verify address */ 364549Seric # define CMDHELP 7 /* help -- give usage info */ 374549Seric # define CMDNOOP 8 /* noop -- do nothing */ 384549Seric # define CMDQUIT 9 /* quit -- close connection and die */ 394577Seric # define CMDMRSQ 10 /* mrsq -- for old mtp compat only */ 404976Seric # define CMDHELO 11 /* helo -- be polite */ 415003Seric # define CMDDBGSHOWQ 12 /* showq -- show send queue (DEBUG) */ 424549Seric 434549Seric static struct cmd CmdTab[] = 444549Seric { 454549Seric "mail", CMDMAIL, 464976Seric "rcpt", CMDRCPT, 474976Seric "mrcp", CMDRCPT, /* for old MTP compatability */ 484549Seric "data", CMDDATA, 494549Seric "rset", CMDRSET, 504549Seric "vrfy", CMDVRFY, 514549Seric "help", CMDHELP, 524549Seric "noop", CMDNOOP, 534549Seric "quit", CMDQUIT, 544577Seric "mrsq", CMDMRSQ, 554976Seric "helo", CMDHELO, 565003Seric # ifdef DEBUG 575003Seric "showq", CMDDBGSHOWQ, 585003Seric # endif DEBUG 594549Seric NULL, CMDERROR, 604549Seric }; 614549Seric 624549Seric smtp() 634549Seric { 644549Seric char inp[MAXLINE]; 654549Seric register char *p; 664549Seric struct cmd *c; 674549Seric char *cmd; 684549Seric extern char *skipword(); 694549Seric extern bool sameword(); 704549Seric bool hasmail; /* mail command received */ 714713Seric int rcps; /* number of recipients */ 725003Seric auto ADDRESS *vrfyqueue; 735003Seric ADDRESS *prev; 744549Seric 755003Seric hasmail = FALSE; 764713Seric rcps = 0; 774549Seric message("220", "%s Sendmail at your service", HostName); 784549Seric for (;;) 794549Seric { 804549Seric To = NULL; 814577Seric Errors = 0; 824549Seric if (fgets(inp, sizeof inp, InChannel) == NULL) 834549Seric { 844549Seric /* end of file, just die */ 854558Seric message("421", "%s Lost input channel", HostName); 864549Seric finis(); 874549Seric } 884549Seric 894549Seric /* clean up end of line */ 904558Seric fixcrlf(inp, TRUE); 914549Seric 924713Seric /* echo command to transcript */ 934713Seric fprintf(Xscript, "*** %s\n", inp); 944713Seric 954549Seric /* break off command */ 964549Seric for (p = inp; isspace(*p); p++) 974549Seric continue; 984549Seric cmd = p; 994549Seric while (*++p != '\0' && !isspace(*p)) 1004549Seric continue; 1014549Seric if (*p != '\0') 1024549Seric *p++ = '\0'; 1034549Seric 1044549Seric /* decode command */ 1054549Seric for (c = CmdTab; c->cmdname != NULL; c++) 1064549Seric { 1074549Seric if (sameword(c->cmdname, cmd)) 1084549Seric break; 1094549Seric } 1104549Seric 1114549Seric /* process command */ 1124549Seric switch (c->cmdcode) 1134549Seric { 1144976Seric case CMDHELO: /* hello -- introduce yourself */ 115*5187Seric define('s', newstr(p)); 1164997Seric message("250", "%s Hello %s, pleased to meet you", 1174997Seric HostName, p); 1184976Seric break; 1194976Seric 1204549Seric case CMDMAIL: /* mail -- designate sender */ 1214558Seric if (hasmail) 1224558Seric { 1234558Seric message("503", "Sender already specified"); 1244558Seric break; 1254558Seric } 1264549Seric p = skipword(p, "from"); 1274549Seric if (p == NULL) 1284549Seric break; 1294549Seric if (index(p, ',') != NULL) 1304549Seric { 1314549Seric message("501", "Source routing not implemented"); 1324549Seric Errors++; 1334549Seric break; 1344549Seric } 1354549Seric setsender(p); 1364577Seric if (Errors == 0) 1374549Seric { 1384549Seric message("250", "Sender ok"); 1394549Seric hasmail = TRUE; 1404549Seric } 1414549Seric break; 1424549Seric 1434976Seric case CMDRCPT: /* rcpt -- designate recipient */ 1444549Seric p = skipword(p, "to"); 1454549Seric if (p == NULL) 1464549Seric break; 1474549Seric if (index(p, ',') != NULL) 1484549Seric { 1494549Seric message("501", "Source routing not implemented"); 1504549Seric Errors++; 1514549Seric break; 1524549Seric } 1535003Seric sendto(p, 1, (ADDRESS *) NULL, &SendQueue); 1544577Seric if (Errors == 0) 1554549Seric { 1564549Seric message("250", "Recipient ok"); 1574713Seric rcps++; 1584549Seric } 1594549Seric break; 1604549Seric 1614549Seric case CMDDATA: /* data -- text of mail */ 1624976Seric if (!hasmail) 1634549Seric { 1644976Seric message("503", "Need MAIL command"); 1654976Seric break; 1664549Seric } 1674713Seric else if (rcps <= 0) 1684549Seric { 1694976Seric message("503", "Need RCPT (recipient)"); 1704976Seric break; 1714549Seric } 1724976Seric 1734976Seric /* collect the text of the message */ 1744976Seric collect(TRUE); 1754976Seric if (Errors != 0) 1764976Seric break; 1774976Seric 1784976Seric /* if sending to multiple people, mail back errors */ 1794976Seric if (rcps != 1) 1804976Seric HoldErrs = MailBack = TRUE; 1814976Seric 1824976Seric /* send to all recipients */ 1834976Seric sendall(FALSE); 1844976Seric 1854976Seric /* reset strange modes */ 1864976Seric HoldErrs = FALSE; 1874976Seric To = NULL; 1884976Seric 1894976Seric /* issue success if appropriate */ 1904976Seric if (Errors == 0 || rcps != 1) 1914976Seric message("250", "Sent"); 1924549Seric break; 1934549Seric 1944549Seric case CMDRSET: /* rset -- reset state */ 1954549Seric message("250", "Reset state"); 1964549Seric finis(); 1974549Seric 1984549Seric case CMDVRFY: /* vrfy -- verify address */ 1995003Seric vrfyqueue = NULL; 2005003Seric sendto(p, 1, (ADDRESS *) NULL, &vrfyqueue); 2015003Seric while (vrfyqueue != NULL) 2025003Seric { 2035003Seric register ADDRESS *a = vrfyqueue->q_next; 2045003Seric char *code; 2055003Seric 2065003Seric while (a != NULL && bitset(QDONTSEND, a->q_flags)) 2075003Seric a = a->q_next; 2085003Seric 2095003Seric if (!bitset(QDONTSEND, vrfyqueue->q_flags)) 2105003Seric { 2115003Seric if (a != NULL) 2125003Seric code = "250-"; 2135003Seric else 2145003Seric code = "250"; 2155003Seric if (vrfyqueue->q_fullname == NULL) 2165003Seric message(code, "<%s>", vrfyqueue->q_paddr); 2175003Seric else 2185003Seric message(code, "%s <%s>", 2195003Seric vrfyqueue->q_fullname, vrfyqueue->q_paddr); 2205003Seric } 2215003Seric else if (a == NULL) 2225003Seric message("554", "Self destructive alias loop"); 2235003Seric vrfyqueue = a; 2245003Seric } 2254549Seric break; 2264549Seric 2274549Seric case CMDHELP: /* help -- give user info */ 2284577Seric if (*p == '\0') 2294577Seric p = "SMTP"; 2304577Seric help(p); 2314549Seric break; 2324549Seric 2334549Seric case CMDNOOP: /* noop -- do nothing */ 2344549Seric message("200", "OK"); 2354549Seric break; 2364549Seric 2374549Seric case CMDQUIT: /* quit -- leave mail */ 2384549Seric message("221", "%s closing connection", HostName); 2394549Seric finis(); 2404549Seric 2414577Seric case CMDMRSQ: /* mrsq -- negotiate protocol */ 2424577Seric if (*p == 'R' || *p == 'T') 2434577Seric { 2444577Seric /* recipients first or text first */ 2454577Seric message("200", "%c ok, please continue", *p); 2464577Seric } 2474577Seric else if (*p == '?') 2484577Seric { 2494577Seric /* what do I prefer? anything, anytime */ 2504577Seric message("215", "R Recipients first is my choice"); 2514577Seric } 2524577Seric else if (*p == '\0') 2534577Seric { 2544577Seric /* no meaningful scheme */ 2554577Seric message("200", "okey dokie boobie"); 2564577Seric } 2574577Seric else 2584577Seric { 2594577Seric /* bad argument */ 2604577Seric message("504", "Scheme unknown"); 2614577Seric } 2624577Seric break; 2634577Seric 2645003Seric # ifdef DEBUG 2655003Seric case CMDDBGSHOWQ: /* show queues */ 2665003Seric printf("SendQueue="); 2675003Seric printaddr(SendQueue, TRUE); 2685003Seric break; 2695003Seric # endif DEBUG 2705003Seric 2714549Seric case CMDERROR: /* unknown command */ 2724549Seric message("500", "Command unrecognized"); 2734549Seric break; 2744549Seric 2754549Seric default: 2764549Seric syserr("smtp: unknown code %d", c->cmdcode); 2774549Seric break; 2784549Seric } 2794549Seric } 2804549Seric } 2814549Seric /* 2824549Seric ** SKIPWORD -- skip a fixed word. 2834549Seric ** 2844549Seric ** Parameters: 2854549Seric ** p -- place to start looking. 2864549Seric ** w -- word to skip. 2874549Seric ** 2884549Seric ** Returns: 2894549Seric ** p following w. 2904549Seric ** NULL on error. 2914549Seric ** 2924549Seric ** Side Effects: 2934549Seric ** clobbers the p data area. 2944549Seric */ 2954549Seric 2964549Seric static char * 2974549Seric skipword(p, w) 2984549Seric register char *p; 2994549Seric char *w; 3004549Seric { 3014549Seric register char *q; 3024549Seric extern bool sameword(); 3034549Seric 3044549Seric /* find beginning of word */ 3054549Seric while (isspace(*p)) 3064549Seric p++; 3074549Seric q = p; 3084549Seric 3094549Seric /* find end of word */ 3104549Seric while (*p != '\0' && *p != ':' && !isspace(*p)) 3114549Seric p++; 3124549Seric while (isspace(*p)) 3134549Seric *p++ = '\0'; 3144549Seric if (*p != ':') 3154549Seric { 3164549Seric syntax: 3174549Seric message("501", "Syntax error"); 3184549Seric Errors++; 3194549Seric return (NULL); 3204549Seric } 3214549Seric *p++ = '\0'; 3224549Seric while (isspace(*p)) 3234549Seric p++; 3244549Seric 3254549Seric /* see if the input word matches desired word */ 3264549Seric if (!sameword(q, w)) 3274549Seric goto syntax; 3284549Seric 3294549Seric return (p); 3304549Seric } 3314577Seric /* 3324577Seric ** HELP -- implement the HELP command. 3334577Seric ** 3344577Seric ** Parameters: 3354577Seric ** topic -- the topic we want help for. 3364577Seric ** 3374577Seric ** Returns: 3384577Seric ** none. 3394577Seric ** 3404577Seric ** Side Effects: 3414577Seric ** outputs the help file to message output. 3424577Seric */ 3434577Seric 3444577Seric help(topic) 3454577Seric char *topic; 3464577Seric { 3474577Seric register FILE *hf; 3484577Seric int len; 3494577Seric char buf[MAXLINE]; 3504577Seric bool noinfo; 3514582Seric extern char *HelpFile; 3524577Seric 3534582Seric hf = fopen(HelpFile, "r"); 3544577Seric if (hf == NULL) 3554577Seric { 3564577Seric /* no help */ 3574577Seric message("502", "HELP not implemented"); 3584577Seric return; 3594577Seric } 3604577Seric 3614577Seric len = strlen(topic); 3624577Seric makelower(topic); 3634577Seric noinfo = TRUE; 3644577Seric 3654577Seric while (fgets(buf, sizeof buf, hf) != NULL) 3664577Seric { 3674577Seric if (strncmp(buf, topic, len) == 0) 3684577Seric { 3694577Seric register char *p; 3704577Seric 3714577Seric p = index(buf, '\t'); 3724577Seric if (p == NULL) 3734577Seric p = buf; 3744577Seric else 3754577Seric p++; 3764577Seric fixcrlf(p, TRUE); 3774577Seric message("214-", p); 3784577Seric noinfo = FALSE; 3794577Seric } 3804577Seric } 3814577Seric 3824577Seric if (noinfo) 3834577Seric message("504", "HELP topic unknown"); 3844577Seric else 3854577Seric message("214", "End of HELP info"); 3864628Seric (void) fclose(hf); 3874577Seric } 3885181Seric 3895181Seric # endif SMTP 390