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