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