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