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