NeoMutt  2020-04-24
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 <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 "gui/lib.h"
45 #include "hdrline.h"
46 #include "alias.h"
47 #include "context.h"
48 #include "format_flags.h"
49 #include "globals.h"
50 #include "hook.h"
51 #include "mutt_menu.h"
52 #include "mutt_parse.h"
53 #include "mutt_thread.h"
54 #include "muttlib.h"
55 #include "sort.h"
56 #include "ncrypt/lib.h"
57 
58 /* These Config Variables are only used in hdrline.c */
62 struct MbTable *C_ToChars;
63 
68 {
80 };
81 
86 {
92 };
93 
100 {
107 };
108 
114 bool mutt_is_mail_list(const struct Address *addr)
115 {
117  return mutt_regexlist_match(&MailLists, addr->mailbox);
118  return false;
119 }
120 
126 bool mutt_is_subscribed_list(const struct Address *addr)
127 {
128  if (!mutt_regexlist_match(&UnMailLists, addr->mailbox) &&
130  {
132  }
133  return false;
134 }
135 
148 static bool check_for_mailing_list(struct AddressList *al, const char *pfx,
149  char *buf, int buflen)
150 {
151  struct Address *a = NULL;
152  TAILQ_FOREACH(a, al, entries)
153  {
155  {
156  if (pfx && buf && buflen)
157  snprintf(buf, buflen, "%s%s", pfx, mutt_get_name(a));
158  return true;
159  }
160  }
161  return false;
162 }
163 
173 static bool check_for_mailing_list_addr(struct AddressList *al, char *buf, int buflen)
174 {
175  struct Address *a = NULL;
176  TAILQ_FOREACH(a, al, entries)
177  {
179  {
180  if (buf && buflen)
181  snprintf(buf, buflen, "%s", a->mailbox);
182  return true;
183  }
184  }
185  return false;
186 }
187 
195 static bool first_mailing_list(char *buf, size_t buflen, struct AddressList *al)
196 {
197  struct Address *a = NULL;
198  TAILQ_FOREACH(a, al, entries)
199  {
201  {
202  mutt_save_path(buf, buflen, a);
203  return true;
204  }
205  }
206  return false;
207 }
208 
219 static size_t add_index_color(char *buf, size_t buflen, MuttFormatFlags flags, char color)
220 {
221  /* only add color markers if we are operating on main index entries. */
222  if (!(flags & MUTT_FORMAT_INDEX))
223  return 0;
224 
225  /* this item is going to be passed to an external filter */
226  if (flags & MUTT_FORMAT_NOFILTER)
227  return 0;
228 
229  if (color == MT_COLOR_INDEX)
230  { /* buf might be uninitialized other cases */
231  const size_t len = mutt_str_strlen(buf);
232  buf += len;
233  buflen -= len;
234  }
235 
236  if (buflen <= 2)
237  return 0;
238 
239  buf[0] = MUTT_SPECIAL_INDEX;
240  buf[1] = color;
241  buf[2] = '\0';
242 
243  return 2;
244 }
245 
256 static const char *get_nth_wchar(struct MbTable *table, int index)
257 {
258  if (!table || !table->chars || (index < 0) || (index >= table->len))
259  return " ";
260 
261  if (table->chars[index][0] == '\r')
262  return "";
263 
264  return table->chars[index];
265 }
266 
275 static const char *make_from_prefix(enum FieldType disp)
276 {
277  /* need 2 bytes at the end, one for the space, another for NUL */
278  static char padded[8];
279  static const char *long_prefixes[DISP_MAX] = {
280  [DISP_TO] = "To ", [DISP_CC] = "Cc ", [DISP_BCC] = "Bcc ",
281  [DISP_FROM] = "", [DISP_PLAIN] = "",
282  };
283 
284  if (!C_FromChars || !C_FromChars->chars || (C_FromChars->len == 0))
285  return long_prefixes[disp];
286 
287  const char *pchar = get_nth_wchar(C_FromChars, disp);
288  if (mutt_str_strlen(pchar) == 0)
289  return "";
290 
291  snprintf(padded, sizeof(padded), "%s ", pchar);
292  return padded;
293 }
294 
309 static void make_from(struct Envelope *env, char *buf, size_t buflen,
310  bool do_lists, MuttFormatFlags flags)
311 {
312  if (!env || !buf)
313  return;
314 
315  bool me;
316  enum FieldType disp;
317  struct AddressList *name = NULL;
318 
319  me = mutt_addr_is_user(TAILQ_FIRST(&env->from));
320 
321  if (do_lists || me)
322  {
323  if (check_for_mailing_list(&env->to, make_from_prefix(DISP_TO), buf, buflen))
324  return;
325  if (check_for_mailing_list(&env->cc, make_from_prefix(DISP_CC), buf, buflen))
326  return;
327  }
328 
329  if (me && !TAILQ_EMPTY(&env->to))
330  {
331  disp = (flags & MUTT_FORMAT_PLAIN) ? DISP_PLAIN : DISP_TO;
332  name = &env->to;
333  }
334  else if (me && !TAILQ_EMPTY(&env->cc))
335  {
336  disp = DISP_CC;
337  name = &env->cc;
338  }
339  else if (me && !TAILQ_EMPTY(&env->bcc))
340  {
341  disp = DISP_BCC;
342  name = &env->bcc;
343  }
344  else if (!TAILQ_EMPTY(&env->from))
345  {
346  disp = DISP_FROM;
347  name = &env->from;
348  }
349  else
350  {
351  *buf = '\0';
352  return;
353  }
354 
355  snprintf(buf, buflen, "%s%s", make_from_prefix(disp), mutt_get_name(TAILQ_FIRST(name)));
356 }
357 
365 static void make_from_addr(struct Envelope *env, char *buf, size_t buflen, bool do_lists)
366 {
367  if (!env || !buf)
368  return;
369 
370  bool me = mutt_addr_is_user(TAILQ_FIRST(&env->from));
371 
372  if (do_lists || me)
373  {
374  if (check_for_mailing_list_addr(&env->to, buf, buflen))
375  return;
376  if (check_for_mailing_list_addr(&env->cc, buf, buflen))
377  return;
378  }
379 
380  if (me && !TAILQ_EMPTY(&env->to))
381  snprintf(buf, buflen, "%s", TAILQ_FIRST(&env->to)->mailbox);
382  else if (me && !TAILQ_EMPTY(&env->cc))
383  snprintf(buf, buflen, "%s", TAILQ_FIRST(&env->cc)->mailbox);
384  else if (!TAILQ_EMPTY(&env->from))
385  mutt_str_strfcpy(buf, TAILQ_FIRST(&env->from)->mailbox, buflen);
386  else
387  *buf = '\0';
388 }
389 
395 static bool user_in_addr(struct AddressList *al)
396 {
397  struct Address *a = NULL;
398  TAILQ_FOREACH(a, al, entries)
399  if (mutt_addr_is_user(a))
400  return true;
401  return false;
402 }
403 
415 static int user_is_recipient(struct Email *e)
416 {
417  if (!e || !e->env)
418  return 0;
419 
420  struct Envelope *env = e->env;
421 
422  if (!e->recip_valid)
423  {
424  e->recip_valid = true;
425 
426  if (mutt_addr_is_user(TAILQ_FIRST(&env->from)))
427  e->recipient = 4;
428  else if (user_in_addr(&env->to))
429  {
430  if (TAILQ_NEXT(TAILQ_FIRST(&env->to), entries) || !TAILQ_EMPTY(&env->cc))
431  e->recipient = 2; /* non-unique recipient */
432  else
433  e->recipient = 1; /* unique recipient */
434  }
435  else if (user_in_addr(&env->cc))
436  e->recipient = 3;
437  else if (check_for_mailing_list(&env->to, NULL, NULL, 0))
438  e->recipient = 5;
439  else if (check_for_mailing_list(&env->cc, NULL, NULL, 0))
440  e->recipient = 5;
441  else if (user_in_addr(&env->reply_to))
442  e->recipient = 6;
443  else
444  e->recipient = 0;
445  }
446 
447  return e->recipient;
448 }
449 
456 static char *apply_subject_mods(struct Envelope *env)
457 {
458  if (!env)
459  return NULL;
460 
462  return env->subject;
463 
464  if (!env->subject || (*env->subject == '\0'))
465  {
466  env->disp_subj = NULL;
467  return NULL;
468  }
469 
471  return env->disp_subj;
472 }
473 
480 static bool thread_is_new(struct Context *ctx, struct Email *e)
481 {
482  return e->collapsed && (e->num_hidden > 1) &&
483  (mutt_thread_contains_unread(ctx, e) == 1);
484 }
485 
492 static bool thread_is_old(struct Context *ctx, struct Email *e)
493 {
494  return e->collapsed && (e->num_hidden > 1) &&
495  (mutt_thread_contains_unread(ctx, e) == 2);
496 }
497 
554 static const char *index_format_str(char *buf, size_t buflen, size_t col, int cols,
555  char op, const char *src, const char *prec,
556  const char *if_str, const char *else_str,
557  unsigned long data, MuttFormatFlags flags)
558 {
559  struct HdrFormatInfo *hfi = (struct HdrFormatInfo *) data;
560  char fmt[128], tmp[1024];
561  char *p = NULL, *tags = NULL;
562  bool optional = (flags & MUTT_FORMAT_OPTIONAL);
563  int threads = ((C_Sort & SORT_MASK) == SORT_THREADS);
564  int is_index = (flags & MUTT_FORMAT_INDEX);
565  size_t colorlen;
566 
567  struct Email *e = hfi->email;
568  struct Context *ctx = hfi->ctx;
569  struct Mailbox *m = hfi->mailbox;
570 
571  if (!e || !e->env)
572  return src;
573 
574  const struct Address *reply_to = TAILQ_FIRST(&e->env->reply_to);
575  const struct Address *from = TAILQ_FIRST(&e->env->from);
576  const struct Address *to = TAILQ_FIRST(&e->env->to);
577  const struct Address *cc = TAILQ_FIRST(&e->env->cc);
578 
579  buf[0] = '\0';
580  switch (op)
581  {
582  case 'A':
583  case 'I':
584  if (op == 'A')
585  {
586  if (reply_to && reply_to->mailbox)
587  {
588  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_AUTHOR);
589  mutt_format_s(buf + colorlen, buflen - colorlen, prec,
590  mutt_addr_for_display(reply_to));
591  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
592  break;
593  }
594  }
595  else
596  {
597  if (mutt_mb_get_initials(mutt_get_name(from), tmp, sizeof(tmp)))
598  {
599  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_AUTHOR);
600  mutt_format_s(buf + colorlen, buflen - colorlen, prec, tmp);
601  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
602  break;
603  }
604  }
605  /* fallthrough */
606 
607  case 'a':
608  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_AUTHOR);
609  if (from && from->mailbox)
610  {
611  mutt_format_s(buf + colorlen, buflen - colorlen, prec, mutt_addr_for_display(from));
612  }
613  else
614  mutt_format_s(buf + colorlen, buflen - colorlen, prec, "");
615  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
616  break;
617 
618  case 'B':
619  case 'K':
620  if (!first_mailing_list(buf, buflen, &e->env->to) &&
621  !first_mailing_list(buf, buflen, &e->env->cc))
622  {
623  buf[0] = '\0';
624  }
625  if (buf[0] != '\0')
626  {
627  mutt_str_strfcpy(tmp, buf, sizeof(tmp));
628  mutt_format_s(buf, buflen, prec, tmp);
629  break;
630  }
631  if (op == 'K')
632  {
633  if (optional)
634  optional = false;
635  /* break if 'K' returns nothing */
636  break;
637  }
638  /* if 'B' returns nothing */
639  /* fallthrough */
640 
641  case 'b':
642  if (m)
643  {
644  p = strrchr(mailbox_path(m), '/');
645  if (p)
646  mutt_str_strfcpy(buf, p + 1, buflen);
647  else
648  mutt_str_strfcpy(buf, mailbox_path(m), buflen);
649  }
650  else
651  mutt_str_strfcpy(buf, "(null)", buflen);
652  mutt_str_strfcpy(tmp, buf, sizeof(tmp));
653  mutt_format_s(buf, buflen, prec, tmp);
654  break;
655 
656  case 'c':
657  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_SIZE);
658  if (src[0] == 'r')
659  {
660  mutt_str_pretty_size(tmp, sizeof(tmp), email_size(e));
661  src++;
662  }
663  else
664  {
665  mutt_str_pretty_size(tmp, sizeof(tmp), e->content->length);
666  }
667  mutt_format_s(buf + colorlen, buflen - colorlen, prec, tmp);
668  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
669  break;
670 
671  case 'C':
672  colorlen = add_index_color(fmt, sizeof(fmt), flags, MT_COLOR_INDEX_NUMBER);
673  snprintf(fmt + colorlen, sizeof(fmt) - colorlen, "%%%sd", prec);
674  add_index_color(fmt + colorlen, sizeof(fmt) - colorlen, flags, MT_COLOR_INDEX);
675  snprintf(buf, buflen, fmt, e->msgno + 1);
676  break;
677 
678  case 'd':
679  case 'D':
680  case '{':
681  case '[':
682  case '(':
683  case '<':
684  /* preprocess $date_format to handle %Z */
685  {
686  const char *cp = NULL;
687  time_t now;
688  int j = 0;
689 
690  if (optional && ((op == '[') || (op == '(')))
691  {
692  now = mutt_date_epoch();
693  struct tm tm = mutt_date_localtime(now);
694  now -= (op == '(') ? e->received : e->date_sent;
695 
696  char *is = (char *) prec;
697  bool invert = false;
698  if (*is == '>')
699  {
700  invert = true;
701  is++;
702  }
703 
704  while (*is && (*is != '?'))
705  {
706  int t = strtol(is, &is, 10);
707  /* semi-broken (assuming 30 days in all months) */
708  switch (*(is++))
709  {
710  case 'y':
711  if (t > 1)
712  {
713  t--;
714  t *= (60 * 60 * 24 * 365);
715  }
716  t += ((tm.tm_mon * 60 * 60 * 24 * 30) + (tm.tm_mday * 60 * 60 * 24) +
717  (tm.tm_hour * 60 * 60) + (tm.tm_min * 60) + tm.tm_sec);
718  break;
719 
720  case 'm':
721  if (t > 1)
722  {
723  t--;
724  t *= (60 * 60 * 24 * 30);
725  }
726  t += ((tm.tm_mday * 60 * 60 * 24) + (tm.tm_hour * 60 * 60) +
727  (tm.tm_min * 60) + tm.tm_sec);
728  break;
729 
730  case 'w':
731  if (t > 1)
732  {
733  t--;
734  t *= (60 * 60 * 24 * 7);
735  }
736  t += ((tm.tm_wday * 60 * 60 * 24) + (tm.tm_hour * 60 * 60) +
737  (tm.tm_min * 60) + tm.tm_sec);
738  break;
739 
740  case 'd':
741  if (t > 1)
742  {
743  t--;
744  t *= (60 * 60 * 24);
745  }
746  t += ((tm.tm_hour * 60 * 60) + (tm.tm_min * 60) + tm.tm_sec);
747  break;
748 
749  case 'H':
750  if (t > 1)
751  {
752  t--;
753  t *= (60 * 60);
754  }
755  t += ((tm.tm_min * 60) + tm.tm_sec);
756  break;
757 
758  case 'M':
759  if (t > 1)
760  {
761  t--;
762  t *= (60);
763  }
764  t += (tm.tm_sec);
765  break;
766 
767  default:
768  break;
769  }
770  j += t;
771  }
772 
773  if (j < 0)
774  j *= -1;
775 
776  if (((now > j) || (now < (-1 * j))) ^ invert)
777  optional = false;
778  break;
779  }
780 
781  p = buf;
782 
783  cp = ((op == 'd') || (op == 'D')) ? (NONULL(C_DateFormat)) : src;
784  bool do_locales;
785  if (*cp == '!')
786  {
787  do_locales = false;
788  cp++;
789  }
790  else
791  do_locales = true;
792 
793  size_t len = buflen - 1;
794  while ((len > 0) &&
795  ((((op == 'd') || (op == 'D')) && *cp) ||
796  ((op == '{') && (*cp != '}')) || ((op == '[') && (*cp != ']')) ||
797  ((op == '(') && (*cp != ')')) || ((op == '<') && (*cp != '>'))))
798  {
799  if (*cp == '%')
800  {
801  cp++;
802  if (((*cp == 'Z') || (*cp == 'z')) && ((op == 'd') || (op == '{')))
803  {
804  if (len >= 5)
805  {
806  sprintf(p, "%c%02u%02u", e->zoccident ? '-' : '+', e->zhours, e->zminutes);
807  p += 5;
808  len -= 5;
809  }
810  else
811  break; /* not enough space left */
812  }
813  else
814  {
815  if (len >= 2)
816  {
817  *p++ = '%';
818  *p++ = *cp;
819  len -= 2;
820  }
821  else
822  break; /* not enough space */
823  }
824  cp++;
825  }
826  else
827  {
828  *p++ = *cp++;
829  len--;
830  }
831  }
832  *p = '\0';
833 
834  struct tm tm;
835  if ((op == '[') || (op == 'D'))
837  else if (op == '(')
838  tm = mutt_date_localtime(e->received);
839  else if (op == '<')
840  {
842  }
843  else
844  {
845  /* restore sender's time zone */
846  now = e->date_sent;
847  if (e->zoccident)
848  now -= (e->zhours * 3600 + e->zminutes * 60);
849  else
850  now += (e->zhours * 3600 + e->zminutes * 60);
851  tm = mutt_date_gmtime(now);
852  }
853 
854  if (!do_locales)
855  setlocale(LC_TIME, "C");
856  strftime(tmp, sizeof(tmp), buf, &tm);
857  if (!do_locales)
858  setlocale(LC_TIME, "");
859 
860  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_DATE);
861  mutt_format_s(buf + colorlen, buflen - colorlen, prec, tmp);
862  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
863 
864  if ((len > 0) && (op != 'd') && (op != 'D')) /* Skip ending op */
865  src = cp + 1;
866  break;
867  }
868 
869  case 'e':
870  snprintf(fmt, sizeof(fmt), "%%%sd", prec);
871  snprintf(buf, buflen, fmt, mutt_messages_in_thread(m, e, 1));
872  break;
873 
874  case 'E':
875  if (!optional)
876  {
877  snprintf(fmt, sizeof(fmt), "%%%sd", prec);
878  snprintf(buf, buflen, fmt, mutt_messages_in_thread(m, e, 0));
879  }
880  else if (mutt_messages_in_thread(m, e, 0) <= 1)
881  optional = false;
882  break;
883 
884  case 'f':
885  tmp[0] = '\0';
886  mutt_addrlist_write(&e->env->from, tmp, sizeof(tmp), true);
887  mutt_format_s(buf, buflen, prec, tmp);
888  break;
889 
890  case 'F':
891  if (!optional)
892  {
893  const bool is_plain = (src[0] == 'p');
894  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_AUTHOR);
895  make_from(e->env, tmp, sizeof(tmp), false,
896  (is_plain ? MUTT_FORMAT_PLAIN : MUTT_FORMAT_NO_FLAGS));
897  mutt_format_s(buf + colorlen, buflen - colorlen, prec, tmp);
898  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
899 
900  if (is_plain)
901  src++;
902  }
903  else if (mutt_addr_is_user(from))
904  {
905  optional = false;
906  }
907  break;
908 
909  case 'g':
910  tags = driver_tags_get_transformed(&e->tags);
911  if (!optional)
912  {
913  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_TAGS);
914  mutt_format_s(buf + colorlen, buflen - colorlen, prec, NONULL(tags));
915  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
916  }
917  else if (!tags)
918  optional = false;
919  FREE(&tags);
920  break;
921 
922  case 'G':
923  {
924  char format[3];
925  char *tag = NULL;
926 
927  if (!optional)
928  {
929  format[0] = op;
930  format[1] = *src;
931  format[2] = '\0';
932 
933  tag = mutt_hash_find(TagFormats, format);
934  if (tag)
935  {
936  tags = driver_tags_get_transformed_for(&e->tags, tag);
937  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_TAG);
938  mutt_format_s(buf + colorlen, buflen - colorlen, prec, NONULL(tags));
939  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
940  FREE(&tags);
941  }
942  src++;
943  }
944  else
945  {
946  format[0] = op;
947  format[1] = *prec;
948  format[2] = '\0';
949 
950  tag = mutt_hash_find(TagFormats, format);
951  if (tag)
952  {
953  tags = driver_tags_get_transformed_for(&e->tags, tag);
954  if (!tags)
955  optional = false;
956  FREE(&tags);
957  }
958  }
959  break;
960  }
961 
962  case 'H':
963  /* (Hormel) spam score */
964  if (optional)
965  optional = !mutt_buffer_is_empty(&e->env->spam);
966 
967  mutt_format_s(buf, buflen, prec, mutt_b2s(&e->env->spam));
968  break;
969 
970  case 'i':
971  mutt_format_s(buf, buflen, prec, e->env->message_id ? e->env->message_id : "<no.id>");
972  break;
973 
974  case 'J':
975  {
976  bool have_tags = true;
977  tags = driver_tags_get_transformed(&e->tags);
978  if (tags)
979  {
980  if (flags & MUTT_FORMAT_TREE)
981  {
982  char *parent_tags = NULL;
983  if (e->thread->prev && e->thread->prev->message)
984  {
985  parent_tags = driver_tags_get_transformed(&e->thread->prev->message->tags);
986  }
987  if (!parent_tags && e->thread->parent && e->thread->parent->message)
988  {
989  parent_tags =
991  }
992  if (parent_tags && (mutt_str_strcasecmp(tags, parent_tags) == 0))
993  have_tags = false;
994  FREE(&parent_tags);
995  }
996  }
997  else
998  have_tags = false;
999 
1000  if (optional)
1001  optional = have_tags;
1002 
1003  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_TAGS);
1004  if (have_tags)
1005  mutt_format_s(buf + colorlen, buflen - colorlen, prec, tags);
1006  else
1007  mutt_format_s(buf + colorlen, buflen - colorlen, prec, "");
1008  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1009  FREE(&tags);
1010  break;
1011  }
1012 
1013  case 'l':
1014  if (!optional)
1015  {
1016  snprintf(fmt, sizeof(fmt), "%%%sd", prec);
1017  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_SIZE);
1018  snprintf(buf + colorlen, buflen - colorlen, fmt, (int) e->lines);
1019  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1020  }
1021  else if (e->lines <= 0)
1022  optional = false;
1023  break;
1024 
1025  case 'L':
1026  if (!optional)
1027  {
1028  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_AUTHOR);
1029  make_from(e->env, tmp, sizeof(tmp), true, flags);
1030  mutt_format_s(buf + colorlen, buflen - colorlen, prec, tmp);
1031  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1032  }
1033  else if (!check_for_mailing_list(&e->env->to, NULL, NULL, 0) &&
1034  !check_for_mailing_list(&e->env->cc, NULL, NULL, 0))
1035  {
1036  optional = false;
1037  }
1038  break;
1039 
1040  case 'm':
1041  if (m)
1042  {
1043  snprintf(fmt, sizeof(fmt), "%%%sd", prec);
1044  snprintf(buf, buflen, fmt, m->msg_count);
1045  }
1046  else
1047  mutt_str_strfcpy(buf, "(null)", buflen);
1048  break;
1049 
1050  case 'n':
1051  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_AUTHOR);
1052  mutt_format_s(buf + colorlen, buflen - colorlen, prec, mutt_get_name(from));
1053  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1054  break;
1055 
1056  case 'M':
1057  snprintf(fmt, sizeof(fmt), "%%%sd", prec);
1058  if (!optional)
1059  {
1060  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_COLLAPSED);
1061  if (threads && is_index && e->collapsed && (e->num_hidden > 1))
1062  {
1063  snprintf(buf + colorlen, buflen - colorlen, fmt, e->num_hidden);
1064  add_index_color(buf, buflen - colorlen, flags, MT_COLOR_INDEX);
1065  }
1066  else if (is_index && threads)
1067  {
1068  mutt_format_s(buf + colorlen, buflen - colorlen, prec, " ");
1069  add_index_color(buf, buflen - colorlen, flags, MT_COLOR_INDEX);
1070  }
1071  else
1072  *buf = '\0';
1073  }
1074  else
1075  {
1076  if (!(threads && is_index && e->collapsed && (e->num_hidden > 1)))
1077  optional = false;
1078  }
1079  break;
1080 
1081  case 'N':
1082  if (!optional)
1083  {
1084  snprintf(fmt, sizeof(fmt), "%%%sd", prec);
1085  snprintf(buf, buflen, fmt, e->score);
1086  }
1087  else
1088  {
1089  if (e->score == 0)
1090  optional = false;
1091  }
1092  break;
1093 
1094  case 'O':
1095  if (!optional)
1096  {
1097  make_from_addr(e->env, tmp, sizeof(tmp), true);
1098  if (!C_SaveAddress && (p = strpbrk(tmp, "%@")))
1099  *p = '\0';
1100  mutt_format_s(buf, buflen, prec, tmp);
1101  }
1102  else if (!check_for_mailing_list_addr(&e->env->to, NULL, 0) &&
1103  !check_for_mailing_list_addr(&e->env->cc, NULL, 0))
1104  {
1105  optional = false;
1106  }
1107  break;
1108 
1109  case 'P':
1110  mutt_str_strfcpy(buf, hfi->pager_progress, buflen);
1111  break;
1112 
1113 #ifdef USE_NNTP
1114  case 'q':
1115  mutt_format_s(buf, buflen, prec, e->env->newsgroups ? e->env->newsgroups : "");
1116  break;
1117 #endif
1118 
1119  case 'r':
1120  tmp[0] = '\0';
1121  mutt_addrlist_write(&e->env->to, tmp, sizeof(tmp), true);
1122  if (optional && (tmp[0] == '\0'))
1123  optional = false;
1124  mutt_format_s(buf, buflen, prec, tmp);
1125  break;
1126 
1127  case 'R':
1128  tmp[0] = '\0';
1129  mutt_addrlist_write(&e->env->cc, tmp, sizeof(tmp), true);
1130  if (optional && (tmp[0] == '\0'))
1131  optional = false;
1132  mutt_format_s(buf, buflen, prec, tmp);
1133  break;
1134 
1135  case 's':
1136  {
1137  char *subj = NULL;
1138  if (e->env->disp_subj)
1139  subj = e->env->disp_subj;
1140  else if (!STAILQ_EMPTY(&SubjectRegexList))
1141  subj = apply_subject_mods(e->env);
1142  else
1143  subj = e->env->subject;
1144  if (flags & MUTT_FORMAT_TREE && !e->collapsed)
1145  {
1146  if (flags & MUTT_FORMAT_FORCESUBJ)
1147  {
1148  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_SUBJECT);
1149  mutt_format_s(buf + colorlen, buflen - colorlen, "", NONULL(subj));
1150  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1151  snprintf(tmp, sizeof(tmp), "%s%s", e->tree, buf);
1152  mutt_format_s_tree(buf, buflen, prec, tmp);
1153  }
1154  else
1155  mutt_format_s_tree(buf, buflen, prec, e->tree);
1156  }
1157  else
1158  {
1159  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_SUBJECT);
1160  mutt_format_s(buf + colorlen, buflen - colorlen, prec, NONULL(subj));
1161  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1162  }
1163  break;
1164  }
1165 
1166  case 'S':
1167  {
1168  const char *wch = NULL;
1169  if (e->deleted)
1170  wch = get_nth_wchar(C_FlagChars, FLAG_CHAR_DELETED);
1171  else if (e->attach_del)
1172  wch = get_nth_wchar(C_FlagChars, FLAG_CHAR_DELETED_ATTACH);
1173  else if (e->tagged)
1174  wch = get_nth_wchar(C_FlagChars, FLAG_CHAR_TAGGED);
1175  else if (e->flagged)
1176  wch = get_nth_wchar(C_FlagChars, FLAG_CHAR_IMPORTANT);
1177  else if (e->replied)
1178  wch = get_nth_wchar(C_FlagChars, FLAG_CHAR_REPLIED);
1179  else if (e->read && (ctx && (ctx->msg_not_read_yet != e->msgno)))
1180  wch = get_nth_wchar(C_FlagChars, FLAG_CHAR_SEMPTY);
1181  else if (e->old)
1182  wch = get_nth_wchar(C_FlagChars, FLAG_CHAR_OLD);
1183  else
1184  wch = get_nth_wchar(C_FlagChars, FLAG_CHAR_NEW);
1185 
1186  snprintf(tmp, sizeof(tmp), "%s", wch);
1187  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_FLAGS);
1188  mutt_format_s(buf + colorlen, buflen - colorlen, prec, tmp);
1189  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1190  break;
1191  }
1192 
1193  case 't':
1194  tmp[0] = '\0';
1195  if (!check_for_mailing_list(&e->env->to, "To ", tmp, sizeof(tmp)) &&
1196  !check_for_mailing_list(&e->env->cc, "Cc ", tmp, sizeof(tmp)))
1197  {
1198  if (to)
1199  snprintf(tmp, sizeof(tmp), "To %s", mutt_get_name(to));
1200  else if (cc)
1201  snprintf(tmp, sizeof(tmp), "Cc %s", mutt_get_name(cc));
1202  }
1203  mutt_format_s(buf, buflen, prec, tmp);
1204  break;
1205 
1206  case 'T':
1207  {
1208  int i;
1209  snprintf(fmt, sizeof(fmt), "%%%ss", prec);
1210  snprintf(buf, buflen, fmt,
1211  (C_ToChars && ((i = user_is_recipient(e))) < C_ToChars->len) ?
1212  C_ToChars->chars[i] :
1213  " ");
1214  break;
1215  }
1216 
1217  case 'u':
1218  if (from && from->mailbox)
1219  {
1220  mutt_str_strfcpy(tmp, mutt_addr_for_display(from), sizeof(tmp));
1221  p = strpbrk(tmp, "%@");
1222  if (p)
1223  *p = '\0';
1224  }
1225  else
1226  tmp[0] = '\0';
1227  mutt_format_s(buf, buflen, prec, tmp);
1228  break;
1229 
1230  case 'v':
1231  if (mutt_addr_is_user(from))
1232  {
1233  if (to)
1234  mutt_format_s(tmp, sizeof(tmp), prec, mutt_get_name(to));
1235  else if (cc)
1236  mutt_format_s(tmp, sizeof(tmp), prec, mutt_get_name(cc));
1237  else
1238  *tmp = '\0';
1239  }
1240  else
1241  mutt_format_s(tmp, sizeof(tmp), prec, mutt_get_name(from));
1242  p = strpbrk(tmp, " %@");
1243  if (p)
1244  *p = '\0';
1245  mutt_format_s(buf, buflen, prec, tmp);
1246  break;
1247 
1248  case 'W':
1249  if (!optional)
1250  {
1251  mutt_format_s(buf, buflen, prec, e->env->organization ? e->env->organization : "");
1252  }
1253  else if (!e->env->organization)
1254  optional = false;
1255  break;
1256 
1257 #ifdef USE_NNTP
1258  case 'x':
1259  if (!optional)
1260  {
1261  mutt_format_s(buf, buflen, prec, e->env->x_comment_to ? e->env->x_comment_to : "");
1262  }
1263  else if (!e->env->x_comment_to)
1264  optional = false;
1265  break;
1266 #endif
1267 
1268  case 'X':
1269  {
1270  int count = mutt_count_body_parts(m, e);
1271 
1272  /* The recursion allows messages without depth to return 0. */
1273  if (optional)
1274  optional = (count != 0);
1275 
1276  snprintf(fmt, sizeof(fmt), "%%%sd", prec);
1277  snprintf(buf, buflen, fmt, count);
1278  break;
1279  }
1280 
1281  case 'y':
1282  if (optional)
1283  optional = (e->env->x_label != NULL);
1284 
1285  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_LABEL);
1286  mutt_format_s(buf + colorlen, buflen - colorlen, prec, NONULL(e->env->x_label));
1287  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1288  break;
1289 
1290  case 'Y':
1291  {
1292  bool label = true;
1293  if (e->env->x_label)
1294  {
1295  struct Email *e_tmp = NULL;
1296  if (flags & MUTT_FORMAT_TREE && (e->thread->prev && e->thread->prev->message &&
1297  e->thread->prev->message->env->x_label))
1298  {
1299  e_tmp = e->thread->prev->message;
1300  }
1301  else if (flags & MUTT_FORMAT_TREE &&
1302  (e->thread->parent && e->thread->parent->message &&
1303  e->thread->parent->message->env->x_label))
1304  {
1305  e_tmp = e->thread->parent->message;
1306  }
1307  if (e_tmp && (mutt_str_strcasecmp(e->env->x_label, e_tmp->env->x_label) == 0))
1308  label = false;
1309  }
1310  else
1311  label = false;
1312 
1313  if (optional)
1314  optional = label;
1315 
1316  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_LABEL);
1317  if (label)
1318  mutt_format_s(buf + colorlen, buflen - colorlen, prec, NONULL(e->env->x_label));
1319  else
1320  mutt_format_s(buf + colorlen, buflen - colorlen, prec, "");
1321  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1322  break;
1323  }
1324 
1325  case 'z':
1326  if (src[0] == 's') /* status: deleted/new/old/replied */
1327  {
1328  const char *ch = NULL;
1329  if (e->deleted)
1330  ch = get_nth_wchar(C_FlagChars, FLAG_CHAR_DELETED);
1331  else if (e->attach_del)
1332  ch = get_nth_wchar(C_FlagChars, FLAG_CHAR_DELETED_ATTACH);
1333  else if (threads && thread_is_new(ctx, e))
1334  ch = get_nth_wchar(C_FlagChars, FLAG_CHAR_NEW_THREAD);
1335  else if (threads && thread_is_old(ctx, e))
1336  ch = get_nth_wchar(C_FlagChars, FLAG_CHAR_OLD_THREAD);
1337  else if (e->read && (ctx && (ctx->msg_not_read_yet != e->msgno)))
1338  {
1339  if (e->replied)
1340  ch = get_nth_wchar(C_FlagChars, FLAG_CHAR_REPLIED);
1341  else
1342  ch = get_nth_wchar(C_FlagChars, FLAG_CHAR_ZEMPTY);
1343  }
1344  else
1345  {
1346  if (e->old)
1347  ch = get_nth_wchar(C_FlagChars, FLAG_CHAR_OLD);
1348  else
1349  ch = get_nth_wchar(C_FlagChars, FLAG_CHAR_NEW);
1350  }
1351 
1352  snprintf(tmp, sizeof(tmp), "%s", ch);
1353  src++;
1354  }
1355  else if (src[0] == 'c') /* crypto */
1356  {
1357  const char *ch = "";
1358  if ((WithCrypto != 0) && (e->security & SEC_GOODSIGN))
1359  ch = get_nth_wchar(C_CryptChars, FLAG_CHAR_CRYPT_GOOD_SIGN);
1360  else if ((WithCrypto != 0) && (e->security & SEC_ENCRYPT))
1361  ch = get_nth_wchar(C_CryptChars, FLAG_CHAR_CRYPT_ENCRYPTED);
1362  else if ((WithCrypto != 0) && (e->security & SEC_SIGN))
1363  ch = get_nth_wchar(C_CryptChars, FLAG_CHAR_CRYPT_SIGNED);
1364  else if (((WithCrypto & APPLICATION_PGP) != 0) && ((e->security & PGP_KEY) == PGP_KEY))
1365  {
1366  ch = get_nth_wchar(C_CryptChars, FLAG_CHAR_CRYPT_CONTAINS_KEY);
1367  }
1368  else
1369  ch = get_nth_wchar(C_CryptChars, FLAG_CHAR_CRYPT_NO_CRYPTO);
1370 
1371  snprintf(tmp, sizeof(tmp), "%s", ch);
1372  src++;
1373  }
1374  else if (src[0] == 't') /* tagged, flagged, recipient */
1375  {
1376  const char *ch = "";
1377  if (e->tagged)
1378  ch = get_nth_wchar(C_FlagChars, FLAG_CHAR_TAGGED);
1379  else if (e->flagged)
1380  ch = get_nth_wchar(C_FlagChars, FLAG_CHAR_IMPORTANT);
1381  else
1382  ch = get_nth_wchar(C_ToChars, user_is_recipient(e));
1383 
1384  snprintf(tmp, sizeof(tmp), "%s", ch);
1385  src++;
1386  }
1387  else /* fallthrough */
1388  break;
1389 
1390  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_FLAGS);
1391  mutt_format_s(buf + colorlen, buflen - colorlen, prec, tmp);
1392  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1393  break;
1394 
1395  case 'Z':
1396  {
1397  /* New/Old for threads; replied; New/Old for messages */
1398  const char *first = NULL;
1399  if (threads && thread_is_new(ctx, e))
1400  first = get_nth_wchar(C_FlagChars, FLAG_CHAR_NEW_THREAD);
1401  else if (threads && thread_is_old(ctx, e))
1402  first = get_nth_wchar(C_FlagChars, FLAG_CHAR_OLD_THREAD);
1403  else if (e->read && (ctx && (ctx->msg_not_read_yet != e->msgno)))
1404  {
1405  if (e->replied)
1406  first = get_nth_wchar(C_FlagChars, FLAG_CHAR_REPLIED);
1407  else
1408  first = get_nth_wchar(C_FlagChars, FLAG_CHAR_ZEMPTY);
1409  }
1410  else
1411  {
1412  if (e->old)
1413  first = get_nth_wchar(C_FlagChars, FLAG_CHAR_OLD);
1414  else
1415  first = get_nth_wchar(C_FlagChars, FLAG_CHAR_NEW);
1416  }
1417 
1418  /* Marked for deletion; deleted attachments; crypto */
1419  const char *second = "";
1420  if (e->deleted)
1421  second = get_nth_wchar(C_FlagChars, FLAG_CHAR_DELETED);
1422  else if (e->attach_del)
1423  second = get_nth_wchar(C_FlagChars, FLAG_CHAR_DELETED_ATTACH);
1424  else if ((WithCrypto != 0) && (e->security & SEC_GOODSIGN))
1425  second = get_nth_wchar(C_CryptChars, FLAG_CHAR_CRYPT_GOOD_SIGN);
1426  else if ((WithCrypto != 0) && (e->security & SEC_ENCRYPT))
1427  second = get_nth_wchar(C_CryptChars, FLAG_CHAR_CRYPT_ENCRYPTED);
1428  else if ((WithCrypto != 0) && (e->security & SEC_SIGN))
1429  second = get_nth_wchar(C_CryptChars, FLAG_CHAR_CRYPT_SIGNED);
1430  else if (((WithCrypto & APPLICATION_PGP) != 0) && (e->security & PGP_KEY))
1431  second = get_nth_wchar(C_CryptChars, FLAG_CHAR_CRYPT_CONTAINS_KEY);
1432  else
1433  second = get_nth_wchar(C_CryptChars, FLAG_CHAR_CRYPT_NO_CRYPTO);
1434 
1435  /* Tagged, flagged and recipient flag */
1436  const char *third = "";
1437  if (e->tagged)
1438  third = get_nth_wchar(C_FlagChars, FLAG_CHAR_TAGGED);
1439  else if (e->flagged)
1440  third = get_nth_wchar(C_FlagChars, FLAG_CHAR_IMPORTANT);
1441  else
1442  third = get_nth_wchar(C_ToChars, user_is_recipient(e));
1443 
1444  snprintf(tmp, sizeof(tmp), "%s%s%s", first, second, third);
1445  }
1446 
1447  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_FLAGS);
1448  mutt_format_s(buf + colorlen, buflen - colorlen, prec, tmp);
1449  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1450  break;
1451 
1452  case '@':
1453  {
1454  const char *end = src;
1455  static unsigned char recurse = 0;
1456 
1457  while ((*end != '\0') && (*end != '@'))
1458  end++;
1459  if ((*end == '@') && (recurse < 20))
1460  {
1461  recurse++;
1462  mutt_str_substr_copy(src, end, tmp, sizeof(tmp));
1463  mutt_expando_format(tmp, sizeof(tmp), col, cols,
1464  NONULL(mutt_idxfmt_hook(tmp, m, e)),
1465  index_format_str, data, flags);
1466  mutt_format_s_x(buf, buflen, prec, tmp, true);
1467  recurse--;
1468 
1469  src = end + 1;
1470  break;
1471  }
1472  }
1473  /* fallthrough */
1474 
1475  default:
1476  snprintf(buf, buflen, "%%%s%c", prec, op);
1477  break;
1478  }
1479 
1480  if (optional)
1481  {
1482  mutt_expando_format(buf, buflen, col, cols, if_str, index_format_str,
1483  (unsigned long) hfi, flags);
1484  }
1485  else if (flags & MUTT_FORMAT_OPTIONAL)
1486  {
1487  mutt_expando_format(buf, buflen, col, cols, else_str, index_format_str,
1488  (unsigned long) hfi, flags);
1489  }
1490 
1491  return src;
1492 }
1493 
1505 void mutt_make_string_flags(char *buf, size_t buflen, int cols, const char *s,
1506  struct Context *ctx, struct Mailbox *m,
1507  struct Email *e, MuttFormatFlags flags)
1508 {
1509  struct HdrFormatInfo hfi;
1510 
1511  hfi.email = e;
1512  hfi.ctx = ctx;
1513  hfi.mailbox = m;
1514  hfi.pager_progress = 0;
1515 
1516  mutt_expando_format(buf, buflen, 0, cols, s, index_format_str, (unsigned long) &hfi, flags);
1517 }
1518 
1528 void mutt_make_string_info(char *buf, size_t buflen, int cols, const char *s,
1529  struct HdrFormatInfo *hfi, MuttFormatFlags flags)
1530 {
1531  mutt_expando_format(buf, buflen, 0, cols, s, index_format_str, (unsigned long) hfi, flags);
1532 }
Convenience wrapper for the gui headers.
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:417
FlagChars
Index into the C_FlagChars variable ($flag_chars)
Definition: hdrline.c:67
Bcc: string.
Definition: hdrline.c:103
struct Context * ctx
Definition: hdrline.h:47
The "current" mailbox.
Definition: context.h:37
Character denoting a tagged email.
Definition: hdrline.c:69
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox&#39;s path string.
Definition: mailbox.h:192
void mutt_expando_format(char *buf, size_t buflen, size_t col, int cols, const char *src, format_t *callback, unsigned long data, MuttFormatFlags flags)
Expand expandos (x) in a string.
Definition: muttlib.c:862
Index: index number.
Definition: color.h:109
Character denoting a important (flagged) email.
Definition: hdrline.c:70
int lines
How many lines in the body of this message?
Definition: email.h:84
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:163
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
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:661
static bool user_in_addr(struct AddressList *al)
Do any of the addresses refer to the user?
Definition: hdrline.c:395
#define MUTT_FORMAT_FORCESUBJ
Print the subject even if unchanged.
Definition: format_flags.h:31
struct AddressList bcc
Email&#39;s &#39;Bcc&#39; list.
Definition: envelope.h:60
struct MuttThread * thread
Thread of Emails.
Definition: email.h:94
static bool thread_is_new(struct Context *ctx, struct Email *e)
Does the email thread contain any new emails?
Definition: hdrline.c:480
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:77
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:125
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:49
static int const char * fmt
Definition: acutest.h:488
bool mutt_is_mail_list(const struct Address *addr)
Is this the email address of a mailing list? - Implements addr_predicate_t.
Definition: hdrline.c:114
short recipient
User_is_recipient()&#39;s return value, cached.
Definition: email.h:77
struct Body * content
List of MIME parts.
Definition: email.h:90
void * mutt_hash_find(const struct Hash *table, const char *strkey)
Find the HashElem data in a Hash table element using a key.
Definition: hash.c:378
Cc: string.
Definition: hdrline.c:102
WHERE struct Hash * TagFormats
Hash table of tag-formats (tag -> format string)
Definition: globals.h:60
Character denoting a message contains a PGP key.
Definition: hdrline.c:90
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:37
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:78
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:692
struct tm mutt_date_gmtime(time_t t)
Converts calendar time to a broken-down time structure expressed in UTC timezone. ...
Definition: date.c:679
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()
Representation of a single alias to an email address.
struct MbTable * C_FromChars
Config: User-configurable index flags: to address, cc address, etc.
Definition: hdrline.c:61
#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:62
Convenience wrapper for the config headers.
static char * apply_subject_mods(struct Envelope *env)
Apply regex modifications to the subject.
Definition: hdrline.c:456
Hundreds of global variables to back the user variables.
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:309
Assorted sorting methods.
Some miscellaneous functions.
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:983
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:45
void mutt_make_string_flags(char *buf, size_t buflen, int cols, const char *s, struct Context *ctx, struct Mailbox *m, struct Email *e, MuttFormatFlags flags)
Create formatted strings using mailbox expandos.
Definition: hdrline.c:1505
struct AddressList from
Email&#39;s &#39;From&#39; list.
Definition: envelope.h:57
const char * name
Definition: pgpmicalg.c:46
struct Envelope * env
Envelope information.
Definition: email.h:89
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:72
struct Mailbox * mailbox
Definition: hdrline.h:48
struct AddressList cc
Email&#39;s &#39;Cc&#39; list.
Definition: envelope.h:59
Character denoting an email that has been read.
Definition: hdrline.c:74
static int user_is_recipient(struct Email *e)
Is the user a recipient of the message.
Definition: hdrline.c:415
bool mutt_regexlist_match(struct RegexList *rl, const char *str)
Does a string match any Regex in the list?
Definition: regex.c:190
Character denoting a thread of emails that has been read.
Definition: hdrline.c:76
Empty string.
Definition: hdrline.c:105
WHERE short C_Sort
Config: Sort method for the index.
Definition: sort.h:58
struct TagList tags
For drivers that support server tagging.
Definition: email.h:102
From: string.
Definition: hdrline.c:104
int score
Message score.
Definition: email.h:88
int msg_not_read_yet
Which msg "new" in pager, -1 if none.
Definition: context.h:45
time_t date_sent
Time when the message was sent (UTC)
Definition: email.h:81
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:1528
#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:870
Sort by email threads.
Definition: sort2.h:56
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:137
Character denoting an email that has been replied to.
Definition: hdrline.c:73
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.
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:1184
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:365
size_t num_hidden
Number of hidden messages in this view.
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:1750
static bool thread_is_old(struct Context *ctx, struct Email *e)
Does the email thread contain any unread emails?
Definition: hdrline.c:492
struct RegexList MailLists
List of regexes to match mailing lists.
Definition: email_globals.c:50
Character denoting a message signed with a verified key.
Definition: hdrline.c:87
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:275
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:776
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:219
GUI present the user with a selectable list.
API for encryption/signing of emails.
bool collapsed
Is this message part of a collapsed thread?
Definition: email.h:73
struct RegexList SubscribedLists
List of regexes to match subscribed mailing lists.
Definition: email_globals.c:52
static bool check_for_mailing_list(struct AddressList *al, const char *pfx, char *buf, int buflen)
Search list of addresses for a mailing list.
Definition: hdrline.c:148
Character denoting a message is PGP-encrypted.
Definition: hdrline.c:88
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:1414
CryptChars
Index into the C_CryptChars variable ($crypt_chars)
Definition: hdrline.c:85
unsigned int zhours
Hours away from UTC.
Definition: email.h:63
char * tree
Character string to print thread tree.
Definition: email.h:93
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
static const char * get_nth_wchar(struct MbTable *table, int index)
Extract one char from a multi-byte table.
Definition: hdrline.c:256
#define SEC_SIGN
Email is signed.
Definition: lib.h:126
Character denoting a read email, $index_format Z expando.
Definition: hdrline.c:79
#define MUTT_FORMAT_INDEX
This is a main index entry.
Definition: format_flags.h:36
Colour indicator.
Definition: mutt_menu.h:76
Index: label field.
Definition: color.h:108
char * subject
Email&#39;s subject.
Definition: envelope.h:66
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:1221
#define PGP_KEY
Definition: lib.h:146
#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
#define mutt_thread_contains_unread(ctx, e)
Definition: mutt_thread.h:60
Character denoting a deleted email.
Definition: hdrline.c:71
struct MbTable * C_FlagChars
Config: User-configurable index flags: tagged, new, etc.
Definition: hdrline.c:60
char * driver_tags_get_transformed(struct TagList *list)
Get transformed tags.
Definition: tags.c:130
To: string.
Definition: hdrline.c:101
bool deleted
Email is deleted.
Definition: email.h:45
bool replied
Email has been replied to.
Definition: email.h:54
static bool check_for_mailing_list_addr(struct AddressList *al, char *buf, int buflen)
Check an address list for a mailing list.
Definition: hdrline.c:173
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:654
WHERE char * C_DateFormat
Config: strftime format string for the d expando.
Definition: globals.h:108
FieldType
Header types.
Definition: hdrline.c:99
Character denoting an unread email.
Definition: hdrline.c:75
Character denoting a message has no cryptography information.
Definition: hdrline.c:91
#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:686
const char * pager_progress
Definition: hdrline.h:50
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:89
#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
struct RegexList UnMailLists
List of regexes to blacklist false matches in MailLists.
Definition: email_globals.c:51
bool mutt_is_subscribed_list(const struct Address *addr)
Is this the email address of a user-subscribed mailing list? - Implements addr_predicate_t.
Definition: hdrline.c:126
#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:205
#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:59
Convenience wrapper for the library headers.
struct Email * email
Definition: hdrline.h:49
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:127
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:1144
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:110
#define SORT_MASK
Mask for the sort id.
Definition: sort2.h:85
time_t received
Time when the message was placed in the mailbox.
Definition: email.h:82
Index: flags field (takes a pattern)
Definition: color.h:102
static bool first_mailing_list(char *buf, size_t buflen, struct AddressList *al)
Get the first mailing list in the list of addresses.
Definition: hdrline.c:195
WHERE bool C_SaveAddress
Config: Use sender&#39;s full address as a default save folder.
Definition: globals.h:245
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:1233
int msgno
Number displayed to the user.
Definition: email.h:86
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, unsigned long data, MuttFormatFlags flags)
Format a string for the index list - Implements format_t.
Definition: hdrline.c:554
void mutt_save_path(char *buf, size_t buflen, const struct Address *addr)
Turn an email address into a filename (for saving)
Definition: muttlib.c:794
char * mutt_str_substr_copy(const char *begin, const char *end, char *buf, size_t buflen)
Copy a sub-string into a buffer.
Definition: string.c:582
const char * mutt_get_name(const struct Address *a)
Pick the best name to display from an address.
Definition: sort.c:157
struct RegexList UnSubscribedLists
List of regexes to blacklist false matches in SubscribedLists.
Definition: email_globals.c:49
struct ReplaceList SubjectRegexList
List of regexes to tidy the view of the email&#39;s subject.
Definition: email_globals.c:53