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