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