Make combinetime() overflow safe (Vincent Lefevre)..
[s-mailx.git] / ignoretab.c
blobb813689f597059fc07611e9750710e37acc81096
1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ `ignore' and `retain' lists of all sort.
3 *@ XXX Should these be in nam_a_grp.c?!
5 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
6 * Copyright (c) 2012 - 2016 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
7 */
8 /*
9 * Copyright (c) 1980, 1993
10 * The Regents of the University of California. All rights reserved.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
36 #undef n_FILE
37 #define n_FILE ignoretab
39 #ifndef HAVE_AMALGAMATION
40 # include "nail.h"
41 #endif
43 /* Add a list of fields to be ignored or retained */
44 static bool_t a_ignoretab_insert(char const **list, struct ignoretab *itp,
45 bool_t ignorret);
47 static void a_ignoretab__show(struct ignoretab *itp, bool_t ignorret);
48 static int a_ignoretab__cmp(void const *l, void const *r);
50 /* Delete a list of fields from an ignored or retained list) */
51 static bool_t a_ignoretab_del(char const **list, struct ignoretab *itp,
52 bool_t ignorret);
54 static void a_ignoretab__delall(struct ignoretab *itp);
55 static bool_t a_ignoretab__del(struct ignoretab *itp, char const *name);
57 static bool_t
58 a_ignoretab_insert(char const **list, struct ignoretab *itp, bool_t ignorret){
59 char const **ap;
60 bool_t rv;
61 NYD2_ENTER;
63 rv = TRU1;
65 if(*list == NULL)
66 a_ignoretab__show(itp, ignorret);
67 else{
68 for(ap = list; *ap != 0; ++ap)
69 switch(n_ignoretab_insert_cp(itp, *ap)){
70 case FAL0:
71 n_err(_("Invalid field name cannot be %s: %s\n"),
72 (ignorret ? _("ignored") : _("retained")), *ap);
73 rv = FAL0;
74 break;
75 case TRUM1:
76 if(options & OPT_D_V)
77 n_err(_("Field already %s: %s\n"),
78 (ignorret ? _("ignored") : _("retained")), *ap);
79 /* FALLTHRU */
80 case TRU1:
81 break;
84 NYD2_LEAVE;
85 return rv;
88 static void
89 a_ignoretab__show(struct ignoretab *itp, bool_t ignorret){
90 struct n_ignoretab_field *itfp;
91 size_t i, sw;
92 char const **ap, **ring;
93 NYD2_ENTER;
95 if(itp->it_count == 0){
96 printf(_("No fields currently being %s\n"),
97 (ignorret ? _("ignored") : _("retained")));
98 goto jleave;
101 ring = salloc((itp->it_count +1) * sizeof *ring);
102 for(ap = ring, i = 0; i < NELEM(itp->it_head); ++i)
103 for(itfp = itp->it_head[i]; itfp != NULL; itfp = itfp->itf_next)
104 *ap++ = itfp->itf_field;
105 *ap = NULL;
107 qsort(ring, itp->it_count, sizeof *ring, &a_ignoretab__cmp);
109 for(sw = scrnwidth, i = 0, ap = ring; *ap != NULL; ++ap){
110 /* These fields are all ASCII */
111 size_t len;
112 char const *pref;
114 pref = " ";
115 len = strlen(*ap) + 2;
116 if(UICMP(z, len, >=, sw - i)){
117 putchar('\n');
118 i = 2;
119 }else if(i == 0)
120 pref = "";
121 i += len;
122 printf("%s%s", pref, *ap);
124 if(i > 0){
125 putchar('\n');
126 fflush(stdout);
128 jleave:
129 NYD2_LEAVE;
132 static int
133 a_ignoretab__cmp(void const *l, void const *r){
134 int rv;
136 rv = asccasecmp(*(char const * const *)l, *(char const * const *)r);
137 return rv;
140 static bool_t
141 a_ignoretab_del(char const **list, struct ignoretab *itp, bool_t ignorret){
142 char const *cp;
143 bool_t rv;
144 NYD2_ENTER;
146 rv = TRU1;
148 if(itp->it_count == 0)
149 printf(_("No fields currently being %s\n"),
150 (ignorret ? _("ignored") : _("retained")));
151 else
152 while((cp = *list++) != NULL)
153 if(cp[0] == '*' && cp[1] == '\0')
154 a_ignoretab__delall(itp);
155 else if(!a_ignoretab__del(itp, cp)){
156 n_err(_("Field not %s: %s\n"),
157 (ignorret ? _("ignored") : _("retained")), cp);
158 rv = FAL0;
160 NYD2_LEAVE;
161 return rv;
164 static void
165 a_ignoretab__delall(struct ignoretab *itp){
166 size_t i;
167 struct n_ignoretab_field *itfp, *x;
168 bool_t isauto;
169 NYD2_ENTER;
171 if(!(isauto = itp->it_auto))
172 for(i = 0; i < NELEM(itp->it_head); ++i)
173 for(itfp = itp->it_head[i]; itfp != NULL; itfp = x){
174 x = itfp->itf_next;
175 free(itfp);
178 memset(itp, 0, sizeof *itp);
179 itp->it_auto = isauto;
180 NYD2_LEAVE;
183 static bool_t
184 a_ignoretab__del(struct ignoretab *itp, char const *name){
185 struct n_ignoretab_field **itfpp, *itfp;
186 ui32_t h;
187 NYD_ENTER;
189 h = torek_ihashn(name, UIZ_MAX) % NELEM(itp->it_head);
191 for(itfp = *(itfpp = &itp->it_head[h]); itfp != NULL;
192 itfpp = &itfp->itf_next, itfp = itfp->itf_next)
193 if(!asccasecmp(itfp->itf_field, name)){
194 --itp->it_count;
195 *itfpp = itfp->itf_next;
196 if(!itp->it_auto)
197 free(itfp);
198 break;
200 NYD_LEAVE;
201 return (itfp != NULL);
204 FL int
205 c_retfield(void *v){
206 int rv;
207 NYD_ENTER;
209 rv = !a_ignoretab_insert(v, &ignore[1], FAL0);
210 NYD_LEAVE;
211 return rv;
214 FL int
215 c_igfield(void *v){
216 int rv;
217 NYD_ENTER;
219 rv = !a_ignoretab_insert(v, &ignore[0], TRU1);
220 NYD_LEAVE;
221 return rv;
224 FL int
225 c_saveretfield(void *v){
226 int rv;
227 NYD_ENTER;
229 rv = !a_ignoretab_insert(v, &saveignore[1], FAL0);
230 NYD_LEAVE;
231 return rv;
234 FL int
235 c_saveigfield(void *v){
236 int rv;
237 NYD_ENTER;
239 rv = !a_ignoretab_insert(v, &saveignore[0], TRU1);
240 NYD_LEAVE;
241 return rv;
244 FL int
245 c_fwdretfield(void *v){
246 int rv;
247 NYD_ENTER;
249 rv = !a_ignoretab_insert(v, &fwdignore[1], FAL0);
250 NYD_LEAVE;
251 return rv;
254 FL int
255 c_fwdigfield(void *v){
256 int rv;
257 NYD_ENTER;
259 rv = !a_ignoretab_insert(v, &fwdignore[0], TRU1);
260 NYD_LEAVE;
261 return rv;
264 FL int
265 c_unignore(void *v){
266 int rv;
267 NYD_ENTER;
269 rv = !a_ignoretab_del(v, &ignore[0], TRU1);
270 NYD_LEAVE;
271 return rv;
274 FL int
275 c_unretain(void *v){
276 int rv;
277 NYD_ENTER;
279 rv = !a_ignoretab_del(v, &ignore[1], FAL0);
280 NYD_LEAVE;
281 return rv;
284 FL int
285 c_unsaveignore(void *v){
286 int rv;
287 NYD_ENTER;
289 rv = !a_ignoretab_del(v, &saveignore[0], TRU1);
290 NYD_LEAVE;
291 return rv;
294 FL int
295 c_unsaveretain(void *v){
296 int rv;
297 NYD_ENTER;
299 rv = !a_ignoretab_del(v, &saveignore[1], FAL0);
300 NYD_LEAVE;
301 return rv;
304 FL int
305 c_unfwdignore(void *v){
306 int rv;
307 NYD_ENTER;
309 rv = !a_ignoretab_del(v, &fwdignore[0], TRU1);
310 NYD_LEAVE;
311 return rv;
314 FL int
315 c_unfwdretain(void *v){
316 int rv;
317 NYD_ENTER;
319 rv = !a_ignoretab_del(v, &fwdignore[1], FAL0);
320 NYD_LEAVE;
321 return rv;
324 FL int
325 is_ign(char const *field, size_t fieldlen, struct ignoretab igta[2]){
326 bool_t b;
327 int rv;
328 NYD_ENTER;
330 rv = 0;
331 if(igta == NULL)
332 goto jleave;
333 rv = 1;
334 if(igta == allignore)
335 goto jleave;
337 b = (igta[1].it_count > 0);
338 rv = n_ignoretab_lookup((b ? &igta[1] : &igta[0]), field, fieldlen);
339 if(b)
340 rv = !rv;
341 jleave:
342 NYD_LEAVE;
343 return rv;
346 FL struct ignoretab *
347 n_ignoretab_creat(struct ignoretab *self, bool_t isauto){
348 NYD_ENTER;
349 memset(self, 0, sizeof *self);
350 self->it_auto = isauto;
351 NYD_LEAVE;
352 return self;
355 FL void
356 n_ignoretab_gut(struct ignoretab *self){
357 NYD_ENTER;
358 if(!self->it_auto && self->it_count > 0)
359 a_ignoretab__delall(self);
360 NYD_LEAVE;
363 FL bool_t
364 n_ignoretab_insert(struct ignoretab *self, char const *dat, size_t len){
365 struct n_ignoretab_field *itfp;
366 ui32_t h;
367 bool_t rv;
368 NYD_ENTER;
370 /* Detect length as necessary, check for valid fieldname */
371 rv = FAL0;
372 if(len == UIZ_MAX){
373 char c;
375 for(len = 0; (c = dat[len]) != '\0'; ++len)
376 if(!fieldnamechar(c))
377 goto jleave;
378 }else if(len == 0)
379 goto jleave;
380 else{
381 char c;
382 size_t i;
384 for(i = 0; i < len; ++i){
385 c = dat[i];
386 if(!fieldnamechar(c))
387 goto jleave;
391 rv = TRUM1;
392 if(n_ignoretab_lookup(self, dat, len))
393 goto jleave;
394 else if(self->it_count == UI32_MAX){
395 n_err(_("Hashtable size limit reached. Cannot insert: %.*s\n"),
396 (int)MIN(len, SI32_MAX), dat);
397 goto jleave;
400 ++len;
401 /* C99 */{
402 size_t i;
404 i = sizeof(*itfp)-VFIELD_SIZEOF(struct n_ignoretab_field,itf_field) + len;
405 itfp = self->it_auto ? salloc(i) : smalloc(i);
407 --len;
408 memcpy(itfp->itf_field, dat, len);
409 itfp->itf_field[len] = '\0';
410 h = torek_ihashn(dat, len) % NELEM(self->it_head);
411 itfp->itf_next = self->it_head[h];
412 self->it_head[h] = itfp;
413 ++self->it_count;
414 rv = TRU1;
415 jleave:
416 NYD_LEAVE;
417 return rv;
420 FL bool_t
421 n_ignoretab_lookup(struct ignoretab *self, char const *dat, size_t len){
422 struct n_ignoretab_field *itfp;
423 NYD_ENTER;
425 if(len == UIZ_MAX)
426 len = strlen(dat);
428 for(itfp = self->it_head[torek_ihashn(dat, len) % NELEM(self->it_head)];
429 itfp != NULL; itfp = itfp->itf_next)
430 if(!ascncasecmp(itfp->itf_field, dat, len))
431 break;
432 NYD_LEAVE;
433 return (itfp != NULL);
436 /* s-it-mode */