1*4549Seric # include "sendmail.h" 2*4549Seric 3*4549Seric /* 4*4549Seric ** SMTP -- run the SMTP protocol. 5*4549Seric ** 6*4549Seric ** Parameters: 7*4549Seric ** none. 8*4549Seric ** 9*4549Seric ** Returns: 10*4549Seric ** never. 11*4549Seric ** 12*4549Seric ** Side Effects: 13*4549Seric ** Reads commands from the input channel and processes 14*4549Seric ** them. 15*4549Seric */ 16*4549Seric 17*4549Seric struct cmd 18*4549Seric { 19*4549Seric char *cmdname; /* command name */ 20*4549Seric int cmdcode; /* internal code, see below */ 21*4549Seric }; 22*4549Seric 23*4549Seric /* values for cmdcode */ 24*4549Seric # define CMDERROR 0 /* bad command */ 25*4549Seric # define CMDMAIL 1 /* mail -- designate sender */ 26*4549Seric # define CMDMRCP 2 /* mrcp -- designate recipient */ 27*4549Seric # define CMDDATA 3 /* data -- send message text */ 28*4549Seric # define CMDDOIT 4 /* doit -- actually do delivery */ 29*4549Seric # define CMDRSET 5 /* rset -- reset state */ 30*4549Seric # define CMDVRFY 6 /* vrfy -- verify address */ 31*4549Seric # define CMDHELP 7 /* help -- give usage info */ 32*4549Seric # define CMDNOOP 8 /* noop -- do nothing */ 33*4549Seric # define CMDQUIT 9 /* quit -- close connection and die */ 34*4549Seric 35*4549Seric static struct cmd CmdTab[] = 36*4549Seric { 37*4549Seric "mail", CMDMAIL, 38*4549Seric "mrcp", CMDMRCP, 39*4549Seric "data", CMDDATA, 40*4549Seric "doit", CMDDOIT, 41*4549Seric "rset", CMDRSET, 42*4549Seric "vrfy", CMDVRFY, 43*4549Seric "help", CMDHELP, 44*4549Seric "noop", CMDNOOP, 45*4549Seric "quit", CMDQUIT, 46*4549Seric NULL, CMDERROR, 47*4549Seric }; 48*4549Seric 49*4549Seric smtp() 50*4549Seric { 51*4549Seric char inp[MAXLINE]; 52*4549Seric register char *p; 53*4549Seric struct cmd *c; 54*4549Seric char *cmd; 55*4549Seric extern char *skipword(); 56*4549Seric extern bool sameword(); 57*4549Seric bool hasmail; /* mail command received */ 58*4549Seric bool hasmrcp; /* has a recipient */ 59*4549Seric bool hasdata; /* has mail data */ 60*4549Seric 61*4549Seric /*%%%*/ HostName = "XYZZY"; 62*4549Seric hasmail = hasmrcp = hasdata = FALSE; 63*4549Seric message("220", "%s Sendmail at your service", HostName); 64*4549Seric for (;;) 65*4549Seric { 66*4549Seric To = NULL; 67*4549Seric Errors = 0; 68*4549Seric if (fgets(inp, sizeof inp, InChannel) == NULL) 69*4549Seric { 70*4549Seric /* end of file, just die */ 71*4549Seric message("421", "Lost input channel"); 72*4549Seric finis(); 73*4549Seric } 74*4549Seric 75*4549Seric /* clean up end of line */ 76*4549Seric p = index(inp, '\n'); 77*4549Seric if (p != NULL) 78*4549Seric *p = '\0'; 79*4549Seric p = index(inp, '\r'); 80*4549Seric if (p != NULL) 81*4549Seric *p = '\0'; 82*4549Seric 83*4549Seric /* break off command */ 84*4549Seric for (p = inp; isspace(*p); p++) 85*4549Seric continue; 86*4549Seric cmd = p; 87*4549Seric while (*++p != '\0' && !isspace(*p)) 88*4549Seric continue; 89*4549Seric if (*p != '\0') 90*4549Seric *p++ = '\0'; 91*4549Seric 92*4549Seric /* decode command */ 93*4549Seric for (c = CmdTab; c->cmdname != NULL; c++) 94*4549Seric { 95*4549Seric if (sameword(c->cmdname, cmd)) 96*4549Seric break; 97*4549Seric } 98*4549Seric 99*4549Seric /* process command */ 100*4549Seric switch (c->cmdcode) 101*4549Seric { 102*4549Seric case CMDMAIL: /* mail -- designate sender */ 103*4549Seric p = skipword(p, "from"); 104*4549Seric if (p == NULL) 105*4549Seric break; 106*4549Seric if (index(p, ',') != NULL) 107*4549Seric { 108*4549Seric message("501", "Source routing not implemented"); 109*4549Seric Errors++; 110*4549Seric break; 111*4549Seric } 112*4549Seric setsender(p); 113*4549Seric if (Errors == 0) 114*4549Seric { 115*4549Seric message("250", "Sender ok"); 116*4549Seric hasmail = TRUE; 117*4549Seric } 118*4549Seric break; 119*4549Seric 120*4549Seric case CMDMRCP: /* mrcp -- designate recipient */ 121*4549Seric p = skipword(p, "to"); 122*4549Seric if (p == NULL) 123*4549Seric break; 124*4549Seric if (index(p, ',') != NULL) 125*4549Seric { 126*4549Seric message("501", "Source routing not implemented"); 127*4549Seric Errors++; 128*4549Seric break; 129*4549Seric } 130*4549Seric sendto(p, 1, NULL); 131*4549Seric if (Errors == 0) 132*4549Seric { 133*4549Seric message("250", "Recipient ok"); 134*4549Seric hasmrcp = TRUE; 135*4549Seric } 136*4549Seric break; 137*4549Seric 138*4549Seric case CMDDATA: /* data -- text of mail */ 139*4549Seric message("354", "Enter mail, end with dot"); 140*4549Seric collect(); 141*4549Seric if (Errors == 0) 142*4549Seric { 143*4549Seric message("250", "Message stored"); 144*4549Seric hasdata = TRUE; 145*4549Seric } 146*4549Seric break; 147*4549Seric 148*4549Seric case CMDDOIT: /* doit -- actually send everything */ 149*4549Seric if (!hasmail) 150*4549Seric message("503", "Need MAIL command"); 151*4549Seric else if (!hasmrcp) 152*4549Seric message("503", "Need MRCP (recipient)"); 153*4549Seric else if (!hasdata) 154*4549Seric message("503", "No message, use DATA"); 155*4549Seric else 156*4549Seric { 157*4549Seric sendall(FALSE); 158*4549Seric if (Errors == 0) 159*4549Seric message("250", "Sent"); 160*4549Seric } 161*4549Seric break; 162*4549Seric 163*4549Seric case CMDRSET: /* rset -- reset state */ 164*4549Seric message("250", "Reset state"); 165*4549Seric finis(); 166*4549Seric 167*4549Seric case CMDVRFY: /* vrfy -- verify address */ 168*4549Seric sendto(p, 1, NULL); 169*4549Seric if (Errors == 0) 170*4549Seric message("250", "user ok"); 171*4549Seric break; 172*4549Seric 173*4549Seric case CMDHELP: /* help -- give user info */ 174*4549Seric message("502", "HELP not implemented"); 175*4549Seric break; 176*4549Seric 177*4549Seric case CMDNOOP: /* noop -- do nothing */ 178*4549Seric message("200", "OK"); 179*4549Seric break; 180*4549Seric 181*4549Seric case CMDQUIT: /* quit -- leave mail */ 182*4549Seric message("221", "%s closing connection", HostName); 183*4549Seric finis(); 184*4549Seric 185*4549Seric case CMDERROR: /* unknown command */ 186*4549Seric message("500", "Command unrecognized"); 187*4549Seric break; 188*4549Seric 189*4549Seric default: 190*4549Seric syserr("smtp: unknown code %d", c->cmdcode); 191*4549Seric break; 192*4549Seric } 193*4549Seric } 194*4549Seric } 195*4549Seric /* 196*4549Seric ** SKIPWORD -- skip a fixed word. 197*4549Seric ** 198*4549Seric ** Parameters: 199*4549Seric ** p -- place to start looking. 200*4549Seric ** w -- word to skip. 201*4549Seric ** 202*4549Seric ** Returns: 203*4549Seric ** p following w. 204*4549Seric ** NULL on error. 205*4549Seric ** 206*4549Seric ** Side Effects: 207*4549Seric ** clobbers the p data area. 208*4549Seric */ 209*4549Seric 210*4549Seric static char * 211*4549Seric skipword(p, w) 212*4549Seric register char *p; 213*4549Seric char *w; 214*4549Seric { 215*4549Seric register char *q; 216*4549Seric extern bool sameword(); 217*4549Seric 218*4549Seric /* find beginning of word */ 219*4549Seric while (isspace(*p)) 220*4549Seric p++; 221*4549Seric q = p; 222*4549Seric 223*4549Seric /* find end of word */ 224*4549Seric while (*p != '\0' && *p != ':' && !isspace(*p)) 225*4549Seric p++; 226*4549Seric while (isspace(*p)) 227*4549Seric *p++ = '\0'; 228*4549Seric if (*p != ':') 229*4549Seric { 230*4549Seric syntax: 231*4549Seric message("501", "Syntax error"); 232*4549Seric Errors++; 233*4549Seric return (NULL); 234*4549Seric } 235*4549Seric *p++ = '\0'; 236*4549Seric while (isspace(*p)) 237*4549Seric p++; 238*4549Seric 239*4549Seric /* see if the input word matches desired word */ 240*4549Seric if (!sameword(q, w)) 241*4549Seric goto syntax; 242*4549Seric 243*4549Seric return (p); 244*4549Seric } 245