14549Seric # include "sendmail.h" 24549Seric 35181Seric # ifndef SMTP 4*7275Seric SCCSID(@(#)srvrsmtp.c 3.18 06/25/82 (no SMTP)); 55181Seric # else SMTP 64556Seric 7*7275Seric SCCSID(@(#)srvrsmtp.c 3.18 06/25/82); 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 */ 41*7275Seric # define CMDDBGSHOWQ 12 /* _showq -- show send queue (DEBUG) */ 42*7275Seric # define CMDDBGDEBUG 13 /* _debug -- set debug mode */ 43*7275Seric # define CMDDBGVERBOSE 14 /* _verbose -- go into verbose mode */ 444549Seric 454549Seric static struct cmd CmdTab[] = 464549Seric { 474549Seric "mail", CMDMAIL, 484976Seric "rcpt", CMDRCPT, 494976Seric "mrcp", CMDRCPT, /* for old MTP compatability */ 504549Seric "data", CMDDATA, 514549Seric "rset", CMDRSET, 524549Seric "vrfy", CMDVRFY, 534549Seric "help", CMDHELP, 544549Seric "noop", CMDNOOP, 554549Seric "quit", CMDQUIT, 564577Seric "mrsq", CMDMRSQ, 574976Seric "helo", CMDHELO, 585003Seric # ifdef DEBUG 59*7275Seric "_showq", CMDDBGSHOWQ, 60*7275Seric "_debug", CMDDBGDEBUG, 61*7275Seric "_verbose", CMDDBGVERBOSE, 625003Seric # endif DEBUG 634549Seric NULL, CMDERROR, 644549Seric }; 654549Seric 664549Seric smtp() 674549Seric { 684549Seric char inp[MAXLINE]; 694549Seric register char *p; 704549Seric struct cmd *c; 714549Seric char *cmd; 724549Seric extern char *skipword(); 734549Seric extern bool sameword(); 744549Seric bool hasmail; /* mail command received */ 754713Seric int rcps; /* number of recipients */ 765003Seric auto ADDRESS *vrfyqueue; 777124Seric extern char Version[]; 784549Seric 795003Seric hasmail = FALSE; 804713Seric rcps = 0; 81*7275Seric close(1); 82*7275Seric dup(fileno(OutChannel)); 837124Seric message("220", "%s Sendmail version %s at your service", HostName, Version); 844549Seric for (;;) 854549Seric { 866907Seric CurEnv->e_to = NULL; 874577Seric Errors = 0; 88*7275Seric (void) fflush(stdout); 894549Seric if (fgets(inp, sizeof inp, InChannel) == NULL) 904549Seric { 914549Seric /* end of file, just die */ 924558Seric message("421", "%s Lost input channel", HostName); 934549Seric finis(); 944549Seric } 954549Seric 964549Seric /* clean up end of line */ 974558Seric fixcrlf(inp, TRUE); 984549Seric 994713Seric /* echo command to transcript */ 1004713Seric fprintf(Xscript, "*** %s\n", inp); 1014713Seric 1024549Seric /* break off command */ 1034549Seric for (p = inp; isspace(*p); p++) 1044549Seric continue; 1054549Seric cmd = p; 1064549Seric while (*++p != '\0' && !isspace(*p)) 1074549Seric continue; 1084549Seric if (*p != '\0') 1094549Seric *p++ = '\0'; 1104549Seric 1114549Seric /* decode command */ 1124549Seric for (c = CmdTab; c->cmdname != NULL; c++) 1134549Seric { 1144549Seric if (sameword(c->cmdname, cmd)) 1154549Seric break; 1164549Seric } 1174549Seric 1184549Seric /* process command */ 1194549Seric switch (c->cmdcode) 1204549Seric { 1214976Seric case CMDHELO: /* hello -- introduce yourself */ 1225187Seric define('s', newstr(p)); 1234997Seric message("250", "%s Hello %s, pleased to meet you", 1244997Seric HostName, p); 1254976Seric break; 1264976Seric 1274549Seric case CMDMAIL: /* mail -- designate sender */ 1284558Seric if (hasmail) 1294558Seric { 1304558Seric message("503", "Sender already specified"); 1314558Seric break; 1324558Seric } 1334549Seric p = skipword(p, "from"); 1344549Seric if (p == NULL) 1354549Seric break; 1364549Seric if (index(p, ',') != NULL) 1374549Seric { 1384549Seric message("501", "Source routing not implemented"); 1394549Seric Errors++; 1404549Seric break; 1414549Seric } 1424549Seric setsender(p); 1434577Seric if (Errors == 0) 1444549Seric { 1454549Seric message("250", "Sender ok"); 1464549Seric hasmail = TRUE; 1474549Seric } 1484549Seric break; 1494549Seric 1504976Seric case CMDRCPT: /* rcpt -- designate recipient */ 1514549Seric p = skipword(p, "to"); 1524549Seric if (p == NULL) 1534549Seric break; 1544549Seric if (index(p, ',') != NULL) 1554549Seric { 1564549Seric message("501", "Source routing not implemented"); 1574549Seric Errors++; 1584549Seric break; 1594549Seric } 1606907Seric sendto(p, 1, (ADDRESS *) NULL, &CurEnv->e_sendqueue); 1614577Seric if (Errors == 0) 1624549Seric { 1636057Seric message("250", "%s... Recipient ok", p); 1644713Seric rcps++; 1654549Seric } 1664549Seric break; 1674549Seric 1684549Seric case CMDDATA: /* data -- text of mail */ 1694976Seric if (!hasmail) 1704549Seric { 1714976Seric message("503", "Need MAIL command"); 1724976Seric break; 1734549Seric } 1744713Seric else if (rcps <= 0) 1754549Seric { 1764976Seric message("503", "Need RCPT (recipient)"); 1774976Seric break; 1784549Seric } 1794976Seric 1804976Seric /* collect the text of the message */ 1814976Seric collect(TRUE); 1824976Seric if (Errors != 0) 1834976Seric break; 1844976Seric 1854976Seric /* if sending to multiple people, mail back errors */ 1864976Seric if (rcps != 1) 1874976Seric HoldErrs = MailBack = TRUE; 1884976Seric 1894976Seric /* send to all recipients */ 1907046Seric sendall(CurEnv, FALSE); 1914976Seric 1924976Seric /* reset strange modes */ 1934976Seric HoldErrs = FALSE; 1946907Seric CurEnv->e_to = NULL; 1954976Seric 1964976Seric /* issue success if appropriate */ 1974976Seric if (Errors == 0 || rcps != 1) 1984976Seric message("250", "Sent"); 1994549Seric break; 2004549Seric 2014549Seric case CMDRSET: /* rset -- reset state */ 2024549Seric message("250", "Reset state"); 2034549Seric finis(); 2044549Seric 2054549Seric case CMDVRFY: /* vrfy -- verify address */ 2065003Seric vrfyqueue = NULL; 2075003Seric sendto(p, 1, (ADDRESS *) NULL, &vrfyqueue); 2085003Seric while (vrfyqueue != NULL) 2095003Seric { 2105003Seric register ADDRESS *a = vrfyqueue->q_next; 2115003Seric char *code; 2125003Seric 2135003Seric while (a != NULL && bitset(QDONTSEND, a->q_flags)) 2145003Seric a = a->q_next; 2155003Seric 2165003Seric if (!bitset(QDONTSEND, vrfyqueue->q_flags)) 2175003Seric { 2185003Seric if (a != NULL) 2195003Seric code = "250-"; 2205003Seric else 2215003Seric code = "250"; 2225003Seric if (vrfyqueue->q_fullname == NULL) 2235003Seric message(code, "<%s>", vrfyqueue->q_paddr); 2245003Seric else 2255003Seric message(code, "%s <%s>", 2265003Seric vrfyqueue->q_fullname, vrfyqueue->q_paddr); 2275003Seric } 2285003Seric else if (a == NULL) 2295003Seric message("554", "Self destructive alias loop"); 2305003Seric vrfyqueue = a; 2315003Seric } 2324549Seric break; 2334549Seric 2344549Seric case CMDHELP: /* help -- give user info */ 2354577Seric if (*p == '\0') 2364577Seric p = "SMTP"; 2374577Seric help(p); 2384549Seric break; 2394549Seric 2404549Seric case CMDNOOP: /* noop -- do nothing */ 2414549Seric message("200", "OK"); 2424549Seric break; 2434549Seric 2444549Seric case CMDQUIT: /* quit -- leave mail */ 2454549Seric message("221", "%s closing connection", HostName); 2464549Seric finis(); 2474549Seric 2484577Seric case CMDMRSQ: /* mrsq -- negotiate protocol */ 2494577Seric if (*p == 'R' || *p == 'T') 2504577Seric { 2514577Seric /* recipients first or text first */ 2524577Seric message("200", "%c ok, please continue", *p); 2534577Seric } 2544577Seric else if (*p == '?') 2554577Seric { 2564577Seric /* what do I prefer? anything, anytime */ 2574577Seric message("215", "R Recipients first is my choice"); 2584577Seric } 2594577Seric else if (*p == '\0') 2604577Seric { 2614577Seric /* no meaningful scheme */ 2624577Seric message("200", "okey dokie boobie"); 2634577Seric } 2644577Seric else 2654577Seric { 2664577Seric /* bad argument */ 2674577Seric message("504", "Scheme unknown"); 2684577Seric } 2694577Seric break; 2704577Seric 2715003Seric # ifdef DEBUG 2725003Seric case CMDDBGSHOWQ: /* show queues */ 2736907Seric printf("Send Queue="); 2746907Seric printaddr(CurEnv->e_sendqueue, TRUE); 2755003Seric break; 276*7275Seric 277*7275Seric case CMDDBGDEBUG: /* set debug mode */ 278*7275Seric Debug = atoi(p); 279*7275Seric message("200", "Debug = %d", Debug); 280*7275Seric break; 281*7275Seric 282*7275Seric case CMDDBGVERBOSE: /* set verbose mode */ 283*7275Seric Verbose = TRUE; 284*7275Seric message("200", "Verbose mode"); 285*7275Seric break; 2865003Seric # endif DEBUG 2875003Seric 2884549Seric case CMDERROR: /* unknown command */ 2894549Seric message("500", "Command unrecognized"); 2904549Seric break; 2914549Seric 2924549Seric default: 2934549Seric syserr("smtp: unknown code %d", c->cmdcode); 2944549Seric break; 2954549Seric } 2964549Seric } 2974549Seric } 2984549Seric /* 2994549Seric ** SKIPWORD -- skip a fixed word. 3004549Seric ** 3014549Seric ** Parameters: 3024549Seric ** p -- place to start looking. 3034549Seric ** w -- word to skip. 3044549Seric ** 3054549Seric ** Returns: 3064549Seric ** p following w. 3074549Seric ** NULL on error. 3084549Seric ** 3094549Seric ** Side Effects: 3104549Seric ** clobbers the p data area. 3114549Seric */ 3124549Seric 3134549Seric static char * 3144549Seric skipword(p, w) 3154549Seric register char *p; 3164549Seric char *w; 3174549Seric { 3184549Seric register char *q; 3194549Seric extern bool sameword(); 3204549Seric 3214549Seric /* find beginning of word */ 3224549Seric while (isspace(*p)) 3234549Seric p++; 3244549Seric q = p; 3254549Seric 3264549Seric /* find end of word */ 3274549Seric while (*p != '\0' && *p != ':' && !isspace(*p)) 3284549Seric p++; 3294549Seric while (isspace(*p)) 3304549Seric *p++ = '\0'; 3314549Seric if (*p != ':') 3324549Seric { 3334549Seric syntax: 3344549Seric message("501", "Syntax error"); 3354549Seric Errors++; 3364549Seric return (NULL); 3374549Seric } 3384549Seric *p++ = '\0'; 3394549Seric while (isspace(*p)) 3404549Seric p++; 3414549Seric 3424549Seric /* see if the input word matches desired word */ 3434549Seric if (!sameword(q, w)) 3444549Seric goto syntax; 3454549Seric 3464549Seric return (p); 3474549Seric } 3484577Seric /* 3494577Seric ** HELP -- implement the HELP command. 3504577Seric ** 3514577Seric ** Parameters: 3524577Seric ** topic -- the topic we want help for. 3534577Seric ** 3544577Seric ** Returns: 3554577Seric ** none. 3564577Seric ** 3574577Seric ** Side Effects: 3584577Seric ** outputs the help file to message output. 3594577Seric */ 3604577Seric 3614577Seric help(topic) 3624577Seric char *topic; 3634577Seric { 3644577Seric register FILE *hf; 3654577Seric int len; 3664577Seric char buf[MAXLINE]; 3674577Seric bool noinfo; 3684582Seric extern char *HelpFile; 3694577Seric 3704582Seric hf = fopen(HelpFile, "r"); 3714577Seric if (hf == NULL) 3724577Seric { 3734577Seric /* no help */ 3744577Seric message("502", "HELP not implemented"); 3754577Seric return; 3764577Seric } 3774577Seric 3784577Seric len = strlen(topic); 3794577Seric makelower(topic); 3804577Seric noinfo = TRUE; 3814577Seric 3824577Seric while (fgets(buf, sizeof buf, hf) != NULL) 3834577Seric { 3844577Seric if (strncmp(buf, topic, len) == 0) 3854577Seric { 3864577Seric register char *p; 3874577Seric 3884577Seric p = index(buf, '\t'); 3894577Seric if (p == NULL) 3904577Seric p = buf; 3914577Seric else 3924577Seric p++; 3934577Seric fixcrlf(p, TRUE); 3944577Seric message("214-", p); 3954577Seric noinfo = FALSE; 3964577Seric } 3974577Seric } 3984577Seric 3994577Seric if (noinfo) 4004577Seric message("504", "HELP topic unknown"); 4014577Seric else 4024577Seric message("214", "End of HELP info"); 4034628Seric (void) fclose(hf); 4044577Seric } 4055181Seric 4065181Seric # endif SMTP 407