"Fossies" - the Fresh Open Source Software Archive

Member "s-nail-14.9.10/ignore.c" (25 Mar 2018, 21696 Bytes) of package /linux/misc/s-nail-14.9.10.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ignore.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 14.9.6_vs_14.9.7.

    1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
    2  *@ `headerpick', `retain' and `ignore', and `un..' variants.
    3  *
    4  * Copyright (c) 2012 - 2018 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
    5  */
    6 /*
    7  * Copyright (c) 1980, 1993
    8  *      The Regents of the University of California.  All rights reserved.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. Neither the name of the University nor the names of its contributors
   19  *    may be used to endorse or promote products derived from this software
   20  *    without specific prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   32  * SUCH DAMAGE.
   33  */
   34 #undef n_FILE
   35 #define n_FILE ignore
   36 
   37 #ifndef HAVE_AMALGAMATION
   38 # include "nail.h"
   39 #endif
   40 
   41 struct a_ignore_type{
   42    ui32_t it_count;     /* Entries in .it_ht (and .it_re) */
   43    bool_t it_all;       /* _All_ fields ought to be _type_ (ignore/retain) */
   44    ui8_t it__dummy[3];
   45    struct a_ignore_field{
   46       struct a_ignore_field *if_next;
   47       char if_field[n_VFIELD_SIZE(0)]; /* Header field */
   48    } *it_ht[3]; /* TODO make hashmap dynamic */
   49 #ifdef HAVE_REGEX
   50    struct a_ignore_re{
   51       struct a_ignore_re *ir_next;
   52       regex_t ir_regex;
   53       char ir_input[n_VFIELD_SIZE(0)]; /* Regex input text (for showing it) */
   54    } *it_re, *it_re_tail;
   55 #endif
   56 };
   57 
   58 struct n_ignore{
   59    struct a_ignore_type i_retain;
   60    struct a_ignore_type i_ignore;
   61    bool_t i_auto;       /* In auto-reclaimed, not heap memory */
   62    bool_t i_bltin;      /* Is a built-in n_IGNORE* type */
   63    ui8_t i_ibm_idx;     /* If .i_bltin: a_ignore_bltin_map[] idx */
   64    ui8_t i__dummy[5];
   65 };
   66 
   67 struct a_ignore_bltin_map{
   68    struct n_ignore *ibm_ip;
   69    char const ibm_name[8];
   70 };
   71 
   72 static struct a_ignore_bltin_map const a_ignore_bltin_map[] = {
   73    {n_IGNORE_TYPE, "type\0"},
   74    {n_IGNORE_SAVE, "save\0"},
   75    {n_IGNORE_FWD, "forward\0"},
   76    {n_IGNORE_TOP, "top\0"},
   77 
   78    {n_IGNORE_TYPE, "print\0"},
   79    {n_IGNORE_FWD, "fwd\0"}
   80 };
   81 #ifdef HAVE_DEVEL /* Avoid gcc warn cascade since n_ignore is defined locally */
   82 n_CTAV(-n__IGNORE_TYPE - n__IGNORE_ADJUST == 0);
   83 n_CTAV(-n__IGNORE_SAVE - n__IGNORE_ADJUST == 1);
   84 n_CTAV(-n__IGNORE_FWD - n__IGNORE_ADJUST == 2);
   85 n_CTAV(-n__IGNORE_TOP - n__IGNORE_ADJUST == 3);
   86 n_CTAV(n__IGNORE_MAX == 3);
   87 #endif
   88 
   89 static struct n_ignore *a_ignore_bltin[n__IGNORE_MAX + 1];
   90 /* Almost everyone uses `ignore'/`retain', put _TYPE in BSS */
   91 static struct n_ignore a_ignore_type;
   92 
   93 /* Return real self, which is xself unless that is one of the built-in specials,
   94  * in which case NULL is returned if nonexistent and docreate is false.
   95  * The other statics assume self has been resolved (unless noted) */
   96 static struct n_ignore *a_ignore_resolve_self(struct n_ignore *xself,
   97                            bool_t docreate);
   98 
   99 /* Lookup whether a mapping is contained: TRU1=retained, TRUM1=ignored.
  100  * If retain is _not_ TRUM1 then only the retained/ignored slot is inspected,
  101  * and regular expressions are not executed but instead their .ir_input is
  102  * text-compared against len bytes of dat.
  103  * Note it doesn't handle the .it_all "all fields" condition */
  104 static bool_t a_ignore_lookup(struct n_ignore const *self, bool_t retain,
  105                char const *dat, size_t len);
  106 
  107 /* Delete all retain( else ignor)ed members */
  108 static void a_ignore_del_allof(struct n_ignore *ip, bool_t retain);
  109 
  110 /* Try to map a string to one of the built-in types */
  111 static struct a_ignore_bltin_map const *a_ignore_resolve_bltin(char const *cp);
  112 
  113 /* Logic behind `headerpick T T' (a.k.a. `retain'+) */
  114 static bool_t a_ignore_addcmd_mux(struct n_ignore *ip, char const **list,
  115                bool_t retain);
  116 
  117 static void a_ignore__show(struct n_ignore const *ip, bool_t retain);
  118 static int a_ignore__cmp(void const *l, void const *r);
  119 
  120 /* Logic behind `unheaderpick T T' (a.k.a. `unretain'+) */
  121 static bool_t a_ignore_delcmd_mux(struct n_ignore *ip, char const **list,
  122                bool_t retain);
  123 
  124 static bool_t a_ignore__delone(struct n_ignore *ip, bool_t retain,
  125                char const *field);
  126 
  127 static struct n_ignore *
  128 a_ignore_resolve_self(struct n_ignore *xself, bool_t docreate){
  129    uintptr_t suip;
  130    struct n_ignore *self;
  131    NYD2_ENTER;
  132 
  133    self = xself;
  134    suip = -(uintptr_t)self - n__IGNORE_ADJUST;
  135 
  136    if(suip <= n__IGNORE_MAX){
  137       if((self = a_ignore_bltin[suip]) == NULL && docreate){
  138          if(xself == n_IGNORE_TYPE){
  139             self = &a_ignore_type;
  140             /* LIB: memset(self, 0, sizeof *self);*/
  141          }else
  142             self = n_ignore_new(FAL0);
  143          self->i_bltin = TRU1;
  144          self->i_ibm_idx = (ui8_t)suip;
  145          a_ignore_bltin[suip] = self;
  146       }
  147    }
  148    NYD2_LEAVE;
  149    return self;
  150 }
  151 
  152 static bool_t
  153 a_ignore_lookup(struct n_ignore const *self, bool_t retain,
  154       char const *dat, size_t len){
  155    bool_t rv;
  156 #ifdef HAVE_REGEX
  157    struct a_ignore_re *irp;
  158 #endif
  159    struct a_ignore_field *ifp;
  160    ui32_t hi;
  161    NYD2_ENTER;
  162 
  163    if(len == UIZ_MAX)
  164       len = strlen(dat);
  165    hi = n_torek_ihashn(dat, len) % n_NELEM(self->i_retain.it_ht);
  166 
  167    /* Again: doesn't handle .it_all conditions! */
  168    /* (Inner functions would be nice, again) */
  169    if(retain && self->i_retain.it_count > 0){
  170       rv = TRU1;
  171       for(ifp = self->i_retain.it_ht[hi]; ifp != NULL; ifp = ifp->if_next)
  172          if(!ascncasecmp(ifp->if_field, dat, len))
  173             goto jleave;
  174 #ifdef HAVE_REGEX
  175       if(dat[len - 1] != '\0')
  176          dat = savestrbuf(dat, len);
  177       for(irp = self->i_retain.it_re; irp != NULL; irp = irp->ir_next)
  178          if((retain == TRUM1
  179                ? (regexec(&irp->ir_regex, dat, 0,NULL, 0) != REG_NOMATCH)
  180                : !strncmp(irp->ir_input, dat, len)))
  181             goto jleave;
  182 #endif
  183       rv = (retain == TRUM1) ? TRUM1 : FAL0;
  184    }else if((retain == TRUM1 || !retain) && self->i_ignore.it_count > 0){
  185       rv = TRUM1;
  186       for(ifp = self->i_ignore.it_ht[hi]; ifp != NULL; ifp = ifp->if_next)
  187          if(!ascncasecmp(ifp->if_field, dat, len))
  188             goto jleave;
  189 #ifdef HAVE_REGEX
  190       if(dat[len - 1] != '\0')
  191          dat = savestrbuf(dat, len);
  192       for(irp = self->i_ignore.it_re; irp != NULL; irp = irp->ir_next)
  193          if((retain == TRUM1
  194                ? (regexec(&irp->ir_regex, dat, 0,NULL, 0) != REG_NOMATCH)
  195                : !strncmp(irp->ir_input, dat, len)))
  196             goto jleave;
  197 #endif
  198       rv = (retain == TRUM1) ? TRU1 : FAL0;
  199    }else
  200       rv = FAL0;
  201 jleave:
  202    NYD2_LEAVE;
  203    return rv;
  204 }
  205 
  206 static void
  207 a_ignore_del_allof(struct n_ignore *ip, bool_t retain){
  208 #ifdef HAVE_REGEX
  209    struct a_ignore_re *irp;
  210 #endif
  211    struct a_ignore_field *ifp;
  212    struct a_ignore_type *itp;
  213    NYD2_ENTER;
  214 
  215    itp = retain ? &ip->i_retain : &ip->i_ignore;
  216 
  217    if(!ip->i_auto){
  218       size_t i;
  219 
  220       for(i = 0; i < n_NELEM(itp->it_ht); ++i)
  221          for(ifp = itp->it_ht[i]; ifp != NULL;){
  222             struct a_ignore_field *x;
  223 
  224             x = ifp;
  225             ifp = ifp->if_next;
  226             n_free(x);
  227          }
  228    }
  229 
  230 #ifdef HAVE_REGEX
  231    for(irp = itp->it_re; irp != NULL;){
  232       struct a_ignore_re *x;
  233 
  234       x = irp;
  235       irp = irp->ir_next;
  236       regfree(&x->ir_regex);
  237       if(!ip->i_auto)
  238          n_free(x);
  239    }
  240 #endif
  241 
  242    memset(itp, 0, sizeof *itp);
  243    NYD2_LEAVE;
  244 }
  245 
  246 static struct a_ignore_bltin_map const *
  247 a_ignore_resolve_bltin(char const *cp){
  248    struct a_ignore_bltin_map const *ibmp;
  249    NYD2_ENTER;
  250 
  251    for(ibmp = &a_ignore_bltin_map[0];;)
  252       if(!asccasecmp(cp, ibmp->ibm_name))
  253          break;
  254       else if(++ibmp == &a_ignore_bltin_map[n_NELEM(a_ignore_bltin_map)]){
  255          ibmp = NULL;
  256          break;
  257       }
  258    NYD2_LEAVE;
  259    return ibmp;
  260 }
  261 
  262 static bool_t
  263 a_ignore_addcmd_mux(struct n_ignore *ip, char const **list, bool_t retain){
  264    char const **ap;
  265    bool_t rv;
  266    NYD2_ENTER;
  267 
  268    ip = a_ignore_resolve_self(ip, rv = (*list != NULL));
  269 
  270    if(!rv){
  271       if(ip != NULL && ip->i_bltin)
  272          a_ignore__show(ip, retain);
  273       rv = TRU1;
  274    }else{
  275       for(ap = list; *ap != 0; ++ap)
  276          switch(n_ignore_insert_cp(ip, retain, *ap)){
  277          case FAL0:
  278             n_err(_("Invalid field name cannot be %s: %s\n"),
  279                (retain ? _("retained") : _("ignored")), *ap);
  280             rv = FAL0;
  281             break;
  282          case TRUM1:
  283             if(n_poption & n_PO_D_V)
  284                n_err(_("Field already %s: %s\n"),
  285                   (retain ? _("retained") : _("ignored")), *ap);
  286             /* FALLTHRU */
  287          case TRU1:
  288             break;
  289          }
  290    }
  291    NYD2_LEAVE;
  292    return rv;
  293 }
  294 
  295 static void
  296 a_ignore__show(struct n_ignore const *ip, bool_t retain){
  297 #ifdef HAVE_REGEX
  298    struct a_ignore_re *irp;
  299 #endif
  300    struct a_ignore_field *ifp;
  301    size_t i, sw;
  302    char const **ap, **ring;
  303    struct a_ignore_type const *itp;
  304    NYD2_ENTER;
  305 
  306    itp = retain ? &ip->i_retain : &ip->i_ignore;
  307 
  308    do{
  309       char const *pre, *attr;
  310 
  311       if(itp->it_all)
  312          pre = n_empty, attr = n_star;
  313       else if(itp->it_count == 0)
  314          pre = n_ns, attr = _("currently covers no fields");
  315       else
  316          break;
  317       fprintf(n_stdout, _("%sheaderpick %s %s %s\n"),
  318          pre, a_ignore_bltin_map[ip->i_ibm_idx].ibm_name,
  319          (retain ? "retain" : "ignore"), attr);
  320       goto jleave;
  321    }while(0);
  322 
  323    ring = salloc((itp->it_count +1) * sizeof *ring);
  324    for(ap = ring, i = 0; i < n_NELEM(itp->it_ht); ++i)
  325       for(ifp = itp->it_ht[i]; ifp != NULL; ifp = ifp->if_next)
  326          *ap++ = ifp->if_field;
  327    *ap = NULL;
  328 
  329    qsort(ring, PTR2SIZE(ap - ring), sizeof *ring, &a_ignore__cmp);
  330 
  331    i = fprintf(n_stdout, "headerpick %s %s",
  332       a_ignore_bltin_map[ip->i_ibm_idx].ibm_name,
  333       (retain ? "retain" : "ignore"));
  334    sw = n_scrnwidth;
  335 
  336    for(ap = ring; *ap != NULL; ++ap){
  337       /* These fields are all ASCII, no visual width needed */
  338       size_t len;
  339 
  340       len = strlen(*ap) + 1;
  341       if(UICMP(z, len, >=, sw - i)){
  342          fputs(" \\\n ", n_stdout);
  343          i = 1;
  344       }
  345       i += len;
  346       putc(' ', n_stdout);
  347       fputs(*ap, n_stdout);
  348    }
  349 
  350    /* Regular expression in FIFO order */
  351 #ifdef HAVE_REGEX
  352    for(irp = itp->it_re; irp != NULL; irp = irp->ir_next){
  353       size_t len;
  354       char const *cp;
  355 
  356       cp = n_shexp_quote_cp(irp->ir_input, FAL0);
  357       len = strlen(cp) + 1;
  358       if(UICMP(z, len, >=, sw - i)){
  359          fputs(" \\\n ", n_stdout);
  360          i = 1;
  361       }
  362       i += len;
  363       putc(' ', n_stdout);
  364       fputs(cp, n_stdout);
  365    }
  366 #endif
  367 
  368    putc('\n', n_stdout);
  369 jleave:
  370    fflush(n_stdout);
  371    NYD2_LEAVE;
  372 }
  373 
  374 static int
  375 a_ignore__cmp(void const *l, void const *r){
  376    int rv;
  377 
  378    rv = asccasecmp(*(char const * const *)l, *(char const * const *)r);
  379    return rv;
  380 }
  381 
  382 static bool_t
  383 a_ignore_delcmd_mux(struct n_ignore *ip, char const **list, bool_t retain){
  384    char const *cp;
  385    struct a_ignore_type *itp;
  386    bool_t rv;
  387    NYD2_ENTER;
  388 
  389    ip = a_ignore_resolve_self(ip, rv = (*list != NULL));
  390    itp = retain ? &ip->i_retain : &ip->i_ignore;
  391 
  392    if(itp->it_count == 0 && !itp->it_all)
  393       n_err(_("No fields currently being %s\n"),
  394          (retain ? _("retained") : _("ignored")));
  395    else
  396       while((cp = *list++) != NULL)
  397          if(cp[0] == '*' && cp[1] == '\0')
  398             a_ignore_del_allof(ip, retain);
  399          else if(!a_ignore__delone(ip, retain, cp)){
  400             n_err(_("Field not %s: %s\n"),
  401                (retain ? _("retained") : _("ignored")), cp);
  402             rv = FAL0;
  403          }
  404    NYD2_LEAVE;
  405    return rv;
  406 }
  407 
  408 static bool_t
  409 a_ignore__delone(struct n_ignore *ip, bool_t retain, char const *field){
  410    struct a_ignore_type *itp;
  411    NYD_ENTER;
  412 
  413    itp = retain ? &ip->i_retain : &ip->i_ignore;
  414 
  415 #ifdef HAVE_REGEX
  416    if(n_is_maybe_regex(field)){
  417       struct a_ignore_re **lirp, *irp;
  418 
  419       for(irp = *(lirp = &itp->it_re); irp != NULL;
  420             lirp = &irp->ir_next, irp = irp->ir_next)
  421          if(!strcmp(field, irp->ir_input)){
  422             *lirp = irp->ir_next;
  423             if(irp == itp->it_re_tail)
  424                itp->it_re_tail = irp->ir_next;
  425 
  426             regfree(&irp->ir_regex);
  427             if(!ip->i_auto)
  428                n_free(irp);
  429             --itp->it_count;
  430             goto jleave;
  431          }
  432    }else
  433 #endif /* HAVE_REGEX */
  434    {
  435       struct a_ignore_field **ifpp, *ifp;
  436       ui32_t hi;
  437 
  438       hi = n_torek_ihashn(field, UIZ_MAX) % n_NELEM(itp->it_ht);
  439 
  440       for(ifp = *(ifpp = &itp->it_ht[hi]); ifp != NULL;
  441             ifpp = &ifp->if_next, ifp = ifp->if_next)
  442          if(!asccasecmp(ifp->if_field, field)){
  443             *ifpp = ifp->if_next;
  444             if(!ip->i_auto)
  445                n_free(ifp);
  446             --itp->it_count;
  447            goto jleave;
  448          }
  449    }
  450 
  451    ip = NULL;
  452 jleave:
  453    NYD_LEAVE;
  454    return (ip != NULL);
  455 }
  456 
  457 FL int
  458 c_headerpick(void *vp){
  459    bool_t retain;
  460    struct a_ignore_bltin_map const *ibmp;
  461    char const **argv;
  462    int rv;
  463    NYD_ENTER;
  464 
  465    rv = 1;
  466    argv = vp;
  467 
  468    /* Without arguments, show all settings of all contexts */
  469    if(*argv == NULL){
  470       rv = 0;
  471       for(ibmp = &a_ignore_bltin_map[0];
  472             ibmp <= &a_ignore_bltin_map[n__IGNORE_MAX]; ++ibmp){
  473          rv |= !a_ignore_addcmd_mux(ibmp->ibm_ip, argv, TRU1);
  474          rv |= !a_ignore_addcmd_mux(ibmp->ibm_ip, argv, FAL0);
  475       }
  476       goto jleave;
  477    }
  478 
  479    if((ibmp = a_ignore_resolve_bltin(*argv)) == NULL){
  480       n_err(_("`headerpick': invalid context: %s\n"), *argv);
  481       goto jleave;
  482    }
  483    ++argv;
  484 
  485    /* With only <context>, show all settings of it */
  486    if(*argv == NULL){
  487       rv = 0;
  488       rv |= !a_ignore_addcmd_mux(ibmp->ibm_ip, argv, TRU1);
  489       rv |= !a_ignore_addcmd_mux(ibmp->ibm_ip, argv, FAL0);
  490       goto jleave;
  491    }
  492 
  493    if(is_asccaseprefix(*argv, "retain"))
  494       retain = TRU1;
  495    else if(is_asccaseprefix(*argv, "ignore"))
  496       retain = FAL0;
  497    else{
  498       n_err(_("`headerpick': invalid type (retain, ignore): %s\n"), *argv);
  499       goto jleave;
  500    }
  501    ++argv;
  502 
  503    /* With only <context> and <type>, show its settings */
  504    if(*argv == NULL){
  505       rv = !a_ignore_addcmd_mux(ibmp->ibm_ip, argv, retain);
  506       goto jleave;
  507    }
  508 
  509    rv = !a_ignore_addcmd_mux(ibmp->ibm_ip, argv, retain);
  510 jleave:
  511    NYD_LEAVE;
  512    return rv;
  513 }
  514 
  515 FL int
  516 c_unheaderpick(void *vp){
  517    bool_t retain;
  518    struct a_ignore_bltin_map const *ibmp;
  519    char const **argv;
  520    int rv;
  521    NYD_ENTER;
  522 
  523    rv = 1;
  524    argv = vp;
  525 
  526    if((ibmp = a_ignore_resolve_bltin(*argv)) == NULL){
  527       n_err(_("`unheaderpick': invalid context: %s\n"), *argv);
  528       goto jleave;
  529    }
  530    ++argv;
  531 
  532    if(is_asccaseprefix(*argv, "retain"))
  533       retain = TRU1;
  534    else if(is_asccaseprefix(*argv, "ignore"))
  535       retain = FAL0;
  536    else{
  537       n_err(_("`unheaderpick': invalid type (retain, ignore): %s\n"), *argv);
  538       goto jleave;
  539    }
  540    ++argv;
  541 
  542    rv = !a_ignore_delcmd_mux(ibmp->ibm_ip, argv, retain);
  543 jleave:
  544    NYD_LEAVE;
  545    return rv;
  546 }
  547 
  548 FL int
  549 c_retain(void *vp){
  550    int rv;
  551    NYD_ENTER;
  552 
  553    rv = !a_ignore_addcmd_mux(n_IGNORE_TYPE, vp, TRU1);
  554    NYD_LEAVE;
  555    return rv;
  556 }
  557 
  558 FL int
  559 c_ignore(void *vp){
  560    int rv;
  561    NYD_ENTER;
  562 
  563    rv = !a_ignore_addcmd_mux(n_IGNORE_TYPE, vp, FAL0);
  564    NYD_LEAVE;
  565    return rv;
  566 }
  567 
  568 FL int
  569 c_unretain(void *vp){
  570    int rv;
  571    NYD_ENTER;
  572 
  573    rv = !a_ignore_delcmd_mux(n_IGNORE_TYPE, vp, TRU1);
  574    NYD_LEAVE;
  575    return rv;
  576 }
  577 
  578 FL int
  579 c_unignore(void *vp){
  580    int rv;
  581    NYD_ENTER;
  582 
  583    rv = !a_ignore_delcmd_mux(n_IGNORE_TYPE, vp, FAL0);
  584    NYD_LEAVE;
  585    return rv;
  586 }
  587 
  588 FL int
  589 c_saveretain(void *v){ /* TODO v15 drop */
  590    int rv;
  591    NYD_ENTER;
  592 
  593    rv = !a_ignore_addcmd_mux(n_IGNORE_SAVE, v, TRU1);
  594    NYD_LEAVE;
  595    return rv;
  596 }
  597 
  598 FL int
  599 c_saveignore(void *v){ /* TODO v15 drop */
  600    int rv;
  601    NYD_ENTER;
  602 
  603    rv = !a_ignore_addcmd_mux(n_IGNORE_SAVE, v, FAL0);
  604    NYD_LEAVE;
  605    return rv;
  606 }
  607 
  608 FL int
  609 c_unsaveretain(void *v){ /* TODO v15 drop */
  610    int rv;
  611    NYD_ENTER;
  612 
  613    rv = !a_ignore_delcmd_mux(n_IGNORE_SAVE, v, TRU1);
  614    NYD_LEAVE;
  615    return rv;
  616 }
  617 
  618 FL int
  619 c_unsaveignore(void *v){ /* TODO v15 drop */
  620    int rv;
  621    NYD_ENTER;
  622 
  623    rv = !a_ignore_delcmd_mux(n_IGNORE_SAVE, v, FAL0);
  624    NYD_LEAVE;
  625    return rv;
  626 }
  627 
  628 FL int
  629 c_fwdretain(void *v){ /* TODO v15 drop */
  630    int rv;
  631    NYD_ENTER;
  632 
  633    rv = !a_ignore_addcmd_mux(n_IGNORE_FWD, v, TRU1);
  634    NYD_LEAVE;
  635    return rv;
  636 }
  637 
  638 FL int
  639 c_fwdignore(void *v){ /* TODO v15 drop */
  640    int rv;
  641    NYD_ENTER;
  642 
  643    rv = !a_ignore_addcmd_mux(n_IGNORE_FWD, v, FAL0);
  644    NYD_LEAVE;
  645    return rv;
  646 }
  647 
  648 FL int
  649 c_unfwdretain(void *v){ /* TODO v15 drop */
  650    int rv;
  651    NYD_ENTER;
  652 
  653    rv = !a_ignore_delcmd_mux(n_IGNORE_FWD, v, TRU1);
  654    NYD_LEAVE;
  655    return rv;
  656 }
  657 
  658 FL int
  659 c_unfwdignore(void *v){ /* TODO v15 drop */
  660    int rv;
  661    NYD_ENTER;
  662 
  663    rv = !a_ignore_delcmd_mux(n_IGNORE_FWD, v, FAL0);
  664    NYD_LEAVE;
  665    return rv;
  666 }
  667 
  668 FL struct n_ignore *
  669 n_ignore_new(bool_t isauto){
  670    struct n_ignore *self;
  671    NYD_ENTER;
  672 
  673    self = isauto ? n_autorec_calloc(1, sizeof *self) : n_calloc(1,sizeof *self);
  674    self->i_auto = isauto;
  675    NYD_LEAVE;
  676    return self;
  677 }
  678 
  679 FL void
  680 n_ignore_del(struct n_ignore *self){
  681    NYD_ENTER;
  682    a_ignore_del_allof(self, TRU1);
  683    a_ignore_del_allof(self, FAL0);
  684    if(!self->i_auto)
  685       n_free(self);
  686    NYD_LEAVE;
  687 }
  688 
  689 FL bool_t
  690 n_ignore_is_any(struct n_ignore const *self){
  691    bool_t rv;
  692    NYD_ENTER;
  693 
  694    self = a_ignore_resolve_self(n_UNCONST(self), FAL0);
  695    rv = (self != NULL &&
  696          (self->i_retain.it_count != 0 || self->i_retain.it_all ||
  697           self->i_ignore.it_count != 0 || self->i_ignore.it_all));
  698    NYD_LEAVE;
  699    return rv;
  700 }
  701 
  702 FL bool_t
  703 n_ignore_insert(struct n_ignore *self, bool_t retain,
  704       char const *dat, size_t len){
  705 #ifdef HAVE_REGEX
  706    struct a_ignore_re *irp;
  707    bool_t isre;
  708 #endif
  709    struct a_ignore_field *ifp;
  710    struct a_ignore_type *itp;
  711    bool_t rv;
  712    NYD_ENTER;
  713 
  714    retain = !!retain; /* Make it true bool, TRUM1 has special _lookup meaning */
  715    rv = FAL0;
  716    self = a_ignore_resolve_self(self, TRU1);
  717 
  718    if(len == UIZ_MAX)
  719       len = strlen(dat);
  720 
  721    /* Request to ignore or retain _anything_?  That is special-treated */
  722    if(len == 1 && dat[0] == '*'){
  723       itp = retain ? &self->i_retain : &self->i_ignore;
  724       if(itp->it_all)
  725          rv = TRUM1;
  726       else{
  727          itp->it_all = TRU1;
  728          a_ignore_del_allof(self, retain);
  729          rv = TRU1;
  730       }
  731       goto jleave;
  732    }
  733 
  734    /* Check for regular expression or valid fieldname */
  735 #ifdef HAVE_REGEX
  736    if(!(isre = n_is_maybe_regex_buf(dat, len)))
  737 #endif
  738    {
  739       char c;
  740       size_t i;
  741 
  742       for(i = 0; i < len; ++i){
  743          c = dat[i];
  744          if(!fieldnamechar(c))
  745             goto jleave;
  746       }
  747    }
  748 
  749    rv = TRUM1;
  750    if(a_ignore_lookup(self, retain, dat, len) == (retain ? TRU1 : TRUM1))
  751       goto jleave;
  752 
  753    itp = retain ? &self->i_retain : &self->i_ignore;
  754 
  755    if(itp->it_count == UI32_MAX){
  756       n_err(_("Header selection size limit reached, cannot insert: %.*s\n"),
  757          (int)n_MIN(len, SI32_MAX), dat);
  758       rv = FAL0;
  759       goto jleave;
  760    }
  761 
  762    rv = TRU1;
  763 #ifdef HAVE_REGEX
  764    if(isre){
  765       struct a_ignore_re *x;
  766       int s;
  767       size_t i;
  768 
  769       i = n_VSTRUCT_SIZEOF(struct a_ignore_re, ir_input) + ++len;
  770       irp = self->i_auto ? n_autorec_alloc(i) : n_alloc(i);
  771       memcpy(irp->ir_input, dat, --len);
  772       irp->ir_input[len] = '\0';
  773 
  774       if((s = regcomp(&irp->ir_regex, irp->ir_input,
  775             REG_EXTENDED | REG_ICASE | REG_NOSUB)) != 0){
  776          n_err(_("Invalid regular expression: %s: %s\n"),
  777             n_shexp_quote_cp(irp->ir_input, FAL0),
  778             n_regex_err_to_doc(NULL, s));
  779          if(!self->i_auto)
  780             n_free(irp);
  781          rv = FAL0;
  782          goto jleave;
  783       }
  784 
  785       irp->ir_next = NULL;
  786       if((x = itp->it_re_tail) != NULL)
  787          x->ir_next = irp;
  788       else
  789          itp->it_re = irp;
  790       itp->it_re_tail = irp;
  791    }else
  792 #endif /* HAVE_REGEX */
  793    {
  794       ui32_t hi;
  795       size_t i;
  796 
  797       i = n_VSTRUCT_SIZEOF(struct a_ignore_field, if_field) + len + 1;
  798       ifp = self->i_auto ? n_autorec_alloc(i) : n_alloc(i);
  799       memcpy(ifp->if_field, dat, len);
  800       ifp->if_field[len] = '\0';
  801       hi = n_torek_ihashn(dat, len) % n_NELEM(itp->it_ht);
  802       ifp->if_next = itp->it_ht[hi];
  803       itp->it_ht[hi] = ifp;
  804    }
  805    ++itp->it_count;
  806 jleave:
  807    NYD_LEAVE;
  808    return rv;
  809 }
  810 
  811 FL bool_t
  812 n_ignore_lookup(struct n_ignore const *self, char const *dat, size_t len){
  813    bool_t rv;
  814    NYD_ENTER;
  815 
  816    if(self == n_IGNORE_ALL)
  817       rv = TRUM1;
  818    else if(len == 0 ||
  819          (self = a_ignore_resolve_self(n_UNCONST(self), FAL0)) == NULL)
  820       rv = FAL0;
  821    else if(self->i_retain.it_all)
  822       rv = TRU1;
  823    else if(self->i_retain.it_count == 0 && self->i_ignore.it_all)
  824       rv = TRUM1;
  825    else
  826       rv = a_ignore_lookup(self, TRUM1, dat, len);
  827    NYD_LEAVE;
  828    return rv;
  829 }
  830 
  831 /* s-it-mode */