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