mutt stable branch with some hacks
1/*
2 * Copyright (C) 1996-2000,2002,2007 Michael R. Elkins <me@mutt.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19#if HAVE_CONFIG_H
20# include "config.h"
21#endif
22
23#include "mutt.h"
24#include "mutt_curses.h"
25#include "sort.h"
26#include "charset.h"
27#include "mutt_crypt.h"
28#include "mutt_idna.h"
29
30#include <ctype.h>
31#include <stdlib.h>
32#include <string.h>
33#include <locale.h>
34
35#ifdef HAVE_ALLOCA_H
36#include <alloca.h>
37#endif
38
39int mutt_is_mail_list (ADDRESS *addr)
40{
41 if (!mutt_match_rx_list (addr->mailbox, UnMailLists))
42 return mutt_match_rx_list (addr->mailbox, MailLists);
43 return 0;
44}
45
46int mutt_is_subscribed_list (ADDRESS *addr)
47{
48 if (!mutt_match_rx_list (addr->mailbox, UnMailLists)
49 && !mutt_match_rx_list (addr->mailbox, UnSubscribedLists))
50 return mutt_match_rx_list (addr->mailbox, SubscribedLists);
51 return 0;
52}
53
54/* Search for a mailing list in the list of addresses pointed to by adr.
55 * If one is found, print pfx and the name of the list into buf, then
56 * return 1. Otherwise, simply return 0.
57 */
58static int
59check_for_mailing_list (ADDRESS *adr, char *pfx, char *buf, int buflen)
60{
61 for (; adr; adr = adr->next)
62 {
63 if (mutt_is_subscribed_list (adr))
64 {
65 if (pfx && buf && buflen)
66 snprintf (buf, buflen, "%s%s", pfx, mutt_get_name (adr));
67 return 1;
68 }
69 }
70 return 0;
71}
72
73/* Search for a mailing list in the list of addresses pointed to by adr.
74 * If one is found, print the address of the list into buf, then return 1.
75 * Otherwise, simply return 0.
76 */
77static int
78check_for_mailing_list_addr (ADDRESS *adr, char *buf, int buflen)
79{
80 for (; adr; adr = adr->next)
81 {
82 if (mutt_is_subscribed_list (adr))
83 {
84 if (buf && buflen)
85 snprintf (buf, buflen, "%s", adr->mailbox);
86 return 1;
87 }
88 }
89 return 0;
90}
91
92
93static int first_mailing_list (char *buf, size_t buflen, ADDRESS *a)
94{
95 for (; a; a = a->next)
96 {
97 if (mutt_is_subscribed_list (a))
98 {
99 mutt_save_path (buf, buflen, a);
100 return 1;
101 }
102 }
103 return 0;
104}
105
106static void make_from (ENVELOPE *hdr, char *buf, size_t len, int do_lists)
107{
108 int me;
109
110 me = mutt_addr_is_user (hdr->from);
111
112 if (do_lists || me)
113 {
114 if (check_for_mailing_list (hdr->to, "To ", buf, len))
115 return;
116 if (check_for_mailing_list (hdr->cc, "Cc ", buf, len))
117 return;
118 }
119
120 if (me && hdr->to)
121 snprintf (buf, len, "To %s", mutt_get_name (hdr->to));
122 else if (me && hdr->cc)
123 snprintf (buf, len, "Cc %s", mutt_get_name (hdr->cc));
124 else if (me && hdr->bcc)
125 snprintf (buf, len, "Bcc %s", mutt_get_name (hdr->bcc));
126 else if (hdr->from)
127 strfcpy (buf, mutt_get_name (hdr->from), len);
128 else
129 *buf = 0;
130}
131
132static void make_from_addr (ENVELOPE *hdr, char *buf, size_t len, int do_lists)
133{
134 int me;
135
136 me = mutt_addr_is_user (hdr->from);
137
138 if (do_lists || me)
139 {
140 if (check_for_mailing_list_addr (hdr->to, buf, len))
141 return;
142 if (check_for_mailing_list_addr (hdr->cc, buf, len))
143 return;
144 }
145
146 if (me && hdr->to)
147 snprintf (buf, len, "%s", hdr->to->mailbox);
148 else if (me && hdr->cc)
149 snprintf (buf, len, "%s", hdr->cc->mailbox);
150 else if (hdr->from)
151 strfcpy (buf, hdr->from->mailbox, len);
152 else
153 *buf = 0;
154}
155
156static int user_in_addr (ADDRESS *a)
157{
158 for (; a; a = a->next)
159 if (mutt_addr_is_user (a))
160 return 1;
161 return 0;
162}
163
164/* Return values:
165 * 0: user is not in list
166 * 1: user is unique recipient
167 * 2: user is in the TO list
168 * 3: user is in the CC list
169 * 4: user is originator
170 * 5: sent to a subscribed mailinglist
171 */
172int mutt_user_is_recipient (HEADER *h)
173{
174 ENVELOPE *env = h->env;
175
176 if (!h->recip_valid)
177 {
178 h->recip_valid = 1;
179
180 if (mutt_addr_is_user (env->from))
181 h->recipient = 4;
182 else if (user_in_addr (env->to))
183 {
184 if (env->to->next || env->cc)
185 h->recipient = 2; /* non-unique recipient */
186 else
187 h->recipient = 1; /* unique recipient */
188 }
189 else if (user_in_addr (env->cc))
190 h->recipient = 3;
191 else if (check_for_mailing_list (env->to, NULL, NULL, 0))
192 h->recipient = 5;
193 else if (check_for_mailing_list (env->cc, NULL, NULL, 0))
194 h->recipient = 5;
195 else
196 h->recipient = 0;
197 }
198
199 return h->recipient;
200}
201
202static char *apply_subject_mods (ENVELOPE *env)
203{
204 if (env == NULL)
205 return NULL;
206
207 if (SubjectRxList == NULL)
208 return env->subject;
209
210 if (env->subject == NULL || *env->subject == '\0')
211 return env->disp_subj = NULL;
212
213 env->disp_subj = mutt_apply_replace(NULL, 0, env->subject, SubjectRxList);
214 return env->disp_subj;
215}
216
217
218/* %a = address of author
219 * %A = reply-to address (if present; otherwise: address of author
220 * %b = filename of the originating folder
221 * %B = the list to which the letter was sent
222 * %c = size of message in bytes
223 * %C = current message number
224 * %d = date and time of message using $date_format and sender's timezone
225 * %D = date and time of message using $date_format and local timezone
226 * %e = current message number in thread
227 * %E = number of messages in current thread
228 * %f = entire from line
229 * %F = like %n, unless from self
230 * %i = message-id
231 * %l = number of lines in the message
232 * %L = like %F, except `lists' are displayed first
233 * %m = number of messages in the mailbox
234 * %n = name of author
235 * %N = score
236 * %O = like %L, except using address instead of name
237 * %P = progress indicator for builtin pager
238 * %r = comma separated list of To: recipients
239 * %R = comma separated list of Cc: recipients
240 * %s = subject
241 * %S = short message status (e.g., N/O/D/!/r/-)
242 * %t = `to:' field (recipients)
243 * %T = $to_chars
244 * %u = user (login) name of author
245 * %v = first name of author, unless from self
246 * %X = number of MIME attachments
247 * %y = `x-label:' field (if present)
248 * %Y = `x-label:' field (if present, tree unfolded, and != parent's x-label)
249 * %Z = status flags */
250
251static const char *
252hdr_format_str (char *dest,
253 size_t destlen,
254 size_t col,
255 int cols,
256 char op,
257 const char *src,
258 const char *prefix,
259 const char *ifstring,
260 const char *elsestring,
261 unsigned long data,
262 format_flag flags)
263{
264 struct hdr_format_info *hfi = (struct hdr_format_info *) data;
265 HEADER *hdr, *htmp;
266 CONTEXT *ctx;
267 char fmt[SHORT_STRING], buf2[LONG_STRING], ch, *p;
268 int do_locales, i;
269 int optional = (flags & MUTT_FORMAT_OPTIONAL);
270 int threads = ((Sort & SORT_MASK) == SORT_THREADS);
271 int is_index = (flags & MUTT_FORMAT_INDEX);
272#define THREAD_NEW (threads && hdr->collapsed && hdr->num_hidden > 1 && mutt_thread_contains_unread (ctx, hdr) == 1)
273#define THREAD_OLD (threads && hdr->collapsed && hdr->num_hidden > 1 && mutt_thread_contains_unread (ctx, hdr) == 2)
274 size_t len;
275
276 hdr = hfi->hdr;
277 ctx = hfi->ctx;
278
279 dest[0] = 0;
280 switch (op)
281 {
282 case 'A':
283 if (hdr->env->reply_to && hdr->env->reply_to->mailbox)
284 {
285 mutt_format_s (dest, destlen, prefix, mutt_addr_for_display (hdr->env->reply_to));
286 break;
287 }
288 /* fall through */
289
290 case 'a':
291 if (hdr->env->from && hdr->env->from->mailbox)
292 {
293 mutt_format_s (dest, destlen, prefix, mutt_addr_for_display (hdr->env->from));
294 }
295 else
296 dest[0] = '\0';
297 break;
298
299 case 'B':
300 if (!first_mailing_list (dest, destlen, hdr->env->to) &&
301 !first_mailing_list (dest, destlen, hdr->env->cc))
302 dest[0] = 0;
303 if (dest[0])
304 {
305 strfcpy (buf2, dest, sizeof(buf2));
306 mutt_format_s (dest, destlen, prefix, buf2);
307 break;
308 }
309 /* fall through */
310
311 case 'b':
312 if (ctx)
313 {
314 if ((p = strrchr (ctx->path, '/')))
315 strfcpy (dest, p + 1, destlen);
316 else
317 strfcpy (dest, ctx->path, destlen);
318 }
319 else
320 strfcpy(dest, "(null)", destlen);
321 strfcpy (buf2, dest, sizeof(buf2));
322 mutt_format_s (dest, destlen, prefix, buf2);
323 break;
324
325 case 'c':
326 mutt_pretty_size (buf2, sizeof (buf2), (long) hdr->content->length);
327 mutt_format_s (dest, destlen, prefix, buf2);
328 break;
329
330 case 'C':
331 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
332 snprintf (dest, destlen, fmt, hdr->msgno + 1);
333 break;
334
335 case 'd':
336 case 'D':
337 case '{':
338 case '[':
339 case '(':
340 case '<':
341
342 /* preprocess $date_format to handle %Z */
343 {
344 const char *cp;
345 struct tm *tm;
346 time_t T;
347
348 p = dest;
349
350 cp = (op == 'd' || op == 'D') ? (NONULL (DateFmt)) : src;
351 if (*cp == '!')
352 {
353 do_locales = 0;
354 cp++;
355 }
356 else
357 do_locales = 1;
358
359 len = destlen - 1;
360 while (len > 0 && (((op == 'd' || op == 'D') && *cp) ||
361 (op == '{' && *cp != '}') ||
362 (op == '[' && *cp != ']') ||
363 (op == '(' && *cp != ')') ||
364 (op == '<' && *cp != '>')))
365 {
366 if (*cp == '%')
367 {
368 cp++;
369 if ((*cp == 'Z' || *cp == 'z') && (op == 'd' || op == '{'))
370 {
371 if (len >= 5)
372 {
373 sprintf (p, "%c%02u%02u", hdr->zoccident ? '-' : '+',
374 hdr->zhours, hdr->zminutes);
375 p += 5;
376 len -= 5;
377 }
378 else
379 break; /* not enough space left */
380 }
381 else
382 {
383 if (len >= 2)
384 {
385 *p++ = '%';
386 *p++ = *cp;
387 len -= 2;
388 }
389 else
390 break; /* not enough space */
391 }
392 cp++;
393 }
394 else
395 {
396 *p++ = *cp++;
397 len--;
398 }
399 }
400 *p = 0;
401
402 if (op == '[' || op == 'D')
403 tm = localtime (&hdr->date_sent);
404 else if (op == '(')
405 tm = localtime (&hdr->received);
406 else if (op == '<')
407 {
408 T = time (NULL);
409 tm = localtime (&T);
410 }
411 else
412 {
413 /* restore sender's time zone */
414 T = hdr->date_sent;
415 if (hdr->zoccident)
416 T -= (hdr->zhours * 3600 + hdr->zminutes * 60);
417 else
418 T += (hdr->zhours * 3600 + hdr->zminutes * 60);
419 tm = gmtime (&T);
420 }
421
422 if (!do_locales)
423 setlocale (LC_TIME, "C");
424 strftime (buf2, sizeof (buf2), dest, tm);
425 if (!do_locales)
426 setlocale (LC_TIME, "");
427
428 mutt_format_s (dest, destlen, prefix, buf2);
429 if (len > 0 && op != 'd' && op != 'D') /* Skip ending op */
430 src = cp + 1;
431 }
432 break;
433
434 case 'e':
435 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
436 snprintf (dest, destlen, fmt, mutt_messages_in_thread(ctx, hdr, 1));
437 break;
438
439 case 'E':
440 if (!optional)
441 {
442 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
443 snprintf (dest, destlen, fmt, mutt_messages_in_thread(ctx, hdr, 0));
444 }
445 else if (mutt_messages_in_thread(ctx, hdr, 0) <= 1)
446 optional = 0;
447 break;
448
449 case 'f':
450 buf2[0] = 0;
451 rfc822_write_address (buf2, sizeof (buf2), hdr->env->from, 1);
452 mutt_format_s (dest, destlen, prefix, buf2);
453 break;
454
455 case 'F':
456 if (!optional)
457 {
458 make_from (hdr->env, buf2, sizeof (buf2), 0);
459 mutt_format_s (dest, destlen, prefix, buf2);
460 }
461 else if (mutt_addr_is_user (hdr->env->from))
462 optional = 0;
463 break;
464
465 case 'H':
466 /* (Hormel) spam score */
467 if (optional)
468 {
469 optional = hdr->env->spam ? 1 : 0;
470 }
471
472 if (hdr->env->spam)
473 mutt_format_s (dest, destlen, prefix, NONULL (hdr->env->spam->data));
474 else
475 mutt_format_s (dest, destlen, prefix, "");
476
477 break;
478
479 case 'i':
480 mutt_format_s (dest, destlen, prefix, hdr->env->message_id ? hdr->env->message_id : "<no.id>");
481 break;
482
483 case 'l':
484 if (!optional)
485 {
486 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
487 snprintf (dest, destlen, fmt, (int) hdr->lines);
488 }
489 else if (hdr->lines <= 0)
490 optional = 0;
491 break;
492
493 case 'L':
494 if (!optional)
495 {
496 make_from (hdr->env, buf2, sizeof (buf2), 1);
497 mutt_format_s (dest, destlen, prefix, buf2);
498 }
499 else if (!check_for_mailing_list (hdr->env->to, NULL, NULL, 0) &&
500 !check_for_mailing_list (hdr->env->cc, NULL, NULL, 0))
501 {
502 optional = 0;
503 }
504 break;
505
506 case 'm':
507 if (ctx)
508 {
509 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
510 snprintf (dest, destlen, fmt, ctx->msgcount);
511 }
512 else
513 strfcpy(dest, "(null)", destlen);
514 break;
515
516 case 'n':
517 mutt_format_s (dest, destlen, prefix, mutt_get_name (hdr->env->from));
518 break;
519
520 case 'N':
521 if (!optional)
522 {
523 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
524 snprintf (dest, destlen, fmt, hdr->score);
525 }
526 else
527 {
528 if (hdr->score == 0)
529 optional = 0;
530 }
531 break;
532
533 case 'O':
534 if (!optional)
535 {
536 make_from_addr (hdr->env, buf2, sizeof (buf2), 1);
537 if (!option (OPTSAVEADDRESS) && (p = strpbrk (buf2, "%@")))
538 *p = 0;
539 mutt_format_s (dest, destlen, prefix, buf2);
540 }
541 else if (!check_for_mailing_list_addr (hdr->env->to, NULL, 0) &&
542 !check_for_mailing_list_addr (hdr->env->cc, NULL, 0))
543 {
544 optional = 0;
545 }
546 break;
547
548 case 'M':
549 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
550 if (!optional)
551 {
552 if (threads && is_index && hdr->collapsed && hdr->num_hidden > 1)
553 snprintf (dest, destlen, fmt, hdr->num_hidden);
554 else if (is_index && threads)
555 mutt_format_s (dest, destlen, prefix, " ");
556 else
557 *dest = '\0';
558 }
559 else
560 {
561 if (!(threads && is_index && hdr->collapsed && hdr->num_hidden > 1))
562 optional = 0;
563 }
564 break;
565
566 case 'P':
567 strfcpy(dest, NONULL(hfi->pager_progress), destlen);
568 break;
569
570 case 'r':
571 buf2[0] = 0;
572 rfc822_write_address(buf2, sizeof(buf2), hdr->env->to, 1);
573 if (optional && buf2[0] == '\0')
574 optional = 0;
575 mutt_format_s (dest, destlen, prefix, buf2);
576 break;
577
578 case 'R':
579 buf2[0] = 0;
580 rfc822_write_address(buf2, sizeof(buf2), hdr->env->cc, 1);
581 if (optional && buf2[0] == '\0')
582 optional = 0;
583 mutt_format_s (dest, destlen, prefix, buf2);
584 break;
585
586 case 's':
587 {
588 char *subj;
589 if (hdr->env->disp_subj)
590 subj = hdr->env->disp_subj;
591 else if (SubjectRxList)
592 subj = apply_subject_mods(hdr->env);
593 else
594 subj = hdr->env->subject;
595 if (flags & MUTT_FORMAT_TREE && !hdr->collapsed)
596 {
597 if (flags & MUTT_FORMAT_FORCESUBJ)
598 {
599 mutt_format_s (dest, destlen, "", NONULL (subj));
600 snprintf (buf2, sizeof (buf2), "%s%s", hdr->tree, dest);
601 mutt_format_s_tree (dest, destlen, prefix, buf2);
602 }
603 else
604 mutt_format_s_tree (dest, destlen, prefix, hdr->tree);
605 }
606 else
607 mutt_format_s (dest, destlen, prefix, NONULL (subj));
608 }
609 break;
610
611 case 'S':
612 if (hdr->deleted)
613 ch = 'D';
614 else if (hdr->attach_del)
615 ch = 'd';
616 else if (hdr->tagged)
617 ch = '*';
618 else if (hdr->flagged)
619 ch = '!';
620 else if (hdr->replied)
621 ch = 'r';
622 else if (hdr->read && (ctx && ctx->msgnotreadyet != hdr->msgno))
623 ch = '-';
624 else if (hdr->old)
625 ch = 'O';
626 else
627 ch = 'N';
628
629 /* FOO - this is probably unsafe, but we are not likely to have such
630 a short string passed into this routine */
631 *dest = ch;
632 *(dest + 1) = 0;
633 break;
634
635 case 't':
636 buf2[0] = 0;
637 if (!check_for_mailing_list (hdr->env->to, "To ", buf2, sizeof (buf2)) &&
638 !check_for_mailing_list (hdr->env->cc, "Cc ", buf2, sizeof (buf2)))
639 {
640 if (hdr->env->to)
641 snprintf (buf2, sizeof (buf2), "To %s", mutt_get_name (hdr->env->to));
642 else if (hdr->env->cc)
643 snprintf (buf2, sizeof (buf2), "Cc %s", mutt_get_name (hdr->env->cc));
644 }
645 mutt_format_s (dest, destlen, prefix, buf2);
646 break;
647
648 case 'T':
649 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
650 snprintf (dest, destlen, fmt,
651 (Tochars && ((i = mutt_user_is_recipient (hdr))) < Tochars->len) ? Tochars->chars[i] : " ");
652 break;
653
654 case 'u':
655 if (hdr->env->from && hdr->env->from->mailbox)
656 {
657 strfcpy (buf2, mutt_addr_for_display (hdr->env->from), sizeof (buf2));
658 if ((p = strpbrk (buf2, "%@")))
659 *p = 0;
660 }
661 else
662 buf2[0] = 0;
663 mutt_format_s (dest, destlen, prefix, buf2);
664 break;
665
666 case 'v':
667 if (mutt_addr_is_user (hdr->env->from))
668 {
669 if (hdr->env->to)
670 mutt_format_s (buf2, sizeof (buf2), prefix, mutt_get_name (hdr->env->to));
671 else if (hdr->env->cc)
672 mutt_format_s (buf2, sizeof (buf2), prefix, mutt_get_name (hdr->env->cc));
673 else
674 *buf2 = 0;
675 }
676 else
677 mutt_format_s (buf2, sizeof (buf2), prefix, mutt_get_name (hdr->env->from));
678 if ((p = strpbrk (buf2, " %@")))
679 *p = 0;
680 mutt_format_s (dest, destlen, prefix, buf2);
681 break;
682
683 case 'Z':
684
685 ch = ' ';
686
687 if (WithCrypto && hdr->security & GOODSIGN)
688 ch = 'S';
689 else if (WithCrypto && hdr->security & ENCRYPT)
690 ch = 'P';
691 else if (WithCrypto && hdr->security & SIGN)
692 ch = 's';
693 else if ((WithCrypto & APPLICATION_PGP) &&
694 ((hdr->security & PGPKEY) == PGPKEY))
695 ch = 'K';
696
697 snprintf (buf2, sizeof (buf2),
698 "%c%c%s", (THREAD_NEW ? 'n' : (THREAD_OLD ? 'o' :
699 ((hdr->read && (ctx && ctx->msgnotreadyet != hdr->msgno))
700 ? (hdr->replied ? 'r' : ' ') : (hdr->old ? 'O' : 'N')))),
701 hdr->deleted ? 'D' : (hdr->attach_del ? 'd' : ch),
702 hdr->tagged ? "*" :
703 (hdr->flagged ? "!" :
704 (Tochars && ((i = mutt_user_is_recipient (hdr)) < Tochars->len) ? Tochars->chars[i] : " ")));
705 mutt_format_s (dest, destlen, prefix, buf2);
706 break;
707
708 case 'X':
709 {
710 int count = mutt_count_body_parts (ctx, hdr);
711
712 /* The recursion allows messages without depth to return 0. */
713 if (optional)
714 optional = count != 0;
715
716 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
717 snprintf (dest, destlen, fmt, count);
718 }
719 break;
720
721 case 'y':
722 if (optional)
723 optional = hdr->env->x_label ? 1 : 0;
724
725 mutt_format_s (dest, destlen, prefix, NONULL (hdr->env->x_label));
726 break;
727
728 case 'Y':
729 if (hdr->env->x_label)
730 {
731 i = 1; /* reduce reuse recycle */
732 htmp = NULL;
733 if (flags & MUTT_FORMAT_TREE
734 && (hdr->thread->prev && hdr->thread->prev->message
735 && hdr->thread->prev->message->env->x_label))
736 htmp = hdr->thread->prev->message;
737 else if (flags & MUTT_FORMAT_TREE
738 && (hdr->thread->parent && hdr->thread->parent->message
739 && hdr->thread->parent->message->env->x_label))
740 htmp = hdr->thread->parent->message;
741 if (htmp && mutt_strcasecmp (hdr->env->x_label,
742 htmp->env->x_label) == 0)
743 i = 0;
744 }
745 else
746 i = 0;
747
748 if (optional)
749 optional = i;
750
751 if (i)
752 mutt_format_s (dest, destlen, prefix, NONULL (hdr->env->x_label));
753 else
754 mutt_format_s (dest, destlen, prefix, "");
755
756 break;
757
758 case '@':
759 {
760 const char *end = src;
761 static unsigned char recurse = 0;
762
763 while (*end && *end != '@')
764 end++;
765 if ((*end == '@') && (recurse < 20))
766 {
767 recurse++;
768 mutt_substrcpy (buf2, src, end, sizeof(buf2));
769 mutt_FormatString (buf2, sizeof(buf2), col, cols,
770 NONULL (mutt_idxfmt_hook (buf2, ctx, hdr)),
771 hdr_format_str, (unsigned long) hfi, flags);
772 mutt_format_s (dest, destlen, prefix, buf2);
773 recurse--;
774
775 src = end + 1;
776 break;
777 }
778 }
779 /* else fall through */
780
781 default:
782 snprintf (dest, destlen, "%%%s%c", prefix, op);
783 break;
784 }
785
786 if (optional)
787 mutt_FormatString (dest, destlen, col, cols, ifstring, hdr_format_str, (unsigned long) hfi, flags);
788 else if (flags & MUTT_FORMAT_OPTIONAL)
789 mutt_FormatString (dest, destlen, col, cols, elsestring, hdr_format_str, (unsigned long) hfi, flags);
790
791 return (src);
792#undef THREAD_NEW
793#undef THREAD_OLD
794}
795
796void
797_mutt_make_string (char *dest, size_t destlen, const char *s, CONTEXT *ctx, HEADER *hdr, format_flag flags)
798{
799 struct hdr_format_info hfi;
800
801 hfi.hdr = hdr;
802 hfi.ctx = ctx;
803 hfi.pager_progress = 0;
804
805 mutt_FormatString (dest, destlen, 0, MuttIndexWindow->cols, s, hdr_format_str, (unsigned long) &hfi, flags);
806}
807
808void
809mutt_make_string_info (char *dst, size_t dstlen, int cols, const char *s, struct hdr_format_info *hfi, format_flag flags)
810{
811 mutt_FormatString (dst, dstlen, 0, cols, s, hdr_format_str, (unsigned long) hfi, flags);
812}