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