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