NeoMutt  2021-02-05-89-gabe350
Teaching an old dog new tricks
DOXYGEN
hdrline.c File Reference
#include "config.h"
#include <locale.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "mutt/lib.h"
#include "address/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "alias/lib.h"
#include "gui/lib.h"
#include "hdrline.h"
#include "ncrypt/lib.h"
#include "context.h"
#include "format_flags.h"
#include "hook.h"
#include "maillist.h"
#include "mutt_globals.h"
#include "mutt_menu.h"
#include "mutt_parse.h"
#include "mutt_thread.h"
#include "muttlib.h"
#include "sort.h"
#include "notmuch/lib.h"
+ Include dependency graph for hdrline.c:

Go to the source code of this file.

Data Structures

struct  HdrFormatInfo
 Data passed to index_format_str() More...
 

Enumerations

enum  FlagChars {
  FLAG_CHAR_TAGGED, FLAG_CHAR_IMPORTANT, FLAG_CHAR_DELETED, FLAG_CHAR_DELETED_ATTACH,
  FLAG_CHAR_REPLIED, FLAG_CHAR_OLD, FLAG_CHAR_NEW, FLAG_CHAR_OLD_THREAD,
  FLAG_CHAR_NEW_THREAD, FLAG_CHAR_SEMPTY, FLAG_CHAR_ZEMPTY
}
 Index into the $flag_chars variable ($flag_chars) More...
 
enum  CryptChars {
  FLAG_CHAR_CRYPT_GOOD_SIGN, FLAG_CHAR_CRYPT_ENCRYPTED, FLAG_CHAR_CRYPT_SIGNED, FLAG_CHAR_CRYPT_CONTAINS_KEY,
  FLAG_CHAR_CRYPT_NO_CRYPTO
}
 Index into the $crypt_chars variable ($crypt_chars) More...
 
enum  FieldType {
  DISP_TO, DISP_CC, DISP_BCC, DISP_FROM,
  DISP_PLAIN, DISP_MAX
}
 Header types. More...
 

Functions

static size_t add_index_color (char *buf, size_t buflen, MuttFormatFlags flags, char color)
 Insert a color marker into a string. More...
 
static const char * get_nth_wchar (struct MbTable *table, int index)
 Extract one char from a multi-byte table. More...
 
static const char * make_from_prefix (enum FieldType disp)
 Create a prefix for an author field. More...
 
static void make_from (struct Envelope *env, char *buf, size_t buflen, bool do_lists, MuttFormatFlags flags)
 Generate a From: field (with optional prefix) More...
 
static void make_from_addr (struct Envelope *env, char *buf, size_t buflen, bool do_lists)
 Create a 'from' address for a reply email. More...
 
static bool user_in_addr (struct AddressList *al)
 Do any of the addresses refer to the user? More...
 
static int user_is_recipient (struct Email *e)
 Is the user a recipient of the message. More...
 
static char * apply_subject_mods (struct Envelope *env)
 Apply regex modifications to the subject. More...
 
static bool thread_is_new (struct Email *e)
 Does the email thread contain any new emails? More...
 
static bool thread_is_old (struct Email *e)
 Does the email thread contain any unread emails? More...
 
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. More...
 
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. More...
 

Variables

struct MbTableC_CryptChars
 Config: User-configurable crypto flags: signed, encrypted etc. More...
 
struct MbTableC_FlagChars
 Config: User-configurable index flags: tagged, new, etc. More...
 
struct MbTableC_FromChars
 Config: User-configurable index flags: to address, cc address, etc. More...
 
struct MbTableC_ToChars
 Config: Indicator characters for the 'To' field in the index. More...
 

Detailed Description

String processing routines to generate the mail index

Authors
  • Michael R. Elkins
  • Richard Russon
  • Ian Zimmerman
  • Pietro Cerutti

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file hdrline.c.

Enumeration Type Documentation

◆ FlagChars

enum FlagChars

Index into the $flag_chars variable ($flag_chars)

Enumerator
FLAG_CHAR_TAGGED 

Character denoting a tagged email.

FLAG_CHAR_IMPORTANT 

Character denoting a important (flagged) email.

FLAG_CHAR_DELETED 

Character denoting a deleted email.

FLAG_CHAR_DELETED_ATTACH 

Character denoting a deleted attachment.

FLAG_CHAR_REPLIED 

Character denoting an email that has been replied to.

FLAG_CHAR_OLD 

Character denoting an email that has been read.

FLAG_CHAR_NEW 

Character denoting an unread email.

FLAG_CHAR_OLD_THREAD 

Character denoting a thread of emails that has been read.

FLAG_CHAR_NEW_THREAD 

Character denoting a thread containing at least one new email.

FLAG_CHAR_SEMPTY 

Character denoting a read email, $index_format S expando.

FLAG_CHAR_ZEMPTY 

Character denoting a read email, $index_format Z expando.

Definition at line 83 of file hdrline.c.

◆ CryptChars

enum CryptChars

Index into the $crypt_chars variable ($crypt_chars)

Enumerator
FLAG_CHAR_CRYPT_GOOD_SIGN 

Character denoting a message signed with a verified key.

FLAG_CHAR_CRYPT_ENCRYPTED 

Character denoting a message is PGP-encrypted.

FLAG_CHAR_CRYPT_SIGNED 

Character denoting a message is signed.

FLAG_CHAR_CRYPT_CONTAINS_KEY 

Character denoting a message contains a PGP key.

FLAG_CHAR_CRYPT_NO_CRYPTO 

Character denoting a message has no cryptography information.

Definition at line 101 of file hdrline.c.

◆ FieldType

enum FieldType

Header types.

Strings for printing headers

Enumerator
DISP_TO 

To: string.

DISP_CC 

Cc: string.

DISP_BCC 

Bcc: string.

DISP_FROM 

From: string.

DISP_PLAIN 

Empty string.

DISP_MAX 

Definition at line 115 of file hdrline.c.

116 {
117  DISP_TO,
118  DISP_CC,
119  DISP_BCC,
120  DISP_FROM,
121  DISP_PLAIN,
122  DISP_MAX,
123 };

Function Documentation

◆ add_index_color()

static size_t add_index_color ( char *  buf,
size_t  buflen,
MuttFormatFlags  flags,
char  color 
)
static

Insert a color marker into a string.

Parameters
bufBuffer to store marker
buflenBuffer length
flagsFlags, see MuttFormatFlags
colorColor, e.g. MT_COLOR_MESSAGE
Return values
numCharacters written

The colors are stored as "magic" strings embedded in the text.

Definition at line 135 of file hdrline.c.

136 {
137  /* only add color markers if we are operating on main index entries. */
138  if (!(flags & MUTT_FORMAT_INDEX))
139  return 0;
140 
141  /* this item is going to be passed to an external filter */
142  if (flags & MUTT_FORMAT_NOFILTER)
143  return 0;
144 
145  if (color == MT_COLOR_INDEX)
146  { /* buf might be uninitialized other cases */
147  const size_t len = mutt_str_len(buf);
148  buf += len;
149  buflen -= len;
150  }
151 
152  if (buflen <= 2)
153  return 0;
154 
155  buf[0] = MUTT_SPECIAL_INDEX;
156  buf[1] = color;
157  buf[2] = '\0';
158 
159  return 2;
160 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ get_nth_wchar()

static const char* get_nth_wchar ( struct MbTable table,
int  index 
)
static

Extract one char from a multi-byte table.

Parameters
tableMulti-byte table
indexSelect this character
Return values
ptrString pointer to the character

Extract one multi-byte character from a string table. If the index is invalid, then a space character will be returned. If the character selected is '
' (Ctrl-M), then "" will be returned.

Definition at line 172 of file hdrline.c.

173 {
174  if (!table || !table->chars || (index < 0) || (index >= table->len))
175  return " ";
176 
177  if (table->chars[index][0] == '\r')
178  return "";
179 
180  return table->chars[index];
181 }
+ Here is the caller graph for this function:

◆ make_from_prefix()

static const char* make_from_prefix ( enum FieldType  disp)
static

Create a prefix for an author field.

Parameters
dispType of field
Return values
ptrPrefix string (do not free it)

If $from_chars is set, pick an appropriate character from it. If not, use the default prefix: "To", "Cc", etc

Definition at line 191 of file hdrline.c.

192 {
193  /* need 2 bytes at the end, one for the space, another for NUL */
194  static char padded[8];
195  static const char *long_prefixes[DISP_MAX] = {
196  [DISP_TO] = "To ", [DISP_CC] = "Cc ", [DISP_BCC] = "Bcc ",
197  [DISP_FROM] = "", [DISP_PLAIN] = "",
198  };
199 
200  if (!C_FromChars || !C_FromChars->chars || (C_FromChars->len == 0))
201  return long_prefixes[disp];
202 
203  const char *pchar = get_nth_wchar(C_FromChars, disp);
204  if (mutt_str_len(pchar) == 0)
205  return "";
206 
207  snprintf(padded, sizeof(padded), "%s ", pchar);
208  return padded;
209 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ make_from()

static void make_from ( struct Envelope env,
char *  buf,
size_t  buflen,
bool  do_lists,
MuttFormatFlags  flags 
)
static

Generate a From: field (with optional prefix)

Parameters
envEnvelope of the email
bufBuffer to store the result
buflenSize of the buffer
do_listsShould we check for mailing lists?
flagsFormat flags, see MuttFormatFlags

Generate the F or L field in $index_format. This is the author, or recipient of the email.

The field can optionally be prefixed by a character from $from_chars. If $from_chars is not set, the prefix will be, "To", "Cc", etc

Definition at line 225 of file hdrline.c.

227 {
228  if (!env || !buf)
229  return;
230 
231  bool me;
232  enum FieldType disp;
233  struct AddressList *name = NULL;
234 
235  me = mutt_addr_is_user(TAILQ_FIRST(&env->from));
236 
237  if (do_lists || me)
238  {
239  if (check_for_mailing_list(&env->to, make_from_prefix(DISP_TO), buf, buflen))
240  return;
241  if (check_for_mailing_list(&env->cc, make_from_prefix(DISP_CC), buf, buflen))
242  return;
243  }
244 
245  if (me && !TAILQ_EMPTY(&env->to))
246  {
247  disp = (flags & MUTT_FORMAT_PLAIN) ? DISP_PLAIN : DISP_TO;
248  name = &env->to;
249  }
250  else if (me && !TAILQ_EMPTY(&env->cc))
251  {
252  disp = DISP_CC;
253  name = &env->cc;
254  }
255  else if (me && !TAILQ_EMPTY(&env->bcc))
256  {
257  disp = DISP_BCC;
258  name = &env->bcc;
259  }
260  else if (!TAILQ_EMPTY(&env->from))
261  {
262  disp = DISP_FROM;
263  name = &env->from;
264  }
265  else
266  {
267  *buf = '\0';
268  return;
269  }
270 
271  snprintf(buf, buflen, "%s%s", make_from_prefix(disp), mutt_get_name(TAILQ_FIRST(name)));
272 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ make_from_addr()

static void make_from_addr ( struct Envelope env,
char *  buf,
size_t  buflen,
bool  do_lists 
)
static

Create a 'from' address for a reply email.

Parameters
envEnvelope of current email
bufBuffer for the result
buflenLength of buffer
do_listsIf true, check for mailing lists

Definition at line 281 of file hdrline.c.

282 {
283  if (!env || !buf)
284  return;
285 
286  bool me = mutt_addr_is_user(TAILQ_FIRST(&env->from));
287 
288  if (do_lists || me)
289  {
290  if (check_for_mailing_list_addr(&env->to, buf, buflen))
291  return;
292  if (check_for_mailing_list_addr(&env->cc, buf, buflen))
293  return;
294  }
295 
296  if (me && !TAILQ_EMPTY(&env->to))
297  snprintf(buf, buflen, "%s", TAILQ_FIRST(&env->to)->mailbox);
298  else if (me && !TAILQ_EMPTY(&env->cc))
299  snprintf(buf, buflen, "%s", TAILQ_FIRST(&env->cc)->mailbox);
300  else if (!TAILQ_EMPTY(&env->from))
301  mutt_str_copy(buf, TAILQ_FIRST(&env->from)->mailbox, buflen);
302  else
303  *buf = '\0';
304 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ user_in_addr()

static bool user_in_addr ( struct AddressList *  al)
static

Do any of the addresses refer to the user?

Parameters
alAddressList
Return values
trueIf any of the addresses match one of the user's addresses

Definition at line 311 of file hdrline.c.

312 {
313  struct Address *a = NULL;
314  TAILQ_FOREACH(a, al, entries)
315  if (mutt_addr_is_user(a))
316  return true;
317  return false;
318 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ user_is_recipient()

static int user_is_recipient ( struct Email e)
static

Is the user a recipient of the message.

Parameters
eEmail to test
Return values
0User is not in list
1User is unique recipient
2User is in the TO list
3User is in the CC list
4User is originator
5Sent to a subscribed mailinglist
6User is in the Reply-To list

Definition at line 331 of file hdrline.c.

332 {
333  if (!e || !e->env)
334  return 0;
335 
336  struct Envelope *env = e->env;
337 
338  if (!e->recip_valid)
339  {
340  e->recip_valid = true;
341 
342  if (mutt_addr_is_user(TAILQ_FIRST(&env->from)))
343  e->recipient = 4;
344  else if (user_in_addr(&env->to))
345  {
346  if (TAILQ_NEXT(TAILQ_FIRST(&env->to), entries) || !TAILQ_EMPTY(&env->cc))
347  e->recipient = 2; /* non-unique recipient */
348  else
349  e->recipient = 1; /* unique recipient */
350  }
351  else if (user_in_addr(&env->cc))
352  e->recipient = 3;
353  else if (check_for_mailing_list(&env->to, NULL, NULL, 0))
354  e->recipient = 5;
355  else if (check_for_mailing_list(&env->cc, NULL, NULL, 0))
356  e->recipient = 5;
357  else if (user_in_addr(&env->reply_to))
358  e->recipient = 6;
359  else
360  e->recipient = 0;
361  }
362 
363  return e->recipient;
364 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ apply_subject_mods()

static char* apply_subject_mods ( struct Envelope env)
static

Apply regex modifications to the subject.

Parameters
envEnvelope of email
Return values
ptrModified subject
NULLNo modification made

Definition at line 372 of file hdrline.c.

373 {
374  if (!env)
375  return NULL;
376 
378  return env->subject;
379 
380  if (!env->subject || (*env->subject == '\0'))
381  {
382  env->disp_subj = NULL;
383  return NULL;
384  }
385 
387  return env->disp_subj;
388 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ thread_is_new()

static bool thread_is_new ( struct Email e)
static

Does the email thread contain any new emails?

Parameters
eEmail
Return values
trueIf thread contains new mail

Definition at line 395 of file hdrline.c.

396 {
397  return e->collapsed && (e->num_hidden > 1) && (mutt_thread_contains_unread(e) == 1);
398 }
+ Here is the caller graph for this function:

◆ thread_is_old()

static bool thread_is_old ( struct Email e)
static

Does the email thread contain any unread emails?

Parameters
eEmail
Return values
trueIf thread contains unread mail

Definition at line 405 of file hdrline.c.

406 {
407  return e->collapsed && (e->num_hidden > 1) && (mutt_thread_contains_unread(e) == 2);
408 }
+ Here is the caller graph for this function:

◆ index_format_str()

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 
)
static

Format a string for the index list - Implements format_t.

Expando Description
%a Address of the author
%A Reply-to address (if present; otherwise: address of author)
%b Filename of the original message folder (think mailbox)
%B The list to which the email was sent, or else the folder name (b)
%C Current message number
%c Number of characters (bytes) in the body of the message
%cr Number of characters (bytes) in the message, including header
%D Date and time of message using $date_format and local timezone
%d Date and time of message using $date_format and sender's timezone
%e Current message number in thread
%E Number of messages in current thread
%Fp Like F, but plain. No contextual formatting is applied to recipient name
%F Author name, or recipient name if the message is from you
%f Sender (address + real name), either From: or Return-Path:
%Gx Individual message tag (e.g. notmuch tags/imap flags)
%g Message tags (e.g. notmuch tags/imap flags)
%H Spam attribute(s) of this message
%I Initials of author
%i Message-id of the current message
%J Message tags (if present, tree unfolded, and != parent's tags)
%K The list to which the email was sent (if any; otherwise: empty)
%L Like F, except 'lists' are displayed first
%l Number of lines in the message
%M Number of hidden messages if the thread is collapsed
%m Total number of message in the mailbox
%n Author's real name (or address if missing)
%N Message score
%O Like L, except using address instead of name
%P Progress indicator for the built-in pager (how much of the file has been displayed)
%q Newsgroup name (if compiled with NNTP support)
%R Comma separated list of Cc: recipients
%r Comma separated list of To: recipients
%S Single character status of the message (N/O/D/d/!/r/-)
%s Subject of the message
%t 'To:' field (recipients)
%T The appropriate character from the $to_chars string
%u User (login) name of the author
%v First name of the author, or the recipient if the message is from you
%W Name of organization of author ('Organization:' field)
%x 'X-Comment-To:' field (if present and compiled with NNTP support)
%X Number of MIME attachments
%y 'X-Label:' field (if present)
%Y 'X-Label:' field (if present, tree unfolded, and != parent's x-label)
%zc Message crypto flags
%zs Message status flags
%zt Message tag flags
%Z Combined message flags
%(fmt) Date/time when the message was received
%[fmt] Message date/time converted to the local time zone
%{fmt} Message date/time converted to sender's time zone

Definition at line 466 of file hdrline.c.

470 {
471  struct HdrFormatInfo *hfi = (struct HdrFormatInfo *) data;
472  char fmt[128], tmp[1024];
473  char *p = NULL, *tags = NULL;
474  bool optional = (flags & MUTT_FORMAT_OPTIONAL);
475  int threads = ((C_Sort & SORT_MASK) == SORT_THREADS);
476  int is_index = (flags & MUTT_FORMAT_INDEX);
477  size_t colorlen;
478 
479  struct Email *e = hfi->email;
480  size_t msg_in_pager = hfi->msg_in_pager;
481  struct Mailbox *m = hfi->mailbox;
482 
483  if (!e || !e->env)
484  return src;
485 
486  const struct Address *reply_to = TAILQ_FIRST(&e->env->reply_to);
487  const struct Address *from = TAILQ_FIRST(&e->env->from);
488  const struct Address *to = TAILQ_FIRST(&e->env->to);
489  const struct Address *cc = TAILQ_FIRST(&e->env->cc);
490 
491  buf[0] = '\0';
492  switch (op)
493  {
494  case 'A':
495  case 'I':
496  if (op == 'A')
497  {
498  if (reply_to && reply_to->mailbox)
499  {
500  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_AUTHOR);
501  mutt_format_s(buf + colorlen, buflen - colorlen, prec,
502  mutt_addr_for_display(reply_to));
503  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
504  break;
505  }
506  }
507  else
508  {
509  if (mutt_mb_get_initials(mutt_get_name(from), tmp, sizeof(tmp)))
510  {
511  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_AUTHOR);
512  mutt_format_s(buf + colorlen, buflen - colorlen, prec, tmp);
513  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
514  break;
515  }
516  }
517  /* fallthrough */
518 
519  case 'a':
520  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_AUTHOR);
521  if (from && from->mailbox)
522  {
523  mutt_format_s(buf + colorlen, buflen - colorlen, prec, mutt_addr_for_display(from));
524  }
525  else
526  mutt_format_s(buf + colorlen, buflen - colorlen, prec, "");
527  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
528  break;
529 
530  case 'B':
531  case 'K':
532  if (!first_mailing_list(buf, buflen, &e->env->to) &&
533  !first_mailing_list(buf, buflen, &e->env->cc))
534  {
535  buf[0] = '\0';
536  }
537  if (buf[0] != '\0')
538  {
539  mutt_str_copy(tmp, buf, sizeof(tmp));
540  mutt_format_s(buf, buflen, prec, tmp);
541  break;
542  }
543  if (op == 'K')
544  {
545  if (optional)
546  optional = false;
547  /* break if 'K' returns nothing */
548  break;
549  }
550  /* if 'B' returns nothing */
551  /* fallthrough */
552 
553  case 'b':
554  if (m)
555  {
556  p = strrchr(mailbox_path(m), '/');
557 #ifdef USE_NOTMUCH
558  if (m->type == MUTT_NOTMUCH)
559  {
560  char *rel_path = nm_email_get_folder_rel_db(m, e);
561  if (rel_path)
562  p = rel_path;
563  }
564 #endif
565 
566  if (p)
567  mutt_str_copy(buf, p + 1, buflen);
568  else
569  mutt_str_copy(buf, mailbox_path(m), buflen);
570  }
571  else
572  mutt_str_copy(buf, "(null)", buflen);
573  mutt_str_copy(tmp, buf, sizeof(tmp));
574  mutt_format_s(buf, buflen, prec, tmp);
575  break;
576 
577  case 'c':
578  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_SIZE);
579  if (src[0] == 'r')
580  {
581  mutt_str_pretty_size(tmp, sizeof(tmp), email_size(e));
582  src++;
583  }
584  else
585  {
586  mutt_str_pretty_size(tmp, sizeof(tmp), e->body->length);
587  }
588  mutt_format_s(buf + colorlen, buflen - colorlen, prec, tmp);
589  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
590  break;
591 
592  case 'C':
593  colorlen = add_index_color(fmt, sizeof(fmt), flags, MT_COLOR_INDEX_NUMBER);
594  snprintf(fmt + colorlen, sizeof(fmt) - colorlen, "%%%sd", prec);
595  add_index_color(fmt + colorlen, sizeof(fmt) - colorlen, flags, MT_COLOR_INDEX);
596  snprintf(buf, buflen, fmt, e->msgno + 1);
597  break;
598 
599  case 'd':
600  case 'D':
601  case '{':
602  case '[':
603  case '(':
604  case '<':
605  /* preprocess $date_format to handle %Z */
606  {
607  const char *cp = NULL;
608  time_t now;
609  int j = 0;
610 
611  if (optional && ((op == '[') || (op == '(')))
612  {
613  now = mutt_date_epoch();
614  struct tm tm = mutt_date_localtime(now);
615  now -= (op == '(') ? e->received : e->date_sent;
616 
617  char *is = (char *) prec;
618  bool invert = false;
619  if (*is == '>')
620  {
621  invert = true;
622  is++;
623  }
624 
625  while (*is && (*is != '?'))
626  {
627  int t = strtol(is, &is, 10);
628  /* semi-broken (assuming 30 days in all months) */
629  switch (*(is++))
630  {
631  case 'y':
632  if (t > 1)
633  {
634  t--;
635  t *= (60 * 60 * 24 * 365);
636  }
637  t += ((tm.tm_mon * 60 * 60 * 24 * 30) + (tm.tm_mday * 60 * 60 * 24) +
638  (tm.tm_hour * 60 * 60) + (tm.tm_min * 60) + tm.tm_sec);
639  break;
640 
641  case 'm':
642  if (t > 1)
643  {
644  t--;
645  t *= (60 * 60 * 24 * 30);
646  }
647  t += ((tm.tm_mday * 60 * 60 * 24) + (tm.tm_hour * 60 * 60) +
648  (tm.tm_min * 60) + tm.tm_sec);
649  break;
650 
651  case 'w':
652  if (t > 1)
653  {
654  t--;
655  t *= (60 * 60 * 24 * 7);
656  }
657  t += ((tm.tm_wday * 60 * 60 * 24) + (tm.tm_hour * 60 * 60) +
658  (tm.tm_min * 60) + tm.tm_sec);
659  break;
660 
661  case 'd':
662  if (t > 1)
663  {
664  t--;
665  t *= (60 * 60 * 24);
666  }
667  t += ((tm.tm_hour * 60 * 60) + (tm.tm_min * 60) + tm.tm_sec);
668  break;
669 
670  case 'H':
671  if (t > 1)
672  {
673  t--;
674  t *= (60 * 60);
675  }
676  t += ((tm.tm_min * 60) + tm.tm_sec);
677  break;
678 
679  case 'M':
680  if (t > 1)
681  {
682  t--;
683  t *= (60);
684  }
685  t += (tm.tm_sec);
686  break;
687 
688  default:
689  break;
690  }
691  j += t;
692  }
693 
694  if (j < 0)
695  j *= -1;
696 
697  if (((now > j) || (now < (-1 * j))) ^ invert)
698  optional = false;
699  break;
700  }
701 
702  p = buf;
703 
704  cp = ((op == 'd') || (op == 'D')) ? (NONULL(C_DateFormat)) : src;
705  bool do_locales;
706  if (*cp == '!')
707  {
708  do_locales = false;
709  cp++;
710  }
711  else
712  do_locales = true;
713 
714  size_t len = buflen - 1;
715  while ((len > 0) &&
716  ((((op == 'd') || (op == 'D')) && *cp) ||
717  ((op == '{') && (*cp != '}')) || ((op == '[') && (*cp != ']')) ||
718  ((op == '(') && (*cp != ')')) || ((op == '<') && (*cp != '>'))))
719  {
720  if (*cp == '%')
721  {
722  cp++;
723  if (((*cp == 'Z') || (*cp == 'z')) && ((op == 'd') || (op == '{')))
724  {
725  if (len >= 5)
726  {
727  sprintf(p, "%c%02u%02u", e->zoccident ? '-' : '+', e->zhours, e->zminutes);
728  p += 5;
729  len -= 5;
730  }
731  else
732  break; /* not enough space left */
733  }
734  else
735  {
736  if (len >= 2)
737  {
738  *p++ = '%';
739  *p++ = *cp;
740  len -= 2;
741  }
742  else
743  break; /* not enough space */
744  }
745  cp++;
746  }
747  else
748  {
749  *p++ = *cp++;
750  len--;
751  }
752  }
753  *p = '\0';
754 
755  struct tm tm;
756  if ((op == '[') || (op == 'D'))
758  else if (op == '(')
759  tm = mutt_date_localtime(e->received);
760  else if (op == '<')
761  {
763  }
764  else
765  {
766  /* restore sender's time zone */
767  now = e->date_sent;
768  if (e->zoccident)
769  now -= (e->zhours * 3600 + e->zminutes * 60);
770  else
771  now += (e->zhours * 3600 + e->zminutes * 60);
772  tm = mutt_date_gmtime(now);
773  }
774 
775  if (!do_locales)
776  setlocale(LC_TIME, "C");
777  strftime(tmp, sizeof(tmp), buf, &tm);
778  if (!do_locales)
779  setlocale(LC_TIME, "");
780 
781  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_DATE);
782  mutt_format_s(buf + colorlen, buflen - colorlen, prec, tmp);
783  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
784 
785  if ((len > 0) && (op != 'd') && (op != 'D')) /* Skip ending op */
786  src = cp + 1;
787  break;
788  }
789 
790  case 'e':
791  snprintf(fmt, sizeof(fmt), "%%%sd", prec);
792  snprintf(buf, buflen, fmt, mutt_messages_in_thread(m, e, MIT_POSITION));
793  break;
794 
795  case 'E':
796  if (!optional)
797  {
798  snprintf(fmt, sizeof(fmt), "%%%sd", prec);
799  snprintf(buf, buflen, fmt, mutt_messages_in_thread(m, e, MIT_NUM_MESSAGES));
800  }
801  else if (mutt_messages_in_thread(m, e, MIT_NUM_MESSAGES) <= 1)
802  optional = false;
803  break;
804 
805  case 'f':
806  tmp[0] = '\0';
807  mutt_addrlist_write(&e->env->from, tmp, sizeof(tmp), true);
808  mutt_format_s(buf, buflen, prec, tmp);
809  break;
810 
811  case 'F':
812  if (!optional)
813  {
814  const bool is_plain = (src[0] == 'p');
815  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_AUTHOR);
816  make_from(e->env, tmp, sizeof(tmp), false,
817  (is_plain ? MUTT_FORMAT_PLAIN : MUTT_FORMAT_NO_FLAGS));
818  mutt_format_s(buf + colorlen, buflen - colorlen, prec, tmp);
819  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
820 
821  if (is_plain)
822  src++;
823  }
824  else if (mutt_addr_is_user(from))
825  {
826  optional = false;
827  }
828  break;
829 
830  case 'g':
831  tags = driver_tags_get_transformed(&e->tags);
832  if (!optional)
833  {
834  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_TAGS);
835  mutt_format_s(buf + colorlen, buflen - colorlen, prec, NONULL(tags));
836  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
837  }
838  else if (!tags)
839  optional = false;
840  FREE(&tags);
841  break;
842 
843  case 'G':
844  {
845  char format[3];
846  char *tag = NULL;
847 
848  if (!optional)
849  {
850  format[0] = op;
851  format[1] = *src;
852  format[2] = '\0';
853 
854  tag = mutt_hash_find(TagFormats, format);
855  if (tag)
856  {
857  tags = driver_tags_get_transformed_for(&e->tags, tag);
858  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_TAG);
859  mutt_format_s(buf + colorlen, buflen - colorlen, prec, NONULL(tags));
860  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
861  FREE(&tags);
862  }
863  src++;
864  }
865  else
866  {
867  format[0] = op;
868  format[1] = *prec;
869  format[2] = '\0';
870 
871  tag = mutt_hash_find(TagFormats, format);
872  if (tag)
873  {
874  tags = driver_tags_get_transformed_for(&e->tags, tag);
875  if (!tags)
876  optional = false;
877  FREE(&tags);
878  }
879  }
880  break;
881  }
882 
883  case 'H':
884  /* (Hormel) spam score */
885  if (optional)
886  optional = !mutt_buffer_is_empty(&e->env->spam);
887 
888  mutt_format_s(buf, buflen, prec, mutt_buffer_string(&e->env->spam));
889  break;
890 
891  case 'i':
892  mutt_format_s(buf, buflen, prec, e->env->message_id ? e->env->message_id : "<no.id>");
893  break;
894 
895  case 'J':
896  {
897  bool have_tags = true;
898  tags = driver_tags_get_transformed(&e->tags);
899  if (tags)
900  {
901  if (flags & MUTT_FORMAT_TREE)
902  {
903  char *parent_tags = NULL;
904  if (e->thread->prev && e->thread->prev->message)
905  {
906  parent_tags = driver_tags_get_transformed(&e->thread->prev->message->tags);
907  }
908  if (!parent_tags && e->thread->parent && e->thread->parent->message)
909  {
910  parent_tags =
912  }
913  if (parent_tags && mutt_istr_equal(tags, parent_tags))
914  have_tags = false;
915  FREE(&parent_tags);
916  }
917  }
918  else
919  have_tags = false;
920 
921  if (optional)
922  optional = have_tags;
923 
924  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_TAGS);
925  if (have_tags)
926  mutt_format_s(buf + colorlen, buflen - colorlen, prec, tags);
927  else
928  mutt_format_s(buf + colorlen, buflen - colorlen, prec, "");
929  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
930  FREE(&tags);
931  break;
932  }
933 
934  case 'l':
935  if (!optional)
936  {
937  snprintf(fmt, sizeof(fmt), "%%%sd", prec);
938  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_SIZE);
939  snprintf(buf + colorlen, buflen - colorlen, fmt, (int) e->lines);
940  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
941  }
942  else if (e->lines <= 0)
943  optional = false;
944  break;
945 
946  case 'L':
947  if (!optional)
948  {
949  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_AUTHOR);
950  make_from(e->env, tmp, sizeof(tmp), true, flags);
951  mutt_format_s(buf + colorlen, buflen - colorlen, prec, tmp);
952  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
953  }
954  else if (!check_for_mailing_list(&e->env->to, NULL, NULL, 0) &&
955  !check_for_mailing_list(&e->env->cc, NULL, NULL, 0))
956  {
957  optional = false;
958  }
959  break;
960 
961  case 'm':
962  if (m)
963  {
964  snprintf(fmt, sizeof(fmt), "%%%sd", prec);
965  snprintf(buf, buflen, fmt, m->msg_count);
966  }
967  else
968  mutt_str_copy(buf, "(null)", buflen);
969  break;
970 
971  case 'n':
972  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_AUTHOR);
973  mutt_format_s(buf + colorlen, buflen - colorlen, prec, mutt_get_name(from));
974  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
975  break;
976 
977  case 'M':
978  snprintf(fmt, sizeof(fmt), "%%%sd", prec);
979  if (!optional)
980  {
981  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_COLLAPSED);
982  if (threads && is_index && e->collapsed && (e->num_hidden > 1))
983  {
984  snprintf(buf + colorlen, buflen - colorlen, fmt, e->num_hidden);
985  add_index_color(buf, buflen - colorlen, flags, MT_COLOR_INDEX);
986  }
987  else if (is_index && threads)
988  {
989  mutt_format_s(buf + colorlen, buflen - colorlen, prec, " ");
990  add_index_color(buf, buflen - colorlen, flags, MT_COLOR_INDEX);
991  }
992  else
993  *buf = '\0';
994  }
995  else
996  {
997  if (!(threads && is_index && e->collapsed && (e->num_hidden > 1)))
998  optional = false;
999  }
1000  break;
1001 
1002  case 'N':
1003  if (!optional)
1004  {
1005  snprintf(fmt, sizeof(fmt), "%%%sd", prec);
1006  snprintf(buf, buflen, fmt, e->score);
1007  }
1008  else
1009  {
1010  if (e->score == 0)
1011  optional = false;
1012  }
1013  break;
1014 
1015  case 'O':
1016  if (!optional)
1017  {
1018  make_from_addr(e->env, tmp, sizeof(tmp), true);
1019  if (!C_SaveAddress && (p = strpbrk(tmp, "%@")))
1020  *p = '\0';
1021  mutt_format_s(buf, buflen, prec, tmp);
1022  }
1023  else if (!check_for_mailing_list_addr(&e->env->to, NULL, 0) &&
1024  !check_for_mailing_list_addr(&e->env->cc, NULL, 0))
1025  {
1026  optional = false;
1027  }
1028  break;
1029 
1030  case 'P':
1031  mutt_str_copy(buf, hfi->pager_progress, buflen);
1032  break;
1033 
1034 #ifdef USE_NNTP
1035  case 'q':
1036  mutt_format_s(buf, buflen, prec, e->env->newsgroups ? e->env->newsgroups : "");
1037  break;
1038 #endif
1039 
1040  case 'r':
1041  tmp[0] = '\0';
1042  mutt_addrlist_write(&e->env->to, tmp, sizeof(tmp), true);
1043  if (optional && (tmp[0] == '\0'))
1044  optional = false;
1045  mutt_format_s(buf, buflen, prec, tmp);
1046  break;
1047 
1048  case 'R':
1049  tmp[0] = '\0';
1050  mutt_addrlist_write(&e->env->cc, tmp, sizeof(tmp), true);
1051  if (optional && (tmp[0] == '\0'))
1052  optional = false;
1053  mutt_format_s(buf, buflen, prec, tmp);
1054  break;
1055 
1056  case 's':
1057  {
1058  char *subj = NULL;
1059  if (e->env->disp_subj)
1060  subj = e->env->disp_subj;
1061  else if (!STAILQ_EMPTY(&SubjectRegexList))
1062  subj = apply_subject_mods(e->env);
1063  else
1064  subj = e->env->subject;
1065  if (flags & MUTT_FORMAT_TREE && !e->collapsed)
1066  {
1067  if (flags & MUTT_FORMAT_FORCESUBJ)
1068  {
1069  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_SUBJECT);
1070  mutt_format_s(buf + colorlen, buflen - colorlen, "", NONULL(subj));
1071  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1072  snprintf(tmp, sizeof(tmp), "%s%s", e->tree, buf);
1073  mutt_format_s_tree(buf, buflen, prec, tmp);
1074  }
1075  else
1076  mutt_format_s_tree(buf, buflen, prec, e->tree);
1077  }
1078  else
1079  {
1080  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_SUBJECT);
1081  mutt_format_s(buf + colorlen, buflen - colorlen, prec, NONULL(subj));
1082  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1083  }
1084  break;
1085  }
1086 
1087  case 'S':
1088  {
1089  const char *wch = NULL;
1090  if (e->deleted)
1092  else if (e->attach_del)
1094  else if (e->tagged)
1096  else if (e->flagged)
1098  else if (e->replied)
1100  else if (e->read && (msg_in_pager != e->msgno))
1102  else if (e->old)
1104  else
1106 
1107  snprintf(tmp, sizeof(tmp), "%s", wch);
1108  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_FLAGS);
1109  mutt_format_s(buf + colorlen, buflen - colorlen, prec, tmp);
1110  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1111  break;
1112  }
1113 
1114  case 't':
1115  tmp[0] = '\0';
1116  if (!check_for_mailing_list(&e->env->to, "To ", tmp, sizeof(tmp)) &&
1117  !check_for_mailing_list(&e->env->cc, "Cc ", tmp, sizeof(tmp)))
1118  {
1119  if (to)
1120  snprintf(tmp, sizeof(tmp), "To %s", mutt_get_name(to));
1121  else if (cc)
1122  snprintf(tmp, sizeof(tmp), "Cc %s", mutt_get_name(cc));
1123  }
1124  mutt_format_s(buf, buflen, prec, tmp);
1125  break;
1126 
1127  case 'T':
1128  {
1129  int i;
1130  snprintf(fmt, sizeof(fmt), "%%%ss", prec);
1131  snprintf(buf, buflen, fmt,
1132  (C_ToChars && ((i = user_is_recipient(e))) < C_ToChars->len) ?
1133  C_ToChars->chars[i] :
1134  " ");
1135  break;
1136  }
1137 
1138  case 'u':
1139  if (from && from->mailbox)
1140  {
1141  mutt_str_copy(tmp, mutt_addr_for_display(from), sizeof(tmp));
1142  p = strpbrk(tmp, "%@");
1143  if (p)
1144  *p = '\0';
1145  }
1146  else
1147  tmp[0] = '\0';
1148  mutt_format_s(buf, buflen, prec, tmp);
1149  break;
1150 
1151  case 'v':
1152  if (mutt_addr_is_user(from))
1153  {
1154  if (to)
1155  mutt_format_s(tmp, sizeof(tmp), prec, mutt_get_name(to));
1156  else if (cc)
1157  mutt_format_s(tmp, sizeof(tmp), prec, mutt_get_name(cc));
1158  else
1159  *tmp = '\0';
1160  }
1161  else
1162  mutt_format_s(tmp, sizeof(tmp), prec, mutt_get_name(from));
1163  p = strpbrk(tmp, " %@");
1164  if (p)
1165  *p = '\0';
1166  mutt_format_s(buf, buflen, prec, tmp);
1167  break;
1168 
1169  case 'W':
1170  if (!optional)
1171  {
1172  mutt_format_s(buf, buflen, prec, e->env->organization ? e->env->organization : "");
1173  }
1174  else if (!e->env->organization)
1175  optional = false;
1176  break;
1177 
1178 #ifdef USE_NNTP
1179  case 'x':
1180  if (!optional)
1181  {
1182  mutt_format_s(buf, buflen, prec, e->env->x_comment_to ? e->env->x_comment_to : "");
1183  }
1184  else if (!e->env->x_comment_to)
1185  optional = false;
1186  break;
1187 #endif
1188 
1189  case 'X':
1190  {
1191  int count = mutt_count_body_parts(m, e);
1192 
1193  /* The recursion allows messages without depth to return 0. */
1194  if (optional)
1195  optional = (count != 0);
1196 
1197  snprintf(fmt, sizeof(fmt), "%%%sd", prec);
1198  snprintf(buf, buflen, fmt, count);
1199  break;
1200  }
1201 
1202  case 'y':
1203  if (optional)
1204  optional = (e->env->x_label != NULL);
1205 
1206  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_LABEL);
1207  mutt_format_s(buf + colorlen, buflen - colorlen, prec, NONULL(e->env->x_label));
1208  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1209  break;
1210 
1211  case 'Y':
1212  {
1213  bool label = true;
1214  if (e->env->x_label)
1215  {
1216  struct Email *e_tmp = NULL;
1217  if (flags & MUTT_FORMAT_TREE && (e->thread->prev && e->thread->prev->message &&
1218  e->thread->prev->message->env->x_label))
1219  {
1220  e_tmp = e->thread->prev->message;
1221  }
1222  else if (flags & MUTT_FORMAT_TREE &&
1223  (e->thread->parent && e->thread->parent->message &&
1224  e->thread->parent->message->env->x_label))
1225  {
1226  e_tmp = e->thread->parent->message;
1227  }
1228  if (e_tmp && mutt_istr_equal(e->env->x_label, e_tmp->env->x_label))
1229  label = false;
1230  }
1231  else
1232  label = false;
1233 
1234  if (optional)
1235  optional = label;
1236 
1237  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_LABEL);
1238  if (label)
1239  mutt_format_s(buf + colorlen, buflen - colorlen, prec, NONULL(e->env->x_label));
1240  else
1241  mutt_format_s(buf + colorlen, buflen - colorlen, prec, "");
1242  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1243  break;
1244  }
1245 
1246  case 'z':
1247  if (src[0] == 's') /* status: deleted/new/old/replied */
1248  {
1249  const char *ch = NULL;
1250  if (e->deleted)
1252  else if (e->attach_del)
1254  else if (threads && thread_is_new(e))
1256  else if (threads && thread_is_old(e))
1258  else if (e->read && (msg_in_pager != e->msgno))
1259  {
1260  if (e->replied)
1262  else
1264  }
1265  else
1266  {
1267  if (e->old)
1269  else
1271  }
1272 
1273  snprintf(tmp, sizeof(tmp), "%s", ch);
1274  src++;
1275  }
1276  else if (src[0] == 'c') /* crypto */
1277  {
1278  const char *ch = "";
1279  if ((WithCrypto != 0) && (e->security & SEC_GOODSIGN))
1281  else if ((WithCrypto != 0) && (e->security & SEC_ENCRYPT))
1283  else if ((WithCrypto != 0) && (e->security & SEC_SIGN))
1285  else if (((WithCrypto & APPLICATION_PGP) != 0) && ((e->security & PGP_KEY) == PGP_KEY))
1286  {
1288  }
1289  else
1291 
1292  snprintf(tmp, sizeof(tmp), "%s", ch);
1293  src++;
1294  }
1295  else if (src[0] == 't') /* tagged, flagged, recipient */
1296  {
1297  const char *ch = "";
1298  if (e->tagged)
1300  else if (e->flagged)
1302  else
1304 
1305  snprintf(tmp, sizeof(tmp), "%s", ch);
1306  src++;
1307  }
1308  else /* fallthrough */
1309  break;
1310 
1311  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_FLAGS);
1312  mutt_format_s(buf + colorlen, buflen - colorlen, prec, tmp);
1313  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1314  break;
1315 
1316  case 'Z':
1317  {
1318  /* New/Old for threads; replied; New/Old for messages */
1319  const char *first = NULL;
1320  if (threads && thread_is_new(e))
1322  else if (threads && thread_is_old(e))
1324  else if (e->read && (msg_in_pager != e->msgno))
1325  {
1326  if (e->replied)
1328  else
1330  }
1331  else
1332  {
1333  if (e->old)
1335  else
1337  }
1338 
1339  /* Marked for deletion; deleted attachments; crypto */
1340  const char *second = "";
1341  if (e->deleted)
1343  else if (e->attach_del)
1345  else if ((WithCrypto != 0) && (e->security & SEC_GOODSIGN))
1347  else if ((WithCrypto != 0) && (e->security & SEC_ENCRYPT))
1349  else if ((WithCrypto != 0) && (e->security & SEC_SIGN))
1351  else if (((WithCrypto & APPLICATION_PGP) != 0) && (e->security & PGP_KEY))
1353  else
1355 
1356  /* Tagged, flagged and recipient flag */
1357  const char *third = "";
1358  if (e->tagged)
1360  else if (e->flagged)
1362  else
1364 
1365  snprintf(tmp, sizeof(tmp), "%s%s%s", first, second, third);
1366  }
1367 
1368  colorlen = add_index_color(buf, buflen, flags, MT_COLOR_INDEX_FLAGS);
1369  mutt_format_s(buf + colorlen, buflen - colorlen, prec, tmp);
1370  add_index_color(buf + colorlen, buflen - colorlen, flags, MT_COLOR_INDEX);
1371  break;
1372 
1373  case '@':
1374  {
1375  const char *end = src;
1376  static unsigned char recurse = 0;
1377 
1378  while ((*end != '\0') && (*end != '@'))
1379  end++;
1380  if ((*end == '@') && (recurse < 20))
1381  {
1382  recurse++;
1383  mutt_strn_copy(tmp, src, end - src, sizeof(tmp));
1384  mutt_expando_format(tmp, sizeof(tmp), col, cols,
1385  NONULL(mutt_idxfmt_hook(tmp, m, e)),
1386  index_format_str, data, flags);
1387  mutt_format_s_x(buf, buflen, prec, tmp, true);
1388  recurse--;
1389 
1390  src = end + 1;
1391  break;
1392  }
1393  }
1394  /* fallthrough */
1395 
1396  default:
1397  snprintf(buf, buflen, "%%%s%c", prec, op);
1398  break;
1399  }
1400 
1401  if (optional)
1402  {
1403  mutt_expando_format(buf, buflen, col, cols, if_str, index_format_str,
1404  (intptr_t) hfi, flags);
1405  }
1406  else if (flags & MUTT_FORMAT_OPTIONAL)
1407  {
1408  mutt_expando_format(buf, buflen, col, cols, else_str, index_format_str,
1409  (intptr_t) hfi, flags);
1410  }
1411 
1412  return src;
1413 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_make_string()

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.

Parameters
bufBuffer for the result
buflenBuffer length
colsNumber of screen columns (OPTIONAL)
sprintf-line format string
mMailbox
inpgrMessage shown in the pager
eEmail
flagsFlags, see MuttFormatFlags
progressPager progress string

Definition at line 1427 of file hdrline.c.

1430 {
1431  struct HdrFormatInfo hfi = { 0 };
1432 
1433  hfi.email = e;
1434  hfi.mailbox = m;
1435  hfi.msg_in_pager = inpgr;
1436  hfi.pager_progress = progress;
1437 
1438  mutt_expando_format(buf, buflen, 0, cols, s, index_format_str, (intptr_t) &hfi, flags);
1439 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ C_CryptChars

struct MbTable* C_CryptChars

Config: User-configurable crypto flags: signed, encrypted etc.

Definition at line 64 of file hdrline.c.

◆ C_FlagChars

struct MbTable* C_FlagChars

Config: User-configurable index flags: tagged, new, etc.

Definition at line 65 of file hdrline.c.

◆ C_FromChars

struct MbTable* C_FromChars

Config: User-configurable index flags: to address, cc address, etc.

Definition at line 66 of file hdrline.c.

◆ C_ToChars

struct MbTable* C_ToChars

Config: Indicator characters for the 'To' field in the index.

Definition at line 67 of file hdrline.c.

Envelope
The header of an Email.
Definition: envelope.h:54
check_for_mailing_list_addr
bool check_for_mailing_list_addr(struct AddressList *al, char *buf, int buflen)
Check an address list for a mailing list.
Definition: maillist.c:103
C_ToChars
struct MbTable * C_ToChars
Config: Indicator characters for the 'To' field in the index.
Definition: hdrline.c:67
Email::date_sent
time_t date_sent
Time when the message was sent (UTC)
Definition: email.h:82
Email::msgno
int msgno
Number displayed to the user.
Definition: email.h:87
Envelope::subject
char * subject
Email's subject.
Definition: envelope.h:66
Envelope::bcc
struct AddressList bcc
Email's 'Bcc' list.
Definition: envelope.h:60
make_from
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:225
DISP_MAX
@ DISP_MAX
Definition: hdrline.c:122
FLAG_CHAR_REPLIED
@ FLAG_CHAR_REPLIED
Character denoting an email that has been replied to.
Definition: hdrline.c:89
get_nth_wchar
static const char * get_nth_wchar(struct MbTable *table, int index)
Extract one char from a multi-byte table.
Definition: hdrline.c:172
MT_COLOR_INDEX_DATE
@ MT_COLOR_INDEX_DATE
Index: date field.
Definition: color.h:107
FLAG_CHAR_CRYPT_SIGNED
@ FLAG_CHAR_CRYPT_SIGNED
Character denoting a message is signed.
Definition: hdrline.c:105
DISP_FROM
@ DISP_FROM
From: string.
Definition: hdrline.c:120
mutt_replacelist_apply
char * mutt_replacelist_apply(struct ReplaceList *rl, char *buf, size_t buflen, const char *str)
Apply replacements to a buffer.
Definition: regex.c:353
make_from_addr
static void make_from_addr(struct Envelope *env, char *buf, size_t buflen, bool do_lists)
Create a 'from' address for a reply email.
Definition: hdrline.c:281
NONULL
#define NONULL(x)
Definition: string2.h:37
HdrFormatInfo::msg_in_pager
int msg_in_pager
Definition: hdrline.c:75
Mailbox
A mailbox.
Definition: mailbox.h:81
SORT_THREADS
@ SORT_THREADS
Sort by email threads.
Definition: sort2.h:51
nm_email_get_folder_rel_db
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:1558
Email::lines
int lines
How many lines in the body of this message?
Definition: email.h:85
Envelope::message_id
char * message_id
Message ID.
Definition: envelope.h:69
C_FromChars
struct MbTable * C_FromChars
Config: User-configurable index flags: to address, cc address, etc.
Definition: hdrline.c:66
HdrFormatInfo::mailbox
struct Mailbox * mailbox
Definition: hdrline.c:74
Envelope::organization
char * organization
Organisation header.
Definition: envelope.h:73
MT_COLOR_INDEX_LABEL
@ MT_COLOR_INDEX_LABEL
Index: label field.
Definition: color.h:108
MUTT_FORMAT_FORCESUBJ
#define MUTT_FORMAT_FORCESUBJ
Print the subject even if unchanged.
Definition: format_flags.h:31
user_in_addr
static bool user_in_addr(struct AddressList *al)
Do any of the addresses refer to the user?
Definition: hdrline.c:311
Email::thread
struct MuttThread * thread
Thread of Emails.
Definition: email.h:95
mutt_get_name
const char * mutt_get_name(const struct Address *a)
Pick the best name to display from an address.
Definition: sort.c:158
MT_COLOR_INDEX_AUTHOR
@ MT_COLOR_INDEX_AUTHOR
Index: author field (takes a pattern)
Definition: color.h:101
FLAG_CHAR_NEW_THREAD
@ FLAG_CHAR_NEW_THREAD
Character denoting a thread containing at least one new email.
Definition: hdrline.c:93
FLAG_CHAR_SEMPTY
@ FLAG_CHAR_SEMPTY
Character denoting a read email, $index_format S expando.
Definition: hdrline.c:94
email_size
size_t email_size(const struct Email *e)
compute the size of an email
Definition: email.c:117
mutt_buffer_is_empty
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
make_from_prefix
static const char * make_from_prefix(enum FieldType disp)
Create a prefix for an author field.
Definition: hdrline.c:191
SEC_ENCRYPT
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:85
DISP_CC
@ DISP_CC
Cc: string.
Definition: hdrline.c:118
SEC_SIGN
#define SEC_SIGN
Email is signed.
Definition: lib.h:86
mutt_addrlist_write
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
Envelope::x_label
char * x_label
X-Label.
Definition: envelope.h:72
Email::num_hidden
size_t num_hidden
Number of hidden messages in this view (only valid when collapsed is set)
Definition: email.h:75
TAILQ_EMPTY
#define TAILQ_EMPTY(head)
Definition: queue.h:714
TAILQ_FOREACH
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
mutt_messages_in_thread
int mutt_messages_in_thread(struct Mailbox *m, struct Email *e, enum MessageInThread mit)
Count the messages in a thread.
Definition: mutt_thread.c:1476
mutt_format_s_x
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:1211
Envelope::x_comment_to
char * x_comment_to
List of 'X-comment-to' fields.
Definition: envelope.h:78
MUTT_FORMAT_TREE
#define MUTT_FORMAT_TREE
Draw the thread tree.
Definition: format_flags.h:32
FREE
#define FREE(x)
Definition: memory.h:40
check_for_mailing_list
bool check_for_mailing_list(struct AddressList *al, const char *pfx, char *buf, int buflen)
Search list of addresses for a mailing list.
Definition: maillist.c:79
DISP_TO
@ DISP_TO
To: string.
Definition: hdrline.c:117
SORT_MASK
#define SORT_MASK
Mask for the sort id.
Definition: sort2.h:80
MT_COLOR_INDEX_NUMBER
@ MT_COLOR_INDEX_NUMBER
Index: index number.
Definition: color.h:109
STAILQ_EMPTY
#define STAILQ_EMPTY(head)
Definition: queue.h:345
MUTT_FORMAT_NO_FLAGS
#define MUTT_FORMAT_NO_FLAGS
No flags are set.
Definition: format_flags.h:30
FLAG_CHAR_TAGGED
@ FLAG_CHAR_TAGGED
Character denoting a tagged email.
Definition: hdrline.c:85
Email::recipient
short recipient
User_is_recipient()'s return value, cached.
Definition: email.h:78
MIT_NUM_MESSAGES
@ MIT_NUM_MESSAGES
Definition: mutt_thread.h:84
Email::zoccident
bool zoccident
True, if west of UTC, False if east.
Definition: email.h:65
FLAG_CHAR_DELETED
@ FLAG_CHAR_DELETED
Character denoting a deleted email.
Definition: hdrline.c:87
MT_COLOR_INDEX_TAGS
@ MT_COLOR_INDEX_TAGS
Index: tags field (g, J)
Definition: color.h:111
Email::tree
char * tree
Character string to print thread tree.
Definition: email.h:94
mutt_strn_copy
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
MuttThread::prev
struct MuttThread * prev
Previous sibling Thread.
Definition: thread.h:48
mutt_istr_equal
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:883
mutt_hash_find
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
MuttThread::parent
struct MuttThread * parent
Parent of this Thread.
Definition: thread.h:45
driver_tags_get_transformed
char * driver_tags_get_transformed(struct TagList *list)
Get transformed tags.
Definition: tags.c:132
Envelope::reply_to
struct AddressList reply_to
Email's 'reply-to'.
Definition: envelope.h:62
C_SaveAddress
WHERE bool C_SaveAddress
Config: Use sender's full address as a default save folder.
Definition: mutt_globals.h:157
Email::old
bool old
Email is seen, but unread.
Definition: email.h:50
Email::received
time_t received
Time when the message was placed in the mailbox.
Definition: email.h:83
TAILQ_FIRST
#define TAILQ_FIRST(head)
Definition: queue.h:716
MIT_POSITION
@ MIT_POSITION
Definition: mutt_thread.h:85
mutt_str_pretty_size
void mutt_str_pretty_size(char *buf, size_t buflen, size_t num)
Display an abbreviated size, like 3.4K.
Definition: muttlib.c:1663
Envelope::cc
struct AddressList cc
Email's 'Cc' list.
Definition: envelope.h:59
thread_is_new
static bool thread_is_new(struct Email *e)
Does the email thread contain any new emails?
Definition: hdrline.c:395
thread_is_old
static bool thread_is_old(struct Email *e)
Does the email thread contain any unread emails?
Definition: hdrline.c:405
Mailbox::type
enum MailboxType type
Mailbox type.
Definition: mailbox.h:105
Email::tagged
bool tagged
Email is tagged.
Definition: email.h:44
mutt_count_body_parts
int mutt_count_body_parts(struct Mailbox *m, struct Email *e)
Count the MIME Body parts.
Definition: mutt_parse.c:208
Email::zminutes
unsigned int zminutes
Minutes away from UTC.
Definition: email.h:64
Body::length
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
APPLICATION_PGP
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:97
mutt_date_localtime
struct tm mutt_date_localtime(time_t t)
Converts calendar time to a broken-down time structure expressed in user timezone.
Definition: date.c:643
MuttThread::message
struct Email * message
Email this Thread refers to.
Definition: thread.h:49
MbTable::len
int len
Number of characters.
Definition: mbtable.h:38
Mailbox::msg_count
int msg_count
Total number of messages.
Definition: mailbox.h:91
C_CryptChars
struct MbTable * C_CryptChars
Config: User-configurable crypto flags: signed, encrypted etc.
Definition: hdrline.c:64
MbTable::chars
char ** chars
The array of multibyte character strings.
Definition: mbtable.h:39
user_is_recipient
static int user_is_recipient(struct Email *e)
Is the user a recipient of the message.
Definition: hdrline.c:331
MUTT_FORMAT_INDEX
#define MUTT_FORMAT_INDEX
This is a main index entry.
Definition: format_flags.h:36
FLAG_CHAR_OLD
@ FLAG_CHAR_OLD
Character denoting an email that has been read.
Definition: hdrline.c:90
MUTT_NOTMUCH
@ MUTT_NOTMUCH
'Notmuch' (virtual) Mailbox type
Definition: mailbox.h:54
Envelope::to
struct AddressList to
Email's 'To' list.
Definition: envelope.h:58
MT_COLOR_INDEX_COLLAPSED
@ MT_COLOR_INDEX_COLLAPSED
Index: number of messages in collapsed thread.
Definition: color.h:106
Email::env
struct Envelope * env
Envelope information.
Definition: email.h:90
FLAG_CHAR_CRYPT_NO_CRYPTO
@ FLAG_CHAR_CRYPT_NO_CRYPTO
Character denoting a message has no cryptography information.
Definition: hdrline.c:107
FLAG_CHAR_NEW
@ FLAG_CHAR_NEW
Character denoting an unread email.
Definition: hdrline.c:91
Email::flagged
bool flagged
Marked important?
Definition: email.h:43
Email::zhours
unsigned int zhours
Hours away from UTC.
Definition: email.h:63
mutt_str_len
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:631
first_mailing_list
bool first_mailing_list(char *buf, size_t buflen, struct AddressList *al)
Get the first mailing list in the list of addresses.
Definition: maillist.c:125
mutt_buffer_string
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
MT_COLOR_INDEX_SIZE
@ MT_COLOR_INDEX_SIZE
Index: size field.
Definition: color.h:110
Envelope::disp_subj
char * disp_subj
Display subject (modified copy of subject)
Definition: envelope.h:68
MUTT_FORMAT_PLAIN
#define MUTT_FORMAT_PLAIN
Do not prepend DISP_TO, DISP_CC ...
Definition: format_flags.h:38
Email::security
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:39
FLAG_CHAR_CRYPT_CONTAINS_KEY
@ FLAG_CHAR_CRYPT_CONTAINS_KEY
Character denoting a message contains a PGP key.
Definition: hdrline.c:106
mutt_date_epoch
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:416
apply_subject_mods
static char * apply_subject_mods(struct Envelope *env)
Apply regex modifications to the subject.
Definition: hdrline.c:372
DISP_BCC
@ DISP_BCC
Bcc: string.
Definition: hdrline.c:119
Email::collapsed
bool collapsed
Is this message part of a collapsed thread?
Definition: email.h:73
FLAG_CHAR_ZEMPTY
@ FLAG_CHAR_ZEMPTY
Character denoting a read email, $index_format Z expando.
Definition: hdrline.c:95
MUTT_DATE_NOW
#define MUTT_DATE_NOW
Constant representing the 'current time', see: mutt_date_gmtime(), mutt_date_localtime()
Definition: date.h:39
MT_COLOR_INDEX_TAG
@ MT_COLOR_INDEX_TAG
Index: tag field (g, takes a pattern)
Definition: color.h:104
mutt_format_s
void mutt_format_s(char *buf, size_t buflen, const char *prec, const char *s)
Format a simple string.
Definition: curs_lib.c:1248
Email::score
int score
Message score.
Definition: email.h:89
MUTT_FORMAT_OPTIONAL
#define MUTT_FORMAT_OPTIONAL
Allow optional field processing.
Definition: format_flags.h:33
WithCrypto
#define WithCrypto
Definition: lib.h:123
Address::mailbox
char * mailbox
Mailbox and host address.
Definition: address.h:37
Envelope::newsgroups
char * newsgroups
List of newsgroups.
Definition: envelope.h:75
Email::deleted
bool deleted
Email is deleted.
Definition: email.h:45
mutt_format_s_tree
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:1260
Envelope::from
struct AddressList from
Email's 'From' list.
Definition: envelope.h:57
driver_tags_get_transformed_for
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:171
FLAG_CHAR_IMPORTANT
@ FLAG_CHAR_IMPORTANT
Character denoting a important (flagged) email.
Definition: hdrline.c:86
MUTT_SPECIAL_INDEX
@ MUTT_SPECIAL_INDEX
Colour indicator.
Definition: mutt_thread.h:71
MT_COLOR_INDEX
@ MT_COLOR_INDEX
Index: default colour (takes a pattern)
Definition: color.h:100
C_Sort
WHERE short C_Sort
Config: Sort method for the index.
Definition: sort.h:60
TAILQ_NEXT
#define TAILQ_NEXT(elm, field)
Definition: queue.h:825
mutt_expando_format
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:774
FLAG_CHAR_DELETED_ATTACH
@ FLAG_CHAR_DELETED_ATTACH
Character denoting a deleted attachment.
Definition: hdrline.c:88
Email::tags
struct TagList tags
For drivers that support server tagging.
Definition: email.h:109
HdrFormatInfo::pager_progress
const char * pager_progress
Definition: hdrline.c:77
C_FlagChars
struct MbTable * C_FlagChars
Config: User-configurable index flags: tagged, new, etc.
Definition: hdrline.c:65
MT_COLOR_INDEX_FLAGS
@ MT_COLOR_INDEX_FLAGS
Index: flags field (takes a pattern)
Definition: color.h:102
mutt_idxfmt_hook
const char * mutt_idxfmt_hook(const char *name, struct Mailbox *m, struct Email *e)
Get index-format-hook format string.
Definition: hook.c:867
PGP_KEY
#define PGP_KEY
Definition: lib.h:106
mutt_date_gmtime
struct tm mutt_date_gmtime(time_t t)
Converts calendar time to a broken-down time structure expressed in UTC timezone.
Definition: date.c:661
Email::recip_valid
bool recip_valid
Is_recipient is valid.
Definition: email.h:58
Envelope::spam
struct Buffer spam
Spam header.
Definition: envelope.h:80
MT_COLOR_INDEX_SUBJECT
@ MT_COLOR_INDEX_SUBJECT
Index: subject field (takes a pattern)
Definition: color.h:103
HdrFormatInfo::email
struct Email * email
Definition: hdrline.c:76
FieldType
FieldType
Header types.
Definition: hdrline.c:115
Email::attach_del
bool attach_del
Has an attachment marked for deletion.
Definition: email.h:49
mailbox_path
static const char * mailbox_path(const struct Mailbox *m)
Get the Mailbox's path string.
Definition: mailbox.h:206
TagFormats
WHERE struct HashTable * TagFormats
Hash Table of tag-formats (tag -> format string)
Definition: mutt_globals.h:59
FLAG_CHAR_CRYPT_ENCRYPTED
@ FLAG_CHAR_CRYPT_ENCRYPTED
Character denoting a message is PGP-encrypted.
Definition: hdrline.c:104
C_DateFormat
WHERE char * C_DateFormat
Config: strftime format string for the d expando.
Definition: mutt_globals.h:89
Email::replied
bool replied
Email has been replied to.
Definition: email.h:54
Email
The envelope/body of an email.
Definition: email.h:37
add_index_color
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:135
FLAG_CHAR_CRYPT_GOOD_SIGN
@ FLAG_CHAR_CRYPT_GOOD_SIGN
Character denoting a message signed with a verified key.
Definition: hdrline.c:103
MUTT_FORMAT_NOFILTER
#define MUTT_FORMAT_NOFILTER
Do not allow filtering on this pass.
Definition: format_flags.h:37
Email::read
bool read
Email is read.
Definition: email.h:51
SubjectRegexList
struct ReplaceList SubjectRegexList
List of regexes to tidy the view of the email's subject.
Definition: globals.c:53
HdrFormatInfo
Data passed to index_format_str()
Definition: hdrline.c:72
SEC_GOODSIGN
#define SEC_GOODSIGN
Email has a valid signature.
Definition: lib.h:87
mutt_mb_get_initials
bool mutt_mb_get_initials(const char *name, char *buf, size_t buflen)
Turn a name into initials.
Definition: mbyte.c:84
Address
An email address.
Definition: address.h:34
mutt_addr_is_user
bool mutt_addr_is_user(const struct Address *addr)
Does the address belong to the user.
Definition: alias.c:556
mutt_addr_for_display
const char * mutt_addr_for_display(const struct Address *a)
Convert an Address for display purposes.
Definition: address.c:986
index_format_str
static const char * index_format_str(char *buf, size_t buflen, size_t col, int cols, char op, const char *src, const char *prec, const char *if_str, const char *else_str, intptr_t data, MuttFormatFlags flags)
Format a string for the index list - Implements format_t.
Definition: hdrline.c:466
Email::body
struct Body * body
List of MIME parts.
Definition: email.h:91
mutt_thread_contains_unread
#define mutt_thread_contains_unread(e)
Definition: mutt_thread.h:91
DISP_PLAIN
@ DISP_PLAIN
Empty string.
Definition: hdrline.c:121
FLAG_CHAR_OLD_THREAD
@ FLAG_CHAR_OLD_THREAD
Character denoting a thread of emails that has been read.
Definition: hdrline.c:92
mutt_str_copy
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:716