|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T s
Length: 12187 (0x2f9b) Types: TextFile Names: »sm_wtmail.c«
└─⟦2d1937cfd⟧ Bits:30007241 EUUGD22: P.P 5.0 └─⟦dc59850a2⟧ »EurOpenD22/pp5.0/pp-5.tar.Z« └─⟦e5a54fb17⟧ └─⟦this⟧ »pp-5.0/Chans/smtp/sm_wtmail.c«
/* sm_wtmail: mail-commands for smtp mail */ # ifndef lint static char Rcsid[] = "@(#)$Header: /cs/research/pp/hubris/pp-beta/Chans/smtp/RCS/sm_wtmail.c,v 5.0 90/09/20 15:54:22 pp Exp Locker: pp $"; # endif /* * $Header: /cs/research/pp/hubris/pp-beta/Chans/smtp/RCS/sm_wtmail.c,v 5.0 90/09/20 15:54:22 pp Exp Locker: pp $ * * $Log: sm_wtmail.c,v $ * Revision 5.0 90/09/20 15:54:22 pp * rcsforce : 5.0 public release * */ #include "util.h" #include "retcode.h" #include "chan.h" #include <signal.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include "ap.h" extern CHAN *chanptr; extern char *loc_dom_mta; extern char *strdup(); extern char *open_host; struct sm_rstruct /* save last reply obtained */ { /* for holding a net reply */ int sm_rval; /* rp.h value for reply */ int sm_rlen; /* current lengh of reply string */ char sm_rgot; /* true, if have a reply */ char sm_rstr[LINESIZE]; /* human-oriented reply text */ } sm_rp; #define smtp_error() (sm_rp.sm_rgot ? sm_rp.sm_rstr : "") static CHAN *sm_chptr; /* structure for channel that we are */ FILE *sm_rfp, *sm_wfp; static char sm_rnotext[] = "No reply text given"; static int sm_rrec (); #define SM_HTIME 180 /* Time allowed for HELO command */ #define SM_OTIME 300 /* Time allowed for a netopen */ #define SM_ATIME 120 /* Time allowed for answer after open */ #define SM_STIME 300 /* Time allowed for MAIL command */ #define SM_TTIME 300 /* Time allowed for RCPT command */ /* Should get smaller when list channel is in place */ #define SM_QTIME 60 /* Time allowed for QUIT command */ int data_bytes = 0; #if sparc && defined(__GNUC__) /* work around bug in gcc 1.37 sparc version */ #define inet_ntoa myinet_ntoa static char *myinet_ntoa (in) struct in_addr in; { static char buf[80]; (void) sprintf (buf, "%d.%d.%d.%d", (in.s_addr >> 24) & 0xff, (in.s_addr >> 16) & 0xff, (in.s_addr >> 8 ) & 0xff, (in.s_addr ) & 0xff); return buf; } #else extern char *inet_ntoa (); #endif sm_wfrom (sender) char *sender; { char linebuf[LINESIZE]; (void) sprintf (linebuf, "MAIL FROM:<%s>", sender); if (rp_isbad (sm_cmd (linebuf, SM_STIME))) return (RP_DHST); switch( sm_rp.sm_rval ) { case 250: break; /* We're off and running! */ case 500: case 501: case 552: return( sm_rp.sm_rval = RP_PARM ); case 421: case 450: case 451: case 452: return( sm_rp.sm_rval = RP_AGN); default: return( sm_rp.sm_rval = RP_BHST); } return( RP_OK ); } sm_wto (adr) /* send one address spec to local */ char adr[]; /* rest of address */ { char linebuf[LINESIZE]; if( isstr(adr)) (void) sprintf (linebuf, "RCPT TO:<%s>", adr); else (void) strcpy(linebuf, "RCPT TO:<>"); if (rp_isbad (sm_cmd (linebuf, SM_TTIME))) return (RP_DHST); switch (sm_rp.sm_rval) { case 250: case 251: sm_rp.sm_rval = RP_AOK; break; case 421: case 450: case 451: case 452: sm_rp.sm_rval = RP_AGN; break; case 550: case 551: case 552: case 553: case 554: /* BOGUS: sendmail is out of spec! */ sm_rp.sm_rval = RP_USER; break; case 500: case 501: sm_rp.sm_rval = RP_PARM; break; default: sm_rp.sm_rval = RP_RPLY; } if (rp_isbad (sm_rp.sm_rval)) PP_NOTICE (("Address failed, reason '%s'", smtp_error())); return (sm_rp.sm_rval); } sm_init (curchan) /* session initialization */ CHAN *curchan; /* name of channel */ { sm_chptr = curchan; /* phs_note (sm_chptr, PHS_CNSTRT); */ return (RP_OK); /* generally, a no-op */ } static sm_irdrply () /* get net reply & stuff into sm_rp */ { static char sep[] = "; "; /* for sticking multi-lines together */ short len, tmpreply, retval; char linebuf[LINESIZE]; char tmpmore; register char *linestrt; /* to bypass bad initial chars in buf */ register short i; register char more; /* are there continuation lines? */ newrply: for (more = FALSE, sm_rp.sm_rgot = FALSE, sm_rp.sm_rlen = 0; rp_isgood (retval = sm_rrec (linebuf, &len));) { PP_LOG (LLOG_PDUS, ("<- %s", linebuf)); /* 1st col in linebuf gets reply code */ for (linestrt = linebuf; /* skip leading baddies, probably */ len > 0 && /* from a lousy Multics */ (!isascii ((char) *linestrt) || !isdigit ((char) *linestrt)); linestrt++, len--); tmpmore = FALSE; /* start fresh */ tmpreply = atoi (linestrt); bcopy (linestrt, sm_rp.sm_rstr, 3); /* Grab reply code */ if ((len -= 3) > 0) { linestrt += 3; if (len > 0 && *linestrt == '-') { tmpmore = TRUE; linestrt++; if (--len > 0) for (; len > 0 && isspace (*linestrt); linestrt++, len--); } } if (more) /* save reply value from 1st line */ { /* we at end of continued reply? */ if (tmpreply != sm_rp.sm_rval || tmpmore) continue; more = FALSE; /* end of continuation */ } else /* not in continuation state */ { sm_rp.sm_rval = tmpreply; more = tmpmore; /* more lines to follow? */ if (len <= 0) { /* fake it, if no text given */ bcopy (sm_rnotext, linestrt = linebuf, (sizeof sm_rnotext) - 1); len = (sizeof sm_rnotext) - 1; } } if ((i = MIN (len, (LINESIZE - 1) - sm_rp.sm_rlen)) > 0) { /* if room left, save the human text */ bcopy (linestrt, &sm_rp.sm_rstr[sm_rp.sm_rlen], i); sm_rp.sm_rlen += i; if (more && sm_rp.sm_rlen < (LINESIZE - 4)) { /* put a separator between lines */ bcopy (sep, &(sm_rp.sm_rstr[sm_rp.sm_rlen]), (sizeof sep) - 1); sm_rp.sm_rlen += (sizeof sep) - 1; } } if (!more) { if (sm_rp.sm_rval < 100) goto newrply; /* skip info messages */ sm_rp.sm_rgot = TRUE; return (RP_OK); } } return (retval); /* error return */ } static sm_rrec (linebuf, len) /* read a reply record from net */ char *linebuf; /* where to stuff text */ short *len; /* where to stuff length */ { extern int errno; *len = 0; /* for clean logging if nothing read */ linebuf[0] = '\0'; fgets (linebuf, LINESIZE, sm_rfp); *len = strlen (linebuf); if (ferror (sm_rfp) || feof (sm_rfp)) { /* error or unexpected eof */ PP_LOG (LLOG_EXCEPTIONS, ("netread: ret=%d, fd=%d", *len, fileno (sm_rfp))); sm_nclose (NOTOK); /* since it won't work anymore */ return (RP_BHST); } if (linebuf[*len - 1] != '\n') { PP_LOG (LLOG_EXCEPTIONS, ("net input overflow")); while (getc (sm_rfp) != '\n' && !ferror (sm_rfp) && !feof (sm_rfp)); } else if (linebuf[*len - 2] == '\r') *len -= 1; /* get rid of crlf or just lf */ linebuf[*len - 1] = '\0'; return (RP_OK); } sm_cmd (cmd, time) /* Send a command */ char *cmd; int time; /* Max time for sending and getting reply */ { short retval; PP_LOG (LLOG_PDUS, ("-> %s", cmd)); if (sm_wfp == NULL) return sm_rp.sm_rval = RP_DHST; if (timeout((time_t)time)) { PP_TRACE (("sm_cmd(): host died?")); sm_nclose (NOTOK); return (sm_rp.sm_rval = RP_DHST); } fprintf (sm_wfp, "%s\r\n", cmd); if (!ferror (sm_wfp)) (void) fflush (sm_wfp); timeout (0); if (ferror (sm_wfp)) { PP_TRACE (("sm_cmd(): host died?")); sm_nclose (NOTOK); return (sm_rp.sm_rval = RP_DHST); } if (rp_isbad (retval = sm_irdrply ())) return( sm_rp.sm_rval = retval ); return (RP_OK); } sm_wstm (buf, len) /* write some message text out */ char *buf; /* what to write */ register int len; /* how long it is */ { static char lastchar = 0; short retval; register char *bufptr; register char newline; if (buf == 0 && len == 0) { /* end of text */ if (lastchar != '\n') { /* make sure it ends cleanly */ fputs ("\r\n", sm_wfp); data_bytes += 2; } if (ferror (sm_wfp)) return (RP_DHST); lastchar = 0; /* reset for next message */ retval = RP_OK; } else { newline = (lastchar == '\n') ? TRUE : FALSE; for (bufptr = buf; len--; bufptr++) { switch (*bufptr) /* cycle through the buffer */ { case '\n': /* Telnet requires crlf */ newline = TRUE; putc ('\r', sm_wfp); data_bytes ++; break; case '.': /* Insert extra period at beginning */ if (newline) { putc ('.', sm_wfp); data_bytes ++; } /* DROP ON THROUGH */ default: newline = FALSE; } if (ferror (sm_wfp)) break; /* finally send the data character */ putc ((lastchar = *bufptr), sm_wfp); data_bytes ++; if (ferror (sm_wfp)) break; } retval = ferror(sm_wfp) ? RP_DHST : RP_OK; } return (retval); } static int start_conn (sp, name, errstr) struct sockaddr_in *sp; char *name; char *errstr; { int s; s = socket (AF_INET, SOCK_STREAM, 0); if( s < 0 ) { PP_SLOG (LLOG_EXCEPTIONS, "socket", ("Can't get socket")); return NOTOK; } if (timeout(SM_OTIME)) { PP_LOG (LLOG_EXCEPTIONS, ("[%s] open timeout", name, inet_ntoa (sp -> sin_addr))); return NOTOK; } if( connect (s, (struct sockaddr *)sp, sizeof *sp) < 0 ) { (void) close (s); PP_SLOG (LLOG_EXCEPTIONS, "connect", ("Connection failed to %s [%s]", name, inet_ntoa (sp -> sin_addr))); timeout (0); return NOTOK; } timeout (0); return s; } sm_nopen(hostnam, errstr ) char *hostnam; char *errstr; { int fds[2], skt; short retval; char linebuf[LINESIZE]; extern int smtpport; struct hostent *hp, *gethostbyname (); struct sockaddr_in sin; char **aptr; PP_TRACE (("[ %s ]", hostnam)); *errstr = 0; #ifdef NAMESERVER if (rp_isbad (retval = ns_gethost (hostnam, &hp))) { (void) sprintf (errstr, "Nameserver lookup failed"); return (retval); } #else NAMESERVER if ((hp = gethostbyname (hostnam)) == NULL) { (void) sprintf (errstr, "Host lookup failed"); return RP_BHST; } #endif NAMESERVER if (smtpport == 0) { struct servent *sp; if ((sp = getservbyname ("smtp", "tcp")) == NULL) { (void) sprintf (errstr, "Can't determine smtp port"); return RP_AGN; } smtpport = (short)sp->s_port; } bzero ((char *)&sin, sizeof sin); sin.sin_family = AF_INET; sin.sin_port = smtpport; /* SEK - try all addresses */ for (aptr = hp -> h_addr_list; *aptr; aptr++) { bcopy (*aptr, (char *)&sin.sin_addr, hp -> h_length); PP_NOTICE (("Attempting open to [%s]", inet_ntoa (sin.sin_addr))); if ((skt = start_conn (&sin, hp -> h_name, errstr)) == NOTOK) continue; fds[0] = skt; fds[1] = dup (skt); if ((sm_rfp = fdopen (fds[0], "r")) == NULL || (sm_wfp = fdopen (fds[1], "w")) == NULL) { return (RP_LIO); } if (timeout(SM_ATIME)) { (void) sprintf (errstr, "Timeout opening %s", hostnam); sm_nclose (NOTOK); return( RP_BHST ); } if (rp_isbad (retval = sm_irdrply ())) { (void) sprintf (errstr, "Bad response from %s: %s", hostnam, smtp_error ()); timeout (0); sm_nclose (NOTOK); return(retval); } timeout (0); if( sm_rp.sm_rval != 220 ) { sm_nclose (NOTOK); return( RP_BHST ); } /* HELO is part of protocol - all commands are 4 letters long */ (void) sprintf (linebuf, "HELO %s", loc_dom_mta); if (rp_isbad (sm_cmd( linebuf, SM_HTIME)) || sm_rp.sm_rval != 250 ) { (void) sprintf (errstr, "Bad response to helo: %s", smtp_error()); sm_nclose (NOTOK); return (RP_RPLY); } PP_NOTICE (("Connected to %s [%s]", hostnam, inet_ntoa (sin.sin_addr))); return (RP_OK); } return (RP_BHST); /* No addresses OK */ } sm_nclose (type) /* end current connection */ short type; /* clean or dirty ending */ { if (type == OK && sm_wfp) sm_cmd ("QUIT", SM_QTIME); if (sm_rfp == NULL && sm_wfp == NULL) return; PP_NOTICE (("Closing connection to %s", open_host)); if (open_host) free(open_host); open_host = NULLCP; if (timeout(15)) { return; } if (sm_rfp != NULL) (void) fclose (sm_rfp); if (sm_wfp != NULL) (void) fclose (sm_wfp); timeout (0); sm_rfp = sm_wfp = NULL; }