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