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

  1. /* io_grey.c: These are IO routines for the greybook channel */
  2.  
  3. # ifndef lint
  4. static char Rcsid[] = "@(#)$Header: /xtel/pp/pp-beta/Chans/grey/RCS/io_grey.c,v 6.0 1991/12/18 20:10:19 jpo Rel $";
  5. # endif
  6.  
  7. /*
  8.  * $Header: /xtel/pp/pp-beta/Chans/grey/RCS/io_grey.c,v 6.0 1991/12/18 20:10:19 jpo Rel $
  9.  *
  10.  * $Log: io_grey.c,v $
  11.  * Revision 6.0  1991/12/18  20:10:19  jpo
  12.  * Release 6.0
  13.  *
  14.  */
  15.  
  16.  
  17.  
  18. #include "util.h"
  19. #include "prm.h"
  20. #include "q.h"
  21. #include "adr.h"
  22. #include "ap.h"
  23. #include "retcode.h"
  24. #include "tb_q.h"
  25. #include "tb_a.h"
  26. #include "tb_prm.h"
  27. #include <isode/cmd_srch.h>
  28. #include <signal.h>
  29.  
  30.  
  31. /*--- statics ---*/
  32. static struct prm_vars          prm = { NULLCP, 0, PRM_ACCEPTALL };
  33. static Q_struct                 Qstruct;
  34.  
  35.  
  36. static int            submit_started = 0;
  37. #define ST_OPENED        3
  38. #define ST_DATAINIT        4
  39. #define ST_JNTHDR               0
  40. #define ST_MSGHDR               1
  41. #define ST_BODY                 2
  42. static int                      state = ST_OPENED;
  43.  
  44.  
  45. static AP_ptr                   newdomain();
  46. static char                     *compress();
  47. static void            berror ();
  48. static int                      add_via();
  49. static int                      aprd_done();
  50. static int                      aprd_init();
  51. static int                      aprdchr();
  52. static int                      fixup_sender();
  53. static int                      hdr_done();
  54. static int                      hdr_init();
  55. static int                      hdr_read();
  56. static int                      process_addrs();
  57. static int            pp_error ();
  58.  
  59. static CHAN                     *mychan = NULLCHAN;
  60. static char            **errstr = (char **) 0;
  61. static char                     *theheader = NULLCP;
  62. static char                     *hdrptr;
  63. static char                     *apchptr;
  64. static char                     *apcharacters = NULLCP;
  65. static char            *fromhost = NULLCP;
  66.  
  67. static int data_bytes;
  68. static struct timeval data_timer;
  69.  
  70. /*--- externals */
  71. extern ADDR                     *adr_new();
  72. extern char            *postmaster;
  73. extern char    *ia5_bp, *hdr_822_bp;
  74.  
  75. #define GB_NOTOK    NOTOK
  76. #define GB_OK        OK
  77. #define GB_RECIPFAILED    -2
  78. #define GB_SENDERFAILED    -3
  79.  
  80.  
  81. /* -------------------  Begin  Routines  ---------------------------------- */
  82.  
  83.  
  84. char    errbuffer[BUFSIZ];
  85.  
  86. /*--- tell PP that a call is arriving ---*/
  87. int pp_open (channame, hostname, perrstr)
  88. char    *channame;
  89. char    *hostname;
  90. char    **perrstr;
  91. {
  92.     RP_Buf          reply;
  93.     Q_struct        *qp = &Qstruct;
  94.     LIST_BPT        *new;
  95.     extern char    *quedfldir;
  96.     static int onceonly = 1;
  97.  
  98.     errstr = perrstr;
  99.     if (onceonly) {
  100.         chan_init (channame);
  101.         (void) chdir (quedfldir);
  102.         ap_use_percent ();
  103.         (void) signal(SIGPIPE, SIG_IGN);
  104.         onceonly = 0;
  105.     }
  106.  
  107.     if (state != ST_OPENED)
  108.         return pp_error (errstr, GB_RECIPFAILED,
  109.                  "Illegal call to ppp_open - internal botch");
  110.     PP_TRACE (("pp_open (%s, %s)", channame, hostname));
  111.  
  112.     if ((mychan = ch_mta2struct (channame, hostname)) == NULLCHAN) {
  113.         (void) sprintf (errbuffer,
  114.                 "Local error: Channel '%s' is not known",
  115.                 channame);
  116.         return pp_error (errstr, GB_RECIPFAILED, errbuffer);
  117.     }
  118.     rename_log (mychan -> ch_name);
  119.  
  120.     PP_NOTICE (("Incoming Call from %s to %s", hostname, mychan->ch_name));
  121.     if (fromhost)
  122.         free (fromhost);
  123.     fromhost = strdup (hostname);
  124.  
  125.     if (submit_started == 0 && rp_isbad (io_init (&reply))) {
  126.         berror (errbuffer, "Can't initialise mail system", &reply);
  127.         return pp_error (errstr, GB_RECIPFAILED, errbuffer);
  128.     }
  129.     submit_started = 1;
  130.  
  131.     if (rp_isbad (io_wprm (&prm, &reply))) {
  132.         berror (errbuffer, "Can't set parameters", &reply);
  133.         return pp_error (errstr, GB_RECIPFAILED, errbuffer);
  134.     }
  135.  
  136.  
  137.     /*--- initialize queue structure ---*/
  138.  
  139.     q_init (qp);
  140.     qp -> msgtype = MT_UMPDU;
  141.     qp -> inbound = list_rchan_new (hostname, NULL);
  142.     qp -> inbound -> li_chan = mychan;
  143.  
  144.     qp -> encodedinfo.eit_types = NULLIST_BPT;
  145.     new = list_bpt_new (hdr_822_bp);
  146.     list_bpt_add (&qp -> encodedinfo.eit_types, new);
  147.     new = list_bpt_new (ia5_bp);
  148.     list_bpt_add (&qp -> encodedinfo.eit_types, new);
  149.  
  150.     if (rp_isbad (io_wrq (qp, &reply))) {
  151.         berror (errbuffer, "Can't write Q struct", &reply);
  152.         return pp_error (errstr, GB_RECIPFAILED, errbuffer);
  153.     }
  154.     data_bytes = 0;
  155.     timer_start (&data_timer);
  156.     state = ST_DATAINIT;
  157.     return GB_OK;
  158. }
  159.  
  160. /* ARGSUSED */
  161. int pp_write (fd, buff, size)  /*--- write some data to PP ---*/
  162. int    fd; 
  163. char    buff[];
  164. int     size;
  165. {
  166.     static int              linefeed = 0;
  167.     static struct qbuf      *qb[2] = {NULL, NULL}, *qp = NULL;
  168.     char                    *cp = NULLCP,
  169.                 *ep = NULLCP,
  170.                 *bp = NULLCP,
  171.                 *q;
  172.     int    retval;
  173.  
  174.     PP_TRACE (("pp_write (%d bytes)", size));
  175.  
  176.     data_bytes += size;
  177.  
  178.     switch (state) {
  179.         case ST_DATAINIT:
  180.         linefeed = 0;
  181.         if (qb[0])
  182.             qb_free (qb[0]), qb[0] = NULL;
  183.         if (qb[1])
  184.             qb_free (qb[1]), qb[1] = NULL;
  185.         state = ST_JNTHDR;
  186.         /* fall */
  187.         case ST_JNTHDR:
  188.         case ST_MSGHDR:
  189.         for (bp = cp = buff, ep = buff + size; cp < ep; cp++) {
  190.             switch (*cp) {
  191.                 case '\r':
  192.                 case ' ':
  193.                 case '\t':
  194.                 continue;
  195.                 case '\n':
  196.                 linefeed ++;
  197.                 if (linefeed < 2)
  198.                     continue;
  199.                 for (q = cp - 1; q > bp && *q == '\r'; q--)
  200.                     continue;
  201.  
  202.                 if (qb[state] == NULL)
  203.                     qb[state] = str2qb (bp, q - bp + 1, 1);
  204.                 else {
  205.                     qp = str2qb (bp, q - bp + 1, 0);
  206.                     insque (qp, qb[state]->qb_back);
  207.                 }
  208.                 bp = cp + 1;
  209.                 state ++;
  210.                 if (state < ST_BODY)
  211.                     continue;
  212.                 break;
  213.                 default:
  214.                 linefeed = 0;
  215.                 continue;
  216.             }
  217.             break;
  218.         }
  219.                 if (state != ST_BODY && bp + 1 < ep) {
  220.                         if (qb[state] == NULL)
  221.                                 qb[state] = str2qb (bp, ep - bp, 1);
  222.                         else {
  223.                                 qp = str2qb (bp, ep - bp, 0);
  224.                                 insque (qp, qb[state]->qb_back);
  225.                         }
  226.                 }
  227.  
  228.         if (qb[0]) {
  229.             cp = NULLCP;
  230.             PP_DBG (("pp_write/qb[0]='%.900s'",
  231.                    cp = qb2str(qb[0])));
  232.             if (cp)
  233.                 free (cp);
  234.         }
  235.         if (qb[1]) {
  236.             cp = NULLCP;
  237.             PP_DBG (("pp_write/qb[1]='%.900s'",
  238.                    cp = qb2str (qb[1])));
  239.             if (cp)
  240.                 free (cp);
  241.         }
  242.  
  243.         if (state == ST_BODY) { /* GOT IT - lets go!! */
  244.             if ((retval = process_addrs (qb[0], qb[1], errstr))
  245.                 != GB_OK)
  246.                 return retval;
  247.             qb_free (qb[0]); qb[0] = NULL;
  248.             qb_free (qb[1]); qb[1] = NULL;
  249.             if (bp + 1 < ep)
  250.                 if (rp_isbad (io_tdata(bp, size - (bp-buff))))
  251.                     return pp_error (errstr,
  252.                              GB_RECIPFAILED,
  253.                              "Data Copy failed");
  254.         }
  255.         break;
  256.  
  257.  
  258.         case ST_BODY:
  259.         if (size <= 0) {
  260.             PP_LOG (LLOG_EXCEPTIONS, ("Funny size to pp_write: %d",
  261.                           size));
  262.             return size;
  263.         }
  264.         if (rp_isbad (io_tdata (buff, size)))
  265.             return pp_error (errstr, GB_RECIPFAILED,
  266.                      "Data Copy Faield");
  267.         return size;
  268.         default:
  269.         return pp_error (errstr, GB_RECIPFAILED,
  270.                  "Illegal call to pp_write - internal error");
  271.     }
  272.     return size;
  273. }
  274.  
  275. /* ARGSUSED */
  276. int pp_close(fd)  /*--- tell PP that all the data has arrived ---*/
  277. int    fd; 
  278. {
  279.     RP_Buf  reply;
  280.  
  281.     PP_TRACE (("pp_close()"));
  282.  
  283.     if (state == ST_MSGHDR)
  284.         if (pp_write (0, "\n", 1) != 1)
  285.             return pp_error (errstr, GB_RECIPFAILED,
  286.                      "pp_write (internal call) failed");
  287.  
  288.     if (state != ST_BODY)
  289.         return pp_error (errstr, GB_RECIPFAILED,
  290.                  "Illegal call to pp_close - internal error");
  291.  
  292.     timer_end (&data_timer, data_bytes, "Data Received");
  293.     if (rp_isbad (io_tdend (&reply))) {
  294.         berror (errbuffer, "data termination failed", &reply);
  295.         return pp_error (errstr, GB_RECIPFAILED, errbuffer);
  296.     }
  297.  
  298.     if (rp_isbad (io_tend (&reply))) {
  299.         berror (errbuffer, "data termination (2) failed", &reply);
  300.         if (rp_gbval (reply.rp_val) == RP_BNO)
  301.             return pp_error (errstr, GB_NOTOK, errbuffer);
  302.         return pp_error (errstr, GB_RECIPFAILED, errbuffer);
  303.     }
  304.  
  305.     PP_NOTICE (("Message successfully transfered"));
  306.     state = ST_OPENED;
  307.     return GB_OK;
  308. }
  309.  
  310.  
  311.  
  312.  
  313. /* -------------------  Static Routines  ---------------------------------- */
  314.  
  315. static AP_ptr newdomain (domn)
  316. char    *domn;
  317. {
  318.     PP_TRACE (("newdomain (%s)", domn));
  319.     return ap_new ((*domn == '[') ? AP_DOMAIN_LITERAL : AP_DOMAIN, domn);
  320. }
  321.  
  322.  
  323.  
  324.  
  325. static process_addrs (qbjnt, qbhdr, errstr)
  326. struct qbuf     *qbjnt;
  327. struct qbuf     *qbhdr;
  328. char    **errstr;
  329. {
  330.     RP_Buf          reply;
  331.     char            *name,
  332.             *contents,
  333.             buffer[BUFSIZ],
  334.             sbuf[BUFSIZ],
  335.             reasonmsg[BUFSIZ],
  336.             *p = NULLCP;
  337.     AP_ptr          ap_sender = NULLAP,
  338.             jntroute = NULLAP,
  339.             local = NULLAP,
  340.             domain = NULLAP,
  341.             route = NULLAP,
  342.             jntaddr = NULLAP,
  343.             ackaddr = NULLAP,
  344.             aptr;
  345.     ADDR            *ap = NULLADDR;
  346.     int             got_sender = 0,
  347.             ack_flag = AD_USR_BASIC,
  348.             retval;
  349.     struct qbuf     *qp = NULL;
  350.     int    n;
  351.  
  352.  
  353.     PP_TRACE (("process_addrs()"));
  354.  
  355.     hdr_init (qbhdr);
  356.  
  357.  
  358.     reasonmsg[0] = 0;
  359.     while (hdr_read (&name, &contents) != NOTOK) {
  360.  
  361.         PP_DBG (("process_addrs (%s %s)", name, contents));
  362.  
  363.         if (lexequ ("sender", name) == 0) {
  364.             if ((aptr = ap_s2t (contents)) == BADAP ||
  365.                 aptr == NULLAP) {
  366.                 PP_LOG (LLOG_EXCEPTIONS,
  367.                     ("Bad sender field %s",
  368.                      contents));
  369.                 (void) sprintf (reasonmsg,
  370.                         "sender %s not parseable", contents);
  371.             }
  372.             else {
  373.                 (void) strcpy (sbuf, contents);
  374.                 ap_sender = aptr;
  375.                 got_sender = 1;
  376.             }
  377.         }
  378.  
  379.         if (lexequ ("from", name) == 0 && !got_sender) {
  380.             if ((aptr = ap_s2t (contents)) == BADAP ||
  381.                 aptr == NULLAP) {
  382.                 PP_LOG (LLOG_EXCEPTIONS,
  383.                        ("Bad from field %s",
  384.                     contents));
  385.                 (void) sprintf (reasonmsg,
  386.                         "From %s not parseable", contents);
  387.             }
  388.             else {
  389.                 ap_sender = aptr;
  390.                 (void) strcpy (sbuf, contents);
  391.             }
  392.         }
  393.  
  394.         if (lexequ ("via", name) == 0) {
  395.             if (add_via (contents, &jntroute, buffer) == NOTOK) {
  396.                 return pp_error (errstr, GB_NOTOK,
  397.                          buffer);
  398.             }
  399.         }
  400.  
  401.         if (lexequ ("acknowledge-to", name) == 0)
  402.             if ((ackaddr = ap_s2t(contents)) == BADAP ||
  403.                 aptr == NULLAP) {
  404.                 PP_LOG (LLOG_EXCEPTIONS,
  405.                     ("Bad acknowledge-to field %s",
  406.                       contents));
  407.                 aptr = NULLAP;
  408.             }
  409.     }
  410.  
  411.     hdr_done();
  412.  
  413.     if (!ap_sender) {
  414.         if (reasonmsg[0])
  415.             return pp_error (errstr, GB_NOTOK,
  416.                      reasonmsg);
  417.         return pp_error (errstr, GB_NOTOK,
  418.                  "No sender field present in Header");
  419.     }
  420.  
  421.     if (fixup_sender (ap_sender, jntroute, buffer, ackaddr))
  422.         ack_flag = AD_USR_CONFIRM;
  423.  
  424.     ap = adr_new (buffer, AD_822_TYPE, 0);
  425.  
  426.     PP_NOTICE (("Sender '%s', original sender '%s'", ap->ad_value, sbuf));
  427.  
  428.     if (rp_isbad (io_wadr (ap, AD_ORIGINATOR, &reply))) {
  429.         (void) sprintf (buffer, "Bad sender '%s'", ap -> ad_value);
  430.         adr_tfree (ap);
  431.         berror (errbuffer, buffer, &reply);
  432.         if (reply.rp_val == RP_BHST ||
  433.             rp_gbval(reply.rp_val) == RP_BNO)
  434.             return pp_error (errstr, GB_NOTOK, errbuffer);
  435.         return pp_error (errstr, GB_RECIPFAILED, errbuffer);
  436.     }
  437.  
  438.     adr_tfree (ap);
  439.  
  440.     aprd_init (qbjnt);
  441.  
  442.     n = 0;
  443.     while ((jntaddr = ap_pinit (aprdchr)) != BADAP) {
  444.         switch (retval = ap_1adr()) {
  445.             case NOTOK:
  446.             ap_free (jntaddr);
  447.             aprd_done ();
  448.             return pp_error (errstr, GB_NOTOK,
  449.                  "unparseable JNT address - BAD JNT HEADER");
  450.  
  451.             case DONE:
  452.             ap_free (jntaddr);
  453.             break;
  454.         }
  455.  
  456.         if (retval == DONE)
  457.             break;
  458.  
  459.         ap_t2p (jntaddr, (AP_ptr *)0, (AP_ptr *)0, &local,
  460.                 &domain, &route);
  461.  
  462.         if (route == NULLAP) {
  463.             if (domain && domain -> ap_obtype == AP_DOMAIN_LITERAL) {
  464.                 ap_free (domain);
  465.                 domain = NULLAP;
  466.             }
  467.         }
  468.         else {
  469.             if (route -> ap_obtype == AP_DOMAIN_LITERAL) {
  470.                 aptr = route;
  471.                 route = aptr -> ap_next;
  472.                 if (route -> ap_obtype != AP_DOMAIN_LITERAL ||
  473.                     route -> ap_obtype != AP_DOMAIN)
  474.                     route = NULLAP;
  475.                 ap_free (aptr);
  476.             }
  477.         }
  478.         ap_dmnormalize (domain, mychan -> ch_ad_order);
  479.         p = ap_p2s_nc (NULLAP, NULLAP, local, domain, route);
  480.         ap = adr_new (p, AD_822_TYPE, 1);
  481.         ap -> ad_usrreq = ack_flag;
  482.  
  483.         PP_NOTICE (("Recipient Address '%s'", ap->ad_value));
  484.  
  485.         if (rp_isbad (io_wadr (ap, AD_RECIPIENT, &reply))) {
  486.             berror (errbuffer, "Recipient failed", &reply);
  487.             return pp_error (errstr, GB_RECIPFAILED, errbuffer);
  488.         }
  489.         adr_tfree (ap);
  490.         n ++;
  491.     }
  492.     if (n == 0)
  493.         return pp_error (errstr, GB_NOTOK,
  494.                  "No recipients in JNT Header");
  495.  
  496.     if (rp_isbad (io_adend (&reply))) {
  497.         berror (errbuffer, "Address termination failed", &reply);
  498.         return pp_error (errstr, GB_RECIPFAILED, errbuffer);
  499.     }
  500.  
  501.     aprd_done();
  502.  
  503.     if (rp_isbad (io_tinit (&reply)) ||
  504.         rp_isbad (io_tpart (hdr_822_bp, FALSE, &reply))) {
  505.         berror (errbuffer, "Text initialisation", &reply);
  506.         return pp_error (errstr, GB_RECIPFAILED, errbuffer);
  507.     }
  508.  
  509.     for (qp = qbhdr -> qb_forw; qp != qbhdr; qp = qp -> qb_forw) {
  510.         if (qp -> qb_len <= 0)
  511.             continue;
  512.         if (rp_isbad (io_tdata (qp->qb_data, qp->qb_len))) {
  513.             (void) sprintf (errbuffer, "Data copy Failed");
  514.             return pp_error (errstr, GB_RECIPFAILED, errbuffer);
  515.         }
  516.     }
  517.  
  518.     if (rp_isbad (io_tdend (&reply))) {
  519.         berror (errbuffer, "Text termination problem", &reply);
  520.         return pp_error (errstr, GB_RECIPFAILED, errbuffer);
  521.     }
  522.  
  523.     if (rp_isbad (io_tpart ("1.ia5", FALSE, &reply))) {
  524.         berror (errbuffer, "Text body initialiastion probelms",
  525.             &reply);
  526.         return pp_error (errstr, GB_RECIPFAILED, errbuffer);
  527.     }
  528.  
  529.     return GB_OK;
  530. }
  531.  
  532. static int fixup_sender (sender, jntroute, dest, ack_to)
  533. AP_ptr  sender;
  534. AP_ptr  jntroute;
  535. char    *dest;
  536. AP_ptr ack_to;
  537. {
  538.     extern  char    *loc_dom_site; 
  539.     AP_ptr          ap, 
  540.             route = NULLAP, 
  541.             domain = NULLAP, 
  542.             mbox = NULLAP;
  543.     int             donevia = 0;
  544.     int        ack = 0;
  545.     char            *p;
  546.  
  547.  
  548.     PP_TRACE (("fixup_sender()")); 
  549.  
  550.  
  551.     ap_t2p (sender, (AP_ptr *)0, (AP_ptr *)0, &mbox, &domain, &route);
  552.  
  553. #define pp_is_burning_up_cpu_time 1
  554.  
  555.     while (pp_is_burning_up_cpu_time) {
  556.  
  557.         if (jntroute != NULLAP) {
  558.             ap = jntroute;
  559.             jntroute = jntroute -> ap_next;
  560.         }
  561.         else if (donevia)
  562.             break;
  563.         else {
  564.             donevia = TRUE;
  565.             if (fromhost == NULLCP || *fromhost == '\0')
  566.                 ap = newdomain (loc_dom_site);
  567.             else
  568.                 ap = newdomain (fromhost);
  569.         }
  570.  
  571.  
  572.         if (domain ==NULLAP)
  573.             domain = ap;
  574.         else {
  575.             ap -> ap_next = route;
  576.             route = ap;
  577.         }
  578.     }
  579.  
  580.  
  581.     /*--- normalise the domains ---*/
  582.     ap_dmnormalize (domain, mychan -> ch_ad_order);
  583.  
  584.     for (ap = route; ap != NULLAP; ap = ap -> ap_next)
  585.         switch (ap -> ap_obtype) {
  586.             case AP_DOMAIN:
  587.             ap_dmnormalize (ap, mychan -> ch_ad_order);
  588.             break;
  589.  
  590.             default:
  591.             break;
  592.         }
  593.  
  594.     /*--- eliminating redundant entries ---*/
  595.     while (route != NULLAP) {
  596.         AP_ptr last = domain;
  597.  
  598.         for (ap = route; ap -> ap_next != NULLAP;) {
  599.             if (ap -> ap_next ->ap_obtype == AP_NIL)
  600.                 break;
  601.             last = ap;
  602.             ap = ap -> ap_next;
  603.         }
  604.         PP_TRACE(("comparing %s & %s",
  605.               last -> ap_obvalue, ap -> ap_obvalue));
  606.         if (lexequ (last -> ap_obvalue, ap -> ap_obvalue) == 0) {
  607.             PP_TRACE (("Removing duplicate route %s (dom %s)",
  608.                    ap -> ap_obvalue, domain -> ap_obvalue));
  609.             ap -> ap_obtype = AP_NIL;
  610.             free (ap -> ap_obvalue);
  611.             ap -> ap_obvalue = NULLCP;
  612.             if (ap == route) {
  613.                 ap_free (route);
  614.                 route = NULLAP;
  615.                 break;
  616.             }
  617.         }
  618.         else
  619.             break;
  620.     }
  621.     if (ack_to) {
  622.         AP_ptr mb, dmn;
  623.  
  624.         ap_t2p (ack_to, NULLAPP, NULLAPP, &mb, &dmn, NULLAPP);
  625.         if (dmn) ap_dmnormalize (dmn, mychan -> ch_ad_order);
  626.         if (mb && dmn &&
  627.             lexequ (mb -> ap_obvalue, mbox -> ap_obvalue) == 0 &&
  628.             lexequ (dmn -> ap_obvalue, domain -> ap_obvalue) == 0)
  629.             ack = 1;
  630.     }
  631.     p = ap_p2s_nc (NULLAP, NULLAP, mbox, domain, route);
  632.     (void) strcpy (dest, p);
  633.     free (p);
  634.     return ack;
  635. }
  636.  
  637. #define retsloppy() (mychan -> ch_strict_mode == CH_STRICT_CHECK ? NOTOK : OK)
  638.  
  639. static add_via (str, route, ebuf)
  640. char    *str;
  641. AP_ptr  *route;
  642. char    *ebuf;
  643. {
  644.     char    *p, *q;
  645.     AP_ptr  ap;
  646.  
  647.  
  648.     PP_TRACE (("add_via (%s)", str));
  649.  
  650.     if ((p = rindex (str, ';')) != NULLCP)
  651.         *p = '\0';
  652.     else {
  653.         (void) sprintf (ebuf, "Illegal Via: field, No ';' \"%s\"",
  654.                 str);
  655.         PP_LOG (LLOG_EXCEPTIONS, ("%s", ebuf));
  656.         return retsloppy();
  657.     }
  658.  
  659.     compress (str, str);
  660.  
  661.     while ((p = index (str, '(')) != NULLCP) {
  662.         if ((q = index (p, ')')) != NULLCP) {
  663.             q++;
  664.             while (*q)
  665.                 *p++ = *q++;
  666.             *p = '\0';
  667.         }
  668.         else
  669.             break;
  670.     }
  671.  
  672.     compress (str, str);
  673.     if (str == NULLCP || *str == NULL) {
  674.         (void) sprintf (ebuf, "empty host component in via field");
  675.         PP_LOG (LLOG_EXCEPTIONS, ("%s", ebuf));
  676.         return retsloppy();
  677.     }
  678.     ap = newdomain (str);
  679.     ap -> ap_next = *route;
  680.     *route = ap;
  681.     return OK;
  682. }
  683.  
  684.  
  685.  
  686.  
  687.  
  688. static hdr_init (qb)
  689. struct qbuf *qb;
  690. {
  691.     hdrptr = theheader = qb2str (qb);
  692.     PP_TRACE (("hdr_init (%.999s)", hdrptr)); 
  693. }
  694.  
  695.  
  696.  
  697.  
  698. static hdr_read (name, contents)
  699. char    **name, **contents;
  700. {
  701.     PP_DBG (("hdr_read (%.80s)", hdrptr)); 
  702.  
  703.     if (*hdrptr == '\0')
  704.         return NOTOK;
  705.  
  706.     *name = hdrptr;
  707.     for (*name = hdrptr; *hdrptr; hdrptr++) {
  708.         if (*hdrptr == ':') {
  709.             *hdrptr ++ = '\0';
  710.             break;
  711.         }
  712.         if (*hdrptr == '\n') {
  713.             *hdrptr = '\0';
  714.             *contents = hdrptr;
  715.             hdrptr ++;
  716.             return OK;
  717.         }
  718.     }
  719.     compress (*name, *name);
  720.  
  721.     if (*hdrptr == '\0')
  722.         return OK;
  723.  
  724.     while (*hdrptr == ' ' || *hdrptr == '\t')
  725.         hdrptr ++;
  726.  
  727.     for (*contents = hdrptr; *hdrptr; hdrptr++) {
  728.         if (*hdrptr == '\n') {
  729.             if (isspace (hdrptr[1])) {
  730.                 *hdrptr = ' ';
  731.                 continue;
  732.             }
  733.             *hdrptr ++ = '\0';
  734.             break;
  735.         }
  736.     }
  737.     return OK;
  738. }
  739.  
  740.  
  741.  
  742.  
  743. static hdr_done()
  744. {
  745.     PP_TRACE (("hdr_done()")); 
  746.     if (theheader) {
  747.         free (theheader);
  748.         theheader = NULLCP; 
  749.     } 
  750. }
  751.  
  752.  
  753.  
  754. static aprd_init (qb)
  755. struct qbuf *qb;
  756. {
  757.     apchptr= apcharacters = qb2str (qb);
  758.     PP_TRACE (("aprd_init (%.999s)", apchptr)); 
  759. }
  760.  
  761.  
  762.  
  763. static aprdchr()
  764. {
  765.     return *apchptr == '\0' ? EOF : *apchptr++;
  766. }
  767.  
  768.  
  769.  
  770. static aprd_done()
  771. {
  772.     PP_TRACE (("aprd_done()"));
  773.     if (apcharacters) {
  774.         free (apcharacters);
  775.         apcharacters = NULLCP;
  776.     }
  777. }
  778.  
  779.  
  780.  
  781. static char *compress (fromptr, toptr)
  782. register char   *fromptr;
  783. register char   *toptr;
  784. {
  785.     register char   chr;
  786.     char            *in_toptr = toptr;
  787.  
  788.  
  789.     PP_DBG (("compress (%s)", fromptr));
  790.  
  791.  
  792.     /*--- init to skip leading spaces tabs and newlines --- */
  793.  
  794.     chr = ' ';
  795.  
  796.  
  797.     while ((*toptr = *fromptr++) != '\0') {
  798.  
  799.         /*--- only save the spaces found in between words ---*/
  800.         if (isspace (*toptr)) {
  801.             if (chr != ' ')
  802.                 *toptr++ = chr = ' ';
  803.         }
  804.         else
  805.             chr = *toptr++;
  806.     }
  807.  
  808.  
  809.     /*--- remove trailing spaces, tabs and newlines  if any ---*/
  810.     if ((chr == ' ')
  811.         && (toptr != in_toptr))
  812.         *--toptr = '\0';
  813.  
  814.     return (toptr);
  815. }
  816.  
  817. static void berror (buffer, str, rp)
  818. char    *buffer, *str;
  819. RP_Buf *rp;
  820. {
  821.     (void) sprintf (buffer, "%s ([%s] %s)",
  822.             str, rp_valstr (rp->rp_val),
  823.             rp -> rp_line[0] ? rp -> rp_line :
  824.             "No further information");
  825. }
  826.  
  827. static int pp_error (err, code, str)
  828. char    **err;
  829. int    code;
  830. char    *str;
  831. {
  832.     char    *kind;
  833.  
  834.     switch (code) {
  835.         case GB_OK:
  836.         kind = "ok";
  837.         break;
  838.         case GB_RECIPFAILED:
  839.         kind = "failed - recipient temp";
  840.         break;
  841.         case GB_NOTOK:
  842.         kind = "failed - permanent";
  843.         break;
  844.  
  845.         case GB_SENDERFAILED:
  846.         kind = "failed - sender temporary";
  847.         break;
  848.         default:
  849.         kind = "UNKNOWN";
  850.         break;
  851.     }
  852.     if (err) *err = strdup (str);
  853.     PP_LOG (LLOG_EXCEPTIONS, ("%s %s", str, kind));
  854.     submit_started = 0;
  855.     io_end (NOTOK);
  856.     state = ST_OPENED;
  857.     return code;
  858. }
  859.