NeoMutt  2020-11-20
Teaching an old dog new tricks
DOXYGEN
hdrline.c
Go to the documentation of this file.
1 
32 #include "config.h"
33 #include <locale.h>
34 #include <stdbool.h>
35 #include <stdint.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <time.h>
40 #include "mutt/lib.h"
41 #include "address/lib.h"
42 #include "config/lib.h"
43 #include "email/lib.h"
44 #include "core/lib.h"
45 #include "alias/lib.h"
46 #include "gui/lib.h"
47 #include "hdrline.h"
48 #include "ncrypt/lib.h"
49 #include "context.h"
50 #include "format_flags.h"
51 #include "hook.h"
52 #include "maillist.h"
53 #include "mutt_globals.h"
54 #include "mutt_menu.h"
55 #include "mutt_parse.h"
56 #include "mutt_thread.h"
57 #include "muttlib.h"
58 #include "sort.h"
59 #ifdef USE_NOTMUCH
60 #include "notmuch/lib.h"
61 #endif
62 
63 /* These Config Variables are only used in hdrline.c */
67 struct MbTable *C_ToChars;
68 
73 {
85 };
86 
91 {
97 };
98 
105 {
112 };
113 
124 static size_t add_index_color(char *buf, size_t buflen, MuttFormatFlags flags, char color)
125 {
126  /* only add color markers if we are operating on main index entries. */
127  if (!(flags & MUTT_FORMAT_INDEX))
128  return 0;
129 
130  /* this item is going to be passed to an external filter */
131  if (flags & MUTT_FORMAT_NOFILTER)
132  return 0;
133 
134  if (color == MT_COLOR_INDEX)
135  { /* buf might be uninitialized other cases */
136  const size_t len = mutt_str_len(buf);
137  buf += len;
138  buflen -= len;
139  }
140 
141  if (buflen <= 2)
142  return 0;
143 
144  buf[0] = MUTT_SPECIAL_INDEX;
145  buf[1] = color;
146  buf[2] = '\0';
147 
148  return 2;
149 }
150 
161 static const char *get_nth_wchar(struct MbTable *table, int index)
162 {
163  if (!table || !table->chars || (index < 0) || (index >= table->len))
164  return " ";
165 
166  if (table->chars[index][0] == '\r')
167  return "";
168 
169  return table->chars[index];
170 }
171 
180 static const char *make_from_prefix(enum FieldType disp)
181 {
182  /* need 2 bytes at the end, one for the space, another for NUL */
183  static char padded[8];
184  static const char *long_prefixes[DISP_MAX] = {
185  [DISP_TO] = "To ", [DISP_CC] = "Cc ", [DISP_BCC] = "Bcc ",
186  [DISP_FROM] = "", [DISP_PLAIN] = "",
187  };
188 
189  if (!C_FromChars || !C_FromChars->chars || (C_FromChars->len == 0))
190  return long_prefixes[disp];
191 
192  const char *pchar = get_nth_wchar(C_FromChars, disp);
193  if (mutt_str_len(pchar) == 0)
194  return "";
195 
196  snprintf(padded, sizeof(padded), "%s ", pchar);
197  return padded;
198 }
199 
214 static void make_from(struct Envelope *env, char *buf, size_t buflen,
215  bool do_lists, MuttFormatFlags flags)
216 {
217  if (!env || !buf)
218  return;
219 
220  bool me;
221  enum FieldType disp;
222  struct AddressList *name = NULL;
223 
224  me = mutt_addr_is_user(TAILQ_FIRST(&env->from));
225 
226  if (do_lists || me)
227  {
228  if (check_for_mailing_list(&env->to, make_from_prefix(DISP_TO), buf, buflen))
229  return;
230  if (check_for_mailing_list(&env->cc, make_from_prefix(DISP_CC), buf, buflen))
231  return;
232  }
233 
234  if (me && !TAILQ_EMPTY(&env->to))
235  {
236  disp = (flags & MUTT_FORMAT_PLAIN) ? DISP_PLAIN : DISP_TO;
237  name = &env->to;
238  }
239  else if (me && !TAILQ_EMPTY(&env->cc))
240  {
241  disp = DISP_CC;
242  name = &env->cc;
243  }
244  else if (me && !TAILQ_EMPTY(&env->bcc))
245  {
246  disp = DISP_BCC;
247  name = &env->bcc;
248  }
249  else if (!TAILQ_EMPTY(&env->from))
250  {
251  disp = DISP_FROM;
252  name = &env->from;
253  }
254  else
255  {
256  *buf = '\0';
257  return;
258  }
259 
260  snprintf(buf, buflen, "%s%s", make_from_prefix(disp), mutt_get_name(TAILQ_FIRST(name)));
261 }
262 
270 static void make_from_addr(struct Envelope *env, char *buf, size_t buflen, bool do_lists)
271 {
272  if (!env || !buf)
273  return;
274 
275  bool me = mutt_addr_is_user(TAILQ_FIRST(&env->from));
276 
277  if (do_lists || me)
278  {
279  if (check_for_mailing_list_addr(&env->to, buf, buflen))
280  return;
281  if (check_for_mailing_list_addr(&env->cc, buf, buflen))
282  return;
283  }
284 
285  if (me && !TAILQ_EMPTY(&env->to))
286  snprintf(buf, buflen, "%s", TAILQ_FIRST(&env->to)->mailbox);
287  else if (me && !TAILQ_EMPTY(&env->cc))
288  snprintf(buf, buflen, "%s", TAILQ_FIRST(&env->cc)->mailbox);
289  else if (!TAILQ_EMPTY(&env->from))
290  mutt_str_copy(buf, TAILQ_FIRST(&env->from)->mailbox, buflen);
291  else
292  *buf = '\0';
293 }
294 
300 static bool user_in_addr(struct AddressList *al)
301 {
302  struct Address *a = NULL;
303  TAILQ_FOREACH(a, al, entries)
304  if (mutt_addr_is_user(a))
305  return true;
306  return false;
307 }
308 
320 static int user_is_recipient(struct Email *e)
321 {
322  if (!e || !e->env)
323  return 0;
324 
325  struct Envelope *env = e->env;
326 
327  if (!e->recip_valid)
328  {
329  e->recip_valid = true;
330 
331  if (mutt_addr_is_user(TAILQ_FIRST(&env->from)))
332  e->recipient = 4;
333  else if (user_in_addr(&env->to))
334  {
335  if (TAILQ_NEXT(TAILQ_FIRST(&env->to), entries) || !TAILQ_EMPTY(&env->cc))
336  e->recipient = 2; /* non-unique recipient */
337  else
338  e->recipient = 1; /* unique recipient */
339  }
340  else if (user_in_addr(&env->cc))
341  e->recipient = 3;
342  else if (check_for_mailing_list(&env->to, NULL, NULL, 0))
343  e->recipient = 5;
344  else if (check_for_mailing_list(&env->cc, NULL, NULL, 0))
345  e->recipient = 5;
346  else if (user_in_addr(&env->reply_to))
347  e->recipient = 6;
348  else
349  e->recipient = 0;
350  }
351 
352  return e->recipient;
353 }
354 
361 static char *apply_subject_mods(struct Envelope *env)
362 {
363  if (!env)
364  return NULL;
365 
367  return env->subject;
368 
369  if (!env->subject || (*env->subject == '\0'))
370  {
371  env->disp_subj = NULL;
372  return NULL;
373  }
374 
376  return env->disp_subj;
377 }
378 
384 static bool thread_is_new(struct Email *e)
385 {
386  return e->collapsed && (e->num_hidden > 1) && (mutt_thread_contains_unread(e) == 1);
387 }
388 
394 static bool thread_is_old(struct Email *e)
395 {
396  return e->collapsed && (e->num_hidden > 1) && (mutt_thread_contains_unread(e) == 2);
397 }
398 
455 static const char *index_format_str(char *buf, size_t buflen, size_t col, int cols,
456  char op, const char *src, const char *prec,
457  const char *if_str, const char *else_str,
458  intptr_t data, MuttFormatFlags flags)
459 {
460  struct HdrFormatInfo *hfi = (struct HdrFormatInfo *) data;
461  char fmt[128], tmp[1024];
462  char *p = NULL, *tags = NULL;
463  bool optional = (flags & MUTT_FORMAT_OPTIONAL);
464  int threads = ((C_Sort & SORT_MASK) == SORT_THREADS);
465  int is_index = (flags & MUTT_FORMAT_INDEX);
466  size_t colorlen;
467 
468  struct Email *e = hfi->email;
469  size_t msg_in_pager = hfi->msg_in_pager;
470  struct Mailbox *m = hfi->mailbox;
471 
472  if (!e || !e->env)
473  return src;
474 
475  const struct Address *reply_to = TAILQ_FIRST(&e->env->reply_to);
476  const struct Address *from = TAILQ_FIRST(&e->env->from);
477  const struct Address *to = TAILQ_FIRST(&e->env->to);
478  const struct Address *cc = TAILQ_FIRST(&e->env->cc);
479 
480  buf[0] = '\0';
481  switch (op)
482  {
483  case 'A':
484  case 'I':
485  if (op == 'A')
486  {
487  if (reply_to && reply_to->mailbox)
488  {
489  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_AUTHOR);
490  mutt_format_s(buf + colorlen, buflen - colorlen, prec,
491  mutt_addr_for_display(reply_to));
492  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
493  break;
494  }
495  }
496  else
497  {
498  if (mutt_mb_get_initials(mutt_get_name(from), tmp, sizeof(tmp)))
499  {
500  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_AUTHOR);
501  mutt_format_s(buf + colorlen, buflen - colorlen, prec, tmp);
502  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
503  break;
504  }
505  }
506  /* fallthrough */
507 
508  case 'a':
509  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_AUTHOR);
510  if (from && from->mailbox)
511  {
512  mutt_format_s(buf + colorlen, buflen - colorlen, prec, mutt_addr_for_display(from));
513  }
514  else
515  mutt_format_s(buf + colorlen, buflen - colorlen, prec, "");
516  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
517  break;
518 
519  case 'B':
520  case 'K':
521  if (!first_mailing_list(buf, buflen, &e->env->to) &&
522  !first_mailing_list(buf, buflen, &e->env->cc))
523  {
524  buf[0] = '\0';
525  }
526  if (buf[0] != '\0')
527  {
528  mutt_str_copy(tmp, buf, sizeof(tmp));
529  mutt_format_s(buf, buflen, prec, tmp);
530  break;
531  }
532  if (op == 'K')
533  {
534  if (optional)
535  optional = false;
536  /* break if 'K' returns nothing */
537  break;
538  }
539  /* if 'B' returns nothing */
540  /* fallthrough */
541 
542  case 'b':
543  if (m)
544  {
545  p = strrchr(mailbox_path(m), '/');
546 #ifdef USE_NOTMUCH
547  if (m->type == MUTT_NOTMUCH)
548  {
549  char *rel_path = nm_email_get_folder_rel_db(m, e);
550  if (rel_path)
551  p = rel_path;
552  }
553 #endif
554 
555  if (p)
556  mutt_str_copy(buf, p + 1, buflen);
557  else
558  mutt_str_copy(buf, mailbox_path(m), buflen);
559  }
560  else
561  mutt_str_copy(buf, "(null)", buflen);
562  mutt_str_copy(tmp, buf, sizeof(tmp));
563  mutt_format_s(buf, buflen, prec, tmp);
564  break;
565 
566  case 'c':
567  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_SIZE);
568  if (src[0] == 'r')
569  {
570  mutt_str_pretty_size(tmp, sizeof(tmp), email_size(e));
571  src++;
572  }
573  else
574  {
575  mutt_str_pretty_size(tmp, sizeof(tmp), e->body->length);
576  }
577  mutt_format_s(buf + colorlen, buflen - colorlen, prec, tmp);
578  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
579  break;
580 
581  case 'C':
582  colorlen = add_index_color(fmt, sizeof(fmt), flags, MT_COLOR_INDEX_NUMBER);
583  snprintf(fmt + colorlen, sizeof(fmt) - colorlen, "%%%sd", prec);
584  add_index_color(fmt + colorlen, sizeof(fmt) - colorlen, flags, MT_COLOR_INDEX);
585  snprintf(buf, buflen, fmt, e->msgno + 1);
586  break;
587 
588  case 'd':
589  case 'D':
590  case '{':
591  case '[':
592  case '(':
593  case '<':
594  /* preprocess $date_format to handle %Z */
595  {
596  const char *cp = NULL;
597  time_t now;
598  int j = 0;
599 
600  if (optional && ((op == '[') || (op == '(')))
601  {
602  now = mutt_date_epoch();
603  struct tm tm = mutt_date_localtime(now);
604  now -= (op == '(') ? e->received : e->date_sent;
605 
606  char *is = (char *) prec;
607  bool invert = false;
608  if (*is == '>')
609  {
610  invert = true;
611  is++;
612  }
613 
614  while (*is && (*is != '?'))
615  {
616  int t = strtol(is, &is, 10);
617  /* semi-broken (assuming 30 days in all months) */
618  switch (*(is++))
619  {
620  case 'y':
621  if (t > 1)
622  {
623  t--;
624  t *= (60 * 60 * 24 * 365);
625  }
626  t += ((tm.tm_mon * 60 * 60 * 24 * 30) + (tm.tm_mday * 60 * 60 * 24) +
627  (tm.tm_hour * 60 * 60) + (tm.tm_min * 60) + tm.tm_sec);
628  break;
629 
630  case 'm':
631  if (t > 1)
632  {
633  t--;
634  t *= (60 * 60 * 24 * 30);
635  }
636  t += ((tm.tm_mday * 60 * 60 * 24) + (tm.tm_hour * 60 * 60) +
637  (tm.tm_min * 60) + tm.tm_sec);
638  break;
639 
640  case 'w':
641  if (t > 1)
642  {
643  t--;
644  t *= (60 * 60 * 24 * 7);
645  }
646  t += ((tm.tm_wday * 60 * 60 * 24) + (tm.tm_hour * 60 * 60) +
647  (tm.tm_min * 60) + tm.tm_sec);
648  break;
649 
650  case 'd':
651  if (t > 1)
652  {
653  t--;
654  t *= (60 * 60 * 24);
655  }
656  t += ((tm.tm_hour * 60 * 60) + (tm.tm_min * 60) + tm.tm_sec);
657  break;
658 
659  case 'H':
660  if (t > 1)
661  {
662  t--;
663  t *= (60 * 60);
664  }
665  t += ((tm.tm_min * 60) + tm.tm_sec);
666  break;
667 
668  case 'M':
669  if (t > 1)
670  {
671  t--;
672  t *= (60);
673  }
674  t += (tm.tm_sec);
675  break;
676 
677  default:
678  break;
679  }
680  j += t;
681  }
682 
683  if (j < 0)
684  j *= -1;
685 
686  if (((now > j) || (now < (-1 * j))) ^ invert)
687  optional = false;
688  break;
689  }
690 
691  p = buf;
692 
693  cp = ((op == 'd') || (op == 'D')) ? (NONULL(C_DateFormat)) : src;
694  bool do_locales;
695  if (*cp == '!')
696  {
697  do_locales = false;
698  cp++;
699  }
700  else
701  do_locales = true;
702 
703  size_t len = buflen - 1;
704  while ((len > 0) &&
705  ((((op == 'd') || (op == 'D')) && *cp) ||
706  ((op == '{') && (*cp != '}')) || ((op == '[') && (*cp != ']')) ||
707  ((op == '(') && (*cp != ')')) || ((op == '<') && (*cp != '>'))))
708  {
709  if (*cp == '%')
710  {
711  cp++;
712  if (((*cp == 'Z') || (*cp == 'z')) && ((op == 'd') || (op == '{')))
713  {
714  if (len >= 5)
715  {
716  sprintf(p, "%c%02u%02u", e->zoccident ? '-' : '+', e->zhours, e->zminutes);
717  p += 5;
718  len -= 5;
719  }
720  else
721  break; /* not enough space left */
722  }
723  else
724  {
725  if (len >= 2)
726  {
727  *p++ = '%';
728  *p++ = *cp;
729  len -= 2;
730  }
731  else
732  break; /* not enough space */
733  }
734  cp++;
735  }
736  else
737  {
738  *p++ = *cp++;
739  len--;
740  }
741  }
742  *p = '\0';
743 
744  struct tm tm;
745  if ((op == '[') || (op == 'D'))
747  else if (op == '(')
748  tm = mutt_date_localtime(e->received);
749  else if (op == '<')
750  {
752  }
753  else
754  {
755  /* restore sender's time zone */
756  now = e->date_sent;
757  if (e->zoccident)
758  now -= (e->zhours * 3600 + e->zminutes * 60);
759  else
760  now += (e->zhours * 3600 + e->zminutes * 60);
761  tm = mutt_date_gmtime(now);
762  }
763 
764  if (!do_locales)
765  setlocale(LC_TIME, "C");
766  strftime(tmp, sizeof(tmp), buf, &tm);
767  if (!do_locales)
768  setlocale(LC_TIME, "");
769 
770  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_DATE);
771  mutt_format_s(buf + colorlen, buflen - colorlen, prec, tmp);
772  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
773 
774  if ((len > 0) && (op != 'd') && (op != 'D')) /* Skip ending op */
775  src = cp + 1;
776  break;
777  }
778 
779  case 'e':
780  snprintf(fmt, sizeof(fmt), "%%%sd", prec);
781  snprintf(buf, buflen, fmt, mutt_messages_in_thread(m, e, 1));
782  break;
783 
784  case 'E':
785  if (!optional)
786  {
787  snprintf(fmt, sizeof(fmt), "%%%sd", prec);
788  snprintf(buf, buflen, fmt, mutt_messages_in_thread(m, e, 0));
789  }
790  else if (mutt_messages_in_thread(m, e, 0) <= 1)
791  optional = false;
792  break;
793 
794  case 'f':
795  tmp[0] = '\0';
796  mutt_addrlist_write(&e->env->from, tmp, sizeof(tmp), true);
797  mutt_format_s(buf, buflen, prec, tmp);
798  break;
799 
800  case 'F':
801  if (!optional)
802  {
803  const bool is_plain = (src[0] == 'p');
804  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_AUTHOR);
805  make_from(e->env, tmp, sizeof(tmp), false,
806  (is_plain ? MUTT_FORMAT_PLAIN : MUTT_FORMAT_NO_FLAGS));
807  mutt_format_s(buf + colorlen, buflen - colorlen, prec, tmp);
808  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
809 
810  if (is_plain)
811  src++;
812  }
813  else if (mutt_addr_is_user(from))
814  {
815  optional = false;
816  }
817  break;
818 
819  case 'g':
820  tags = driver_tags_get_transformed(&e->tags);
821  if (!optional)
822  {
823  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_TAGS);
824  mutt_format_s(buf + colorlen, buflen - colorlen, prec, NONULL(tags));
825  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
826  }
827  else if (!tags)
828  optional = false;
829  FREE(&tags);
830  break;
831 
832  case 'G':
833  {
834  char format[3];
835  char *tag = NULL;
836 
837  if (!optional)
838  {
839  format[0] = op;
840  format[1] = *src;
841  format[2] = '\0';
842 
843  tag = mutt_hash_find(TagFormats, format);
844  if (tag)
845  {
846  tags = driver_tags_get_transformed_for(&e->tags, tag);
847  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_TAG);
848  mutt_format_s(buf + colorlen, buflen - colorlen, prec, NONULL(tags));
849  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
850  FREE(&tags);
851  }
852  src++;
853  }
854  else
855  {
856  format[0] = op;
857  format[1] = *prec;
858  format[2] = '\0';
859 
860  tag = mutt_hash_find(TagFormats, format);
861  if (tag)
862  {
863  tags = driver_tags_get_transformed_for(&e->tags, tag);
864  if (!tags)
865  optional = false;
866  FREE(&tags);
867  }
868  }
869  break;
870  }
871 
872  case 'H':
873  /* (Hormel) spam score */
874  if (optional)
875  optional = !mutt_buffer_is_empty(&e->env->spam);
876 
877  mutt_format_s(buf, buflen, prec, mutt_b2s(&e->env->spam));
878  break;
879 
880  case 'i':
881  mutt_format_s(buf, buflen, prec, e->env->message_id ? e->env->message_id : "<no.id>");
882  break;
883 
884  case 'J':
885  {
886  bool have_tags = true;
887  tags = driver_tags_get_transformed(&e->tags);
888  if (tags)
889  {
890  if (flags & MUTT_FORMAT_TREE)
891  {
892  char *parent_tags = NULL;
893  if (e->thread->prev && e->thread->prev->message)
894  {
895  parent_tags = driver_tags_get_transformed(&e->thread->prev->message->tags);
896  }
897  if (!parent_tags && e->thread->parent && e->thread->parent->message)
898  {
899  parent_tags =
901  }
902  if (parent_tags && mutt_istr_equal(tags, parent_tags))
903  have_tags = false;
904  FREE(&parent_tags);
905  }
906  }
907  else
908  have_tags = false;
909 
910  if (optional)
911  optional = have_tags;
912 
913  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_TAGS);
914  if (have_tags)
915  mutt_format_s(buf + colorlen, buflen - colorlen, prec, tags);
916  else
917  mutt_format_s(buf + colorlen, buflen - colorlen, prec, "");
918  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
919  FREE(&tags);
920  break;
921  }
922 
923  case 'l':
924  if (!optional)
925  {
926  snprintf(fmt, sizeof(fmt), "%%%sd", prec);
927  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_SIZE);
928  snprintf(buf + colorlen, buflen - colorlen, fmt, (int) e->lines);
929  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
930  }
931  else if (e->lines <= 0)
932  optional = false;
933  break;
934 
935  case 'L':
936  if (!optional)
937  {
938  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_AUTHOR);
939  make_from(e->env, tmp, sizeof(tmp), true, flags);
940  mutt_format_s(buf + colorlen, buflen - colorlen, prec, tmp);
941  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
942  }
943  else if (!check_for_mailing_list(&e->env->to, NULL, NULL, 0) &&
944  !check_for_mailing_list(&e->env->cc, NULL, NULL, 0))
945  {
946  optional = false;
947  }
948  break;
949 
950  case 'm':
951  if (m)
952  {
953  snprintf(fmt, sizeof(fmt), "%%%sd", prec);
954  snprintf(buf, buflen, fmt, m->msg_count);
955  }
956  else
957  mutt_str_copy(buf, "(null)", buflen);
958  break;
959 
960  case 'n':
961  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_AUTHOR);
962  mutt_format_s(buf + colorlen, buflen - colorlen, prec, mutt_get_name(from));
963  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
964  break;
965 
966  case 'M':
967  snprintf(fmt, sizeof(fmt), "%%%sd", prec);
968  if (!optional)
969  {
970  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_COLLAPSED);
971  if (threads && is_index && e->collapsed && (e->num_hidden > 1))
972  {
973  snprintf(buf + colorlen, buflen - colorlen, fmt, e->num_hidden);
974  add_index_color(buf, buflen - colorlen, flags, MT_COLOR_INDEX);
975  }
976  else if (is_index && threads)
977  {
978  mutt_format_s(buf + colorlen, buflen - colorlen, prec, " ");
979  add_index_color(buf, buflen - colorlen, flags, MT_COLOR_INDEX);
980  }
981  else
982  *buf = '\0';
983  }
984  else
985  {
986  if (!(threads && is_index && e->collapsed && (e->num_hidden > 1)))
987  optional = false;
988  }
989  break;
990 
991  case 'N':
992  if (!optional)
993  {
994  snprintf(fmt, sizeof(fmt), "%%%sd", prec);
995  snprintf(buf, buflen, fmt, e->score);
996  }
997  else
998  {
999  if (e->score == 0)
1000  optional = false;
1001  }
1002  break;
1003 
1004  case 'O':
1005  if (!optional)
1006  {
1007  make_from_addr(e->env, tmp, sizeof(tmp), true);
1008  if (!C_SaveAddress && (p = strpbrk(tmp, "%@")))
1009  *p = '\0';
1010  mutt_format_s(buf, buflen, prec, tmp);
1011  }
1012  else if (!check_for_mailing_list_addr(&e->env->to, NULL, 0) &&
1013  !check_for_mailing_list_addr(&e->env->cc, NULL, 0))
1014  {
1015  optional = false;
1016  }
1017  break;
1018 
1019  case 'P':
1020  mutt_str_copy(buf, hfi->pager_progress, buflen);
1021  break;
1022 
1023 #ifdef USE_NNTP
1024  case 'q':
1025  mutt_format_s(buf, buflen, prec, e->env->newsgroups ? e->env->newsgroups : "");
1026  break;
1027 #endif
1028 
1029  case 'r':
1030  tmp[0] = '\0';
1031  mutt_addrlist_write(&e->env->to, tmp, sizeof(tmp), true);
1032  if (optional && (tmp[0] == '\0'))
1033  optional = false;
1034  mutt_format_s(buf, buflen, prec, tmp);
1035  break;
1036 
1037  case 'R':
1038  tmp[0] = '\0';
1039  mutt_addrlist_write(&e->env->cc, tmp, sizeof(tmp), true);
1040  if (optional && (tmp[0] == '\0'))
1041  optional = false;
1042  mutt_format_s(buf, buflen, prec, tmp);
1043  break;
1044 
1045  case 's':
1046  {
1047  char *subj = NULL;
1048  if (e->env->disp_subj)
1049  subj = e->env->disp_subj;
1050  else if (!STAILQ_EMPTY(&SubjectRegexList))
1051  subj = apply_subject_mods(e->env);
1052  else
1053  subj = e->env->subject;
1054  if (flags & MUTT_FORMAT_TREE && !e->collapsed)
1055  {
1056  if (flags & MUTT_FORMAT_FORCESUBJ)
1057  {
1058  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_SUBJECT);
1059  mutt_format_s(buf + colorlen, buflen - colorlen, "", NONULL(subj));
1060  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1061  snprintf(tmp, sizeof(tmp), "%s%s", e->tree, buf);
1062  mutt_format_s_tree(buf, buflen, prec, tmp);
1063  }
1064  else
1065  mutt_format_s_tree(buf, buflen, prec, e->tree);
1066  }
1067  else
1068  {
1069  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_SUBJECT);
1070  mutt_format_s(buf + colorlen, buflen - colorlen, prec, NONULL(subj));
1071  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1072  }
1073  break;
1074  }
1075 
1076  case 'S':
1077  {
1078  const char *wch = NULL;
1079  if (e->deleted)
1080  wch = get_nth_wchar(C_FlagChars, FLAG_CHAR_DELETED);
1081  else if (e->attach_del)
1082  wch = get_nth_wchar(C_FlagChars, FLAG_CHAR_DELETED_ATTACH);
1083  else if (e->tagged)
1084  wch = get_nth_wchar(C_FlagChars, FLAG_CHAR_TAGGED);
1085  else if (e->flagged)
1086  wch = get_nth_wchar(C_FlagChars, FLAG_CHAR_IMPORTANT);
1087  else if (e->replied)
1088  wch = get_nth_wchar(C_FlagChars, FLAG_CHAR_REPLIED);
1089  else if (e->read && (msg_in_pager != e->msgno))
1090  wch = get_nth_wchar(C_FlagChars, FLAG_CHAR_SEMPTY);
1091  else if (e->old)
1092  wch = get_nth_wchar(C_FlagChars, FLAG_CHAR_OLD);
1093  else
1094  wch = get_nth_wchar(C_FlagChars, FLAG_CHAR_NEW);
1095 
1096  snprintf(tmp, sizeof(tmp), "%s", wch);
1097  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_FLAGS);
1098  mutt_format_s(buf + colorlen, buflen - colorlen, prec, tmp);
1099  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1100  break;
1101  }
1102 
1103  case 't':
1104  tmp[0] = '\0';
1105  if (!check_for_mailing_list(&e->env->to, "To ", tmp, sizeof(tmp)) &&
1106  !check_for_mailing_list(&e->env->cc, "Cc ", tmp, sizeof(tmp)))
1107  {
1108  if (to)
1109  snprintf(tmp, sizeof(tmp), "To %s", mutt_get_name(to));
1110  else if (cc)
1111  snprintf(tmp, sizeof(tmp), "Cc %s", mutt_get_name(cc));
1112  }
1113  mutt_format_s(buf, buflen, prec, tmp);
1114  break;
1115 
1116  case 'T':
1117  {
1118  int i;
1119  snprintf(fmt, sizeof(fmt), "%%%ss", prec);
1120  snprintf(buf, buflen, fmt,
1121  (C_ToChars && ((i = user_is_recipient(e))) < C_ToChars->len) ?
1122  C_ToChars->chars[i] :
1123  " ");
1124  break;
1125  }
1126 
1127  case 'u':
1128  if (from && from->mailbox)
1129  {
1130  mutt_str_copy(tmp, mutt_addr_for_display(from), sizeof(tmp));
1131  p = strpbrk(tmp, "%@");
1132  if (p)
1133  *p = '\0';
1134  }
1135  else
1136  tmp[0] = '\0';
1137  mutt_format_s(buf, buflen, prec, tmp);
1138  break;
1139 
1140  case 'v':
1141  if (mutt_addr_is_user(from))
1142  {
1143  if (to)
1144  mutt_format_s(tmp, sizeof(tmp), prec, mutt_get_name(to));
1145  else if (cc)
1146  mutt_format_s(tmp, sizeof(tmp), prec, mutt_get_name(cc));
1147  else
1148  *tmp = '\0';
1149  }
1150  else
1151  mutt_format_s(tmp, sizeof(tmp), prec, mutt_get_name(from));
1152  p = strpbrk(tmp, " %@");
1153  if (p)
1154  *p = '\0';
1155  mutt_format_s(buf, buflen, prec, tmp);
1156  break;
1157 
1158  case 'W':
1159  if (!optional)
1160  {
1161  mutt_format_s(buf, buflen, prec, e->env->organization ? e->env->organization : "");
1162  }
1163  else if (!e->env->organization)
1164  optional = false;
1165  break;
1166 
1167 #ifdef USE_NNTP
1168  case 'x':
1169  if (!optional)
1170  {
1171  mutt_format_s(buf, buflen, prec, e->env->x_comment_to ? e->env->x_comment_to : "");
1172  }
1173  else if (!e->env->x_comment_to)
1174  optional = false;
1175  break;
1176 #endif
1177 
1178  case 'X':
1179  {
1180  int count = mutt_count_body_parts(m, e);
1181 
1182  /* The recursion allows messages without depth to return 0. */
1183  if (optional)
1184  optional = (count != 0);
1185 
1186  snprintf(fmt, sizeof(fmt), "%%%sd", prec);
1187  snprintf(buf, buflen, fmt, count);
1188  break;
1189  }
1190 
1191  case 'y':
1192  if (optional)
1193  optional = (e->env->x_label != NULL);
1194 
1195  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_LABEL);
1196  mutt_format_s(buf + colorlen, buflen - colorlen, prec, NONULL(e->env->x_label));
1197  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1198  break;
1199 
1200  case 'Y':
1201  {
1202  bool label = true;
1203  if (e->env->x_label)
1204  {
1205  struct Email *e_tmp = NULL;
1206  if (flags & MUTT_FORMAT_TREE && (e->thread->prev && e->thread->prev->message &&
1207  e->thread->prev->message->env->x_label))
1208  {
1209  e_tmp = e->thread->prev->message;
1210  }
1211  else if (flags & MUTT_FORMAT_TREE &&
1212  (e->thread->parent && e->thread->parent->message &&
1213  e->thread->parent->message->env->x_label))
1214  {
1215  e_tmp = e->thread->parent->message;
1216  }
1217  if (e_tmp && mutt_istr_equal(e->env->x_label, e_tmp->env->x_label))
1218  label = false;
1219  }
1220  else
1221  label = false;
1222 
1223  if (optional)
1224  optional = label;
1225 
1226  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_LABEL);
1227  if (label)
1228  mutt_format_s(buf + colorlen, buflen - colorlen, prec, NONULL(e->env->x_label));
1229  else
1230  mutt_format_s(buf + colorlen, buflen - colorlen, prec, "");
1231  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1232  break;
1233  }
1234 
1235  case 'z':
1236  if (src[0] == 's') /* status: deleted/new/old/replied */
1237  {
1238  const char *ch = NULL;
1239  if (e->deleted)
1240  ch = get_nth_wchar(C_FlagChars, FLAG_CHAR_DELETED);
1241  else if (e->attach_del)
1242  ch = get_nth_wchar(C_FlagChars, FLAG_CHAR_DELETED_ATTACH);
1243  else if (threads && thread_is_new(e))
1244  ch = get_nth_wchar(C_FlagChars, FLAG_CHAR_NEW_THREAD);
1245  else if (threads && thread_is_old(e))
1246  ch = get_nth_wchar(C_FlagChars, FLAG_CHAR_OLD_THREAD);
1247  else if (e->read && (msg_in_pager != e->msgno))
1248  {
1249  if (e->replied)
1250  ch = get_nth_wchar(C_FlagChars, FLAG_CHAR_REPLIED);
1251  else
1252  ch = get_nth_wchar(C_FlagChars, FLAG_CHAR_ZEMPTY);
1253  }
1254  else
1255  {
1256  if (e->old)
1257  ch = get_nth_wchar(C_FlagChars, FLAG_CHAR_OLD);
1258  else
1259  ch = get_nth_wchar(C_FlagChars, FLAG_CHAR_NEW);
1260  }
1261 
1262  snprintf(tmp, sizeof(tmp), "%s", ch);
1263  src++;
1264  }
1265  else if (src[0] == 'c') /* crypto */
1266  {
1267  const char *ch = "";
1268  if ((WithCrypto != 0) && (e->security & SEC_GOODSIGN))
1269  ch = get_nth_wchar(C_CryptChars, FLAG_CHAR_CRYPT_GOOD_SIGN);
1270  else if ((WithCrypto != 0) && (e->security & SEC_ENCRYPT))
1271  ch = get_nth_wchar(C_CryptChars, FLAG_CHAR_CRYPT_ENCRYPTED);
1272  else if ((WithCrypto != 0) && (e->security & SEC_SIGN))
1273  ch = get_nth_wchar(C_CryptChars, FLAG_CHAR_CRYPT_SIGNED);
1274  else if (((WithCrypto & APPLICATION_PGP) != 0) && ((e->security & PGP_KEY) == PGP_KEY))
1275  {
1276  ch = get_nth_wchar(C_CryptChars, FLAG_CHAR_CRYPT_CONTAINS_KEY);
1277  }
1278  else
1279  ch = get_nth_wchar(C_CryptChars, FLAG_CHAR_CRYPT_NO_CRYPTO);
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 = "";
1287  if (e->tagged)
1288  ch = get_nth_wchar(C_FlagChars, FLAG_CHAR_TAGGED);
1289  else if (e->flagged)
1290  ch = get_nth_wchar(C_FlagChars, FLAG_CHAR_IMPORTANT);
1291  else
1292  ch = get_nth_wchar(C_ToChars, user_is_recipient(e));
1293 
1294  snprintf(tmp, sizeof(tmp), "%s", ch);
1295  src++;
1296  }
1297  else /* fallthrough */
1298  break;
1299 
1300  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_FLAGS);
1301  mutt_format_s(buf + colorlen, buflen - colorlen, prec, tmp);
1302  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1303  break;
1304 
1305  case 'Z':
1306  {
1307  /* New/Old for threads; replied; New/Old for messages */
1308  const char *first = NULL;
1309  if (threads && thread_is_new(e))
1310  first = get_nth_wchar(C_FlagChars, FLAG_CHAR_NEW_THREAD);
1311  else if (threads && thread_is_old(e))
1312  first = get_nth_wchar(C_FlagChars, FLAG_CHAR_OLD_THREAD);
1313  else if (e->read && (msg_in_pager != e->msgno))
1314  {
1315  if (e->replied)
1316  first = get_nth_wchar(C_FlagChars, FLAG_CHAR_REPLIED);
1317  else
1318  first = get_nth_wchar(C_FlagChars, FLAG_CHAR_ZEMPTY);
1319  }
1320  else
1321  {
1322  if (e->old)
1323  first = get_nth_wchar(C_FlagChars, FLAG_CHAR_OLD);
1324  else
1325  first = get_nth_wchar(C_FlagChars, FLAG_CHAR_NEW);
1326  }
1327 
1328  /* Marked for deletion; deleted attachments; crypto */
1329  const char *second = "";
1330  if (e->deleted)
1331  second = get_nth_wchar(C_FlagChars, FLAG_CHAR_DELETED);
1332  else if (e->attach_del)
1333  second = get_nth_wchar(C_FlagChars, FLAG_CHAR_DELETED_ATTACH);
1334  else if ((WithCrypto != 0) && (e->security & SEC_GOODSIGN))
1335  second = get_nth_wchar(C_CryptChars, FLAG_CHAR_CRYPT_GOOD_SIGN);
1336  else if ((WithCrypto != 0) && (e->security & SEC_ENCRYPT))
1337  second = get_nth_wchar(C_CryptChars, FLAG_CHAR_CRYPT_ENCRYPTED);
1338  else if ((WithCrypto != 0) && (e->security & SEC_SIGN))
1339  second = get_nth_wchar(C_CryptChars, FLAG_CHAR_CRYPT_SIGNED);
1340  else if (((WithCrypto & APPLICATION_PGP) != 0) && (e->security & PGP_KEY))
1341  second = get_nth_wchar(C_CryptChars, FLAG_CHAR_CRYPT_CONTAINS_KEY);
1342  else
1343  second = get_nth_wchar(C_CryptChars, FLAG_CHAR_CRYPT_NO_CRYPTO);
1344 
1345  /* Tagged, flagged and recipient flag */
1346  const char *third = "";
1347  if (e->tagged)
1348  third = get_nth_wchar(C_FlagChars, FLAG_CHAR_TAGGED);
1349  else if (e->flagged)
1350  third = get_nth_wchar(C_FlagChars, FLAG_CHAR_IMPORTANT);
1351  else
1352  third = get_nth_wchar(C_ToChars, user_is_recipient(e));
1353 
1354  snprintf(tmp, sizeof(tmp), "%s%s%s", first, second, third);
1355  }
1356 
1357  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_FLAGS);
1358  mutt_format_s(buf + colorlen, buflen - colorlen, prec, tmp);
1359  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1360  break;
1361 
1362  case '@':
1363  {
1364  const char *end = src;
1365  static unsigned char recurse = 0;
1366 
1367  while ((*end != '\0') && (*end != '@'))
1368  end++;
1369  if ((*end == '@') && (recurse < 20))
1370  {
1371  recurse++;
1372  mutt_strn_copy(tmp, src, end - src, sizeof(tmp));
1373  mutt_expando_format(tmp, sizeof(tmp), col, cols,
1374  NONULL(mutt_idxfmt_hook(tmp, m, e)),
1375  index_format_str, data, flags);
1376  mutt_format_s_x(buf, buflen, prec, tmp, true);
1377  recurse--;
1378 
1379  src = end + 1;
1380  break;
1381  }
1382  }
1383  /* fallthrough */
1384 
1385  default:
1386  snprintf(buf, buflen, "%%%s%c", prec, op);
1387  break;
1388  }
1389 
1390  if (optional)
1391  {
1392  mutt_expando_format(buf, buflen, col, cols, if_str, index_format_str,
1393  (intptr_t) hfi, flags);
1394  }
1395  else if (flags & MUTT_FORMAT_OPTIONAL)
1396  {
1397  mutt_expando_format(buf, buflen, col, cols, else_str, index_format_str,
1398  (intptr_t) hfi, flags);
1399  }
1400 
1401  return src;
1402 }
1403 
1415 void mutt_make_string_flags(char *buf, size_t buflen, int cols, const char *s,
1416  struct Mailbox *m, int inpgr, struct Email *e,
1417  MuttFormatFlags flags)
1418 {
1419  struct HdrFormatInfo hfi;
1420 
1421  hfi.email = e;
1422  hfi.mailbox = m;
1423  hfi.msg_in_pager = inpgr;
1424  hfi.pager_progress = 0;
1425 
1426  mutt_expando_format(buf, buflen, 0, cols, s, index_format_str, (intptr_t) &hfi, flags);
1427 }
1428 
1438 void mutt_make_string_info(char *buf, size_t buflen, int cols, const char *s,
1439  struct HdrFormatInfo *hfi, MuttFormatFlags flags)
1440 {
1441  mutt_expando_format(buf, buflen, 0, cols, s, index_format_str, (intptr_t) hfi, flags);
1442 }
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:354
Convenience wrapper for the gui headers.
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:416
FlagChars
Index into the $flag_chars variable ($flag_chars)
Definition: hdrline.c:72
Bcc: string.
Definition: hdrline.c:108
Character denoting a tagged email.
Definition: hdrline.c:74
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox&#39;s path string.
Definition: mailbox.h:203
Index: index number.
Definition: color.h:109
Character denoting a important (flagged) email.
Definition: hdrline.c:75
int lines
How many lines in the body of this message?
Definition: email.h:85
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
uint8_t MuttFormatFlags
Flags for mutt_expando_format(), e.g. MUTT_FORMAT_FORCESUBJ.
Definition: format_flags.h:29
#define NONULL(x)
Definition: string2.h:37
Miscellaneous email parsing routines.
int msg_count
Total number of messages.
Definition: mailbox.h:91
#define WithCrypto
Definition: lib.h:123
void mutt_make_string_flags(char *buf, size_t buflen, int cols, const char *s, struct Mailbox *m, int inpgr, struct Email *e, MuttFormatFlags flags)
Create formatted strings using mailbox expandos.
Definition: hdrline.c:1415
The envelope/body of an email.
Definition: email.h:37
Index: tags field (g, J)
Definition: color.h:111
#define TAILQ_FIRST(head)
Definition: queue.h:716
char ** chars
The array of multibyte character strings.
Definition: mbtable.h:39
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
struct Body * body
List of MIME parts.
Definition: email.h:91
struct ReplaceList SubjectRegexList
List of regexes to tidy the view of the email&#39;s subject.
Definition: globals.c:53
Structs that make up an email.
String processing routines to generate the mail index.
The "currently-open" mailbox.
struct AddressList reply_to
Email&#39;s &#39;reply-to&#39;.
Definition: envelope.h:62
struct tm mutt_date_localtime(time_t t)
Converts calendar time to a broken-down time structure expressed in user timezone.
Definition: date.c:643
static bool user_in_addr(struct AddressList *al)
Do any of the addresses refer to the user?
Definition: hdrline.c:300
#define MUTT_FORMAT_FORCESUBJ
Print the subject even if unchanged.
Definition: format_flags.h:31
static bool thread_is_new(struct Email *e)
Does the email thread contain any new emails?
Definition: hdrline.c:384
struct AddressList bcc
Email&#39;s &#39;Bcc&#39; list.
Definition: envelope.h:60
struct MuttThread * thread
Thread of Emails.
Definition: email.h:95
char * disp_subj
Display subject (modified copy of subject)
Definition: envelope.h:68
Character denoting a thread containing at least one new email.
Definition: hdrline.c:82
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:85
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:49
short recipient
User_is_recipient()&#39;s return value, cached.
Definition: email.h:78
Cc: string.
Definition: hdrline.c:107
Character denoting a message contains a PGP key.
Definition: hdrline.c:95
An email address.
Definition: address.h:34
#define MUTT_DATE_NOW
Constant representing the &#39;current time&#39;, see: mutt_date_gmtime(), mutt_date_localtime() ...
Definition: date.h:39
struct MuttThread * parent
Parent of this Thread.
Definition: thread.h:45
char * mailbox
Mailbox and host address.
Definition: address.h:37
Character denoting a read email, $index_format S expando.
Definition: hdrline.c:83
struct tm mutt_date_gmtime(time_t t)
Converts calendar time to a broken-down time structure expressed in UTC timezone. ...
Definition: date.c:661
static bool thread_is_old(struct Email *e)
Does the email thread contain any unread emails?
Definition: hdrline.c:394
multibyte character table
Definition: mbtable.h:35
bool zoccident
True, if west of UTC, False if east.
Definition: email.h:65
Index: number of messages in collapsed thread.
Definition: color.h:106
Flags to control mutt_expando_format()
struct MbTable * C_FromChars
Config: User-configurable index flags: to address, cc address, etc.
Definition: hdrline.c:66
#define MUTT_FORMAT_NO_FLAGS
No flags are set.
Definition: format_flags.h:30
struct MbTable * C_ToChars
Config: Indicator characters for the &#39;To&#39; field in the index.
Definition: hdrline.c:67
Convenience wrapper for the config headers.
static char * apply_subject_mods(struct Envelope *env)
Apply regex modifications to the subject.
Definition: hdrline.c:361
Email Address Handling.
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:214
Assorted sorting methods.
Some miscellaneous functions.
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
Index: author field (takes a pattern)
Definition: color.h:101
bool tagged
Email is tagged.
Definition: email.h:44
bool read
Email is read.
Definition: email.h:51
const char * mutt_addr_for_display(const struct Address *a)
Convert an Address for display purposes.
Definition: address.c:986
char * message_id
Message ID.
Definition: envelope.h:69
struct MuttThread * prev
Previous sibling Thread.
Definition: thread.h:48
Parse and execute user-defined hooks.
#define MUTT_FORMAT_TREE
Draw the thread tree.
Definition: format_flags.h:32
bool old
Email is seen, but unread.
Definition: email.h:50
Data passed to index_format_str()
Definition: hdrline.h:44
struct AddressList from
Email&#39;s &#39;From&#39; list.
Definition: envelope.h:57
struct Envelope * env
Envelope information.
Definition: email.h:90
Index: tag field (g, takes a pattern)
Definition: color.h:104
Convenience wrapper for the core headers.
Character denoting a deleted attachment.
Definition: hdrline.c:77
struct Mailbox * mailbox
Definition: hdrline.h:46
struct AddressList cc
Email&#39;s &#39;Cc&#39; list.
Definition: envelope.h:59
#define mutt_thread_contains_unread(e)
Definition: mutt_thread.h:85
Character denoting an email that has been read.
Definition: hdrline.c:79
static int user_is_recipient(struct Email *e)
Is the user a recipient of the message.
Definition: hdrline.c:320
Character denoting a thread of emails that has been read.
Definition: hdrline.c:81
Empty string.
Definition: hdrline.c:110
WHERE short C_Sort
Config: Sort method for the index.
Definition: sort.h:60
Email Aliases.
struct TagList tags
For drivers that support server tagging.
Definition: email.h:109
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:528
From: string.
Definition: hdrline.c:109
int score
Message score.
Definition: email.h:89
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:883
time_t date_sent
Time when the message was sent (UTC)
Definition: email.h:82
void mutt_make_string_info(char *buf, size_t buflen, int cols, const char *s, struct HdrFormatInfo *hfi, MuttFormatFlags flags)
Create pager status bar string.
Definition: hdrline.c:1438
#define mutt_b2s(buf)
Definition: buffer.h:41
Index: date field.
Definition: color.h:107
char * x_comment_to
List of &#39;X-comment-to&#39; fields.
Definition: envelope.h:78
const char * mutt_idxfmt_hook(const char *name, struct Mailbox *m, struct Email *e)
Get index-format-hook format string.
Definition: hook.c:866
Notmuch virtual mailbox type.
Sort by email threads.
Definition: sort2.h:51
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:97
Character denoting an email that has been replied to.
Definition: hdrline.c:78
Index: size field.
Definition: color.h:110
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:169
Create/manipulate threading in emails.
WHERE bool C_SaveAddress
Config: Use sender&#39;s full address as a default save folder.
Definition: mutt_globals.h:157
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
A mailbox.
Definition: mailbox.h:81
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:1207
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
static void make_from_addr(struct Envelope *env, char *buf, size_t buflen, bool do_lists)
Create a &#39;from&#39; address for a reply email.
Definition: hdrline.c:270
size_t num_hidden
Number of hidden messages in this view (only valid when collapsed is set)
Definition: email.h:75
void mutt_str_pretty_size(char *buf, size_t buflen, size_t num)
Display an abbreviated size, like 3.4K.
Definition: muttlib.c:1659
Character denoting a message signed with a verified key.
Definition: hdrline.c:92
bool mutt_mb_get_initials(const char *name, char *buf, size_t buflen)
Turn a name into initials.
Definition: mbyte.c:84
static const char * make_from_prefix(enum FieldType disp)
Create a prefix for an author field.
Definition: hdrline.c:180
static size_t add_index_color(char *buf, size_t buflen, MuttFormatFlags flags, char color)
Insert a color marker into a string.
Definition: hdrline.c:124
GUI present the user with a selectable list.
int msg_in_pager
Definition: hdrline.h:47
API for encryption/signing of emails.
bool collapsed
Is this message part of a collapsed thread?
Definition: email.h:73
Character denoting a message is PGP-encrypted.
Definition: hdrline.c:93
char * mutt_replacelist_apply(struct ReplaceList *rl, char *buf, size_t buflen, const char *str)
Apply replacements to a buffer.
Definition: regex.c:351
int mutt_messages_in_thread(struct Mailbox *m, struct Email *e, int flag)
Count the messages in a thread.
Definition: mutt_thread.c:1479
CryptChars
Index into the $crypt_chars variable ($crypt_chars)
Definition: hdrline.c:90
unsigned int zhours
Hours away from UTC.
Definition: email.h:63
char * tree
Character string to print thread tree.
Definition: email.h:94
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib...
Definition: email.h:39
struct Email * message
Email this Thread refers to.
Definition: thread.h:49
Handle mailing lists.
static const char * get_nth_wchar(struct MbTable *table, int index)
Extract one char from a multi-byte table.
Definition: hdrline.c:161
&#39;Notmuch&#39; (virtual) Mailbox type
Definition: mailbox.h:54
#define SEC_SIGN
Email is signed.
Definition: lib.h:86
Character denoting a read email, $index_format Z expando.
Definition: hdrline.c:84
#define MUTT_FORMAT_INDEX
This is a main index entry.
Definition: format_flags.h:36
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:631
Index: label field.
Definition: color.h:108
char * subject
Email&#39;s subject.
Definition: envelope.h:66
WHERE char * C_DateFormat
Config: strftime format string for the d expando.
Definition: mutt_globals.h:89
Index: subject field (takes a pattern)
Definition: color.h:103
void mutt_format_s(char *buf, size_t buflen, const char *prec, const char *s)
Format a simple string.
Definition: curs_lib.c:1244
#define PGP_KEY
Definition: lib.h:106
#define MUTT_FORMAT_PLAIN
Do not prepend DISP_TO, DISP_CC ...
Definition: format_flags.h:38
bool flagged
Marked important?
Definition: email.h:43
char * newsgroups
List of newsgroups.
Definition: envelope.h:75
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:716
Character denoting a deleted email.
Definition: hdrline.c:76
struct MbTable * C_FlagChars
Config: User-configurable index flags: tagged, new, etc.
Definition: hdrline.c:65
char * driver_tags_get_transformed(struct TagList *list)
Get transformed tags.
Definition: tags.c:130
To: string.
Definition: hdrline.c:106
bool deleted
Email is deleted.
Definition: email.h:45
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:772
bool replied
Email has been replied to.
Definition: email.h:54
FieldType
Header types.
Definition: hdrline.c:104
Character denoting an unread email.
Definition: hdrline.c:80
Character denoting a message has no cryptography information.
Definition: hdrline.c:96
Colour indicator.
Definition: mutt_thread.h:71
#define FREE(x)
Definition: memory.h:40
bool mutt_addr_is_user(const struct Address *addr)
Does the address belong to the user.
Definition: alias.c:547
const char * pager_progress
Definition: hdrline.h:49
char * organization
Organisation header.
Definition: envelope.h:73
#define MUTT_FORMAT_NOFILTER
Do not allow filtering on this pass.
Definition: format_flags.h:37
Character denoting a message is signed.
Definition: hdrline.c:94
#define STAILQ_EMPTY(head)
Definition: queue.h:345
bool recip_valid
Is_recipient is valid.
Definition: email.h:58
#define MUTT_FORMAT_OPTIONAL
Allow optional field processing.
Definition: format_flags.h:33
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
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:1688
#define TAILQ_NEXT(elm, field)
Definition: queue.h:825
int mutt_count_body_parts(struct Mailbox *m, struct Email *e)
Count the MIME Body parts.
Definition: mutt_parse.c:206
Hundreds of global variables to back the user variables.
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
#define TAILQ_EMPTY(head)
Definition: queue.h:714
Index: default colour (takes a pattern)
Definition: color.h:100
struct MbTable * C_CryptChars
Config: User-configurable crypto flags: signed, encrypted etc.
Definition: hdrline.c:64
Convenience wrapper for the library headers.
WHERE struct HashTable * TagFormats
Hash Table of tag-formats (tag -> format string)
Definition: mutt_globals.h:59
struct Email * email
Definition: hdrline.h:48
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
char * x_label
X-Label.
Definition: envelope.h:72
#define SEC_GOODSIGN
Email has a valid signature.
Definition: lib.h:87
size_t mutt_addrlist_write(const struct AddressList *al, char *buf, size_t buflen, bool display)
Write an Address to a buffer.
Definition: address.c:1150
unsigned int zminutes
Minutes away from UTC.
Definition: email.h:64
size_t email_size(const struct Email *e)
compute the size of an email
Definition: email.c:117
#define SORT_MASK
Mask for the sort id.
Definition: sort2.h:80
time_t received
Time when the message was placed in the mailbox.
Definition: email.h:83
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:455
Index: flags field (takes a pattern)
Definition: color.h:102
The header of an Email.
Definition: envelope.h:54
struct Buffer spam
Spam header.
Definition: envelope.h:80
int len
Number of characters.
Definition: mbtable.h:38
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:1256
int msgno
Number displayed to the user.
Definition: email.h:87
const char * mutt_get_name(const struct Address *a)
Pick the best name to display from an address.
Definition: sort.c:157