1 # include <ctype.h> 2 # include <sysexits.h> 3 # include "sendmail.h" 4 5 # ifndef SMTP 6 SCCSID(@(#)usersmtp.c 3.37 01/09/83 (no SMTP)); 7 # else SMTP 8 9 SCCSID(@(#)usersmtp.c 3.37 01/09/83); 10 11 12 13 /* 14 ** USERSMTP -- run SMTP protocol from the user end. 15 ** 16 ** This protocol is described in RFC821. 17 */ 18 19 #define REPLYTYPE(r) ((r) / 100) /* first digit of reply code */ 20 #define REPLYCLASS(r) (((r) / 10) % 10) /* second digit of reply code */ 21 #define SMTPCLOSING 421 /* "Service Shutting Down" */ 22 23 char SmtpReplyBuffer[MAXLINE]; /* buffer for replies */ 24 FILE *SmtpOut; /* output file */ 25 FILE *SmtpIn; /* input file */ 26 int SmtpPid; /* pid of mailer */ 27 bool SmtpClosing; /* set on a forced close */ 28 /* 29 ** SMTPINIT -- initialize SMTP. 30 ** 31 ** Opens the connection and sends the initial protocol. 32 ** 33 ** Parameters: 34 ** m -- mailer to create connection to. 35 ** pvp -- pointer to parameter vector to pass to 36 ** the mailer. 37 ** 38 ** Returns: 39 ** appropriate exit status -- EX_OK on success. 40 ** 41 ** Side Effects: 42 ** creates connection and sends initial protocol. 43 */ 44 45 smtpinit(m, pvp) 46 struct mailer *m; 47 char **pvp; 48 { 49 register int r; 50 char buf[MAXNAME]; 51 extern char *canonname(); 52 53 /* 54 ** Open the connection to the mailer. 55 */ 56 57 SmtpIn = SmtpOut = NULL; 58 SmtpClosing = FALSE; 59 SmtpPid = openmailer(m, pvp, (ADDRESS *) NULL, TRUE, &SmtpOut, &SmtpIn); 60 if (SmtpPid < 0) 61 { 62 # ifdef DEBUG 63 if (tTd(18, 1)) 64 printf("smtpinit: cannot open %s: stat %d errno %d\n", 65 pvp[0], ExitStat, errno); 66 # endif DEBUG 67 return (ExitStat); 68 } 69 70 /* 71 ** Get the greeting message. 72 ** This should appear spontaneously. 73 */ 74 75 r = reply(m); 76 if (r < 0 || REPLYTYPE(r) != 2) 77 return (EX_TEMPFAIL); 78 79 /* 80 ** Send the HELO command. 81 ** My mother taught me to always introduce myself. 82 */ 83 84 smtpmessage("HELO %s", m, HostName); 85 r = reply(m); 86 if (r < 0) 87 return (EX_TEMPFAIL); 88 else if (REPLYTYPE(r) == 5) 89 return (EX_UNAVAILABLE); 90 else if (REPLYTYPE(r) != 2) 91 return (EX_TEMPFAIL); 92 93 /* 94 ** If this is expected to be another sendmail, send some internal 95 ** commands. 96 */ 97 98 if (bitset(M_INTERNAL, m->m_flags)) 99 { 100 /* tell it to be verbose */ 101 smtpmessage("VERB", m); 102 r = reply(m); 103 if (r < 0) 104 return (EX_TEMPFAIL); 105 106 /* tell it we will be sending one transaction only */ 107 smtpmessage("ONEX", m); 108 r = reply(m); 109 if (r < 0) 110 return (EX_TEMPFAIL); 111 } 112 113 /* 114 ** Send the MAIL command. 115 ** Designates the sender. 116 */ 117 118 expand("$g", buf, &buf[sizeof buf - 1], CurEnv); 119 if (CurEnv->e_from.q_mailer == LocalMailer || 120 !bitset(M_FROMPATH, m->m_flags)) 121 { 122 smtpmessage("MAIL From:<%s>", m, canonname(buf, 1)); 123 } 124 else 125 { 126 smtpmessage("MAIL From:<@%s%c%s>", m, HostName, 127 buf[0] == '@' ? ',' : ':', canonname(buf, 1)); 128 } 129 r = reply(m); 130 if (r < 0 || REPLYTYPE(r) == 4) 131 return (EX_TEMPFAIL); 132 else if (r == 250) 133 return (EX_OK); 134 else if (r == 552) 135 return (EX_UNAVAILABLE); 136 return (EX_PROTOCOL); 137 } 138 /* 139 ** SMTPRCPT -- designate recipient. 140 ** 141 ** Parameters: 142 ** to -- address of recipient. 143 ** m -- the mailer we are sending to. 144 ** 145 ** Returns: 146 ** exit status corresponding to recipient status. 147 ** 148 ** Side Effects: 149 ** Sends the mail via SMTP. 150 */ 151 152 smtprcpt(to, m) 153 ADDRESS *to; 154 register MAILER *m; 155 { 156 register int r; 157 extern char *canonname(); 158 159 smtpmessage("RCPT To:<%s>", m, canonname(to->q_user, 2)); 160 161 r = reply(m); 162 if (r < 0 || REPLYTYPE(r) == 4) 163 return (EX_TEMPFAIL); 164 else if (REPLYTYPE(r) == 2) 165 return (EX_OK); 166 else if (r == 550 || r == 551 || r == 553) 167 return (EX_NOUSER); 168 else if (r == 552 || r == 554) 169 return (EX_UNAVAILABLE); 170 return (EX_PROTOCOL); 171 } 172 /* 173 ** SMTPDATA -- send the data and clean up the transaction. 174 ** 175 ** Parameters: 176 ** m -- mailer being sent to. 177 ** e -- the envelope for this message. 178 ** 179 ** Returns: 180 ** exit status corresponding to DATA command. 181 ** 182 ** Side Effects: 183 ** none. 184 */ 185 186 smtpdata(m, e) 187 struct mailer *m; 188 register ENVELOPE *e; 189 { 190 register int r; 191 192 /* 193 ** Send the data. 194 ** First send the command and check that it is ok. 195 ** Then send the data. 196 ** Follow it up with a dot to terminate. 197 ** Finally get the results of the transaction. 198 */ 199 200 /* send the command and check ok to proceed */ 201 smtpmessage("DATA", m); 202 r = reply(m); 203 if (r < 0 || REPLYTYPE(r) == 4) 204 return (EX_TEMPFAIL); 205 else if (r == 554) 206 return (EX_UNAVAILABLE); 207 else if (r != 354) 208 return (EX_PROTOCOL); 209 210 /* now output the actual message */ 211 (*e->e_puthdr)(SmtpOut, m, CurEnv); 212 putline("\n", SmtpOut, m); 213 (*e->e_putbody)(SmtpOut, m, CurEnv); 214 215 /* terminate the message */ 216 fprintf(SmtpOut, ".%s", crlf(m)); 217 if (Verbose && !HoldErrs) 218 nmessage(Arpa_Info, ">>> ."); 219 220 /* check for the results of the transaction */ 221 r = reply(m); 222 if (r < 0 || REPLYTYPE(r) == 4) 223 return (EX_TEMPFAIL); 224 else if (r == 250) 225 return (EX_OK); 226 else if (r == 552 || r == 554) 227 return (EX_UNAVAILABLE); 228 return (EX_PROTOCOL); 229 } 230 /* 231 ** SMTPQUIT -- close the SMTP connection. 232 ** 233 ** Parameters: 234 ** name -- name of mailer we are quitting. 235 ** 236 ** Returns: 237 ** none. 238 ** 239 ** Side Effects: 240 ** sends the final protocol and closes the connection. 241 */ 242 243 smtpquit(name, m) 244 char *name; 245 register MAILER *m; 246 { 247 int i; 248 249 /* if the connection is already closed, don't bother */ 250 if (SmtpIn == NULL) 251 return; 252 253 /* send the quit message if not a forced quit */ 254 if (!SmtpClosing) 255 { 256 smtpmessage("QUIT", m); 257 (void) reply(m); 258 if (SmtpClosing) 259 return; 260 } 261 262 /* now actually close the connection */ 263 (void) fclose(SmtpIn); 264 (void) fclose(SmtpOut); 265 SmtpIn = SmtpOut = NULL; 266 267 /* and pick up the zombie */ 268 i = endmailer(SmtpPid, name); 269 if (i != EX_OK) 270 syserr("smtpquit %s: stat %d", name, i); 271 } 272 /* 273 ** REPLY -- read arpanet reply 274 ** 275 ** Parameters: 276 ** m -- the mailer we are reading the reply from. 277 ** 278 ** Returns: 279 ** reply code it reads. 280 ** 281 ** Side Effects: 282 ** flushes the mail file. 283 */ 284 285 reply(m) 286 { 287 (void) fflush(SmtpOut); 288 289 if (tTd(18, 1)) 290 printf("reply\n"); 291 292 /* 293 ** Read the input line, being careful not to hang. 294 */ 295 296 for (;;) 297 { 298 register int r; 299 register char *p; 300 301 /* actually do the read */ 302 if (CurEnv->e_xfp != NULL) 303 (void) fflush(CurEnv->e_xfp); /* for debugging */ 304 305 /* if we are in the process of closing just give the code */ 306 if (SmtpClosing) 307 return (SMTPCLOSING); 308 309 /* get the line from the other side */ 310 p = sfgets(SmtpReplyBuffer, sizeof SmtpReplyBuffer, SmtpIn); 311 if (p == NULL) 312 { 313 extern char MsgBuf[]; /* err.c */ 314 extern char Arpa_TSyserr[]; /* conf.c */ 315 316 message(Arpa_TSyserr, "reply: read error"); 317 # ifdef LOG 318 syslog(LOG_ERR, "%s", &MsgBuf[4]); 319 # endif LOG 320 SmtpClosing = TRUE; 321 smtpquit("reply error", m); 322 return (-1); 323 } 324 fixcrlf(SmtpReplyBuffer, TRUE); 325 326 /* log the input in the transcript for future error returns */ 327 if (Verbose && !HoldErrs) 328 nmessage(Arpa_Info, "%s", SmtpReplyBuffer); 329 else if (CurEnv->e_xfp != NULL) 330 fprintf(CurEnv->e_xfp, "%s\n", SmtpReplyBuffer); 331 332 /* if continuation is required, we can go on */ 333 if (SmtpReplyBuffer[3] == '-' || !isdigit(SmtpReplyBuffer[0])) 334 continue; 335 336 /* decode the reply code */ 337 r = atoi(SmtpReplyBuffer); 338 339 /* extra semantics: 0xx codes are "informational" */ 340 if (r < 100) 341 continue; 342 343 /* reply code 421 is "Service Shutting Down" */ 344 if (r == SMTPCLOSING) 345 { 346 /* send the quit protocol */ 347 smtpquit("SMTP Shutdown", m); 348 SmtpClosing = TRUE; 349 } 350 351 return (r); 352 } 353 } 354 /* 355 ** SMTPMESSAGE -- send message to server 356 ** 357 ** Parameters: 358 ** f -- format 359 ** m -- the mailer to control formatting. 360 ** a, b, c -- parameters 361 ** 362 ** Returns: 363 ** none. 364 ** 365 ** Side Effects: 366 ** writes message to SmtpOut. 367 */ 368 369 /*VARARGS1*/ 370 smtpmessage(f, m, a, b, c) 371 char *f; 372 MAILER *m; 373 { 374 char buf[100]; 375 376 (void) sprintf(buf, f, a, b, c); 377 if (tTd(18, 1) || (Verbose && !HoldErrs)) 378 nmessage(Arpa_Info, ">>> %s", buf); 379 else if (CurEnv->e_xfp != NULL) 380 fprintf(CurEnv->e_xfp, ">>> %s\n", buf); 381 if (!SmtpClosing) 382 fprintf(SmtpOut, "%s%s", buf, crlf(m)); 383 } 384 385 # endif SMTP 386