]> diplodocus.org Git - nmh/blob - uip/picksbr.c
With -messageid random, make the part after the @ more resemble a
[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
82 /* the magic array for case-independence */
83 static unsigned char cc[] = {
84 0000,0001,0002,0003,0004,0005,0006,0007,
85 0010,0011,0012,0013,0014,0015,0016,0017,
86 0020,0021,0022,0023,0024,0025,0026,0027,
87 0030,0031,0032,0033,0034,0035,0036,0037,
88 0040,0041,0042,0043,0044,0045,0046,0047,
89 0050,0051,0052,0053,0054,0055,0056,0057,
90 0060,0061,0062,0063,0064,0065,0066,0067,
91 0070,0071,0072,0073,0074,0075,0076,0077,
92 0100,0141,0142,0143,0144,0145,0146,0147,
93 0150,0151,0152,0153,0154,0155,0156,0157,
94 0160,0161,0162,0163,0164,0165,0166,0167,
95 0170,0171,0172,0133,0134,0135,0136,0137,
96 0140,0141,0142,0143,0144,0145,0146,0147,
97 0150,0151,0152,0153,0154,0155,0156,0157,
98 0160,0161,0162,0163,0164,0165,0166,0167,
99 0170,0171,0172,0173,0174,0175,0176,0177,
100
101 0200,0201,0202,0203,0204,0205,0206,0207,
102 0210,0211,0212,0213,0214,0215,0216,0217,
103 0220,0221,0222,0223,0224,0225,0226,0227,
104 0230,0231,0232,0233,0234,0235,0236,0237,
105 0240,0241,0242,0243,0244,0245,0246,0247,
106 0250,0251,0252,0253,0254,0255,0256,0257,
107 0260,0261,0262,0263,0264,0265,0266,0267,
108 0270,0271,0272,0273,0274,0275,0276,0277,
109 0300,0301,0302,0303,0304,0305,0306,0307,
110 0310,0311,0312,0313,0314,0315,0316,0317,
111 0320,0321,0322,0323,0324,0325,0326,0327,
112 0330,0331,0332,0333,0334,0335,0336,0337,
113 0340,0341,0342,0343,0344,0345,0346,0347,
114 0350,0351,0352,0353,0354,0355,0356,0357,
115 0360,0361,0362,0363,0364,0365,0366,0367,
116 0370,0371,0372,0373,0374,0375,0376,0377,
117 };
118
119 /*
120 * DEFINITIONS FOR NEXUS
121 */
122
123 #define nxtarg() (*argp ? *argp++ : NULL)
124 #define prvarg() argp--
125
126 #define padvise if (!talked++) advise
127
128 struct nexus {
129 int (*n_action)();
130
131 union {
132 /* for {OR,AND,NOT}action */
133 struct {
134 struct nexus *un_L_child;
135 struct nexus *un_R_child;
136 } st1;
137
138 /* for GREPaction */
139 struct {
140 int un_header;
141 int un_circf;
142 char un_expbuf[ESIZE];
143 char *un_patbuf;
144 } st2;
145
146 /* for TWSaction */
147 struct {
148 char *un_datef;
149 int un_after;
150 struct tws un_tws;
151 } st3;
152 } un;
153 };
154
155 #define n_L_child un.st1.un_L_child
156 #define n_R_child un.st1.un_R_child
157
158 #define n_header un.st2.un_header
159 #define n_circf un.st2.un_circf
160 #define n_expbuf un.st2.un_expbuf
161 #define n_patbuf un.st2.un_patbuf
162
163 #define n_datef un.st3.un_datef
164 #define n_after un.st3.un_after
165 #define n_tws un.st3.un_tws
166
167 static int talked;
168 static int pdebug = 0;
169
170 static char *datesw;
171 static char **argp;
172
173 static struct nexus *head;
174
175 /*
176 * prototypes for date routines
177 */
178 static struct tws *tws_parse(char *, int);
179 static struct tws *tws_special(char *);
180
181 /*
182 * static prototypes
183 */
184 static void PRaction(struct nexus *, int);
185 static int gcompile(struct nexus *, char *);
186 static int advance(char *, char *);
187 static int cclass(unsigned char *, int, int);
188 static int tcompile(char *, struct tws *, int);
189
190 static struct nexus *parse(void);
191 static struct nexus *nexp1(void);
192 static struct nexus *nexp2(void);
193 static struct nexus *nexp3(void);
194 static struct nexus *newnexus(int (*)());
195
196 static int ORaction();
197 static int ANDaction();
198 static int NOTaction();
199 static int GREPaction();
200 static int TWSaction();
201
202
203 int
204 pcompile (char **vec, char *date)
205 {
206 register char *cp;
207
208 if ((cp = getenv ("MHPDEBUG")) && *cp)
209 pdebug++;
210
211 argp = vec;
212 if ((datesw = date) == NULL)
213 datesw = "date";
214 talked = 0;
215
216 if ((head = parse ()) == NULL)
217 return (talked ? 0 : 1);
218
219 if (*argp) {
220 padvise (NULL, "%s unexpected", *argp);
221 return 0;
222 }
223
224 return 1;
225 }
226
227
228 static struct nexus *
229 parse (void)
230 {
231 register char *cp;
232 register struct nexus *n, *o;
233
234 if ((n = nexp1 ()) == NULL || (cp = nxtarg ()) == NULL)
235 return n;
236
237 if (*cp != '-') {
238 padvise (NULL, "%s unexpected", cp);
239 return NULL;
240 }
241
242 if (*++cp == '-')
243 goto header;
244 switch (smatch (cp, parswit)) {
245 case AMBIGSW:
246 ambigsw (cp, parswit);
247 talked++;
248 return NULL;
249 case UNKWNSW:
250 fprintf (stderr, "-%s unknown\n", cp);
251 talked++;
252 return NULL;
253
254 case PROR:
255 o = newnexus (ORaction);
256 o->n_L_child = n;
257 if ((o->n_R_child = parse ()))
258 return o;
259 padvise (NULL, "missing disjunctive");
260 return NULL;
261
262 header: ;
263 default:
264 prvarg ();
265 return n;
266 }
267 }
268
269 static struct nexus *
270 nexp1 (void)
271 {
272 register char *cp;
273 register struct nexus *n, *o;
274
275 if ((n = nexp2 ()) == NULL || (cp = nxtarg ()) == NULL)
276 return n;
277
278 if (*cp != '-') {
279 padvise (NULL, "%s unexpected", cp);
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 return NULL;
290 case UNKWNSW:
291 fprintf (stderr, "-%s unknown\n", cp);
292 talked++;
293 return NULL;
294
295 case PRAND:
296 o = newnexus (ANDaction);
297 o->n_L_child = n;
298 if ((o->n_R_child = nexp1 ()))
299 return o;
300 padvise (NULL, "missing conjunctive");
301 return NULL;
302
303 header: ;
304 default:
305 prvarg ();
306 return n;
307 }
308 }
309
310
311 static struct nexus *
312 nexp2 (void)
313 {
314 register char *cp;
315 register struct nexus *n;
316
317 if ((cp = nxtarg ()) == NULL)
318 return NULL;
319
320 if (*cp != '-') {
321 prvarg ();
322 return nexp3 ();
323 }
324
325 if (*++cp == '-')
326 goto header;
327 switch (smatch (cp, parswit)) {
328 case AMBIGSW:
329 ambigsw (cp, parswit);
330 talked++;
331 return NULL;
332 case UNKWNSW:
333 fprintf (stderr, "-%s unknown\n", cp);
334 talked++;
335 return NULL;
336
337 case PRNOT:
338 n = newnexus (NOTaction);
339 if ((n->n_L_child = nexp3 ()))
340 return n;
341 padvise (NULL, "missing negation");
342 return NULL;
343
344 header: ;
345 default:
346 prvarg ();
347 return nexp3 ();
348 }
349 }
350
351 static struct nexus *
352 nexp3 (void)
353 {
354 int i;
355 register char *cp, *dp;
356 char buffer[BUFSIZ], temp[64];
357 register struct nexus *n;
358
359 if ((cp = nxtarg ()) == NULL)
360 return NULL;
361
362 if (*cp != '-') {
363 padvise (NULL, "%s unexpected", cp);
364 return NULL;
365 }
366
367 if (*++cp == '-') {
368 dp = ++cp;
369 goto header;
370 }
371 switch (i = smatch (cp, parswit)) {
372 case AMBIGSW:
373 ambigsw (cp, parswit);
374 talked++;
375 return NULL;
376 case UNKWNSW:
377 fprintf (stderr, "-%s unknown\n", cp);
378 talked++;
379 return NULL;
380
381 case PRLBR:
382 if ((n = parse ()) == NULL) {
383 padvise (NULL, "missing group");
384 return NULL;
385 }
386 if ((cp = nxtarg ()) == NULL) {
387 padvise (NULL, "missing -rbrace");
388 return NULL;
389 }
390 if (*cp++ == '-' && smatch (cp, parswit) == PRRBR)
391 return n;
392 padvise (NULL, "%s unexpected", --cp);
393 return NULL;
394
395 default:
396 prvarg ();
397 return NULL;
398
399 case PRCC:
400 case PRDATE:
401 case PRFROM:
402 case PRTO:
403 case PRSUBJ:
404 strncpy(temp, parswit[i].sw, sizeof(temp));
405 temp[sizeof(temp) - 1] = '\0';
406 dp = *brkstring (temp, " ", NULL);
407 header: ;
408 if (!(cp = nxtarg ())) {/* allow -xyz arguments */
409 padvise (NULL, "missing argument to %s", argp[-2]);
410 return NULL;
411 }
412 n = newnexus (GREPaction);
413 n->n_header = 1;
414 snprintf (buffer, sizeof(buffer), "^%s[ \t]*:.*%s", dp, cp);
415 dp = buffer;
416 goto pattern;
417
418 case PRSRCH:
419 n = newnexus (GREPaction);
420 n->n_header = 0;
421 if (!(cp = nxtarg ())) {/* allow -xyz arguments */
422 padvise (NULL, "missing argument to %s", argp[-2]);
423 return NULL;
424 }
425 dp = cp;
426 pattern: ;
427 if (!gcompile (n, dp)) {
428 padvise (NULL, "pattern error in %s %s", argp[-2], cp);
429 return NULL;
430 }
431 n->n_patbuf = getcpy (dp);
432 return n;
433
434 case PROTHR:
435 padvise (NULL, "internal error!");
436 return NULL;
437
438 case PRDATF:
439 if (!(datesw = nxtarg ()) || *datesw == '-') {
440 padvise (NULL, "missing argument to %s", argp[-2]);
441 return NULL;
442 }
443 return nexp3 ();
444
445 case PRAFTR:
446 case PRBEFR:
447 if (!(cp = nxtarg ())) {/* allow -xyz arguments */
448 padvise (NULL, "missing argument to %s", argp[-2]);
449 return NULL;
450 }
451 n = newnexus (TWSaction);
452 n->n_datef = datesw;
453 if (!tcompile (cp, &n->n_tws, n->n_after = i == PRAFTR)) {
454 padvise (NULL, "unable to parse %s %s", argp[-2], cp);
455 return NULL;
456 }
457 return n;
458 }
459 }
460
461
462 static struct nexus *
463 newnexus (int (*action)())
464 {
465 register struct nexus *p;
466
467 if ((p = (struct nexus *) calloc ((size_t) 1, sizeof *p)) == NULL)
468 adios (NULL, "unable to allocate component storage");
469
470 p->n_action = action;
471 return p;
472 }
473
474
475 #define args(a) a, fp, msgnum, start, stop
476 #define params args (n)
477 #define plist \
478 register struct nexus *n; \
479 register FILE *fp; \
480 int msgnum; \
481 long start, \
482 stop;
483
484 int
485 pmatches (FILE *fp, int msgnum, long start, long stop)
486 {
487 if (!head)
488 return 1;
489
490 if (!talked++ && pdebug)
491 PRaction (head, 0);
492
493 return (*head->n_action) (args (head));
494 }
495
496
497 static void
498 PRaction (struct nexus *n, int level)
499 {
500 register int i;
501
502 for (i = 0; i < level; i++)
503 fprintf (stderr, "| ");
504
505 if (n->n_action == ORaction) {
506 fprintf (stderr, "OR\n");
507 PRaction (n->n_L_child, level + 1);
508 PRaction (n->n_R_child, level + 1);
509 return;
510 }
511 if (n->n_action == ANDaction) {
512 fprintf (stderr, "AND\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 == NOTaction) {
518 fprintf (stderr, "NOT\n");
519 PRaction (n->n_L_child, level + 1);
520 return;
521 }
522 if (n->n_action == GREPaction) {
523 fprintf (stderr, "PATTERN(%s) %s\n",
524 n->n_header ? "header" : "body", n->n_patbuf);
525 return;
526 }
527 if (n->n_action == TWSaction) {
528 fprintf (stderr, "TEMPORAL(%s) %s: %s\n",
529 n->n_after ? "after" : "before", n->n_datef,
530 dasctime (&n->n_tws, TW_NULL));
531 return;
532 }
533 fprintf (stderr, "UNKNOWN(0x%x)\n",
534 (unsigned int)(unsigned long) (*n->n_action));
535 }
536
537
538 static int
539 ORaction (params)
540 plist
541 {
542 if ((*n->n_L_child->n_action) (args (n->n_L_child)))
543 return 1;
544 return (*n->n_R_child->n_action) (args (n->n_R_child));
545 }
546
547
548 static int
549 ANDaction (params)
550 plist
551 {
552 if (!(*n->n_L_child->n_action) (args (n->n_L_child)))
553 return 0;
554 return (*n->n_R_child->n_action) (args (n->n_R_child));
555 }
556
557
558 static int
559 NOTaction (params)
560 plist
561 {
562 return (!(*n->n_L_child->n_action) (args (n->n_L_child)));
563 }
564
565
566 static int
567 gcompile (struct nexus *n, char *astr)
568 {
569 register int c;
570 int cclcnt;
571 register unsigned char *ep, *dp, *sp, *lastep = 0;
572
573 dp = (ep = n->n_expbuf) + sizeof n->n_expbuf;
574 sp = astr;
575 if (*sp == '^') {
576 n->n_circf = 1;
577 sp++;
578 }
579 else
580 n->n_circf = 0;
581 for (;;) {
582 if (ep >= dp)
583 goto cerror;
584 if ((c = *sp++) != '*')
585 lastep = ep;
586 switch (c) {
587 case '\0':
588 *ep++ = CEOF;
589 return 1;
590
591 case '.':
592 *ep++ = CDOT;
593 continue;
594
595 case '*':
596 if (lastep == 0)
597 goto defchar;
598 *lastep |= STAR;
599 continue;
600
601 case '$':
602 if (*sp != '\0')
603 goto defchar;
604 *ep++ = CDOL;
605 continue;
606
607 case '[':
608 *ep++ = CCL;
609 *ep++ = 0;
610 cclcnt = 0;
611 if ((c = *sp++) == '^') {
612 c = *sp++;
613 ep[-2] = NCCL;
614 }
615 if (c == '-') {
616 *ep++ = c;
617 cclcnt++;
618 c = *sp++;
619 }
620 do {
621 if (c == '-' && *sp != '\0' && *sp != ']') {
622 for (c = ep[-1]+1; c < *sp; c++) {
623 *ep++ = c;
624 cclcnt++;
625 if (c == '\0' || ep >= dp)
626 goto cerror;
627 }
628 } else {
629 *ep++ = c;
630 cclcnt++;
631 if (c == '\0' || ep >= dp)
632 goto cerror;
633 }
634 } while ((c = *sp++) != ']');
635 if (cclcnt > 255)
636 goto cerror;
637 lastep[1] = cclcnt;
638 continue;
639
640 case '\\':
641 if ((c = *sp++) == '\0')
642 goto cerror;
643 defchar:
644 default:
645 *ep++ = CCHR;
646 *ep++ = c;
647 }
648 }
649
650 cerror: ;
651 return 0;
652 }
653
654
655 static int
656 GREPaction (params)
657 plist
658 {
659 int c, body, lf;
660 long pos = start;
661 register char *p1, *p2, *ebp, *cbp;
662 char ibuf[BUFSIZ];
663 NMH_UNUSED (msgnum);
664
665 fseek (fp, start, SEEK_SET);
666 body = 0;
667 ebp = cbp = ibuf;
668 for (;;) {
669 if (body && n->n_header)
670 return 0;
671 p1 = linebuf;
672 p2 = cbp;
673 lf = 0;
674 for (;;) {
675 if (p2 >= ebp) {
676 if (fgets (ibuf, sizeof ibuf, fp) == NULL
677 || (stop && pos >= stop)) {
678 if (lf)
679 break;
680 return 0;
681 }
682 pos += (long) strlen (ibuf);
683 p2 = ibuf;
684 ebp = ibuf + strlen (ibuf);
685 }
686 c = *p2++;
687 if (lf && c != '\n') {
688 if (c != ' ' && c != '\t') {
689 --p2;
690 break;
691 }
692 else
693 lf = 0;
694 }
695 if (c == '\n') {
696 if (body)
697 break;
698 else {
699 if (lf) {
700 body++;
701 break;
702 }
703 lf++;
704 c = ' ';
705 }
706 }
707 if (c && p1 < &linebuf[LBSIZE - 1])
708 *p1++ = c;
709 }
710
711 *p1++ = 0;
712 cbp = p2;
713 p1 = linebuf;
714 p2 = n->n_expbuf;
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 (lp, 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 (!mh_strcasecmp (ap, "today"))
899 return dlocaltime (&clock);
900 if (!mh_strcasecmp (ap, "yesterday")) {
901 clock -= (long) (60 * 60 * 24);
902 return dlocaltime (&clock);
903 }
904 if (!mh_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 (!mh_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 NMH_UNUSED (stop);
938
939 fseek (fp, start, SEEK_SET);
940 for (state = FLD, bp = NULL;;) {
941 switch (state = m_getfld (state, name, buf, sizeof buf, fp)) {
942 case FLD:
943 case FLDEOF:
944 case FLDPLUS:
945 if (bp != NULL)
946 free (bp), bp = NULL;
947 bp = add (buf, NULL);
948 while (state == FLDPLUS) {
949 state = m_getfld (state, name, buf, sizeof buf, fp);
950 bp = add (buf, bp);
951 }
952 if (!mh_strcasecmp (name, n->n_datef))
953 break;
954 if (state != FLDEOF)
955 continue;
956
957 case BODY:
958 case BODYEOF:
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
974 if ((tw = dparsetime (bp)) == NULL)
975 advise (NULL, "unable to parse %s field in message %d, matching...",
976 n->n_datef, msgnum), state = 1;
977 else
978 state = n->n_after ? (twsort (tw, &n->n_tws) > 0)
979 : (twsort (tw, &n->n_tws) < 0);
980
981 if (bp != NULL)
982 free (bp);
983 return state;
984 }