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

  1. /* list.c: list processor channel (both directory and table) */
  2.  
  3. # ifndef lint
  4. static char Rcsid[] = "@(#)$Header: /xtel/pp/pp-beta/Chans/lists/RCS/list.c,v 6.0 1991/12/18 20:10:43 jpo Rel $";
  5. # endif
  6.  
  7. /*
  8.  * $Header: /xtel/pp/pp-beta/Chans/lists/RCS/list.c,v 6.0 1991/12/18 20:10:43 jpo Rel $
  9.  *
  10.  * $Log: list.c,v $
  11.  * Revision 6.0  1991/12/18  20:10:43  jpo
  12.  * Release 6.0
  13.  *
  14.  */
  15.  
  16.  
  17.  
  18. #include "util.h"
  19. #include "head.h"
  20. #include "qmgr.h"
  21. #include "chan.h"
  22. #include "q.h"
  23. #include "dr.h"
  24. #include "or.h"
  25. #include "prm.h"
  26.  
  27. #include <sys/types.h>
  28. #include <sys/stat.h>
  29. #ifdef SYS5
  30. #include <fcntl.h>
  31. #endif
  32.  
  33.  
  34. #ifdef    DIRLIST
  35.  
  36. #include "dlist.h"
  37. #include <isode/quipu/attrvalue.h>
  38.  
  39. #else
  40.  
  41. #include "dl.h"
  42.  
  43. #endif
  44.  
  45. #include "retcode.h"
  46. #include "sys.file.h"
  47. #include <varargs.h>
  48.  
  49. extern void     rd_end(), sys_init(), err_abrt();
  50. extern struct type_Qmgr_DeliveryStatus *delivery_resetDRs();
  51.  
  52. extern ADDR     *adr_new();
  53. extern char     *ad_getlocal();
  54. extern char    *quedfldir;
  55. extern char    *loc_dom_site;
  56. extern OR_ptr     or_std2or(),
  57.         or_default(),
  58.         or_std2or();
  59.  
  60. extern LLog    *log_dsap;
  61. #ifndef    DIRLIST
  62. extern ADDR    *tb_getModerator();
  63. #endif
  64.  
  65. static int     expandList();
  66. static char     *get_adrstr();
  67. static int    get_adrtype();
  68. static void     dirinit();
  69. static void     set_success();
  70. static int     initialise(), endfunc ();
  71. static ADDR     *getnthrecip();
  72. static int     submit_error();
  73. static int     processMsg();
  74. static int    expansionLoop;
  75. static struct type_Qmgr_DeliveryStatus     *process();
  76. static Q_struct                qs;
  77.  
  78. static int    processDR();
  79.  
  80. #ifdef    DIRLIST
  81.  
  82. static ADDR    *construct_sender();
  83. Attr_Sequence    this_list = NULLATTR;
  84. extern int        dir_getdl();
  85. extern AttributeType     at_Owner;
  86. extern AttributeType     at_Policy;
  87. extern AttributeType     at_Member;
  88. extern ADDR            *ORName2ADDR();
  89.  
  90. #endif
  91.  
  92. CHAN         *mychan;
  93. char        *this_msg = NULL, *this_chan = NULL;
  94. int        start_submit;
  95. int        first_successDR, first_failureDR;
  96. int        adrno;
  97. int        expandSublists = FALSE;
  98. int        linked = TRUE;
  99.  
  100. /* -----------------------  Begin  Routines  -------------------------------  */
  101.  
  102.  
  103. main (argc, argv)
  104. int    argc;
  105. char    **argv;
  106. {
  107. #ifdef  DIRLIST
  108. int     n = 1;
  109. #endif
  110.  
  111. #ifdef    PP_DEBUG
  112.     char    pp_debug = FALSE;
  113. #endif
  114.  
  115.     sys_init (argv[0]);
  116.     or_myinit();
  117.     dirinit();
  118.  
  119. #ifdef    DIRLIST
  120.     quipu_syntaxes ();
  121.     pp_syntaxes();
  122. #endif
  123.  
  124. #ifdef PP_DEBUG
  125.     if (argc>1 && (strcmp (argv[1], "debug") == 0))
  126.         pp_debug = TRUE;
  127. #endif
  128.  
  129. #ifdef    DIRLIST
  130.     dsap_init (&n, &argv);
  131.     log_dsap -> ll_file = strdup ("dsap.log");
  132.  
  133.     (void) pp_quipu_run ();
  134. #endif
  135.  
  136. #ifdef    PP_DEBUG
  137.     if (pp_debug)
  138.         debug_channel_control (argc,argv,initialise,process,endfunc);
  139.     else
  140. #endif
  141.         channel_control (argc,argv,initialise,process,endfunc);
  142. }
  143.  
  144.  
  145.  
  146. /* -----------------------  Static Routines  -------------------------------  */
  147.  
  148.  
  149.  
  150. /* --- routine to move to correct place in file system --- */
  151. static void dirinit()
  152. {
  153.     if (chdir (quedfldir) < 0)
  154.         err_abrt (RP_LIO, 
  155.             "Unable to change directory to '%s'", quedfldir);
  156. }
  157.  
  158.  
  159. /* ARGSUSED */
  160. static int endfunc (arg)
  161. struct type_Qmgr_Channel *arg;
  162. {
  163.     if (start_submit == FALSE) 
  164.         io_end (OK);
  165.     start_submit = TRUE;
  166.  
  167. #ifdef    DIRLIST
  168.     dl_unbind();
  169. #endif
  170. }
  171.  
  172.  
  173.  
  174. /* ---   channel initialise routine --- */
  175.  
  176. DN    bindas = NULLDN;
  177. char    *bindpasswd = NULLCP;
  178.  
  179. static void do_ch_info_flags(info)
  180. char    *info;
  181. {
  182.     char    *info_copy, *margv[20];
  183.     int    margc, ix;
  184.  
  185.     if (info == NULLCP) return;
  186.  
  187.     info_copy = strdup(info);
  188.     if ((margc = sstr2arg(info_copy, 20, margv, ",")) > 0) {
  189.         for (ix = 0; ix < margc; ix++) {
  190.             if (lexequ(margv[ix], "dosublists") == 0)
  191.                 expandSublists = TRUE;
  192.             else if (lexequ(margv[ix], "notlinked") == 0)
  193.                 linked = FALSE;
  194.             else if (lexequ(margv[ix], "linked") == 0)
  195.                 linked = TRUE;
  196. #ifdef DIRLIST
  197.             else if (lexnequ(margv[ix], "DN", strlen("DN")) == 0) {
  198.                 char    *dn = index(margv[ix], '=');
  199.                 
  200.                 if (dn == NULLCP)
  201.                     PP_LOG(LLOG_EXCEPTIONS,
  202.                            ("Incorrectly formatted info field '%s' expecting key=value",
  203.                         margv[ix]));
  204.                 else {
  205.                     dn++;
  206.                     if ((bindas = str2dn(dn)) == NULLDN)
  207.                         PP_LOG(LLOG_EXCEPTIONS,
  208.                                ("Invalid DN '%s'",
  209.                             dn));
  210.                 }
  211.             }
  212.             else if (lexnequ(margv[ix], "passwd", strlen("passwd")) == 0) {
  213.                 char    *pd = index(margv[ix], '=');
  214.                 
  215.                 if (pd == NULLCP)
  216.                     PP_LOG(LLOG_EXCEPTIONS,
  217.                            ("Incorrectly formatted info field '%s' expecting key=value",
  218.                         margv[ix]));
  219.                 else {
  220.                     pd++;
  221.                     bindpasswd = strdup(pd);
  222.                 }
  223.             }
  224. #endif
  225.             else 
  226.                 PP_LOG(LLOG_EXCEPTIONS,
  227.                        ("Unknown ch_info flag '%s'",
  228.                     margv[ix]));
  229.         }
  230.     }
  231.     free(info_copy);
  232. }
  233.  
  234. static int initialise (arg)
  235. struct type_Qmgr_Channel    *arg;
  236. {
  237.     char    *name;
  238.  
  239.     name = qb2str (arg);
  240.  
  241.     if ((mychan = ch_nm2struct (name)) == NULLCHAN) {
  242.         PP_OPER (NULLCP, ("Channel '%s' not known", name));
  243.         if (name != NULLCP) 
  244.             free (name);
  245.         return NOTOK;
  246.     }
  247.  
  248.     start_submit = TRUE;
  249.     if (mychan -> ch_out_info != NULLCP)
  250.         do_ch_info_flags(mychan->ch_out_info);
  251.  
  252.     /* --- check if a list channel --- */
  253.     if (name != NULLCP)
  254.         free (name);
  255.  
  256. #ifdef    DIRLIST
  257.     if (dl_bind (bindas, bindpasswd) != OK)
  258.         return NOTOK;
  259. #endif
  260.  
  261.     return OK;
  262. }
  263.  
  264.  
  265.  
  266. /* ---   routine to check if allowed to list process this message --- */
  267.  
  268. static int security_check (msg)
  269. struct type_Qmgr_ProcMsg    *msg;
  270. {
  271.     char     *msg_file = NULLCP, 
  272.         *msg_chan = NULLCP;
  273.     int     result;
  274.  
  275.     result   = TRUE;
  276.     msg_file = qb2str (msg->qid);
  277.     msg_chan = qb2str (msg->channel);
  278.  
  279.     if ((mychan == NULLCHAN) || (strcmp (msg_chan,mychan->ch_name) !=0)) {
  280.         PP_LOG (LLOG_EXCEPTIONS,
  281.                ("channel err: '%s'", msg_chan));
  282.         result = FALSE;
  283.     }
  284.  
  285.     if (msg_file != NULLCP)        free (msg_file);
  286.     if (msg_chan != NULLCP)     free (msg_chan);
  287.  
  288.     return result;
  289. }
  290.  
  291.  
  292.  
  293.  
  294. /* ---   routine called to do list processing --- */
  295.  
  296. static struct type_Qmgr_DeliveryStatus *process (arg)
  297. struct type_Qmgr_ProcMsg *arg;
  298. {
  299.     struct prm_vars            prm;
  300.     Q_struct            que;
  301.     ADDR                *sender = NULL;
  302.     ADDR                *recips = NULL;
  303.     int                 rcount,
  304.                     retval;
  305.     struct type_Qmgr_UserList     *ix;
  306.     ADDR                *adr;
  307.     RP_Buf                reply;
  308.  
  309.  
  310.     bzero ((char *)&prm, sizeof (prm));
  311.     bzero ((char *)&que, sizeof (que));
  312.     
  313.     delivery_init (arg->users);
  314.     delivery_setall (int_Qmgr_status_messageFailure);
  315.     first_failureDR = first_successDR = TRUE;
  316.  
  317.     if (security_check (arg) != TRUE)
  318.         return deliverystate;
  319.  
  320.     if (this_msg != NULLCP)      free (this_msg);
  321.     if (this_chan != NULLCP)  free (this_chan);
  322.  
  323.     this_msg = qb2str (arg->qid);
  324.     this_chan = qb2str (arg->channel);
  325.  
  326.     PP_LOG (LLOG_NOTICE,
  327.            ("processing msg '%s' through '%s'",this_msg, this_chan));
  328.  
  329.     if (rp_isbad (rd_msg (this_msg,&prm,&que,&sender,&recips,&rcount))) {
  330.         PP_LOG (LLOG_EXCEPTIONS,
  331.                ("Chans/list rd_msg err: '%s'",this_msg));
  332.         rd_end();
  333.         return delivery_setallstate(int_Qmgr_status_messageFailure,
  334.                         "Can't read message");
  335.     }
  336.  
  337.     for (ix = arg->users; ix; ix = ix->next) {
  338.         if ((adr = getnthrecip (&que, ix->RecipientId->parm)) == NULL) {
  339.  
  340.             PP_LOG (LLOG_EXCEPTIONS,
  341.                 ("failed to find recipient %d of msg '%s'",
  342.                  ix->RecipientId->parm, this_msg));
  343.  
  344.             delivery_setstate (ix->RecipientId->parm,
  345.                        int_Qmgr_status_messageFailure,
  346.                        "Unable to find specified recipient");
  347.             continue;
  348.         }
  349.         
  350.         if (start_submit == TRUE && rp_isbad (io_init (&reply))) {
  351.             submit_error (adr,"io_init",&reply);
  352.             rd_end();
  353.             return delivery_setallstate (int_Qmgr_status_messageFailure,
  354.                              "Unable to start submit");
  355.         }
  356.         else
  357.             start_submit = FALSE;
  358.             
  359.         switch (dchan_acheck (adr, sender, mychan, 1, (char **)NULL)) {
  360.             default:
  361.             case NOTOK:
  362.             break;
  363.             case OK:
  364.             switch (que.msgtype) {
  365.                 case MT_UMPDU:
  366.                 default:
  367.                 processMsg (this_msg,&prm,&que,adr,sender);
  368.                 break;
  369.                 case MT_DMPDU:
  370.                 processDR (this_msg,&prm,&que,adr,sender);
  371.                 break;
  372.             }
  373.             break;
  374.         }
  375.  
  376.     }
  377.  
  378.     if (rp_isbad (retval = wr_q2dr (&que, this_msg))) {
  379.         PP_LOG (LLOG_EXCEPTIONS,
  380.                ("%s wr_q2dr failure '%d'",mychan->ch_name,retval));
  381.         (void) delivery_resetDRs (int_Qmgr_status_messageFailure);
  382.     }
  383.  
  384.     rd_end();
  385.     q_free (&que);
  386.     prm_free(&prm);
  387.     return deliverystate;
  388. }
  389.  
  390.  
  391.  
  392.  
  393. /* ---   --- */
  394. static int submit_error (recip, proc, reply)
  395. ADDR    *recip;
  396. char    *proc;
  397. RP_Buf    *reply;
  398. {
  399.     char    buf[BUFSIZ];
  400.     PP_LOG (LLOG_EXCEPTIONS,
  401.            ("Chans/list %s failure [%s]", proc, reply->rp_line));
  402.  
  403.     if (recip != NULLADDR) {
  404.         (void) sprintf (buf,
  405.                 "'%s' failure for '%s' [%s]",
  406.                 proc,
  407.                 this_msg,
  408.                 reply -> rp_line);
  409.         PP_OPER(NULLCP,("%s", buf));
  410.         delivery_setstate (recip->ad_no, 
  411.                    int_Qmgr_status_messageFailure,
  412.                    buf);
  413.     }
  414.  
  415.     start_submit = TRUE;
  416.     io_end (NOTOK);
  417.  
  418.     return OK;
  419. }
  420.  
  421. static int processMsg (msg, prm, que, recip, origsender)
  422. char        *msg;
  423. struct prm_vars    *prm;
  424. Q_struct    *que;
  425. ADDR        *recip;
  426. ADDR        *origsender;
  427. {
  428.     ADDR    *expanded,
  429.         *ix,
  430.         *sender;
  431.     RP_Buf    reply;
  432.     char    *msgdir = NULLCP,
  433.         file[MAXPATHLENGTH],
  434.         buf[BUFSIZ],
  435.         *strippedname;
  436.     int    dirlen,
  437.         n,
  438.         fd_in;
  439.     int size;
  440.     struct stat st;
  441.     struct timeval data_time;
  442. #ifdef    DIRLIST
  443.     Attr_Sequence    policy_as;
  444. #else
  445.     char    *local;
  446. #endif
  447.  
  448.     if (qid2dir (msg, recip, TRUE, &msgdir) != OK) {
  449.         PP_LOG (LLOG_EXCEPTIONS,
  450.             ("msg dir not found for recip %d of msg '%s'",
  451.              recip->ad_no, msg));
  452.         delivery_setstate (recip->ad_no, 
  453.                    int_Qmgr_status_messageFailure,
  454.                    "source directory not found");
  455.         return 0;
  456.     }
  457.  
  458.     if (que->dl_expansion_prohibited == TRUE) {
  459.         delivery_set (recip -> ad_no,
  460.                   (first_failureDR == TRUE) ? 
  461.                   int_Qmgr_status_negativeDR : int_Qmgr_status_failureSharedDR);
  462.         first_failureDR = FALSE;
  463.         (void) sprintf (buf, "DL expansion prohibited for this message");
  464.         set_1dr (que, recip -> ad_no, this_msg,
  465.              DRR_UNABLE_TO_TRANSFER, DRD_DL_EXPANSION_PROHIBITED,
  466.              buf);
  467.         return 0;
  468.     }
  469.     
  470.     /* --- expand list and resubmit message --- */
  471.     q_init (&qs);
  472.  
  473.     q_almost_dup (&qs, que);
  474.  
  475.     if (recip -> ad_content != NULLCP) {
  476.         if (qs.cont_type) free(qs.cont_type);
  477.         qs.cont_type = strdup(recip -> ad_content);
  478.     } else if (qs.cont_type != NULLCP) {
  479.         free(qs.cont_type);
  480.         qs.cont_type = NULLCP;
  481.     }
  482.  
  483.     if (recip -> ad_eit != NULLIST_BPT) 
  484.         qs.encodedinfo.eit_types = list_bpt_dup (recip->ad_eit);
  485.     else
  486.         qs.encodedinfo.eit_types = list_bpt_dup (que->encodedinfo.eit_types);
  487.  
  488.     if (qs.ua_id) {
  489.         free(qs.ua_id);
  490.         qs.ua_id = NULLCP;
  491.     }
  492.     qs.priority = PRIO_NONURGENT;
  493.     qs.disclose_recips = FALSE;
  494.     adrno = 1;
  495.  
  496.     expansionLoop = FALSE;
  497.     switch (expandList (recip,&expanded,& (qs.dl_expansion_history))) {
  498.         case NOTOK:
  499.         delivery_set (recip->ad_no, 
  500.                   (first_failureDR == TRUE) ? 
  501.                   int_Qmgr_status_negativeDR : 
  502.                   int_Qmgr_status_failureSharedDR);
  503.         first_failureDR = FALSE;
  504.         (void) sprintf (buf, "Unable to expand list '%s'",get_adrstr (recip));
  505.         set_1dr (que, recip->ad_no, this_msg,
  506.              DRR_UNABLE_TO_TRANSFER, DRD_DL_EXPANSION_FAILURE, buf);
  507.         return 0;
  508.         case DONE:
  509.         delivery_setstate (recip->ad_no,
  510.                    (mychan -> ch_sort[0] == CH_SORT_USR) ?
  511.                    int_Qmgr_status_mtaFailure : 
  512.                    int_Qmgr_status_messageFailure,
  513.                    "temporary list processing failure (better check the logs)");
  514.         return 0;
  515.         default:
  516.         break;
  517.     }
  518.  
  519.  
  520.     /* --- expands to nothing so done --- */
  521.     if (expanded == NULLADDR) {
  522.         if (expansionLoop == TRUE)
  523.             set_success(recip, que, 0);
  524.         PP_LOG(LLOG_EXCEPTIONS,
  525.                ("list '%s' is an empty list", recip->ad_value));
  526.         return 0;
  527.     }
  528.  
  529. #ifdef    DIRLIST
  530.     if (check_dl_permission (origsender,this_list) == NOTOK) {
  531.         delivery_set(recip->ad_no, 
  532.                  (first_failureDR == TRUE) ? int_Qmgr_status_negativeDR : int_Qmgr_status_failureSharedDR);
  533.         first_failureDR = FALSE;
  534.         (void) sprintf(buf, "Distribution list policy prevents expansion of '%s'",get_adrstr(recip));
  535.         set_1dr(que, recip->ad_no,  this_msg,
  536.                DRR_UNABLE_TO_TRANSFER,
  537.                DRD_DL_EXPANSION_FAILURE,
  538.                buf);
  539.         return 0;
  540.     }
  541.  
  542.     if (((policy_as = as_find_type(this_list,at_Policy)) != NULLATTR) &&
  543.         (policy_as->attr_value != NULLAV)) {
  544.         struct dl_policy * policy;
  545.  
  546.         policy = (struct dl_policy *) policy_as->attr_value->avseq_av.av_struct;
  547.  
  548.         if (policy->dp_expand)
  549.             qs.dl_expansion_prohibited = FALSE;
  550.         else
  551.             qs.dl_expansion_prohibited = TRUE;
  552.  
  553.         switch (policy->dp_priority) {
  554.         case DP_LOW:
  555.             qs.priority = PRIO_NONURGENT; break; 
  556.         case DP_HIGH:
  557.             qs.priority = PRIO_URGENT; break; 
  558.         case DP_NORMAL:
  559.             qs.priority = PRIO_NORMAL; break; 
  560.         case DP_ORIGINAL:
  561.             qs.priority = que->priority; break; 
  562.         }
  563.  
  564.         switch (policy->dp_convert) {
  565.         case DP_ORIGINAL: 
  566.             qs.implicit_conversion_prohibited = que->implicit_conversion_prohibited ;  break;
  567.         case DP_FALSE: 
  568.             qs.implicit_conversion_prohibited = FALSE; break;
  569.         case DP_TRUE: 
  570.             qs.implicit_conversion_prohibited = TRUE;  break;
  571.         }
  572.  
  573.     } else {
  574.         /* Assume default policy */
  575.         qs.dl_expansion_prohibited = FALSE;
  576.         qs.priority = PRIO_NONURGENT;
  577.         qs.implicit_conversion_prohibited = que->implicit_conversion_prohibited;
  578.     }
  579.  
  580.     if ((sender = construct_sender (this_list)) == NULLADDR) 
  581.         return submit_error(recip,"construct sender",&reply);
  582. #else
  583.     if ((local = ad_getlocal (recip->ad_r822adr, AD_822_TYPE)) == NULLCP)
  584.         sender = tb_getModerator(recip->ad_r822adr);
  585.     else {
  586.         sender = tb_getModerator (local);
  587.         free (local);
  588.     }
  589.     if (sender == NULLADDR)
  590.         return 0;
  591. #endif
  592.     qs.inbound = list_rchan_new (loc_dom_site,mychan->ch_name);
  593.     sender->ad_status = AD_STAT_DONE;
  594.     sender->ad_resp = NO;
  595.     prm->prm_opts = prm->prm_opts | PRM_ACCEPTALL | PRM_NOTRACE;
  596.     /* --- now resubmit --- */
  597.  
  598.     timer_start(&data_time);
  599.     if (rp_isbad (io_wprm (prm, &reply))) 
  600.         return submit_error (recip,"io_wprm",&reply);
  601.  
  602.     if (rp_isbad (io_wrq (&qs, &reply))) 
  603.         return submit_error (recip,"io_wrq",&reply);
  604.  
  605.     if (sender->ad_redirection_history != (Redirection *) NULL) {
  606.         /* free of existing redirection history */
  607.         redirect_free(sender->ad_redirection_history);
  608.         sender->ad_redirection_history = (Redirection *) NULL;
  609.     }
  610.     if (rp_isbad (io_wadr (sender, AD_ORIGINATOR, &reply))) {
  611.         char    nbuf[BUFSIZ];
  612.         (void) sprintf(nbuf, "io_wadr(%s)", sender->ad_value);
  613.         return submit_error (recip,nbuf,&reply);
  614.     }
  615.     
  616.     ix = expanded;
  617.     while (ix != NULL) {
  618.         if (ix->ad_redirection_history != (Redirection *) NULL) {
  619.             /* free of existing redirection history */
  620.             redirect_free(ix->ad_redirection_history);
  621.             ix->ad_redirection_history = (Redirection *) NULL;
  622.         }
  623.         ix->ad_explicitconversion = recip->ad_explicitconversion;
  624.         if (rp_isbad (io_wadr (ix, AD_RECIPIENT, &reply))) {
  625.             char    nbuf[BUFSIZ];
  626.             (void) sprintf(nbuf, "io_wadr(%s)",
  627.                        ix -> ad_value);
  628.             return submit_error (recip,nbuf, &reply);
  629.         }
  630.         ix = ix->ad_next;
  631.     }
  632.  
  633.     if (rp_isbad (io_adend (&reply)))
  634.         return submit_error (recip,"io_adend", &reply);
  635.  
  636.     /* --- send over body --- */
  637.     if (rp_isbad (io_tinit (&reply)))
  638.         return submit_error (recip,"io_tinit",&reply);
  639.  
  640.     dirlen = strlen (msgdir) +1;
  641.  
  642.     msg_rinit (msgdir);
  643.  
  644.     size = 0;
  645.     while (msg_rfile (file) != RP_DONE) {
  646.  
  647.         /* --- transmit file --- */
  648.         strippedname = file + dirlen;
  649.         if (stat (file, &st) != NOTOK)
  650.             size += st.st_size;
  651.         if (linked == TRUE) {
  652.             (void) sprintf(buf, "%s %s",strippedname, file);
  653.             if (rp_isbad (io_tpart (buf, TRUE, &reply))) 
  654.                 return submit_error (recip,"io_tpart",&reply);
  655.         } else {
  656.             if (rp_isbad (io_tpart (strippedname, FALSE, &reply))) 
  657.                 return submit_error (recip,"io_tpart",&reply);
  658.  
  659.             if ((fd_in = open (file, O_RDONLY)) == -1) {
  660.                 (void) strcpy (reply.rp_line,file);
  661.                 return submit_error (recip,"open",&reply);
  662.             }
  663.             while ((n = read (fd_in, buf, BUFSIZ)) > 0) {
  664.                 if (rp_isbad (io_tdata (buf, n))) {
  665.                     (void) strcpy (reply.rp_line,"???");
  666.                     return submit_error (recip,"io_tdata",&reply);
  667.                 }
  668.             }
  669.  
  670.             close (fd_in);
  671.             if (rp_isbad (io_tdend (&reply)))
  672.                 return submit_error (recip,"io_tdend", &reply);
  673.         }
  674.     }
  675.     msg_rend();
  676.     if (rp_isbad (io_tend (&reply)))
  677.         return submit_error (recip,"io_tend", &reply);
  678.     set_success (recip,que, size);
  679.     timer_end(&data_time, size, "Data submitted");
  680.     return 0;
  681. }
  682.  
  683.  
  684.  
  685. static void set_success (recip, que, size)
  686. ADDR        *recip;
  687. Q_struct    *que;
  688. int        size;
  689. {
  690.     if (recip->ad_usrreq == AD_USR_CONFIRM ||
  691.         recip->ad_mtarreq == AD_MTA_CONFIRM ||
  692.         recip->ad_mtarreq == AD_MTA_AUDIT_CONFIRM) 
  693.     {
  694.         set_1dr (que, recip->ad_no, this_msg,
  695.              DRR_NO_REASON, -1, NULLCP);
  696.         delivery_set (recip->ad_no, 
  697.                  (first_successDR == TRUE) ? 
  698.                 int_Qmgr_status_positiveDR : 
  699.                 int_Qmgr_status_successSharedDR);
  700.         first_successDR = FALSE;
  701.     }
  702.     else {
  703.          (void) wr_ad_status (recip, AD_STAT_DONE);
  704.          (void) wr_stat (recip, que, this_msg, size);
  705.          delivery_set (recip->ad_no, int_Qmgr_status_success);
  706.     }
  707. }
  708.  
  709.  
  710.  
  711. /* ---   --- */
  712. static ADDR *getnthrecip (que, num)
  713. Q_struct    *que;
  714. int        num;
  715. {
  716.     ADDR *ix = que->Raddress;
  717.  
  718.     if (num == 0)
  719.         return que->Oaddress;
  720.     while ((ix != NULL) && (ix->ad_no != num))
  721.         ix = ix->ad_next;
  722.     return ix;
  723. }
  724.  
  725.  
  726. /*   */
  727. #ifdef    DIRLIST
  728. static ADDR *construct_sender(as)
  729. Attr_Sequence     as;
  730. {
  731.     ADDR     *ret = NULLADDR;
  732.     ADDR     *get_manager();
  733.     ADDR     *get_postmaster();
  734.  
  735.     if ((ret = get_manager(as)) == NULLADDR)
  736.         return (get_postmaster());
  737.  
  738.     return ret;
  739. }
  740. #endif
  741.  
  742. /* ---   --- */
  743. static char *getORname (adr)
  744. ADDR    *adr;
  745. {
  746.     OR_ptr     tree = NULLOR,
  747.         new = NULLOR;
  748.     char    buf[BUFSIZ],
  749.         *value;
  750.  
  751.     bzero (buf, BUFSIZ);
  752.     if (adr -> ad_r400adr != NULLCP)
  753.         return strdup(adr -> ad_r400adr);
  754.  
  755.     value = adr -> ad_value;
  756.  
  757.     if ((or_rfc2or (value, &tree) != OK) || tree == NULLOR) { 
  758.         PP_LOG (LLOG_EXCEPTIONS, 
  759.              ("getORname: Failed to parse '%s'", value));
  760.         if (adr->ad_dn)
  761.             return strdup(adr->ad_dn);
  762.         return NULLCP; 
  763.     }
  764.  
  765.     new = or_default (tree);
  766.     or_or2std (new, buf, 0);
  767.     if (new) or_free (new);
  768.  
  769.     return strdup (buf);
  770. }
  771.  
  772.  
  773.  
  774. static void postExpansion (adr, pdlh)
  775. ADDR        *adr;
  776. DLHistory    **pdlh;
  777. {
  778.     char    *orname;
  779.     
  780.     if ((orname = getORname (adr)) == NULLCP)
  781.         return;
  782.     dlh_add (pdlh,dlh_new (orname, NULLCP, NULLUTC));
  783.     free (orname);
  784. }
  785.  
  786.  
  787.  
  788. static int expandedBefore (adr, dlh)
  789. ADDR        *adr;
  790. DLHistory    *dlh;
  791. {
  792.     char    *orname;
  793.     int    found = FALSE;
  794.  
  795.     if ((orname = getORname (adr)) == NULLCP)
  796.         return FALSE;
  797.  
  798.     while (found == FALSE && dlh != NULL) {
  799.         if (strcmp (orname, dlh->dlh_addr) == 0)
  800.             found = TRUE;
  801.         else 
  802.             dlh = dlh -> dlh_next;
  803.     }
  804.  
  805.     free (orname);
  806.     return found;
  807.  
  808.  
  809. #ifdef    DIRLIST
  810. static ADDR *dl2addr(as, pnum)
  811. Attr_Sequence as;
  812. int    *pnum;
  813. {
  814. Attr_Sequence tmp;
  815. ADDR    *ret = NULLADDR;
  816. ADDR    *next;
  817. AV_Sequence avs;
  818. int     num = 0;
  819.  
  820.     /* Find mhsDLmembers */
  821.     if ((tmp = as_find_type(as,at_Member)) == NULLATTR)
  822.         return NULLADDR;
  823.  
  824.     /* Convert to ADDR */
  825.     for (avs=tmp->attr_value; avs!= NULLAV; avs=avs->avseq_next) {
  826.         if ((next = ORName2ADDR ((ORName *)avs->avseq_av.av_struct,TRUE)) == NULLADDR)
  827.             return NULLADDR;
  828.         next->ad_extension = num;
  829.         next->ad_no = num;
  830.         num++;
  831.         adr_add(&ret, next);
  832.     }
  833.         *pnum = num;
  834.     return ret;
  835.  
  836. }
  837. #else
  838. static ADDR *dl2addr (indl, pnum)
  839. dl    *indl;
  840. int    *pnum;
  841. {
  842.     ADDR    *ret = NULLADDR;
  843.     Name    *list = indl -> dl_list;
  844.     int    type = AD_ANY_TYPE;
  845.  
  846.     for (*pnum=0; list != NULL; list = list -> next, (*pnum)++) 
  847.         adr_add (&ret, adr_new (list->name, type, adrno++));
  848.  
  849.     return ret;
  850. }
  851. #endif
  852.  
  853.  
  854. static int attemptExpansion (key, type, padr, complain)
  855. char    *key;
  856. int    type;
  857. ADDR    **padr;
  858. int    complain;
  859. {
  860. #ifndef    DIRLIST    
  861.     dl    *list;
  862. #endif
  863.     char    *local;
  864.     int    count;
  865.     *padr = NULLADDR;
  866.  
  867.     if ((local = ad_getlocal (key,type)) != NULLCP) {
  868.         PP_NOTICE(("Attempting to expand list '%s'", local));
  869. #ifdef    DIRLIST
  870.         switch (dir_getdl(local, &this_list)) {
  871.             case OK:
  872.             *padr = dl2addr(this_list, &count);
  873.             PP_NOTICE(("Expanded list '%s' to %d recipient%s", 
  874.                    local, count,
  875.                    (count == 1) ? "" : "s"));
  876.             free(local);
  877.             return OK;
  878.             case DONE:
  879.             PP_NOTICE (("Temporary failure to expand list '%s'",
  880.                     local));
  881.             free (local);
  882.             return DONE;
  883.             default:
  884.             PP_NOTICE (("Failed to find list '%s' in the directory", local));
  885.             free (local);
  886.             break;
  887.         }
  888. #else
  889.         switch (tb_getdl (local, &list,complain)) {
  890.             case OK:
  891.             *padr = dl2addr (list, &count);
  892.             dl_free (list);
  893.             PP_NOTICE(("Expanded list '%s' to %d recipient%s", 
  894.                    local, count,
  895.                    (count == 1) ? "" : "s"));
  896.             free (local);
  897.             return OK;
  898.             case DONE:
  899.             if (list != NULL)
  900.                 dl_free(list);
  901.             PP_NOTICE (("Temporary failure to expand list '%s'", 
  902.                     local));
  903.             free(local);
  904.             return DONE;
  905.             default:
  906.             if (list != NULL)
  907.                 dl_free(list);
  908.             PP_NOTICE (("Failed to expand list '%s'", local));
  909.             free (local);
  910.             break;
  911.         } 
  912. #endif
  913.     }
  914.  
  915. #ifdef DONT_WANT_THIS_ANYMORE
  916.  
  917.     PP_NOTICE(("Attempting to expand list '%s'", key));
  918.  
  919. #ifdef    DIRLIST
  920.     switch (dir_getdl(key, &this_list)) {
  921.         case OK:
  922.         *padr = dl2addr(this_list, &count);
  923.         PP_NOTICE(("Expanded list '%s' to %d recipient%s", 
  924.                key, count,
  925.                (count == 1) ? "" : "s"));
  926.         return OK;
  927.         case DONE:
  928.         PP_NOTICE (("Temporary failure to expand list '%s'",
  929.                 key));
  930.         return DONE;
  931.         default:
  932.         PP_NOTICE (("Failed to expand list '%s'", key));
  933.         break;
  934.     }
  935. #else
  936.  
  937.     switch (tb_getdl (key,&list,complain)) {
  938.         case OK:
  939.         *padr = dl2addr (list, &count);
  940.         dl_free (list);
  941.         PP_NOTICE(("Expanded list '%s' to %d recipients", 
  942.                key, count));
  943.         return OK;
  944.         case DONE:
  945.         if (list != NULL)
  946.             dl_free(list);
  947.         PP_NOTICE (("Temporary failure to expand list '%s'", 
  948.                 key));
  949.         return DONE;
  950.         default:
  951.         if (list != NULL)
  952.             dl_free(list);
  953.         PP_NOTICE (("Failed to expand list '%s'", key));
  954.         break;
  955.     } 
  956. #endif
  957.  
  958. #endif
  959.     return NOTOK;
  960. }
  961.  
  962.  
  963.  
  964. /* --- rm this from the list --- */
  965. static adr_rm (this, list)
  966. ADDR    *this,
  967.     **list;
  968. {
  969.     ADDR    *ix;
  970.  
  971.     /* --- bullet proofing --- */
  972.     if (this == NULLADDR || list == NULL)
  973.         return;
  974.  
  975.     if (this == *list) 
  976.         /* --- first in list (easy) --- */
  977.         *list = (*list) -> ad_next;
  978.     else {
  979.         ix = *list;
  980.         while ( ix != NULLADDR
  981.                && ix -> ad_next != this)
  982.             ix = ix -> ad_next;
  983.         if (ix != NULLADDR)
  984.             ix -> ad_next = this -> ad_next;
  985.     }
  986. }
  987.  
  988.  
  989.  
  990. static int expandList (orig, plist, pdlh)
  991. ADDR        *orig,
  992.         **plist;
  993. DLHistory    **pdlh;
  994. {
  995.     ADDR    *new,
  996.         *temp,
  997.         *ix;
  998.     RP_Buf    rp;
  999.     int    do_next = TRUE;
  1000.  
  1001. #ifdef    DIRLIST
  1002.     Attr_Sequence    save_as;
  1003. #endif
  1004.  
  1005.     *plist = NULLADDR;
  1006.  
  1007.     if (expandedBefore (orig, *pdlh) == TRUE) {
  1008.         expansionLoop = TRUE;
  1009.         return TRUE;
  1010.     }
  1011.     switch(attemptExpansion (get_adrstr (orig),
  1012.                  get_adrtype (orig),
  1013.                  &new,
  1014.                  OK)) {
  1015.         case OK:
  1016.         postExpansion (orig,pdlh);
  1017.         break;
  1018.         case DONE:
  1019.         /* temporary failure */
  1020.         return DONE;
  1021.         default:
  1022.         /* --- cannot expand starting list --- */
  1023.         return NOTOK;
  1024.     }
  1025.     
  1026.     adr_add (plist, new);
  1027.     ix = new;
  1028. #ifdef    DIRLIST
  1029.     save_as = this_list;
  1030. #endif
  1031.  
  1032.     while (expandSublists == TRUE && ix != NULLADDR) {
  1033. #ifdef UKORDER
  1034.         if (!rp_isbad(ad_parse(ix, &rp, CH_UK_PREF))
  1035. #else
  1036.         if (!rp_isbad(ad_parse(ix, &rp, CH_USA_PREF))
  1037. #endif
  1038.             && ix->ad_outchan
  1039.             && ix->ad_outchan->li_chan
  1040.             && lexequ(ix->ad_outchan->li_chan->ch_name, 
  1041.                   mychan->ch_name) == 0) {
  1042.             /* attempt to expand sublist */
  1043.             if (expandedBefore (ix, *pdlh) == TRUE) {
  1044.                 temp = ix;
  1045.                 ix = ix -> ad_next;
  1046.                 do_next = FALSE;
  1047.                 expansionLoop = TRUE;
  1048.                 adr_rm (temp, plist);
  1049.                 adr_free (temp);
  1050.             } 
  1051.             else if (attemptExpansion (get_adrstr(ix),
  1052.                            get_adrtype(ix),
  1053.                            &new,
  1054.                            NOTOK) == OK) {
  1055.                 postExpansion (ix, pdlh);
  1056.                 temp = ix;
  1057.                 adr_rm (temp, plist);
  1058.                 adr_free (temp);
  1059.                 adr_add (plist, new);
  1060.                 ix = new;
  1061.                 do_next = FALSE;
  1062.             }
  1063.         }
  1064.         if (do_next == TRUE)
  1065.             ix = ix -> ad_next;
  1066.         else
  1067.             do_next = TRUE;
  1068.     }
  1069. #ifdef    DIRLIST
  1070.     this_list = save_as;
  1071. #endif
  1072.     return OK;
  1073. }
  1074.  
  1075.  
  1076. static char  *get_adrstr (adr)
  1077. ADDR    *adr;
  1078. {
  1079.     char    *key;
  1080.     
  1081.     switch (mychan->ch_out_ad_type) {
  1082.         case AD_X400_TYPE:
  1083.         key = adr->ad_r400adr;
  1084.         break;
  1085.         case AD_822_TYPE:
  1086.         key = adr->ad_r822adr;
  1087.         break;
  1088.         default:
  1089.         switch (adr->ad_type) {
  1090.             case AD_X400_TYPE:
  1091.             key = adr->ad_r400adr;
  1092.             break;
  1093.             case AD_822_TYPE:
  1094.             key = adr->ad_r822adr;
  1095.             break;
  1096.             default:
  1097.             key = adr->ad_value;
  1098.             break;
  1099.         }
  1100.         break;
  1101.     }
  1102.  
  1103.     return key;
  1104. }
  1105.  
  1106. static int get_adrtype (adr)
  1107. ADDR    *adr;
  1108. {
  1109.     switch (mychan->ch_out_ad_type) {
  1110.         case AD_X400_TYPE:
  1111.         case AD_822_TYPE:
  1112.         return mychan->ch_out_ad_type;
  1113.         default:
  1114.         return adr->ad_type;
  1115.     }
  1116. }
  1117.  
  1118. /*   */
  1119. /* DR to list maintainer */
  1120.  
  1121. static int processDR (msg, prm, que, recip, origsender)
  1122. char        *msg;
  1123. struct prm_vars    *prm;
  1124. Q_struct    *que;
  1125. ADDR        *recip;
  1126. ADDR        *origsender;
  1127. {
  1128.     DRmpdu drs, *dr = &drs;
  1129.     char    *msgdir, *key, *local, file[MAXPATHLENGTH],
  1130.         *strippedname, buf[BUFSIZ];
  1131.     ADDR    *moderator = NULLADDR;
  1132.     RP_Buf    reply;
  1133.     int    retval, size, dirlen, fd_in, n;
  1134.     struct stat st;
  1135.     struct timeval data_time;
  1136.     
  1137.     /* read in DR */
  1138.     dr_init(dr);
  1139.     if (rp_isbad(get_dr(recip->ad_no,
  1140.                 this_msg,
  1141.                 dr))) {
  1142.         PP_LOG (LLOG_EXCEPTIONS,
  1143.             ("report.%d not found for msg '%s'",
  1144.              recip->ad_no, msg));
  1145.         delivery_setstate (recip->ad_no, 
  1146.                    int_Qmgr_status_messageFailure,
  1147.                    "DR not found");
  1148.         return 0;
  1149.     }
  1150.     /* get Moderator of list (copied from above) */
  1151.     key = (origsender->ad_type == AD_X400_TYPE) ? origsender->ad_r400adr : 
  1152.         origsender->ad_r822adr;
  1153.     if ((local = ad_getlocal(key, origsender->ad_type, YES)) == NULLCP)
  1154.         local = strdup(key);
  1155.     
  1156. #ifdef DIRLIST
  1157.     switch (dir_getdl(local, &this_list)) {
  1158.         case OK:
  1159.         break;
  1160.  
  1161.         case DONE:
  1162.         /* temp failure */
  1163.         PP_LOG (LLOG_EXCEPTIONS,
  1164.             ("Tempory failure to access list '%s'",
  1165.              local));
  1166.         delivery_setstate (recip->ad_no, 
  1167.                    int_Qmgr_status_messageFailure,
  1168.                    "temporary X.500 problem");
  1169.         return 0;
  1170.         
  1171.         default:
  1172.         /* perm failure */
  1173.         /* hack up moderator and send to postmaster */
  1174.         moderator = adr_new(getpostmaster(AD_822_TYPE), 
  1175.                     AD_822_TYPE, 0);
  1176.     }
  1177.     if (moderator == NULLADDR
  1178.         && (moderator = construct_sender (this_list)) == NULLADDR) 
  1179.         return submit_error(recip,"construct sender",&reply);
  1180. #else
  1181.     moderator = tb_getModerator(local);
  1182. #endif
  1183.     free(local);
  1184.  
  1185.     timer_start(&data_time);
  1186.     if (rp_isbad (io_wprm (prm, &reply))) 
  1187.         return submit_error (recip,"io_wprm",&reply);
  1188.  
  1189.     if (rp_isbad (io_wrq (que, &reply))) 
  1190.         return submit_error (recip,"io_wrq",&reply);
  1191.  
  1192.     if (moderator->ad_redirection_history != (Redirection *) NULL) {
  1193.         /* free of existing redirection history */
  1194.         redirect_free(moderator->ad_redirection_history);
  1195.         moderator->ad_redirection_history = (Redirection *) NULL;
  1196.     }
  1197.     if (rp_isbad (io_wadr (moderator, AD_ORIGINATOR, &reply))) {
  1198.         char    nbuf[BUFSIZ];
  1199.         (void) sprintf(nbuf, "io_wadr(%s)",
  1200.                    moderator -> ad_value);
  1201.         return submit_error (recip,nbuf, &reply);
  1202.     }
  1203.  
  1204.     if (rp_isbad (io_wadr (recip, AD_RECIPIENT, &reply))) {
  1205.         char    nbuf[BUFSIZ];
  1206.         (void) sprintf(nbuf, "io_wadr(%s)", recip->ad_value);
  1207.         return submit_error (recip,nbuf,&reply);
  1208.     }
  1209.  
  1210.     if (rp_isbad (io_adend (&reply)))
  1211.         return submit_error (recip,"io_adend", &reply);
  1212.  
  1213.     if (rp_isbad (io_wdr (dr, &reply)))
  1214.         return submit_error(recip, "io_wdr", &reply);
  1215.  
  1216.     if (rp_isbad (io_tinit (&reply)))
  1217.         return submit_error (recip, "io_tinit", &reply);
  1218.  
  1219.     if (qid2dir (msg, recip, TRUE, &msgdir) != OK) {
  1220.         PP_LOG (LLOG_EXCEPTIONS,
  1221.             ("msg dir not found for recip %d of msg '%s'",
  1222.              recip->ad_no, msg));
  1223.         delivery_setstate (recip->ad_no, 
  1224.                    int_Qmgr_status_messageFailure,
  1225.                    "source directory not found");
  1226.         return 0;
  1227.     }
  1228.  
  1229.     dirlen = strlen (msgdir) +1;
  1230.  
  1231.     if (msg_rinit(msgdir) != NOTOK) {
  1232.         size = 0;
  1233.         while (msg_rfile (file) != RP_DONE) {
  1234.  
  1235.             /* --- transmit file --- */
  1236.             strippedname = file + dirlen;
  1237.             if (stat (file, &st) != NOTOK)
  1238.                 size += st.st_size;
  1239.             if (linked == TRUE) {
  1240.                 (void) sprintf(buf, "%s %s",strippedname, file);
  1241.                 if (rp_isbad (io_tpart (buf, TRUE, &reply))) 
  1242.                     return submit_error (recip,"io_tpart",&reply);
  1243.             } else {
  1244.                 if (rp_isbad (io_tpart (strippedname, FALSE, &reply))) 
  1245.                     return submit_error (recip,"io_tpart",&reply);
  1246.  
  1247.                 if ((fd_in = open (file, O_RDONLY)) == -1) {
  1248.                     (void) strcpy (reply.rp_line,file);
  1249.                     return submit_error (recip,"open",&reply);
  1250.                 }
  1251.                 while ((n = read (fd_in, buf, BUFSIZ)) > 0) {
  1252.                     if (rp_isbad (io_tdata (buf, n))) {
  1253.                         (void) strcpy (reply.rp_line,"???");
  1254.                         return submit_error (recip,"io_tdata",&reply);
  1255.                     }
  1256.                 }
  1257.  
  1258.                 close (fd_in);
  1259.                 if (rp_isbad (io_tdend (&reply)))
  1260.                     return submit_error (recip,"io_tdend", &reply);
  1261.             }
  1262.         }
  1263.         msg_rend();
  1264.     }
  1265.         
  1266.     if (rp_isbad (io_tend (&reply)))
  1267.         return submit_error (recip, "io_tend", &reply);
  1268.     set_success (recip, que, size);
  1269.     timer_end(&data_time, size, "Data submitted");
  1270.     return 0;
  1271. }
  1272.     
  1273. #ifndef lint
  1274.  
  1275. void    advise (va_alist)
  1276. va_dcl
  1277. {
  1278.     int     code;
  1279.     va_list ap;
  1280.  
  1281.     va_start (ap);
  1282.  
  1283.     code = va_arg (ap, int);
  1284.  
  1285.     (void) _ll_log (log_dsap, code, ap);
  1286.  
  1287.     va_end (ap);
  1288. }
  1289.  
  1290. #else
  1291. /* VARARGS */
  1292.  
  1293. void    advise (code, what, fmt)
  1294. char    *what,
  1295.         *fmt;
  1296. int      code;
  1297. {
  1298.     advise (code, what, fmt);
  1299. }
  1300. #endif
  1301.