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