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