|
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: 12618 (0x314a) Types: TextFile Names: »smtp.c«
└─⟦2d1937cfd⟧ Bits:30007241 EUUGD22: P.P 5.0 └─⟦dc59850a2⟧ »EurOpenD22/pp5.0/pp-5.tar.Z« └─⟦e5a54fb17⟧ └─⟦this⟧ »pp-5.0/Chans/smtp/smtp.c«
/* smtp: as invoked by qmgr to deliver smtp stuff*/ # ifndef lint static char Rcsid[] = "@(#)$Header: /cs/research/pp/hubris/pp-beta/Chans/smtp/RCS/smtp.c,v 5.0 90/09/20 15:54:26 pp Exp Locker: pp $"; # endif /* * $Header: /cs/research/pp/hubris/pp-beta/Chans/smtp/RCS/smtp.c,v 5.0 90/09/20 15:54:26 pp Exp Locker: pp $ * * $Log: smtp.c,v $ * Revision 5.0 90/09/20 15:54:26 pp * rcsforce : 5.0 public release * */ #include "head.h" #include "chan.h" #include "prm.h" #include "q.h" #include "dr.h" #include "qmgr.h" #include <pwd.h> #include <sys/file.h> #include <signal.h> extern char *aquedir, *mquedir, *quedfldir; extern void rd_end(), chan_init(), err_abrt(), timer_start(), timer_end(); FILE *msg_fp; CHAN *mychan; char *this_msg; int smtpport = 0; extern struct sm_rstruct { /* save last reply obtained */ 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 : "") extern time_t time(); #define SM_RTIME 15 /* Time allowed for a RSET command */ #define SM_DTIME 120 /* Time allowed for a DATA command */ #define SM_PTIME 600 /* Time allowed for the "." command */ #define SM_TTIME 180 /* Time allowed for a block of text */ static struct type_Qmgr_DeliveryStatus *process(); static void dirinit(); static int chaninit(); static int endproc (); static int dotext (); static int copy (); /* --------------------- Begin Routines -------------------------------- */ main (argc, argv) int argc; char **argv; { char *p; int opt; extern char *optarg; if (p = rindex (argv[0], '/')) p ++; if (p == NULLCP || *p == NULL) p = argv[0]; chan_init (p); /* init the channel - and find out who we are */ while ((opt = getopt (argc, argv, "p:")) != EOF) { switch (opt) { case 'p': smtpport = htons (atoi (optarg)); break; default: PP_LOG (LLOG_EXCEPTIONS, ("Bad argument -%c", opt)); break; } } dirinit(); /* get to the right directory */ (void) signal (SIGPIPE, SIG_IGN); #ifdef PP_DEBUG if (argc > 1 && strcmp (argv[1], "debug") == 0) debug_channel_control (argc, argv, chaninit, process, endproc); else #endif channel_control (argc, argv, chaninit, process, endproc); exit (0); } static int chaninit (arg) struct type_Qmgr_Channel *arg; { char *p = qb2str (arg); if ((mychan = ch_nm2struct (p)) == (CHAN *)0) err_abrt (RP_PARM, "Channel '%s' not known", p); rename_log(p); sm_init (mychan); PP_NOTICE (("starting %s (%s)", mychan -> ch_name, mychan -> ch_show)); free (p); return OK; } char *cur_host; char *open_host; int open_state; /* defines meaning of open_host */ #define STATE_INITIAL 0 #define STATE_OPEN 1 #define STATE_BAD_HOST 2 #define STATE_TIMED_OUT 3 char *sender; char *formatdir; static int endproc () { if (cur_host) sm_nclose (OK); } static struct type_Qmgr_DeliveryStatus *process (arg) struct type_Qmgr_ProcMsg *arg; { struct prm_vars prm; struct type_Qmgr_UserList *up; Q_struct Qstruct, *qp = &Qstruct; int retval; ADDR *ap, *ad_sendr = NULLADDR, *ad_recip = NULLADDR, *alp = NULLADDR, *ad_list = NULLADDR; int ad_count; if (this_msg) free (this_msg); this_msg = qb2str (arg -> qid); bzero ((char *)&prm, sizeof prm); bzero ((char *)qp, sizeof *qp); (void) delivery_init (arg -> users); retval = rd_msg (this_msg, &prm, qp, &ad_sendr, &ad_recip, &ad_count); if (rp_isbad (retval)) { PP_LOG (LLOG_EXCEPTIONS, ("rd_msg err: %s", this_msg)); return delivery_setallstate (int_Qmgr_status_messageFailure, "Can't read message"); } sender = ad_sendr -> ad_r822adr; for (ap = ad_recip; ap; ap = ap -> ad_next) { for (up = arg ->users; up; up = up -> next) { if (up -> RecipientId -> parm != ap -> ad_no) continue; switch (chan_acheck (ap, mychan, ad_list == NULLADDR, &cur_host)) { default: case NOTOK: continue; case OK: break; } break; } if (up == NULL) continue; if (ad_list == NULLADDR) ad_list = alp = (ADDR *) calloc (1, sizeof *alp); else { alp -> ad_next = (ADDR *) calloc (1, sizeof *alp); alp = alp -> ad_next; } *alp = *ap; alp -> ad_next = NULLADDR; } if (ad_list == NULLADDR) { PP_LOG (LLOG_EXCEPTIONS, ("No recipients in user list")); rd_end (); q_free (qp); return deliverystate; } PP_NOTICE (("processing msg %s to %s", this_msg, cur_host)); deliver (ad_list, qp); q_free (qp); rd_end(); return deliverystate; } static void dirinit() /* Change into pp queue space */ { if (chdir (quedfldir) < 0) err_abrt (RP_LIO, "Unable to change directory to '%s'", quedfldir); } deliver (ad_list, qp) ADDR *ad_list; Q_struct *qp; { ADDR *ap; int naddrs; char buf [LINESIZE]; PP_TRACE (("deliver ()")); if (lexequ (cur_host, open_host) != 0) { /* Brand new host */ if (open_host != NULLCP) { free (open_host); if (open_state == STATE_OPEN) sm_nclose (OK); } open_host = strdup (cur_host); switch (sm_nopen (cur_host, buf)) { case RP_OK: open_state = STATE_OPEN; break; case RP_NO: open_state = STATE_BAD_HOST; break; default: open_state = STATE_TIMED_OUT; break; } } switch (open_state) { case STATE_OPEN: break; /* just carry on */ case STATE_BAD_HOST: PP_NOTICE ((buf)); set_all_dr (qp, ad_list, DRR_UNABLE_TO_TRANSFER, DRD_UNRECOGNISED_OR, buf); wr_q2dr (qp, this_msg); (void) delivery_setall (int_Qmgr_status_negativeDR); return; case STATE_TIMED_OUT: PP_NOTICE (("Connection failed to '%s': %s", cur_host, buf)); (void) delivery_setallstate (int_Qmgr_status_mtaFailure, buf); return; } naddrs = 0; if (do_sender (sender) == NOTOK) return; for (ap = ad_list; ap; ap = ap -> ad_next) { switch (do_recip (ap, qp) ){ case OK: naddrs ++; break; case NOTOK: break; default: return; } } if (naddrs == 0) { (void) reset (); wr_q2dr (qp, this_msg); PP_NOTICE ((">>> Message %s transfered to no recipients", this_msg, naddrs)); delivery_setall (int_Qmgr_status_negativeDR); return; } if (dotext (ad_list, naddrs) == NOTOK) return; for (ap = ad_list; ap; ap = ap -> ad_next) { if (ap -> ad_resp) { if (ap -> ad_usrreq == AD_USR_CONFIRM || ap -> ad_mtarreq == AD_MTA_CONFIRM || ap -> ad_mtarreq == AD_MTA_AUDIT_CONFIRM) { set_1dr (qp, ap -> ad_no, DRR_NO_REASON, -1, NULLCP); delivery_set (ap -> ad_no, int_Qmgr_status_positiveDR); } else { (void) wr_ad_status (ap, AD_STAT_DONE); delivery_set (ap -> ad_no, int_Qmgr_status_success); } } } wr_q2dr (qp, this_msg); PP_NOTICE ((">>> Message %s transfered to %d recipients", this_msg, naddrs)); } do_recip (ap, qp) ADDR *ap; Q_struct *qp; { int retval; char errbuf[BUFSIZ]; PP_NOTICE (("Recipient %s", ap -> ad_r822adr)); if (rp_isbad (retval = sm_wto (ap ->ad_r822adr))) { switch (retval) { case RP_DHST: PP_LOG (LLOG_EXCEPTIONS, ("Host died")); (void) delivery_setallstate (int_Qmgr_status_mtaAndMessageFailure, "Host died"); return DONE; case RP_AOK: ap -> ad_resp = 1; return OK; case RP_AGN: (void) delivery_setstate (ap -> ad_no, int_Qmgr_status_messageFailure, smtp_error ()); PP_LOG (LLOG_EXCEPTIONS, ("Temporary failure: %s", smtp_error ())); ap -> ad_resp = 0; return NOTOK; case RP_USER: (void) delivery_set (ap -> ad_no, int_Qmgr_status_negativeDR); (void) sprintf (errbuf, "MTA '%s' gives error message %s", cur_host, smtp_error ()); PP_LOG (LLOG_EXCEPTIONS, ("User error: %s", errbuf)); set_1dr (qp, ap -> ad_no, DRR_UNABLE_TO_TRANSFER, DRD_UNRECOGNISED_OR, errbuf); ap -> ad_resp = 0; return NOTOK; case RP_PARM: ap -> ad_resp = 0; PP_LOG (LLOG_EXCEPTIONS, ("Parameter problem: %s", smtp_error())); (void) delivery_setstate (ap -> ad_no, int_Qmgr_status_messageFailure, smtp_error ()); return NOTOK; case RP_RPLY: default: PP_LOG (LLOG_EXCEPTIONS, ("Message failure: %s", smtp_error ())); (void) delivery_setallstate (int_Qmgr_status_messageFailure, smtp_error ()); (void) reset (); return DONE; } } return OK; } do_sender (sndr) char *sndr; { int retval; PP_NOTICE (("sender %s", sndr)); if (rp_isbad (retval = sm_wfrom (sender))) { switch (retval) { case RP_DHST: PP_LOG (LLOG_EXCEPTIONS, ("Host connection died")); (void) delivery_setallstate (int_Qmgr_status_mtaAndMessageFailure, "host connection failed"); sm_nclose (NOTOK); return NOTOK; case RP_PARM: PP_LOG (LLOG_EXCEPTIONS, ("Parameter problem: %s", smtp_error())); (void) delivery_setallstate (int_Qmgr_status_mtaAndMessageFailure, smtp_error ()); sm_nclose (NOTOK); return NOTOK; case RP_AGN: (void) delivery_setallstate (int_Qmgr_status_messageFailure, smtp_error ()); PP_LOG (LLOG_EXCEPTIONS, ("Temporary error: %s", smtp_error ())); (void) reset (); return NOTOK; case RP_OK: break; default: PP_LOG (LLOG_EXCEPTIONS, ("Protocol error: %s", smtp_error())); (void) delivery_setallstate (int_Qmgr_status_mtaAndMessageFailure, smtp_error ()); sm_nclose (NOTOK); return NOTOK; } } return OK; } extern int data_bytes; static int dotext (ap, naddrs) ADDR *ap; int naddrs; { extern FILE *sm_wfp; int retval; char filename[FILNSIZE]; struct timeval data_time; int first = 1; if (qid2dir (this_msg, ap, TRUE, &formatdir) == NOTOK) { PP_LOG (LLOG_EXCEPTIONS, ("Can't locate message %s", this_msg)); (void) delivery_setallstate (int_Qmgr_status_messageFailure, "Cant find message"); (void) reset (); return NOTOK; } if (rp_isbad (retval = msg_rinit (formatdir))) { (void) delivery_setallstate (int_Qmgr_status_messageFailure, "Can't read message"); reset (); return NOTOK; } if (rp_isbad (sm_cmd ("DATA", SM_DTIME))) { (void) delivery_setallstate (int_Qmgr_status_messageFailure, smtp_error ()); sm_nclose (NOTOK); return (NOTOK); } data_bytes = 0; timer_start (&data_time); while ((retval = msg_rfile (filename)) == RP_OK) { if (rp_isbad (copy (filename))) { (void) delivery_setallstate(int_Qmgr_status_mtaAndMessageFailure, "Can't transfer data"); sm_nclose (NOTOK); return NOTOK; } if (first) { sm_wstm ("\n", 1); first = 0; } } if (rp_isbad (retval)) { (void) delivery_setallstate (int_Qmgr_status_messageFailure, "Message transfer failed"); sm_nclose (NOTOK); return NOTOK; } if (rp_isbad (sm_wstm (NULLCP, 0))) { (void) delivery_setallstate (int_Qmgr_status_messageFailure, "Bad temination of data"); sm_nclose (NOTOK); return NOTOK; } if (rp_isbad (retval = sm_cmd (".", SM_PTIME + 3 * naddrs))) { switch (retval) { case RP_DHST: PP_LOG (LLOG_EXCEPTIONS, ("Host connection died")); (void) delivery_setallstate (int_Qmgr_status_mtaAndMessageFailure, "Connection died"); break; default: PP_LOG (LLOG_EXCEPTIONS, ("Temporary failure: %s", smtp_error ())); (void) delivery_setallstate (int_Qmgr_status_messageFailure, smtp_error ()); break; } return NOTOK; } timer_end (&data_time, data_bytes, "Data Transfered"); msg_rend(); return OK; } static int copy (fname) char *fname; { FILE *ifp; char buf[BUFSIZ]; int n, retval = RP_OK; if ((ifp = fopen (fname,"r")) == NULL) { PP_LOG (LLOG_EXCEPTIONS, ("Can't read file '%s'", fname)); return RP_FOPN; } while ((n = fread (buf, sizeof (char), sizeof (buf), ifp)) > 0) if (rp_isbad (retval = sm_wstm (buf, n))) break; (void) fclose (ifp); return retval; } reset () { int retval; if (rp_isbad (retval = sm_cmd ("RSET", SM_RTIME))) { switch (retval) { default: (void) delivery_setallstate (int_Qmgr_status_mtaFailure, smtp_error ()); sm_nclose (NOTOK); return NOTOK; case RP_OK: break; } } return OK; }