home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pp / pp-6.0 / Chans / decnet / decnet.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-18  |  14.8 KB  |  682 lines

  1. /* decnet.c: main decnet program */
  2.  
  3. # ifndef lint
  4. static char Rcsid[] = "@(#)$Header: /xtel/pp/pp-beta/Chans/decnet/RCS/decnet.c,v 6.0 1991/12/18 20:06:35 jpo Rel $";
  5. # endif
  6.  
  7. /*
  8.  * $Header: /xtel/pp/pp-beta/Chans/decnet/RCS/decnet.c,v 6.0 1991/12/18 20:06:35 jpo Rel $
  9.  *
  10.  * $Log: decnet.c,v $
  11.  * Revision 6.0  1991/12/18  20:06:35  jpo
  12.  * Release 6.0
  13.  *
  14.  */
  15.  
  16. /*
  17.  * Mail11 channel for PP
  18.  */
  19.  
  20. #include "head.h"
  21. #include "chan.h"
  22. #include "prm.h"
  23. #include "q.h"
  24. #include "dr.h"
  25. #include "qmgr.h"
  26. #include <sys/stat.h>
  27.  
  28. /* Externs */
  29. extern  char    *quedfldir;
  30. extern void     rd_end(), chan_init(), err_abrt(), timer_start(), timer_end();
  31. FILE            *msg_fp;
  32. extern char     *rfc_de();
  33. extern char     de_status_text[];
  34.  
  35. /* Local variables */
  36. CHAN *mychan;                           /* Our channel structure */
  37. char *sender;                           /* Message sender */
  38. char *this_msg;                         /* Message id */
  39. char *cur_host = NULLCP;                /* Current host */
  40. char *open_host = NULLCP;
  41. char bp_name[MAXPATHLENGTH];                 /* Body part file name */
  42. FILE *bp;                               /* Body part file descriptor */
  43. int strip = 0;                          /* If true then strip headers */
  44. int cc_ok = 0;                          /* If true then may send cc line */
  45. int mrgate = 0;                         /* If true then talking to MRGATE */
  46. int map_space = 0;                      /* If true then map <space_char> to ' ' */
  47. char space_char = '_';                  /* Character which will be substituted by ' ' */
  48. int  de_fd;                             /* File descriptor for decnet */
  49. int     open_state;                     /* defines meaning of open_host */
  50. #define STATE_INITIAL   0
  51. #define STATE_OPEN      1
  52. #define STATE_BAD_HOST  2
  53. #define STATE_TIMED_OUT 3
  54.  
  55. /* Local Procedures */
  56. char                            *fix_header();
  57. void                            dirinit();
  58. int                             chaninit(),
  59.                 endproc();
  60. struct type_Qmgr_DeliveryStatus *process();
  61. static int data_bytes;
  62.  
  63. main(argc, argv)
  64. int argc;
  65. char **argv;
  66. {
  67.  
  68.     /* First initialise the channel */
  69.  
  70.     chan_init(argv[0]);
  71.  
  72.     /* Go to correct directory */
  73.  
  74.     dirinit();
  75.  
  76. #ifdef PP_DEBUG
  77.     if (argc > 1 && strcmp(argv[1], "debug") == 0)
  78.         debug_channel_control(argc, argv, chaninit, process, endproc);
  79.     else
  80. #endif
  81.         channel_control(argc, argv, chaninit, process, endproc);
  82.     exit(0);
  83. }
  84.  
  85. static int chaninit(arg)
  86. struct type_Qmgr_Channel *arg;
  87. {
  88.     extern char *strstr();
  89.     char *p = qb2str(arg);
  90.  
  91.     /* Check channel OK */
  92.     if ((mychan = ch_nm2struct(p)) == (CHAN *)0)
  93.         err_abrt(RP_PARM, "Channel `%s' not known", p);
  94.     /* Do any initialising */
  95.  
  96.     rename_log(p);
  97.     PP_NOTICE (("starting %s (%s)", mychan -> ch_name, mychan -> ch_show));
  98.  
  99.     /* Check the config options */
  100.     strip = (strstr(mychan->ch_out_info, "strip") != NULLCP);
  101.     mrgate = (strstr(mychan->ch_out_info, "mrgate") != NULLCP);
  102.     map_space = (strstr(mychan->ch_out_info, "map_space") != NULLCP);
  103.  
  104.     PP_TRACE (("options: strip(%d) mrgate(%d) map_space(%d)", strip, mrgate, map_space));
  105.  
  106.     free(p);
  107.     return (OK);
  108. }
  109.  
  110. static int endproc()
  111. {
  112.     PP_TRACE(("endproc()"));
  113. }
  114.  
  115. static struct type_Qmgr_DeliveryStatus *process(arg)
  116. struct type_Qmgr_ProcMsg *arg;
  117. {
  118.     struct prm_vars prm;
  119.     struct type_Qmgr_UserList *up;
  120.     Q_struct Qstruct, *qp = &Qstruct;
  121.     int retval;
  122.     ADDR    *ap,
  123.         *ad_sendr = NULLADDR,
  124.         *ad_recip = NULLADDR,
  125.         *alp,
  126.         *ad_list = NULLADDR;
  127.     int ad_count;
  128.  
  129.     PP_TRACE(("process()"));
  130.     if (this_msg) free(this_msg);
  131.  
  132.     this_msg = qb2str (arg -> qid);
  133.  
  134.     PP_TRACE(("process msg %s", this_msg));
  135.  
  136.     memset((char *)&prm, 0, sizeof(prm));
  137.     memset((char *)qp, 0, sizeof(*qp));
  138.  
  139.     (void) delivery_init(arg->users);
  140.  
  141.     retval = rd_msg(this_msg, &prm, qp, &ad_sendr, &ad_recip, &ad_count);
  142.  
  143.     if (rp_isbad(retval))
  144.     {
  145.         PP_LOG(LLOG_EXCEPTIONS,("rd_msg err: %s", this_msg));
  146.         return delivery_setall(int_Qmgr_status_messageFailure);
  147.     }
  148.  
  149.     sender = ad_sendr->ad_r822adr;
  150.     PP_TRACE(("sender: %s", sender));
  151.  
  152.     for (ap = ad_recip; ap; ap = ap->ad_next)
  153.     {
  154.         for (up = arg->users; up; up = up->next)
  155.         {
  156.             if (up->RecipientId->parm != ap->ad_no)
  157.                 continue;
  158.             switch (chan_acheck (ap, mychan,
  159.                          ad_list == NULLADDR, &cur_host)) {
  160.                 default:
  161.                 case NOTOK:
  162.                 continue;
  163.  
  164.                 case OK:
  165.                 break;
  166.             }
  167.             break;
  168.         }
  169.         if (up == NULL)
  170.             continue;
  171.  
  172.         if (ad_list == NULLADDR)
  173.         {
  174.             PP_DBG(("allocating ad_list and alp"));
  175.             ad_list = alp = (ADDR *)calloc(1, sizeof(*alp));
  176.         }
  177.         else
  178.         {
  179.             PP_DBG(("allocating alp"));
  180.             alp->ad_next = (ADDR *)calloc(1, sizeof(*alp));
  181.             alp = alp->ad_next;
  182.         }
  183.         *alp = *ap;
  184.         alp->ad_next = NULLADDR;
  185.     }
  186.  
  187.     if (ad_list == NULLADDR)
  188.     {
  189.         PP_LOG(LLOG_EXCEPTIONS, ("No recipients in user list"));
  190.         rd_end();
  191.         q_free (qp);
  192.         return deliverystate;
  193.     }
  194.  
  195.     PP_NOTICE (("processing msg %s to %s", this_msg, cur_host));
  196.  
  197.     deliver(ad_list, qp);
  198.  
  199.     q_free (qp);
  200.     rd_end();
  201.  
  202.     return deliverystate;
  203. }
  204.  
  205. /* Do delivery of message */
  206.  
  207. deliver(ad_list, qp)
  208. ADDR *ad_list;
  209. Q_struct *qp;
  210. {
  211.     ADDR *ap;
  212.     int     naddrs, good_cnt, bad_cnt;
  213.     char    buf [LINESIZE];
  214.     struct timeval data_time;
  215.  
  216.     PP_TRACE(("deliver()"));
  217.  
  218.     if (lexequ (cur_host, open_host) != 0)
  219.     {
  220.         /* Brand new host */
  221.  
  222.         if (open_host != NULLCP)
  223.         {
  224.             free (open_host);
  225.             if (open_state == STATE_OPEN)
  226.                 de_nclose (OK);
  227.         }
  228.         open_host = strdup (cur_host);
  229.  
  230.         switch (de_nopen (cur_host, buf))
  231.         {
  232.             case RP_OK:
  233.                 open_state = STATE_OPEN;
  234.                 break;
  235.             case RP_NO:
  236.                 open_state = STATE_BAD_HOST;
  237.                 break;
  238.             default:
  239.                 open_state = STATE_TIMED_OUT;
  240.                 break;
  241.         }
  242.     }
  243.  
  244.     switch (open_state)
  245.     {
  246.         case STATE_OPEN:
  247.             break;          /* just carry on */
  248.         case STATE_BAD_HOST:
  249.             PP_NOTICE ((buf));
  250.             set_all_dr (qp, ad_list, this_msg,
  251.                  DRR_UNABLE_TO_TRANSFER,
  252.                  DRD_UNRECOGNISED_OR,
  253.                  buf);
  254.             wr_q2dr (qp, this_msg);
  255.             (void) delivery_setall (int_Qmgr_status_negativeDR);
  256.             return;
  257.         case STATE_TIMED_OUT:
  258.             PP_NOTICE (("Connection failed to '%s': %s",
  259.                     cur_host, buf));
  260.             (void) delivery_setallstate
  261.                 (int_Qmgr_status_mtaFailure,
  262.                  buf);
  263.             return;
  264.     }
  265.  
  266.     naddrs = 0;
  267.  
  268.     if (do_sender (ad_list, sender) == NOTOK)
  269.         return;
  270.  
  271.     for (ap = ad_list; ap; ap = ap -> ad_next) {
  272.         switch (do_recip (ap, qp) ){
  273.             case OK:
  274.             naddrs ++;
  275.             break;
  276.  
  277.             case NOTOK:
  278.             break;
  279.  
  280.             default:
  281.             return;
  282.         }
  283.     }
  284.  
  285.     if (naddrs == 0) {
  286.         (void) reset ();
  287.         wr_q2dr (qp, this_msg);
  288.         PP_NOTICE ((">>> Message %s transfered to no recipients",
  289.                 this_msg, naddrs));
  290.         delivery_setall (int_Qmgr_status_negativeDR);
  291.         return;
  292.     }
  293.     /* Terminate list of addressees */
  294.     de_mark();
  295.  
  296.     data_bytes = 0;
  297.     timer_start (&data_time);
  298.  
  299.     /* Send To: Cc: and Subj: headers */
  300.     if (rp_isbad(de_headers(ad_list)))
  301.     {
  302.         PP_NOTICE((">>> Message %s failed during header transfer",
  303.                 this_msg));
  304.         msg_rend();
  305.         return;
  306.     }
  307.  
  308.     /* Send message body */
  309.     if (rp_isbad(de_txt()))
  310.     {
  311.         (void) delivery_setallstate (int_Qmgr_status_messageFailure,
  312.             "failure during body transfer");
  313.         PP_NOTICE((">>> Message %s failed during body transfer",
  314.                 this_msg));
  315.         (void) reset();
  316.         msg_rend();
  317.         return;
  318.     }
  319.  
  320.     /* Sit and receive the status codes */
  321.     bad_cnt = good_cnt = 0;
  322.     for (ap = ad_list; ap; ap = ap->ad_next)
  323.     {
  324.         if (ap->ad_resp)
  325.         {
  326.             switch (de_status())
  327.             {
  328.             case RP_NIO:
  329.                 delivery_setstate (ap -> ad_no, int_Qmgr_status_mtaAndMessageFailure, "channel failure during final status phase");
  330.                 bad_cnt++;
  331.                 break;
  332.             case RP_OK:
  333.                 (void) wr_ad_status (ap, AD_STAT_DONE);
  334.                 if (ap -> ad_usrreq == AD_USR_CONFIRM ||
  335.                     ap -> ad_mtarreq == AD_MTA_CONFIRM ||
  336.                     ap -> ad_mtarreq == AD_MTA_AUDIT_CONFIRM)
  337.                 {
  338.                     set_1dr (qp, ap -> ad_no, this_msg,
  339.                         DRR_NO_REASON, -1, NULLCP);
  340.                     delivery_set (ap -> ad_no,
  341.                         int_Qmgr_status_positiveDR);
  342.                 }
  343.                 else {
  344.                     delivery_set (ap -> ad_no, int_Qmgr_status_success);
  345.                     wr_stat (ap, qp, this_msg, data_bytes);
  346.                 }
  347.                 good_cnt++;
  348.                 break;
  349.             case RP_NO:
  350.                 set_1dr (qp, ap->ad_no, this_msg,
  351.                     DRR_TRANSFER_FAILURE,
  352.                     DRD_MTA_CONGESTION,
  353.                     de_status_text);
  354.                 delivery_setstate (ap -> ad_no,
  355.                            int_Qmgr_status_negativeDR,
  356.                            "message transfer failed during final status phase");
  357.                 bad_cnt++;
  358.                 break;
  359.             default:
  360.                 set_1dr (qp, ap->ad_no, this_msg,
  361.                     DRR_TRANSFER_FAILURE,
  362.                     DRD_MTA_CONGESTION,
  363.                     "final status failure (unknown reason)");
  364.                 delivery_setstate (ap -> ad_no, int_Qmgr_status_negativeDR, "internal MTA failure during final status phase");
  365.                 bad_cnt++;
  366.                 break;
  367.             }
  368.         }
  369.     }
  370.     timer_end (&data_time, data_bytes, "Data Transfered");
  371.  
  372.     wr_q2dr (qp, this_msg);
  373.     PP_NOTICE ((">>> Message %s transferred to %d recipients, failed on %d recipients",
  374.             this_msg, good_cnt, bad_cnt));
  375.     /* Unlock the message files */
  376.     msg_rend();
  377. }
  378.  
  379. /* Change in PP queue space */
  380.  
  381. static void dirinit()
  382. {
  383.     if (chdir(quedfldir) < 0)
  384.         err_abrt(RP_LIO, "Unable to change directory to `%s'", quedfldir);
  385. }
  386.  
  387. /* Send the `sender field' */
  388.  
  389. do_sender(ap, sndr)
  390. ADDR *ap;
  391. char *sndr;
  392. {
  393.     char *formatdir;
  394.     char buf[LINESIZE];
  395.     char *from = NULLCP;
  396.  
  397.     PP_TRACE(("do_sender()"));
  398.  
  399.     if (qid2dir (this_msg, ap, TRUE, &formatdir) == NOTOK) {
  400.         PP_LOG (LLOG_EXCEPTIONS, ("Can't locate message %s",
  401.                       this_msg));
  402.         (void) delivery_setallstate (int_Qmgr_status_messageFailure,
  403.                     "Can't find message");
  404.         (void) reset ();
  405.         return NOTOK;
  406.     }
  407.  
  408.     if (rp_isbad (msg_rinit (formatdir))) {
  409.         PP_LOG (LLOG_EXCEPTIONS, ("Can't read message %s files",
  410.                       this_msg));
  411.         (void) delivery_setallstate (int_Qmgr_status_messageFailure,
  412.                     "Can't read message");
  413.         reset ();
  414.         return NOTOK;
  415.     }
  416.  
  417.     /* Get the first file (which will be the header) */
  418.  
  419.     if (rp_isbad (msg_rfile (bp_name))) {
  420.         PP_LOG (LLOG_EXCEPTIONS, ("Can't initialise message %s files",
  421.                       this_msg));
  422.         (void) delivery_setallstate (int_Qmgr_status_messageFailure,
  423.                     "Can't read message file name");
  424.         reset ();
  425.         return NOTOK;
  426.     }
  427.  
  428.     PP_TRACE(("message file (%s)", bp_name));
  429.     /* open the file */
  430.     if ((bp = fopen(bp_name, "r")) == 0)
  431.     {
  432.         PP_LOG (LLOG_EXCEPTIONS, ("Can't open bp %s file",
  433.                       this_msg));
  434.         (void) delivery_setallstate (int_Qmgr_status_messageFailure,
  435.                     "Can't open bp file");
  436.         reset ();
  437.         return NOTOK;
  438.     }
  439.  
  440.     /* Now extract the From: line (removing the terminating
  441.        newline */
  442.     while (fgets(buf, sizeof(buf), bp) != 0)
  443.     {
  444.         buf[strlen(buf) - 1] = '\0';
  445.         if (strncmp(buf, "From:", 5) == 0)
  446.         {
  447.             from = strdup(fix_header(buf));
  448.             break;
  449.         }
  450.     }
  451.  
  452.     /* Check if we are sending to a mail router. If so then we have
  453.     to make the sender address look as VMSish as possible */
  454.     if (mrgate)
  455.     {
  456.         return (de_send((from) ? rfc_de(from) : rfc_de(sndr)));
  457.     }
  458.  
  459.     /* Check and see if the sender needs quotes to protect it from the
  460.     depredations of VMS */
  461.  
  462.     if (strpbrk((from) ? from : sndr, "@%:,") != 0)
  463.         sprintf(buf, "\"%s\"", (from) ? from : sndr);
  464.     else
  465.         strcpy(buf, (from) ? from: sndr);
  466.  
  467.     return (de_send(buf));
  468. }
  469.  
  470. /* This routine passes over a single recipient address */
  471.  
  472. do_recip (ap, qp)
  473. ADDR    *ap;
  474. Q_struct *qp;
  475. {
  476.     char    errbuf[BUFSIZ];
  477.  
  478.     PP_NOTICE (("Recipient %s", ap -> ad_r822adr));
  479.  
  480.     switch (de_wto (ap ->ad_r822adr))
  481.     {
  482.     case RP_AOK:
  483.         ap -> ad_resp = 1;
  484.         return OK;
  485.  
  486.     case RP_NIO:
  487.         (void) delivery_setstate (ap -> ad_no,
  488.             int_Qmgr_status_messageFailure,
  489.                 "network error");
  490.         PP_LOG (LLOG_EXCEPTIONS, ("Temporary failure: %s",
  491.                     "network error"));
  492.         ap -> ad_resp = 0;
  493.         return NOTOK;
  494.  
  495.     case RP_USER:
  496.         (void) delivery_set (ap -> ad_no,
  497.             int_Qmgr_status_negativeDR);
  498.         (void) sprintf (errbuf,
  499.             "MTA '%s' rejects address %s",
  500.             cur_host, ap->ad_r822adr);
  501.         PP_LOG (LLOG_EXCEPTIONS, ("User error: %s", errbuf));
  502.         set_1dr (qp, ap -> ad_no, this_msg,
  503.             DRR_UNABLE_TO_TRANSFER,
  504.             DRD_UNRECOGNISED_OR,
  505.             errbuf);
  506.         ap -> ad_resp = 0;
  507.         return NOTOK;
  508.  
  509.     default:
  510.         PP_LOG (LLOG_EXCEPTIONS, ("Message failure: %s",
  511.                     "unknown error"));
  512.         (void) delivery_setallstate (int_Qmgr_status_messageFailure,
  513.                 "unknown error");
  514.         (void) reset ();
  515.         return DONE;
  516.     }
  517. }
  518.  
  519. /* This routine gets and sends the header lines */
  520.  
  521. de_headers(ap)
  522. ADDR *ap;
  523. {
  524.     char line[BUFSIZ];
  525.     char    *to = NULLCP,
  526.         *subject = NULLCP,
  527.         *cc = NULLCP;
  528.  
  529.     PP_TRACE(("de_headers()"));
  530.  
  531.     /* Rewind the header file (opened by de_from) */
  532.     rewind(bp);
  533.  
  534.     /* Now extract the To:, Cc: and Subject lines (removing the terminating
  535.        newline */
  536.     while (fgets(line, sizeof(line), bp) != 0)
  537.     {
  538.         line[strlen(line) - 1] = '\0';
  539.         if (strncmp(line, "To:", 3) == 0)
  540.         {
  541.             to = strdup(line);
  542.         }
  543.         else if (strncmp(line, "Subject:", 8) == 0)
  544.         {
  545.             subject = strdup(line);
  546.         }
  547.         else if (strncmp(line, "Cc:", 3) == 0)
  548.         {
  549.             cc = strdup(line);
  550.         }
  551.     }
  552.  
  553.     /* Send the various fields */
  554.     if (rp_isbad(de_send((to) ? fix_header(to) : "(Unknown)"))
  555.         || (cc_ok && rp_isbad(de_send((cc) ? fix_header(cc) : "")))
  556.         || rp_isbad(de_send((subject) ? fix_header(subject) : "(None)")))
  557.     {
  558.         (void) delivery_setstate (ap -> ad_no,
  559.             int_Qmgr_status_messageFailure,
  560.                 "network error");
  561.         PP_LOG (LLOG_EXCEPTIONS, ("Temporary failure: %s",
  562.                     "network error"));
  563.         return NOTOK;
  564.     }
  565.  
  566.     /* Clean up */
  567.     if (to) free(to);
  568.     if (subject) free(subject);
  569.     if (cc) free(cc);
  570.  
  571.     return OK;
  572. }
  573.  
  574. /* This routine gets and sends the message text */
  575.  
  576. de_txt()
  577. {
  578.     char line[BUFSIZ];
  579.     int n;
  580.  
  581.     PP_TRACE(("de_txt()"));
  582.     /* If we have set header stripping then close the header */
  583.     if (strip)
  584.     {
  585.         fclose(bp);
  586.         /* If there is no more body parts, just wrap up */
  587.         if (msg_rfile(bp_name) == RP_DONE)
  588.         {
  589.             de_mark();
  590.             return OK;
  591.         }
  592.         /* other wise open the next body part */
  593.         if ((bp = fopen(bp_name, "r")) == 0)
  594.         {
  595.             PP_LOG (LLOG_EXCEPTIONS, ("Can't open bp %s file",
  596.                         this_msg));
  597.             (void) delivery_setallstate (int_Qmgr_status_messageFailure,
  598.                         "Can't open bp file");
  599.             reset ();
  600.             return NOTOK;
  601.         }
  602.     }
  603.     else
  604.     {
  605.         rewind(bp);
  606.     }
  607.  
  608.     /* Now iterate through the body parts */
  609.     while (1)
  610.     {
  611.         /* Send a body part */
  612.         while (fgets(line, sizeof(line), bp) != 0)
  613.         {
  614.             line[(n = strlen(line)) - 1] = '\0';
  615.             n--;
  616.             data_bytes += n;
  617.             if (rp_isbad(de_send(line)))
  618.             {
  619.                 return NOTOK;
  620.             }
  621.         }
  622.         /* Send a blank line to seperate the body parts */
  623.         de_send("");
  624.  
  625.         /* Close it and get the next one */
  626.         fclose(bp);
  627.  
  628.         /* If there is no more body parts, just wrap up */
  629.         if (msg_rfile(bp_name) == RP_DONE)
  630.             break;
  631.  
  632.         /* other wise open the next body part */
  633.         if ((bp = fopen(bp_name, "r")) == 0)
  634.         {
  635.             PP_LOG (LLOG_EXCEPTIONS, ("Can't open bp %s file",
  636.                         this_msg));
  637.             (void) delivery_setallstate (int_Qmgr_status_messageFailure,
  638.                         "Can't open bp file");
  639.             reset ();
  640.             return NOTOK;
  641.         }
  642.     }
  643.     de_mark();
  644.     return OK;
  645. }
  646.  
  647. /* This is the equivalent of the `reset' function. However, since mail11
  648.    doesn't have the ability to reset, we have to close down the connection
  649.  */
  650.  
  651. reset()
  652. {
  653.     PP_TRACE(("reset()"));
  654.  
  655.     if (open_host != NULLCP)
  656.     {
  657.         free (open_host);
  658.         if (open_state == STATE_OPEN)
  659.             de_nclose (OK);
  660.         open_host = NULLCP;
  661.     }
  662. }
  663.  
  664. /* This trivial little function takes a header line and returns a pointer
  665.    to the first non space character after the first `:'
  666.  */
  667.  
  668. char *fix_header(h)
  669. char *h;
  670. {
  671.     char *s;
  672.     extern char *strchr();
  673.  
  674.     if ((s = strchr(h, ':')) != NULL)
  675.     {
  676.         while (*++s == ' ');
  677.         return s;
  678.     }
  679.     return h;
  680.  
  681. }
  682.