1 # include "sendmail.h" 2 3 # ifndef SMTP 4 SCCSID(@(#)srvrsmtp.c 3.17 06/07/82 (no SMTP)); 5 # else SMTP 6 7 SCCSID(@(#)srvrsmtp.c 3.17 06/07/82); 8 9 /* 10 ** SMTP -- run the SMTP protocol. 11 ** 12 ** Parameters: 13 ** none. 14 ** 15 ** Returns: 16 ** never. 17 ** 18 ** Side Effects: 19 ** Reads commands from the input channel and processes 20 ** them. 21 */ 22 23 struct cmd 24 { 25 char *cmdname; /* command name */ 26 int cmdcode; /* internal code, see below */ 27 }; 28 29 /* values for cmdcode */ 30 # define CMDERROR 0 /* bad command */ 31 # define CMDMAIL 1 /* mail -- designate sender */ 32 # define CMDRCPT 2 /* rcpt -- designate recipient */ 33 # define CMDDATA 3 /* data -- send message text */ 34 # define CMDRSET 5 /* rset -- reset state */ 35 # define CMDVRFY 6 /* vrfy -- verify address */ 36 # define CMDHELP 7 /* help -- give usage info */ 37 # define CMDNOOP 8 /* noop -- do nothing */ 38 # define CMDQUIT 9 /* quit -- close connection and die */ 39 # define CMDMRSQ 10 /* mrsq -- for old mtp compat only */ 40 # define CMDHELO 11 /* helo -- be polite */ 41 # define CMDDBGSHOWQ 12 /* showq -- show send queue (DEBUG) */ 42 43 static struct cmd CmdTab[] = 44 { 45 "mail", CMDMAIL, 46 "rcpt", CMDRCPT, 47 "mrcp", CMDRCPT, /* for old MTP compatability */ 48 "data", CMDDATA, 49 "rset", CMDRSET, 50 "vrfy", CMDVRFY, 51 "help", CMDHELP, 52 "noop", CMDNOOP, 53 "quit", CMDQUIT, 54 "mrsq", CMDMRSQ, 55 "helo", CMDHELO, 56 # ifdef DEBUG 57 "showq", CMDDBGSHOWQ, 58 # endif DEBUG 59 NULL, CMDERROR, 60 }; 61 62 smtp() 63 { 64 char inp[MAXLINE]; 65 register char *p; 66 struct cmd *c; 67 char *cmd; 68 extern char *skipword(); 69 extern bool sameword(); 70 bool hasmail; /* mail command received */ 71 int rcps; /* number of recipients */ 72 auto ADDRESS *vrfyqueue; 73 extern char Version[]; 74 75 hasmail = FALSE; 76 rcps = 0; 77 message("220", "%s Sendmail version %s at your service", HostName, Version); 78 for (;;) 79 { 80 CurEnv->e_to = NULL; 81 Errors = 0; 82 if (fgets(inp, sizeof inp, InChannel) == NULL) 83 { 84 /* end of file, just die */ 85 message("421", "%s Lost input channel", HostName); 86 finis(); 87 } 88 89 /* clean up end of line */ 90 fixcrlf(inp, TRUE); 91 92 /* echo command to transcript */ 93 fprintf(Xscript, "*** %s\n", inp); 94 95 /* break off command */ 96 for (p = inp; isspace(*p); p++) 97 continue; 98 cmd = p; 99 while (*++p != '\0' && !isspace(*p)) 100 continue; 101 if (*p != '\0') 102 *p++ = '\0'; 103 104 /* decode command */ 105 for (c = CmdTab; c->cmdname != NULL; c++) 106 { 107 if (sameword(c->cmdname, cmd)) 108 break; 109 } 110 111 /* process command */ 112 switch (c->cmdcode) 113 { 114 case CMDHELO: /* hello -- introduce yourself */ 115 define('s', newstr(p)); 116 message("250", "%s Hello %s, pleased to meet you", 117 HostName, p); 118 break; 119 120 case CMDMAIL: /* mail -- designate sender */ 121 if (hasmail) 122 { 123 message("503", "Sender already specified"); 124 break; 125 } 126 p = skipword(p, "from"); 127 if (p == NULL) 128 break; 129 if (index(p, ',') != NULL) 130 { 131 message("501", "Source routing not implemented"); 132 Errors++; 133 break; 134 } 135 setsender(p); 136 if (Errors == 0) 137 { 138 message("250", "Sender ok"); 139 hasmail = TRUE; 140 } 141 break; 142 143 case CMDRCPT: /* rcpt -- designate recipient */ 144 p = skipword(p, "to"); 145 if (p == NULL) 146 break; 147 if (index(p, ',') != NULL) 148 { 149 message("501", "Source routing not implemented"); 150 Errors++; 151 break; 152 } 153 sendto(p, 1, (ADDRESS *) NULL, &CurEnv->e_sendqueue); 154 if (Errors == 0) 155 { 156 message("250", "%s... Recipient ok", p); 157 rcps++; 158 } 159 break; 160 161 case CMDDATA: /* data -- text of mail */ 162 if (!hasmail) 163 { 164 message("503", "Need MAIL command"); 165 break; 166 } 167 else if (rcps <= 0) 168 { 169 message("503", "Need RCPT (recipient)"); 170 break; 171 } 172 173 /* collect the text of the message */ 174 collect(TRUE); 175 if (Errors != 0) 176 break; 177 178 /* if sending to multiple people, mail back errors */ 179 if (rcps != 1) 180 HoldErrs = MailBack = TRUE; 181 182 /* send to all recipients */ 183 sendall(CurEnv, FALSE); 184 185 /* reset strange modes */ 186 HoldErrs = FALSE; 187 CurEnv->e_to = NULL; 188 189 /* issue success if appropriate */ 190 if (Errors == 0 || rcps != 1) 191 message("250", "Sent"); 192 break; 193 194 case CMDRSET: /* rset -- reset state */ 195 message("250", "Reset state"); 196 finis(); 197 198 case CMDVRFY: /* vrfy -- verify address */ 199 vrfyqueue = NULL; 200 sendto(p, 1, (ADDRESS *) NULL, &vrfyqueue); 201 while (vrfyqueue != NULL) 202 { 203 register ADDRESS *a = vrfyqueue->q_next; 204 char *code; 205 206 while (a != NULL && bitset(QDONTSEND, a->q_flags)) 207 a = a->q_next; 208 209 if (!bitset(QDONTSEND, vrfyqueue->q_flags)) 210 { 211 if (a != NULL) 212 code = "250-"; 213 else 214 code = "250"; 215 if (vrfyqueue->q_fullname == NULL) 216 message(code, "<%s>", vrfyqueue->q_paddr); 217 else 218 message(code, "%s <%s>", 219 vrfyqueue->q_fullname, vrfyqueue->q_paddr); 220 } 221 else if (a == NULL) 222 message("554", "Self destructive alias loop"); 223 vrfyqueue = a; 224 } 225 break; 226 227 case CMDHELP: /* help -- give user info */ 228 if (*p == '\0') 229 p = "SMTP"; 230 help(p); 231 break; 232 233 case CMDNOOP: /* noop -- do nothing */ 234 message("200", "OK"); 235 break; 236 237 case CMDQUIT: /* quit -- leave mail */ 238 message("221", "%s closing connection", HostName); 239 finis(); 240 241 case CMDMRSQ: /* mrsq -- negotiate protocol */ 242 if (*p == 'R' || *p == 'T') 243 { 244 /* recipients first or text first */ 245 message("200", "%c ok, please continue", *p); 246 } 247 else if (*p == '?') 248 { 249 /* what do I prefer? anything, anytime */ 250 message("215", "R Recipients first is my choice"); 251 } 252 else if (*p == '\0') 253 { 254 /* no meaningful scheme */ 255 message("200", "okey dokie boobie"); 256 } 257 else 258 { 259 /* bad argument */ 260 message("504", "Scheme unknown"); 261 } 262 break; 263 264 # ifdef DEBUG 265 case CMDDBGSHOWQ: /* show queues */ 266 printf("Send Queue="); 267 printaddr(CurEnv->e_sendqueue, TRUE); 268 break; 269 # endif DEBUG 270 271 case CMDERROR: /* unknown command */ 272 message("500", "Command unrecognized"); 273 break; 274 275 default: 276 syserr("smtp: unknown code %d", c->cmdcode); 277 break; 278 } 279 } 280 } 281 /* 282 ** SKIPWORD -- skip a fixed word. 283 ** 284 ** Parameters: 285 ** p -- place to start looking. 286 ** w -- word to skip. 287 ** 288 ** Returns: 289 ** p following w. 290 ** NULL on error. 291 ** 292 ** Side Effects: 293 ** clobbers the p data area. 294 */ 295 296 static char * 297 skipword(p, w) 298 register char *p; 299 char *w; 300 { 301 register char *q; 302 extern bool sameword(); 303 304 /* find beginning of word */ 305 while (isspace(*p)) 306 p++; 307 q = p; 308 309 /* find end of word */ 310 while (*p != '\0' && *p != ':' && !isspace(*p)) 311 p++; 312 while (isspace(*p)) 313 *p++ = '\0'; 314 if (*p != ':') 315 { 316 syntax: 317 message("501", "Syntax error"); 318 Errors++; 319 return (NULL); 320 } 321 *p++ = '\0'; 322 while (isspace(*p)) 323 p++; 324 325 /* see if the input word matches desired word */ 326 if (!sameword(q, w)) 327 goto syntax; 328 329 return (p); 330 } 331 /* 332 ** HELP -- implement the HELP command. 333 ** 334 ** Parameters: 335 ** topic -- the topic we want help for. 336 ** 337 ** Returns: 338 ** none. 339 ** 340 ** Side Effects: 341 ** outputs the help file to message output. 342 */ 343 344 help(topic) 345 char *topic; 346 { 347 register FILE *hf; 348 int len; 349 char buf[MAXLINE]; 350 bool noinfo; 351 extern char *HelpFile; 352 353 hf = fopen(HelpFile, "r"); 354 if (hf == NULL) 355 { 356 /* no help */ 357 message("502", "HELP not implemented"); 358 return; 359 } 360 361 len = strlen(topic); 362 makelower(topic); 363 noinfo = TRUE; 364 365 while (fgets(buf, sizeof buf, hf) != NULL) 366 { 367 if (strncmp(buf, topic, len) == 0) 368 { 369 register char *p; 370 371 p = index(buf, '\t'); 372 if (p == NULL) 373 p = buf; 374 else 375 p++; 376 fixcrlf(p, TRUE); 377 message("214-", p); 378 noinfo = FALSE; 379 } 380 } 381 382 if (noinfo) 383 message("504", "HELP topic unknown"); 384 else 385 message("214", "End of HELP info"); 386 (void) fclose(hf); 387 } 388 389 # endif SMTP 390