NeoMutt  2024-02-01-35-geee02f
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 = NULL;
490#ifdef USE_NOTMUCH
491 if (m->type == MUTT_NOTMUCH)
492 {
494 }
495#endif
496 if (!p)
497 {
498 p = strrchr(mailbox_path(m), '/');
499 if (p)
500 {
501 p++;
502 }
503 }
504 mutt_str_copy(buf, p ? p : mailbox_path(m), buflen);
505 }
506 else
507 {
508 mutt_str_copy(buf, "(null)", buflen);
509 }
510 mutt_str_copy(tmp, buf, sizeof(tmp));
511 mutt_format(buf, buflen, prec, tmp, false);
512 break;
513
514 case 'c':
515 colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_SIZE);
516 if (src[0] == 'r')
517 {
518 mutt_str_pretty_size(tmp, sizeof(tmp), email_size(e));
519 src++;
520 }
521 else
522 {
523 mutt_str_pretty_size(tmp, sizeof(tmp), e->body->length);
524 }
525 mutt_format(buf + colorlen, buflen - colorlen, prec, tmp, false);
526 add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
527 break;
528
529 case 'C':
530 colorlen = add_index_color(fmt, sizeof(fmt), flags, MT_COLOR_INDEX_NUMBER);
531 snprintf(fmt + colorlen, sizeof(fmt) - colorlen, "%%%sd", prec);
532 add_index_color(fmt + colorlen, sizeof(fmt) - colorlen, flags, MT_COLOR_INDEX);
533 snprintf(buf, buflen, fmt, e->msgno + 1);
534 break;
535
536 case 'd':
537 case 'D':
538 case '{':
539 case '[':
540 case '(':
541 case '<':
542 /* preprocess $date_format to handle %Z */
543 {
544 const char *cp = NULL;
545 time_t now;
546 int j = 0;
547
548 if (optional && ((op == '[') || (op == '(')))
549 {
550 now = mutt_date_now();
551 struct tm tm = mutt_date_localtime(now);
552 now -= (op == '(') ? e->received : e->date_sent;
553
554 char *is = (char *) prec;
555 bool invert = false;
556 if (*is == '>')
557 {
558 invert = true;
559 is++;
560 }
561
562 while (*is && (*is != '?'))
563 {
564 int t = strtol(is, &is, 10);
565 /* semi-broken (assuming 30 days in all months) */
566 switch (*(is++))
567 {
568 case 'y':
569 if (t > 1)
570 {
571 t--;
572 t *= (60 * 60 * 24 * 365);
573 }
574 t += ((tm.tm_mon * 60 * 60 * 24 * 30) + (tm.tm_mday * 60 * 60 * 24) +
575 (tm.tm_hour * 60 * 60) + (tm.tm_min * 60) + tm.tm_sec);
576 break;
577
578 case 'm':
579 if (t > 1)
580 {
581 t--;
582 t *= (60 * 60 * 24 * 30);
583 }
584 t += ((tm.tm_mday * 60 * 60 * 24) + (tm.tm_hour * 60 * 60) +
585 (tm.tm_min * 60) + tm.tm_sec);
586 break;
587
588 case 'w':
589 if (t > 1)
590 {
591 t--;
592 t *= (60 * 60 * 24 * 7);
593 }
594 t += ((tm.tm_wday * 60 * 60 * 24) + (tm.tm_hour * 60 * 60) +
595 (tm.tm_min * 60) + tm.tm_sec);
596 break;
597
598 case 'd':
599 if (t > 1)
600 {
601 t--;
602 t *= (60 * 60 * 24);
603 }
604 t += ((tm.tm_hour * 60 * 60) + (tm.tm_min * 60) + tm.tm_sec);
605 break;
606
607 case 'H':
608 if (t > 1)
609 {
610 t--;
611 t *= (60 * 60);
612 }
613 t += ((tm.tm_min * 60) + tm.tm_sec);
614 break;
615
616 case 'M':
617 if (t > 1)
618 {
619 t--;
620 t *= (60);
621 }
622 t += (tm.tm_sec);
623 break;
624
625 default:
626 break;
627 }
628 j += t;
629 }
630
631 if (j < 0)
632 j *= -1;
633
634 if (((now > j) || (now < (-1 * j))) ^ invert)
635 optional = false;
636 break;
637 }
638
639 p = buf;
640
641 cp = ((op == 'd') || (op == 'D')) ? (NONULL(c_date_format)) : src;
642 bool use_c_locale = false;
643 if (*cp == '!')
644 {
645 use_c_locale = true;
646 cp++;
647 }
648
649 size_t len = buflen - 1;
650 while ((len > 0) &&
651 ((((op == 'd') || (op == 'D')) && *cp) ||
652 ((op == '{') && (*cp != '}')) || ((op == '[') && (*cp != ']')) ||
653 ((op == '(') && (*cp != ')')) || ((op == '<') && (*cp != '>'))))
654 {
655 if (*cp == '%')
656 {
657 cp++;
658 if (((*cp == 'Z') || (*cp == 'z')) && ((op == 'd') || (op == '{')))
659 {
660 if (len >= 5)
661 {
662 sprintf(p, "%c%02u%02u", e->zoccident ? '-' : '+', e->zhours, e->zminutes);
663 p += 5;
664 len -= 5;
665 }
666 else
667 {
668 break; /* not enough space left */
669 }
670 }
671 else
672 {
673 if (len >= 2)
674 {
675 *p++ = '%';
676 *p++ = *cp;
677 len -= 2;
678 }
679 else
680 {
681 break; /* not enough space */
682 }
683 }
684 cp++;
685 }
686 else
687 {
688 *p++ = *cp++;
689 len--;
690 }
691 }
692 *p = '\0';
693
694 struct tm tm = { 0 };
695 if ((op == '[') || (op == 'D'))
696 {
698 }
699 else if (op == '(')
700 {
702 }
703 else if (op == '<')
704 {
706 }
707 else
708 {
709 /* restore sender's time zone */
710 now = e->date_sent;
711 if (e->zoccident)
712 now -= (e->zhours * 3600 + e->zminutes * 60);
713 else
714 now += (e->zhours * 3600 + e->zminutes * 60);
715 tm = mutt_date_gmtime(now);
716 }
717
718 if (use_c_locale)
719 strftime_l(tmp, sizeof(tmp), buf, &tm, NeoMutt->time_c_locale);
720 else
721 strftime(tmp, sizeof(tmp), buf, &tm);
722
723 colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_DATE);
724 mutt_format(buf + colorlen, buflen - colorlen, prec, tmp, false);
725 add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
726
727 if ((len > 0) && (op != 'd') && (op != 'D')) /* Skip ending op */
728 src = cp + 1;
729 break;
730 }
731
732 case 'e':
733 snprintf(fmt, sizeof(fmt), "%%%sd", prec);
734 snprintf(buf, buflen, fmt, mutt_messages_in_thread(m, e, MIT_POSITION));
735 break;
736
737 case 'E':
738 if (!optional)
739 {
740 snprintf(fmt, sizeof(fmt), "%%%sd", prec);
741 snprintf(buf, buflen, fmt, mutt_messages_in_thread(m, e, MIT_NUM_MESSAGES));
742 }
743 else if (mutt_messages_in_thread(m, e, MIT_NUM_MESSAGES) <= 1)
744 {
745 optional = false;
746 }
747 break;
748
749 case 'f':
750 {
751 struct Buffer *tmpbuf = buf_pool_get();
752 mutt_addrlist_write(&e->env->from, tmpbuf, true);
753 mutt_str_copy(tmp, buf_string(tmpbuf), sizeof(tmp));
754 buf_pool_release(&tmpbuf);
755 mutt_format(buf, buflen, prec, tmp, false);
756 break;
757 }
758
759 case 'F':
760 if (!optional)
761 {
762 const bool is_plain = (src[0] == 'p');
763 colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_AUTHOR);
764 make_from(e->env, tmp, sizeof(tmp), false,
766 mutt_format(buf + colorlen, buflen - colorlen, prec, tmp, false);
767 add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
768
769 if (is_plain)
770 src++;
771 }
772 else if (mutt_addr_is_user(from))
773 {
774 optional = false;
775 }
776 break;
777
778 case 'g':
779 {
780 struct Buffer *tags = buf_pool_get();
782 if (!optional)
783 {
784 colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_TAGS);
785 mutt_format(buf + colorlen, buflen - colorlen, prec, buf_string(tags), false);
786 add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
787 }
788 else if (buf_is_empty(tags))
789 {
790 optional = false;
791 }
792 buf_pool_release(&tags);
793 break;
794 }
795
796 case 'G':
797 {
798 char format[3] = { 0 };
799 char *tag = NULL;
800
801 if (!optional)
802 {
803 format[0] = op;
804 format[1] = *src;
805 format[2] = '\0';
806
807 tag = mutt_hash_find(TagFormats, format);
808 if (tag)
809 {
810 struct Buffer *tags = buf_pool_get();
812 colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_TAG);
813 mutt_format(buf + colorlen, buflen - colorlen, prec, buf_string(tags), false);
814 add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
815 buf_pool_release(&tags);
816 }
817 src++;
818 }
819 else
820 {
821 format[0] = op;
822 format[1] = *prec;
823 format[2] = '\0';
824
825 tag = mutt_hash_find(TagFormats, format);
826 if (tag)
827 {
828 struct Buffer *tags = buf_pool_get();
830 if (buf_is_empty(tags))
831 optional = false;
832 buf_pool_release(&tags);
833 }
834 }
835 break;
836 }
837
838 case 'H':
839 /* (Hormel) spam score */
840 if (optional)
841 optional = !buf_is_empty(&e->env->spam);
842
843 mutt_format(buf, buflen, prec, buf_string(&e->env->spam), false);
844 break;
845
846 case 'i':
847 mutt_format(buf, buflen, prec,
848 e->env->message_id ? e->env->message_id : "<no.id>", false);
849 break;
850
851 case 'J':
852 {
853 bool have_tags = true;
854 struct Buffer *tags = buf_pool_get();
856 if (!buf_is_empty(tags))
857 {
858 if (flags & MUTT_FORMAT_TREE)
859 {
860 struct Buffer *parent_tags = buf_pool_get();
861 if (e->thread->prev && e->thread->prev->message)
862 {
864 }
865 if (buf_is_empty(parent_tags) && e->thread->parent &&
866 e->thread->parent->message)
867 {
869 }
870 if (!buf_is_empty(parent_tags) && buf_istr_equal(tags, parent_tags))
871 have_tags = false;
872 buf_pool_release(&parent_tags);
873 }
874 }
875 else
876 {
877 have_tags = false;
878 }
879
880 if (optional)
881 optional = have_tags;
882
883 colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_TAGS);
884 if (have_tags)
885 mutt_format(buf + colorlen, buflen - colorlen, prec, buf_string(tags), false);
886 else
887 mutt_format(buf + colorlen, buflen - colorlen, prec, "", false);
888 add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
889 buf_pool_release(&tags);
890 break;
891 }
892
893 case 'l':
894 if (!optional)
895 {
896 snprintf(fmt, sizeof(fmt), "%%%sd", prec);
897 colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_SIZE);
898 snprintf(buf + colorlen, buflen - colorlen, fmt, e->lines);
899 add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
900 }
901 else if (e->lines <= 0)
902 {
903 optional = false;
904 }
905 break;
906
907 case 'L':
908 if (!optional)
909 {
910 colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_AUTHOR);
911 make_from(e->env, tmp, sizeof(tmp), true, flags);
912 mutt_format(buf + colorlen, buflen - colorlen, prec, tmp, false);
913 add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
914 }
915 else if (!check_for_mailing_list(&e->env->to, NULL, NULL, 0) &&
916 !check_for_mailing_list(&e->env->cc, NULL, NULL, 0))
917 {
918 optional = false;
919 }
920 break;
921
922 case 'm':
923 if (m)
924 {
925 snprintf(fmt, sizeof(fmt), "%%%sd", prec);
926 snprintf(buf, buflen, fmt, m->msg_count);
927 }
928 else
929 {
930 mutt_str_copy(buf, "(null)", buflen);
931 }
932 break;
933
934 case 'n':
935 colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_AUTHOR);
936 mutt_format(buf + colorlen, buflen - colorlen, prec, mutt_get_name(from), false);
937 add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
938 break;
939
940 case 'M':
941 snprintf(fmt, sizeof(fmt), "%%%sd", prec);
942 if (!optional)
943 {
944 colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_COLLAPSED);
945 if (threads && is_index && e->collapsed && (e->num_hidden > 1))
946 {
947 snprintf(buf + colorlen, buflen - colorlen, fmt, e->num_hidden);
948 add_index_color(buf, buflen - colorlen, flags, MT_COLOR_INDEX);
949 }
950 else if (is_index && threads)
951 {
952 mutt_format(buf + colorlen, buflen - colorlen, prec, " ", false);
953 add_index_color(buf, buflen - colorlen, flags, MT_COLOR_INDEX);
954 }
955 else
956 {
957 *buf = '\0';
958 }
959 }
960 else
961 {
962 if (!(threads && is_index && e->collapsed && (e->num_hidden > 1)))
963 optional = false;
964 }
965 break;
966
967 case 'N':
968 if (!optional)
969 {
970 snprintf(fmt, sizeof(fmt), "%%%sd", prec);
971 snprintf(buf, buflen, fmt, e->score);
972 }
973 else
974 {
975 if (e->score == 0)
976 optional = false;
977 }
978 break;
979
980 case 'O':
981 if (!optional)
982 {
983 make_from_addr(e->env, tmp, sizeof(tmp), true);
984 const bool c_save_address = cs_subset_bool(NeoMutt->sub, "save_address");
985 if (!c_save_address && (p = strpbrk(tmp, "%@")))
986 *p = '\0';
987 mutt_format(buf, buflen, prec, tmp, false);
988 }
989 else if (!check_for_mailing_list_addr(&e->env->to, NULL, 0) &&
990 !check_for_mailing_list_addr(&e->env->cc, NULL, 0))
991 {
992 optional = false;
993 }
994 break;
995
996 case 'P':
997 mutt_str_copy(buf, hfi->pager_progress, buflen);
998 break;
999
1000 case 'q':
1001 mutt_format(buf, buflen, prec, e->env->newsgroups ? e->env->newsgroups : "", false);
1002 break;
1003
1004 case 'r':
1005 {
1006 struct Buffer *tmpbuf = buf_pool_get();
1007 mutt_addrlist_write(&e->env->to, tmpbuf, true);
1008 mutt_str_copy(tmp, buf_string(tmpbuf), sizeof(tmp));
1009 buf_pool_release(&tmpbuf);
1010 if (optional && (tmp[0] == '\0'))
1011 optional = false;
1012 mutt_format(buf, buflen, prec, tmp, false);
1013 break;
1014 }
1015
1016 case 'R':
1017 {
1018 struct Buffer *tmpbuf = buf_pool_get();
1019 mutt_addrlist_write(&e->env->cc, tmpbuf, true);
1020 mutt_str_copy(tmp, buf_string(tmpbuf), sizeof(tmp));
1021 buf_pool_release(&tmpbuf);
1022 if (optional && (tmp[0] == '\0'))
1023 optional = false;
1024 mutt_format(buf, buflen, prec, tmp, false);
1025 break;
1026 }
1027
1028 case 's':
1029 {
1031 char *subj = NULL;
1032 if (e->env->disp_subj)
1033 subj = e->env->disp_subj;
1034 else
1035 subj = e->env->subject;
1036 if (flags & MUTT_FORMAT_TREE && !e->collapsed)
1037 {
1038 if (flags & MUTT_FORMAT_FORCESUBJ)
1039 {
1040 colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_SUBJECT);
1041 mutt_format(buf + colorlen, buflen - colorlen, "", NONULL(subj), false);
1042 add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1043 snprintf(tmp, sizeof(tmp), "%s%s", e->tree, buf);
1044 mutt_format(buf, buflen, prec, tmp, true);
1045 }
1046 else
1047 {
1048 mutt_format(buf, buflen, prec, e->tree, true);
1049 }
1050 }
1051 else
1052 {
1053 colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_SUBJECT);
1054 mutt_format(buf + colorlen, buflen - colorlen, prec, NONULL(subj), false);
1055 add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1056 }
1057 break;
1058 }
1059
1060 case 'S':
1061 {
1062 const char *wch = NULL;
1063 if (e->deleted)
1064 wch = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_DELETED);
1065 else if (e->attach_del)
1067 else if (e->tagged)
1068 wch = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_TAGGED);
1069 else if (e->flagged)
1070 wch = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_IMPORTANT);
1071 else if (e->replied)
1072 wch = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_REPLIED);
1073 else if (e->read && (msg_in_pager != e->msgno))
1074 wch = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_SEMPTY);
1075 else if (e->old)
1076 wch = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_OLD);
1077 else
1078 wch = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_NEW);
1079
1080 snprintf(tmp, sizeof(tmp), "%s", wch);
1081 colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_FLAGS);
1082 mutt_format(buf + colorlen, buflen - colorlen, prec, tmp, false);
1083 add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1084 break;
1085 }
1086
1087 case 't':
1088 tmp[0] = '\0';
1089 if (!check_for_mailing_list(&e->env->to, "To ", tmp, sizeof(tmp)) &&
1090 !check_for_mailing_list(&e->env->cc, "Cc ", tmp, sizeof(tmp)))
1091 {
1092 if (to)
1093 snprintf(tmp, sizeof(tmp), "To %s", mutt_get_name(to));
1094 else if (cc)
1095 snprintf(tmp, sizeof(tmp), "Cc %s", mutt_get_name(cc));
1096 }
1097 mutt_format(buf, buflen, prec, tmp, false);
1098 break;
1099
1100 case 'T':
1101 {
1102 int i;
1103 snprintf(fmt, sizeof(fmt), "%%%ss", prec);
1104 snprintf(buf, buflen, fmt,
1105 (c_to_chars && ((i = user_is_recipient(e))) < c_to_chars->len) ?
1106 c_to_chars->chars[i] :
1107 " ");
1108 break;
1109 }
1110
1111 case 'u':
1112 if (from && from->mailbox)
1113 {
1114 mutt_str_copy(tmp, mutt_addr_for_display(from), sizeof(tmp));
1115 p = strpbrk(tmp, "%@");
1116 if (p)
1117 *p = '\0';
1118 }
1119 else
1120 {
1121 tmp[0] = '\0';
1122 }
1123 mutt_format(buf, buflen, prec, tmp, false);
1124 break;
1125
1126 case 'v':
1127 if (mutt_addr_is_user(from))
1128 {
1129 if (to)
1130 mutt_format(tmp, sizeof(tmp), prec, mutt_get_name(to), false);
1131 else if (cc)
1132 mutt_format(tmp, sizeof(tmp), prec, mutt_get_name(cc), false);
1133 else
1134 *tmp = '\0';
1135 }
1136 else
1137 {
1138 mutt_format(tmp, sizeof(tmp), prec, mutt_get_name(from), false);
1139 }
1140 p = strpbrk(tmp, " %@");
1141 if (p)
1142 *p = '\0';
1143 mutt_format(buf, buflen, prec, tmp, false);
1144 break;
1145
1146 case 'W':
1147 if (!optional)
1148 {
1149 mutt_format(buf, buflen, prec,
1150 e->env->organization ? e->env->organization : "", false);
1151 }
1152 else if (!e->env->organization)
1153 {
1154 optional = false;
1155 }
1156 break;
1157
1158 case 'x':
1159 if (!optional)
1160 {
1161 mutt_format(buf, buflen, prec,
1162 e->env->x_comment_to ? e->env->x_comment_to : "", false);
1163 }
1164 else if (!e->env->x_comment_to)
1165 {
1166 optional = false;
1167 }
1168 break;
1169
1170 case 'X':
1171 {
1172 struct Message *msg = mx_msg_open(m, e);
1173 if (msg)
1174 {
1175 int count = mutt_count_body_parts(m, e, msg->fp);
1176 mx_msg_close(m, &msg);
1177
1178 /* The recursion allows messages without depth to return 0. */
1179 if (optional)
1180 optional = (count != 0);
1181
1182 snprintf(fmt, sizeof(fmt), "%%%sd", prec);
1183 snprintf(buf, buflen, fmt, count);
1184 }
1185 break;
1186 }
1187
1188 case 'y':
1189 if (optional)
1190 optional = (e->env->x_label != NULL);
1191
1192 colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_LABEL);
1193 mutt_format(buf + colorlen, buflen - colorlen, prec, NONULL(e->env->x_label), false);
1194 add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1195 break;
1196
1197 case 'Y':
1198 {
1199 bool label = true;
1200 if (e->env->x_label)
1201 {
1202 struct Email *e_tmp = NULL;
1203 if (flags & MUTT_FORMAT_TREE && (e->thread->prev && e->thread->prev->message &&
1204 e->thread->prev->message->env->x_label))
1205 {
1206 e_tmp = e->thread->prev->message;
1207 }
1208 else if (flags & MUTT_FORMAT_TREE &&
1209 (e->thread->parent && e->thread->parent->message &&
1211 {
1212 e_tmp = e->thread->parent->message;
1213 }
1214 if (e_tmp && mutt_istr_equal(e->env->x_label, e_tmp->env->x_label))
1215 label = false;
1216 }
1217 else
1218 {
1219 label = false;
1220 }
1221
1222 if (optional)
1223 optional = label;
1224
1225 colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_LABEL);
1226 if (label)
1227 mutt_format(buf + colorlen, buflen - colorlen, prec, NONULL(e->env->x_label), false);
1228 else
1229 mutt_format(buf + colorlen, buflen - colorlen, prec, "", false);
1230 add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1231 break;
1232 }
1233
1234 case 'z':
1235 if (src[0] == 's') /* status: deleted/new/old/replied */
1236 {
1237 const char *ch = NULL;
1238 if (e->deleted)
1239 {
1240 ch = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_DELETED);
1241 }
1242 else if (e->attach_del)
1243 {
1245 }
1246 else if (threads && thread_is_new(e))
1247 {
1248 ch = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_NEW_THREAD);
1249 }
1250 else if (threads && thread_is_old(e))
1251 {
1252 ch = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_OLD_THREAD);
1253 }
1254 else if (e->read && (msg_in_pager != e->msgno))
1255 {
1256 if (e->replied)
1257 ch = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_REPLIED);
1258 else
1259 ch = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_ZEMPTY);
1260 }
1261 else
1262 {
1263 if (e->old)
1264 ch = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_OLD);
1265 else
1266 ch = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_NEW);
1267 }
1268
1269 snprintf(tmp, sizeof(tmp), "%s", ch);
1270 src++;
1271 }
1272 else if (src[0] == 'c') /* crypto */
1273 {
1274 const char *ch = NULL;
1275 if ((WithCrypto != 0) && (e->security & SEC_GOODSIGN))
1276 {
1278 }
1279 else if ((WithCrypto != 0) && (e->security & SEC_ENCRYPT))
1280 {
1282 }
1283 else if ((WithCrypto != 0) && (e->security & SEC_SIGN))
1284 {
1285 ch = mbtable_get_nth_wchar(c_crypt_chars, FLAG_CHAR_CRYPT_SIGNED);
1286 }
1287 else if (((WithCrypto & APPLICATION_PGP) != 0) && ((e->security & PGP_KEY) == PGP_KEY))
1288 {
1290 }
1291 else
1292 {
1294 }
1295
1296 snprintf(tmp, sizeof(tmp), "%s", ch);
1297 src++;
1298 }
1299 else if (src[0] == 't') /* tagged, flagged, recipient */
1300 {
1301 const char *ch = NULL;
1302 if (e->tagged)
1303 ch = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_TAGGED);
1304 else if (e->flagged)
1305 ch = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_IMPORTANT);
1306 else
1307 ch = mbtable_get_nth_wchar(c_to_chars, user_is_recipient(e));
1308
1309 snprintf(tmp, sizeof(tmp), "%s", ch);
1310 src++;
1311 }
1312 else /* fallthrough */
1313 {
1314 break;
1315 }
1316
1317 colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_FLAGS);
1318 mutt_format(buf + colorlen, buflen - colorlen, prec, tmp, false);
1319 add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1320 break;
1321
1322 case 'Z':
1323 {
1324 /* New/Old for threads; replied; New/Old for messages */
1325 const char *first = NULL;
1326 if (threads && thread_is_new(e))
1327 {
1328 first = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_NEW_THREAD);
1329 }
1330 else if (threads && thread_is_old(e))
1331 {
1332 first = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_OLD_THREAD);
1333 }
1334 else if (e->read && (msg_in_pager != e->msgno))
1335 {
1336 if (e->replied)
1337 first = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_REPLIED);
1338 else
1339 first = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_ZEMPTY);
1340 }
1341 else
1342 {
1343 if (e->old)
1344 first = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_OLD);
1345 else
1346 first = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_NEW);
1347 }
1348
1349 /* Marked for deletion; deleted attachments; crypto */
1350 const char *second = NULL;
1351 if (e->deleted)
1352 second = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_DELETED);
1353 else if (e->attach_del)
1354 second = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_DELETED_ATTACH);
1355 else if ((WithCrypto != 0) && (e->security & SEC_GOODSIGN))
1356 second = mbtable_get_nth_wchar(c_crypt_chars, FLAG_CHAR_CRYPT_GOOD_SIGN);
1357 else if ((WithCrypto != 0) && (e->security & SEC_ENCRYPT))
1358 second = mbtable_get_nth_wchar(c_crypt_chars, FLAG_CHAR_CRYPT_ENCRYPTED);
1359 else if ((WithCrypto != 0) && (e->security & SEC_SIGN))
1360 second = mbtable_get_nth_wchar(c_crypt_chars, FLAG_CHAR_CRYPT_SIGNED);
1361 else if (((WithCrypto & APPLICATION_PGP) != 0) && (e->security & PGP_KEY))
1362 second = mbtable_get_nth_wchar(c_crypt_chars, FLAG_CHAR_CRYPT_CONTAINS_KEY);
1363 else
1364 second = mbtable_get_nth_wchar(c_crypt_chars, FLAG_CHAR_CRYPT_NO_CRYPTO);
1365
1366 /* Tagged, flagged and recipient flag */
1367 const char *third = NULL;
1368 if (e->tagged)
1369 third = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_TAGGED);
1370 else if (e->flagged)
1371 third = mbtable_get_nth_wchar(c_flag_chars, FLAG_CHAR_IMPORTANT);
1372 else
1373 third = mbtable_get_nth_wchar(c_to_chars, user_is_recipient(e));
1374
1375 snprintf(tmp, sizeof(tmp), "%s%s%s", first, second, third);
1376 }
1377
1378 colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_FLAGS);
1379 mutt_format(buf + colorlen, buflen - colorlen, prec, tmp, false);
1380 add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1381 break;
1382
1383 case '@':
1384 {
1385 if (!m)
1386 break;
1387
1388 const char *end = src;
1389 static unsigned char recurse = 0;
1390
1391 while ((*end != '\0') && (*end != '@'))
1392 end++;
1393 if ((*end == '@') && (recurse < 20))
1394 {
1395 recurse++;
1396 mutt_strn_copy(tmp, src, end - src, sizeof(tmp));
1397 mutt_expando_format(tmp, sizeof(tmp), col, cols,
1398 NONULL(mutt_idxfmt_hook(tmp, m, e)),
1399 index_format_str, data, flags);
1400 mutt_format(buf, buflen, prec, tmp, true);
1401 recurse--;
1402
1403 src = end + 1;
1404 break;
1405 }
1406 }
1408
1409 default:
1410 snprintf(buf, buflen, "%%%s%c", prec, op);
1411 break;
1412 }
1413
1414 if (optional)
1415 {
1416 mutt_expando_format(buf, buflen, col, cols, if_str, index_format_str, data, flags);
1417 }
1418 else if (flags & MUTT_FORMAT_OPTIONAL)
1419 {
1420 mutt_expando_format(buf, buflen, col, cols, else_str, index_format_str, data, flags);
1421 }
1422
1423 /* We return the format string, unchanged */
1424 return src;
1425}
1426
1440void mutt_make_string(struct Buffer *buf, int cols, const char *s,
1441 struct Mailbox *m, int inpgr, struct Email *e,
1442 MuttFormatFlags flags, const char *progress)
1443{
1444 struct HdrFormatInfo hfi = { 0 };
1445
1446 hfi.email = e;
1447 hfi.mailbox = m;
1448 hfi.msg_in_pager = inpgr;
1449 hfi.pager_progress = progress;
1450
1451 mutt_expando_format(buf->data, buf->dsize, 0, cols, s, index_format_str,
1452 (intptr_t) &hfi, flags);
1453}
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:1440
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