NeoMutt  2024-02-01-23-g345d7b
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
hdrline.c
Go to the documentation of this file.
1
38#include "config.h"
39#include <stdbool.h>
40#include <stdint.h>
41#include <stdio.h>
42#include <stdlib.h>
43#include <string.h>
44#include <time.h>
45#include "mutt/lib.h"
46#include "address/lib.h"
47#include "config/lib.h"
48#include "email/lib.h"
49#include "core/lib.h"
50#include "alias/lib.h"
51#include "gui/lib.h"
52#include "hdrline.h"
53#include "attach/lib.h"
54#include "color/lib.h"
55#include "ncrypt/lib.h"
56#include "format_flags.h"
57#include "hook.h"
58#include "maillist.h"
59#include "mutt_thread.h"
60#include "muttlib.h"
61#include "mx.h"
62#include "sort.h"
63#include "subjectrx.h"
64#ifdef USE_NOTMUCH
65#include "notmuch/lib.h"
66#endif
67
72{
73 struct Mailbox *mailbox;
75 struct Email *email;
76 const char *pager_progress;
77};
78
85{
92};
93
104static size_t add_index_color(char *buf, size_t buflen, MuttFormatFlags flags, enum ColorId color)
105{
106 /* only add color markers if we are operating on main index entries. */
107 if (!(flags & MUTT_FORMAT_INDEX))
108 return 0;
109
110 /* this item is going to be passed to an external filter */
111 if (flags & MUTT_FORMAT_NOFILTER)
112 return 0;
113
114 if (color == MT_COLOR_INDEX)
115 { /* buf might be uninitialized other cases */
116 const size_t len = mutt_str_len(buf);
117 buf += len;
118 buflen -= len;
119 }
120
121 if (buflen <= 2)
122 return 0;
123
124 buf[0] = MUTT_SPECIAL_INDEX;
125 buf[1] = color;
126 buf[2] = '\0';
127
128 return 2;
129}
130
139static const char *make_from_prefix(enum FieldType disp)
140{
141 /* need 2 bytes at the end, one for the space, another for NUL */
142 static char padded[8];
143 static const char *long_prefixes[DISP_MAX] = {
144 [DISP_TO] = "To ", [DISP_CC] = "Cc ", [DISP_BCC] = "Bcc ",
145 [DISP_FROM] = "", [DISP_PLAIN] = "",
146 };
147
148 const struct MbTable *c_from_chars = cs_subset_mbtable(NeoMutt->sub, "from_chars");
149
150 if (!c_from_chars || !c_from_chars->chars || (c_from_chars->len == 0))
151 return long_prefixes[disp];
152
153 const char *pchar = mbtable_get_nth_wchar(c_from_chars, disp);
154 if (mutt_str_len(pchar) == 0)
155 return "";
156
157 snprintf(padded, sizeof(padded), "%s ", pchar);
158 return padded;
159}
160
175static void make_from(struct Envelope *env, char *buf, size_t buflen,
176 bool do_lists, MuttFormatFlags flags)
177{
178 if (!env || !buf)
179 return;
180
181 bool me;
182 enum FieldType disp;
183 struct AddressList *name = NULL;
184
186
187 if (do_lists || me)
188 {
189 if (check_for_mailing_list(&env->to, make_from_prefix(DISP_TO), buf, buflen))
190 return;
191 if (check_for_mailing_list(&env->cc, make_from_prefix(DISP_CC), buf, buflen))
192 return;
193 }
194
195 if (me && !TAILQ_EMPTY(&env->to))
196 {
197 disp = (flags & MUTT_FORMAT_PLAIN) ? DISP_PLAIN : DISP_TO;
198 name = &env->to;
199 }
200 else if (me && !TAILQ_EMPTY(&env->cc))
201 {
202 disp = DISP_CC;
203 name = &env->cc;
204 }
205 else if (me && !TAILQ_EMPTY(&env->bcc))
206 {
207 disp = DISP_BCC;
208 name = &env->bcc;
209 }
210 else if (!TAILQ_EMPTY(&env->from))
211 {
212 disp = DISP_FROM;
213 name = &env->from;
214 }
215 else
216 {
217 *buf = '\0';
218 return;
219 }
220
221 snprintf(buf, buflen, "%s%s", make_from_prefix(disp), mutt_get_name(TAILQ_FIRST(name)));
222}
223
231static void make_from_addr(struct Envelope *env, char *buf, size_t buflen, bool do_lists)
232{
233 if (!env || !buf)
234 return;
235
236 bool me = mutt_addr_is_user(TAILQ_FIRST(&env->from));
237
238 if (do_lists || me)
239 {
240 if (check_for_mailing_list_addr(&env->to, buf, buflen))
241 return;
242 if (check_for_mailing_list_addr(&env->cc, buf, buflen))
243 return;
244 }
245
246 if (me && !TAILQ_EMPTY(&env->to))
247 snprintf(buf, buflen, "%s", buf_string(TAILQ_FIRST(&env->to)->mailbox));
248 else if (me && !TAILQ_EMPTY(&env->cc))
249 snprintf(buf, buflen, "%s", buf_string(TAILQ_FIRST(&env->cc)->mailbox));
250 else if (!TAILQ_EMPTY(&env->from))
251 mutt_str_copy(buf, buf_string(TAILQ_FIRST(&env->from)->mailbox), buflen);
252 else
253 *buf = '\0';
254}
255
261static bool user_in_addr(struct AddressList *al)
262{
263 struct Address *a = NULL;
264 TAILQ_FOREACH(a, al, entries)
265 if (mutt_addr_is_user(a))
266 return true;
267 return false;
268}
269
275static enum ToChars user_is_recipient(struct Email *e)
276{
277 if (!e || !e->env)
279
280 struct Envelope *env = e->env;
281
282 if (!e->recip_valid)
283 {
284 e->recip_valid = true;
285
287 {
289 }
290 else if (user_in_addr(&env->to))
291 {
292 if (TAILQ_NEXT(TAILQ_FIRST(&env->to), entries) || !TAILQ_EMPTY(&env->cc))
293 e->recipient = FLAG_CHAR_TO_TO; /* non-unique recipient */
294 else
295 e->recipient = FLAG_CHAR_TO_UNIQUE; /* unique recipient */
296 }
297 else if (user_in_addr(&env->cc))
298 {
300 }
301 else if (check_for_mailing_list(&env->to, NULL, NULL, 0))
302 {
304 }
305 else if (check_for_mailing_list(&env->cc, NULL, NULL, 0))
306 {
308 }
309 else if (user_in_addr(&env->reply_to))
310 {
312 }
313 else
314 {
316 }
317 }
318
319 return e->recipient;
320}
321
327static bool thread_is_new(struct Email *e)
328{
329 return e->collapsed && (e->num_hidden > 1) && (mutt_thread_contains_unread(e) == 1);
330}
331
337static bool thread_is_old(struct Email *e)
338{
339 return e->collapsed && (e->num_hidden > 1) && (mutt_thread_contains_unread(e) == 2);
340}
341
399static const char *index_format_str(char *buf, size_t buflen, size_t col, int cols,
400 char op, const char *src, const char *prec,
401 const char *if_str, const char *else_str,
402 intptr_t data, MuttFormatFlags flags)
403{
404 struct HdrFormatInfo *hfi = (struct HdrFormatInfo *) data;
405 char fmt[128] = { 0 };
406 char tmp[1024] = { 0 };
407 char *p = NULL;
408 bool optional = (flags & MUTT_FORMAT_OPTIONAL);
409 const bool threads = mutt_using_threads();
410 int is_index = (flags & MUTT_FORMAT_INDEX);
411 size_t colorlen;
412
413 struct Email *e = hfi->email;
414 size_t msg_in_pager = hfi->msg_in_pager;
415 struct Mailbox *m = hfi->mailbox;
416
417 if (!e || !e->env)
418 return src;
419
420 const struct Address *reply_to = TAILQ_FIRST(&e->env->reply_to);
421 const struct Address *from = TAILQ_FIRST(&e->env->from);
422 const struct Address *to = TAILQ_FIRST(&e->env->to);
423 const struct Address *cc = TAILQ_FIRST(&e->env->cc);
424
425 const struct MbTable *c_crypt_chars = cs_subset_mbtable(NeoMutt->sub, "crypt_chars");
426 const struct MbTable *c_flag_chars = cs_subset_mbtable(NeoMutt->sub, "flag_chars");
427 const struct MbTable *c_to_chars = cs_subset_mbtable(NeoMutt->sub, "to_chars");
428 const char *const c_date_format = cs_subset_string(NeoMutt->sub, "date_format");
429
430 buf[0] = '\0';
431 switch (op)
432 {
433 case 'A':
434 case 'I':
435 if (op == 'A')
436 {
437 if (reply_to && reply_to->mailbox)
438 {
439 colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_AUTHOR);
440 mutt_format(buf + colorlen, buflen - colorlen, prec,
441 mutt_addr_for_display(reply_to), false);
442 add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
443 break;
444 }
445 }
446 else
447 {
448 if (mutt_mb_get_initials(mutt_get_name(from), tmp, sizeof(tmp)))
449 {
450 colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_AUTHOR);
451 mutt_format(buf + colorlen, buflen - colorlen, prec, tmp, false);
452 add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
453 break;
454 }
455 }
457
458 case 'a':
459 colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_AUTHOR);
460 if (from && from->mailbox)
461 {
462 mutt_format(buf + colorlen, buflen - colorlen, prec,
463 mutt_addr_for_display(from), false);
464 }
465 else
466 {
467 mutt_format(buf + colorlen, buflen - colorlen, prec, "", false);
468 }
469 add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
470 break;
471
472 case 'B':
473 case 'K':
474 if (first_mailing_list(buf, buflen, &e->env->to) ||
475 first_mailing_list(buf, buflen, &e->env->cc))
476 {
477 mutt_str_copy(tmp, buf, sizeof(tmp));
478 mutt_format(buf, buflen, prec, tmp, false);
479 }
480 else if (optional)
481 {
482 optional = false;
483 }
484 break;
485
486 case 'b':
487 if (m)
488 {
489 p = strrchr(mailbox_path(m), '/');
490#ifdef USE_NOTMUCH
491 if (m->type == MUTT_NOTMUCH)
492 {
493 char *rel_path = nm_email_get_folder_rel_db(m, e);
494 if (rel_path)
495 p = rel_path;
496 }
497#endif
498
499 if (p)
500 mutt_str_copy(buf, p + 1, buflen);
501 else
502 mutt_str_copy(buf, mailbox_path(m), buflen);
503 }
504 else
505 {
506 mutt_str_copy(buf, "(null)", buflen);
507 }
508 mutt_str_copy(tmp, buf, sizeof(tmp));
509 mutt_format(buf, buflen, prec, tmp, false);
510 break;
511
512 case 'c':
513 colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_SIZE);
514 if (src[0] == 'r')
515 {
516 mutt_str_pretty_size(tmp, sizeof(tmp), email_size(e));
517 src++;
518 }
519 else
520 {
521 mutt_str_pretty_size(tmp, sizeof(tmp), e->body->length);
522 }
523 mutt_format(buf + colorlen, buflen - colorlen, prec, tmp, false);
524 add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
525 break;
526
527 case 'C':
528 colorlen = add_index_color(fmt, sizeof(fmt), flags, MT_COLOR_INDEX_NUMBER);
529 snprintf(fmt + colorlen, sizeof(fmt) - colorlen, "%%%sd", prec);
530 add_index_color(fmt + colorlen, sizeof(fmt) - colorlen, flags, MT_COLOR_INDEX);
531 snprintf(buf, buflen, fmt, e->msgno + 1);
532 break;
533
534 case 'd':
535 case 'D':
536 case '{':
537 case '[':
538 case '(':
539 case '<':
540 /* preprocess $date_format to handle %Z */
541 {
542 const char *cp = NULL;
543 time_t now;
544 int j = 0;
545
546 if (optional && ((op == '[') || (op == '(')))
547 {
548 now = mutt_date_now();
549 struct tm tm = mutt_date_localtime(now);
550 now -= (op == '(') ? e->received : e->date_sent;
551
552 char *is = (char *) prec;
553 bool invert = false;
554 if (*is == '>')
555 {
556 invert = true;
557 is++;
558 }
559
560 while (*is && (*is != '?'))
561 {
562 int t = strtol(is, &is, 10);
563 /* semi-broken (assuming 30 days in all months) */
564 switch (*(is++))
565 {
566 case 'y':
567 if (t > 1)
568 {
569 t--;
570 t *= (60 * 60 * 24 * 365);
571 }
572 t += ((tm.tm_mon * 60 * 60 * 24 * 30) + (tm.tm_mday * 60 * 60 * 24) +
573 (tm.tm_hour * 60 * 60) + (tm.tm_min * 60) + tm.tm_sec);
574 break;
575
576 case 'm':
577 if (t > 1)
578 {
579 t--;
580 t *= (60 * 60 * 24 * 30);
581 }
582 t += ((tm.tm_mday * 60 * 60 * 24) + (tm.tm_hour * 60 * 60) +
583 (tm.tm_min * 60) + tm.tm_sec);
584 break;
585
586 case 'w':
587 if (t > 1)
588 {
589 t--;
590 t *= (60 * 60 * 24 * 7);
591 }
592 t += ((tm.tm_wday * 60 * 60 * 24) + (tm.tm_hour * 60 * 60) +
593 (tm.tm_min * 60) + tm.tm_sec);
594 break;
595
596 case 'd':
597 if (t > 1)
598 {
599 t--;
600 t *= (60 * 60 * 24);
601 }
602 t += ((tm.tm_hour * 60 * 60) + (tm.tm_min * 60) + tm.tm_sec);
603 break;
604
605 case 'H':
606 if (t > 1)
607 {
608 t--;
609 t *= (60 * 60);
610 }
611 t += ((tm.tm_min * 60) + tm.tm_sec);
612 break;
613
614 case 'M':
615 if (t > 1)
616 {
617 t--;
618 t *= (60);
619 }
620 t += (tm.tm_sec);
621 break;
622
623 default:
624 break;
625 }
626 j += t;
627 }
628
629 if (j < 0)
630 j *= -1;
631
632 if (((now > j) || (now < (-1 * j))) ^ invert)
633 optional = false;
634 break;
635 }
636
637 p = buf;
638
639 cp = ((op == 'd') || (op == 'D')) ? (NONULL(c_date_format)) : src;
640 bool use_c_locale = false;
641 if (*cp == '!')
642 {
643 use_c_locale = true;
644 cp++;
645 }
646
647 size_t len = buflen - 1;
648 while ((len > 0) &&
649 ((((op == 'd') || (op == 'D')) && *cp) ||
650 ((op == '{') && (*cp != '}')) || ((op == '[') && (*cp != ']')) ||
651 ((op == '(') && (*cp != ')')) || ((op == '<') && (*cp != '>'))))
652 {
653 if (*cp == '%')
654 {
655 cp++;
656 if (((*cp == 'Z') || (*cp == 'z')) && ((op == 'd') || (op == '{')))
657 {
658 if (len >= 5)
659 {
660 sprintf(p, "%c%02u%02u", e->zoccident ? '-' : '+', e->zhours, e->zminutes);
661 p += 5;
662 len -= 5;
663 }
664 else
665 {
666 break; /* not enough space left */
667 }
668 }
669 else
670 {
671 if (len >= 2)
672 {
673 *p++ = '%';
674 *p++ = *cp;
675 len -= 2;
676 }
677 else
678 {
679 break; /* not enough space */
680 }
681 }
682 cp++;
683 }
684 else
685 {
686 *p++ = *cp++;
687 len--;
688 }
689 }
690 *p = '\0';
691
692 struct tm tm = { 0 };
693 if ((op == '[') || (op == 'D'))
694 {
696 }
697 else if (op == '(')
698 {
700 }
701 else if (op == '<')
702 {
704 }
705 else
706 {
707 /* restore sender's time zone */
708 now = e->date_sent;
709 if (e->zoccident)
710 now -= (e->zhours * 3600 + e->zminutes * 60);
711 else
712 now += (e->zhours * 3600 + e->zminutes * 60);
713 tm = mutt_date_gmtime(now);
714 }
715
716 if (use_c_locale)
717 strftime_l(tmp, sizeof(tmp), buf, &tm, NeoMutt->time_c_locale);
718 else
719 strftime(tmp, sizeof(tmp), buf, &tm);
720
721 colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_DATE);
722 mutt_format(buf + colorlen, buflen - colorlen, prec, tmp, false);
723 add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
724
725 if ((len > 0) && (op != 'd') && (op != 'D')) /* Skip ending op */
726 src = cp + 1;
727 break;
728 }
729
730 case 'e':
731 snprintf(fmt, sizeof(fmt), "%%%sd", prec);
732 snprintf(buf, buflen, fmt, mutt_messages_in_thread(m, e, MIT_POSITION));
733 break;
734
735 case 'E':
736 if (!optional)
737 {
738 snprintf(fmt, sizeof(fmt), "%%%sd", prec);
739 snprintf(buf, buflen, fmt, mutt_messages_in_thread(m, e, MIT_NUM_MESSAGES));
740 }
741 else if (mutt_messages_in_thread(m, e, MIT_NUM_MESSAGES) <= 1)
742 {
743 optional = false;
744 }
745 break;
746
747 case 'f':
748 {
749 struct Buffer *tmpbuf = buf_pool_get();
750 mutt_addrlist_write(&e->env->from, tmpbuf, true);
751 mutt_str_copy(tmp, buf_string(tmpbuf), sizeof(tmp));
752 buf_pool_release(&tmpbuf);
753 mutt_format(buf, buflen, prec, tmp, false);
754 break;
755 }
756
757 case 'F':
758 if (!optional)
759 {
760 const bool is_plain = (src[0] == 'p');
761 colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_AUTHOR);
762 make_from(e->env, tmp, sizeof(tmp), false,
764 mutt_format(buf + colorlen, buflen - colorlen, prec, tmp, false);
765 add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
766
767 if (is_plain)
768 src++;
769 }
770 else if (mutt_addr_is_user(from))
771 {
772 optional = false;
773 }
774 break;
775
776 case 'g':
777 {
778 struct Buffer *tags = buf_pool_get();
780 if (!optional)
781 {
782 colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_TAGS);
783 mutt_format(buf + colorlen, buflen - colorlen, prec, buf_string(tags), false);
784 add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
785 }
786 else if (buf_is_empty(tags))
787 {
788 optional = false;
789 }
790 buf_pool_release(&tags);
791 break;
792 }
793
794 case 'G':
795 {
796 char format[3] = { 0 };
797 char *tag = NULL;
798
799 if (!optional)
800 {
801 format[0] = op;
802 format[1] = *src;
803 format[2] = '\0';
804
805 tag = mutt_hash_find(TagFormats, format);
806 if (tag)
807 {
808 struct Buffer *tags = buf_pool_get();
810 colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_TAG);
811 mutt_format(buf + colorlen, buflen - colorlen, prec, buf_string(tags), false);
812 add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
813 buf_pool_release(&tags);
814 }
815 src++;
816 }
817 else
818 {
819 format[0] = op;
820 format[1] = *prec;
821 format[2] = '\0';
822
823 tag = mutt_hash_find(TagFormats, format);
824 if (tag)
825 {
826 struct Buffer *tags = buf_pool_get();
828 if (buf_is_empty(tags))
829 optional = false;
830 buf_pool_release(&tags);
831 }
832 }
833 break;
834 }
835
836 case 'H':
837 /* (Hormel) spam score */
838 if (optional)
839 optional = !buf_is_empty(&e->env->spam);
840
841 mutt_format(buf, buflen, prec, buf_string(&e->env->spam), false);
842 break;
843
844 case 'i':
845 mutt_format(buf, buflen, prec,
846 e->env->message_id ? e->env->message_id : "<no.id>", false);
847 break;
848
849 case 'J':
850 {
851 bool have_tags = true;
852 struct Buffer *tags = buf_pool_get();
854 if (!buf_is_empty(tags))
855 {
856 if (flags & MUTT_FORMAT_TREE)
857 {
858 struct Buffer *parent_tags = buf_pool_get();
859 if (e->thread->prev && e->thread->prev->message)
860 {
862 }
863 if (buf_is_empty(parent_tags) && e->thread->parent &&
864 e->thread->parent->message)
865 {
867 }
868 if (!buf_is_empty(parent_tags) && buf_istr_equal(tags, parent_tags))
869 have_tags = false;
870 buf_pool_release(&parent_tags);
871 }
872 }
873 else
874 {
875 have_tags = false;
876 }
877
878 if (optional)
879 optional = have_tags;
880
881 colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_TAGS);
882 if (have_tags)
883 mutt_format(buf + colorlen, buflen - colorlen, prec, buf_string(tags), false);
884 else
885 mutt_format(buf + colorlen, buflen - colorlen, prec, "", false);
886 add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
887 buf_pool_release(&tags);
888 break;
889 }
890
891 case 'l':
892 if (!optional)
893 {
894 snprintf(fmt, sizeof(fmt), "%%%sd", prec);
895 colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_SIZE);
896 snprintf(buf + colorlen, buflen - colorlen, fmt, e->lines);
897 add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
898 }
899 else if (e->lines <= 0)
900 {
901 optional = false;
902 }
903 break;
904
905 case 'L':
906 if (!optional)
907 {
908 colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_AUTHOR);
909 make_from(e->env, tmp, sizeof(tmp), true, flags);
910 mutt_format(buf + colorlen, buflen - colorlen, prec, tmp, false);
911 add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
912 }
913 else if (!check_for_mailing_list(&e->env->to, NULL, NULL, 0) &&
914 !check_for_mailing_list(&e->env->cc, NULL, NULL, 0))
915 {
916 optional = false;
917 }
918 break;
919
920 case 'm':
921 if (m)
922 {
923 snprintf(fmt, sizeof(fmt), "%%%sd", prec);
924 snprintf(buf, buflen, fmt, m->msg_count);
925 }
926 else
927 {
928 mutt_str_copy(buf, "(null)", buflen);
929 }
930 break;
931
932 case 'n':
933 colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_AUTHOR);
934 mutt_format(buf + colorlen, buflen - colorlen, prec, mutt_get_name(from), false);
935 add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
936 break;
937
938 case 'M':
939 snprintf(fmt, sizeof(fmt), "%%%sd", prec);
940 if (!optional)
941 {
942 colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_COLLAPSED);
943 if (threads && is_index && e->collapsed && (e->num_hidden > 1))
944 {
945 snprintf(buf + colorlen, buflen - colorlen, fmt, e->num_hidden);
946 add_index_color(buf, buflen - colorlen, flags, MT_COLOR_INDEX);
947 }
948 else if (is_index && threads)
949 {
950 mutt_format(buf + colorlen, buflen - colorlen, prec, " ", false);
951 add_index_color(buf, buflen - colorlen, flags, MT_COLOR_INDEX);
952 }
953 else
954 {
955 *buf = '\0';
956 }
957 }
958 else
959 {
960 if (!(threads && is_index && e->collapsed && (e->num_hidden > 1)))
961 optional = false;
962 }
963 break;
964
965 case 'N':
966 if (!optional)
967 {
968 snprintf(fmt, sizeof(fmt), "%%%sd", prec);
969 snprintf(buf, buflen, fmt, e->score);
970 }
971 else
972 {
973 if (e->score == 0)
974 optional = false;
975 }
976 break;
977
978 case 'O':
979 if (!optional)
980 {
981 make_from_addr(e->env, tmp, sizeof(tmp), true);
982 const bool c_save_address = cs_subset_bool(NeoMutt->sub, "save_address");
983 if (!c_save_address && (p = strpbrk(tmp, "%@")))
984 *p = '\0';
985 mutt_format(buf, buflen, prec, tmp, false);
986 }
987 else if (!check_for_mailing_list_addr(&e->env->to, NULL, 0) &&
988 !check_for_mailing_list_addr(&e->env->cc, NULL, 0))
989 {
990 optional = false;
991 }
992 break;
993
994 case 'P':
995 mutt_str_copy(buf, hfi->pager_progress, buflen);
996 break;
997
998 case 'q':
999 mutt_format(buf, buflen, prec, e->env->newsgroups ? e->env->newsgroups : "", false);
1000 break;
1001
1002 case 'r':
1003 {
1004 struct Buffer *tmpbuf = buf_pool_get();
1005 mutt_addrlist_write(&e->env->to, tmpbuf, true);
1006 mutt_str_copy(tmp, buf_string(tmpbuf), sizeof(tmp));
1007 buf_pool_release(&tmpbuf);
1008 if (optional && (tmp[0] == '\0'))
1009 optional = false;
1010 mutt_format(buf, buflen, prec, tmp, false);
1011 break;
1012 }
1013
1014 case 'R':
1015 {
1016 struct Buffer *tmpbuf = buf_pool_get();
1017 mutt_addrlist_write(&e->env->cc, tmpbuf, true);
1018 mutt_str_copy(tmp, buf_string(tmpbuf), sizeof(tmp));
1019 buf_pool_release(&tmpbuf);
1020 if (optional && (tmp[0] == '\0'))
1021 optional = false;
1022 mutt_format(buf, buflen, prec, tmp, false);
1023 break;
1024 }
1025
1026 case 's':
1027 {
1029 char *subj = NULL;
1030 if (e->env->disp_subj)
1031 subj = e->env->disp_subj;
1032 else
1033 subj = e->env->subject;
1034 if (flags & MUTT_FORMAT_TREE && !e->collapsed)
1035 {
1036 if (flags & MUTT_FORMAT_FORCESUBJ)
1037 {
1038 colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_SUBJECT);
1039 mutt_format(buf + colorlen, buflen - colorlen, "", NONULL(subj), false);
1040 add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1041 snprintf(tmp, sizeof(tmp), "%s%s", e->tree, buf);
1042 mutt_format(buf, buflen, prec, tmp, true);
1043 }
1044 else
1045 {
1046 mutt_format(buf, buflen, prec, e->tree, true);
1047 }
1048 }
1049 else
1050 {
1051 colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_SUBJECT);
1052 mutt_format(buf + colorlen, buflen - colorlen, prec, NONULL(subj), false);
1053 add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1054 }
1055 break;
1056 }
1057
1058 case 'S':
1059 {
1060 const char *wch = NULL;
1061 if (e->deleted)
1062 wch = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_DELETED);
1063 else if (e->attach_del)
1065 else if (e->tagged)
1066 wch = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_TAGGED);
1067 else if (e->flagged)
1068 wch = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_IMPORTANT);
1069 else if (e->replied)
1070 wch = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_REPLIED);
1071 else if (e->read && (msg_in_pager != e->msgno))
1072 wch = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_SEMPTY);
1073 else if (e->old)
1074 wch = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_OLD);
1075 else
1076 wch = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_NEW);
1077
1078 snprintf(tmp, sizeof(tmp), "%s", wch);
1079 colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_FLAGS);
1080 mutt_format(buf + colorlen, buflen - colorlen, prec, tmp, false);
1081 add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1082 break;
1083 }
1084
1085 case 't':
1086 tmp[0] = '\0';
1087 if (!check_for_mailing_list(&e->env->to, "To ", tmp, sizeof(tmp)) &&
1088 !check_for_mailing_list(&e->env->cc, "Cc ", tmp, sizeof(tmp)))
1089 {
1090 if (to)
1091 snprintf(tmp, sizeof(tmp), "To %s", mutt_get_name(to));
1092 else if (cc)
1093 snprintf(tmp, sizeof(tmp), "Cc %s", mutt_get_name(cc));
1094 }
1095 mutt_format(buf, buflen, prec, tmp, false);
1096 break;
1097
1098 case 'T':
1099 {
1100 int i;
1101 snprintf(fmt, sizeof(fmt), "%%%ss", prec);
1102 snprintf(buf, buflen, fmt,
1103 (c_to_chars && ((i = user_is_recipient(e))) < c_to_chars->len) ?
1104 c_to_chars->chars[i] :
1105 " ");
1106 break;
1107 }
1108
1109 case 'u':
1110 if (from && from->mailbox)
1111 {
1112 mutt_str_copy(tmp, mutt_addr_for_display(from), sizeof(tmp));
1113 p = strpbrk(tmp, "%@");
1114 if (p)
1115 *p = '\0';
1116 }
1117 else
1118 {
1119 tmp[0] = '\0';
1120 }
1121 mutt_format(buf, buflen, prec, tmp, false);
1122 break;
1123
1124 case 'v':
1125 if (mutt_addr_is_user(from))
1126 {
1127 if (to)
1128 mutt_format(tmp, sizeof(tmp), prec, mutt_get_name(to), false);
1129 else if (cc)
1130 mutt_format(tmp, sizeof(tmp), prec, mutt_get_name(cc), false);
1131 else
1132 *tmp = '\0';
1133 }
1134 else
1135 {
1136 mutt_format(tmp, sizeof(tmp), prec, mutt_get_name(from), false);
1137 }
1138 p = strpbrk(tmp, " %@");
1139 if (p)
1140 *p = '\0';
1141 mutt_format(buf, buflen, prec, tmp, false);
1142 break;
1143
1144 case 'W':
1145 if (!optional)
1146 {
1147 mutt_format(buf, buflen, prec,
1148 e->env->organization ? e->env->organization : "", false);
1149 }
1150 else if (!e->env->organization)
1151 {
1152 optional = false;
1153 }
1154 break;
1155
1156 case 'x':
1157 if (!optional)
1158 {
1159 mutt_format(buf, buflen, prec,
1160 e->env->x_comment_to ? e->env->x_comment_to : "", false);
1161 }
1162 else if (!e->env->x_comment_to)
1163 {
1164 optional = false;
1165 }
1166 break;
1167
1168 case 'X':
1169 {
1170 struct Message *msg = mx_msg_open(m, e);
1171 if (msg)
1172 {
1173 int count = mutt_count_body_parts(m, e, msg->fp);
1174 mx_msg_close(m, &msg);
1175
1176 /* The recursion allows messages without depth to return 0. */
1177 if (optional)
1178 optional = (count != 0);
1179
1180 snprintf(fmt, sizeof(fmt), "%%%sd", prec);
1181 snprintf(buf, buflen, fmt, count);
1182 }
1183 break;
1184 }
1185
1186 case 'y':
1187 if (optional)
1188 optional = (e->env->x_label != NULL);
1189
1190 colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_LABEL);
1191 mutt_format(buf + colorlen, buflen - colorlen, prec, NONULL(e->env->x_label), false);
1192 add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1193 break;
1194
1195 case 'Y':
1196 {
1197 bool label = true;
1198 if (e->env->x_label)
1199 {
1200 struct Email *e_tmp = NULL;
1201 if (flags & MUTT_FORMAT_TREE && (e->thread->prev && e->thread->prev->message &&
1202 e->thread->prev->message->env->x_label))
1203 {
1204 e_tmp = e->thread->prev->message;
1205 }
1206 else if (flags & MUTT_FORMAT_TREE &&
1207 (e->thread->parent && e->thread->parent->message &&
1209 {
1210 e_tmp = e->thread->parent->message;
1211 }
1212 if (e_tmp && mutt_istr_equal(e->env->x_label, e_tmp->env->x_label))
1213 label = false;
1214 }
1215 else
1216 {
1217 label = false;
1218 }
1219
1220 if (optional)
1221 optional = label;
1222
1223 colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_LABEL);
1224 if (label)
1225 mutt_format(buf + colorlen, buflen - colorlen, prec, NONULL(e->env->x_label), false);
1226 else
1227 mutt_format(buf + colorlen, buflen - colorlen, prec, "", false);
1228 add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1229 break;
1230 }
1231
1232 case 'z':
1233 if (src[0] == 's') /* status: deleted/new/old/replied */
1234 {
1235 const char *ch = NULL;
1236 if (e->deleted)
1237 {
1238 ch = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_DELETED);
1239 }
1240 else if (e->attach_del)
1241 {
1243 }
1244 else if (threads && thread_is_new(e))
1245 {
1246 ch = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_NEW_THREAD);
1247 }
1248 else if (threads && thread_is_old(e))
1249 {
1250 ch = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_OLD_THREAD);
1251 }
1252 else if (e->read && (msg_in_pager != e->msgno))
1253 {
1254 if (e->replied)
1255 ch = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_REPLIED);
1256 else
1257 ch = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_ZEMPTY);
1258 }
1259 else
1260 {
1261 if (e->old)
1262 ch = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_OLD);
1263 else
1264 ch = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_NEW);
1265 }
1266
1267 snprintf(tmp, sizeof(tmp), "%s", ch);
1268 src++;
1269 }
1270 else if (src[0] == 'c') /* crypto */
1271 {
1272 const char *ch = NULL;
1273 if ((WithCrypto != 0) && (e->security & SEC_GOODSIGN))
1274 {
1276 }
1277 else if ((WithCrypto != 0) && (e->security & SEC_ENCRYPT))
1278 {
1280 }
1281 else if ((WithCrypto != 0) && (e->security & SEC_SIGN))
1282 {
1283 ch = mbtable_get_nth_wchar(c_crypt_chars, FLAG_CHAR_CRYPT_SIGNED);
1284 }
1285 else if (((WithCrypto & APPLICATION_PGP) != 0) && ((e->security & PGP_KEY) == PGP_KEY))
1286 {
1288 }
1289 else
1290 {
1292 }
1293
1294 snprintf(tmp, sizeof(tmp), "%s", ch);
1295 src++;
1296 }
1297 else if (src[0] == 't') /* tagged, flagged, recipient */
1298 {
1299 const char *ch = NULL;
1300 if (e->tagged)
1301 ch = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_TAGGED);
1302 else if (e->flagged)
1303 ch = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_IMPORTANT);
1304 else
1305 ch = mbtable_get_nth_wchar(c_to_chars, user_is_recipient(e));
1306
1307 snprintf(tmp, sizeof(tmp), "%s", ch);
1308 src++;
1309 }
1310 else /* fallthrough */
1311 {
1312 break;
1313 }
1314
1315 colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_FLAGS);
1316 mutt_format(buf + colorlen, buflen - colorlen, prec, tmp, false);
1317 add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1318 break;
1319
1320 case 'Z':
1321 {
1322 /* New/Old for threads; replied; New/Old for messages */
1323 const char *first = NULL;
1324 if (threads && thread_is_new(e))
1325 {
1326 first = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_NEW_THREAD);
1327 }
1328 else if (threads && thread_is_old(e))
1329 {
1330 first = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_OLD_THREAD);
1331 }
1332 else if (e->read && (msg_in_pager != e->msgno))
1333 {
1334 if (e->replied)
1335 first = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_REPLIED);
1336 else
1337 first = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_ZEMPTY);
1338 }
1339 else
1340 {
1341 if (e->old)
1342 first = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_OLD);
1343 else
1344 first = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_NEW);
1345 }
1346
1347 /* Marked for deletion; deleted attachments; crypto */
1348 const char *second = NULL;
1349 if (e->deleted)
1350 second = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_DELETED);
1351 else if (e->attach_del)
1352 second = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_DELETED_ATTACH);
1353 else if ((WithCrypto != 0) && (e->security & SEC_GOODSIGN))
1354 second = mbtable_get_nth_wchar(c_crypt_chars, FLAG_CHAR_CRYPT_GOOD_SIGN);
1355 else if ((WithCrypto != 0) && (e->security & SEC_ENCRYPT))
1356 second = mbtable_get_nth_wchar(c_crypt_chars, FLAG_CHAR_CRYPT_ENCRYPTED);
1357 else if ((WithCrypto != 0) && (e->security & SEC_SIGN))
1358 second = mbtable_get_nth_wchar(c_crypt_chars, FLAG_CHAR_CRYPT_SIGNED);
1359 else if (((WithCrypto & APPLICATION_PGP) != 0) && (e->security & PGP_KEY))
1360 second = mbtable_get_nth_wchar(c_crypt_chars, FLAG_CHAR_CRYPT_CONTAINS_KEY);
1361 else
1362 second = mbtable_get_nth_wchar(c_crypt_chars, FLAG_CHAR_CRYPT_NO_CRYPTO);
1363
1364 /* Tagged, flagged and recipient flag */
1365 const char *third = NULL;
1366 if (e->tagged)
1367 third = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_TAGGED);
1368 else if (e->flagged)
1369 third = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_IMPORTANT);
1370 else
1371 third = mbtable_get_nth_wchar(c_to_chars, user_is_recipient(e));
1372
1373 snprintf(tmp, sizeof(tmp), "%s%s%s", first, second, third);
1374 }
1375
1376 colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_FLAGS);
1377 mutt_format(buf + colorlen, buflen - colorlen, prec, tmp, false);
1378 add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1379 break;
1380
1381 case '@':
1382 {
1383 if (!m)
1384 break;
1385
1386 const char *end = src;
1387 static unsigned char recurse = 0;
1388
1389 while ((*end != '\0') && (*end != '@'))
1390 end++;
1391 if ((*end == '@') && (recurse < 20))
1392 {
1393 recurse++;
1394 mutt_strn_copy(tmp, src, end - src, sizeof(tmp));
1395 mutt_expando_format(tmp, sizeof(tmp), col, cols,
1396 NONULL(mutt_idxfmt_hook(tmp, m, e)),
1397 index_format_str, data, flags);
1398 mutt_format(buf, buflen, prec, tmp, true);
1399 recurse--;
1400
1401 src = end + 1;
1402 break;
1403 }
1404 }
1406
1407 default:
1408 snprintf(buf, buflen, "%%%s%c", prec, op);
1409 break;
1410 }
1411
1412 if (optional)
1413 {
1414 mutt_expando_format(buf, buflen, col, cols, if_str, index_format_str, data, flags);
1415 }
1416 else if (flags & MUTT_FORMAT_OPTIONAL)
1417 {
1418 mutt_expando_format(buf, buflen, col, cols, else_str, index_format_str, data, flags);
1419 }
1420
1421 /* We return the format string, unchanged */
1422 return src;
1423}
1424
1438void mutt_make_string(struct Buffer *buf, int cols, const char *s,
1439 struct Mailbox *m, int inpgr, struct Email *e,
1440 MuttFormatFlags flags, const char *progress)
1441{
1442 struct HdrFormatInfo hfi = { 0 };
1443
1444 hfi.email = e;
1445 hfi.mailbox = m;
1446 hfi.msg_in_pager = inpgr;
1447 hfi.pager_progress = progress;
1448
1449 mutt_expando_format(buf->data, buf->dsize, 0, cols, s, index_format_str,
1450 (intptr_t) &hfi, flags);
1451}
size_t mutt_addrlist_write(const struct AddressList *al, struct Buffer *buf, bool display)
Write an Address to a buffer.
Definition: address.c:1210
const char * mutt_addr_for_display(const struct Address *a)
Convert an Address for display purposes.
Definition: address.c:1012
Email Address Handling.
Email Aliases.
bool mutt_addr_is_user(const struct Address *addr)
Does the address belong to the user.
Definition: alias.c:605
GUI display the mailboxes in a side panel.
int mutt_count_body_parts(const struct Mailbox *m, struct Email *e, FILE *fp)
Count the MIME Body parts.
Definition: attachments.c:252
bool buf_istr_equal(const struct Buffer *a, const struct Buffer *b)
Return if two buffers are equal, case insensitive.
Definition: buffer.c:714
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:308
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:97
Color and attribute parsing.
ColorId
List of all colored objects.
Definition: color.h:40
@ MT_COLOR_INDEX_AUTHOR
Index: author field.
Definition: color.h:84
@ MT_COLOR_INDEX_SIZE
Index: size field.
Definition: color.h:90
@ MT_COLOR_INDEX_TAGS
Index: tags field (g, J)
Definition: color.h:93
@ MT_COLOR_INDEX_SUBJECT
Index: subject field.
Definition: color.h:91
@ MT_COLOR_INDEX_DATE
Index: date field.
Definition: color.h:86
@ MT_COLOR_INDEX_TAG
Index: tag field (G)
Definition: color.h:92
@ MT_COLOR_INDEX_LABEL
Index: label field.
Definition: color.h:88
@ MT_COLOR_INDEX
Index: default colour.
Definition: color.h:83
@ MT_COLOR_INDEX_NUMBER
Index: index number.
Definition: color.h:89
@ MT_COLOR_INDEX_FLAGS
Index: flags field.
Definition: color.h:87
@ MT_COLOR_INDEX_COLLAPSED
Index: number of messages in collapsed thread.
Definition: color.h:85
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:292
struct MbTable * cs_subset_mbtable(const struct ConfigSubset *sub, const char *name)
Get a Multibyte table config item by name.
Definition: helpers.c:120
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:48
Convenience wrapper for the config headers.
Convenience wrapper for the core headers.
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:211
@ MUTT_NOTMUCH
'Notmuch' (virtual) Mailbox type
Definition: mailbox.h:51
size_t email_size(const struct Email *e)
Compute the size of an email.
Definition: email.c:127
Structs that make up an email.
void mutt_format(char *buf, size_t buflen, const char *prec, const char *s, bool arboreal)
Format a string like snprintf()
Definition: format.c:178
Flags to control mutt_expando_format()
#define MUTT_FORMAT_NOFILTER
Do not allow filtering on this pass.
Definition: format_flags.h:37
#define MUTT_FORMAT_FORCESUBJ
Print the subject even if unchanged.
Definition: format_flags.h:31
#define MUTT_FORMAT_NO_FLAGS
No flags are set.
Definition: format_flags.h:30
#define MUTT_FORMAT_INDEX
This is a main index entry.
Definition: format_flags.h:36
#define MUTT_FORMAT_OPTIONAL
Allow optional field processing.
Definition: format_flags.h:33
#define MUTT_FORMAT_TREE
Draw the thread tree.
Definition: format_flags.h:32
#define MUTT_FORMAT_PLAIN
Do not prepend DISP_TO, DISP_CC ...
Definition: format_flags.h:38
uint8_t MuttFormatFlags
Flags for mutt_expando_format(), e.g. MUTT_FORMAT_FORCESUBJ.
Definition: format_flags.h:29
void mutt_expando_format(char *buf, size_t buflen, size_t col, int cols, const char *src, format_t callback, intptr_t data, MuttFormatFlags flags)
Expand expandos (x) in a string -.
Definition: muttlib.c:740
static const char * index_format_str(char *buf, size_t buflen, size_t col, int cols, char op, const char *src, const char *prec, const char *if_str, const char *else_str, intptr_t data, MuttFormatFlags flags)
Format a string for the index list - Implements format_t -.
Definition: hdrline.c:399
Convenience wrapper for the gui headers.
void * mutt_hash_find(const struct HashTable *table, const char *strkey)
Find the HashElem data in a Hash Table element using a key.
Definition: hash.c:362
static const char * make_from_prefix(enum FieldType disp)
Create a prefix for an author field.
Definition: hdrline.c:139
static void make_from_addr(struct Envelope *env, char *buf, size_t buflen, bool do_lists)
Create a 'from' address for a reply email.
Definition: hdrline.c:231
FieldType
Header types.
Definition: hdrline.c:85
@ DISP_PLAIN
Empty string.
Definition: hdrline.c:90
@ DISP_TO
To: string.
Definition: hdrline.c:86
@ DISP_CC
Cc: string.
Definition: hdrline.c:87
@ DISP_BCC
Bcc: string.
Definition: hdrline.c:88
@ DISP_MAX
Definition: hdrline.c:91
@ DISP_FROM
From: string.
Definition: hdrline.c:89
static bool thread_is_old(struct Email *e)
Does the email thread contain any unread emails?
Definition: hdrline.c:337
void mutt_make_string(struct Buffer *buf, int cols, const char *s, struct Mailbox *m, int inpgr, struct Email *e, MuttFormatFlags flags, const char *progress)
Create formatted strings using mailbox expandos.
Definition: hdrline.c:1438
static enum ToChars user_is_recipient(struct Email *e)
Is the user a recipient of the message.
Definition: hdrline.c:275
static size_t add_index_color(char *buf, size_t buflen, MuttFormatFlags flags, enum ColorId color)
Insert a color marker into a string.
Definition: hdrline.c:104
static void make_from(struct Envelope *env, char *buf, size_t buflen, bool do_lists, MuttFormatFlags flags)
Generate a From: field (with optional prefix)
Definition: hdrline.c:175
static bool thread_is_new(struct Email *e)
Does the email thread contain any new emails?
Definition: hdrline.c:327
static bool user_in_addr(struct AddressList *al)
Do any of the addresses refer to the user?
Definition: hdrline.c:261
String processing routines to generate the mail index.
ToChars
Index into the $to_chars config variable.
Definition: hdrline.h:68
@ FLAG_CHAR_TO_ORIGINATOR
Character denoting that the user is originator.
Definition: hdrline.h:73
@ FLAG_CHAR_TO_UNIQUE
Character denoting that the user is unique recipient.
Definition: hdrline.h:70
@ FLAG_CHAR_TO_NOT_IN_THE_LIST
Character denoting that the user is not in list.
Definition: hdrline.h:69
@ FLAG_CHAR_TO_TO
Character denoting that the user is in the TO list.
Definition: hdrline.h:71
@ FLAG_CHAR_TO_CC
Character denoting that the user is in the CC list.
Definition: hdrline.h:72
@ FLAG_CHAR_TO_REPLY_TO
Character denoting that the user is in the Reply-To list.
Definition: hdrline.h:75
@ FLAG_CHAR_TO_SUBSCRIBED_LIST
Character denoting that the message is sent to a subscribed mailing list.
Definition: hdrline.h:74
@ FLAG_CHAR_CRYPT_CONTAINS_KEY
Character denoting a message contains a PGP key.
Definition: hdrline.h:60
@ FLAG_CHAR_CRYPT_SIGNED
Character denoting a message is signed.
Definition: hdrline.h:59
@ FLAG_CHAR_CRYPT_NO_CRYPTO
Character denoting a message has no cryptography information.
Definition: hdrline.h:61
@ FLAG_CHAR_CRYPT_GOOD_SIGN
Character denoting a message signed with a verified key.
Definition: hdrline.h:57
@ FLAG_CHAR_CRYPT_ENCRYPTED
Character denoting a message is PGP-encrypted.
Definition: hdrline.h:58
@ FLAG_CHAR_OLD
Character denoting an email that has been read.
Definition: hdrline.h:44
@ FLAG_CHAR_REPLIED
Character denoting an email that has been replied to.
Definition: hdrline.h:43
@ FLAG_CHAR_OLD_THREAD
Character denoting a thread of emails that has been read.
Definition: hdrline.h:46
@ FLAG_CHAR_ZEMPTY
Character denoting a read email, $index_format Z expando.
Definition: hdrline.h:49
@ FLAG_CHAR_TAGGED
Character denoting a tagged email.
Definition: hdrline.h:39
@ FLAG_CHAR_NEW
Character denoting an unread email.
Definition: hdrline.h:45
@ FLAG_CHAR_DELETED
Character denoting a deleted email.
Definition: hdrline.h:41
@ FLAG_CHAR_NEW_THREAD
Character denoting a thread containing at least one new email.
Definition: hdrline.h:47
@ FLAG_CHAR_DELETED_ATTACH
Character denoting a deleted attachment.
Definition: hdrline.h:42
@ FLAG_CHAR_SEMPTY
Character denoting a read email, $index_format S expando.
Definition: hdrline.h:48
@ FLAG_CHAR_IMPORTANT
Character denoting a important (flagged) email.
Definition: hdrline.h:40
const char * mutt_idxfmt_hook(const char *name, struct Mailbox *m, struct Email *e)
Get index-format-hook format string.
Definition: hook.c:964
Parse and execute user-defined hooks.
bool check_for_mailing_list(struct AddressList *al, const char *pfx, char *buf, int buflen)
Search list of addresses for a mailing list.
Definition: maillist.c:79
bool check_for_mailing_list_addr(struct AddressList *al, char *buf, int buflen)
Check an address list for a mailing list.
Definition: maillist.c:103
bool first_mailing_list(char *buf, size_t buflen, struct AddressList *al)
Get the first mailing list in the list of addresses.
Definition: maillist.c:125
Handle mailing lists.
const char * mbtable_get_nth_wchar(const struct MbTable *table, int index)
Extract one char from a multi-byte table.
Definition: mbtable.c:331
bool mutt_mb_get_initials(const char *name, char *buf, size_t buflen)
Turn a name into initials.
Definition: mbyte.c:82
struct tm mutt_date_localtime(time_t t)
Converts calendar time to a broken-down time structure expressed in user timezone.
Definition: date.c:908
struct tm mutt_date_gmtime(time_t t)
Converts calendar time to a broken-down time structure expressed in UTC timezone.
Definition: date.c:929
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:455
Convenience wrapper for the library headers.
#define FALLTHROUGH
Definition: lib.h:111
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:721
char * mutt_strn_copy(char *dest, const char *src, size_t len, size_t dsize)
Copy a sub-string into a buffer.
Definition: string.c:409
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:545
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:630
int mutt_messages_in_thread(struct Mailbox *m, struct Email *e, enum MessageInThread mit)
Count the messages in a thread.
Definition: mutt_thread.c:1658
Create/manipulate threading in emails.
#define mutt_using_threads()
Definition: mutt_thread.h:114
@ MIT_NUM_MESSAGES
How many messages are in the thread.
Definition: mutt_thread.h:89
@ MIT_POSITION
Our position in the thread.
Definition: mutt_thread.h:90
#define mutt_thread_contains_unread(e)
Definition: mutt_thread.h:109
@ MUTT_SPECIAL_INDEX
Colour indicator.
Definition: mutt_thread.h:73
void mutt_str_pretty_size(char *buf, size_t buflen, size_t num)
Display an abbreviated size, like 3.4K.
Definition: muttlib.c:1644
Some miscellaneous functions.
int mx_msg_close(struct Mailbox *m, struct Message **ptr)
Close a message.
Definition: mx.c:1178
struct Message * mx_msg_open(struct Mailbox *m, struct Email *e)
Return a stream pointer for a message.
Definition: mx.c:1132
API for mailboxes.
API for encryption/signing of emails.
#define SEC_GOODSIGN
Email has a valid signature.
Definition: lib.h:80
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:90
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:78
#define PGP_KEY
Definition: lib.h:99
#define WithCrypto
Definition: lib.h:116
#define SEC_SIGN
Email is signed.
Definition: lib.h:79
Notmuch virtual mailbox type.
char * nm_email_get_folder_rel_db(struct Mailbox *m, struct Email *e)
Get the folder for a Email from the same level as the notmuch database.
Definition: notmuch.c:1488
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
#define TAILQ_FIRST(head)
Definition: queue.h:723
#define TAILQ_NEXT(elm, field)
Definition: queue.h:832
#define TAILQ_EMPTY(head)
Definition: queue.h:721
const char * mutt_get_name(const struct Address *a)
Pick the best name to display from an address.
Definition: sort.c:134
Assorted sorting methods.
#define NONULL(x)
Definition: string2.h:37
An email address.
Definition: address.h:36
struct Buffer * mailbox
Mailbox and host address.
Definition: address.h:38
LOFF_T length
length (in bytes) of attachment
Definition: body.h:53
String manipulation buffer.
Definition: buffer.h:36
size_t dsize
Length of data.
Definition: buffer.h:39
char * data
Pointer to data.
Definition: buffer.h:37
The envelope/body of an email.
Definition: email.h:39
bool read
Email is read.
Definition: email.h:50
unsigned int zminutes
Minutes away from UTC.
Definition: email.h:57
bool recip_valid
Is_recipient is valid.
Definition: email.h:107
struct Envelope * env
Envelope information.
Definition: email.h:68
bool collapsed
Is this message part of a collapsed thread?
Definition: email.h:123
int lines
How many lines in the body of this message?
Definition: email.h:62
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:43
struct Body * body
List of MIME parts.
Definition: email.h:69
char * tree
Character string to print thread tree.
Definition: email.h:128
bool old
Email is seen, but unread.
Definition: email.h:49
size_t num_hidden
Number of hidden messages in this view (only valid when collapsed is set)
Definition: email.h:126
bool zoccident
True, if west of UTC, False if east.
Definition: email.h:58
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:102
bool flagged
Marked important?
Definition: email.h:47
unsigned int zhours
Hours away from UTC.
Definition: email.h:56
time_t date_sent
Time when the message was sent (UTC)
Definition: email.h:60
bool replied
Email has been replied to.
Definition: email.h:51
struct TagList tags
For drivers that support server tagging.
Definition: email.h:72
int score
Message score.
Definition: email.h:116
int msgno
Number displayed to the user.
Definition: email.h:114
bool deleted
Email is deleted.
Definition: email.h:78
short recipient
User_is_recipient()'s return value, cached.
Definition: email.h:119
bool tagged
Email is tagged.
Definition: email.h:110
time_t received
Time when the message was placed in the mailbox.
Definition: email.h:61
struct MuttThread * thread
Thread of Emails.
Definition: email.h:122
The header of an Email.
Definition: envelope.h:57
char *const subject
Email's subject.
Definition: envelope.h:70
struct AddressList to
Email's 'To' list.
Definition: envelope.h:60
struct AddressList reply_to
Email's 'reply-to'.
Definition: envelope.h:64
char * message_id
Message ID.
Definition: envelope.h:73
char * x_comment_to
List of 'X-comment-to' fields.
Definition: envelope.h:81
char * newsgroups
List of newsgroups.
Definition: envelope.h:78
struct AddressList cc
Email's 'Cc' list.
Definition: envelope.h:61
struct Buffer spam
Spam header.
Definition: envelope.h:82
struct AddressList bcc
Email's 'Bcc' list.
Definition: envelope.h:62
char * organization
Organisation header.
Definition: envelope.h:77
char * x_label
X-Label.
Definition: envelope.h:76
char * disp_subj
Display subject (modified copy of subject)
Definition: envelope.h:72
struct AddressList from
Email's 'From' list.
Definition: envelope.h:59
Data passed to index_format_str()
Definition: hdrline.c:72
struct Email * email
Current Email.
Definition: hdrline.c:75
int msg_in_pager
Index of Email displayed in the Pager.
Definition: hdrline.c:74
struct Mailbox * mailbox
Current Mailbox.
Definition: hdrline.c:73
const char * pager_progress
String representing Pager position through Email.
Definition: hdrline.c:76
A mailbox.
Definition: mailbox.h:79
int msg_count
Total number of messages.
Definition: mailbox.h:88
enum MailboxType type
Mailbox type.
Definition: mailbox.h:102
Multibyte character table.
Definition: mbtable.h:36
int len
Number of characters.
Definition: mbtable.h:38
char ** chars
The array of multibyte character strings.
Definition: mbtable.h:39
A local copy of an email.
Definition: message.h:34
FILE * fp
pointer to the message data
Definition: message.h:35
struct Message::@0 flags
Flags for the Message.
struct MuttThread * parent
Parent of this Thread.
Definition: thread.h:44
struct MuttThread * prev
Previous sibling Thread.
Definition: thread.h:47
struct Email * message
Email this Thread refers to.
Definition: thread.h:49
Container for Accounts, Notifications.
Definition: neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
locale_t time_c_locale
Current locale but LC_TIME=C.
Definition: neomutt.h:47
bool subjrx_apply_mods(struct Envelope *env)
Apply regex modifications to the subject.
Definition: subjectrx.c:129
Subject Regex handling.
struct HashTable * TagFormats
Hash Table: "inbox" -> "GI" - Tag format strings.
Definition: tags.c:42
void driver_tags_get_transformed(struct TagList *tl, struct Buffer *tags)
Get transformed tags separated by space.
Definition: tags.c:152
void driver_tags_get_transformed_for(struct TagList *tl, const char *name, struct Buffer *tags)
Get transformed tags for a tag name separated by space.
Definition: tags.c:187