home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pp / pp-6.0 / Src / submit / ad_mgt.c next >
Encoding:
C/C++ Source or Header  |  1991-12-18  |  18.9 KB  |  825 lines

  1. /* ad_mgt.c: address management routines */
  2.  
  3. # ifndef lint
  4. static char Rcsid[] = "@(#)$Header: /xtel/pp/pp-beta/Src/submit/RCS/ad_mgt.c,v 6.0 1991/12/18 20:28:02 jpo Rel $";
  5. # endif
  6.  
  7. /*
  8.  * $Header: /xtel/pp/pp-beta/Src/submit/RCS/ad_mgt.c,v 6.0 1991/12/18 20:28:02 jpo Rel $
  9.  *
  10.  * $Log: ad_mgt.c,v $
  11.  * Revision 6.0  1991/12/18  20:28:02  jpo
  12.  * Release 6.0
  13.  *
  14.  */
  15.  
  16.  
  17.  
  18. #include "util.h"
  19. #include <varargs.h>
  20. #include "retcode.h"
  21. #include <isode/cmd_srch.h>
  22. #include "q.h"
  23. #include "dr.h"
  24. #include "ap.h"
  25.  
  26. extern int        accept_all;
  27.  
  28. extern void        x400_add(), rfc822_add(), err_abrt(), pro_reply();
  29. extern void        redirect_free ();
  30. extern char        *getpostmaster();
  31.  
  32. /* -- globals -- */
  33. static int        ad_extend;
  34.  
  35.  
  36. /* -- local routines -- */
  37. int        rplose ();
  38. int        validate_sender ();
  39. void        ad_init ();
  40. int        validate_recip ();
  41. void        ad_log_print ();
  42.  
  43. static int        bad_address();
  44. static int        recip_parse();
  45. static int        do_sender_dr_outchan();
  46. static void        set_return_chan();
  47.  
  48. #define gval(x)            ((x -> ad_type) == AD_X400_TYPE ? \
  49.                  (x -> ad_r400adr) : (x -> ad_r822adr))    
  50.  
  51.  
  52. /* ---------------------  Begin     Routines  -------------------------------- */
  53.  
  54.  
  55. ADDR *read_sender (qp)
  56. Q_struct *qp;
  57. {
  58.     RP_Buf    rpbuf,
  59.         *rp = &rpbuf;
  60.     ADDR    *ad = NULLADDR;
  61.     int     retval;
  62.     int type = qp -> inbound -> li_chan -> ch_in_ad_type;
  63.  
  64.     PP_TRACE (("submit/read_sender (%d)", type));
  65.     rp -> rp_val = RP_OK;
  66.  
  67.     if ((retval = rd_adr (stdin, TRUE, &ad)) == RP_DONE)
  68.         err_abrt (retval, "Error reading sender");
  69.  
  70.  
  71.     if (rp_isbad (retval) || ad -> ad_value == NULLCP) {
  72.         if (ad == NULLADDR)
  73.             err_abrt (RP_EOF, "No sender given");
  74.  
  75.         err_abrt (retval, "Invalid sender '%s'",
  76.               isstr (ad -> ad_value) ? ad -> ad_value : "(none)");
  77.     }
  78.  
  79.  
  80.     ad -> ad_resp = FALSE;
  81.     if (qp -> msgtype == MT_DMPDU)
  82.         ad -> ad_status = AD_STAT_PEND;
  83.     else
  84.         ad -> ad_status = AD_STAT_DONE;
  85.     ad -> ad_extension = 0;
  86.     ad -> ad_no = 0;
  87.     ad -> ad_type = type;
  88.  
  89.  
  90.  
  91.     if (qp -> msgtype == MT_DMPDU)
  92.         ad -> ad_resp = TRUE;
  93.  
  94.     return ad;
  95. }
  96.  
  97. static void copy_drstuff(ad, newad, isPostie)
  98. ADDR    *ad, *newad;
  99. int    isPostie;
  100. {
  101.     LIST_RCHAN    *tmpchan;
  102.     char        *tmpchar;
  103.  
  104.     tmpchan = ad->ad_fmtchan;
  105.     ad->ad_fmtchan = newad->ad_fmtchan;
  106.     newad->ad_fmtchan = tmpchan;
  107.  
  108.     tmpchan = ad->ad_outchan;
  109.     ad->ad_outchan = newad->ad_outchan;
  110.     newad->ad_outchan = tmpchan;
  111.             
  112.     if (isPostie == TRUE) {
  113.         tmpchar = ad->ad_r400DR;
  114.         ad->ad_r400DR = newad->ad_r400adr;
  115.         newad->ad_r400adr = tmpchar;
  116.  
  117.         tmpchar = ad->ad_r822DR;
  118.         ad->ad_r822DR = newad->ad_r822adr;
  119.         newad->ad_r822adr = tmpchar;
  120.     }
  121. }
  122.  
  123. static int x400routeback (ad, inbound, mta)
  124. ADDR    *ad;
  125. CHAN    *inbound;
  126. char    *mta;
  127. {
  128.     LIST_RCHAN    *outchans = NULLIST_RCHAN, *ix;
  129.     int        found;
  130.     char        buf[BUFSIZ];
  131.     /* attempt to route back x400 message to inbound mta */
  132.     
  133.     if (tb_getchan (mta, &outchans) != OK)
  134.         /* can't find inbound mta in routing tables */
  135.         return NOTOK;
  136.     ix = outchans;
  137.     found = FALSE;
  138.     while (ix != NULLIST_RCHAN && found == FALSE) {
  139.         if (ix -> li_chan != NULLCHAN
  140.             && ix -> li_chan  == inbound) {
  141.             /* found routing via inbound */
  142.             /* now check that can route to inbound mta that way */
  143.             if ((ix -> li_mta == NULLCP
  144.                 || lexequ(ix -> li_mta, mta) == 0)
  145.                 && (ix -> li_chan -> ch_table == NULLTBL
  146.                 || tb_k2val(ix -> li_chan -> ch_table,
  147.                         mta, buf, 1) == OK))
  148.                 found = TRUE;
  149.         }
  150.         if (found == FALSE)
  151.             ix = ix -> li_next;
  152.     }
  153.  
  154.     if (found == TRUE) {
  155.         /* can routeback via x400 */
  156.         if (ad->ad_outchan != NULLIST_RCHAN)
  157.             list_rchan_free(ad->ad_outchan);
  158.         ad->ad_outchan = ix;
  159.         /* remove all but ad->ad_outchan */
  160.         if (ad -> ad_outchan -> li_next != NULLIST_RCHAN) {
  161.             list_rchan_free (ad->ad_outchan->li_next);
  162.             ad->ad_outchan->li_next = NULLIST_RCHAN;
  163.         }
  164.         if (outchans != ad->ad_outchan) {
  165.             for (ix = outchans;
  166.                  ix != NULLIST_RCHAN &&
  167.                  ix -> li_next != ad->ad_outchan;
  168.                  ix = ix -> li_next)
  169.               continue;
  170.             if (ix != NULLIST_RCHAN)
  171.                 ix -> li_next = NULLIST_RCHAN;
  172.             list_rchan_free(outchans);
  173.         }
  174.         PP_NOTICE (("Will route DRs for unrouteable sender '%s' via inbound mta '%s'",
  175.                 ad->ad_value,
  176.                 mta));
  177.         return OK;
  178.     }
  179.     PP_LOG (LLOG_EXCEPTIONS,
  180.         ("unable to route DRs to inbound mta '%s' via channel '%s' for unrouteable sender '%s'",
  181.          mta, inbound->ch_name, ad->ad_value));
  182.     return NOTOK;
  183. }
  184.  
  185. static void removeNon822chans (plist)
  186. LIST_RCHAN    **plist;
  187. {
  188.     LIST_RCHAN    *ix, *tmp;
  189.     /* remove all non 822 channels */
  190.  
  191.     /* remove ones at front of queue */
  192.     while (*plist != NULLIST_RCHAN
  193.            && (*plist) -> li_chan -> ch_out_ad_type != AD_822_TYPE) {
  194.         tmp = *plist;
  195.         *plist = tmp -> li_next;
  196.         tmp -> li_next = NULLIST_RCHAN;
  197.         list_rchan_free(tmp);
  198.     }
  199.  
  200.     if (*plist != NULLIST_RCHAN) {
  201.         ix = *plist;
  202.         while (ix -> li_next != NULLIST_RCHAN) {
  203.             if (ix -> li_next -> li_chan -> ch_out_ad_type != AD_822_TYPE) {
  204.                 tmp = ix -> li_next;
  205.                 ix -> li_next = tmp -> li_next;
  206.                 tmp -> li_next = NULLIST_RCHAN;
  207.                 list_rchan_free (tmp);
  208.             } else
  209.                 ix  = ix -> li_next;
  210.         }
  211.     }
  212. }
  213.  
  214. static int r822routeback (ad, inbound, mta)
  215. ADDR    *ad;
  216. CHAN    *inbound;
  217. char    *mta;
  218. {
  219.     AP_ptr    tree, group, name, local, domain, route;
  220.     RP_Buf    rpbuf;
  221.     ADDR    *newad;
  222.     char    buf[BUFSIZ];
  223.  
  224.     /* attempt to source route DRs back via inbound mta */
  225.  
  226.     if (ap_s2p(ad->ad_value, &tree, &group, &name, &local,
  227.            &domain, &route) != (char *) NOTOK) {
  228.         char    *str;
  229.         AP_ptr    newap = ap_new (AP_DOMAIN,
  230.                     mta);
  231.         if (domain == NULLAP)
  232.             str = ap_p2s (group, name, local,
  233.                       newap, NULLAP);
  234.         else if (route == NULLAP)
  235.             str = ap_p2s (group, name, local,
  236.                       domain, newap);
  237.         else {
  238.             newap->ap_next = route;
  239.             newap->ap_ptrtype = AP_PTR_MORE;
  240.             str = ap_p2s (group, name, local,
  241.                       domain, newap);
  242.             newap->ap_next = NULLAP;
  243.         }
  244.         ap_sqdelete(tree, NULLAP);
  245.         ap_free(tree);
  246.         ap_free(newap);
  247.         strcpy(buf, str);
  248.         free(str);
  249.     } else {
  250.         PP_LOG (LLOG_EXCEPTIONS,
  251.             ("unable to parse sender '%s' so unwilling to route DRs via inbound mta",
  252.              ad->ad_value));
  253.         return NOTOK;
  254.     }
  255.             
  256.     newad = adr_new (buf,
  257.              inbound->ch_in_ad_type,
  258.              0);
  259.     newad->ad_resp = FALSE;
  260.  
  261.     if (rp_isbad (ad_parse (newad, &rpbuf,
  262.                 inbound->ch_ad_order))) {
  263.         PP_LOG (LLOG_EXCEPTIONS,
  264.             ("unable to route DRs to inbound mta '%s' for bad sender '%s' [%s]",
  265.              mta,
  266.              ad -> ad_value,
  267.              rpbuf.rp_line));
  268.         adr_free (newad);
  269.         return NOTOK;
  270.     }
  271.  
  272.     removeNon822chans(&(newad->ad_outchan));
  273.     if (newad->ad_outchan == NULLIST_RCHAN) {
  274.         PP_LOG (LLOG_EXCEPTIONS,
  275.             ("Unable to route DRs to inbound mta '%s' via an rfc 822 channel for unrouteable sender '%s'",
  276.              mta, ad->ad_value));
  277.         adr_free(newad);
  278.         return NOTOK;
  279.     }
  280.  
  281.     /* copy various things across */
  282.     copy_drstuff(ad, newad, FALSE);
  283.     adr_free (newad);
  284.     PP_NOTICE(("Will source route DRs for unrouteable sender '%s' via inbound mta '%s'",
  285.            ad->ad_value, mta));
  286.     return OK;
  287. }
  288.  
  289. static int postmasterrouteback (ad, inbound, mta)
  290. ADDR    *ad;
  291. CHAN    *inbound;
  292. char    *mta;
  293. {
  294.     RP_Buf    rpbuf;
  295.     ADDR    *newad;
  296.  
  297.     /* attempt to route DRs to 822 postmaster */
  298.     PP_NOTICE(("Failed to route DRs for unrouteable sender '%s' back to inbound mta '%s', now attepmting sloppy mode routing to postmaster",
  299.            ad->ad_value, mta));
  300.  
  301.     newad = adr_new(getpostmaster(inbound->ch_in_ad_type),
  302.             inbound->ch_in_ad_type,
  303.             0);
  304.     newad->ad_resp = FALSE;
  305.     if (rp_isbad (ad_parse (newad, &rpbuf, 
  306.                 inbound->ch_ad_order))) {
  307.         PP_LOG (LLOG_EXCEPTIONS,
  308.             ("parsing of postmaster address '%s' fails [%s]",
  309.              newad->ad_value,
  310.              rpbuf.rp_line));
  311.         adr_free (newad);
  312.         return NOTOK;
  313.     }
  314.  
  315.     removeNon822chans(&(newad->ad_outchan));
  316.     if (newad->ad_outchan == NULLIST_RCHAN) {
  317.         PP_LOG (LLOG_EXCEPTIONS,
  318.             ("Unable to route DRs to postmaster '%s' via an rfc 822 channel for unrouteable sender '%s'",
  319.              newad->ad_value, ad->ad_value));
  320.         adr_free(newad);
  321.         return NOTOK;
  322.     }
  323.     
  324.     /* copy various things across */
  325.     PP_NOTICE(("Will route DRs for bad sender '%s' to postmaster '%s'",
  326.            ad->ad_value, newad->ad_value));
  327.     copy_drstuff(ad, newad, TRUE);
  328.     adr_free (newad);
  329.     return OK;
  330. }
  331.  
  332. int validate_sender(qp, ad, user, rp) /* -- read in sender and validate -- */
  333. ADDR    *ad;
  334. Q_struct *qp;
  335. char *user;
  336. RP_Buf *rp;
  337. {
  338.   CHAN    *ch_in = qp -> inbound -> li_chan;
  339.   int    oldresp;
  340.   /* --- *** --- 
  341.      Reject bad senders unless we can figure out some hack to
  342.      return them.
  343.      --- *** ---  */
  344.  
  345.   ad_extend = 1;        /* -- reset -- */
  346.     
  347.   oldresp = ad -> ad_resp;
  348.   ad->ad_resp = FALSE;
  349.   if (rp_isbad (ad_parse (ad, rp, ch_in -> ch_ad_order))) {
  350.     if (ch_in->ch_badSenderPolicy == CH_BADSENDER_SLOPPY
  351.     && ((ch_in->ch_in_ad_type == AD_X400_TYPE 
  352.          && x400routeback(ad, ch_in, qp -> inbound -> li_mta) == OK)
  353.         /* managed to route back via x400 to inbound mta */
  354.         || (ch_in->ch_in_ad_type == AD_822_TYPE
  355.         && r822routeback (ad, ch_in, qp->inbound->li_mta) == OK)
  356.         /* managed to route back via 822 to inbound mta */
  357.         || postmasterrouteback (ad, ch_in, qp->inbound->li_mta) == OK
  358.         /* managed to route back to 822 local postmaster */))
  359.       /* managed to route DRs somehow */
  360.       rp -> rp_val = RP_OK;
  361.     else {
  362.       /* bad sender bounce */
  363.       PP_LOG(LLOG_EXCEPTIONS,
  364.          ("Bounced message due to unrouteable sender"));
  365.       return rp -> rp_val;
  366.     }
  367.  
  368.   }
  369.   ad->ad_resp = oldresp;
  370.  
  371.   PP_NOTICE (("Sender '%s'", ad -> ad_value));
  372.  
  373.   if (ch_in -> ch_access == CH_MTS && user != NULLCP &&
  374.       tb_checkauth (gval(ad), ch_in,
  375.             user, NULLCP) == NOTOK)
  376.     return rplose (rp, RP_USER,
  377.            "User %s not allowed to submit as %s",
  378.            gval(ad), user);
  379.  
  380.   ad -> ad_resp = FALSE;
  381.   return do_sender_dr_outchan (ad, qp, rp);
  382. }
  383.  
  384. ADDR *read_recipient (qp)
  385. Q_struct *qp;
  386. {
  387.     int        retval;
  388.     RP_Buf rps, *rp = &rps;
  389.     ADDR        *ad;
  390.     int type = qp -> inbound -> li_chan -> ch_in_ad_type;
  391.  
  392.     PP_TRACE (("submit/read_recip()"));
  393.  
  394.     ad = NULLADDR;
  395.  
  396.     retval = rd_adr (stdin, TRUE, &ad);
  397.  
  398.     switch (retval) {
  399.         case RP_OK:
  400.         if (ad -> ad_value == NULLCP)
  401.             break;
  402.         ad -> ad_type = type;
  403.         if (ad -> ad_resp == NO)
  404.             ad -> ad_status = AD_STAT_DONE;
  405.         return ad;
  406.  
  407.         case RP_DONE:
  408.         return NULL;
  409.  
  410.     }
  411.     PP_TRACE (("submit/read_recipient(def=%s)",
  412.            rp_valstr (retval)));
  413.     rp -> rp_val = retval;
  414.     (void) strcpy(rp -> rp_line, "Empty address ?");
  415.     if (ad == NULLADDR)
  416.         ad = adr_new(" ", NULL, NULL);
  417.     else
  418.         ad -> ad_value = strdup(" ");
  419.     ad->ad_r822adr = strdup(" ");
  420.     x400_add(ad);
  421.     ad->ad_type = type;
  422.     ad -> ad_no = ad_extend++;
  423.     if (ad -> ad_extension == 0)
  424.         ad -> ad_extension = ad -> ad_no;
  425.     if (ad -> ad_resp)
  426.         ad->ad_status = AD_STAT_PEND;
  427.     else
  428.         ad->ad_status = AD_STAT_DONE;
  429.     return ad;
  430. }
  431.  
  432.  
  433.  
  434.  
  435. static void set_return_chan (ad, chan, host)
  436. ADDR    *ad;
  437. CHAN    *chan;
  438. char    *host;
  439. {
  440.     LIST_RCHAN    *ch;
  441.  
  442.     if (chan == NULLCHAN || ad == NULLADDR || host == NULLCP)
  443.         err_abrt (RP_BAD, "set_return_chan called with NULL fields");
  444.  
  445.     PP_TRACE (("set_return_chan (chan='%s', host='%s', drchan='%s')", 
  446.         chan -> ch_name ? chan -> ch_name : "", 
  447.         host ? host : "", 
  448.         chan -> ch_drchan ? chan -> ch_drchan : ""));
  449.  
  450.     if (isstr (chan -> ch_drchan)) 
  451.         ch = list_rchan_new (host, chan -> ch_drchan);
  452.     else
  453.         ch = list_rchan_new (host, chan -> ch_name);
  454.  
  455.     if (ad -> ad_outchan)
  456.         list_rchan_free (ad -> ad_outchan);
  457.     ad -> ad_outchan = ch;
  458. }
  459.  
  460.  
  461. static int do_sender_dr_outchan (ad, qp, rp)
  462. ADDR    *ad;
  463. Q_struct *qp;
  464. RP_Buf *rp;
  465. {
  466.     PP_TRACE (("do_sender_dr_outchan (%s)", ad -> ad_value));
  467.  
  468.     if (ad -> ad_outchan == NULLIST_RCHAN ||
  469.         ad -> ad_outchan -> li_chan == NULLCHAN)
  470.         return rplose (rp, RP_BAD, "DR has no channel");
  471.  
  472.     if (fillin_orig_outchan (qp, ad) == NOTOK)
  473.         return rplose (rp, RP_BAD, "Can't find channel for DR");
  474.  
  475.     set_return_chan (ad, ad -> ad_outchan -> li_chan,
  476.              ad -> ad_outchan -> li_mta);
  477.     return RP_OK;
  478. }
  479.  
  480.  
  481. /* -- read recip, & validate before adding to list. -- */
  482. int validate_recip(ad, qp, rp)
  483. ADDR    *ad;
  484. Q_struct *qp;
  485. RP_Buf *rp;
  486. {
  487.     int    retval;
  488.  
  489.     PP_TRACE (("submit/validate_recip()"));
  490.  
  491.     ad -> ad_no = ad_extend++;
  492.     if (ad -> ad_extension == 0)
  493.         ad -> ad_extension = ad -> ad_no;
  494.  
  495.     switch (ad -> ad_status) {
  496.     case AD_STAT_DRWRITTEN:
  497.         if (ad -> ad_resp == FALSE) {
  498.             (void) rplose (rp, RP_AOK, "DR '%s'", ad -> ad_value);
  499.             break;
  500.         }
  501.         else if (ad -> ad_no != DR_FILENO_DEFAULT)
  502.             ad -> ad_status = AD_STAT_DONE;
  503.         /* fall */
  504.  
  505.     case AD_STAT_PEND:
  506.         retval = recip_parse (ad, qp, rp);
  507.         if (rp_isbad (retval)) {
  508.             if (rp_isbad (bad_address (ad, qp, rp)))
  509.                 return rp -> rp_val;
  510.             break;
  511.         }
  512.  
  513.         (void) rplose (rp, RP_AOK, "Nice address %s", ad -> ad_value);
  514.         break;
  515.  
  516.     default:
  517.         (void) rplose (rp, RP_AOK, "Skip '%s'", ad -> ad_value);
  518.         break;
  519.  
  520.     }
  521.     return rp -> rp_val;
  522. }
  523.  
  524. static int bad_address (ad, qp, rp)
  525. ADDR    *ad;
  526. Q_struct *qp;
  527. RP_Buf    *rp;
  528. {
  529.     int    retval = rp -> rp_val;
  530.  
  531.     if (rp_gbval (retval) == RP_BTNO &&
  532.         retval != RP_BHST &&
  533.         retval != RP_DHST)
  534.         return retval;    /* temp failure */
  535.  
  536.     if (accept_all && qp -> msgtype != MT_DMPDU) {
  537.         ad -> ad_parse_stat = retval;
  538.         ad -> ad_status = AD_STAT_DRREQUIRED; 
  539.         ad -> ad_reason =  DRR_UNABLE_TO_TRANSFER; 
  540.         ad -> ad_diagnostic = DRD_UNRECOGNISED_OR; 
  541.         ad -> ad_add_info = strdup (rp -> rp_line);
  542.         (void) rplose (rp, RP_AOK,
  543.                    "Recipient %s failed to parse: DR to be generated",
  544.                 ad -> ad_value);
  545.     }
  546.     else if (accept_all && qp -> msgtype == MT_DMPDU)
  547.         return rp -> rp_val;
  548.     else {
  549.         ad -> ad_resp = FALSE;
  550.         ad -> ad_status = AD_STAT_DONE;
  551.     }
  552.  
  553.     return rp -> rp_val;
  554. }
  555.  
  556. extern Redirection *redirect_new();
  557. extern void redirect_add(), redirect_rewind();
  558. extern char *adminstration_req_alt;
  559.  
  560. static int recip_parse (ad, qp, rp)
  561. ADDR    *ad;
  562. Q_struct *qp;
  563. RP_Buf    *rp;
  564. {
  565.     int    retval;
  566.     char    *orig;
  567.     Redirection    *rewind;
  568.     PP_TRACE (("submit/recip_parse()"));
  569.  
  570.     retval = ad_parse (ad, rp, qp -> inbound -> li_chan  -> ch_ad_order);
  571.  
  572.     if (rp_isbad (retval) 
  573.         && qp->alternate_recip_allowed == TRUE
  574.         && qp->recip_reassign_prohibited != TRUE
  575.         && isstr(ad -> ad_orig_req_alt)) {
  576.         char    buf[BUFSIZ];
  577.  
  578.         PP_TRACE(("attempting ad_orig_req_alt '%s'", 
  579.               ad -> ad_orig_req_alt));
  580.         if (ad->ad_type == AD_X400_TYPE) {
  581.             if (isstr(ad->ad_r400adr))
  582.                 strcat(buf, ad->ad_r400adr);
  583.             else
  584.                 strcat(buf, ad->ad_value);
  585.         } else {
  586.             OR_ptr    or = NULLOR;
  587.             
  588.             if (isstr(ad->ad_r822adr))
  589.                 or_rfc2or_aux(ad->ad_r822adr, &or, ad->ad_no);
  590.             else
  591.                 or_rfc2or_aux(ad->ad_value, &or, ad->ad_no);
  592.             if (or != NULLOR) {
  593.                 or_or2std(or, buf, FALSE);
  594.                 or_free(or);
  595.             } else
  596.                 buf[0] = '\0';
  597.         }
  598.         rewind = redirect_new(buf,
  599.                       (isstr(ad->ad_dn)) ?
  600.                       ad->ad_dn : "",
  601.                       NULLUTC,
  602.                       RDR_ORIG_ASSIGNED);
  603.         if (redirect_before(ad->ad_redirection_history,
  604.                     rewind) == TRUE) {
  605.             PP_NOTICE(("redirection loop detected for '%s'",
  606.                    buf));
  607.             redirect_free(rewind);
  608.         } else {
  609.             redirect_add(&(ad->ad_redirection_history),
  610.                      rewind);
  611.             orig = ad->ad_value;
  612.  
  613.             ad -> ad_value = strdup (ad -> ad_orig_req_alt);
  614.             if (ad -> ad_r400adr != NULLCP) {
  615.                 free(ad -> ad_r400adr);
  616.                 ad -> ad_r400adr = NULLCP;
  617.             }
  618.             if (ad -> ad_r822adr != NULLCP) {
  619.                 free(ad -> ad_r822adr);
  620.                 ad -> ad_r822adr = NULLCP;
  621.             }
  622.  
  623.             aparse_rewindx400(ad -> aparse);
  624.             aparse_rewindr822(ad -> aparse);
  625.             if (ad->ad_parse_message) {
  626.                 free(ad->ad_parse_message);
  627.                 ad->ad_parse_message = NULLCP;
  628.             }
  629.             if (rp_isbad(retval = ad_parse (ad, rp,
  630.                             qp -> inbound -> li_chan  -> ch_ad_order))) {
  631.                 redirect_rewind(&(ad->ad_redirection_history),
  632.                         rewind);
  633.                 if (ad->ad_value) free(ad->ad_value);
  634.                 ad->ad_value = orig;
  635.                 if (ad -> ad_r400adr != NULLCP) {
  636.                     free(ad -> ad_r400adr);
  637.                     ad -> ad_r400adr = NULLCP;
  638.                 }
  639.                 if (ad -> ad_r822adr != NULLCP) {
  640.                     free(ad -> ad_r822adr);
  641.                     ad -> ad_r822adr = NULLCP;
  642.                 }
  643.             } else {
  644.                 if (orig) free(orig);
  645.             }
  646.         }
  647.     }    
  648.  
  649.     if (rp_isbad(retval) && isstr(adminstration_req_alt)) {
  650.         char    buf[BUFSIZ];
  651.         char    *saveerror = NULLCP;
  652.  
  653.         PP_TRACE(("attempting adminstration_req_alt '%s'",
  654.               adminstration_req_alt));
  655.  
  656.         if (ad->ad_type == AD_X400_TYPE) {
  657.             if (isstr(ad->ad_r400adr))
  658.                 strcat(buf, ad->ad_r400adr);
  659.             else
  660.                 strcat(buf, ad->ad_value);
  661.         } else {
  662.             OR_ptr    or = NULLOR;
  663.             
  664.             if (isstr(ad->ad_r822adr))
  665.                 or_rfc2or_aux(ad->ad_r822adr, &or, ad->ad_no);
  666.             else
  667.                 or_rfc2or_aux(ad->ad_value, &or, ad->ad_no);
  668.             if (or != NULLOR) {
  669.                 or_or2std(or, buf, FALSE);
  670.                 or_free(or);
  671.             } else
  672.                 buf[0] = '\0';
  673.         }
  674.         
  675.         rewind = redirect_new(buf,
  676.                       (isstr(ad->ad_dn)) ?
  677.                       ad->ad_dn : "",
  678.                       NULLUTC,
  679.                       RDR_MD_ASSIGNED);
  680.         if (redirect_before(ad->ad_redirection_history,
  681.                     rewind) == TRUE) {
  682.             PP_NOTICE(("redirection loop detected for '%s'",
  683.                    buf));
  684.             redirect_free(rewind);
  685.         } else {
  686.             redirect_add(&(ad->ad_redirection_history),
  687.                      rewind);
  688.             orig = ad->ad_value;
  689.             ad -> ad_value = strdup (adminstration_req_alt);
  690.             if (ad -> ad_r400adr != NULLCP) {
  691.                 free(ad -> ad_r400adr);
  692.                 ad -> ad_r400adr = NULLCP;
  693.             }
  694.             if (ad -> ad_r822adr != NULLCP) {
  695.                 free(ad -> ad_r822adr);
  696.                 ad -> ad_r822adr = NULLCP;
  697.             }
  698.  
  699.             aparse_rewindx400(ad -> aparse);
  700.             aparse_rewindr822(ad -> aparse);
  701.             saveerror = ad->ad_parse_message;
  702.             ad->ad_parse_message = NULLCP;
  703.  
  704.             if (rp_isbad(retval = ad_parse (ad, rp,
  705.                             qp -> inbound -> li_chan  -> ch_ad_order))) {
  706.                 redirect_rewind(&(ad->ad_redirection_history),
  707.                         rewind);
  708.                 if (ad -> ad_r400adr != NULLCP) {
  709.                     free(ad -> ad_r400adr);
  710.                     ad -> ad_r400adr = NULLCP;
  711.                 }
  712.                 if (ad -> ad_r822adr != NULLCP) {
  713.                     free(ad -> ad_r822adr);
  714.                     ad -> ad_r822adr = NULLCP;
  715.                 }
  716.                 if (ad->ad_parse_message) 
  717.                     free(ad->ad_parse_message);
  718.                 ad->ad_parse_message = saveerror;
  719.             } else {
  720.                 if (saveerror)
  721.                     free(saveerror);
  722.             }
  723.             /* maintain previous ad_value for */
  724.             /* adminstration_req_alt redirects */
  725.             if (ad->ad_value) free(ad->ad_value);
  726.             ad->ad_value = orig;
  727.         }
  728.     }
  729.         
  730.     if (!accept_all && rp_isbad (retval)) {
  731.         PP_TRACE (("recip_parse failed (%s %s)",
  732.                rp_valstr((int)rp -> rp_val),
  733.                rp -> rp_line));
  734.         return retval;
  735.     }
  736.  
  737.  
  738.     /* -- Patch up the local x400adr -- */
  739.  
  740.     if (!rp_isbad (retval)) {
  741.         if (ad -> ad_r400adr == NULLCP && ad -> ad_type == AD_822_TYPE)
  742.             x400_add (ad);
  743.  
  744.         if (ad -> ad_r822adr == NULLCP && ad -> ad_type == AD_X400_TYPE)
  745.             rfc822_add (ad);
  746.     }
  747.     else {
  748.         if (ad -> ad_r400adr == NULLCP)
  749.             ad -> ad_r400adr = strdup (ad -> ad_value);
  750.         if (ad -> ad_r822adr == NULLCP)
  751.             ad -> ad_r822adr = strdup (ad -> ad_value);
  752.     }
  753.     return (retval);
  754. }
  755.  
  756.  
  757.  
  758.  
  759. void ad_log_print (ad)
  760. ADDR           *ad;
  761. {
  762.     char    *recip;
  763.     if (ad == NULLADDR)
  764.         return;
  765.  
  766.  
  767.     switch (ad -> ad_type) {
  768.         case AD_X400_TYPE:
  769.         recip = (ad -> ad_r400adr) ? ad -> ad_r400adr : ad -> ad_value;
  770.         break;
  771.         case AD_822_TYPE:
  772.         recip = (ad -> ad_r822adr) ? ad -> ad_r822adr : ad -> ad_value;
  773.         break;
  774.         default:
  775.         recip = ad->ad_value;
  776.         break;
  777.     }
  778.     PP_NOTICE (("Recipient '%s'  mta '%s'",
  779.             recip,
  780.             (ad -> ad_outchan && ad -> ad_outchan -> li_mta) ?
  781.             ad -> ad_outchan -> li_mta : "<unknown>"));
  782.  
  783.     ad_log_print (ad -> ad_next);
  784. }
  785.  
  786.  
  787.  
  788. #ifdef lint
  789. /* VARARGS3 */
  790. int rplose (rp, val, str)
  791. RP_Buf    *rp;
  792. int    val;
  793. char    *str;
  794. {
  795.     return rplose (rp, val, str);
  796. }
  797. #else
  798. int rplose (va_alist)
  799. va_dcl
  800. {
  801.     va_list ap;
  802.     RP_Buf    *rp;
  803.     int    val;
  804.     char    buf[BUFSIZ];
  805.  
  806.     va_start (ap);
  807.  
  808.     rp = va_arg (ap, RP_Buf *);
  809.     val = va_arg (ap, int);
  810.  
  811.     _asprintf (buf, NULLCP, ap);
  812.  
  813.     if (rp_isbad (val))
  814.         PP_LOG (LLOG_EXCEPTIONS, ("rplose (%s, '%s')",
  815.                       rp_valstr (val), buf));
  816.  
  817.     rp -> rp_val = val;
  818.     (void) strncpy (rp -> rp_line, buf, sizeof (rp -> rp_line) - 1);
  819.  
  820.     va_end (ap);
  821.  
  822.     return val;
  823. }
  824. #endif
  825.