1 # include "sendmail.h" 2 3 static char SccsId[] = "@(#)srvrsmtp.c 3.6 10/26/81"; 4 5 /* 6 ** SMTP -- run the SMTP protocol. 7 ** 8 ** Parameters: 9 ** none. 10 ** 11 ** Returns: 12 ** never. 13 ** 14 ** Side Effects: 15 ** Reads commands from the input channel and processes 16 ** them. 17 */ 18 19 struct cmd 20 { 21 char *cmdname; /* command name */ 22 int cmdcode; /* internal code, see below */ 23 }; 24 25 /* values for cmdcode */ 26 # define CMDERROR 0 /* bad command */ 27 # define CMDMAIL 1 /* mail -- designate sender */ 28 # define CMDMRCP 2 /* mrcp -- designate recipient */ 29 # define CMDDATA 3 /* data -- send message text */ 30 # define CMDDOIT 4 /* doit -- actually do delivery */ 31 # define CMDRSET 5 /* rset -- reset state */ 32 # define CMDVRFY 6 /* vrfy -- verify address */ 33 # define CMDHELP 7 /* help -- give usage info */ 34 # define CMDNOOP 8 /* noop -- do nothing */ 35 # define CMDQUIT 9 /* quit -- close connection and die */ 36 # define CMDMRSQ 10 /* mrsq -- for old mtp compat only */ 37 38 static struct cmd CmdTab[] = 39 { 40 "mail", CMDMAIL, 41 "mrcp", CMDMRCP, 42 "data", CMDDATA, 43 "doit", CMDDOIT, 44 "rset", CMDRSET, 45 "vrfy", CMDVRFY, 46 "help", CMDHELP, 47 "noop", CMDNOOP, 48 "quit", CMDQUIT, 49 "mrsq", CMDMRSQ, 50 NULL, CMDERROR, 51 }; 52 53 smtp() 54 { 55 char inp[MAXLINE]; 56 register char *p; 57 struct cmd *c; 58 char *cmd; 59 extern char *skipword(); 60 extern bool sameword(); 61 bool hasmail; /* mail command received */ 62 bool hasmrcp; /* has a recipient */ 63 bool hasdata; /* has mail data */ 64 65 hasmail = hasmrcp = hasdata = FALSE; 66 message("220", "%s Sendmail at your service", HostName); 67 for (;;) 68 { 69 To = NULL; 70 Errors = 0; 71 if (fgets(inp, sizeof inp, InChannel) == NULL) 72 { 73 /* end of file, just die */ 74 message("421", "%s Lost input channel", HostName); 75 finis(); 76 } 77 78 /* clean up end of line */ 79 fixcrlf(inp, TRUE); 80 81 /* break off command */ 82 for (p = inp; isspace(*p); p++) 83 continue; 84 cmd = p; 85 while (*++p != '\0' && !isspace(*p)) 86 continue; 87 if (*p != '\0') 88 *p++ = '\0'; 89 90 /* decode command */ 91 for (c = CmdTab; c->cmdname != NULL; c++) 92 { 93 if (sameword(c->cmdname, cmd)) 94 break; 95 } 96 97 /* process command */ 98 switch (c->cmdcode) 99 { 100 case CMDMAIL: /* mail -- designate sender */ 101 if (hasmail) 102 { 103 message("503", "Sender already specified"); 104 break; 105 } 106 p = skipword(p, "from"); 107 if (p == NULL) 108 break; 109 if (index(p, ',') != NULL) 110 { 111 message("501", "Source routing not implemented"); 112 Errors++; 113 break; 114 } 115 setsender(p); 116 if (Errors == 0) 117 { 118 message("250", "Sender ok"); 119 hasmail = TRUE; 120 } 121 break; 122 123 case CMDMRCP: /* mrcp -- designate recipient */ 124 p = skipword(p, "to"); 125 if (p == NULL) 126 break; 127 if (index(p, ',') != NULL) 128 { 129 message("501", "Source routing not implemented"); 130 Errors++; 131 break; 132 } 133 sendto(p, 1, (ADDRESS *) NULL); 134 if (Errors == 0) 135 { 136 message("250", "Recipient ok"); 137 hasmrcp = TRUE; 138 } 139 break; 140 141 case CMDDATA: /* data -- text of mail */ 142 message("354", "Enter mail, end with dot"); 143 collect(); 144 if (Errors == 0) 145 { 146 message("250", "Message stored"); 147 hasdata = TRUE; 148 } 149 break; 150 151 case CMDDOIT: /* doit -- actually send everything */ 152 if (!hasmail) 153 message("503", "Need MAIL command"); 154 else if (!hasmrcp) 155 message("503", "Need MRCP (recipient)"); 156 else if (!hasdata) 157 message("503", "No message, use DATA"); 158 else 159 { 160 sendall(FALSE); 161 if (Errors == 0) 162 message("250", "Sent"); 163 } 164 break; 165 166 case CMDRSET: /* rset -- reset state */ 167 message("250", "Reset state"); 168 finis(); 169 170 case CMDVRFY: /* vrfy -- verify address */ 171 sendto(p, 1, (ADDRESS *) NULL); 172 if (Errors == 0) 173 message("250", "user ok"); 174 break; 175 176 case CMDHELP: /* help -- give user info */ 177 if (*p == '\0') 178 p = "SMTP"; 179 help(p); 180 break; 181 182 case CMDNOOP: /* noop -- do nothing */ 183 message("200", "OK"); 184 break; 185 186 case CMDQUIT: /* quit -- leave mail */ 187 message("221", "%s closing connection", HostName); 188 finis(); 189 190 case CMDMRSQ: /* mrsq -- negotiate protocol */ 191 if (*p == 'R' || *p == 'T') 192 { 193 /* recipients first or text first */ 194 message("200", "%c ok, please continue", *p); 195 } 196 else if (*p == '?') 197 { 198 /* what do I prefer? anything, anytime */ 199 message("215", "R Recipients first is my choice"); 200 } 201 else if (*p == '\0') 202 { 203 /* no meaningful scheme */ 204 message("200", "okey dokie boobie"); 205 } 206 else 207 { 208 /* bad argument */ 209 message("504", "Scheme unknown"); 210 } 211 break; 212 213 case CMDERROR: /* unknown command */ 214 message("500", "Command unrecognized"); 215 break; 216 217 default: 218 syserr("smtp: unknown code %d", c->cmdcode); 219 break; 220 } 221 } 222 } 223 /* 224 ** SKIPWORD -- skip a fixed word. 225 ** 226 ** Parameters: 227 ** p -- place to start looking. 228 ** w -- word to skip. 229 ** 230 ** Returns: 231 ** p following w. 232 ** NULL on error. 233 ** 234 ** Side Effects: 235 ** clobbers the p data area. 236 */ 237 238 static char * 239 skipword(p, w) 240 register char *p; 241 char *w; 242 { 243 register char *q; 244 extern bool sameword(); 245 246 /* find beginning of word */ 247 while (isspace(*p)) 248 p++; 249 q = p; 250 251 /* find end of word */ 252 while (*p != '\0' && *p != ':' && !isspace(*p)) 253 p++; 254 while (isspace(*p)) 255 *p++ = '\0'; 256 if (*p != ':') 257 { 258 syntax: 259 message("501", "Syntax error"); 260 Errors++; 261 return (NULL); 262 } 263 *p++ = '\0'; 264 while (isspace(*p)) 265 p++; 266 267 /* see if the input word matches desired word */ 268 if (!sameword(q, w)) 269 goto syntax; 270 271 return (p); 272 } 273 /* 274 ** HELP -- implement the HELP command. 275 ** 276 ** Parameters: 277 ** topic -- the topic we want help for. 278 ** 279 ** Returns: 280 ** none. 281 ** 282 ** Side Effects: 283 ** outputs the help file to message output. 284 */ 285 286 help(topic) 287 char *topic; 288 { 289 register FILE *hf; 290 int len; 291 char buf[MAXLINE]; 292 bool noinfo; 293 extern char *HelpFile; 294 295 hf = fopen(HelpFile, "r"); 296 if (hf == NULL) 297 { 298 /* no help */ 299 message("502", "HELP not implemented"); 300 return; 301 } 302 303 len = strlen(topic); 304 makelower(topic); 305 noinfo = TRUE; 306 307 while (fgets(buf, sizeof buf, hf) != NULL) 308 { 309 if (strncmp(buf, topic, len) == 0) 310 { 311 register char *p; 312 313 p = index(buf, '\t'); 314 if (p == NULL) 315 p = buf; 316 else 317 p++; 318 fixcrlf(p, TRUE); 319 message("214-", p); 320 noinfo = FALSE; 321 } 322 } 323 324 if (noinfo) 325 message("504", "HELP topic unknown"); 326 else 327 message("214", "End of HELP info"); 328 (void) fclose(hf); 329 } 330