make-config.in: complete path (leftover of [807f64e2], 2015-12-26!)
[s-mailx.git] / ignore.c
blobde9df1af44f73ea562022952d9352e85b0c46483
1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ `headerpick', `retain' and `ignore', and `un..' variants.
4 * Copyright (c) 2012 - 2018 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
5 * SPDX-License-Identifier: ISC
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #undef n_FILE
20 #define n_FILE ignore
22 #ifndef HAVE_AMALGAMATION
23 # include "nail.h"
24 #endif
26 struct a_ignore_type{
27 ui32_t it_count; /* Entries in .it_ht (and .it_re) */
28 bool_t it_all; /* _All_ fields ought to be _type_ (ignore/retain) */
29 ui8_t it__dummy[3];
30 struct a_ignore_field{
31 struct a_ignore_field *if_next;
32 char if_field[n_VFIELD_SIZE(0)]; /* Header field */
33 } *it_ht[3]; /* TODO make hashmap dynamic */
34 #ifdef HAVE_REGEX
35 struct a_ignore_re{
36 struct a_ignore_re *ir_next;
37 regex_t ir_regex;
38 char ir_input[n_VFIELD_SIZE(0)]; /* Regex input text (for showing it) */
39 } *it_re, *it_re_tail;
40 #endif
43 struct n_ignore{
44 struct a_ignore_type i_retain;
45 struct a_ignore_type i_ignore;
46 bool_t i_auto; /* In auto-reclaimed, not heap memory */
47 bool_t i_bltin; /* Is a built-in n_IGNORE* type */
48 ui8_t i_ibm_idx; /* If .i_bltin: a_ignore_bltin_map[] idx */
49 ui8_t i__dummy[5];
52 struct a_ignore_bltin_map{
53 struct n_ignore *ibm_ip;
54 char const ibm_name[8];
57 static struct a_ignore_bltin_map const a_ignore_bltin_map[] = {
58 {n_IGNORE_TYPE, "type\0"},
59 {n_IGNORE_SAVE, "save\0"},
60 {n_IGNORE_FWD, "forward\0"},
61 {n_IGNORE_TOP, "top\0"},
63 {n_IGNORE_TYPE, "print\0"},
64 {n_IGNORE_FWD, "fwd\0"}
66 #ifdef HAVE_DEVEL /* Avoid gcc warn cascade since n_ignore is defined locally */
67 n_CTAV(-n__IGNORE_TYPE - n__IGNORE_ADJUST == 0);
68 n_CTAV(-n__IGNORE_SAVE - n__IGNORE_ADJUST == 1);
69 n_CTAV(-n__IGNORE_FWD - n__IGNORE_ADJUST == 2);
70 n_CTAV(-n__IGNORE_TOP - n__IGNORE_ADJUST == 3);
71 n_CTAV(n__IGNORE_MAX == 3);
72 #endif
74 static struct n_ignore *a_ignore_bltin[n__IGNORE_MAX + 1];
75 /* Almost everyone uses `ignore'/`retain', put _TYPE in BSS */
76 static struct n_ignore a_ignore_type;
78 /* Return real self, which is xself unless that is one of the built-in specials,
79 * in which case NULL is returned if nonexistent and docreate is false.
80 * The other statics assume self has been resolved (unless noted) */
81 static struct n_ignore *a_ignore_resolve_self(struct n_ignore *xself,
82 bool_t docreate);
84 /* Lookup whether a mapping is contained: TRU1=retained, TRUM1=ignored.
85 * If retain is _not_ TRUM1 then only the retained/ignored slot is inspected,
86 * and regular expressions are not executed but instead their .ir_input is
87 * text-compared against len bytes of dat.
88 * Note it doesn't handle the .it_all "all fields" condition */
89 static bool_t a_ignore_lookup(struct n_ignore const *self, bool_t retain,
90 char const *dat, size_t len);
92 /* Delete all retain( else ignor)ed members */
93 static void a_ignore_del_allof(struct n_ignore *ip, bool_t retain);
95 /* Try to map a string to one of the built-in types */
96 static struct a_ignore_bltin_map const *a_ignore_resolve_bltin(char const *cp);
98 /* Logic behind `headerpick T T' (a.k.a. `retain'+) */
99 static bool_t a_ignore_addcmd_mux(struct n_ignore *ip, char const **list,
100 bool_t retain);
102 static void a_ignore__show(struct n_ignore const *ip, bool_t retain);
103 static int a_ignore__cmp(void const *l, void const *r);
105 /* Logic behind `unheaderpick T T' (a.k.a. `unretain'+) */
106 static bool_t a_ignore_delcmd_mux(struct n_ignore *ip, char const **list,
107 bool_t retain);
109 static bool_t a_ignore__delone(struct n_ignore *ip, bool_t retain,
110 char const *field);
112 static struct n_ignore *
113 a_ignore_resolve_self(struct n_ignore *xself, bool_t docreate){
114 uintptr_t suip;
115 struct n_ignore *self;
116 NYD2_ENTER;
118 self = xself;
119 suip = -(uintptr_t)self - n__IGNORE_ADJUST;
121 if(suip <= n__IGNORE_MAX){
122 if((self = a_ignore_bltin[suip]) == NULL && docreate){
123 if(xself == n_IGNORE_TYPE){
124 self = &a_ignore_type;
125 /* LIB: memset(self, 0, sizeof *self);*/
126 }else
127 self = n_ignore_new(FAL0);
128 self->i_bltin = TRU1;
129 self->i_ibm_idx = (ui8_t)suip;
130 a_ignore_bltin[suip] = self;
133 NYD2_LEAVE;
134 return self;
137 static bool_t
138 a_ignore_lookup(struct n_ignore const *self, bool_t retain,
139 char const *dat, size_t len){
140 bool_t rv;
141 #ifdef HAVE_REGEX
142 struct a_ignore_re *irp;
143 #endif
144 struct a_ignore_field *ifp;
145 ui32_t hi;
146 NYD2_ENTER;
148 if(len == UIZ_MAX)
149 len = strlen(dat);
150 hi = n_torek_ihashn(dat, len) % n_NELEM(self->i_retain.it_ht);
152 /* Again: doesn't handle .it_all conditions! */
153 /* (Inner functions would be nice, again) */
154 if(retain && self->i_retain.it_count > 0){
155 rv = TRU1;
156 for(ifp = self->i_retain.it_ht[hi]; ifp != NULL; ifp = ifp->if_next)
157 if(!ascncasecmp(ifp->if_field, dat, len))
158 goto jleave;
159 #ifdef HAVE_REGEX
160 if(dat[len - 1] != '\0')
161 dat = savestrbuf(dat, len);
162 for(irp = self->i_retain.it_re; irp != NULL; irp = irp->ir_next)
163 if((retain == TRUM1
164 ? (regexec(&irp->ir_regex, dat, 0,NULL, 0) != REG_NOMATCH)
165 : !strncmp(irp->ir_input, dat, len)))
166 goto jleave;
167 #endif
168 rv = (retain == TRUM1) ? TRUM1 : FAL0;
169 }else if((retain == TRUM1 || !retain) && self->i_ignore.it_count > 0){
170 rv = TRUM1;
171 for(ifp = self->i_ignore.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_ignore.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) ? TRU1 : FAL0;
184 }else
185 rv = FAL0;
186 jleave:
187 NYD2_LEAVE;
188 return rv;
191 static void
192 a_ignore_del_allof(struct n_ignore *ip, bool_t retain){
193 #ifdef HAVE_REGEX
194 struct a_ignore_re *irp;
195 #endif
196 struct a_ignore_field *ifp;
197 struct a_ignore_type *itp;
198 NYD2_ENTER;
200 itp = retain ? &ip->i_retain : &ip->i_ignore;
202 if(!ip->i_auto){
203 size_t i;
205 for(i = 0; i < n_NELEM(itp->it_ht); ++i)
206 for(ifp = itp->it_ht[i]; ifp != NULL;){
207 struct a_ignore_field *x;
209 x = ifp;
210 ifp = ifp->if_next;
211 n_free(x);
215 #ifdef HAVE_REGEX
216 for(irp = itp->it_re; irp != NULL;){
217 struct a_ignore_re *x;
219 x = irp;
220 irp = irp->ir_next;
221 regfree(&x->ir_regex);
222 if(!ip->i_auto)
223 n_free(x);
225 #endif
227 memset(itp, 0, sizeof *itp);
228 NYD2_LEAVE;
231 static struct a_ignore_bltin_map const *
232 a_ignore_resolve_bltin(char const *cp){
233 struct a_ignore_bltin_map const *ibmp;
234 NYD2_ENTER;
236 for(ibmp = &a_ignore_bltin_map[0];;)
237 if(!asccasecmp(cp, ibmp->ibm_name))
238 break;
239 else if(++ibmp == &a_ignore_bltin_map[n_NELEM(a_ignore_bltin_map)]){
240 ibmp = NULL;
241 break;
243 NYD2_LEAVE;
244 return ibmp;
247 static bool_t
248 a_ignore_addcmd_mux(struct n_ignore *ip, char const **list, bool_t retain){
249 char const **ap;
250 bool_t rv;
251 NYD2_ENTER;
253 ip = a_ignore_resolve_self(ip, rv = (*list != NULL));
255 if(!rv){
256 if(ip != NULL && ip->i_bltin)
257 a_ignore__show(ip, retain);
258 rv = TRU1;
259 }else{
260 for(ap = list; *ap != 0; ++ap)
261 switch(n_ignore_insert_cp(ip, retain, *ap)){
262 case FAL0:
263 n_err(_("Invalid field name cannot be %s: %s\n"),
264 (retain ? _("retained") : _("ignored")), *ap);
265 rv = FAL0;
266 break;
267 case TRUM1:
268 if(n_poption & n_PO_D_V)
269 n_err(_("Field already %s: %s\n"),
270 (retain ? _("retained") : _("ignored")), *ap);
271 /* FALLTHRU */
272 case TRU1:
273 break;
276 NYD2_LEAVE;
277 return rv;
280 static void
281 a_ignore__show(struct n_ignore const *ip, bool_t retain){
282 #ifdef HAVE_REGEX
283 struct a_ignore_re *irp;
284 #endif
285 struct a_ignore_field *ifp;
286 size_t i, sw;
287 char const **ap, **ring;
288 struct a_ignore_type const *itp;
289 NYD2_ENTER;
291 itp = retain ? &ip->i_retain : &ip->i_ignore;
294 char const *pre, *attr;
296 if(itp->it_all)
297 pre = n_empty, attr = n_star;
298 else if(itp->it_count == 0)
299 pre = n_ns, attr = _("currently covers no fields");
300 else
301 break;
302 fprintf(n_stdout, _("%sheaderpick %s %s %s\n"),
303 pre, a_ignore_bltin_map[ip->i_ibm_idx].ibm_name,
304 (retain ? "retain" : "ignore"), attr);
305 goto jleave;
306 }while(0);
308 ring = n_autorec_alloc((itp->it_count +1) * sizeof *ring);
309 for(ap = ring, i = 0; i < n_NELEM(itp->it_ht); ++i)
310 for(ifp = itp->it_ht[i]; ifp != NULL; ifp = ifp->if_next)
311 *ap++ = ifp->if_field;
312 *ap = NULL;
314 qsort(ring, PTR2SIZE(ap - ring), sizeof *ring, &a_ignore__cmp);
316 i = fprintf(n_stdout, "headerpick %s %s",
317 a_ignore_bltin_map[ip->i_ibm_idx].ibm_name,
318 (retain ? "retain" : "ignore"));
319 sw = n_scrnwidth;
321 for(ap = ring; *ap != NULL; ++ap){
322 /* These fields are all ASCII, no visual width needed */
323 size_t len;
325 len = strlen(*ap) + 1;
326 if(UICMP(z, len, >=, sw - i)){
327 fputs(" \\\n ", n_stdout);
328 i = 1;
330 i += len;
331 putc(' ', n_stdout);
332 fputs(*ap, n_stdout);
335 /* Regular expression in FIFO order */
336 #ifdef HAVE_REGEX
337 for(irp = itp->it_re; irp != NULL; irp = irp->ir_next){
338 size_t len;
339 char const *cp;
341 cp = n_shexp_quote_cp(irp->ir_input, FAL0);
342 len = strlen(cp) + 1;
343 if(UICMP(z, len, >=, sw - i)){
344 fputs(" \\\n ", n_stdout);
345 i = 1;
347 i += len;
348 putc(' ', n_stdout);
349 fputs(cp, n_stdout);
351 #endif
353 putc('\n', n_stdout);
354 jleave:
355 fflush(n_stdout);
356 NYD2_LEAVE;
359 static int
360 a_ignore__cmp(void const *l, void const *r){
361 int rv;
363 rv = asccasecmp(*(char const * const *)l, *(char const * const *)r);
364 return rv;
367 static bool_t
368 a_ignore_delcmd_mux(struct n_ignore *ip, char const **list, bool_t retain){
369 char const *cp;
370 struct a_ignore_type *itp;
371 bool_t rv;
372 NYD2_ENTER;
374 ip = a_ignore_resolve_self(ip, rv = (*list != NULL));
375 itp = retain ? &ip->i_retain : &ip->i_ignore;
377 if(itp->it_count == 0 && !itp->it_all)
378 n_err(_("No fields currently being %s\n"),
379 (retain ? _("retained") : _("ignored")));
380 else
381 while((cp = *list++) != NULL)
382 if(cp[0] == '*' && cp[1] == '\0')
383 a_ignore_del_allof(ip, retain);
384 else if(!a_ignore__delone(ip, retain, cp)){
385 n_err(_("Field not %s: %s\n"),
386 (retain ? _("retained") : _("ignored")), cp);
387 rv = FAL0;
389 NYD2_LEAVE;
390 return rv;
393 static bool_t
394 a_ignore__delone(struct n_ignore *ip, bool_t retain, char const *field){
395 struct a_ignore_type *itp;
396 NYD_ENTER;
398 itp = retain ? &ip->i_retain : &ip->i_ignore;
400 #ifdef HAVE_REGEX
401 if(n_is_maybe_regex(field)){
402 struct a_ignore_re **lirp, *irp;
404 for(irp = *(lirp = &itp->it_re); irp != NULL;
405 lirp = &irp->ir_next, irp = irp->ir_next)
406 if(!strcmp(field, irp->ir_input)){
407 *lirp = irp->ir_next;
408 if(irp == itp->it_re_tail)
409 itp->it_re_tail = irp->ir_next;
411 regfree(&irp->ir_regex);
412 if(!ip->i_auto)
413 n_free(irp);
414 --itp->it_count;
415 goto jleave;
417 }else
418 #endif /* HAVE_REGEX */
420 struct a_ignore_field **ifpp, *ifp;
421 ui32_t hi;
423 hi = n_torek_ihashn(field, UIZ_MAX) % n_NELEM(itp->it_ht);
425 for(ifp = *(ifpp = &itp->it_ht[hi]); ifp != NULL;
426 ifpp = &ifp->if_next, ifp = ifp->if_next)
427 if(!asccasecmp(ifp->if_field, field)){
428 *ifpp = ifp->if_next;
429 if(!ip->i_auto)
430 n_free(ifp);
431 --itp->it_count;
432 goto jleave;
436 ip = NULL;
437 jleave:
438 NYD_LEAVE;
439 return (ip != NULL);
442 FL int
443 c_headerpick(void *vp){
444 bool_t retain;
445 struct a_ignore_bltin_map const *ibmp;
446 char const **argv;
447 int rv;
448 NYD_ENTER;
450 rv = 1;
451 argv = vp;
453 /* Without arguments, show all settings of all contexts */
454 if(*argv == NULL){
455 rv = 0;
456 for(ibmp = &a_ignore_bltin_map[0];
457 ibmp <= &a_ignore_bltin_map[n__IGNORE_MAX]; ++ibmp){
458 rv |= !a_ignore_addcmd_mux(ibmp->ibm_ip, argv, TRU1);
459 rv |= !a_ignore_addcmd_mux(ibmp->ibm_ip, argv, FAL0);
461 goto jleave;
464 if((ibmp = a_ignore_resolve_bltin(*argv)) == NULL){
465 n_err(_("`headerpick': invalid context: %s\n"), *argv);
466 goto jleave;
468 ++argv;
470 /* With only <context>, show all settings of it */
471 if(*argv == NULL){
472 rv = 0;
473 rv |= !a_ignore_addcmd_mux(ibmp->ibm_ip, argv, TRU1);
474 rv |= !a_ignore_addcmd_mux(ibmp->ibm_ip, argv, FAL0);
475 goto jleave;
478 if(is_asccaseprefix(*argv, "retain"))
479 retain = TRU1;
480 else if(is_asccaseprefix(*argv, "ignore"))
481 retain = FAL0;
482 else{
483 n_err(_("`headerpick': invalid type (retain, ignore): %s\n"), *argv);
484 goto jleave;
486 ++argv;
488 /* With only <context> and <type>, show its settings */
489 if(*argv == NULL){
490 rv = !a_ignore_addcmd_mux(ibmp->ibm_ip, argv, retain);
491 goto jleave;
494 rv = !a_ignore_addcmd_mux(ibmp->ibm_ip, argv, retain);
495 jleave:
496 NYD_LEAVE;
497 return rv;
500 FL int
501 c_unheaderpick(void *vp){
502 bool_t retain;
503 struct a_ignore_bltin_map const *ibmp;
504 char const **argv;
505 int rv;
506 NYD_ENTER;
508 rv = 1;
509 argv = vp;
511 if((ibmp = a_ignore_resolve_bltin(*argv)) == NULL){
512 n_err(_("`unheaderpick': invalid context: %s\n"), *argv);
513 goto jleave;
515 ++argv;
517 if(is_asccaseprefix(*argv, "retain"))
518 retain = TRU1;
519 else if(is_asccaseprefix(*argv, "ignore"))
520 retain = FAL0;
521 else{
522 n_err(_("`unheaderpick': invalid type (retain, ignore): %s\n"), *argv);
523 goto jleave;
525 ++argv;
527 rv = !a_ignore_delcmd_mux(ibmp->ibm_ip, argv, retain);
528 jleave:
529 NYD_LEAVE;
530 return rv;
533 FL int
534 c_retain(void *vp){
535 int rv;
536 NYD_ENTER;
538 rv = !a_ignore_addcmd_mux(n_IGNORE_TYPE, vp, TRU1);
539 NYD_LEAVE;
540 return rv;
543 FL int
544 c_ignore(void *vp){
545 int rv;
546 NYD_ENTER;
548 rv = !a_ignore_addcmd_mux(n_IGNORE_TYPE, vp, FAL0);
549 NYD_LEAVE;
550 return rv;
553 FL int
554 c_unretain(void *vp){
555 int rv;
556 NYD_ENTER;
558 rv = !a_ignore_delcmd_mux(n_IGNORE_TYPE, vp, TRU1);
559 NYD_LEAVE;
560 return rv;
563 FL int
564 c_unignore(void *vp){
565 int rv;
566 NYD_ENTER;
568 rv = !a_ignore_delcmd_mux(n_IGNORE_TYPE, vp, FAL0);
569 NYD_LEAVE;
570 return rv;
573 FL int
574 c_saveretain(void *v){ /* TODO v15 drop */
575 int rv;
576 NYD_ENTER;
578 rv = !a_ignore_addcmd_mux(n_IGNORE_SAVE, v, TRU1);
579 NYD_LEAVE;
580 return rv;
583 FL int
584 c_saveignore(void *v){ /* TODO v15 drop */
585 int rv;
586 NYD_ENTER;
588 rv = !a_ignore_addcmd_mux(n_IGNORE_SAVE, v, FAL0);
589 NYD_LEAVE;
590 return rv;
593 FL int
594 c_unsaveretain(void *v){ /* TODO v15 drop */
595 int rv;
596 NYD_ENTER;
598 rv = !a_ignore_delcmd_mux(n_IGNORE_SAVE, v, TRU1);
599 NYD_LEAVE;
600 return rv;
603 FL int
604 c_unsaveignore(void *v){ /* TODO v15 drop */
605 int rv;
606 NYD_ENTER;
608 rv = !a_ignore_delcmd_mux(n_IGNORE_SAVE, v, FAL0);
609 NYD_LEAVE;
610 return rv;
613 FL int
614 c_fwdretain(void *v){ /* TODO v15 drop */
615 int rv;
616 NYD_ENTER;
618 rv = !a_ignore_addcmd_mux(n_IGNORE_FWD, v, TRU1);
619 NYD_LEAVE;
620 return rv;
623 FL int
624 c_fwdignore(void *v){ /* TODO v15 drop */
625 int rv;
626 NYD_ENTER;
628 rv = !a_ignore_addcmd_mux(n_IGNORE_FWD, v, FAL0);
629 NYD_LEAVE;
630 return rv;
633 FL int
634 c_unfwdretain(void *v){ /* TODO v15 drop */
635 int rv;
636 NYD_ENTER;
638 rv = !a_ignore_delcmd_mux(n_IGNORE_FWD, v, TRU1);
639 NYD_LEAVE;
640 return rv;
643 FL int
644 c_unfwdignore(void *v){ /* TODO v15 drop */
645 int rv;
646 NYD_ENTER;
648 rv = !a_ignore_delcmd_mux(n_IGNORE_FWD, v, FAL0);
649 NYD_LEAVE;
650 return rv;
653 FL struct n_ignore *
654 n_ignore_new(bool_t isauto){
655 struct n_ignore *self;
656 NYD_ENTER;
658 self = isauto ? n_autorec_calloc(1, sizeof *self) : n_calloc(1,sizeof *self);
659 self->i_auto = isauto;
660 NYD_LEAVE;
661 return self;
664 FL void
665 n_ignore_del(struct n_ignore *self){
666 NYD_ENTER;
667 a_ignore_del_allof(self, TRU1);
668 a_ignore_del_allof(self, FAL0);
669 if(!self->i_auto)
670 n_free(self);
671 NYD_LEAVE;
674 FL bool_t
675 n_ignore_is_any(struct n_ignore const *self){
676 bool_t rv;
677 NYD_ENTER;
679 self = a_ignore_resolve_self(n_UNCONST(self), FAL0);
680 rv = (self != NULL &&
681 (self->i_retain.it_count != 0 || self->i_retain.it_all ||
682 self->i_ignore.it_count != 0 || self->i_ignore.it_all));
683 NYD_LEAVE;
684 return rv;
687 FL bool_t
688 n_ignore_insert(struct n_ignore *self, bool_t retain,
689 char const *dat, size_t len){
690 #ifdef HAVE_REGEX
691 struct a_ignore_re *irp;
692 bool_t isre;
693 #endif
694 struct a_ignore_field *ifp;
695 struct a_ignore_type *itp;
696 bool_t rv;
697 NYD_ENTER;
699 retain = !!retain; /* Make it true bool, TRUM1 has special _lookup meaning */
700 rv = FAL0;
701 self = a_ignore_resolve_self(self, TRU1);
703 if(len == UIZ_MAX)
704 len = strlen(dat);
706 /* Request to ignore or retain _anything_? That is special-treated */
707 if(len == 1 && dat[0] == '*'){
708 itp = retain ? &self->i_retain : &self->i_ignore;
709 if(itp->it_all)
710 rv = TRUM1;
711 else{
712 itp->it_all = TRU1;
713 a_ignore_del_allof(self, retain);
714 rv = TRU1;
716 goto jleave;
719 /* Check for regular expression or valid fieldname */
720 #ifdef HAVE_REGEX
721 if(!(isre = n_is_maybe_regex_buf(dat, len)))
722 #endif
724 char c;
725 size_t i;
727 for(i = 0; i < len; ++i){
728 c = dat[i];
729 if(!fieldnamechar(c))
730 goto jleave;
734 rv = TRUM1;
735 if(a_ignore_lookup(self, retain, dat, len) == (retain ? TRU1 : TRUM1))
736 goto jleave;
738 itp = retain ? &self->i_retain : &self->i_ignore;
740 if(itp->it_count == UI32_MAX){
741 n_err(_("Header selection size limit reached, cannot insert: %.*s\n"),
742 (int)n_MIN(len, SI32_MAX), dat);
743 rv = FAL0;
744 goto jleave;
747 rv = TRU1;
748 #ifdef HAVE_REGEX
749 if(isre){
750 struct a_ignore_re *x;
751 int s;
752 size_t i;
754 i = n_VSTRUCT_SIZEOF(struct a_ignore_re, ir_input) + ++len;
755 irp = self->i_auto ? n_autorec_alloc(i) : n_alloc(i);
756 memcpy(irp->ir_input, dat, --len);
757 irp->ir_input[len] = '\0';
759 if((s = regcomp(&irp->ir_regex, irp->ir_input,
760 REG_EXTENDED | REG_ICASE | REG_NOSUB)) != 0){
761 n_err(_("Invalid regular expression: %s: %s\n"),
762 n_shexp_quote_cp(irp->ir_input, FAL0),
763 n_regex_err_to_doc(NULL, s));
764 if(!self->i_auto)
765 n_free(irp);
766 rv = FAL0;
767 goto jleave;
770 irp->ir_next = NULL;
771 if((x = itp->it_re_tail) != NULL)
772 x->ir_next = irp;
773 else
774 itp->it_re = irp;
775 itp->it_re_tail = irp;
776 }else
777 #endif /* HAVE_REGEX */
779 ui32_t hi;
780 size_t i;
782 i = n_VSTRUCT_SIZEOF(struct a_ignore_field, if_field) + len + 1;
783 ifp = self->i_auto ? n_autorec_alloc(i) : n_alloc(i);
784 memcpy(ifp->if_field, dat, len);
785 ifp->if_field[len] = '\0';
786 hi = n_torek_ihashn(dat, len) % n_NELEM(itp->it_ht);
787 ifp->if_next = itp->it_ht[hi];
788 itp->it_ht[hi] = ifp;
790 ++itp->it_count;
791 jleave:
792 NYD_LEAVE;
793 return rv;
796 FL bool_t
797 n_ignore_lookup(struct n_ignore const *self, char const *dat, size_t len){
798 bool_t rv;
799 NYD_ENTER;
801 if(self == n_IGNORE_ALL)
802 rv = TRUM1;
803 else if(len == 0 ||
804 (self = a_ignore_resolve_self(n_UNCONST(self), FAL0)) == NULL)
805 rv = FAL0;
806 else if(self->i_retain.it_all)
807 rv = TRU1;
808 else if(self->i_retain.it_count == 0 && self->i_ignore.it_all)
809 rv = TRUM1;
810 else
811 rv = a_ignore_lookup(self, TRUM1, dat, len);
812 NYD_LEAVE;
813 return rv;
816 /* s-it-mode */