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