head 1.30; access; symbols; locks; strict; comment @ * @; 1.30 date 96.02.09.23.05.06; author jromine; state Exp; branches; next 1.29; 1.29 date 95.12.06.22.29.38; author jromine; state Exp; branches; next 1.28; 1.28 date 94.03.23.23.24.51; author jromine; state Exp; branches; next 1.27; 1.27 date 93.12.01.03.50.31; author jromine; state Exp; branches; next 1.26; 1.26 date 93.09.01.20.55.22; author jromine; state Exp; branches; next 1.25; 1.25 date 93.08.25.17.17.29; author jromine; state Exp; branches; next 1.24; 1.24 date 93.08.20.16.14.30; author jromine; state Exp; branches; next 1.23; 1.23 date 93.08.20.15.47.14; author jromine; state Exp; branches; next 1.22; 1.22 date 93.08.19.23.35.31; author jromine; state Exp; branches; next 1.21; 1.21 date 92.11.09.18.19.32; author jromine; state Exp; branches; next 1.20; 1.20 date 92.11.06.18.04.48; author jromine; state Exp; branches; next 1.19; 1.19 date 92.11.06.17.26.22; author jromine; state Exp; branches; next 1.18; 1.18 date 92.11.02.18.55.04; author jromine; state Exp; branches; next 1.17; 1.17 date 92.10.26.22.42.56; author jromine; state Exp; branches; next 1.16; 1.16 date 92.10.26.16.39.18; author jromine; state Exp; branches; next 1.15; 1.15 date 92.10.21.03.27.12; author jromine; state Exp; branches; next 1.14; 1.14 date 92.10.21.03.26.43; author jromine; state Exp; branches; next 1.13; 1.13 date 92.10.20.15.36.40; author jromine; state Exp; branches; next 1.12; 1.12 date 92.10.16.16.51.15; author jromine; state Exp; branches; next 1.11; 1.11 date 92.03.03.17.11.03; author jromine; state Exp; branches; next 1.10; 1.10 date 92.03.03.17.09.57; author jromine; state Exp; branches; next 1.9; 1.9 date 92.02.10.18.12.35; author jromine; state Exp; branches; next 1.8; 1.8 date 92.02.05.22.10.36; author jromine; state Exp; branches; next 1.7; 1.7 date 92.01.31.21.40.09; author jromine; state Exp; branches; next 1.6; 1.6 date 90.04.05.15.30.07; author sources; state Exp; branches; next 1.5; 1.5 date 90.04.05.14.43.29; author sources; state Exp; branches; next 1.4; 1.4 date 90.02.06.12.58.44; author sources; state Exp; branches; next 1.3; 1.3 date 90.02.05.14.56.10; author sources; state Exp; branches; next 1.2; 1.2 date 90.02.01.14.00.49; author sources; state Exp; branches; next 1.1; 1.1 date 90.02.01.13.39.06; author sources; state Exp; branches; next ; desc @@ 1.30 log @loop over servers when initial response is bad @ text @/* smail.c - MH interface to SendMail/SMTP */ #ifndef lint static char ident[] = "@@(#)$Id: smail.c,v 1.29 1995/12/06 22:29:38 jromine Exp jromine $"; #endif /* LINTLIBRARY */ /* This module implements an interface to SendMail very similar to the MMDF mm_(3) routines. The sm_() routines herein talk SMTP to a sendmail process, mapping SMTP reply codes into RP_-style codes. */ #ifdef BSD42 /* Under 4.2BSD, the alarm handing stuff for time-outs will NOT work due to the way syscalls get restarted. This really is not crucial, since we expect SendMail to be well-behaved and not hang on us. The only time I've ever seen Sendmail hang was with a bogus configuration file... */ #endif /* BSD42 */ #ifdef SENDMAILBUG /* * It appears that some versions of Sendmail will return Code 451 * when they don't really want to indicate a failure. * "Code 451 almost always means sendmail has deferred; we don't * really want bomb out at this point since sendmail will rectify * things later." So, if you define SENDMAILBUG, Code 451 is * considered the same as Code 250. Yuck! */ #ifndef SENDMAIL #undef SENDMAILBUG #endif /* not SENDMAIL */ #endif /* SENDMAILBUG */ #ifdef hpux /* HP-UX has this capability. It also handles (some) signals. */ #define BSD42 #endif /* hpux */ #if !defined(BSD42) && !defined(SOCKETS) #undef SMTP #endif /* not BSD42 and not SOCKETS */ #ifdef SMTP #undef SENDMAIL #endif /* SMTP */ #include "../h/strings.h" #include #include "smail.h" #include "../zotnet/mts.h" #include #include #ifndef TYPESIG #define TYPESIG int #endif #define NOTOK (-1) #define OK 0 #define DONE 1 #define TRUE 1 #define FALSE 0 #define NBITS ((sizeof (int)) * 8) #define min(a,b) ((a) < (b) ? (a) : (b)) /* these codes must all be different! */ #define SM_OPEN 90 /* Changed from 30 in case of nameserver flakiness */ #define SM_HELO 20 #define SM_RSET 15 #define SM_MAIL 40 #define SM_RCPT 120 #define SM_DATA 20 #define SM_TEXT 150 #define SM_DOT 180 #define SM_QUIT 30 #define SM_CLOS 10 /* */ static TYPESIG alrmser (); static int sm_addrs = 0; static int sm_alarmed = 0; #ifndef SMTP static int sm_child = NOTOK; #endif /* not SMTP */ static int sm_debug = 0; static int sm_nl = TRUE; static int sm_verbose = 0; static FILE * sm_rfp = NULL; static FILE * sm_wfp = NULL; #ifdef MPOP static int sm_ispool = 0; static char sm_tmpfil[BUFSIZ]; #endif /* MPOP */ static char *sm_noreply = "No reply text given"; static char *sm_moreply = "; "; struct smtp sm_reply; /* global... */ void discard (); char *r1bindex (); static int rclient(), sm_ierror(), smtalk(), sm_wrecord(), sm_wstream(); static int sm_werror(), smhear(), sm_rrecord(), sm_rerror(); #ifdef MPOP extern int errno; #ifndef BSD44 extern int sys_nerr; extern char *sys_errlist[]; #endif #endif static int doingEHLO; #define MAXEHLO 10 char *EHLOkeys[MAXEHLO + 1]; char *EHLOset (); #ifdef SMTP #ifndef MAXARGS #define MAXARGS 1000 #endif extern char **brkstring (), **copyip (), *getcpy (); #endif /* */ #ifndef SMTP /* ARGSUSED */ int sm_init (client, server, watch, verbose, debug, onex, queued) char *client, *server; int watch, verbose, debug, onex, queued; { register int i, result, vecp; int pdi[2], pdo[2]; char *vec[15]; if (watch) #ifndef SUN40 verbose = TRUE; #else /* to show the transaction, -watch must imply -snoop */ debug = verbose = TRUE; #endif sm_verbose = verbose; sm_debug = debug; if (sm_rfp != NULL && sm_wfp != NULL) return RP_OK; if (client == NULL || *client == '\0') client = clientname; #ifdef ZMAILER if (client == NULL || *client == '\0') client = "localhost"; #endif if (pipe (pdi) == NOTOK) return sm_ierror ("no pipes"); if (pipe (pdo) == NOTOK) { (void) close (pdi[0]); (void) close (pdi[1]); return sm_ierror ("no pipes"); } for (i = 0; (sm_child = fork ()) == NOTOK && i < 5; i++) sleep (5); switch (sm_child) { case NOTOK: (void) close (pdo[0]); (void) close (pdo[1]); (void) close (pdi[0]); (void) close (pdi[1]); return sm_ierror ("unable to fork"); case OK: if (pdo[0] != fileno (stdin)) (void) dup2 (pdo[0], fileno (stdin)); if (pdi[1] != fileno (stdout)) (void) dup2 (pdi[1], fileno (stdout)); if (pdi[1] != fileno (stderr)) (void) dup2 (pdi[1], fileno (stderr)); for (i = fileno (stderr) + 1; i < NBITS; i++) (void) close (i); vecp = 0; vec[vecp++] = r1bindex (sendmail, '/'); vec[vecp++] = "-bs"; #ifndef ZMAILER vec[vecp++] = watch ? "-odi" : queued ? "-odq" : "-odb"; vec[vecp++] = "-oem"; vec[vecp++] = "-om"; #ifndef RAND if (verbose) vec[vecp++] = "-ov"; #endif /* not RAND */ #endif /* not ZMAILER */ vec[vecp++] = NULL; (void) setgid (getegid ()); (void) setuid (geteuid ()); execvp (sendmail, vec); fprintf (stderr, "unable to exec "); perror (sendmail); _exit (-1); /* NOTREACHED */ default: (void) signal (SIGALRM, alrmser); (void) signal (SIGPIPE, SIG_IGN); (void) close (pdi[1]); (void) close (pdo[0]); if ((sm_rfp = fdopen (pdi[0], "r")) == NULL || (sm_wfp = fdopen (pdo[1], "w")) == NULL) { (void) close (pdi[0]); (void) close (pdo[1]); sm_rfp = sm_wfp = NULL; return sm_ierror ("unable to fdopen"); } sm_alarmed = 0; (void) alarm (SM_OPEN); result = smhear (); (void) alarm (0); switch (result) { case 220: break; default: (void) sm_end (NOTOK); return RP_RPLY; } if (client && *client) { doingEHLO = 1; result = smtalk (SM_HELO, "EHLO %s", client); doingEHLO = 0; if (500 <= result && result <= 599) result = smtalk (SM_HELO, "HELO %s", client); switch (result) { case 250: break; default: (void) sm_end (NOTOK); return RP_RPLY; } } #ifndef ZMAILER if (onex) (void) smtalk (SM_HELO, "ONEX"); #endif if (watch) (void) smtalk (SM_HELO, "VERB on"); return RP_OK; } } #else /* SMTP */ /* */ int sm_init (client, server, watch, verbose, debug, onex, queued) char *client, *server; int watch, verbose, debug, onex, queued; { register int result, sd1, sd2; register char **ap; char *cp, *arguments[MAXARGS]; ap = arguments; if (!server || !*server) server = servers; (void) copyip (brkstring (getcpy (server), " ", "\n"), ap); if (watch) #if !defined(SUN40) || defined(MMDFII) verbose = TRUE; #else /* to show the transaction, -watch must imply -snoop */ debug = verbose = TRUE; #endif sm_verbose = verbose; sm_debug = debug; #ifdef MPOP if (sm_ispool) goto all_done; #endif if (sm_rfp != NULL && sm_wfp != NULL) goto send_options; if (client == NULL || *client == '\0') if (clientname) client = clientname; else client = LocalName (); /* no clientname -> LocalName */ #ifdef ZMAILER if (client == NULL || *client == '\0') client = "localhost"; #endif /* not ZMAILER */ ap = arguments; again: ; for (sd1 = NOTOK; *ap; ap++) { if ((sd1 = rclient (*ap, "tcp", "smtp")) != NOTOK) break; } if (sd1 == NOTOK) return RP_BHST; #ifdef MPOP if (sm_ispool) { if (sm_rfp) { (void) alarm (SM_CLOS); (void) fclose (sm_rfp); (void) alarm (0); sm_rfp = NULL; } if ((sm_wfp = fdopen (sd1, "w")) == NULL) { (void) unlink (sm_tmpfil); (void) close (sd1); return sm_ierror ("unable to fdopen"); } all_done: ; sm_reply.text[sm_reply.length = 0] = NULL; return (sm_reply.code = RP_OK); } #endif /* MPOP */ if ((sd2 = dup (sd1)) == NOTOK) { (void) close (sd1); return sm_ierror ("unable to dup"); } (void) signal (SIGALRM, alrmser); (void) signal (SIGPIPE, SIG_IGN); if ((sm_rfp = fdopen (sd1, "r")) == NULL || (sm_wfp = fdopen (sd2, "w")) == NULL) { (void) close (sd1); (void) close (sd2); sm_rfp = sm_wfp = NULL; return sm_ierror ("unable to fdopen"); } sm_alarmed = 0; (void) alarm (SM_OPEN); result = smhear (); (void) alarm (0); switch (result) { case 220: break; default: (void) sm_end (NOTOK); if (*++ap) { sd1 = NOTOK; goto again; } return RP_RPLY; } if (client && *client) { doingEHLO = 1; result = smtalk (SM_HELO, "EHLO %s", client); doingEHLO = 0; if (500 <= result && result <= 599) result = smtalk (SM_HELO, "HELO %s", client); switch (result) { case 250: break; default: (void) sm_end (NOTOK); return RP_RPLY; } } send_options: ; if (watch && EHLOset ("XVRB")) (void) smtalk (SM_HELO, "VERB on"); if (onex && EHLOset ("XONE")) (void) smtalk (SM_HELO, "ONEX"); if (queued && EHLOset ("XQUE")) (void) smtalk (SM_HELO, "QUED"); return RP_OK; } static int rclient (server, protocol, service) char *server, *protocol, *service; { int sd; char response[BUFSIZ]; #ifdef MPOP char *cp; #endif /* MPOP */ if ((sd = client (server, protocol, service, FALSE, response)) != NOTOK) return sd; #ifdef MPOP if (!server && servers && (cp = index (servers, '/'))) { register char **ap; char *arguments[MAXARGS]; (void) copyip (brkstring (cp = getcpy (servers), " ", "\n"), arguments); for (ap = arguments; *ap; ap++) if (**ap == '/') { register char *dp; if ((dp = rindex (*ap, '/')) && *++dp == NULL) *--dp = NULL; (void) sprintf (sm_tmpfil, "%s/smtpXXXXXX", *ap); (void) mktemp (sm_tmpfil); if ((sd = creat (sm_tmpfil, 0600)) != NOTOK) { sm_ispool = 1; break; } } free (cp); if (sd != NOTOK) return sd; } #endif /* MPOP */ (void) sm_ierror ("%s", response); return NOTOK; } #endif /* SMTP */ /* */ int sm_winit (mode, from) register int mode; register char *from; { #ifdef MPOP if (sm_ispool && !sm_wfp) { (void) strlen (strcpy (sm_reply.text, "unable to create new spool file")); sm_reply.code = NOTOK; return RP_BHST; } #endif /* MPOP */ switch (smtalk (SM_MAIL, "%s FROM:<%s>", mode == S_SEND ? "SEND" : mode == S_SOML ? "SOML" : mode == S_SAML ? "SAML" : "MAIL", from)) { case 250: sm_addrs = 0; return RP_OK; case 500: case 501: case 552: return RP_PARM; default: return RP_RPLY; } } /* */ #ifdef BERK /* ARGUSED */ #endif /* BERK */ int sm_wadr (mbox, host, path) register char *mbox; #ifndef BERK register #endif /* not BERK */ char *host, *path; { #ifndef BERK switch (smtalk (SM_RCPT, host && *host ? "RCPT TO:<%s%s@@%s>" : "RCPT TO:<%s%s>", path ? path : "", mbox, host)) { #else /* BERK */ switch (smtalk (SM_RCPT, "RCPT TO:%s", mbox)) { #endif /* BERK */ case 250: case 251: sm_addrs++; return RP_OK; case 451: #ifdef SENDMAILBUG sm_addrs++; return RP_OK; #endif /* SENDMAILBUG */ case 421: case 450: case 452: return RP_NO; case 500: case 501: return RP_PARM; case 550: case 551: case 552: case 553: return RP_USER; default: return RP_RPLY; } } /* */ int sm_waend () { switch (smtalk (SM_DATA, "DATA")) { case 354: sm_nl = TRUE; return RP_OK; case 451: #ifdef SENDMAILBUG sm_nl = TRUE; return RP_OK; #endif /* SENDMAILBUG */ case 421: return RP_NO; case 500: case 501: case 503: case 554: return RP_NDEL; default: return RP_RPLY; } } /* */ int sm_wtxt (buffer, len) register char *buffer; register int len; { register int result; sm_alarmed = 0; (void) alarm (SM_TEXT); result = sm_wstream (buffer, len); (void) alarm (0); return (result == NOTOK ? RP_BHST : RP_OK); } /* */ int sm_wtend () { if (sm_wstream ((char *) NULL, 0) == NOTOK) return RP_BHST; switch (smtalk (SM_DOT + 3 * sm_addrs, ".")) { case 250: case 251: return RP_OK; case 451: #ifdef SENDMAILBUG return RP_OK; #endif /* SENDMAILBUG */ case 452: default: return RP_NO; case 552: case 554: return RP_NDEL; } } /* */ int sm_end (type) register int type; { register int status; struct smtp sm_note; #ifndef SMTP switch (sm_child) { case NOTOK: case OK: return RP_OK; default: break; } #endif /* not SMTP */ if (sm_rfp == NULL && sm_wfp == NULL) return RP_OK; switch (type) { case OK: (void) smtalk (SM_QUIT, "QUIT"); break; case NOTOK: sm_note.code = sm_reply.code; (void) strncpy (sm_note.text, sm_reply.text, sm_note.length = sm_reply.length);/* fall */ case DONE: if (smtalk (SM_RSET, "RSET") == 250 && type == DONE) return RP_OK; #ifndef SMTP (void) kill (sm_child, SIGKILL); discard (sm_rfp); discard (sm_wfp); #else /* SMTP */ (void) smtalk (SM_QUIT, "QUIT"); #endif /* not SMTP */ if (type == NOTOK) { sm_reply.code = sm_note.code; (void) strncpy (sm_reply.text, sm_note.text, sm_reply.length = sm_note.length); } break; } #ifdef MPOP #ifdef SMTP if (sm_ispool) { sm_ispool = 0; if (sm_wfp) { (void) unlink (sm_tmpfil); (void) fclose (sm_wfp); sm_wfp = NULL; } } #endif #endif /* MPOP */ if (sm_rfp != NULL) { (void) alarm (SM_CLOS); (void) fclose (sm_rfp); (void) alarm (0); } if (sm_wfp != NULL) { (void) alarm (SM_CLOS); (void) fclose (sm_wfp); (void) alarm (0); } #ifndef SMTP status = pidwait (sm_child); sm_child = NOTOK; #else /* SMTP */ status = 0; #endif /* SMTP */ sm_rfp = sm_wfp = NULL; return (status ? RP_BHST : RP_OK); } /* */ #ifdef MPOP #ifdef SMTP #include #include int sm_bulk (file) char *file; { int cc, i, j, k, result; long pos; register char *dp; char *bp, *cp, buffer[BUFSIZ], sender[BUFSIZ]; FILE *fp, *gp; gp = NULL; k = strlen (file) - sizeof ".bulk"; if ((fp = fopen (file, "r")) == NULL) { (void) sprintf (bp = sm_reply.text, "unable to read %s: ", file); bp += strlen (bp); if (errno > 0 && errno < sys_nerr) (void) sprintf (bp, "%s", sys_errlist[errno]); else (void) sprintf (bp, "Error %d", errno); sm_reply.length = strlen (sm_reply.text); sm_reply.code = NOTOK; return RP_BHST; } if (sm_debug) { printf ("reading file %s\n", file); (void) fflush (stdout); } i = j = 0; while (fgets (buffer, sizeof buffer, fp)) { if (j++ == 0) (void) strcpy (sender, buffer + sizeof "MAIL FROM:" - 1); if (strcmp (buffer, "DATA\r\n") == 0) { i = 1; break; } } if (i == 0) { if (sm_debug) { printf ("no DATA...\n"); (void) fflush (stdout); } losing0: ; (void) sprintf (buffer, "%s.bad", file); (void) rename (file, buffer); if (gp) { (void) sprintf (buffer, "%*.*sA.bulk", k, k, file); (void) unlink (buffer); (void) fclose (gp); } (void) fclose (fp); return RP_OK; } if (j < 3) { if (sm_debug) { printf ("no %srecipients...\n", j < 1 ? "sender or " : ""); (void) fflush (stdout); } goto losing0; } if ((cp = malloc ((unsigned) (cc = (pos = ftell (fp)) + 1))) == NULL) { sm_reply.length = strlen (strcpy (sm_reply.text, "out of memory")); losing1: ; sm_reply.code = NOTOK; (void) fclose (fp); return RP_BHST; } (void) fseek (fp, 0L, 0); for (dp = cp, i = 0; i++ < j; dp += strlen (dp)) if (fgets (dp, cc - (dp - cp), fp) == NULL) { sm_reply.length = strlen (strcpy (sm_reply.text, "premature eof")); losing2: ; free (cp); goto losing1; } *dp = NULL; for (dp = cp, i = cc - 1; i > 0; dp += cc, i -= cc) if ((cc = write (fileno (sm_wfp), dp, i)) == NOTOK) { losing3: ; (void) strcpy (bp = sm_reply.text, "error writing to server: "); bp += strlen (bp); if (errno > 0 && errno < sys_nerr) (void) sprintf (bp, "%s", sys_errlist[errno]); else (void) sprintf (bp, "Error %d", errno); sm_reply.length = strlen (sm_reply.text); goto losing2; } else if (sm_debug) { printf ("wrote %d octets to server\n", cc); (void) fflush (stdout); } for (dp = cp, i = 0; i++ < j; dp = index (dp, '\n'), dp++) { if (sm_debug) { if (bp = index (dp, '\r')) *bp = NULL; printf ("=> %s\n", dp); (void) fflush (stdout); if (bp) *bp = '\r'; } switch (smhear () + (i == 1 ? 1000 : i != j ? 2000 : 3000)) { case 1000 + 250: sm_addrs = 0; result = RP_OK; break; case 1000 + 500: case 1000 + 501: case 1000 + 552: case 2000 + 500: case 2000 + 501: result = RP_PARM; (void) smtalk (SM_RSET, "RSET"); free (cp); goto losing0; case 2000 + 250: case 2000 + 251: sm_addrs++; result = RP_OK; break; case 2000 + 451: #ifdef SENDMAILBUG sm_addrs++; result = RP_OK; break; #endif case 2000 + 421: case 2000 + 450: case 2000 + 452: result = RP_NO; goto bad_addr; case 2000 + 550: case 2000 + 551: case 2000 + 552: case 2000 + 553: result = RP_USER; bad_addr: ; if (k <= 0 || strcmp (sender, "<>\r\n") == 0) break; if (gp == NULL) { int l; (void) sprintf (buffer, "%*.*sA.bulk", k, k, file); if ((gp = fopen (buffer, "w+")) == NULL) goto bad_data; fprintf (gp, "MAIL FROM:<>\r\nRCPT TO:%sDATA\r\n", sender); l = strlen (sender); fprintf (gp, "To: %*.*s\r\nSubject: Invalid addresses (%s)\r\n", l - 4, l - 4, sender + 1, file); fprintf (gp, "Date: %s\r\nFrom: Postmaster@@%s\r\n\r\n", dtimenow (), LocalName ()); } if (bp = index (dp, '\r')) *bp = NULL; fprintf (gp, "=> %s\r\n", dp); if (bp) *bp = '\r'; fprintf (gp, "<= %s\r\n", rp_string (result)); (void) fflush (gp); break; case 3000 + 354: #ifdef SENDMAILBUG ok_data: ; #endif result = RP_OK; break; case 3000 + 451: #ifdef SENDMAILBUG goto ok_data; #endif case 3000 + 421: result = RP_NO; bad_data: ; (void) smtalk (SM_RSET, "RSET"); free (cp); if (gp) { (void) sprintf (buffer, "%*.*sA.bulk", k, k, file); (void) unlink (buffer); (void) fclose (gp); } (void) fclose (fp); return result; case 3000 + 500: case 3000 + 501: case 3000 + 503: case 3000 + 554: (void) smtalk (SM_RSET, "RSET"); free (cp); goto no_dice; default: result = RP_RPLY; goto bad_data; } } free (cp); { struct stat st; #ifdef SYS5 cc = BUFSIZ; #else if (fstat (fileno (sm_wfp), &st) == NOTOK || (cc = st.st_blksize) < BUFSIZ) cc = BUFSIZ; #endif if ((cp = malloc ((unsigned) cc)) == NULL) { (void) smtalk (SM_RSET, "RSET"); sm_reply.length = strlen (strcpy (sm_reply.text, "out of memory")); goto losing1; } } (void) fseek (fp, pos, 0); for (;;) { int eof = 0; for (dp = cp, i = cc; i > 0; dp += j, i -= j) if ((j = fread (cp, sizeof *cp, i, fp)) == OK) { if (ferror (fp)) { (void) sprintf (bp = sm_reply.text, "error reading %s: ", file); bp += strlen (bp); if (errno > 0 && errno < sys_nerr) (void) sprintf (bp, "%s", sys_errlist[errno]); else (void) sprintf (bp, "Error %d", errno); sm_reply.length = strlen (sm_reply.text); goto losing2; } cc = dp - cp; eof = 1; break; } for (dp = cp, i = cc; i > 0; dp += j, i -= j) if ((j = write (fileno (sm_wfp), dp, i)) == NOTOK) goto losing3; else if (sm_debug) { printf ("wrote %d octets to server\n", j); (void) fflush (stdout); } if (eof) break; } free (cp); switch (smhear ()) { case 250: case 251: #ifdef SENDMAILBUG ok_dot: ; #endif result = RP_OK; (void) unlink (file); break; case 451: #ifdef SENDMAILBUG goto ok_dot; #endif case 452: default: result = RP_NO; if (gp) { (void) sprintf (buffer, "%*.*sA.bulk", k, k, file); (void) unlink (buffer); (void) fclose (gp); gp = NULL; } break; case 552: case 554: no_dice: ; result = RP_NDEL; if (k <= 0 || strcmp (sender, "<>\r\n") == 0) { (void) unlink (file); break; } if (gp) { (void) fflush (gp); (void) ftruncate (fileno (gp), 0L); (void) fseek (gp, 0L, 0); } else { (void) sprintf (buffer, "%*.*sA.bulk", k, k, file); if ((gp = fopen (buffer, "w")) == NULL) break; } fprintf (gp, "MAIL FROM:<>\r\nRCPT TO:%sDATA\r\n", sender); i = strlen (sender); fprintf (gp, "To: %*.*s\r\nSubject: Failed mail (%s)\r\n", i - 4, i - 4, sender + 1, file); fprintf (gp, "Date: %s\r\nFrom: Postmaster@@%s\r\n\r\n", dtimenow (), LocalName ()); break; } if (gp) { (void) fputs ("\r\n------- Begin Returned message\r\n\r\n", gp); (void) fseek (fp, pos, 0); while (fgets (buffer, sizeof buffer, fp)) { if (buffer[0] == '-') (void) fputs ("- ", gp); if (strcmp (buffer, ".\r\n")) (void) fputs (buffer, gp); } (void) fputs ("\r\n------- End Returned Message\r\n\r\n.\r\n", gp); (void) fflush (gp); if (!ferror (gp)) (void) unlink (file); (void) fclose (gp); } (void) fclose (fp); return result; } #endif #endif /* MPOP */ /* */ /* VARARGS */ static int sm_ierror (fmt, a, b, c, d) char *fmt, *a, *b, *c, *d; { (void) sprintf (sm_reply.text, fmt, a, b, c, d); sm_reply.length = strlen (sm_reply.text); sm_reply.code = NOTOK; return RP_BHST; } /* */ /* VARARGS2 */ static int smtalk (time, fmt, a, b, c, d) register int time; register char *fmt; register char *a, *b, *c, *d; { register int result; char buffer[BUFSIZ]; (void) sprintf (buffer, fmt, a, b, c, d); if (sm_debug) { printf ("=> %s\n", buffer); (void) fflush (stdout); } #ifdef MPOP if (sm_ispool) { char file[BUFSIZ]; if (strcmp (buffer, ".") == 0) time = SM_DOT; fprintf (sm_wfp, "%s\r\n", buffer); switch (time) { case SM_DOT: (void) fflush (sm_wfp); if (ferror (sm_wfp)) return sm_werror (); (void) sprintf (file, "%s%c.bulk", sm_tmpfil, (char) (sm_ispool + 'a' - 1)); if (rename (sm_tmpfil, file) == NOTOK) { char *bp; (void) sprintf (bp = sm_reply.text, "error renaming %s to %s: ", sm_tmpfil, file); bp += strlen (bp); if (errno > 0 && errno < sys_nerr) (void) sprintf (bp, "%s", sys_errlist[errno]); else (void) sprintf (bp, "Error %d", errno); sm_reply.length = strlen (sm_reply.text); sm_reply.code = NOTOK; return RP_BHST; } (void) fclose (sm_wfp); if (sm_wfp = fopen (sm_tmpfil, "w")) (void) chmod (sm_tmpfil, 0600); sm_ispool++; /* and fall... */ case SM_MAIL: case SM_RCPT: result = 250; break; case SM_RSET: (void) fflush (sm_wfp); (void) ftruncate (fileno (sm_wfp), 0L); (void) fseek (sm_wfp, 0L, 0); result = 250; break; case SM_DATA: result = 354; break; case SM_QUIT: (void) unlink (sm_tmpfil); sm_ispool = 0; result = 221; break; default: result = 500; break; } if (sm_debug) { printf ("<= %d\n", result); (void) fflush (stdout); } sm_reply.text[sm_reply.length = 0] = NULL; return (sm_reply.code = result); } #endif /* MPOP */ sm_alarmed = 0; (void) alarm ((unsigned) time); if ((result = sm_wrecord (buffer, strlen (buffer))) != NOTOK) result = smhear (); (void) alarm (0); return result; } /* */ static int sm_wrecord (buffer, len) register char *buffer; register int len; { if (sm_wfp == NULL) return sm_werror (); (void) fwrite (buffer, sizeof *buffer, len, sm_wfp); (void) fputs ("\r\n", sm_wfp); (void) fflush (sm_wfp); return (ferror (sm_wfp) ? sm_werror () : OK); } /* */ static int sm_wstream (buffer, len) register char *buffer; register int len; { register char *bp; static char lc = 0; if (sm_wfp == NULL) return sm_werror (); if (buffer == NULL && len == 0) { if (lc != '\n') (void) fputs ("\r\n", sm_wfp); lc = 0; return (ferror (sm_wfp) ? sm_werror () : OK); } for (bp = buffer; len > 0; bp++, len--) { switch (*bp) { case '\n': sm_nl = TRUE; (void) fputc ('\r', sm_wfp); break; case '.': if (sm_nl) (void) fputc ('.', sm_wfp);/* FALL THROUGH */ default: sm_nl = FALSE; } (void) fputc (*bp, sm_wfp); if (ferror (sm_wfp)) return sm_werror (); } if (bp > buffer) lc = *--bp; return (ferror (sm_wfp) ? sm_werror () : OK); } /* */ #ifdef _AIX /* * AIX by default will inline the strlen and strcpy commands by redefining * them as __strlen and __strcpy respectively. This causes compile problems * with the #ifdef MPOP in the middle. Should the #ifdef MPOP be removed, * remove these #undefs. */ #undef strlen #undef strcpy #endif /* _AIX */ static int sm_werror () { sm_reply.length = #ifdef SMTP strlen (strcpy (sm_reply.text, sm_wfp == NULL ? "no socket opened" : sm_alarmed ? "write to socket timed out" #ifdef MPOP : sm_ispool ? "error writing to spool file" #endif : "error writing to socket")); #else /* !SMTP */ strlen (strcpy (sm_reply.text, sm_wfp == NULL ? "no pipe opened" : sm_alarmed ? "write to pipe timed out" : "error writing to pipe")); #endif /* !SMTP */ return (sm_reply.code = NOTOK); } /* */ static int smhear () { register int i, code, cont, rc, more; int bc; register char *bp, *rp; char **ehlo, buffer[BUFSIZ]; if (doingEHLO) { static int at_least_once = 0; if (at_least_once) { char *ep; for (ehlo = EHLOkeys; ep = *ehlo; ehlo++) free (ep); } else at_least_once = 1; *(ehlo = EHLOkeys) = NULL; } again: ; sm_reply.text[sm_reply.length = 0] = 0; rp = sm_reply.text, rc = sizeof sm_reply.text - 1; for (more = FALSE; sm_rrecord (bp = buffer, &bc) != NOTOK;) { if (sm_debug) { printf ("<= %s\n", buffer); (void) fflush (stdout); } if (doingEHLO && strncmp (buffer, "250", sizeof "250" - 1) == 0 && (buffer[3] == '-' || doingEHLO == 2) && buffer[4]) { if (doingEHLO == 2) { int len = strlen (buffer + 4); if (*ehlo = malloc ((unsigned) (strlen (buffer + 4) + 1))) { (void) strcpy (*ehlo++, buffer + 4); *ehlo = NULL; if (ehlo >= EHLOkeys + MAXEHLO) doingEHLO = 0; } else doingEHLO = 0; } else doingEHLO = 2; } for (; bc > 0 && (!isascii (*bp) || !isdigit (*bp)); bp++, bc--) continue; cont = FALSE; code = atoi (bp); bp += 3, bc -= 3; for (; bc > 0 && isspace (*bp); bp++, bc--) continue; if (bc > 0 && *bp == '-') { cont = TRUE; bp++, bc--; for (; bc > 0 && isspace (*bp); bp++, bc--) continue; } if (more) { if (code != sm_reply.code || cont) continue; more = FALSE; } else { sm_reply.code = code; more = cont; if (bc <= 0) { (void) strcpy (bp = buffer, sm_noreply); bc = strlen (sm_noreply); } } if ((i = min (bc, rc)) > 0) { (void) strncpy (rp, bp, i); rp += i, rc -= i; if (more && rc > strlen (sm_moreply) + 1) { (void) strcpy (sm_reply.text + rc, sm_moreply); rc += strlen (sm_moreply); } } if (more) continue; if (sm_reply.code < 100) { if (sm_verbose) { printf ("%s\n", sm_reply.text); (void) fflush (stdout); } goto again; } sm_reply.length = rp - sm_reply.text; return sm_reply.code; } return NOTOK; } /* */ static int sm_rrecord (buffer, len) register char *buffer; register int *len; { if (sm_rfp == NULL) return sm_rerror (); buffer[*len = 0] = 0; (void) fgets (buffer, BUFSIZ, sm_rfp); *len = strlen (buffer); if (ferror (sm_rfp) || feof (sm_rfp)) return sm_rerror (); if (buffer[*len - 1] != '\n') while (getc (sm_rfp) != '\n' && !ferror (sm_rfp) && !feof (sm_rfp)) continue; else if (buffer[*len - 2] == '\r') *len -= 1; buffer[*len - 1] = 0; return OK; } /* */ static int sm_rerror () { sm_reply.length = #ifdef SMTP strlen (strcpy (sm_reply.text, sm_rfp == NULL ? "no socket opened" : sm_alarmed ? "read from socket timed out" : feof (sm_rfp) ? "premature end-of-file on socket" : "error reading from socket")); #else /* not SMTP */ strlen (strcpy (sm_reply.text, sm_rfp == NULL ? "no pipe opened" : sm_alarmed ? "read from pipe timed out" : feof (sm_rfp) ? "premature end-of-file on pipe" : "error reading from pipe")); #endif /* not SMTP */ return (sm_reply.code = NOTOK); } /* */ /* ARGSUSED */ static TYPESIG alrmser (i) int i; { #ifndef BSD42 signal (SIGALRM, alrmser); #endif /* BSD42 */ sm_alarmed++; if (sm_debug) { printf ("timed out...\n"); (void) fflush (stdout); } } /* */ char *rp_string (code) register int code; { register char *text; static char buffer[BUFSIZ]; switch (sm_reply.code != NOTOK ? code : NOTOK) { case RP_AOK: text = "AOK"; break; case RP_MOK: text = "MOK"; break; case RP_OK: text = "OK"; break; case RP_RPLY: text = "RPLY"; break; case RP_BHST: default: text = "BHST"; (void) sprintf (buffer, "[%s] %s", text, sm_reply.text); return buffer; case RP_PARM: text = "PARM"; break; case RP_NO: text = "NO"; break; case RP_USER: text = "USER"; break; case RP_NDEL: text = "NDEL"; break; } (void) sprintf (buffer, "[%s] %3d %s", text, sm_reply.code, sm_reply.text); return buffer; } /* */ #ifdef SMTP static char *broken[MAXARGS + 1]; static char **brkstring (strg, brksep, brkterm) register char *strg; register char *brksep, *brkterm; { register int bi; register char c, *sp; sp = strg; for (bi = 0; bi < MAXARGS; bi++) { while (brkany (c = *sp, brksep)) *sp++ = 0; if (!c || brkany (c, brkterm)) { *sp = 0; broken[bi] = 0; return broken; } broken[bi] = sp; while ((c = *++sp) && !brkany (c, brksep) && !brkany (c, brkterm)) continue; } broken[MAXARGS] = 0; return broken; } static brkany (chr, strg) register char chr, *strg; { register char *sp; if (strg) for (sp = strg; *sp; sp++) if (chr == *sp) return 1; return 0; } static char **copyip (p, q) register char **p, **q; { while (*p) *q++ = *p++; *q = 0; return q; } #endif /* */ char *EHLOset (s) char *s; { int len = strlen (s); register char *ep, **ehlo; for (ehlo = EHLOkeys; ep = *ehlo; ehlo++) if (strncmp (ep, s, len) == 0) { for (ep += len; *ep == ' '; ep++) continue; return ep; } return 0; } @ 1.29 log @64bit fix @ text @d3 1 a3 1 static char ident[] = "@@(#)$Id: smail.c,v 1.28 1994/03/23 23:24:51 jromine Exp jromine $"; a120 1 extern char **brkstring (), **copyip (), *getcpy (); a122 1 d130 8 d297 3 d301 5 d331 7 a337 1 if ((sd1 = rclient (server, "tcp", "smtp")) == NOTOK) d380 1 a380 1 default: d382 4 a418 4 #ifdef MPOP #define MAXARGS 1000 #endif /* MPOP */ a1485 1 #ifdef MPOP a1544 1 #endif /* MPOP */ @ 1.28 log @clientname fix @ text @d3 1 a3 1 static char ident[] = "@@(#)$Id: smail.c,v 1.27 1993/12/01 03:50:31 jromine Exp jromine $"; d1056 1 @ 1.27 log @fixes from mtr @ text @d3 1 a3 1 static char ident[] = "@@(#)$Id: smail.c,v 1.26 1993/09/01 20:55:22 jromine Exp jromine $"; d308 4 a311 1 client = clientname; a314 5 #else #if !defined(SENDMTS) || defined(MMDFII) || defined(SVR4) if (client == NULL || *client == 0) client = LocalName (); #endif @ 1.26 log @add clientname tailor option @ text @d3 1 a3 1 static char ident[] = "@@(#)$Id: smail.c,v 1.25 1993/08/25 17:17:29 jromine Exp jromine $"; d116 1 a116 1 extern int errno @ 1.25 log @off_t fixes for BSD44 @ text @d3 1 a3 1 static char ident[] = "@@(#)$Id: smail.c,v 1.24 1993/08/20 16:14:30 jromine Exp jromine $"; d165 2 d307 2 @ 1.24 log @don't use ONEX with ZMAILER @ text @d3 1 a3 1 static char ident[] = "@@(#)$Id: smail.c,v 1.23 1993/08/20 15:47:14 jromine Exp jromine $"; d116 3 a118 1 extern int errno, sys_nerr; d120 1 @ 1.23 log @fixes from mtr remove SMTP_ONEX @ text @d3 1 a3 1 static char ident[] = "@@(#)$Id: smail.c,v 1.22 1993/08/19 23:35:31 jromine Exp jromine $"; d260 1 d263 1 @ 1.22 log @enable ONEX only with "options SMTP_ONEX" @ text @d3 1 a3 1 static char ident[] = "@@(#)$Id: smail.c,v 1.21 1992/11/09 18:19:32 jromine Exp jromine $"; d121 8 d135 8 a142 6 int sm_init (client, server, watch, verbose, debug) register char *client; char *server; register int watch, verbose, debug; d161 1 d199 1 a199 1 vec[vecp++] = watch ? "-odi" : "-odb"; a240 9 #ifdef SMTP_ONEX (void) smtalk(SM_HELO, "ONEX"); #endif if (watch) (void) smtalk(SM_HELO, "VERB on"); if (client && *client) switch (smtalk (SM_HELO, "HELO %s", client)) { case 250: break; d242 13 a254 1 default: d258 7 d272 8 a279 6 int sm_init (client, server, watch, verbose, debug) register char *client, *server; register int watch, verbose, debug; d286 3 a288 1 #if defined(SUN40) && !defined(MMDFII) a289 2 #else verbose = TRUE; d293 4 d298 2 a299 1 return RP_OK; d308 1 a308 1 #endif /* ZMAILER */ a309 4 #ifdef MPOP if (sm_ispool) goto all_done; #endif d357 10 a366 9 #ifdef SMTP_ONEX (void) smtalk(SM_HELO, "ONEX"); #endif #ifndef MMDFII if (watch) (void) smtalk(SM_HELO, "VERB on"); #endif if (client && *client) switch (smtalk (SM_HELO, "HELO %s", client)) { d374 1 d376 8 d1238 2 a1239 1 char buffer[BUFSIZ]; d1241 15 d1267 20 d1334 1 d1519 19 @ 1.21 log @force on -snoop under SUN40 only @ text @d3 1 a3 1 static char ident[] = "@@(#)$Id: smail.c,v 1.20 1992/11/06 18:04:48 jromine Exp jromine $"; d230 1 a230 1 #ifndef ZMAILER d232 1 a232 1 #endif /* not ZMAILER */ d333 1 a333 1 #if !(defined(ZMAILER) || defined(MMDFII)) d335 1 a335 1 #endif /* not ZMAILER */ @ 1.20 log @have -watch imply -snoop under SendMail #endif sugar @ text @d3 1 a3 1 static char ident[] = "@@(#)$Id: smail.c,v 1.19 1992/11/06 17:26:22 jromine Exp jromine $"; d142 1 a142 1 #ifdef notdef d263 3 a265 1 #ifdef MMDFII a266 2 #else debug = verbose = TRUE; @ 1.19 log @define TYPESIG @ text @d3 2 a4 2 static char ident[] = "@@(#)$Id: smail.c,v 1.18 1992/11/02 18:55:04 jromine Exp jromine $"; #endif lint d19 1 a19 1 #endif BSD42 d31 2 a32 2 #endif not SENDMAIL #endif SENDMAILBUG d37 1 a37 1 #endif hpux d41 1 a41 1 #endif not BSD42 and not SOCKETS d44 1 a44 1 #endif SMTP d90 1 a90 1 #endif not SMTP d142 1 d144 3 d194 2 a195 2 #endif not RAND #endif not ZMAILER d247 1 a247 1 #else SMTP d263 1 d265 3 d335 1 a335 1 #endif not ZMAILER d404 1 a404 1 #endif SMTP d442 1 a442 1 #endif BERK d448 1 a448 1 #endif not BERK d456 1 a456 1 #else BERK d458 1 a458 1 #endif BERK d468 1 a468 1 #endif SENDMAILBUG d501 1 a501 1 #endif SENDMAILBUG d546 1 a546 1 #endif SENDMAILBUG d574 1 a574 1 #endif not SMTP d594 1 a594 1 #else SMTP d596 1 a596 1 #endif not SMTP d632 1 a632 1 #else SMTP d634 1 a634 1 #endif SMTP d1305 1 a1305 1 #else not SMTP d1310 1 a1310 1 #endif not SMTP d1324 1 a1324 1 #endif BSD42 @ 1.18 log @_AIX fixes from Bill Wohler @ text @d3 1 a3 1 static char ident[] = "@@(#)$Id: smail.c,v 1.17 1992/10/26 22:42:56 jromine Exp jromine $"; d53 4 @ 1.17 log @TYPESIG alrmser @ text @d3 1 a3 1 static char ident[] = "@@(#)$Id: smail.c,v 1.16 1992/10/26 16:39:18 jromine Exp jromine $"; d1151 11 @ 1.16 log @#ifdef MPOP reversed. @ text @d3 1 a3 1 static char ident[] = "@@(#)$Id: smail.c,v 1.15 1992/10/21 03:27:12 jromine Exp jromine $"; d80 1 a80 1 static int alrmser (); d1296 1 a1296 1 static int alrmser (i) @ 1.15 log @-watch shows SMTP transaction, not -verbose @ text @d3 1 a3 1 static char ident[] = "@@(#)$Id: smail.c,v 1.14 1992/10/21 03:26:43 jromine Exp jromine $"; d111 1 a111 1 #ifndef MPOP @ 1.14 log @fixup #ifdef's ZMAILER, MPOP @ text @d3 1 a3 1 static char ident[] = "@@(#)$Id: smail.c,v 1.13 1992/10/20 15:36:40 jromine Exp jromine $"; d225 1 a225 1 if (verbose) d325 1 a325 1 if (verbose) @ 1.13 log @ifdef MPOP @ text @d3 1 a3 1 static char ident[] = "@@(#)$Id: smail.c,v 1.12 1992/10/16 16:51:15 jromine Exp jromine $"; d111 1 a111 1 d115 1 d260 4 a266 5 #else #ifdef ZMAILER if (client == NULL || *client == '\0') client = "localhost"; #endif ZMAILER d268 1 d273 1 d276 1 @ 1.12 log @mobile pop ifdef's (MPOP) @ text @d3 1 a3 1 static char ident[] = "@@(#)$Id: smail.c,v 1.11 1992/03/03 17:11:03 jromine Exp jromine $"; d1154 1 d1156 1 d1158 1 a1158 1 #else not SMTP d1162 1 a1162 1 #endif not SMTP @ 1.11 log @fix from mtr @ text @d3 1 a3 1 static char ident[] = "@@(#)$Id: smail.c,v 1.10 1992/03/03 17:09:57 jromine Exp jromine $"; d94 1 d97 1 d269 1 d290 1 d339 1 d341 1 d349 4 a352 2 char *cp, response[BUFSIZ]; d357 1 d384 1 d397 1 d404 1 d589 1 d601 1 d627 1 d852 3 d858 1 d973 1 d1010 1 d1078 1 d1359 1 d1419 1 @ 1.10 log @fixes from mtr @ text @d3 1 a3 1 static char ident[] = "@@(#)$Id: smail.c,v 1.9 1992/02/10 18:12:35 jromine Exp jromine $"; d109 5 a335 5 extern int errno, sys_nerr; extern char *sys_errlist[]; extern char **brkstring (), **copyip (), *getcpy (); @ 1.9 log @some SVR4 changes add "localdomain" tailor option @ text @d3 1 a3 1 static char ident[] = "@@(#)$Id: smail.c,v 1.8 1992/02/05 22:10:36 jromine Exp jromine $"; d66 1 d73 3 a75 3 #define SM_TEXT 120 #define SM_DOT 120 #define SM_QUIT 20 d94 3 d262 2 d266 16 d330 7 d343 2 a344 1 char response[BUFSIZ]; d349 27 d387 7 d577 11 d613 344 d990 68 d1077 1 a1077 1 fputs ("\r\n", sm_wfp); d1097 1 a1097 1 fputs ("\r\n", sm_wfp); d1132 1 d1334 62 @ 1.8 log @add zmailer support @ text @d3 1 a3 1 static char ident[] = "@@(#)$Id: smail.c,v 1.7 1992/01/31 21:40:09 jromine Exp jromine $"; d212 1 a212 1 #endif not ZMAILER d248 2 a249 2 #if !defined(SENDMTS) || defined(MMDFII) if (client == NULL || *client == NULL) d287 1 a287 1 #ifndef ZMAILER d290 1 d293 1 @ 1.7 log @kerberos @ text @d3 1 a3 1 static char ident[] = "@@(#)$Id: smail.c,v 1.6 1990/04/05 15:30:07 sources Exp jromine $"; d131 4 d167 1 d175 1 d210 5 d251 5 d287 5 @ 1.6 log @add ID @ text @d3 1 a3 1 static char ident[] = "@@(#)$Id:$"; d580 1 a580 1 static char lc = NULL; d588 1 a588 1 lc = NULL; d647 1 a647 1 sm_reply.text[sm_reply.length = 0] = NULL; d718 1 a718 1 buffer[*len = 0] = NULL; d730 1 a730 1 buffer[*len - 1] = NULL; @ 1.5 log @add ID @ text @d3 1 a3 1 static char ident[] = "$Id:"; @ 1.4 log @ANSI Compilance @ text @d2 3 @ 1.3 log @SOCKETS @ text @d76 1 a76 1 int alrmser (); d98 3 @ 1.2 log @raise SMTP open timeout to 90 secs for slow systems #define BSD42 #ifdef hpux, so HPUX systems can use SMTP #ifdef SENDMAILBUG consider 451 SMTP reply codes the same as 250. @ text @d36 1 a36 1 #ifndef BSD42 d38 1 a38 1 #endif not BSD42 @ 1.1 log @Initial revision @ text @d17 13 d31 5 d63 1 a63 1 #define SM_OPEN 30 d344 5 a350 1 case 451: d377 5 a382 1 case 451: d424 3 @