]> diplodocus.org Git - nmh/blob - uip/picksbr.c
Alter mh-chart(7)'s NAME to be lowercase.
[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
161 static char *datesw;
162 static char **argp;
163
164 static struct nexus *head;
165
166 /*
167 * prototypes for date routines
168 */
169 static struct tws *tws_parse(char *, int);
170 static struct tws *tws_special(char *);
171
172 /*
173 * static prototypes
174 */
175 static void PRaction(struct nexus *, int);
176 static int gcompile(struct nexus *, char *);
177 static int advance(char *, char *);
178 static int cclass(unsigned char *, int, int);
179 static int tcompile(char *, struct tws *, int);
180
181 static struct nexus *parse(void);
182 static struct nexus *nexp1(void);
183 static struct nexus *nexp2(void);
184 static struct nexus *nexp3(void);
185 static struct nexus *newnexus(int (*)());
186
187 static int ORaction();
188 static int ANDaction();
189 static int NOTaction();
190 static int GREPaction();
191 static int TWSaction();
192
193
194 int
195 pcompile (char **vec, char *date)
196 {
197 argp = vec;
198 if ((datesw = date) == NULL)
199 datesw = "date";
200 talked = 0;
201
202 if ((head = parse ()) == NULL)
203 return (talked ? 0 : 1);
204
205 if (*argp) {
206 padvise (NULL, "%s unexpected", *argp);
207 return 0;
208 }
209
210 return 1;
211 }
212
213
214 static struct nexus *
215 parse (void)
216 {
217 char *cp;
218 struct nexus *n, *o;
219
220 if ((n = nexp1 ()) == NULL || (cp = nxtarg ()) == NULL)
221 return n;
222
223 if (*cp != '-') {
224 padvise (NULL, "%s unexpected", cp);
225 return NULL;
226 }
227
228 if (*++cp == '-')
229 goto header;
230 switch (smatch (cp, parswit)) {
231 case AMBIGSW:
232 ambigsw (cp, parswit);
233 talked++;
234 return NULL;
235 case UNKWNSW:
236 fprintf (stderr, "-%s unknown\n", cp);
237 talked++;
238 return NULL;
239
240 case PROR:
241 o = newnexus (ORaction);
242 o->n_L_child = n;
243 if ((o->n_R_child = parse ()))
244 return o;
245 padvise (NULL, "missing disjunctive");
246 free (o);
247 return NULL;
248
249 header: ;
250 default:
251 prvarg ();
252 return n;
253 }
254 }
255
256 static struct nexus *
257 nexp1 (void)
258 {
259 char *cp;
260 struct nexus *n, *o;
261
262 if ((n = nexp2 ()) == NULL || (cp = nxtarg ()) == NULL)
263 return n;
264
265 if (*cp != '-') {
266 padvise (NULL, "%s unexpected", cp);
267 free (n);
268 return NULL;
269 }
270
271 if (*++cp == '-')
272 goto header;
273 switch (smatch (cp, parswit)) {
274 case AMBIGSW:
275 ambigsw (cp, parswit);
276 talked++;
277 free (n);
278 return NULL;
279 case UNKWNSW:
280 fprintf (stderr, "-%s unknown\n", cp);
281 talked++;
282 free (n);
283 return NULL;
284
285 case PRAND:
286 o = newnexus (ANDaction);
287 o->n_L_child = n;
288 if ((o->n_R_child = nexp1 ()))
289 return o;
290 padvise (NULL, "missing conjunctive");
291 free (o);
292 return NULL;
293
294 header: ;
295 default:
296 prvarg ();
297 return n;
298 }
299 }
300
301
302 static struct nexus *
303 nexp2 (void)
304 {
305 char *cp;
306 struct nexus *n;
307
308 if ((cp = nxtarg ()) == NULL)
309 return NULL;
310
311 if (*cp != '-') {
312 prvarg ();
313 return nexp3 ();
314 }
315
316 if (*++cp == '-')
317 goto header;
318 switch (smatch (cp, parswit)) {
319 case AMBIGSW:
320 ambigsw (cp, parswit);
321 talked++;
322 return NULL;
323 case UNKWNSW:
324 fprintf (stderr, "-%s unknown\n", cp);
325 talked++;
326 return NULL;
327
328 case PRNOT:
329 n = newnexus (NOTaction);
330 if ((n->n_L_child = nexp3 ()))
331 return n;
332 padvise (NULL, "missing negation");
333 free (n);
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 char *cp, *dp;
348 char buffer[BUFSIZ], temp[64];
349 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 free (n);
416 return NULL;
417 }
418 dp = cp;
419 pattern: ;
420 if (!gcompile (n, dp)) {
421 padvise (NULL, "pattern error in %s %s", argp[-2], cp);
422 free (n);
423 return NULL;
424 }
425 n->n_patbuf = mh_xstrdup(dp);
426 return n;
427
428 case PROTHR:
429 padvise (NULL, "internal error!");
430 return NULL;
431
432 case PRDATF:
433 if (!(datesw = nxtarg ()) || *datesw == '-') {
434 padvise (NULL, "missing argument to %s", argp[-2]);
435 return NULL;
436 }
437 return nexp3 ();
438
439 case PRAFTR:
440 case PRBEFR:
441 if (!(cp = nxtarg ())) {/* allow -xyz arguments */
442 padvise (NULL, "missing argument to %s", argp[-2]);
443 return NULL;
444 }
445 n = newnexus (TWSaction);
446 n->n_datef = datesw;
447 if (!tcompile (cp, &n->n_tws, n->n_after = i == PRAFTR)) {
448 padvise (NULL, "unable to parse %s %s", argp[-2], cp);
449 free (n);
450 return NULL;
451 }
452 return n;
453 }
454 }
455
456
457 static struct nexus *
458 newnexus (int (*action)())
459 {
460 struct nexus *p;
461
462 NEW0(p);
463 p->n_action = action;
464 return p;
465 }
466
467
468 #define args(a) a, fp, msgnum, start, stop
469 #define params args (n)
470 #define plist \
471 struct nexus *n; \
472 FILE *fp; \
473 int msgnum; \
474 long start, \
475 stop;
476
477 int
478 pmatches (FILE *fp, int msgnum, long start, long stop, int debug)
479 {
480 if (!head)
481 return 1;
482
483 if (!talked++ && debug)
484 PRaction (head, 0);
485
486 return (*head->n_action) (args (head));
487 }
488
489
490 static void
491 PRaction (struct nexus *n, int level)
492 {
493 int i;
494
495 for (i = 0; i < level; i++)
496 fprintf (stderr, "| ");
497
498 if (n->n_action == ORaction) {
499 fprintf (stderr, "OR\n");
500 PRaction (n->n_L_child, level + 1);
501 PRaction (n->n_R_child, level + 1);
502 return;
503 }
504 if (n->n_action == ANDaction) {
505 fprintf (stderr, "AND\n");
506 PRaction (n->n_L_child, level + 1);
507 PRaction (n->n_R_child, level + 1);
508 return;
509 }
510 if (n->n_action == NOTaction) {
511 fprintf (stderr, "NOT\n");
512 PRaction (n->n_L_child, level + 1);
513 return;
514 }
515 if (n->n_action == GREPaction) {
516 fprintf (stderr, "PATTERN(%s) %s\n",
517 n->n_header ? "header" : "body", n->n_patbuf);
518 return;
519 }
520 if (n->n_action == TWSaction) {
521 fprintf (stderr, "TEMPORAL(%s) %s: %s\n",
522 n->n_after ? "after" : "before", n->n_datef,
523 dasctime (&n->n_tws, TW_NULL));
524 return;
525 }
526 fprintf (stderr, "UNKNOWN(0x%x)\n",
527 (unsigned int)(unsigned long) (*n->n_action));
528 }
529
530
531 static int
532 ORaction (params)
533 plist
534 {
535 if ((*n->n_L_child->n_action) (args (n->n_L_child)))
536 return 1;
537 return (*n->n_R_child->n_action) (args (n->n_R_child));
538 }
539
540
541 static int
542 ANDaction (params)
543 plist
544 {
545 if (!(*n->n_L_child->n_action) (args (n->n_L_child)))
546 return 0;
547 return (*n->n_R_child->n_action) (args (n->n_R_child));
548 }
549
550
551 static int
552 NOTaction (params)
553 plist
554 {
555 return (!(*n->n_L_child->n_action) (args (n->n_L_child)));
556 }
557
558
559 static int
560 gcompile (struct nexus *n, char *astr)
561 {
562 int c;
563 int cclcnt;
564 unsigned char *ep, *dp, *sp, *lastep = 0;
565
566 dp = (ep = (unsigned char *) n->n_expbuf) + sizeof n->n_expbuf;
567 sp = (unsigned char *) astr;
568 if (*sp == '^') {
569 n->n_circf = 1;
570 sp++;
571 }
572 else
573 n->n_circf = 0;
574 for (;;) {
575 if (ep >= dp)
576 goto cerror;
577 if ((c = *sp++) != '*')
578 lastep = ep;
579 switch (c) {
580 case '\0':
581 *ep++ = CEOF;
582 return 1;
583
584 case '.':
585 *ep++ = CDOT;
586 continue;
587
588 case '*':
589 if (lastep == 0)
590 goto defchar;
591 *lastep |= STAR;
592 continue;
593
594 case '$':
595 if (*sp != '\0')
596 goto defchar;
597 *ep++ = CDOL;
598 continue;
599
600 case '[':
601 *ep++ = CCL;
602 *ep++ = 0;
603 cclcnt = 0;
604 if ((c = *sp++) == '^') {
605 c = *sp++;
606 ep[-2] = NCCL;
607 }
608 if (c == '-') {
609 *ep++ = c;
610 cclcnt++;
611 c = *sp++;
612 }
613 do {
614 if (c == '-' && *sp != '\0' && *sp != ']') {
615 for (c = ep[-1]+1; c < *sp; c++) {
616 *ep++ = c;
617 cclcnt++;
618 if (c == '\0' || ep >= dp)
619 goto cerror;
620 }
621 } else {
622 *ep++ = c;
623 cclcnt++;
624 if (c == '\0' || ep >= dp)
625 goto cerror;
626 }
627 } while ((c = *sp++) != ']');
628 if (cclcnt > 255)
629 goto cerror;
630 lastep[1] = cclcnt;
631 continue;
632
633 case '\\':
634 if ((c = *sp++) == '\0')
635 goto cerror;
636 /* FALLTHRU */
637 defchar:
638 default:
639 *ep++ = CCHR;
640 *ep++ = c;
641 }
642 }
643
644 cerror: ;
645 return 0;
646 }
647
648
649 static int
650 GREPaction (params)
651 plist
652 {
653 int c, body, lf;
654 long pos = start;
655 char *p1, *p2, *ebp, *cbp;
656 char ibuf[BUFSIZ];
657 NMH_UNUSED (msgnum);
658
659 fseek (fp, start, SEEK_SET);
660 body = 0;
661 ebp = cbp = ibuf;
662 for (;;) {
663 if (body && n->n_header)
664 return 0;
665 p1 = linebuf;
666 p2 = cbp;
667 lf = 0;
668 for (;;) {
669 if (p2 >= ebp) {
670 if (fgets (ibuf, sizeof ibuf, fp) == NULL
671 || (stop && pos >= stop)) {
672 if (lf)
673 break;
674 return 0;
675 }
676 pos += (long) strlen (ibuf);
677 p2 = ibuf;
678 ebp = ibuf + strlen (ibuf);
679 }
680 c = *p2++;
681 if (lf && c != '\n') {
682 if (c != ' ' && c != '\t') {
683 --p2;
684 break;
685 }
686 else
687 lf = 0;
688 }
689 if (c == '\n') {
690 if (body)
691 break;
692 else {
693 if (lf) {
694 body++;
695 break;
696 }
697 lf++;
698 /* Unfold by skipping the newline. */
699 c = 0;
700 }
701 }
702 if (c && p1 < &linebuf[LBSIZE - 1])
703 *p1++ = c;
704 }
705
706 *p1++ = 0;
707 cbp = p2;
708 p1 = linebuf;
709 p2 = n->n_expbuf;
710
711 /* Attempt to decode as a MIME header. If it's the last header,
712 body will be 1 and lf will be at least 1. */
713 if ((body == 0 || lf > 0) &&
714 decode_rfc2047 (linebuf, decoded_linebuf, sizeof decoded_linebuf)) {
715 p1 = decoded_linebuf;
716 }
717
718 if (n->n_circf) {
719 if (advance (p1, p2))
720 return 1;
721 continue;
722 }
723
724 if (*p2 == CCHR) {
725 c = p2[1];
726 do {
727 if (*p1 == c || cc[(unsigned char)*p1] == c)
728 if (advance (p1, p2))
729 return 1;
730 } while (*p1++);
731 continue;
732 }
733
734 do {
735 if (advance (p1, p2))
736 return 1;
737 } while (*p1++);
738 }
739 }
740
741
742 static int
743 advance (char *alp, char *aep)
744 {
745 unsigned char *lp, *ep, *curlp;
746
747 lp = (unsigned char *)alp;
748 ep = (unsigned char *)aep;
749 for (;;)
750 switch (*ep++) {
751 case CCHR:
752 if (*ep++ == *lp++ || ep[-1] == cc[lp[-1]])
753 continue;
754 return 0;
755
756 case CDOT:
757 if (*lp++)
758 continue;
759 return 0;
760
761 case CDOL:
762 if (*lp == 0)
763 continue;
764 return 0;
765
766 case CEOF:
767 return 1;
768
769 case CCL:
770 if (cclass (ep, *lp++, 1)) {
771 ep += *ep + 1;
772 continue;
773 }
774 return 0;
775
776 case NCCL:
777 if (cclass (ep, *lp++, 0)) {
778 ep += *ep + 1;
779 continue;
780 }
781 return 0;
782
783 case CDOT | STAR:
784 curlp = lp;
785 while (*lp++)
786 continue;
787 goto star;
788
789 case CCHR | STAR:
790 curlp = lp;
791 while (*lp++ == *ep || cc[lp[-1]] == *ep)
792 continue;
793 ep++;
794 goto star;
795
796 case CCL | STAR:
797 case NCCL | STAR:
798 curlp = lp;
799 while (cclass (ep, *lp++, ep[-1] == (CCL | STAR)))
800 continue;
801 ep += *ep + 1;
802 goto star;
803
804 star:
805 do {
806 lp--;
807 if (advance ((char *) lp, (char *) ep))
808 return (1);
809 } while (lp > curlp);
810 return 0;
811
812 default:
813 admonish (NULL, "advance() botch -- you lose big");
814 return 0;
815 }
816 }
817
818
819 static int
820 cclass (unsigned char *aset, int ac, int af)
821 {
822 unsigned int n;
823 unsigned char c, *set;
824
825 set = aset;
826 if ((c = ac) == 0)
827 return (0);
828
829 n = *set++;
830 while (n--)
831 if (*set++ == c || set[-1] == cc[c])
832 return (af);
833
834 return (!af);
835 }
836
837
838 static int
839 tcompile (char *ap, struct tws *tb, int isafter)
840 {
841 struct tws *tw;
842
843 if ((tw = tws_parse (ap, isafter)) == NULL)
844 return 0;
845
846 twscopy (tb, tw);
847 return 1;
848 }
849
850
851 static struct tws *
852 tws_parse (char *ap, int isafter)
853 {
854 char buffer[BUFSIZ];
855 struct tws *tw, *ts;
856
857 if ((tw = tws_special (ap)) != NULL) {
858 tw->tw_sec = tw->tw_min = isafter ? 59 : 0;
859 tw->tw_hour = isafter ? 23 : 0;
860 return tw;
861 }
862 if ((tw = dparsetime (ap)) != NULL)
863 return tw;
864
865 if ((ts = dlocaltimenow ()) == NULL)
866 return NULL;
867
868 snprintf (buffer, sizeof(buffer), "%s %s", ap, dtwszone (ts));
869 if ((tw = dparsetime (buffer)) != NULL)
870 return tw;
871
872 snprintf (buffer, sizeof(buffer), "%s %02d:%02d:%02d %s", ap,
873 ts->tw_hour, ts->tw_min, ts->tw_sec, dtwszone (ts));
874 if ((tw = dparsetime (buffer)) != NULL)
875 return tw;
876
877 snprintf (buffer, sizeof(buffer), "%02d %s %04d %s",
878 ts->tw_mday, tw_moty[ts->tw_mon], ts->tw_year, ap);
879 if ((tw = dparsetime (buffer)) != NULL)
880 return tw;
881
882 snprintf (buffer, sizeof(buffer), "%02d %s %04d %s %s",
883 ts->tw_mday, tw_moty[ts->tw_mon], ts->tw_year,
884 ap, dtwszone (ts));
885 if ((tw = dparsetime (buffer)) != NULL)
886 return tw;
887
888 return NULL;
889 }
890
891
892 static struct tws *
893 tws_special (char *ap)
894 {
895 int i;
896 time_t clock;
897 struct tws *tw;
898
899 time (&clock);
900 if (!strcasecmp (ap, "today"))
901 return dlocaltime (&clock);
902 if (!strcasecmp (ap, "yesterday")) {
903 clock -= (long) (60 * 60 * 24);
904 return dlocaltime (&clock);
905 }
906 if (!strcasecmp (ap, "tomorrow")) {
907 clock += (long) (60 * 60 * 24);
908 return dlocaltime (&clock);
909 }
910
911 for (i = 0; tw_ldotw[i]; i++)
912 if (!strcasecmp (ap, tw_ldotw[i]))
913 break;
914 if (tw_ldotw[i]) {
915 if ((tw = dlocaltime (&clock)) == NULL)
916 return NULL;
917 if ((i -= tw->tw_wday) > 0)
918 i -= 7;
919 }
920 else {
921 if (*ap != '-')
922 return NULL;
923 /* -ddd days ago */
924 i = atoi (ap); /* we should error check this */
925 }
926
927 clock += (long) ((60 * 60 * 24) * i);
928 return dlocaltime (&clock);
929 }
930
931
932 static int
933 TWSaction (params)
934 plist
935 {
936 int state;
937 char *bp;
938 char buf[BUFSIZ], name[NAMESZ];
939 struct tws *tw;
940 m_getfld_state_t gstate = 0;
941 NMH_UNUSED (stop);
942
943 fseek (fp, start, SEEK_SET);
944 for (bp = NULL;;) {
945 int bufsz = sizeof buf;
946 switch (state = m_getfld (&gstate, name, buf, &bufsz, fp)) {
947 case FLD:
948 case FLDPLUS:
949 mh_xfree(bp);
950 bp = mh_xstrdup(buf);
951 while (state == FLDPLUS) {
952 bufsz = sizeof buf;
953 state = m_getfld (&gstate, name, buf, &bufsz, fp);
954 bp = add (buf, bp);
955 }
956 if (!strcasecmp (name, n->n_datef))
957 break;
958 continue;
959
960 case BODY:
961 case FILEEOF:
962 case LENERR:
963 case FMTERR:
964 if (state == LENERR || state == FMTERR)
965 advise (NULL, "format error in message %d", msgnum);
966 mh_xfree(bp);
967 return 0;
968
969 default:
970 adios (NULL, "internal error -- you lose");
971 }
972 break;
973 }
974 m_getfld_state_destroy (&gstate);
975
976 if ((tw = dparsetime (bp)) == NULL)
977 advise (NULL, "unable to parse %s field in message %d, matching...",
978 n->n_datef, msgnum), state = 1;
979 else
980 state = n->n_after ? (twsort (tw, &n->n_tws) > 0)
981 : (twsort (tw, &n->n_tws) < 0);
982
983 mh_xfree(bp);
984 return state;
985 }