[bug #4297] The strlen mh-format function can crash if 'str' is null.
[mmh] / sbr / fmt_scan.c
1
2 /*
3  * fmt_scan.c -- format string interpretation
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/addrsbr.h>
14 #include <h/fmt_scan.h>
15 #include <h/tws.h>
16 #include <h/fmt_compile.h>
17
18 #ifdef TIME_WITH_SYS_TIME
19 # include <sys/time.h>
20 # include <time.h>
21 #else
22 # ifdef TM_IN_SYS_TIME
23 #  include <sys/time.h>
24 # else
25 #  include <time.h>
26 # endif
27 #endif
28
29 #define NFMTS MAXARGS
30
31 extern char *formataddr ();     /* hook for custom address formatting */
32
33 #ifdef LBL
34 struct msgs *fmt_current_folder; /* current folder (set by main program) */
35 #endif
36
37 extern int fmt_norm;            /* defined in sbr/fmt_def.c = AD_NAME */
38 struct mailname fmt_mnull;
39
40 /*
41  * static prototypes
42  */
43 static int match (char *, char *);
44 static char *get_x400_friendly (char *, char *, int);
45 static int get_x400_comp (char *, char *, char *, int);
46
47
48 /*
49  * test if string "sub" appears anywhere in
50  * string "str" (case insensitive).
51  */
52
53 static int
54 match (char *str, char *sub)
55 {
56     int c1, c2;
57     char *s1, *s2;
58
59 #ifdef LOCALE
60     while ((c1 = *sub)) {
61         c1 = (isalpha(c1) && isupper(c1)) ? tolower(c1) : c1;
62         while ((c2 = *str++) && c1 != ((isalpha(c2) && isupper(c2)) ? tolower(c2) : c2))
63             ;
64         if (! c2)
65             return 0;
66         s1 = sub + 1; s2 = str;
67         while ((c1 = *s1++) && ((isalpha(c1) && isupper(c1)) ? tolower(c1) : c1) == ((isalpha(c2 =*s2++) && isupper(c2)) ? tolower(c2) : c2))
68             ;
69         if (! c1)
70             return 1;
71     }
72 #else
73     while ((c1 = *sub)) {
74         while ((c2 = *str++) && (c1 | 040) != (c2 | 040))
75             ;
76         if (! c2)
77             return 0;
78         s1 = sub + 1; s2 = str;
79         while ((c1 = *s1++) && (c1 | 040) == (*s2++ | 040))
80             ;
81         if (! c1)
82             return 1;
83     }
84 #endif
85     return 1;
86 }
87
88 /*
89  * macros to format data
90  */
91
92 #define PUTDF(cp, num, wid, fill)\
93         if (cp + wid < ep) {\
94             if ((i = (num)) < 0)\
95                 i = -(num);\
96             if ((c = (wid)) < 0)\
97                 c = -c;\
98             sp = cp + c;\
99             do {\
100                 *--sp = (i % 10) + '0';\
101                 i /= 10;\
102             } while (i > 0 && sp > cp);\
103             if (i > 0)\
104                 *sp = '?';\
105             else if ((num) < 0 && sp > cp)\
106                 *--sp = '-';\
107             while (sp > cp)\
108                 *--sp = fill;\
109             cp += c;\
110             }
111
112 #define PUTD(cp, num)\
113         if (cp < ep) {\
114             if ((i = (num)) == 0)\
115                 *cp++ = '0';\
116             else {\
117                 if ((i = (num)) < 0) {\
118                     *cp++ = '-';\
119                     i = -(num);\
120                     }\
121                 c = 10;\
122                 while (c <= i) \
123                     c *= 10;\
124                 while (cp < ep && c > 1) {\
125                     c /= 10;\
126                     *cp++ = (i / c) + '0';\
127                     i %= c;\
128                     }\
129                 }\
130             }
131
132 #ifdef LOCALE
133 #define PUTSF(cp, str, wid, fill) {\
134                 ljust = 0;\
135                 if ((i = (wid)) < 0) {\
136                         i = -i;\
137                         ljust++;\
138                 }\
139                 if ((sp = (str))) {\
140                         if (ljust) {\
141                                 c = strlen(sp);\
142                                 if (c > i)\
143                                         sp += c - i;\
144                                 else {\
145                                         while( --i >= c && cp < ep)\
146                                                 *cp++ = fill;\
147                                         i++;\
148                                 }\
149                         } else {\
150                             while ((c = (unsigned char) *sp) && (iscntrl(c) || isspace(c)))\
151                                 sp++;\
152                         }\
153                         while ((c = (unsigned char) *sp++) && --i >= 0 && cp < ep)\
154                                 if (isgraph(c)) \
155                                     *cp++ = c;\
156                                 else {\
157                                         while ((c = (unsigned char) *sp) && (iscntrl(c) || isspace(c)))\
158                                                 sp++;\
159                                             *cp++ = ' ';\
160                                 }\
161                 }\
162                 if (!ljust)\
163                 while( --i >= 0 && cp < ep)\
164                     *cp++ = fill;\
165         }
166
167 #define PUTS(cp, str) {\
168                 if ((sp = (str))) {\
169                     while ((c = (unsigned char) *sp) && (iscntrl(c) || isspace(c)))\
170                         sp++;\
171                     while((c = (unsigned char) *sp++) && cp < ep)\
172                         if (isgraph(c)) \
173                             *cp++ = c;\
174                         else {\
175                             while ((c = (unsigned char) *sp) && (iscntrl(c) || isspace(c)))\
176                                 sp++;\
177                             *cp++ = ' ';\
178                         }\
179                 }\
180         }
181
182 #else /* LOCALE */
183 #define PUTSF(cp, str, wid, fill) {\
184                 ljust = 0;\
185                 if ((i = (wid)) < 0) {\
186                         i = -i;\
187                         ljust++;\
188                 }\
189                 if (sp = (str)) {\
190                         if (ljust) {\
191                                 c = strlen(sp);\
192                                 if (c > i)\
193                                         sp += c - i;\
194                                 else {\
195                                         while( --i >= c && cp < ep)\
196                                                 *cp++ = fill;\
197                                         i++;\
198                                 }\
199                         } else {\
200                     while ((c = *sp) && c <= 32)\
201                         sp++;\
202                         }\
203                         while ((c = *sp++) && --i >= 0 && cp < ep)\
204                                 if (c > 32) \
205                             *cp++ = c;\
206                         else {\
207                                         while ((c = *sp) && c <= 32)\
208                                 sp++;\
209                             *cp++ = ' ';\
210                         }\
211                 }\
212                 if (!ljust)\
213                 while( --i >= 0 && cp < ep)\
214                     *cp++ = fill;\
215                 }
216
217 #define PUTS(cp, str) {\
218                 if (sp = (str)) {\
219                     while ((c = *sp) && c <= 32)\
220                         sp++;\
221                     while( (c = *sp++) && cp < ep)\
222                         if ( c > 32 ) \
223                             *cp++ = c;\
224                         else {\
225                             while ( (c = *sp) && c <= 32 )\
226                                 sp++;\
227                             *cp++ = ' ';\
228                         }\
229                 }\
230                 }
231
232 #endif /* LOCALE */
233
234
235 static char *lmonth[] = { "January",  "February","March",   "April",
236                           "May",      "June",    "July",    "August",
237                           "September","October", "November","December" };
238
239 static char *
240 get_x400_friendly (char *mbox, char *buffer, int buffer_len)
241 {
242     char given[BUFSIZ], surname[BUFSIZ];
243
244     if (mbox == NULL)
245         return NULL;
246     if (*mbox == '"')
247         mbox++;
248     if (*mbox != '/')
249         return NULL;
250
251     if (get_x400_comp (mbox, "/PN=", buffer, buffer_len)) {
252         for (mbox = buffer; (mbox = strchr(mbox, '.')); )
253             *mbox++ = ' ';
254
255         return buffer;
256     }
257
258     if (!get_x400_comp (mbox, "/S=", surname, sizeof(surname)))
259         return NULL;
260
261     if (get_x400_comp (mbox, "/G=", given, sizeof(given)))
262         snprintf (buffer, buffer_len, "%s %s", given, surname);
263     else
264         snprintf (buffer, buffer_len, "%s", surname);
265
266     return buffer;
267 }
268
269 static int
270 get_x400_comp (char *mbox, char *key, char *buffer, int buffer_len)
271 {
272     int idx;
273     char *cp;
274
275     if ((idx = stringdex (key, mbox)) < 0
276             || !(cp = strchr(mbox += idx + strlen (key), '/')))
277         return 0;
278
279     snprintf (buffer, buffer_len, "%*.*s", cp - mbox, cp - mbox, mbox);
280     return 1;
281 }
282
283 struct format *
284 fmt_scan (struct format *format, char *scanl, int width, int *dat)
285 {
286     char *cp, *ep, *sp;
287     char *savestr, *str = NULL;
288     char buffer[BUFSIZ], buffer2[BUFSIZ];
289     int i, c, ljust;
290     int value = 0;
291     time_t t;
292     struct format *fmt;
293     struct comp *comp;
294     struct tws *tws;
295     struct mailname *mn;
296
297     cp = scanl;
298     ep = scanl + width - 1;
299
300     for (fmt = format; fmt->f_type != FT_DONE; fmt++)
301         switch (fmt->f_type) {
302         case FT_PARSEADDR:
303         case FT_PARSEDATE:
304             fmt->f_comp->c_flags &= ~CF_PARSED;
305             break;
306         }
307
308     fmt = format;
309
310     while (cp < ep) {
311         switch (fmt->f_type) {
312
313         case FT_COMP:
314             PUTS (cp, fmt->f_comp->c_text);
315             break;
316         case FT_COMPF:
317             PUTSF (cp, fmt->f_comp->c_text, fmt->f_width, fmt->f_fill);
318             break;
319
320         case FT_LIT:
321             sp = fmt->f_text;
322             while( (c = *sp++) && cp < ep)
323                 *cp++ = c;
324             break;
325         case FT_LITF:
326             sp = fmt->f_text;
327             ljust = 0;
328             i = fmt->f_width;
329             if (i < 0) {
330                 i = -i;
331                 ljust++;                /* XXX should do something with this */
332             }
333             while( (c = *sp++) && --i >= 0 && cp < ep)
334                 *cp++ = c;
335             while( --i >= 0 && cp < ep)
336                 *cp++ = fmt->f_fill;
337             break;
338
339         case FT_STR:
340             PUTS (cp, str);
341             break;
342         case FT_STRF:
343             PUTSF (cp, str, fmt->f_width, fmt->f_fill);
344             break;
345         case FT_STRFW:
346             adios (NULL, "internal error (FT_STRFW)");
347
348         case FT_NUM:
349             PUTD (cp, value);
350             break;
351         case FT_NUMF:
352             PUTDF (cp, value, fmt->f_width, fmt->f_fill);
353             break;
354
355         case FT_CHAR:
356             *cp++ = fmt->f_char;
357             break;
358
359         case FT_DONE:
360             goto finished;
361
362         case FT_IF_S:
363             if (!(value = (str && *str))) {
364                 fmt += fmt->f_skip;
365                 continue;
366             }
367             break;
368
369         case FT_IF_S_NULL:
370             if (!(value = (str == NULL || *str == 0))) {
371                 fmt += fmt->f_skip;
372                 continue;
373             }
374             break;
375
376         case FT_IF_V_EQ:
377             if (value != fmt->f_value) {
378                 fmt += fmt->f_skip;
379                 continue;
380             }
381             break;
382
383         case FT_IF_V_NE:
384             if (value == fmt->f_value) {
385                 fmt += fmt->f_skip;
386                 continue;
387             }
388             break;
389
390         case FT_IF_V_GT:
391             if (value <= fmt->f_value) {
392                 fmt += fmt->f_skip;
393                 continue;
394             }
395             break;
396
397         case FT_IF_MATCH:
398             if (!(value = (str && match (str, fmt->f_text)))) {
399                 fmt += fmt->f_skip;
400                 continue;
401             }
402             break;
403
404         case FT_V_MATCH:
405             if (str)
406                 value = match (str, fmt->f_text);
407             else
408                 value = 0;
409             break;
410
411         case FT_IF_AMATCH:
412             if (!(value = (str && uprf (str, fmt->f_text)))) {
413                 fmt += fmt->f_skip;
414                 continue;
415             }
416             break;
417
418         case FT_V_AMATCH:
419             value = uprf (str, fmt->f_text);
420             break;
421
422         case FT_S_NONNULL:
423             value = (str != NULL && *str != 0);
424             break;
425
426         case FT_S_NULL:
427             value = (str == NULL || *str == 0);
428             break;
429
430         case FT_V_EQ:
431             value = (fmt->f_value == value);
432             break;
433
434         case FT_V_NE:
435             value = (fmt->f_value != value);
436             break;
437
438         case FT_V_GT:
439             value = (fmt->f_value > value);
440             break;
441
442         case FT_GOTO:
443             fmt += fmt->f_skip;
444             continue;
445
446         case FT_NOP:
447             break;
448
449         case FT_LS_COMP:
450             str = fmt->f_comp->c_text;
451             break;
452         case FT_LS_LIT:
453             str = fmt->f_text;
454             break;
455         case FT_LS_GETENV:
456             if (!(str = getenv (fmt->f_text)))
457                 str = "";
458             break;
459         case FT_LS_CFIND:
460             if (!(str = context_find (fmt->f_text)))
461                 str = "";
462             break;
463
464         case FT_LS_DECODECOMP:
465             if (decode_rfc2047(fmt->f_comp->c_text, buffer2))
466                 str = buffer2;
467             else
468                 str = fmt->f_comp->c_text;
469             break;
470
471         case FT_LS_DECODE:
472             if (str && decode_rfc2047(str, buffer2))
473                 str = buffer2;
474             break;
475
476         case FT_LS_TRIM:
477             if (str) {
478                     char *xp;
479
480                     strncpy(buffer, str, sizeof(buffer));
481                     str = buffer;
482                     while (isspace(*str))
483                             str++;
484                     ljust = 0;
485                     if ((i = fmt->f_width) < 0) {
486                             i = -i;
487                             ljust++;
488                     }
489
490                     if (!ljust && i > 0 && strlen(str) > i)
491                             str[i] = '\0';
492                     xp = str;
493                     xp += strlen(str) - 1;
494                     while (xp > str && isspace(*xp))
495                             *xp-- = '\0';
496                     if (ljust && i > 0 && strlen(str) > i)
497                         str += strlen(str) - i;
498             }
499             break;
500
501         case FT_LV_COMPFLAG:
502             value = (fmt->f_comp->c_flags & CF_TRUE) != 0;
503             break;
504         case FT_LV_COMP:
505             value = (comp = fmt->f_comp)->c_text ? atoi(comp->c_text) : 0;
506             break;
507         case FT_LV_LIT:
508             value = fmt->f_value;
509             break;
510         case FT_LV_DAT:
511             value = dat[fmt->f_value];
512             break;
513         case FT_LV_STRLEN:
514             if (str != NULL)
515                     value = strlen(str);
516             else
517                     value = 0;
518             break;
519         case FT_LV_CHAR_LEFT:
520             value = width - (cp - scanl);
521             break;
522         case FT_LV_PLUS_L:
523             value += fmt->f_value;
524             break;
525         case FT_LV_MINUS_L:
526             value = fmt->f_value - value;
527             break;
528         case FT_LV_DIVIDE_L:
529             if (fmt->f_value)
530                 value = value / fmt->f_value;
531             else
532                 value = 0;
533             break;
534         case FT_LV_MODULO_L:
535             if (fmt->f_value)
536                 value = value % fmt->f_value;
537             else
538                 value = 0;
539             break;
540         case FT_SAVESTR:
541             savestr = str;
542             break;
543
544         case FT_LV_SEC:
545             value = fmt->f_comp->c_tws->tw_sec;
546             break;
547         case FT_LV_MIN:
548             value = fmt->f_comp->c_tws->tw_min;
549             break;
550         case FT_LV_HOUR:
551             value = fmt->f_comp->c_tws->tw_hour;
552             break;
553         case FT_LV_MDAY:
554             value = fmt->f_comp->c_tws->tw_mday;
555             break;
556         case FT_LV_MON:
557             value = fmt->f_comp->c_tws->tw_mon + 1;
558             break;
559         case FT_LS_MONTH:
560             str = tw_moty[fmt->f_comp->c_tws->tw_mon];
561             break;
562         case FT_LS_LMONTH:
563             str = lmonth[fmt->f_comp->c_tws->tw_mon];
564             break;
565         case FT_LS_ZONE:
566             str = dtwszone (fmt->f_comp->c_tws);
567             break;
568         case FT_LV_YEAR:
569             value = fmt->f_comp->c_tws->tw_year;
570             break;
571         case FT_LV_WDAY:
572             if (!(((tws = fmt->f_comp->c_tws)->tw_flags) & (TW_SEXP|TW_SIMP)))
573                 set_dotw (tws);
574             value = tws->tw_wday;
575             break;
576         case FT_LS_DAY:
577             if (!(((tws = fmt->f_comp->c_tws)->tw_flags) & (TW_SEXP|TW_SIMP)))
578                 set_dotw (tws);
579             str = tw_dotw[tws->tw_wday];
580             break;
581         case FT_LS_WEEKDAY:
582             if (!(((tws = fmt->f_comp->c_tws)->tw_flags) & (TW_SEXP|TW_SIMP)))
583                 set_dotw (tws);
584             str = tw_ldotw[tws->tw_wday];
585             break;
586         case FT_LV_YDAY:
587             value = fmt->f_comp->c_tws->tw_yday;
588             break;
589         case FT_LV_ZONE:
590             value = fmt->f_comp->c_tws->tw_zone;
591             break;
592         case FT_LV_CLOCK:
593             if ((value = fmt->f_comp->c_tws->tw_clock) == 0)
594                 value = dmktime(fmt->f_comp->c_tws);
595             break;
596         case FT_LV_RCLOCK:
597             if ((value = fmt->f_comp->c_tws->tw_clock) == 0)
598                 value = dmktime(fmt->f_comp->c_tws);
599             value = time((time_t *) 0) - value;
600             break;
601         case FT_LV_DAYF:
602             if (!(((tws = fmt->f_comp->c_tws)->tw_flags) & (TW_SEXP|TW_SIMP)))
603                 set_dotw (tws);
604             switch (fmt->f_comp->c_tws->tw_flags & TW_SDAY) {
605                 case TW_SEXP:
606                     value = 1; break;
607                 case TW_SIMP:
608                     value = 0; break;
609                 default:
610                     value = -1; break;
611             }
612         case FT_LV_ZONEF:
613             if ((fmt->f_comp->c_tws->tw_flags & TW_SZONE) == TW_SZEXP)
614                     value = 1;
615             else
616                     value = -1;
617             break;
618         case FT_LV_DST:
619             value = fmt->f_comp->c_tws->tw_flags & TW_DST;
620             break;
621         case FT_LS_822DATE:
622             str = dasctime (fmt->f_comp->c_tws , TW_ZONE);
623             break;
624         case FT_LS_PRETTY:
625             str = dasctime (fmt->f_comp->c_tws, TW_NULL);
626             break;
627
628         case FT_LS_PERS:
629             str = fmt->f_comp->c_mn->m_pers;
630             break;
631         case FT_LS_MBOX:
632             str = fmt->f_comp->c_mn->m_mbox;
633             break;
634         case FT_LS_HOST:
635             str = fmt->f_comp->c_mn->m_host;
636             break;
637         case FT_LS_PATH:
638             str = fmt->f_comp->c_mn->m_path;
639             break;
640         case FT_LS_GNAME:
641             str = fmt->f_comp->c_mn->m_gname;
642             break;
643         case FT_LS_NOTE:
644             str = fmt->f_comp->c_mn->m_note;
645             break;
646         case FT_LS_822ADDR:
647             str = adrformat( fmt->f_comp->c_mn );
648             break;
649         case FT_LV_HOSTTYPE:
650             value = fmt->f_comp->c_mn->m_type;
651             break;
652         case FT_LV_INGRPF:
653             value = fmt->f_comp->c_mn->m_ingrp;
654             break;
655         case FT_LV_NOHOSTF:
656             value = fmt->f_comp->c_mn->m_nohost;
657             break;
658         case FT_LS_ADDR:
659         case FT_LS_FRIENDLY:
660             if ((mn = fmt->f_comp->c_mn) == &fmt_mnull) {
661                 str = fmt->f_comp->c_text;
662                 break;
663             }
664             if (fmt->f_type == FT_LS_ADDR)
665                 goto unfriendly;
666             if ((str = mn->m_pers) == NULL) {
667                 if ((str = mn->m_note)) {
668                     strncpy (buffer, str, sizeof(buffer));
669                     str = buffer;
670                     if (*str == '(')
671                         str++;
672                     sp = str + strlen(str) - 1;
673                     if (*sp == ')') {
674                         *sp-- = '\0';
675                         while (sp >= str)
676                             if (*sp == ' ')
677                                 *sp-- = '\0';
678                             else
679                                 break;
680                     }
681                 } else if (!(str = get_x400_friendly (mn->m_mbox,
682                                 buffer, sizeof(buffer)))) {
683         unfriendly: ;
684                   switch (mn->m_type) {
685                     case LOCALHOST:
686                         str = mn->m_mbox;
687                         break;
688                     case UUCPHOST:
689                         snprintf (buffer, sizeof(buffer), "%s!%s",
690                                 mn->m_host, mn->m_mbox);
691                         str = buffer;
692                         break;
693                     default:
694                         if (mn->m_mbox) {
695                             snprintf (buffer, sizeof(buffer), "%s@%s",
696                                 mn->m_mbox, mn->m_host);
697                             str= buffer;
698                         }
699                         else
700                             str = mn->m_text;
701                         break;
702                   }
703                 }
704             }
705             break;
706
707         case FT_LOCALDATE:
708             comp = fmt->f_comp;
709             if ((t = comp->c_tws->tw_clock) == 0)
710                 t = dmktime(comp->c_tws);
711             tws = dlocaltime(&t);
712             *comp->c_tws = *tws;
713             break;
714
715         case FT_GMTDATE:
716             comp = fmt->f_comp;
717             if ((t = comp->c_tws->tw_clock) == 0)
718                 t = dmktime(comp->c_tws);
719             tws = dgmtime(&t);
720             *comp->c_tws = *tws;
721             break;
722
723         case FT_PARSEDATE:
724             comp = fmt->f_comp;
725             if (comp->c_flags & CF_PARSED)
726                 break;
727             if ((sp = comp->c_text) && (tws = dparsetime(sp))) {
728                 *comp->c_tws = *tws;
729                 comp->c_flags &= ~CF_TRUE;
730             } else if ((comp->c_flags & CF_DATEFAB) == 0) {
731                 memset ((char *) comp->c_tws, 0, sizeof *comp->c_tws);
732                 comp->c_flags = CF_TRUE;
733             }
734             comp->c_flags |= CF_PARSED;
735             break;
736
737         case FT_FORMATADDR:
738             /* hook for custom address list formatting (see replsbr.c) */
739             str = formataddr (savestr, str);
740             break;
741
742         case FT_PUTADDR:
743             /* output the str register as an address component,
744              * splitting it into multiple lines if necessary.  The
745              * value reg. contains the max line length.  The lit.
746              * field may contain a string to prepend to the result
747              * (e.g., "To: ")
748              */
749             {
750             char *lp, *lastb;
751             int indent, wid, len;
752
753             lp = str;
754             wid = value;
755             len = strlen (str);
756             sp = fmt->f_text;
757             indent = strlen (sp);
758             wid -= indent;
759             while( (c = *sp++) && cp < ep)
760                 *cp++ = c;
761             while (len > wid) {
762                 /* try to break at a comma; failing that, break at a
763                  * space.
764                  */
765                 lastb = 0; sp = lp + wid;
766                 while (sp > lp && (c = *--sp) != ',') {
767                     if (! lastb && isspace(c))
768                         lastb = sp - 1;
769                 }
770                 if (sp == lp) {
771                     if (! (sp = lastb)) {
772                         sp = lp + wid - 1;
773                         while (*sp && *sp != ',' && !isspace(*sp))
774                             sp++;
775                         if (*sp != ',')
776                             sp--;
777                     }
778                 }
779                 len -= sp - lp + 1;
780                 while (cp < ep && lp <= sp)
781                     *cp++ = *lp++;
782                 while (isspace(*lp))
783                     lp++, len--;
784                 if (*lp) {
785                     if (cp < ep)
786                         *cp++ = '\n';
787                     for (i=indent; cp < ep && i > 0; i--)
788                         *cp++ = ' ';
789                 }
790             }
791             PUTS (cp, lp);
792             }
793             break;
794
795         case FT_PARSEADDR:
796             comp = fmt->f_comp;
797             if (comp->c_flags & CF_PARSED)
798                 break;
799             if (comp->c_mn != &fmt_mnull)
800                 mnfree (comp->c_mn);
801             if ((sp = comp->c_text) && (sp = getname(sp)) &&
802                 (mn = getm (sp, NULL, 0, fmt_norm, NULL))) {
803                 comp->c_mn = mn;
804                 while (getname(""))
805                     ;
806                 comp->c_flags |= CF_PARSED;
807             } else {
808                 while (getname(""))             /* XXX */
809                     ;
810                 comp->c_mn = &fmt_mnull;
811             }
812             break;
813             
814         case FT_MYMBOX:
815             /*
816              * if there's no component, we say true.  Otherwise we
817              * say "true" only if we can parse the address and it
818              * matches one of our addresses.
819              */
820             comp = fmt->f_comp;
821             if (comp->c_mn != &fmt_mnull)
822                 mnfree (comp->c_mn);
823             if ((sp = comp->c_text) && (sp = getname(sp)) &&
824                 (mn = getm (sp, NULL, 0, AD_NAME, NULL))) {
825                 comp->c_mn = mn;
826                 if (ismymbox(mn))
827                     comp->c_flags |= CF_TRUE;
828                 else
829                     comp->c_flags &= ~CF_TRUE;
830                 while ((sp = getname(sp)))
831                     if ((comp->c_flags & CF_TRUE) == 0 &&
832                         (mn = getm (sp, NULL, 0, AD_NAME, NULL)))
833                         if (ismymbox(mn))
834                             comp->c_flags |= CF_TRUE;
835             } else {
836                 while (getname(""))             /* XXX */
837                     ;
838                 if (comp->c_text == 0)
839                     comp->c_flags |= CF_TRUE;
840                 else
841                     comp->c_flags &= ~CF_TRUE;
842                 comp->c_mn = &fmt_mnull;
843             }
844             break;
845
846         case FT_ADDTOSEQ:
847 #ifdef LBL
848             /* If we're working on a folder (as opposed to a file), add the
849              * current msg to sequence given in literal field.  Don't
850              * disturb string or value registers.
851              */
852             if (fmt_current_folder)
853                     seq_addmsg(fmt_current_folder, fmt->f_text, dat[0], -1);
854 #endif
855             break;
856         }
857         fmt++;
858     }
859 #ifndef JLR
860     finished:;
861     if (cp[-1] != '\n')
862         *cp++ = '\n';
863     *cp   = 0;
864     return ((struct format *)0);
865 #else /* JLR */
866     if (cp[-1] != '\n')
867         *cp++ = '\n';
868     while (fmt->f_type != FT_DONE)
869         fmt++;
870
871     finished:;    
872     *cp = '\0';
873     return (fmt->f_value ? ++fmt : (struct format *) 0);
874
875 #endif /* JLR */
876 }