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

  1. /* rfc822norm: program to 822norm stdin to stdout */
  2.  
  3. # ifndef lint
  4. static char Rcsid[] = "@(#)$Header: /xtel/pp/pp-beta/Format/rfc822norm/RCS/rfc822norm.c,v 6.0 1991/12/18 20:20:54 jpo Rel $";
  5. # endif
  6.  
  7. /*
  8.  * $Header: /xtel/pp/pp-beta/Format/rfc822norm/RCS/rfc822norm.c,v 6.0 1991/12/18 20:20:54 jpo Rel $
  9.  *
  10.  * $Log: rfc822norm.c,v $
  11.  * Revision 6.0  1991/12/18  20:20:54  jpo
  12.  * Release 6.0
  13.  *
  14.  */
  15.  
  16.  
  17.  
  18. #include    "util.h"
  19. #include    <isode/general.h>
  20. #include    <isode/cmd_srch.h>
  21. #include    "ap.h"
  22. #include    "alias.h"
  23. #include    "chan.h"
  24. #include    "retcode.h"
  25. #include    "adr.h"
  26.  
  27. #define    OPT_822        1
  28. #define OPT_733        2    
  29. #define    OPT_JNT        3
  30. #define    OPT_BIGEND    4
  31. #define OPT_LITTLEEND    5
  32. #define    OPT_STRIPROUTES    6
  33. #define OPT_STRIPDOMAIN    7
  34. #define    OPT_STRIPTRACE    8
  35. #define OPT_JNTSENDER    9
  36. #define OPT_FOLD    10
  37. #define OPT_MSGID    11
  38. #define OPT_PERCENT    12
  39. #define OPT_HIDELOCAL    13
  40. #define OPT_STRIPACK    14
  41. #define OPT_GENACK    15
  42. #define OPT_CHANGEDOMAIN 16
  43. #define OPT_FULL    17
  44. #define OPT_EXORDOM    18
  45. #define    OPT_VALDOM    19
  46. #define OPT_EXORCISE    20
  47. #define OPT_EXTERNAL    21
  48. #define OPT_INTERNAL    22
  49.  
  50. CMD_TABLE    tbl_options [] = { /* rfc822norm commandline options */
  51.     "-822",        OPT_822,
  52.     "-733",        OPT_733,
  53.     "-jnt",        OPT_JNT,
  54.     "-bigend",    OPT_BIGEND,
  55.     "-littleend",    OPT_LITTLEEND,
  56.     "-striproutes",    OPT_STRIPROUTES,
  57.     "-stripdomain",    OPT_STRIPDOMAIN,
  58.     "-changedomain", OPT_CHANGEDOMAIN,
  59.     "-striptrace",    OPT_STRIPTRACE,
  60.     "-jntsender",    OPT_JNTSENDER,
  61.     "-fold",    OPT_FOLD,
  62.     "-msgid",    OPT_MSGID,
  63.     "-percent",    OPT_PERCENT,
  64.     "-full",    OPT_FULL,
  65.     "-hidelocal",    OPT_HIDELOCAL,
  66.     "-stripack",    OPT_STRIPACK,
  67.     "-acks",    OPT_GENACK,
  68.     "-exorcise",        OPT_EXORCISE,
  69.     "-exorcise-domain",     OPT_EXORDOM,
  70.     "-valid-domains",    OPT_VALDOM,
  71.     "-external",    OPT_EXTERNAL,
  72.     "-internal",    OPT_INTERNAL,
  73.     0,        -1
  74.     };
  75.  
  76. #define    FLD_TO            1
  77. #define    FLD_CC            2
  78. #define    FLD_BCC            3
  79. #define    FLD_FROM        4
  80. #define    FLD_SENDER        5
  81. #define FLD_REPLY_TO        6
  82. #define    FLD_RESENT_FROM        7
  83. #define FLD_RESENT_SENDER    8
  84. #define    FLD_RESENT_TO        9
  85. #define    FLD_RESENT_CC        10
  86. #define    FLD_RESENT_BCC        11
  87. #define    FLD_RESENT_BY        12
  88. #define    FLD_REMAILED_FROM    13
  89. #define FLD_REMAILED_TO        14
  90. #define FLD_REMAILED_BY        15
  91. #define FLD_REDISTRIBUTED_FROM    16
  92. #define FLD_REDISTRIBUTED_TO    17
  93. #define FLD_REDISTRIBUTED_BY    18
  94. #define FLD_ORIG_SENDER        19
  95. /* RFC 987 extensions */
  96. #define FLD_RFC987        20
  97. /* RFC 987 (88) extensions - proposed */
  98. #define FLD_RFC987_88        21
  99. #define FLD_JNT_ACK        22
  100. /* misc */
  101. #define FLD_ERRORS_TO        23
  102. #define FLD_DATE        24
  103.  
  104. CMD_TABLE    tbl_fields [] = {/* address field names */
  105. /* REAL RFC 822 */
  106.     "Date",            FLD_DATE,
  107.     "To",            FLD_TO,
  108.     "CC",            FLD_CC,
  109.     "bcc",            FLD_BCC,
  110.     "From",            FLD_FROM,
  111.     "Sender",        FLD_SENDER,
  112.     "Reply-to",        FLD_REPLY_TO,
  113.     "Resent-From",        FLD_RESENT_FROM,
  114.     "Resent-Sender",    FLD_RESENT_SENDER,
  115.     "Resent-To",        FLD_RESENT_TO,
  116.     "Resent-Cc",        FLD_RESENT_CC,
  117.     "Resent-Bcc",        FLD_RESENT_BCC,
  118.     "Resent-By",        FLD_RESENT_BY,
  119. /* JNT stuff */
  120.     "Original-Sender",    FLD_ORIG_SENDER,
  121.     "Acknowledge-To",    FLD_JNT_ACK,
  122. /* RFC 733 & other misc stuff */
  123.     "Remailed-From",    FLD_REMAILED_FROM,
  124.     "Remailed-To",        FLD_REMAILED_TO,
  125.     "Remailed-By",        FLD_REMAILED_BY,
  126.     "Redistributed-From",    FLD_REDISTRIBUTED_FROM,
  127.     "Redistributed-To",    FLD_REDISTRIBUTED_TO,
  128.     "Redistributed-By",    FLD_REDISTRIBUTED_BY,
  129.     "Errors-To",        FLD_ERRORS_TO,
  130. /* RFC 987 fields */
  131.     "P1-Recipient",        FLD_RFC987,
  132. /* RFC 987 (88) fields */
  133.     "X400-Originator",            FLD_RFC987_88,
  134.     "X400-Recipients",            FLD_RFC987_88,
  135.     "Notification-IPM-Originator",        FLD_RFC987_88,
  136.     "Notification-Preferred-Recipients",    FLD_RFC987_88,
  137.     "MTS-Originator",            FLD_RFC987_88,
  138.     "MTS-Recipient",            FLD_RFC987_88,
  139.     "Originally-Intended-Recipient",    FLD_RFC987_88,
  140.     "Originator-Return-Address",        FLD_RFC987_88,
  141.     "Report-Reporting-DL-Name",        FLD_RFC987_88,
  142.     "Report-Originator-and-DL-Expansion-History",
  143.                         FLD_RFC987_88,
  144.     0,            -1
  145.     };
  146.  
  147. #define FOLD_SPACE    0
  148. #define FOLD_COMMA    1
  149. #define FOLD_SEMICOLON    2
  150. #define    FOLD_RECIEVED    3
  151. #define FOLD_NONE    4
  152.  
  153. CMD_TABLE    tbl_nonfields [] = {/* feilds dont deal with */
  154.     "Received",        FOLD_RECIEVED,
  155.     "X400-Received",    FOLD_SEMICOLON,
  156.     "Via",            FOLD_SEMICOLON,
  157.     "References",        FOLD_COMMA,
  158.     "Keywords",        FOLD_COMMA,
  159.     "X400-MTS-Identifier",    FOLD_NONE,
  160.     "Message-ID",        FOLD_NONE,
  161.     "In-Reply-To",        FOLD_NONE,
  162.     "Obsoletes",        FOLD_COMMA,
  163.     0,            -1
  164.     };
  165.  
  166. #define TRACE_RECIEVED    1
  167. #define TRACE_VIA    2
  168. #define TRACE_X400    3
  169.  
  170. CMD_TABLE    tbl_tracefields [] = {/* fields viable for strip trace */
  171.     "Received",        TRACE_RECIEVED,
  172.     "Via",            TRACE_VIA,
  173.     "X400-Received",    TRACE_X400,
  174.     0,            -1
  175. };
  176.  
  177. typedef struct dom_pair {
  178.     AP_ptr    from;
  179.     AP_ptr    to;
  180. } DomPair;
  181.  
  182. typedef enum {maj_none, rfc822, rfc733, jnt} Major_options;
  183. typedef enum {min_none, bigend, littleend} Minor_options;
  184.  
  185. extern void sys_init(), err_abrt();
  186. static void norm_sender();
  187. static int equalWithJntsender();
  188. #ifdef VAT
  189. static int tidy_up();
  190. #endif
  191. static getitm(), out_adr();
  192.  
  193. char        *myname;
  194. int        nadrs;
  195. int        pcol;
  196. int        nonempty;
  197. int        fold_width;
  198. int        order_pref, percents;
  199. int        normalised = APARSE_NORM_NONE;
  200. int        striptrace = FALSE,
  201.         striproutes = FALSE,
  202.         stripacks = FALSE,
  203.         genacks = FALSE;
  204. char        **stripdomains = NULL;
  205. char        **hidedomains = NULL;
  206. struct dom_pair    *changedomains = NULL;
  207. int        num_domains = 0,
  208.         num_pairs = 0,
  209.         num_to_hide = 0,
  210.         message_id = 0,
  211.         acks = 0,
  212.         msgid_req = FALSE,
  213.         internal = FALSE;
  214. char        *jntsender = NULL,
  215.         *jntsendernorm = NULL;
  216. AP_ptr        jnttree, jntgroup, jntname, jntloc, jntdom, jntroute;
  217. static int    getach();
  218. static int    getbufchar();
  219. static char    *next_fold();
  220. static char    *fold_recieved();
  221. extern AP_ptr    ap_pinit();
  222. extern char    *compress();
  223. extern char    *rcmd_srch();
  224. extern int    ap_outtype;
  225. extern int    ap_perlev;
  226. extern char    *loc_dom_site,
  227.         *loc_dom_mta;
  228. char        *rloc_dom_site,
  229.         *rloc_dom_mta;
  230. static char    *reverse();
  231. #ifndef BSD42
  232. #define random rand
  233. #define srandom srand
  234. #endif
  235.  
  236. #define    DEFAULT_FOLD_WIDTH    79
  237.  
  238. static char    *fieldbuf = NULL,
  239.         *contbuf = NULL;
  240. static int    fieldsize = 0,
  241.         contsize = 0;
  242. static int    fieldlen = 0,
  243.         contlen = 0;
  244. static char    *contix = NULL;
  245.  
  246. static int    exorcise = FALSE;
  247. static Table    *exorciseTable;
  248. static char    *exorciseDomain;
  249.  
  250. /* ARGSUSED */
  251. main(argc,argv)
  252. int    argc;
  253. char    **argv;
  254. {
  255.     /* parse flags */
  256.     Major_options maj = maj_none;
  257.     Minor_options mino = min_none;
  258.  
  259.     myname = *argv++;
  260.     sys_init(myname);
  261.     or_myinit();
  262. /*    malloc_debug(2);*/
  263.     ap_outtype = AP_PARSE_822;
  264.     fold_width = DEFAULT_FOLD_WIDTH;
  265.     order_pref = CH_USA_PREF;
  266.     normalised = APARSE_NORM_NONE;
  267.     jntsendernorm = NULL;
  268.     percents = FALSE;
  269.     jntsender = NULL;
  270.     message_id = 0;
  271.     msgid_req = FALSE;
  272.     srandom(getpid());
  273.  
  274.     exorcise = FALSE;
  275.     exorciseDomain = strdup(loc_dom_site);
  276.     exorciseTable = tb_nm2struct ("domain");
  277.  
  278.     rloc_dom_site = reverse(loc_dom_site);
  279.     rloc_dom_mta = reverse(loc_dom_mta);
  280.     while (*argv != NULL) {
  281.         switch(cmd_srch(*argv,tbl_options)) {
  282.             case -1:
  283.             PP_LOG(LLOG_EXCEPTIONS,
  284.                    ("unknown option '%s'",*argv));
  285.             exit(1);
  286.             
  287.             case OPT_MSGID:
  288.             msgid_req = TRUE;
  289.             break;
  290.  
  291.             case OPT_PERCENT:
  292.             percents = TRUE;
  293.             ap_use_percent();
  294.             break;
  295.             
  296.             case OPT_FULL:
  297.             normalised = APARSE_NORM_ALL;
  298.             break;
  299.  
  300.             case OPT_FOLD:
  301.             if (*(argv+1) == NULL)
  302.                 PP_LOG(LLOG_EXCEPTIONS,
  303.                        ("no fold width given with %s",*argv));
  304.             else {
  305.                 ++argv;
  306.                 fold_width = atoi(*argv);
  307.             }
  308.             break;
  309.  
  310.             case OPT_822:
  311.             if ((maj == maj_none) || (maj == rfc822)) {
  312.                 ap_outtype &= AP_TYPE_MASK;
  313.                 ap_outtype |= AP_PARSE_822;
  314.                 maj = rfc822;
  315.             }
  316.             break;
  317.  
  318.             case OPT_733:
  319.             if ((maj == maj_none) || (maj == rfc733)) {
  320.                 ap_outtype &= AP_TYPE_MASK;
  321.                 ap_outtype |= AP_PARSE_733;
  322.                 maj = rfc733;
  323.             } 
  324.             break;
  325.  
  326.             case OPT_JNT:
  327.             if ((maj == maj_none || maj == jnt)
  328.                 && (mino == min_none || mino == bigend)) {
  329.                 ap_outtype &= AP_TYPE_MASK;
  330.                 ap_outtype |= AP_PARSE_733;
  331.                 maj = jnt;
  332.                 ap_outtype |= AP_PARSE_BIG;
  333.                 mino = bigend;
  334.                 order_pref = CH_UK_PREF;
  335.                 break;
  336.             }
  337.             PP_LOG(LLOG_EXCEPTIONS,
  338.                    ("multiple major parse options"));
  339.             exit(1);
  340.  
  341.             case OPT_BIGEND:
  342.             if (mino == min_none || mino == bigend) {
  343.                 ap_outtype |= AP_PARSE_BIG;
  344.                 mino = bigend;
  345.                 order_pref = CH_UK_PREF;
  346.             }
  347.             break;
  348.  
  349.             case OPT_LITTLEEND:
  350.             if (mino == min_none || mino == littleend) {
  351.                 mino = littleend;
  352.                 break;
  353.             }
  354.             PP_LOG(LLOG_EXCEPTIONS,
  355.                    ("multiple minor parse options"));
  356.             exit(1);
  357.  
  358.             case OPT_STRIPTRACE:
  359.             striptrace = TRUE;
  360.             break;
  361.  
  362.             case OPT_STRIPROUTES:
  363.             striproutes = TRUE;
  364.             break;
  365.  
  366.             case OPT_STRIPDOMAIN:
  367.             if (*(argv+1) == NULL)
  368.                 PP_LOG(LLOG_EXCEPTIONS,
  369.                        ("no domain specified with %s", *argv));
  370.             else {
  371.                 ++argv;
  372.                 if (num_domains == 0)
  373.                     stripdomains = (char **) calloc(1, 
  374.                         (unsigned int) sizeof(char *));
  375.                 else
  376.                     stripdomains = (char **) realloc((char *) stripdomains,
  377.                                      (unsigned int) ((num_domains + 1) * sizeof(char *)));
  378.                 stripdomains[num_domains++] = *argv;
  379.             }
  380.             break;
  381.  
  382.             case OPT_CHANGEDOMAIN:
  383.             if (*(argv+1) == NULL
  384.                 || *(argv+2) == NULL)
  385.                 PP_LOG(LLOG_EXCEPTIONS,
  386.                        ("no domain pair specified with %s",
  387.                     *argv));
  388.             else {
  389.                 if (num_pairs == 0)
  390.                     changedomains = (struct dom_pair *)
  391.                         calloc (1, 
  392.                             (unsigned int) sizeof(struct dom_pair));
  393.                 else
  394.                     changedomains = (struct dom_pair *)
  395.                         realloc ((char *) changedomains,
  396.                              (unsigned int) ((num_pairs + 1) * sizeof (char *)));
  397.                 argv++;
  398.                 changedomains[num_pairs].from = ap_new(AP_DOMAIN,
  399.                                        *argv++);
  400.                 changedomains[num_pairs++].to = ap_new(AP_DOMAIN,
  401.                                        *argv);
  402.             }
  403.             break;
  404.                 
  405.             case OPT_JNTSENDER:
  406.             if (*(argv+1) == NULL)
  407.                 PP_LOG(LLOG_EXCEPTIONS,
  408.                        ("no sender specified with %s", *argv));
  409.             else {
  410.                 argv++;
  411.                 jntsender = *argv;
  412.             }
  413.             break;
  414.  
  415.             case OPT_STRIPACK:
  416.             stripacks = TRUE;
  417.             break;
  418.  
  419.             case OPT_GENACK:
  420.             if (*(argv+1) == NULL)
  421.                 PP_LOG(LLOG_EXCEPTIONS,
  422.                        ("no flag specified with %s", *argv));
  423.             else {
  424.                 argv++;
  425.                 if (lexequ(*argv, "yes") == 0)
  426.                     genacks = TRUE;
  427.             }
  428.             break;
  429.  
  430.             case OPT_HIDELOCAL:
  431.             if (*(argv+1) == NULL)
  432.                 PP_LOG(LLOG_EXCEPTIONS,
  433.                        ("no domain specified with %s", *argv));
  434.             else {
  435.                 ++argv;
  436.                 if (num_to_hide == 0)
  437.                     hidedomains = (char **) calloc(1, 
  438.                         (unsigned int) sizeof(char *));
  439.                 else
  440.                     hidedomains = (char **) realloc((char *) hidedomains,
  441.                                      (unsigned int) ((num_to_hide + 1) * sizeof(char *)));
  442.                 hidedomains[num_to_hide++] = *argv;
  443.             }
  444.             break;
  445.  
  446.             case OPT_EXORCISE:
  447.             exorcise = TRUE;
  448.             break;
  449.  
  450.             case OPT_EXORDOM:
  451.             if (*(argv+1) == NULL) {
  452.                 PP_LOG(LLOG_EXCEPTIONS,
  453.                        ("no domain given with %s", *argv));
  454.                 exit(1);
  455.             }        
  456.             ++argv;
  457.             free(exorciseDomain);
  458.             exorciseDomain = strdup(*argv);
  459.             exorcise = TRUE;
  460.             break;
  461.  
  462.             case OPT_VALDOM:
  463.             if (*(argv+1) == NULL) {
  464.                 PP_LOG(LLOG_EXCEPTIONS,
  465.                        ("no table given with %s", *argv));
  466.                 exit(1);
  467.             } else if ((exorciseTable = tb_nm2struct(*(argv+1))) == NULLTBL) {
  468.                 PP_LOG(LLOG_EXCEPTIONS,
  469.                        ("unknown table %s given with %s",
  470.                     *(argv+1), *argv));
  471.                 exit(1);
  472.             }
  473.             ++argv;
  474.             exorcise = TRUE;
  475.             break;
  476.  
  477.             case OPT_EXTERNAL:
  478.             internal = FALSE;
  479.             break;
  480.             
  481.             case OPT_INTERNAL:
  482.             internal = TRUE;
  483.             break;
  484.  
  485.             default:
  486.             PP_LOG(LLOG_EXCEPTIONS,
  487.                    ("unknown option '%s'"));
  488.             exit(1);
  489.         }
  490.         argv++;
  491.     }
  492.  
  493.     if (genacks == TRUE && !jntsender)
  494.         PP_LOG(LLOG_EXCEPTIONS,
  495.                ("Acknowledge-To required but no sender specified"));
  496.     if (jntsender)
  497.         norm_sender();
  498.     /* ap_outtype set so now process */
  499.     if (proc() != OK)
  500.         err_abrt( RP_LIO, "couldn't reformat it");
  501.     free(rloc_dom_site);
  502.     free(rloc_dom_mta);
  503.     /* copy out rest of file */
  504.     exit(0);
  505. }
  506.  
  507. /*   */
  508.  
  509. static void    norm_sender()
  510. {
  511.     Aparse_ptr    aparse = aparse_new();
  512.     aparse -> r822_str = strdup(jntsender);
  513.     aparse -> ad_type = AD_822_TYPE;
  514.     aparse -> dmnorder = order_pref;
  515.     aparse -> normalised = normalised;
  516.     aparse -> percents = percents;
  517.     aparse -> internal = internal;
  518.  
  519.     if (aparse_norm(aparse) == NOTOK) {
  520.         jnttree = ap_s2t(jntsender);
  521.  
  522.         jnttree = ap_t2p (jnttree, &jntgroup, &jntname,
  523.                   &jntloc, &jntdom, &jntroute);
  524.     } else {
  525.         jnttree = aparse->ap_tree;
  526.         jntgroup = aparse->ap_group;
  527.         jntname = aparse->ap_name;
  528.         jntloc = aparse->ap_local;
  529.         jntdom = aparse->ap_domain;
  530.         jntroute = aparse->ap_route;
  531.         aparse -> ap_tree = NULLAP;
  532.     }
  533.     aparse_free(aparse);
  534.     free ((char *) aparse);
  535.     jntsendernorm = ap_p2s(jntgroup, jntname, jntloc, jntdom, jntroute);
  536. }
  537.  
  538. static int equalWithJntsender(tree)
  539. AP_ptr    tree;
  540. {
  541.     AP_ptr    jix = tree, aix = jntloc;
  542.  
  543.     while (jix != NULLAP && 
  544.            aix != NULLAP &&
  545.            aix -> ap_obvalue != NULLCP &&
  546.            jix -> ap_obvalue != NULLCP) {
  547.         if (jix -> ap_obtype == AP_COMMENT)
  548.             jix = jix -> ap_next;
  549.         else if (aix -> ap_obtype == AP_COMMENT)
  550.             aix = aix -> ap_next;
  551.         else if (strcmp(aix -> ap_obvalue, jix -> ap_obvalue) != 0)
  552.             return 0;
  553.         else {
  554.             aix = aix -> ap_next;
  555.             jix = jix -> ap_next;
  556.         }
  557.     }
  558.     while (jix != NULLAP && jix->ap_obvalue == NULLCP)
  559.         jix = jix -> ap_next;
  560.  
  561.     while (aix != NULLAP && aix->ap_obvalue == NULLCP)
  562.         aix = aix -> ap_next;
  563.  
  564.     if (aix == NULLAP && jix == NULLAP)
  565.         return 1;
  566.     return 0;
  567. }
  568.  
  569. /*   */
  570.  
  571. int    noFrom, from, gotDate;
  572.  
  573. /* 822norm stdin to stdout */
  574. proc ()
  575. {
  576.     int    amp_fail;
  577.     int    res;
  578.     int    done;
  579.     register char    *cp;
  580.     PP_TRACE(("outtype %o",ap_outtype));
  581.     noFrom = 1;
  582.     gotDate = 0;
  583.     from = 0;
  584.     while ((getitm(&res) == OK) && (res == OK)) {
  585.  
  586.         ap_clear();
  587.         nadrs = 0;
  588.         amp_fail = FALSE;
  589.         nonempty = FALSE;
  590.         done = FALSE;
  591.  
  592.         if (ap_pinit(getbufchar) == BADAP) {
  593.             PP_LOG(LLOG_EXCEPTIONS,
  594.                    ("problem parsing message"));
  595.             return NOTOK;
  596.         }
  597.             
  598.         while (done == FALSE) {
  599.             res = ap_1adr();    /* Parse one adr */
  600.             switch(res) {
  601.                 case DONE:    /* done */
  602.                 done = TRUE;
  603.                 break;
  604.                 case NOTOK:
  605.                 /* pass the garbage and generate warning */
  606.                 amp_fail = TRUE;
  607.                 break;
  608.                 default:    /* print it */
  609.                 ap_ppush (getbufchar);
  610.                 if ((res = out_adr(ap_pstrt)) != OK) 
  611.                     return res;
  612.                 ap_ppop();
  613.                 ap_pstrt = ap_pcur = ap_alloc ();
  614.                 break;
  615.             }
  616.         }
  617.         putchar('\n');
  618.         if (ap_perlev) {    /* if still nested */
  619.             PP_TRACE(("nested level %d",ap_perlev));
  620.             amp_fail++;
  621.         }
  622.         if (amp_fail == TRUE) {
  623.             char    *fold, *ix;
  624.             int    nonempty = FALSE;
  625.             printf("PP-Warning: Parse error in original version of preceding line\n");
  626.             printf("Original-%s: ", fieldbuf);
  627.             ix = &(contbuf[0]);
  628.             while (*ix != '\0') {
  629.                 fold = next_fold(ix+1, FOLD_COMMA);
  630.                 if ((fold_width != -1)
  631.                     && (fold - ix + pcol > fold_width)
  632.                     && nonempty == TRUE) {
  633.                     /* fold */
  634.                     pcol = strlen(fieldbuf) + strlen("Original-: ");
  635.                     printf("\n%*s",
  636.                            strlen(fieldbuf) + strlen("Original-: "),
  637.                            "");
  638.                     while (isspace(*ix))
  639.                         ix++;
  640.                 } else
  641.                     nonempty = TRUE;
  642.                 pcol += fold - ix;
  643.                 while (ix != fold)
  644.                     putchar (*ix++);
  645.             }
  646.             putchar('\n');                
  647.         }
  648.     }
  649.  
  650.     if (gotDate == 0) {
  651.         /* no date so add one */
  652.         UTC    ut;
  653.         char    buf[BUFSIZ], *cp;
  654.         strcpy (buf, "Date");
  655.         cp = &buf[0];
  656.         while (*cp != '\0')
  657.             putchar (*cp++);
  658.         putchar (':');
  659.         putchar (' ');
  660.  
  661.         ut = utcnow();
  662.         UTC2rfc(ut, buf);
  663.  
  664.         cp = &buf[0];
  665.         while (*cp != '\0')
  666.             putchar (*cp++);
  667.         putchar('\n');
  668.     }
  669.  
  670.     if (message_id == 0 && msgid_req == TRUE) {
  671.         /* output message id */
  672.         MPDUid    msgid;
  673.         char    buf[BUFSIZ];
  674.         strcpy(buf, "Message-ID");
  675.         cp = &buf[0];
  676.         while (*cp != '\0')
  677.             putchar (*cp++);
  678.         putchar (':');
  679.         putchar (' ');
  680.  
  681.         MPDUid_new(&msgid);
  682.         (void) sprintf(buf, "<\"%s\"@%s>", 
  683.                    msgid.mpduid_string, loc_dom_site);
  684.         cp = buf;
  685.         while (*cp != '\0')
  686.             putchar (*cp++);
  687.         putchar ('\n');
  688.     }
  689.     if (jntsendernorm != NULL) {
  690.         if (genacks == TRUE && acks == 0) {
  691.             /* output Acknowledge-To field */
  692.             cp = rcmd_srch(FLD_JNT_ACK, tbl_fields);
  693.             while (*cp != '\0')
  694.                 putchar (*cp++);
  695.             putchar(':');
  696.             putchar(' ');
  697.             cp = jntsendernorm;
  698.             while (*cp != '\0')
  699.                 putchar(*cp++);
  700.             putchar('\n');
  701.         }
  702.  
  703.         if (noFrom) {
  704.             /* output Sender */
  705.             cp = rcmd_srch(FLD_SENDER, tbl_fields);
  706.             while (*cp != '\0')
  707.                 putchar(*cp++);
  708.             putchar(':');
  709.             putchar(' ');
  710.  
  711.             cp = jntsendernorm;
  712.             while (*cp != '\0')
  713.                 putchar(*cp++);
  714.             putchar('\n');
  715.         }
  716.  
  717.         ap_sqdelete(jnttree, NULLAP);
  718.         free((char *)jnttree);
  719.     }
  720.     if (res == NOTOK) 
  721.         return NOTOK;
  722.     
  723. #ifdef VAT
  724.     tidy_up();
  725. #endif
  726.  
  727.     return (ferror(stdout) ? NOTOK : OK);
  728. }
  729.  
  730. /*   */
  731. /* input routines */
  732.  
  733. #define    INC    2
  734.  
  735. /* returns current pointer = *orig + olength */
  736. static char    *resize_buf(orig, olength, size)
  737. char    **orig;
  738. int    olength,
  739.     *size;
  740. {
  741.  
  742.     *size += INC;
  743.     if (*orig == NULLCP)
  744.         *orig = calloc (1, (unsigned int) (*size));
  745.     else
  746.         *orig = realloc (*orig, (unsigned int) (*size));
  747.     return ((*orig)+olength);
  748. }
  749.  
  750. /* returns OK while still got more input to read */
  751. /* result == NOTOK if failed parsing */
  752. static int getitm(result)
  753. int     *result;
  754. {
  755.     register int    c;
  756.     register char    *cp,
  757.             *ix;
  758.     int        gotitm = FALSE;
  759.     int        fld;
  760.  
  761.     fieldlen = 0;
  762.     cp = fieldbuf;
  763.     *result = OK;
  764.  
  765.     while (gotitm == FALSE) {
  766.         if ((c = getach()) == EOF) 
  767.             /* end of file */
  768.             return NOTOK;
  769.         
  770.         switch (c) {
  771.             case '\n':
  772.             if (fieldlen != 0)
  773.                 break;
  774.             case '\0':
  775.             /* end of input */
  776.             return NOTOK;
  777.         }
  778.         
  779.         switch (c) {
  780.             case ':':
  781.             /* Field name collected */
  782.             if ((fieldlen+1) >= fieldsize) 
  783.                 cp = resize_buf(&fieldbuf,fieldlen,&fieldsize);
  784.             *cp = '\0';
  785.             PP_TRACE(("field '%s'",fieldbuf));
  786.             ix = fieldbuf;
  787.             if (isspace(*ix) && *ix != '\n') {
  788.                 while (isspace(*ix) && *ix != '\n')
  789.                     ix++;
  790.                 /* rewind back one to first nonspace */
  791.                 ix--;
  792.             }
  793.  
  794.             /* got field now get contents */
  795.             cp = contbuf;
  796.             contlen = 0;
  797.  
  798.             while (((c = getach()) != 0) && (c != EOF)) {
  799.                 if (++contlen >= contsize) 
  800.                     cp = resize_buf(&contbuf,(contlen-1),&contsize);
  801.                 *cp++ = c;
  802.             }
  803.                 
  804.             /* terminate with a null char */
  805.             if ((contlen + 1) >= contsize) 
  806.                 cp = resize_buf(&contbuf,contlen,&contsize);
  807.             *cp ='\0';
  808.             compress(fieldbuf, fieldbuf);
  809.             compress(contbuf, contbuf);
  810.             contix = contbuf;
  811.  
  812.             fld = cmd_srch(ix, tbl_tracefields);
  813.  
  814.             /* check if need to skip */
  815.             if (striptrace == TRUE
  816.                 && fld != -1) {
  817.                 /* skip it */
  818.                 cp = fieldbuf;
  819.                 fieldlen = 0;
  820.                 break;
  821.             } 
  822.             
  823.             if (fld != -1
  824.                 && valid_trace(fld, fieldbuf, contbuf) != OK) {
  825.                 /* already output with error */
  826.                 cp = fieldbuf;
  827.                 fieldlen = 0;
  828.                 break;
  829.             }
  830.  
  831.             fld = cmd_srch(ix, tbl_fields);
  832.  
  833.             if (fld == FLD_JNT_ACK) {
  834.                 if (stripacks == TRUE) {
  835.                     /* skip it */
  836.                     cp = fieldbuf;
  837.                     fieldlen = 0;
  838.                     break;
  839.                 } else
  840.                     acks++;
  841.             }
  842.                    
  843.             if (fld == FLD_FROM)
  844.                 from = 1;
  845.             else
  846.                 from = 0;
  847.  
  848.             if (jntsender != NULL
  849.                 && (fld == FLD_SENDER))
  850.                 /* convert to Original-Sender */
  851.                 cp = rcmd_srch(FLD_ORIG_SENDER, tbl_fields);
  852.             else 
  853.                 cp = fieldbuf;
  854.  
  855.             if (fld == FLD_DATE)
  856.                 gotDate++;
  857.  
  858.             pcol = strlen(cp)+2;
  859.             while (*cp != '\0')
  860.                 putchar(*cp++);
  861.             putchar(':');
  862.             /* put in jpo's space */
  863.             putchar(' ');
  864.  
  865.             if (fld != -1 && fld != FLD_DATE) {
  866.                 gotitm = TRUE;
  867.  
  868.             } else {
  869.                 int    fold_num;
  870.                 /* copy rest of line out */
  871.                 nonempty = FALSE;
  872.                 pcol = strlen(fieldbuf) + 1;
  873.                 cp = contix;
  874.                 if (lexequ(fieldbuf, "Message-ID") == 0)
  875.                     message_id++;
  876.                     
  877.                 if ((fold_num = cmd_srch(fieldbuf,tbl_nonfields)) == -1) {
  878.                     PP_DBG(("unknown non field %s folding on spaces",fieldbuf));
  879.                     fold_num = FOLD_SPACE;
  880.                 }
  881.                 while (*contix != '\0') {
  882.                     /* go to next fold */
  883.                     cp = next_fold(contix+1,fold_num);
  884.                     
  885.                     if ((fold_width != -1)
  886.                         && (cp - contix + pcol > fold_width) 
  887.                         && nonempty) {
  888.                         /* new line */
  889.                         pcol = strlen(fieldbuf) + 2;
  890.                         printf("\n%*s", strlen(fieldbuf) + 2, "");
  891.                         /* strip out white space */
  892.                         while (isspace(*contix))
  893.                             contix++;
  894.                     } else
  895.                         nonempty = TRUE;
  896.                     pcol += cp - contix;
  897.                     /* output line */
  898.                     while (contix != cp)
  899.                         putchar(*contix++);
  900.                 }
  901.                 putchar('\n');                
  902.                 if (c == EOF)
  903.                     /* EOF */
  904.                     return NOTOK;
  905.             }
  906.             cp = fieldbuf;
  907.             fieldlen = 0;
  908.             break;
  909.  
  910.             default:
  911.             if (++fieldlen >= fieldsize) 
  912.                 cp = resize_buf(&fieldbuf,(fieldlen-1),&fieldsize);
  913.             *cp++ = c;
  914.         }
  915.     }
  916.     return OK;
  917. }
  918.  
  919. static int isblank(ch)
  920. char    ch;
  921. {
  922.     return (ch == ' ' || ch == '\t');
  923. }
  924.  
  925. /* returns 0 when reach end of an item */
  926. /* returns EOF when reach EOF */
  927. static int    getach()
  928. {
  929.     static unsigned char    buf[MAXPATHLENGTH];
  930.     static unsigned char    *bufp = buf;
  931.     static int    noInput = 0;
  932.     
  933.     if (noInput == 0) { /* buffer is empty */
  934.         noInput = read(0, buf, MAXPATHLENGTH);
  935.         bufp = buf;
  936.     }
  937.  
  938.     if (*bufp == '\n') {
  939.         if (noInput == 1) {
  940.             /* last char in buffer */
  941.             noInput = read(0, buf, MAXPATHLENGTH);
  942.             bufp = buf;
  943.             if (isblank(*bufp)) {
  944.                 noInput--;
  945.                 return *bufp++;
  946.             } else
  947.                 return 0;
  948.         } else if (isblank(*(bufp+1))) {
  949.             /* skip newline */
  950.             bufp++;
  951.             noInput--;
  952.         }
  953.     }
  954.     if (*bufp == '\n') {
  955.         bufp++;
  956.         noInput--;
  957.         return 0;
  958.     }
  959.     return ((--noInput >= 0) ? *bufp++ : EOF);
  960. }
  961.  
  962. static int    getbufchar()
  963. {
  964.     char    ret = *contix;
  965.     if (ret != 0) contix++;
  966.     return (ret == 0) ? EOF : ret;
  967. }
  968.  
  969. /*   */
  970. /* output routine */
  971.  
  972. static char    *next_fold(ix,fold)
  973. char    *ix;
  974. int    fold;
  975. {
  976.     char       fold_ch;
  977.  
  978.     switch (fold) {
  979.         case FOLD_NONE:
  980.         fold_ch = '\0';
  981.         break;
  982.         case FOLD_SPACE:
  983.         fold_ch = ' ';
  984.         break;
  985.         case FOLD_COMMA:
  986.         fold_ch = ',';
  987.         break;
  988.         case FOLD_SEMICOLON:
  989.         fold_ch = ';';
  990.         break;
  991.         case FOLD_RECIEVED:
  992.         return  fold_recieved(ix);
  993.         default:
  994.         PP_LOG(LLOG_EXCEPTIONS,
  995.                ("unknown fold number %d",fold));
  996.         fold_ch = ' ';
  997.     }
  998.  
  999.     while (*ix != '\0' && *ix != fold_ch)
  1000.         ix++;
  1001.     if (*ix == '\0')
  1002.         return ix;
  1003.     else
  1004.         return ++ix;
  1005. }
  1006.  
  1007. static char    *fold_recieved(chs)
  1008. char    *chs;
  1009. {
  1010.     char    *ix;
  1011.     while (*chs != '\0' && *chs != ';' && *chs != ' ')
  1012.         chs++;
  1013.     if (*chs == '\0')
  1014.         return chs;
  1015.     if (*chs == ';')
  1016.         return ++chs;
  1017.     /* skip leading spaces */
  1018.     while (isspace(*chs))
  1019.         chs++;
  1020.  
  1021.     /* now check if have key words */
  1022.     ix = chs;
  1023.     while (*ix != '\0' &&
  1024.            (ix - chs <= (int)strlen("from")+1)) {
  1025.         
  1026.         if (ix - chs == 3) {
  1027.             if (strncmp(chs,"by ",3) == 0)
  1028.                 return chs;
  1029.             else if (strncmp(chs,"id ",3) == 0)
  1030.                 return chs;
  1031.         }
  1032.         
  1033.         if (ix - chs == 4) {
  1034.             if (strncmp(chs,"via ",4) == 0)
  1035.                 return chs;
  1036.             else if (strncmp(chs,"for ",4) == 0)
  1037.                 return chs;
  1038.         }
  1039.         
  1040.         if (ix - chs == 5) {
  1041.             if (strncmp(chs,"from ",5) == 0)
  1042.                 return chs;
  1043.             else if (strncmp(chs, "with ", 5) == 0)
  1044.                 return chs;
  1045.                 
  1046.         }
  1047.         ix++;
  1048.     }
  1049.     if (*ix == '\0')
  1050.         return ix;
  1051.     return fold_recieved(chs);
  1052. }
  1053.  
  1054. static int specifiedDomain(ptr)
  1055. AP_ptr    ptr;
  1056. {
  1057.     int    specified = FALSE,
  1058.         i = 0;
  1059.  
  1060.     if (ptr->ap_obtype != AP_DOMAIN
  1061.         && ptr -> ap_obtype != AP_DOMAIN_LITERAL)
  1062.         return FALSE;
  1063.  
  1064.     while (specified != TRUE && i < num_domains) {
  1065.         if ((ptr->ap_obvalue != NULL)
  1066.             && (strcmp(stripdomains[i], ptr->ap_obvalue) == 0))
  1067.             specified = TRUE;
  1068.         i++;
  1069.     }
  1070.     return specified;
  1071. }
  1072.  
  1073.  
  1074. static int hiddenDomain(ptr)
  1075. AP_ptr    ptr;
  1076. {
  1077.     int    hidden = FALSE,
  1078.         i, nwild, nw;
  1079.     char   *bp, *cp;
  1080.  
  1081.     /* get to next domain */
  1082.     while ((ptr != NULL) && (ptr->ap_obtype != AP_DOMAIN))
  1083.         ptr = ptr->ap_next;
  1084.     if (ptr == NULL)
  1085.         return 0;
  1086.  
  1087.     if (ptr->ap_obvalue != NULL)
  1088.         for (i = 0; hidden != TRUE && i < num_to_hide; i++) {
  1089.             for (nwild = 0; hidedomains[i][nwild] == '.' ||
  1090.                 hidedomains[i][nwild] == '*'; nwild ++)
  1091.                 continue;
  1092.             nw = nwild;
  1093.             nwild /= 2;
  1094.             bp = cp = ptr->ap_obvalue;
  1095.             if ( ! hidedomains[i][nw] ) {
  1096.                 PP_LOG (LLOG_EXCEPTIONS,
  1097.                     ("Format/rfc822norm/hiddenDomain: Too wild - Reality error"));
  1098.                 continue;
  1099.             }
  1100.  
  1101.             while ( (nwild -- > 0) && (bp = index(bp, '.')) != NULL)
  1102.                 bp ++;
  1103.             if ( !bp )
  1104.                 continue;
  1105.             while ((bp = index(bp,'.')) != NULL) {
  1106.                 if (++bp =='\0')
  1107.                     break;
  1108.                 cp = index(cp,'.'); 
  1109.                 cp++;
  1110.                 if ((strcmp(&hidedomains[i][nw], bp) == 0)) {
  1111.                     hidden = TRUE;
  1112.                     strcpy(ptr->ap_obvalue, cp);
  1113.                     break;
  1114.                 }
  1115.             }
  1116.         }
  1117.     return hidden;
  1118. }
  1119.  
  1120. static int recognisedDomain(ptr)
  1121. AP_ptr    ptr;
  1122. {
  1123.     if (ptr->ap_obtype != AP_DOMAIN
  1124.         && ptr->ap_obtype != AP_DOMAIN_LITERAL)
  1125.         return FALSE;
  1126.     if (ptr->ap_normalised != TRUE)
  1127.         rfc822_norm_dmn(ptr, order_pref);
  1128.     return ptr->ap_recognised;
  1129. }
  1130.  
  1131. static void changedomain (dom)
  1132. AP_ptr     dom;
  1133. {
  1134.     int    i;
  1135.     for (i = 0; i < num_pairs; i++) {
  1136.         if (changedomains[i].from->ap_normalised != TRUE)
  1137.             rfc822_norm_dmn(changedomains[i].from,
  1138.                     order_pref);
  1139.         if (lexequ(changedomains[i].from->ap_obvalue, 
  1140.                dom->ap_obvalue) == 0)
  1141.             break;
  1142.     }
  1143.     if (i < num_pairs) {
  1144.         if (dom->ap_obvalue)
  1145.             free(dom->ap_obvalue);
  1146.         if (changedomains[i].to->ap_normalised != TRUE)
  1147.             rfc822_norm_dmn(changedomains[i].to,
  1148.                     order_pref);
  1149.         dom->ap_obvalue = strdup(changedomains[i].to->ap_obvalue);
  1150.         if (dom->ap_normalised == TRUE) {
  1151.             if (dom->ap_localhub) {
  1152.                 free (dom->ap_localhub);
  1153.                 dom->ap_localhub = NULLCP;
  1154.             }
  1155.             if (dom->ap_chankey) {
  1156.                 free (dom->ap_chankey);
  1157.                 dom->ap_chankey = NULLCP;
  1158.             }
  1159.             if (dom->ap_error) {
  1160.                 free (dom->ap_error);
  1161.                 dom->ap_error = NULLCP;
  1162.             }
  1163.         }
  1164.     }
  1165. }
  1166.  
  1167. static void do_changedomains (tree)
  1168. AP_ptr    tree;
  1169. {
  1170.     while (tree != NULLAP) {
  1171.         if (tree -> ap_obtype == AP_DOMAIN
  1172.             || tree -> ap_obtype == AP_DOMAIN_LITERAL)
  1173.             changedomain(tree);
  1174.         tree = tree->ap_next;
  1175.     }
  1176. }
  1177.  
  1178. static void    do_stripdomains(pap, pgroup, pname, ploc, 
  1179.                 pdom, proute)
  1180. AP_ptr  *pap,
  1181.     *pgroup,
  1182.     *pname,
  1183.     *ploc,
  1184.     *pdom,
  1185.     *proute;
  1186. {
  1187.     AP_ptr    ix, hdr;
  1188.     int    cont = TRUE;
  1189.  
  1190.     if (*proute != NULLAP) {
  1191.         /* go down tree removing specified domains */
  1192.         hdr = ap_new(AP_DOMAIN, "header");
  1193.         hdr->ap_next = *pap;
  1194.         hdr->ap_ptrtype = AP_PTR_MORE;
  1195.         ix = hdr;
  1196.  
  1197.         while ((ix->ap_next != NULL)
  1198.                && cont == TRUE) {
  1199.             switch (ix -> ap_next -> ap_obtype) {
  1200.                 case AP_DOMAIN:
  1201.                 case AP_DOMAIN_LITERAL:
  1202.                 if (specifiedDomain (ix->ap_next) == TRUE) 
  1203.                     ap_delete (ix);
  1204.                 else
  1205.                     ix = ix -> ap_next;
  1206.                 break;
  1207.  
  1208.                 case AP_MAILBOX:
  1209.                 case AP_GENERIC_WORD:
  1210.                 /* don't remove dom so stop here */
  1211.                 cont = FALSE;
  1212.                 break;
  1213.                 
  1214.                 default:
  1215.                 ix = ix -> ap_next;
  1216.             }
  1217.         }
  1218.  
  1219.         /* reset all pointers */
  1220.         *pap = hdr->ap_next;
  1221.         hdr->ap_next = NULLAP;
  1222.         ap_free(hdr);
  1223.         (void) ap_t2p(*pap, pgroup, pname, ploc, pdom, proute);
  1224.     }
  1225. }
  1226.  
  1227. static void    do_striproutes(pap, pgroup, pname, ploc, 
  1228.                 pdom, proute)
  1229. AP_ptr  *pap,
  1230.     *pgroup,
  1231.     *pname,
  1232.     *ploc,
  1233.     *pdom,
  1234.     *proute;
  1235. {
  1236.     int    cont = TRUE;
  1237.     char    *tmp;
  1238.     AP_ptr    ix,
  1239.         hdr;
  1240.  
  1241.     if (recognisedDomain(*pdom) == TRUE) {
  1242.         /* recognised *pdom, remove all route */
  1243.         tmp = ap_p2s(*pgroup, *pname, *ploc, 
  1244.                 *pdom, NULLAP);
  1245.         ix = *pap;
  1246.         ap_s2p(tmp, pap, pgroup, pname, ploc, pdom, proute);
  1247.         ap_free(ix);
  1248.         free(tmp);
  1249.     } else {    
  1250.         /* go down tree removing recognised domains */
  1251.         hdr = ap_new(AP_DOMAIN, "header");
  1252.         hdr->ap_next = *pap;
  1253.         hdr->ap_ptrtype = AP_PTR_MORE;
  1254.         ix = hdr;
  1255.  
  1256.         while ((ix->ap_next != NULL)
  1257.                && cont == TRUE) {
  1258.             switch (ix -> ap_next -> ap_obtype) {
  1259.                 case AP_DOMAIN:
  1260.                 case AP_DOMAIN_LITERAL:
  1261.                 if (recognisedDomain (ix->ap_next) == TRUE) 
  1262.                     ap_delete (ix);
  1263.                 else
  1264.                     cont = FALSE;
  1265.                 break;
  1266.  
  1267.                 case AP_MAILBOX:
  1268.                 case AP_GENERIC_WORD:
  1269.                 cont = FALSE;
  1270.                 break;
  1271.                 
  1272.                 default:
  1273.                 ix = ix -> ap_next;
  1274.             }
  1275.         }
  1276.  
  1277.         /* reset all pointers */
  1278.         *pap = hdr->ap_next;
  1279.         hdr->ap_next = NULLAP;
  1280.         ap_free(hdr);
  1281.         (void) ap_t2p(*pap, pgroup, pname, ploc, pdom, proute);
  1282.     }
  1283. }
  1284.  
  1285. static 
  1286. do_hidedomains(dom_ptr, route_ptr)
  1287. AP_ptr  dom_ptr,
  1288. route_ptr;
  1289. {
  1290.     int    retval = 0;
  1291.     AP_ptr    ptr;
  1292.     if ((ptr = route_ptr) != NULLAP )
  1293.         while ( ptr ) {
  1294.             retval += hiddenDomain(ptr);
  1295.             ptr = ptr->ap_next;
  1296.         }
  1297.     return retval += hiddenDomain(dom_ptr);
  1298. }
  1299.  
  1300. #ifdef VAT
  1301. static int     tidy_up()
  1302. {
  1303.     if (random() % 10000 != 42)
  1304.         return;
  1305.     /* lucky person gets a message */
  1306.     switch (random() % 4) {
  1307.         case 0:
  1308.         printf ("Checked-by: NSA, MI5, CIA, KGB\n");
  1309.         break;
  1310.         case 1:
  1311.         printf ("Green-Message: This message is stored on recycled memory\n");
  1312.         break;
  1313.         case 2:
  1314.         printf ("Best-Wishes-From: Steve, Julian, Pete, Alina et al\n");
  1315.         break;
  1316.         default:
  1317.         printf ("Congratulations: You are the recipient of our %d message\n", random() % 1000000);
  1318.         break;
  1319.     }
  1320. }
  1321. #endif
  1322.  
  1323. static char *re_parse_ptr;
  1324. static int    get_rp_char()
  1325. {
  1326.     char    ret = *re_parse_ptr;
  1327.     if (ret != 0) re_parse_ptr++;
  1328.     return (ret == 0) ? EOF : ret;
  1329. }
  1330.  
  1331. /*   */
  1332.  
  1333. static int mustExorcise(domain)
  1334. char    *domain;
  1335. {
  1336.     int    retval = FALSE;
  1337.     char    chan[BUFSIZ], normalised[BUFSIZ];
  1338.     char    *subdom;
  1339.  
  1340.     if (exorciseTable == NULLTBL) {
  1341.         PP_LOG(LLOG_EXCEPTIONS,
  1342.                ("No table of valid addresses"));
  1343.         return FALSE;
  1344.     }
  1345.     if (tb_getdomain_table(exorciseTable, domain, chan, normalised, 
  1346.                    order_pref, &subdom) != OK)
  1347.         retval = TRUE;
  1348.     if (subdom) free(subdom);
  1349.     return retval;
  1350. }
  1351.  
  1352. AP_ptr    exorciseAp;
  1353.  
  1354. static void createExorciseAp ()
  1355. {    
  1356.     exorciseAp = ap_new(AP_DOMAIN, exorciseDomain);
  1357.     rfc822_norm_dmn (exorciseAp, order_pref);
  1358. }
  1359.  
  1360. static void do_exorcisedomain (pap, pgroup, pname, ploc,
  1361.                    pdom, proute)
  1362. AP_ptr    *pap, *pgroup, *pname, *ploc, *pdom, *proute;
  1363. {
  1364.     AP_ptr    ix;
  1365.     if (*proute != NULLAP) {
  1366.         for (ix = *proute;
  1367.              ix != NULLAP && 
  1368.              ix -> ap_obtype != AP_DOMAIN
  1369.              && ix -> ap_obtype != AP_DOMAIN_LITERAL;
  1370.              ix = ix -> ap_next);
  1371.         if (ix != NULLAP
  1372.             && mustExorcise(ix->ap_obvalue) == TRUE) {
  1373.             if (exorciseAp == NULLAP)
  1374.                 createExorciseAp();
  1375.             /* add exorciseAp immediately before ix */
  1376.             ap_insert(ix, AP_PTR_MORE,
  1377.                   ap_new(ix -> ap_obtype,
  1378.                      ix -> ap_obvalue));
  1379.             free(ix -> ap_obvalue);
  1380.             ap_fllnode(ix, exorciseAp -> ap_obtype,
  1381.                    exorciseAp -> ap_obvalue);
  1382.         }
  1383.     } else if (*pdom != NULLAP) {
  1384.         for (ix = *pdom;
  1385.              ix != NULLAP && 
  1386.              ix -> ap_obtype != AP_DOMAIN
  1387.              && ix -> ap_obtype != AP_DOMAIN_LITERAL;
  1388.              ix = ix -> ap_next);
  1389.         if (ix != NULLAP
  1390.             && mustExorcise (ix->ap_obvalue) == TRUE) {
  1391.             char    *addrp;
  1392.             if (exorciseAp == NULLAP)
  1393.                 createExorciseAp();
  1394.             /* add exorciseAp to route */
  1395.             addrp = ap_p2s(*pgroup, *pname, *ploc, 
  1396.                        *pdom, exorciseAp);
  1397.             ap_sqdelete (*pap, NULLAP);
  1398.             ap_free(*pap);
  1399.             ap_s2p(addrp, pap, pgroup, pname, ploc, pdom, proute);
  1400.             free(addrp);
  1401.         }
  1402.     }
  1403. }
  1404.  
  1405. /*   */
  1406. extern aliasList     *aliases;
  1407.  
  1408. static int    out_adr(ap)
  1409. AP_ptr    ap;
  1410. {
  1411.     AP_ptr  loc_ptr,        /* -- in case fake personal name needed -- */
  1412.     group_ptr,
  1413.     name_ptr,
  1414.     dom_ptr,
  1415.     route_ptr, tmp;
  1416.     char    *addrp;
  1417.     int    len;
  1418.     static  rd = 0;
  1419.     Aparse_ptr    aparse = aparse_new();
  1420.  
  1421.     if (ap->ap_obtype == AP_NIL)
  1422.         return OK;
  1423.  
  1424.     rd++;
  1425.     
  1426.     aparse -> ad_type = AD_822_TYPE;
  1427.     aparse -> dmnorder = order_pref;
  1428.     aparse -> normalised = normalised;
  1429.     aparse -> percents = percents;
  1430.     aparse -> internal = internal;
  1431.  
  1432.     ap_t2s(ap, &(aparse->r822_str));
  1433.     if (aparse_norm(aparse) == NOTOK) {
  1434.         ap = ap_t2p(ap, &group_ptr, &name_ptr, 
  1435.                 &loc_ptr, &dom_ptr, &route_ptr);
  1436.     } else {
  1437.         tmp = ap;
  1438.         ap = aparse->ap_tree;
  1439.         aparse->ap_tree = tmp;
  1440.         group_ptr = aparse->ap_group;
  1441.         name_ptr = aparse->ap_name;
  1442.         loc_ptr = aparse->ap_local;
  1443.         dom_ptr = aparse->ap_domain;
  1444.         route_ptr = aparse->ap_route;
  1445.     }
  1446.     aparse_free(aparse);
  1447.     free ((char *) aparse);
  1448.  
  1449.     if (from && equalWithJntsender(loc_ptr))
  1450.         noFrom = 0;
  1451.     
  1452.     if (num_pairs != 0
  1453.         && changedomains != NULL)
  1454.         do_changedomains (ap);
  1455.     
  1456.     /* do all stripping then create addrp */
  1457.     if ((dom_ptr != NULL)
  1458.         && (num_to_hide != 0)
  1459.         && do_hidedomains(dom_ptr, route_ptr)) {
  1460.  
  1461.     /* This might be local now, so go through the whole expansion
  1462.      * process again.  Remember though that we might be exremely
  1463.      * silly, and cause `infinite' recursion.  Hence the rd variable.
  1464.      *
  1465.      * If we are being silly we'll take what was demanded, and log an
  1466.      * exception later
  1467.      */
  1468.  
  1469.         if (rd < 3) {
  1470.             re_parse_ptr = addrp = ap_p2s(group_ptr, name_ptr, loc_ptr, 
  1471.                               dom_ptr, route_ptr);
  1472.             ap_sqdelete (ap, NULLAP);
  1473.             ap_free (ap);
  1474.             ap = ap_pstrt = ap_pcur = ap_alloc ();
  1475.             ap_ppush(get_rp_char);
  1476.             ap_clear();
  1477.             if (ap_1adr() == OK)
  1478.                 out_adr(ap);
  1479.             ap_ppop();
  1480.             free(addrp);
  1481.             rd--;
  1482.             return OK;
  1483.             /* NOTREACHED */
  1484.         }
  1485.     }
  1486.     if ((dom_ptr != NULL)
  1487.         && (striproutes == TRUE))
  1488.         do_striproutes(&ap, &group_ptr, &name_ptr, &loc_ptr,
  1489.                    &dom_ptr, &route_ptr);
  1490.     else if ((dom_ptr != NULL) 
  1491.          && (num_domains != 0))
  1492.         do_stripdomains(&ap, &group_ptr, &name_ptr, &loc_ptr,
  1493.                 &dom_ptr, &route_ptr);
  1494.  
  1495.     if (exorcise == TRUE)
  1496.         do_exorcisedomain(&ap, &group_ptr, &name_ptr, &loc_ptr,
  1497.                   &dom_ptr, &route_ptr);
  1498.  
  1499.     addrp = ap_p2s(group_ptr, name_ptr, loc_ptr, 
  1500.                dom_ptr, route_ptr);
  1501.  
  1502.                        
  1503.     if (addrp == (char *)NOTOK) {
  1504.         PP_LOG (LLOG_EXCEPTIONS,
  1505.             ("Lib/addr/ap_t2s: error from ap_p2s()"));
  1506.         addrp = strdup ("(PP Error!)");
  1507.     }
  1508.     if (rd == 3) {
  1509.         PP_LOG (LLOG_EXCEPTIONS,
  1510.             ("Format/rfc822norm: Excessive local hiding - lying about %s", addrp));
  1511.     }
  1512.  
  1513.     if (nadrs != 0) {
  1514.         printf(", ");
  1515.         pcol += 2;
  1516.     }
  1517.  
  1518.     PP_TRACE(("output '%s'",addrp));
  1519.  
  1520.     if ((len = strlen(addrp)) > 0) { /* print */
  1521.         pcol += len;
  1522.         if (fold_width != -1 && pcol > fold_width && nonempty) {
  1523.             pcol = strlen(fieldbuf) + 2 + len;
  1524.             printf("\n%*s", strlen(fieldbuf) + 2, "");
  1525.         } else
  1526.             nonempty = TRUE;
  1527.         
  1528.         printf("%s",addrp);
  1529.         nadrs++;
  1530.     }
  1531.     free(addrp);
  1532. /*    ap_sqdelete (ap, NULLAP);
  1533.     ap_free (ap);*/
  1534.     rd--;
  1535.     return OK;
  1536. }
  1537.  
  1538. /*   */
  1539. static char *reverse(str)
  1540. char    *str;
  1541. {
  1542.     char    *ret = malloc((unsigned) strlen(str)+1),
  1543.         *dup = strdup(str),
  1544.         *ix;
  1545.     ret[0] = '\0';
  1546.     while ((ix = rindex(dup,'.')) != NULL) {
  1547.         if (ret[0] == '\0')
  1548.             sprintf(ret, "%s", ix+1);
  1549.         else
  1550.             sprintf(ret,"%s.%s",ret,ix+1);
  1551.         *ix = '\0';
  1552.     }
  1553.     if (ret[0] == '\0')
  1554.         sprintf(ret, "%s", dup);
  1555.     else
  1556.         sprintf(ret,"%s.%s",ret,dup);
  1557.     free(dup);
  1558.     return ret;
  1559. }
  1560.  
  1561. /*   */
  1562.  
  1563. static int valid_received (cont)
  1564. char    *cont;
  1565. {
  1566.     if (index (cont, ';') == NULLCP)
  1567.         return NOTOK;
  1568.     return OK;
  1569. }
  1570.  
  1571. static int valid_via(cont)
  1572. char    *cont;
  1573. {
  1574.     char    *sep, *ix;
  1575.     if ((sep = index (cont, ';')) == NULLCP)
  1576.         return NOTOK;
  1577.     
  1578.     for (ix = &(cont[0]);
  1579.          ix != sep && isspace(*ix);
  1580.          ix++);
  1581.     
  1582.     if (ix == sep)
  1583.         return NOTOK;
  1584.     
  1585.     return OK;
  1586. }
  1587.  
  1588. static int valid_x400(cont)
  1589. char    *cont;
  1590. {
  1591.     char    *sep;
  1592.     /* at least two semi-colons */
  1593.     if ((sep = index(cont, ';')) == NULLCP
  1594.         || index((sep+1), ';') == NULLCP)
  1595.         return NOTOK;
  1596.     return OK;
  1597. }
  1598.  
  1599. int valid_trace(type, field, cont)
  1600. int    type;
  1601. char    *field;
  1602. char    *cont;
  1603. {
  1604.     int    retval = OK;
  1605.     switch (type) {
  1606.         case TRACE_RECIEVED:
  1607.         retval = valid_received(cont);
  1608.         break;
  1609.         case TRACE_VIA:
  1610.         retval = valid_via(cont);
  1611.         break;
  1612.         case TRACE_X400:
  1613.         retval = valid_x400(cont);
  1614.         break;
  1615.         default:
  1616.         break;
  1617.     }
  1618.  
  1619.     if (retval == NOTOK) {
  1620.         char    *fold, *ix;
  1621.         int    nonempty = FALSE;
  1622.         
  1623.         printf("Original-%s: ", field);
  1624.         ix = &(cont[0]);
  1625.         while (*ix != '\0') {
  1626.             fold = next_fold(ix+1, FOLD_SPACE);
  1627.             if ((fold_width != -1)
  1628.                 && (fold - ix + pcol > fold_width)
  1629.                 && nonempty == TRUE) {
  1630.                 /* fold */
  1631.                 pcol = strlen(field) + strlen("Original-: ");
  1632.                 printf("\n%*s",
  1633.                        strlen(field) + strlen("Original-: "),
  1634.                        "");
  1635.                 while (isspace(*ix))
  1636.                     ix++;
  1637.             } else
  1638.                 nonempty = TRUE;
  1639.             pcol += fold - ix;
  1640.             while (ix != fold)
  1641.                 putchar (*ix++);
  1642.         }
  1643.         putchar('\n');                
  1644.  
  1645.         printf("PP-warning: Illegal %s field on preceding line\n",
  1646.                rcmd_srch(type, tbl_tracefields));
  1647.     }
  1648.     return retval;
  1649. }
  1650.