]> diplodocus.org Git - nmh/blob - uip/picksbr.c
decode_rfc2047(): Stop unused-variable warning if HAVE_ICONV false.
[nmh] / uip / picksbr.c
1 /* picksbr.c -- routines to help pick along...
2 *
3 * This code is Copyright (c) 2002, by the authors of nmh. See the
4 * COPYRIGHT file in the root directory of the nmh distribution for
5 * complete copyright information.
6 */
7
8 #include "h/mh.h"
9 #include "picksbr.h"
10 #include "sbr/dtime.h"
11 #include "sbr/dtime.h"
12 #include "sbr/m_getfld.h"
13 #include "sbr/smatch.h"
14 #include "sbr/fmt_rfc2047.h"
15 #include "sbr/brkstring.h"
16 #include "sbr/ambigsw.h"
17 #include "sbr/error.h"
18 #include "h/tws.h"
19 #include "h/utils.h"
20
21 #ifdef HAVE_SYS_TIME_H
22 # include <sys/time.h>
23 #endif
24 #include <time.h>
25
26 #define PARSE_SWITCHES \
27 X("and", 0, PRAND) \
28 X("or", 0, PROR) \
29 X("not", 0, PRNOT) \
30 X("lbrace", 0, PRLBR) \
31 X("rbrace", 0, PRRBR) \
32 X("cc pattern", 0, PRCC) \
33 X("date pattern", 0, PRDATE) \
34 X("from pattern", 0, PRFROM) \
35 X("search pattern", 0, PRSRCH) \
36 X("subject pattern", 0, PRSUBJ) \
37 X("to pattern", 0, PRTO) \
38 X("-othercomponent pattern", 15, PROTHR) \
39 X("after date", 0, PRAFTR) \
40 X("before date", 0, PRBEFR) \
41 X("datefield field", 5, PRDATF) \
42
43 #define X(sw, minchars, id) id,
44 DEFINE_SWITCH_ENUM(PARSE);
45 #undef X
46
47 #define X(sw, minchars, id) { sw, minchars, id },
48 DEFINE_SWITCH_ARRAY(PARSE, parswit);
49 #undef X
50
51 /* DEFINITIONS FOR PATTERN MATCHING */
52
53 /*
54 * We really should be using re_comp() and re_exec() here. Unfortunately,
55 * pick advertises that lowercase characters matches characters of both
56 * cases. Since re_exec() doesn't exhibit this behavior, we are stuck
57 * with this version. Furthermore, we need to be able to save and restore
58 * the state of the pattern matcher in order to do things "efficiently".
59 *
60 * The matching power of this algorithm isn't as powerful as the re_xxx()
61 * routines (no \(xxx\) and \n constructs). Such is life.
62 */
63
64 #define CCHR 2
65 #define CDOT 4
66 #define CCL 6
67 #define NCCL 8
68 #define CDOL 10
69 #define CEOF 11
70
71 #define STAR 01
72
73 #define LBSIZE NMH_BUFSIZ
74 #define ESIZE 1024
75
76
77 static char linebuf[LBSIZE + 1];
78 static char decoded_linebuf[LBSIZE + 1];
79
80 /* the magic array for case-independence */
81 static unsigned char cc[] = {
82 0000,0001,0002,0003,0004,0005,0006,0007,
83 0010,0011,0012,0013,0014,0015,0016,0017,
84 0020,0021,0022,0023,0024,0025,0026,0027,
85 0030,0031,0032,0033,0034,0035,0036,0037,
86 0040,0041,0042,0043,0044,0045,0046,0047,
87 0050,0051,0052,0053,0054,0055,0056,0057,
88 0060,0061,0062,0063,0064,0065,0066,0067,
89 0070,0071,0072,0073,0074,0075,0076,0077,
90 0100,0141,0142,0143,0144,0145,0146,0147,
91 0150,0151,0152,0153,0154,0155,0156,0157,
92 0160,0161,0162,0163,0164,0165,0166,0167,
93 0170,0171,0172,0133,0134,0135,0136,0137,
94 0140,0141,0142,0143,0144,0145,0146,0147,
95 0150,0151,0152,0153,0154,0155,0156,0157,
96 0160,0161,0162,0163,0164,0165,0166,0167,
97 0170,0171,0172,0173,0174,0175,0176,0177,
98
99 0200,0201,0202,0203,0204,0205,0206,0207,
100 0210,0211,0212,0213,0214,0215,0216,0217,
101 0220,0221,0222,0223,0224,0225,0226,0227,
102 0230,0231,0232,0233,0234,0235,0236,0237,
103 0240,0241,0242,0243,0244,0245,0246,0247,
104 0250,0251,0252,0253,0254,0255,0256,0257,
105 0260,0261,0262,0263,0264,0265,0266,0267,
106 0270,0271,0272,0273,0274,0275,0276,0277,
107 0300,0301,0302,0303,0304,0305,0306,0307,
108 0310,0311,0312,0313,0314,0315,0316,0317,
109 0320,0321,0322,0323,0324,0325,0326,0327,
110 0330,0331,0332,0333,0334,0335,0336,0337,
111 0340,0341,0342,0343,0344,0345,0346,0347,
112 0350,0351,0352,0353,0354,0355,0356,0357,
113 0360,0361,0362,0363,0364,0365,0366,0367,
114 0370,0371,0372,0373,0374,0375,0376,0377,
115 };
116
117 /*
118 * DEFINITIONS FOR NEXUS
119 */
120
121 #define nxtarg() (*argp ? *argp++ : NULL)
122 #define prvarg() argp--
123
124 #define pinform if (!talked++) inform
125
126 struct nexus {
127 int (*n_action)(struct nexus *n, FILE *fp, int msgnum, long start, long stop);
128
129 union {
130 /* for {OR,AND,NOT}action */
131 struct {
132 struct nexus *un_L_child;
133 struct nexus *un_R_child;
134 } st1;
135
136 /* for GREPaction */
137 struct {
138 int un_header;
139 int un_circf;
140 char un_expbuf[ESIZE];
141 char *un_patbuf;
142 } st2;
143
144 /* for TWSaction */
145 struct {
146 char *un_datef;
147 int un_after;
148 struct tws un_tws;
149 } st3;
150 } un;
151 };
152
153 #define n_L_child un.st1.un_L_child
154 #define n_R_child un.st1.un_R_child
155
156 #define n_header un.st2.un_header
157 #define n_circf un.st2.un_circf
158 #define n_expbuf un.st2.un_expbuf
159 #define n_patbuf un.st2.un_patbuf
160
161 #define n_datef un.st3.un_datef
162 #define n_after un.st3.un_after
163 #define n_tws un.st3.un_tws
164
165 static int talked;
166
167 static char *datesw;
168 static char **argp;
169
170 static struct nexus *head;
171
172 /*
173 * prototypes for date routines
174 */
175 static struct tws *tws_parse(char *, int);
176 static struct tws *tws_special(char *);
177
178 /*
179 * static prototypes
180 */
181 static void PRaction(struct nexus *, int);
182 static int gcompile(struct nexus *, char *);
183 static int advance(char *, char *);
184 static int cclass(unsigned char *, int, int);
185 static int tcompile(char *, struct tws *, int);
186
187 static struct nexus *parse(void);
188 static struct nexus *nexp1(void);
189 static struct nexus *nexp2(void);
190 static struct nexus *nexp3(void);
191 static struct nexus *newnexus(int (*action)(struct nexus *n,
192 FILE *fp, int msgnum, long start, long stop));
193
194 static int ORaction(struct nexus *n, FILE *fp, int msgnum,
195 long start, long stop);
196 static int ANDaction(struct nexus *n, FILE *fp, int msgnum,
197 long start, long stop);
198 static int NOTaction(struct nexus *n, FILE *fp, int msgnum,
199 long start, long stop);
200 static int GREPaction(struct nexus *n, FILE *fp, int msgnum,
201 long start, long stop);
202 static int TWSaction(struct nexus *n, FILE *fp, int msgnum,
203 long start, long stop);
204
205
206 int
207 pcompile (char **vec, char *date)
208 {
209 argp = vec;
210 if ((datesw = date) == NULL)
211 datesw = "date";
212 talked = 0;
213
214 if ((head = parse ()) == NULL)
215 return !talked;
216
217 if (*argp) {
218 inform("%s unexpected", *argp);
219 return 0;
220 }
221
222 return 1;
223 }
224
225
226 static struct nexus *
227 parse (void)
228 {
229 char *cp;
230 struct nexus *n, *o;
231
232 if ((n = nexp1 ()) == NULL || (cp = nxtarg ()) == NULL)
233 return n;
234
235 if (*cp != '-') {
236 pinform("%s unexpected", cp);
237 return NULL;
238 }
239
240 if (*++cp == '-')
241 goto header;
242 switch (smatch (cp, parswit)) {
243 case AMBIGSW:
244 ambigsw (cp, parswit);
245 talked++;
246 return NULL;
247 case UNKWNSW:
248 fprintf (stderr, "-%s unknown\n", cp);
249 talked++;
250 return NULL;
251
252 case PROR:
253 o = newnexus (ORaction);
254 o->n_L_child = n;
255 if ((o->n_R_child = parse ()))
256 return o;
257 pinform("missing disjunctive");
258 free (o);
259 return NULL;
260
261 header: ;
262 default:
263 prvarg ();
264 return n;
265 }
266 }
267
268 static struct nexus *
269 nexp1 (void)
270 {
271 char *cp;
272 struct nexus *n, *o;
273
274 if ((n = nexp2 ()) == NULL || (cp = nxtarg ()) == NULL)
275 return n;
276
277 if (*cp != '-') {
278 pinform("%s unexpected", cp);
279 free (n);
280 return NULL;
281 }
282
283 if (*++cp == '-')
284 goto header;
285 switch (smatch (cp, parswit)) {
286 case AMBIGSW:
287 ambigsw (cp, parswit);
288 talked++;
289 free (n);
290 return NULL;
291 case UNKWNSW:
292 fprintf (stderr, "-%s unknown\n", cp);
293 talked++;
294 free (n);
295 return NULL;
296
297 case PRAND:
298 o = newnexus (ANDaction);
299 o->n_L_child = n;
300 if ((o->n_R_child = nexp1 ()))
301 return o;
302 pinform("missing conjunctive");
303 free (o);
304 return NULL;
305
306 header: ;
307 default:
308 prvarg ();
309 return n;
310 }
311 }
312
313
314 static struct nexus *
315 nexp2 (void)
316 {
317 char *cp;
318 struct nexus *n;
319
320 if ((cp = nxtarg ()) == NULL)
321 return NULL;
322
323 if (*cp != '-') {
324 prvarg ();
325 return nexp3 ();
326 }
327
328 if (*++cp == '-')
329 goto header;
330 switch (smatch (cp, parswit)) {
331 case AMBIGSW:
332 ambigsw (cp, parswit);
333 talked++;
334 return NULL;
335 case UNKWNSW:
336 fprintf (stderr, "-%s unknown\n", cp);
337 talked++;
338 return NULL;
339
340 case PRNOT:
341 n = newnexus (NOTaction);
342 if ((n->n_L_child = nexp3 ()))
343 return n;
344 pinform("missing negation");
345 free (n);
346 return NULL;
347
348 header: ;
349 default:
350 prvarg ();
351 return nexp3 ();
352 }
353 }
354
355 static struct nexus *
356 nexp3 (void)
357 {
358 int i;
359 char *cp, *dp;
360 char buffer[BUFSIZ], temp[64];
361 struct nexus *n;
362
363 if ((cp = nxtarg ()) == NULL)
364 return NULL;
365
366 if (*cp != '-') {
367 pinform("%s unexpected", cp);
368 return NULL;
369 }
370
371 if (*++cp == '-') {
372 dp = ++cp;
373 goto header;
374 }
375 switch (i = smatch (cp, parswit)) {
376 case AMBIGSW:
377 ambigsw (cp, parswit);
378 talked++;
379 return NULL;
380 case UNKWNSW:
381 fprintf (stderr, "-%s unknown\n", cp);
382 talked++;
383 return NULL;
384
385 case PRLBR:
386 if ((n = parse ()) == NULL) {
387 pinform("missing group");
388 return NULL;
389 }
390 if ((cp = nxtarg ()) == NULL) {
391 pinform("missing -rbrace");
392 return NULL;
393 }
394 if (*cp++ == '-' && smatch (cp, parswit) == PRRBR)
395 return n;
396 pinform("%s unexpected", --cp);
397 return NULL;
398
399 default:
400 prvarg ();
401 return NULL;
402
403 case PRCC:
404 case PRDATE:
405 case PRFROM:
406 case PRTO:
407 case PRSUBJ:
408 strncpy(temp, parswit[i].sw, sizeof(temp));
409 temp[sizeof(temp) - 1] = '\0';
410 dp = *brkstring (temp, " ", NULL);
411 header: ;
412 if (!(cp = nxtarg ())) {/* allow -xyz arguments */
413 pinform("missing argument to %s", argp[-2]);
414 return NULL;
415 }
416 n = newnexus (GREPaction);
417 n->n_header = 1;
418 snprintf (buffer, sizeof(buffer), "^%s[ \t]*:.*%s", dp, cp);
419 dp = buffer;
420 goto pattern;
421
422 case PRSRCH:
423 n = newnexus (GREPaction);
424 n->n_header = 0;
425 if (!(cp = nxtarg ())) {/* allow -xyz arguments */
426 pinform("missing argument to %s", argp[-2]);
427 free (n);
428 return NULL;
429 }
430 dp = cp;
431 pattern: ;
432 if (!gcompile (n, dp)) {
433 pinform("pattern error in %s %s", argp[-2], cp);
434 free (n);
435 return NULL;
436 }
437 n->n_patbuf = mh_xstrdup(dp);
438 return n;
439
440 case PROTHR:
441 pinform("internal error!");
442 return NULL;
443
444 case PRDATF:
445 if (!(datesw = nxtarg ()) || *datesw == '-') {
446 pinform("missing argument to %s", argp[-2]);
447 return NULL;
448 }
449 return nexp3 ();
450
451 case PRAFTR:
452 case PRBEFR:
453 if (!(cp = nxtarg ())) {/* allow -xyz arguments */
454 pinform("missing argument to %s", argp[-2]);
455 return NULL;
456 }
457 n = newnexus (TWSaction);
458 n->n_datef = datesw;
459 if (!tcompile (cp, &n->n_tws, n->n_after = i == PRAFTR)) {
460 pinform("unable to parse %s %s", argp[-2], cp);
461 free (n);
462 return NULL;
463 }
464 return n;
465 }
466 }
467
468
469 static struct nexus *
470 newnexus(int (*action)(struct nexus *n, FILE *fp, int msgnum,
471 long start, long stop))
472 {
473 struct nexus *p;
474
475 NEW0(p);
476 p->n_action = action;
477 return p;
478 }
479
480
481 int
482 pmatches (FILE *fp, int msgnum, long start, long stop, int debug)
483 {
484 if (!head)
485 return 1;
486
487 if (!talked++ && debug)
488 PRaction (head, 0);
489
490 return (*head->n_action)(head, fp, msgnum, start, stop);
491 }
492
493
494 static void
495 PRaction (struct nexus *n, int level)
496 {
497 int i;
498
499 for (i = 0; i < level; i++)
500 fprintf (stderr, "| ");
501
502 if (n->n_action == ORaction) {
503 fprintf (stderr, "OR\n");
504 PRaction (n->n_L_child, level + 1);
505 PRaction (n->n_R_child, level + 1);
506 return;
507 }
508 if (n->n_action == ANDaction) {
509 fprintf (stderr, "AND\n");
510 PRaction (n->n_L_child, level + 1);
511 PRaction (n->n_R_child, level + 1);
512 return;
513 }
514 if (n->n_action == NOTaction) {
515 fprintf (stderr, "NOT\n");
516 PRaction (n->n_L_child, level + 1);
517 return;
518 }
519 if (n->n_action == GREPaction) {
520 fprintf (stderr, "PATTERN(%s) %s\n",
521 n->n_header ? "header" : "body", n->n_patbuf);
522 return;
523 }
524 if (n->n_action == TWSaction) {
525 fprintf (stderr, "TEMPORAL(%s) %s: %s\n",
526 n->n_after ? "after" : "before", n->n_datef,
527 dasctime (&n->n_tws, TW_NULL));
528 return;
529 }
530
531 generic_pointer gp;
532 gp.f = (void (*)(void))n->n_action;
533 fprintf(stderr, "UNKNOWN(%p)\n", gp.v);
534 }
535
536
537 static int
538 ORaction(struct nexus *n, FILE *fp, int msgnum, long start, long stop)
539 {
540 if ((*n->n_L_child->n_action)(n->n_L_child, fp, msgnum, start, stop))
541 return 1;
542 return (*n->n_R_child->n_action)(n->n_R_child, fp, msgnum, start, stop);
543 }
544
545
546 static int
547 ANDaction(struct nexus *n, FILE *fp, int msgnum, long start, long stop)
548 {
549 if (!(*n->n_L_child->n_action)(n->n_L_child, fp, msgnum, start, stop))
550 return 0;
551 return (*n->n_R_child->n_action)(n->n_R_child, fp, msgnum, start, stop);
552 }
553
554
555 static int
556 NOTaction(struct nexus *n, FILE *fp, int msgnum, long start, long stop)
557 {
558 return (!(*n->n_L_child->n_action)(n->n_L_child, fp, msgnum, start, stop));
559 }
560
561
562 static int
563 gcompile (struct nexus *n, char *astr)
564 {
565 int c;
566 int cclcnt;
567 unsigned char *ep, *dp, *sp, *lastep = 0;
568
569 dp = (ep = (unsigned char *) n->n_expbuf) + sizeof n->n_expbuf;
570 sp = (unsigned char *) astr;
571 if (*sp == '^') {
572 n->n_circf = 1;
573 sp++;
574 }
575 else
576 n->n_circf = 0;
577 for (;;) {
578 if (ep >= dp)
579 goto cerror;
580 if ((c = *sp++) != '*')
581 lastep = ep;
582 switch (c) {
583 case '\0':
584 *ep++ = CEOF;
585 return 1;
586
587 case '.':
588 *ep++ = CDOT;
589 continue;
590
591 case '*':
592 if (lastep == 0)
593 goto defchar;
594 *lastep |= STAR;
595 continue;
596
597 case '$':
598 if (*sp != '\0')
599 goto defchar;
600 *ep++ = CDOL;
601 continue;
602
603 case '[':
604 *ep++ = CCL;
605 *ep++ = 0;
606 cclcnt = 0;
607 if ((c = *sp++) == '^') {
608 c = *sp++;
609 ep[-2] = NCCL;
610 }
611 if (c == '-') {
612 *ep++ = c;
613 cclcnt++;
614 c = *sp++;
615 }
616 do {
617 if (c == '-' && *sp != '\0' && *sp != ']') {
618 for (c = ep[-1]+1; c < *sp; c++) {
619 *ep++ = c;
620 cclcnt++;
621 if (c == '\0' || ep >= dp)
622 goto cerror;
623 }
624 } else {
625 *ep++ = c;
626 cclcnt++;
627 if (c == '\0' || ep >= dp)
628 goto cerror;
629 }
630 } while ((c = *sp++) != ']');
631 if (cclcnt > 255)
632 goto cerror;
633 lastep[1] = cclcnt;
634 continue;
635
636 case '\\':
637 if ((c = *sp++) == '\0')
638 goto cerror;
639 /* FALLTHRU */
640 defchar:
641 default:
642 *ep++ = CCHR;
643 *ep++ = c;
644 }
645 }
646
647 cerror: ;
648 return 0;
649 }
650
651
652 static int
653 GREPaction(struct nexus *n, FILE *fp, int msgnum, long start, long stop)
654 {
655 int c;
656 bool body;
657 bool lf;
658 long pos = start;
659 char *p1, *p2, *ebp, *cbp;
660 char ibuf[BUFSIZ];
661 NMH_UNUSED (msgnum);
662
663 fseek (fp, start, SEEK_SET);
664 body = false;
665 ebp = cbp = ibuf;
666 for (;;) {
667 if (body && n->n_header)
668 return 0;
669 p1 = linebuf;
670 p2 = cbp;
671 lf = false;
672 for (;;) {
673 if (p2 >= ebp) {
674 if (fgets (ibuf, sizeof ibuf, fp) == NULL
675 || (stop && pos >= stop)) {
676 if (lf)
677 break;
678 return 0;
679 }
680 pos += (long) strlen (ibuf);
681 p2 = ibuf;
682 ebp = ibuf + strlen (ibuf);
683 }
684 c = *p2++;
685 if (lf && c != '\n') {
686 if (c != ' ' && c != '\t') {
687 --p2;
688 break;
689 }
690 lf = false;
691 }
692 if (c == '\n') {
693 if (body)
694 break;
695 if (lf) {
696 body = true;
697 break;
698 }
699 lf = true;
700 /* Unfold by skipping the newline. */
701 c = 0;
702 }
703 if (c && p1 < &linebuf[LBSIZE - 1])
704 *p1++ = c;
705 }
706
707 *p1++ = 0;
708 cbp = p2;
709 p1 = linebuf;
710 p2 = n->n_expbuf;
711
712 /* Attempt to decode as a MIME header. If it's the last header,
713 body will be 1 and lf will be at least 1. */
714 if ((!body || lf) &&
715 decode_rfc2047 (linebuf, decoded_linebuf, sizeof decoded_linebuf)) {
716 p1 = decoded_linebuf;
717 }
718
719 if (n->n_circf) {
720 if (advance (p1, p2))
721 return 1;
722 continue;
723 }
724
725 if (*p2 == CCHR) {
726 c = p2[1];
727 do {
728 if (*p1 == c || cc[(unsigned char)*p1] == c)
729 if (advance (p1, p2))
730 return 1;
731 } while (*p1++);
732 continue;
733 }
734
735 do {
736 if (advance (p1, p2))
737 return 1;
738 } while (*p1++);
739 }
740 }
741
742
743 static int
744 advance (char *alp, char *aep)
745 {
746 unsigned char *lp, *ep, *curlp;
747
748 lp = (unsigned char *)alp;
749 ep = (unsigned char *)aep;
750 for (;;)
751 switch (*ep++) {
752 case CCHR:
753 if (*ep++ == *lp++ || ep[-1] == cc[lp[-1]])
754 continue;
755 return 0;
756
757 case CDOT:
758 if (*lp++)
759 continue;
760 return 0;
761
762 case CDOL:
763 if (*lp == 0)
764 continue;
765 return 0;
766
767 case CEOF:
768 return 1;
769
770 case CCL:
771 if (cclass (ep, *lp++, 1)) {
772 ep += *ep + 1;
773 continue;
774 }
775 return 0;
776
777 case NCCL:
778 if (cclass (ep, *lp++, 0)) {
779 ep += *ep + 1;
780 continue;
781 }
782 return 0;
783
784 case CDOT | STAR:
785 curlp = lp;
786 while (*lp++)
787 continue;
788 goto star;
789
790 case CCHR | STAR:
791 curlp = lp;
792 while (*lp++ == *ep || cc[lp[-1]] == *ep)
793 continue;
794 ep++;
795 goto star;
796
797 case CCL | STAR:
798 case NCCL | STAR:
799 curlp = lp;
800 while (cclass (ep, *lp++, ep[-1] == (CCL | STAR)))
801 continue;
802 ep += *ep + 1;
803 goto star;
804
805 star:
806 do {
807 lp--;
808 if (advance ((char *) lp, (char *) ep))
809 return 1;
810 } while (lp > curlp);
811 return 0;
812
813 default:
814 inform("advance() botch -- you lose big, continuing...");
815 return 0;
816 }
817 }
818
819
820 static int
821 cclass (unsigned char *aset, int ac, int af)
822 {
823 unsigned int n;
824 unsigned char c, *set;
825
826 set = aset;
827 if ((c = ac) == 0)
828 return 0;
829
830 n = *set++;
831 while (n--)
832 if (*set++ == c || set[-1] == cc[c])
833 return af;
834
835 return !af;
836 }
837
838
839 static int
840 tcompile (char *ap, struct tws *tb, int isafter)
841 {
842 struct tws *tw;
843
844 if ((tw = tws_parse (ap, isafter)) == NULL)
845 return 0;
846
847 *tb = *tw;
848 return 1;
849 }
850
851
852 static struct tws *
853 tws_parse (char *ap, int isafter)
854 {
855 char buffer[BUFSIZ];
856 struct tws *tw, *ts;
857
858 if ((tw = tws_special (ap)) != NULL) {
859 tw->tw_sec = tw->tw_min = isafter ? 59 : 0;
860 tw->tw_hour = isafter ? 23 : 0;
861 return tw;
862 }
863 if ((tw = dparsetime (ap)) != NULL)
864 return tw;
865
866 if ((ts = dlocaltimenow ()) == NULL)
867 return NULL;
868
869 snprintf (buffer, sizeof(buffer), "%s %s", ap, dtwszone (ts));
870 if ((tw = dparsetime (buffer)) != NULL)
871 return tw;
872
873 snprintf (buffer, sizeof(buffer), "%s %02d:%02d:%02d %s", ap,
874 ts->tw_hour, ts->tw_min, ts->tw_sec, dtwszone (ts));
875 if ((tw = dparsetime (buffer)) != NULL)
876 return tw;
877
878 snprintf (buffer, sizeof(buffer), "%02d %s %04d %s",
879 ts->tw_mday, tw_moty[ts->tw_mon], ts->tw_year, ap);
880 if ((tw = dparsetime (buffer)) != NULL)
881 return tw;
882
883 snprintf (buffer, sizeof(buffer), "%02d %s %04d %s %s",
884 ts->tw_mday, tw_moty[ts->tw_mon], ts->tw_year,
885 ap, dtwszone (ts));
886 if ((tw = dparsetime (buffer)) != NULL)
887 return tw;
888
889 return NULL;
890 }
891
892
893 static struct tws *
894 tws_special (char *ap)
895 {
896 int i;
897 time_t clock;
898 struct tws *tw;
899
900 time (&clock);
901 if (!strcasecmp (ap, "today"))
902 return dlocaltime (&clock);
903 if (!strcasecmp (ap, "yesterday")) {
904 clock -= (long) (60 * 60 * 24);
905 return dlocaltime (&clock);
906 }
907 if (!strcasecmp (ap, "tomorrow")) {
908 clock += (long) (60 * 60 * 24);
909 return dlocaltime (&clock);
910 }
911
912 for (i = 0; tw_ldotw[i]; i++)
913 if (!strcasecmp (ap, tw_ldotw[i]))
914 break;
915 if (tw_ldotw[i]) {
916 if ((tw = dlocaltime (&clock)) == NULL)
917 return NULL;
918 if ((i -= tw->tw_wday) > 0)
919 i -= 7;
920 }
921 else {
922 if (*ap != '-')
923 return NULL;
924 /* -ddd days ago */
925 i = atoi (ap); /* we should error check this */
926 }
927
928 clock += (long) ((60 * 60 * 24) * i);
929 return dlocaltime (&clock);
930 }
931
932
933 static int
934 TWSaction(struct nexus *n, FILE *fp, int msgnum, long start, long stop)
935 {
936 int state;
937 char *bp;
938 char buf[NMH_BUFSIZ], name[NAMESZ];
939 struct tws *tw;
940 m_getfld_state_t gstate;
941 NMH_UNUSED (stop);
942
943 fseek (fp, start, SEEK_SET);
944 gstate = m_getfld_state_init(fp);
945 for (bp = NULL;;) {
946 int bufsz = sizeof buf;
947 switch (state = m_getfld2(&gstate, name, buf, &bufsz)) {
948 case FLD:
949 case FLDPLUS:
950 free(bp);
951 bp = mh_xstrdup(buf);
952 while (state == FLDPLUS) {
953 bufsz = sizeof buf;
954 state = m_getfld2(&gstate, name, buf, &bufsz);
955 bp = add (buf, bp);
956 }
957 if (!strcasecmp (name, n->n_datef))
958 break;
959 continue;
960
961 case BODY:
962 case FILEEOF:
963 case LENERR:
964 case FMTERR:
965 if (state == LENERR || state == FMTERR)
966 inform("format error in message %d", msgnum);
967 free(bp);
968 return 0;
969
970 default:
971 die("internal error -- you lose");
972 }
973 break;
974 }
975 m_getfld_state_destroy (&gstate);
976
977 if ((tw = dparsetime (bp)) == NULL)
978 inform("unable to parse %s field in message %d, matching...",
979 n->n_datef, msgnum), state = 1;
980 else
981 state = n->n_after ? (twsort (tw, &n->n_tws) > 0)
982 : (twsort (tw, &n->n_tws) < 0);
983
984 free(bp);
985 return state;
986 }