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