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