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