more constness.
[apps/madmutt.git] / hdrline.c
index 93f3bc7..716a5df 100644 (file)
--- a/hdrline.c
+++ b/hdrline.c
@@ -1,41 +1,46 @@
 /*
+ * Copyright notice from original mutt:
  * Copyright (C) 1996-2000,2002 Michael R. Elkins <me@mutt.org>
- * 
- *     This program is free software; you can redistribute it and/or modify
- *     it under the terms of the GNU General Public License as published by
- *     the Free Software Foundation; either version 2 of the License, or
- *     (at your option) any later version.
- * 
- *     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, write to the Free Software
- *     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
- */ 
+ *
+ * This file is part of mutt-ng, see http://www.muttng.org/.
+ * It's licensed under the GNU General Public License,
+ * please see the file GPL in the top level source directory.
+ */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
 
 #include "mutt.h"
 #include "mutt_curses.h"
 #include "sort.h"
+#include "thread.h"
 #include "charset.h"
 #include "mutt_crypt.h"
 #include "mutt_idna.h"
+#include "mime.h"
+
+#include "lib/str.h"
+#include "lib/rx.h"
 
 #include <ctype.h>
 #include <stdlib.h>
 #include <string.h>
 #include <locale.h>
 
-int mutt_is_mail_list (ADDRESS *addr)
+int mutt_is_mail_list (ADDRESS * addr)
 {
-  return mutt_match_rx_list (addr->mailbox, MailLists);
+  if (!rx_list_match (UnMailLists, addr->mailbox))
+    return rx_list_match (MailLists, addr->mailbox);
+  return 0;
 }
 
-int mutt_is_subscribed_list (ADDRESS *addr)
+int mutt_is_subscribed_list (ADDRESS * addr)
 {
-  return mutt_match_rx_list (addr->mailbox, SubscribedLists);
+  if (!rx_list_match (UnMailLists, addr->mailbox)
+      && !rx_list_match (UnSubscribedLists, addr->mailbox))
+    return rx_list_match (SubscribedLists, addr->mailbox);
+  return 0;
 }
 
 /* Search for a mailing list in the list of addresses pointed to by adr.
@@ -43,14 +48,12 @@ int mutt_is_subscribed_list (ADDRESS *addr)
  * return 1.  Otherwise, simply return 0.
  */
 static int
-check_for_mailing_list (ADDRESS *adr, char *pfx, char *buf, int buflen)
+check_for_mailing_list (ADDRESS * adr, const char *pfx, char *buf, int buflen)
 {
-  for (; adr; adr = adr->next)
-  {
-    if (mutt_is_subscribed_list (adr))
-    {
+  for (; adr; adr = adr->next) {
+    if (mutt_is_subscribed_list (adr)) {
       if (pfx && buf && buflen)
-       snprintf (buf, buflen, "%s%s", pfx, mutt_get_name (adr));
+        snprintf (buf, buflen, "%s%s", pfx, mutt_get_name (adr));
       return 1;
     }
   }
@@ -61,15 +64,12 @@ check_for_mailing_list (ADDRESS *adr, char *pfx, char *buf, int buflen)
  * If one is found, print the address of the list into buf, then return 1.
  * Otherwise, simply return 0.
  */
-static int
-check_for_mailing_list_addr (ADDRESS *adr, char *buf, int buflen)
+static int check_for_mailing_list_addr (ADDRESS * adr, char *buf, int buflen)
 {
-  for (; adr; adr = adr->next)
-  {
-    if (mutt_is_subscribed_list (adr))
-    {
+  for (; adr; adr = adr->next) {
+    if (mutt_is_subscribed_list (adr)) {
       if (buf && buflen)
-       snprintf (buf, buflen, "%s", adr->mailbox);
+        snprintf (buf, buflen, "%s", adr->mailbox);
       return 1;
     }
   }
@@ -77,12 +77,10 @@ check_for_mailing_list_addr (ADDRESS *adr, char *buf, int buflen)
 }
 
 
-static int first_mailing_list (char *buf, size_t buflen, ADDRESS *a)
+static int first_mailing_list (char *buf, size_t buflen, ADDRESS * a)
 {
-  for (; a; a = a->next)
-  {
-    if (mutt_is_subscribed_list (a))
-    {
+  for (; a; a = a->next) {
+    if (mutt_is_subscribed_list (a)) {
       mutt_save_path (buf, buflen, a);
       return 1;
     }
@@ -90,14 +88,13 @@ static int first_mailing_list (char *buf, size_t buflen, ADDRESS *a)
   return 0;
 }
 
-static void make_from (ENVELOPE *hdr, char *buf, size_t len, int do_lists)
+static void make_from (ENVELOPE * hdr, char *buf, size_t len, int do_lists)
 {
   int me;
 
   me = mutt_addr_is_user (hdr->from);
 
-  if (do_lists || me)
-  {
+  if (do_lists || me) {
     if (check_for_mailing_list (hdr->to, "To ", buf, len))
       return;
     if (check_for_mailing_list (hdr->cc, "Cc ", buf, len))
@@ -114,14 +111,14 @@ static void make_from (ENVELOPE *hdr, char *buf, size_t len, int do_lists)
     *buf = 0;
 }
 
-static void make_from_addr (ENVELOPE *hdr, char *buf, size_t len, int do_lists)
+static void make_from_addr (ENVELOPE * hdr, char *buf, size_t len,
+                            int do_lists)
 {
   int me;
 
   me = mutt_addr_is_user (hdr->from);
 
-  if (do_lists || me)
-  {
+  if (do_lists || me) {
     if (check_for_mailing_list_addr (hdr->to, buf, len))
       return;
     if (check_for_mailing_list_addr (hdr->cc, buf, len))
@@ -138,7 +135,7 @@ static void make_from_addr (ENVELOPE *hdr, char *buf, size_t len, int do_lists)
     *buf = 0;
 }
 
-static int user_in_addr (ADDRESS *a)
+static int user_in_addr (ADDRESS * a)
 {
   for (; a; a = a->next)
     if (mutt_addr_is_user (a))
@@ -154,22 +151,20 @@ static int user_in_addr (ADDRESS *a)
  * 4: user is originator
  * 5: sent to a subscribed mailinglist
  */
-int mutt_user_is_recipient (HEADER *h)
+int mutt_user_is_recipient (HEADER * h)
 {
   ENVELOPE *env = h->env;
 
-  if(!h->recip_valid)
-  {
+  if (!h->recip_valid) {
     h->recip_valid = 1;
-    
+
     if (mutt_addr_is_user (env->from))
       h->recipient = 4;
-    else if (user_in_addr (env->to))
-    {
+    else if (user_in_addr (env->to)) {
       if (env->to->next || env->cc)
-       h->recipient = 2; /* non-unique recipient */
+        h->recipient = 2;       /* non-unique recipient */
       else
-       h->recipient = 1; /* unique recipient */
+        h->recipient = 1;       /* unique recipient */
     }
     else if (user_in_addr (env->cc))
       h->recipient = 3;
@@ -180,7 +175,7 @@ int mutt_user_is_recipient (HEADER *h)
     else
       h->recipient = 0;
   }
-  
+
   return h->recipient;
 }
 
@@ -212,26 +207,24 @@ int mutt_user_is_recipient (HEADER *h)
  * %u = user (login) name of author
  * %v = first name of author, unless from self
  * %W = where user is (organization)
+ * %X = number of MIME attachments
  * %y = `x-label:' field (if present)
  * %Y = `x-label:' field (if present, tree unfolded, and != parent's x-label)
  * %Z = status flags   */
 
-struct hdr_format_info
-{
+struct hdr_format_info {
   CONTEXT *ctx;
   HEADER *hdr;
 };
 
-static const char *
-hdr_format_str (char *dest,
-               size_t destlen,
-               char op,
-               const char *src,
-               const char *prefix,
-               const char *ifstring,
-               const char *elsestring,
-               unsigned long data,
-               format_flag flags)
+static const char *hdr_format_str (char *dest,
+                                   size_t destlen,
+                                   char op,
+                                   const char *src,
+                                   const char *prefix,
+                                   const char *ifstring,
+                                   const char *elsestring,
+                                   unsigned long data, format_flag flags)
 {
   struct hdr_format_info *hfi = (struct hdr_format_info *) data;
   HEADER *hdr, *htmp;
@@ -241,6 +234,7 @@ hdr_format_str (char *dest,
   int optional = (flags & M_FORMAT_OPTIONAL);
   int threads = ((Sort & SORT_MASK) == SORT_THREADS);
   int is_index = (flags & M_FORMAT_INDEX);
+
 #define THREAD_NEW (threads && hdr->collapsed && hdr->num_hidden > 1 && mutt_thread_contains_unread (ctx, hdr) == 1)
 #define THREAD_OLD (threads && hdr->collapsed && hdr->num_hidden > 1 && mutt_thread_contains_unread (ctx, hdr) == 2)
   size_t len;
@@ -249,477 +243,496 @@ hdr_format_str (char *dest,
   ctx = hfi->ctx;
 
   dest[0] = 0;
-  switch (op)
-  {
-    case 'A':
-      if(hdr->env->reply_to && hdr->env->reply_to->mailbox)
-      {
-       mutt_format_s (dest, destlen, prefix, mutt_addr_for_display (hdr->env->reply_to));
-       break;
-      }
-      /* fall through if 'A' returns nothing */
-
-    case 'a':
-      if(hdr->env->from && hdr->env->from->mailbox)
-      {
-       mutt_format_s (dest, destlen, prefix, mutt_addr_for_display (hdr->env->from));
-      }
-      else
-        dest[0] = '\0';
+  switch (op) {
+  case 'A':
+    if (hdr->env->reply_to && hdr->env->reply_to->mailbox) {
+      mutt_format_s (dest, destlen, prefix,
+                     mutt_addr_for_display (hdr->env->reply_to));
       break;
+    }
+    /* fall through if 'A' returns nothing */
 
-    case 'B':
-      if (!first_mailing_list (dest, destlen, hdr->env->to) &&
-         !first_mailing_list (dest, destlen, hdr->env->cc))
-       dest[0] = 0;
-      if (dest[0])
-      {
-       strfcpy (buf2, dest, sizeof(buf2));
-       mutt_format_s (dest, destlen, prefix, buf2);
-       break;
-      }
-      /* fall through if 'B' returns nothing */
-
-    case 'b':
-      if(ctx)
-      {
-       if ((p = strrchr (ctx->path, '/')))
-         strfcpy (dest, p + 1, destlen);
-       else
-         strfcpy (dest, ctx->path, destlen);
-      }
-      else 
-       strfcpy(dest, "(null)", destlen);
-      strfcpy (buf2, dest, sizeof(buf2));
-      mutt_format_s (dest, destlen, prefix, buf2);
-      break;
-    
-    case 'c':
-      mutt_pretty_size (buf2, sizeof (buf2), (long) hdr->content->length);
+  case 'a':
+    if (hdr->env->from && hdr->env->from->mailbox) {
+      mutt_format_s (dest, destlen, prefix,
+                     mutt_addr_for_display (hdr->env->from));
+    }
+    else
+      dest[0] = '\0';
+    break;
+
+  case 'B':
+    if (!first_mailing_list (dest, destlen, hdr->env->to) &&
+        !first_mailing_list (dest, destlen, hdr->env->cc))
+      dest[0] = 0;
+    if (dest[0]) {
+      strfcpy (buf2, dest, sizeof (buf2));
       mutt_format_s (dest, destlen, prefix, buf2);
       break;
+    }
+    /* fall through if 'B' returns nothing */
 
-    case 'C':
-      snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
-      snprintf (dest, destlen, fmt, hdr->msgno + 1);
-      break;
+  case 'b':
+    if (ctx) {
+      if ((p = strrchr (ctx->path, '/')))
+        strfcpy (dest, p + 1, destlen);
+      else
+        strfcpy (dest, ctx->path, destlen);
+    }
+    else
+      strfcpy (dest, "(null)", destlen);
+    strfcpy (buf2, dest, sizeof (buf2));
+    mutt_format_s (dest, destlen, prefix, buf2);
+    break;
+
+  case 'c':
+    mutt_pretty_size (buf2, sizeof (buf2), (long) hdr->content->length);
+    mutt_format_s (dest, destlen, prefix, buf2);
+    break;
+
+  case 'C':
+    snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
+    snprintf (dest, destlen, fmt, hdr->msgno + 1);
+    break;
+
+  case 'd':
+  case 'D':
+  case '{':
+  case '[':
+  case '(':
+  case '<':
+
+    /* preprocess $date_format to handle %Z */
+    {
+      const char *cp;
+      struct tm *tm;
+      time_t T;
 
-    case 'd':
-    case 'D':
-    case '{':
-    case '[':
-    case '(':
-    case '<':
-
-      /* preprocess $date_format to handle %Z */
-      {
-       const char *cp;
-       struct tm *tm; 
-       time_t T;
-
-       p = dest;
-
-       cp = (op == 'd' || op == 'D') ? (NONULL (DateFmt)) : src;
-       if (*cp == '!')
-       {
-         do_locales = 0;
-         cp++;
-       }
-       else
-         do_locales = 1;
-
-       len = destlen - 1;
-       while (len > 0 && (((op == 'd' || op == 'D') && *cp) ||
-                          (op == '{' && *cp != '}') || 
-                          (op == '[' && *cp != ']') ||
-                          (op == '(' && *cp != ')') ||
-                          (op == '<' && *cp != '>')))
-       {
-         if (*cp == '%')
-         {
-           cp++;
-           if ((*cp == 'Z' || *cp == 'z') && (op == 'd' || op == '{'))
-           {
-             if (len >= 5)
-             {
-               sprintf (p, "%c%02u%02u", hdr->zoccident ? '-' : '+',
-                        hdr->zhours, hdr->zminutes);
-               p += 5;
-               len -= 5;
-             }
-             else
-               break; /* not enough space left */
-           }
-           else
-           {
-             if (len >= 2)
-             {
-               *p++ = '%';
-               *p++ = *cp;
-               len -= 2;
-             }
-             else
-               break; /* not enough space */
-           }
-           cp++;
-         }
-         else
-         {
-           *p++ = *cp++;
-           len--;
-         }
-       }
-       *p = 0;
-
-       if (do_locales && Locale)
-         setlocale (LC_TIME, Locale);
-
-       if (op == '[' || op == 'D')
-         tm = localtime (&hdr->date_sent);
-       else if (op == '(')
-         tm = localtime (&hdr->received);
-       else if (op == '<')
-       {
-         T = time (NULL);
-         tm = localtime (&T);
-       }
-       else
-       {
-         /* restore sender's time zone */
-         T = hdr->date_sent;
-         if (hdr->zoccident)
-           T -= (hdr->zhours * 3600 + hdr->zminutes * 60);
-         else
-           T += (hdr->zhours * 3600 + hdr->zminutes * 60);
-         tm = gmtime (&T);
-       }
-
-       strftime (buf2, sizeof (buf2), dest, tm);
-
-       if (do_locales)
-         setlocale (LC_TIME, "C");
-
-       mutt_format_s (dest, destlen, prefix, buf2);
-       if (len > 0 && op != 'd' && op != 'D') /* Skip ending op */
-         src = cp + 1;
+      p = dest;
+
+      cp = (op == 'd' || op == 'D') ? (NONULL (DateFmt)) : src;
+      if (*cp == '!') {
+        do_locales = 0;
+        cp++;
+      }
+      else
+        do_locales = 1;
+
+      len = destlen - 1;
+      while (len > 0 && (((op == 'd' || op == 'D') && *cp) ||
+                         (op == '{' && *cp != '}') ||
+                         (op == '[' && *cp != ']') ||
+                         (op == '(' && *cp != ')') ||
+                         (op == '<' && *cp != '>'))) {
+        if (*cp == '%') {
+          cp++;
+          if ((*cp == 'Z' || *cp == 'z') && (op == 'd' || op == '{')) {
+            if (len >= 5) {
+              sprintf (p, "%c%02u%02u", hdr->zoccident ? '-' : '+',
+                       hdr->zhours, hdr->zminutes);
+              p += 5;
+              len -= 5;
+            }
+            else
+              break;            /* not enough space left */
+          }
+          else {
+            if (len >= 2) {
+              *p++ = '%';
+              *p++ = *cp;
+              len -= 2;
+            }
+            else
+              break;            /* not enough space */
+          }
+          cp++;
+        }
+        else {
+          *p++ = *cp++;
+          len--;
+        }
+      }
+      *p = 0;
+
+      if (do_locales && Locale)
+        setlocale (LC_TIME, Locale);
+
+      if (op == '[' || op == 'D')
+        tm = localtime (&hdr->date_sent);
+      else if (op == '(')
+        tm = localtime (&hdr->received);
+      else if (op == '<') {
+        T = time (NULL);
+        tm = localtime (&T);
+      }
+      else {
+        /* restore sender's time zone */
+        T = hdr->date_sent;
+        if (hdr->zoccident)
+          T -= (hdr->zhours * 3600 + hdr->zminutes * 60);
+        else
+          T += (hdr->zhours * 3600 + hdr->zminutes * 60);
+        tm = gmtime (&T);
       }
-      break;
 
-    case 'e':
-      snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
-      snprintf (dest, destlen, fmt, mutt_messages_in_thread(ctx, hdr, 1));
-      break;
+      strftime (buf2, sizeof (buf2), dest, tm);
 
-    case 'E':
-      if (!optional)
-      {
-       snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
-       snprintf (dest, destlen, fmt, mutt_messages_in_thread(ctx, hdr, 0));
-      }
-      else if (mutt_messages_in_thread(ctx, hdr, 0) <= 1)
-       optional = 0;
-      break;
+      if (do_locales)
+        setlocale (LC_TIME, "C");
 
-    case 'f':
-      buf2[0] = 0;
-      rfc822_write_address (buf2, sizeof (buf2), hdr->env->from, 1);
       mutt_format_s (dest, destlen, prefix, buf2);
-      break;
+      if (len > 0 && op != 'd' && op != 'D')    /* Skip ending op */
+        src = cp + 1;
+    }
+    break;
 
-    case 'F':
-      if (!optional)
-      {
-        make_from (hdr->env, buf2, sizeof (buf2), 0);
-       mutt_format_s (dest, destlen, prefix, buf2);
-      }
-      else if (mutt_addr_is_user (hdr->env->from))
-        optional = 0;
-      break;
+  case 'e':
+    snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
+    snprintf (dest, destlen, fmt, mutt_messages_in_thread (ctx, hdr, 1));
+    break;
+
+  case 'E':
+    if (!optional) {
+      snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
+      snprintf (dest, destlen, fmt, mutt_messages_in_thread (ctx, hdr, 0));
+    }
+    else if (mutt_messages_in_thread (ctx, hdr, 0) <= 1)
+      optional = 0;
+    break;
+
+  case 'f':
+    buf2[0] = 0;
+    rfc822_write_address (buf2, sizeof (buf2), hdr->env->from, 1);
+    mutt_format_s (dest, destlen, prefix, buf2);
+    break;
+
+  case 'F':
+    if (!optional) {
+      make_from (hdr->env, buf2, sizeof (buf2), 0);
+      mutt_format_s (dest, destlen, prefix, buf2);
+    }
+    else if (mutt_addr_is_user (hdr->env->from))
+      optional = 0;
+    break;
 
 #ifdef USE_NNTP
-    case 'g':
-      mutt_format_s (dest, destlen, prefix, hdr->env->newsgroups ? hdr->env->newsgroups : "");
-      break;
+  case 'g':
+    mutt_format_s (dest, destlen, prefix,
+                   hdr->env->newsgroups ? hdr->env->newsgroups : "");
+    break;
 #endif
 
-    case 'i':
-      mutt_format_s (dest, destlen, prefix, hdr->env->message_id ? hdr->env->message_id : "<no.id>");
-      break;
+  case 'H':
+    /* (Hormel) spam score */
+    if (optional)
+      optional = hdr->env->spam ? 1 : 0;
 
-    case 'I':
-      {
-       int iflag = FALSE;
-       int j = 0;
-
-       for (i = 0; hdr->env->from && hdr->env->from->personal &&
-                   hdr->env->from->personal[i] && j < SHORT_STRING - 1; i++)
-       {
-         if (isalpha ((int)hdr->env->from->personal[i]))
-         {
-           if (!iflag)
-           {
-             buf2[j++] = hdr->env->from->personal[i];
-             iflag = TRUE;
-           }
-         }
-         else
-           iflag = FALSE;
-       }
-
-       buf2[j] = '\0';
-      }
-      mutt_format_s (dest, destlen, prefix, buf2);
-      break;
+    if (hdr->env->spam)
+      mutt_format_s (dest, destlen, prefix, NONULL (hdr->env->spam->data));
+    else
+      mutt_format_s (dest, destlen, prefix, "");
 
-    case 'l':
-      if (!optional)
-      {
-       snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
-       snprintf (dest, destlen, fmt, (int) hdr->lines);
-      }
-      else if (hdr->lines <= 0)
-        optional = 0;
-      break;
+    break;
 
-    case 'L':
-      if (!optional)
-      {
-       make_from (hdr->env, buf2, sizeof (buf2), 1);
-       mutt_format_s (dest, destlen, prefix, buf2);
-      }
-      else if (!check_for_mailing_list (hdr->env->to, NULL, NULL, 0) &&
-              !check_for_mailing_list (hdr->env->cc, NULL, NULL, 0))
-      {
-       optional = 0;
-      }
-      break;
+  case 'i':
+    mutt_format_s (dest, destlen, prefix,
+                   hdr->env->message_id ? hdr->env->message_id : "<no.id>");
+    break;
 
-    case 'm':
-      if(ctx)
-      {
-       snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
-       snprintf (dest, destlen, fmt, ctx->msgcount);
+  case 'I':
+    {
+      int iflag = FALSE;
+      int j = 0;
+
+      for (i = 0; hdr->env->from && hdr->env->from->personal &&
+           hdr->env->from->personal[i] && j < SHORT_STRING - 1; i++) {
+        if (isalpha ((int) hdr->env->from->personal[i])) {
+          if (!iflag) {
+            buf2[j++] = hdr->env->from->personal[i];
+            iflag = TRUE;
+          }
+        }
+        else
+          iflag = FALSE;
       }
-      else
-       strfcpy(dest, "(null)", destlen);
-      break;
 
-    case 'n':
-      mutt_format_s (dest, destlen, prefix, mutt_get_name (hdr->env->from));
-      break;
+      buf2[j] = '\0';
+    }
+    mutt_format_s (dest, destlen, prefix, buf2);
+    break;
 
-    case 'N':
-      if (!optional)
-      {
-       snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
-       snprintf (dest, destlen, fmt, hdr->score);
-      }
-      else
-      {
-       if (hdr->score == 0)
-         optional = 0;
-      }
-      break;
+  case 'l':
+    if (!optional) {
+      snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
+      snprintf (dest, destlen, fmt, (int) hdr->lines);
+    }
+    else if (hdr->lines <= 0)
+      optional = 0;
+    break;
 
-    case 'O':
-      if (!optional)
-      {
-       make_from_addr (hdr->env, buf2, sizeof (buf2), 1);
-       if (!option (OPTSAVEADDRESS) && (p = strpbrk (buf2, "%@")))
-         *p = 0;
-       mutt_format_s (dest, destlen, prefix, buf2);
-      }
-      else if (!check_for_mailing_list_addr (hdr->env->to, NULL, 0) &&
-              !check_for_mailing_list_addr (hdr->env->cc, NULL, 0))
-      {
-       optional = 0;
-      }
-      break;
+  case 'L':
+    if (!optional) {
+      make_from (hdr->env, buf2, sizeof (buf2), 1);
+      mutt_format_s (dest, destlen, prefix, buf2);
+    }
+    else if (!check_for_mailing_list (hdr->env->to, NULL, NULL, 0) &&
+             !check_for_mailing_list (hdr->env->cc, NULL, NULL, 0)) {
+      optional = 0;
+    }
+    break;
 
-    case 'M':
+  case 'm':
+    if (ctx) {
       snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
-      if (!optional)
-      {
-       if (threads && is_index && hdr->collapsed && hdr->num_hidden > 1)
-         snprintf (dest, destlen, fmt, hdr->num_hidden);
-       else if (is_index && threads)
-         mutt_format_s (dest, destlen, prefix, " ");
-       else
-         *dest = '\0';
-      }
-      else
-      {
-       if (!(threads && is_index && hdr->collapsed && hdr->num_hidden > 1))
-         optional = 0;
-      }
-      break;
-
-    case 's':
-      
-      if (flags & M_FORMAT_TREE && !hdr->collapsed)
-      {
-       if (flags & M_FORMAT_FORCESUBJ)
-       {
-         mutt_format_s (dest, destlen, "", NONULL (hdr->env->subject));
-         snprintf (buf2, sizeof (buf2), "%s%s", hdr->tree, dest);
-         mutt_format_s_tree (dest, destlen, prefix, buf2);
-       }
-       else
-         mutt_format_s_tree (dest, destlen, prefix, hdr->tree);
-      }
-      else
-       mutt_format_s (dest, destlen, prefix, NONULL (hdr->env->subject));
-      break;
+      snprintf (dest, destlen, fmt, ctx->msgcount);
+    }
+    else
+      strfcpy (dest, "(null)", destlen);
+    break;
 
-    case 'S':
-      if (hdr->deleted)
-       ch = 'D';
-      else if (hdr->attach_del)
-       ch = 'd';
-      else if (hdr->tagged)
-       ch = '*';
-      else if (hdr->flagged)
-       ch = '!';
-      else if (hdr->replied)
-       ch = 'r';
-      else if (hdr->read && (ctx && ctx->msgnotreadyet != hdr->msgno))
-       ch = '-';
-      else if (hdr->old)
-       ch = 'O';
-      else
-       ch = 'N';
+  case 'n':
+    mutt_format_s (dest, destlen, prefix, mutt_get_name (hdr->env->from));
+    break;
 
-      /* FOO - this is probably unsafe, but we are not likely to have such
-        a short string passed into this routine */
-      *dest = ch;
-      *(dest + 1) = 0;
-      break;
+  case 'N':
+    if (!optional) {
+      snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
+      snprintf (dest, destlen, fmt, hdr->score);
+    }
+    else {
+      if (hdr->score == 0)
+        optional = 0;
+    }
+    break;
 
-    case 't':
-      buf2[0] = 0;
-      if (!check_for_mailing_list (hdr->env->to, "To ", buf2, sizeof (buf2)) &&
-         !check_for_mailing_list (hdr->env->cc, "Cc ", buf2, sizeof (buf2)))
-      {
-       if (hdr->env->to)
-         snprintf (buf2, sizeof (buf2), "To %s", mutt_get_name (hdr->env->to));
-       else if (hdr->env->cc)
-         snprintf (buf2, sizeof (buf2), "Cc %s", mutt_get_name (hdr->env->cc));
-      }
+  case 'O':
+    if (!optional) {
+      make_from_addr (hdr->env, buf2, sizeof (buf2), 1);
+      if (!option (OPTSAVEADDRESS) && (p = strpbrk (buf2, "%@")))
+        *p = 0;
       mutt_format_s (dest, destlen, prefix, buf2);
-      break;
+    }
+    else if (!check_for_mailing_list_addr (hdr->env->to, NULL, 0) &&
+             !check_for_mailing_list_addr (hdr->env->cc, NULL, 0)) {
+      optional = 0;
+    }
+    break;
+
+  case 'M':
+    snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
+    if (!optional) {
+      if (threads && is_index && hdr->collapsed && hdr->num_hidden > 1)
+        snprintf (dest, destlen, fmt, hdr->num_hidden);
+      else if (is_index && threads)
+        mutt_format_s (dest, destlen, prefix, " ");
+      else
+        *dest = '\0';
+    }
+    else {
+      if (!(threads && is_index && hdr->collapsed && hdr->num_hidden > 1))
+        optional = 0;
+    }
+    break;
 
-    case 'T':
-      snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
-      snprintf (dest, destlen, fmt,
-               (Tochars && ((i = mutt_user_is_recipient (hdr))) < mutt_strlen (Tochars)) ? Tochars[i] : ' ');
-      break;
+  case 's':
 
-    case 'u':
-      if (hdr->env->from && hdr->env->from->mailbox)
-      {
-       strfcpy (buf2, mutt_addr_for_display (hdr->env->from), sizeof (buf2));
-       if ((p = strpbrk (buf2, "%@")))
-         *p = 0;
+    if (flags & M_FORMAT_TREE && !hdr->collapsed) {
+      if (flags & M_FORMAT_FORCESUBJ) {
+        mutt_format_s (dest, destlen, "", NONULL (hdr->env->subject));
+        snprintf (buf2, sizeof (buf2), "%s%s", hdr->tree, dest);
+        mutt_format_s_tree (dest, destlen, prefix, buf2);
       }
       else
-       buf2[0] = 0;
-      mutt_format_s (dest, destlen, prefix, buf2);
-      break;
-
-    case 'v':
-      if (mutt_addr_is_user (hdr->env->from)) 
-      {
-       if (hdr->env->to)
-         mutt_format_s (buf2, sizeof (buf2), prefix, mutt_get_name (hdr->env->to));
-       else if (hdr->env->cc)
-         mutt_format_s (buf2, sizeof (buf2), prefix, mutt_get_name (hdr->env->cc));
-       else
-         *buf2 = 0;
-      }
+        mutt_format_s_tree (dest, destlen, prefix, hdr->tree);
+    }
+    else
+      mutt_format_s (dest, destlen, prefix, NONULL (hdr->env->subject));
+    break;
+
+  case 'S':
+    if (hdr->deleted)
+      ch = 'D';
+    else if (hdr->attach_del)
+      ch = 'd';
+    else if (hdr->tagged)
+      ch = '*';
+    else if (hdr->flagged)
+      ch = '!';
+    else if (hdr->replied)
+      ch = 'r';
+    else if (hdr->read && (ctx && ctx->msgnotreadyet != hdr->msgno))
+      ch = '-';
+    else if (hdr->old)
+      ch = 'O';
+    else
+      ch = 'N';
+
+    /* FOO - this is probably unsafe, but we are not likely to have such
+       a short string passed into this routine */
+    *dest = ch;
+    *(dest + 1) = 0;
+    break;
+
+  case 't':
+    buf2[0] = 0;
+    if (!check_for_mailing_list (hdr->env->to, "To ", buf2, sizeof (buf2)) &&
+        !check_for_mailing_list (hdr->env->cc, "Cc ", buf2, sizeof (buf2))) {
+      if (hdr->env->to)
+        snprintf (buf2, sizeof (buf2), "To %s", mutt_get_name (hdr->env->to));
+      else if (hdr->env->cc)
+        snprintf (buf2, sizeof (buf2), "Cc %s", mutt_get_name (hdr->env->cc));
+    }
+    mutt_format_s (dest, destlen, prefix, buf2);
+    break;
+
+  case 'T':
+    snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
+    snprintf (dest, destlen, fmt,
+              (Tochars
+               && ((i = mutt_user_is_recipient (hdr))) <
+               str_len (Tochars)) ? Tochars[i] : ' ');
+    break;
+
+  case 'u':
+    if (hdr->env->from && hdr->env->from->mailbox) {
+      strfcpy (buf2, mutt_addr_for_display (hdr->env->from), sizeof (buf2));
+      if ((p = strpbrk (buf2, "%@")))
+        *p = 0;
+    }
+    else
+      buf2[0] = 0;
+    mutt_format_s (dest, destlen, prefix, buf2);
+    break;
+
+  case 'v':
+    if (mutt_addr_is_user (hdr->env->from)) {
+      if (hdr->env->to)
+        mutt_format_s (buf2, sizeof (buf2), prefix,
+                       mutt_get_name (hdr->env->to));
+      else if (hdr->env->cc)
+        mutt_format_s (buf2, sizeof (buf2), prefix,
+                       mutt_get_name (hdr->env->cc));
       else
-       mutt_format_s (buf2, sizeof (buf2), prefix, mutt_get_name (hdr->env->from));
-      if ((p = strpbrk (buf2, " %@")))
-       *p = 0;
-      mutt_format_s (dest, destlen, prefix, buf2);
-      break;
-
-    case 'W':
-      if (!optional)
-       mutt_format_s (dest, destlen, prefix, hdr->env->organization ? hdr->env->organization : "");
-      else if (!hdr->env->organization)
-       optional = 0;
-      break;
-
-    case 'Z':
-    
-      ch = ' ';
-
-      if (WithCrypto && hdr->security & GOODSIGN)
-        ch = 'S';
-      else if (WithCrypto && hdr->security & ENCRYPT)
-       ch = 'P';
-      else if (WithCrypto && hdr->security & SIGN)
-        ch = 's';
-      else if ((WithCrypto & APPLICATION_PGP) && hdr->security & PGPKEY)
-        ch = 'K';
-
-      snprintf (buf2, sizeof (buf2),
-               "%c%c%c", (THREAD_NEW ? 'n' : (THREAD_OLD ? 'o' : 
-               ((hdr->read && (ctx && ctx->msgnotreadyet != hdr->msgno))
-               ? (hdr->replied ? 'r' : ' ') : (hdr->old ? 'O' : 'N')))),
-               hdr->deleted ? 'D' : (hdr->attach_del ? 'd' : ch),
-               hdr->tagged ? '*' :
-               (hdr->flagged ? '!' :
-                (Tochars && ((i = mutt_user_is_recipient (hdr)) < mutt_strlen (Tochars)) ? Tochars[i] : ' ')));
-      mutt_format_s (dest, destlen, prefix, buf2);
-      break;
+        *buf2 = 0;
+    }
+    else
+      mutt_format_s (buf2, sizeof (buf2), prefix,
+                     mutt_get_name (hdr->env->from));
+    if ((p = strpbrk (buf2, " %@")))
+      *p = 0;
+    mutt_format_s (dest, destlen, prefix, buf2);
+    break;
+
+  case 'W':
+    if (!optional)
+      mutt_format_s (dest, destlen, prefix,
+                     hdr->env->organization ? hdr->env->organization : "");
+    else if (!hdr->env->organization)
+      optional = 0;
+    break;
+
+  case 'X':
+    {
+      int count = 0;
 
-     case 'y':
-       if (optional)
-        optional = hdr->env->x_label ? 1 : 0;
-
-       mutt_format_s (dest, destlen, prefix, NONULL (hdr->env->x_label));
-       break;
-    case 'Y':
-      if (hdr->env->x_label)
-      {
-       i = 1;  /* reduce reuse recycle */
-       htmp = NULL;
-       if (flags & M_FORMAT_TREE
-           && (hdr->thread->prev && hdr->thread->prev->message
-               && hdr->thread->prev->message->env->x_label))
-         htmp = hdr->thread->prev->message;
-       else if (flags & M_FORMAT_TREE
-                && (hdr->thread->parent && hdr->thread->parent->message
-                    && hdr->thread->parent->message->env->x_label))
-         htmp = hdr->thread->parent->message;
-       if (htmp && mutt_strcasecmp (hdr->env->x_label,
-                                    htmp->env->x_label) == 0)
-         i = 0;
+      if (option (OPTCOUNTATTACH)) {
+        if (!hdr->content->parts)
+          mutt_parse_mime_message(ctx, hdr);
+        count = mutt_count_body_parts(hdr, 0);
       }
-      else
-       i = 0;
 
+      /* The recursion allows messages without depth to return 0. */
       if (optional)
-       optional = i;
+        optional = count != 0;
+      
+      snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
+      snprintf (dest, destlen, fmt, count);
+    }
+    break;
+
+  case 'Z':
+
+    ch = ' ';
+
+    if (WithCrypto && hdr->security & GOODSIGN)
+      ch = 'S';
+    else if (WithCrypto && hdr->security & ENCRYPT)
+      ch = 'P';
+    else if (WithCrypto && hdr->security & SIGN)
+      ch = 's';
+    else if ((WithCrypto & APPLICATION_PGP) && hdr->security & PGPKEY)
+      ch = 'K';
+
+    snprintf (buf2, sizeof (buf2),
+              "%c%c%c", (THREAD_NEW ? 'n' : (THREAD_OLD ? 'o' :
+                                             ((hdr->read
+                                               && (ctx
+                                                   && ctx->msgnotreadyet !=
+                                                   hdr->msgno))
+                                              ? (hdr->
+                                                 replied ? 'r' : ' ') : (hdr->
+                                                                         old ?
+                                                                         'O' :
+                                                                         'N')))),
+              hdr->deleted ? 'D' : (hdr->attach_del ? 'd' : ch),
+              hdr->tagged ? '*' : (hdr->
+                                   flagged ? '!' : (Tochars
+                                                    &&
+                                                    ((i =
+                                                      mutt_user_is_recipient
+                                                      (hdr)) <
+                                                     str_len (Tochars)) ?
+                                                    Tochars[i] : ' ')));
+    mutt_format_s (dest, destlen, prefix, buf2);
+    break;
+
+  case 'y':
+    if (optional)
+      optional = hdr->env->x_label ? 1 : 0;
+
+    mutt_format_s (dest, destlen, prefix, NONULL (hdr->env->x_label));
+    break;
+
+  case 'Y':
+    if (hdr->env->x_label) {
+      i = 1;                    /* reduce reuse recycle */
+      htmp = NULL;
+      if (flags & M_FORMAT_TREE
+          && (hdr->thread->prev && hdr->thread->prev->message
+              && hdr->thread->prev->message->env->x_label))
+        htmp = hdr->thread->prev->message;
+      else if (flags & M_FORMAT_TREE
+               && (hdr->thread->parent && hdr->thread->parent->message
+                   && hdr->thread->parent->message->env->x_label))
+        htmp = hdr->thread->parent->message;
+      if (htmp && str_casecmp (hdr->env->x_label,
+                                   htmp->env->x_label) == 0)
+        i = 0;
+    }
+    else
+      i = 0;
 
-      if (i)
-        mutt_format_s (dest, destlen, prefix, NONULL (hdr->env->x_label));
-      else
-        mutt_format_s (dest, destlen, prefix, "");
+    if (optional)
+      optional = i;
 
-      break;
+    if (i)
+      mutt_format_s (dest, destlen, prefix, NONULL (hdr->env->x_label));
+    else
+      mutt_format_s (dest, destlen, prefix, "");
 
-    default:
-      snprintf (dest, destlen, "%%%s%c", prefix, op);
-      break;
+    break;
+
+  default:
+    snprintf (dest, destlen, "%%%s%c", prefix, op);
+    break;
   }
 
   if (optional)
-    mutt_FormatString (dest, destlen, ifstring, hdr_format_str, (unsigned long) hfi, flags);
+    mutt_FormatString (dest, destlen, ifstring, hdr_format_str,
+                       (unsigned long) hfi, flags);
   else if (flags & M_FORMAT_OPTIONAL)
-    mutt_FormatString (dest, destlen, elsestring, hdr_format_str, (unsigned long) hfi, flags);
+    mutt_FormatString (dest, destlen, elsestring, hdr_format_str,
+                       (unsigned long) hfi, flags);
 
   return (src);
 #undef THREAD_NEW
@@ -727,12 +740,14 @@ hdr_format_str (char *dest,
 }
 
 void
-_mutt_make_string (char *dest, size_t destlen, const char *s, CONTEXT *ctx, HEADER *hdr, format_flag flags)
+_mutt_make_string (char *dest, size_t destlen, const char *s, CONTEXT * ctx,
+                   HEADER * hdr, format_flag flags)
 {
   struct hdr_format_info hfi;
 
   hfi.hdr = hdr;
   hfi.ctx = ctx;
 
-  mutt_FormatString (dest, destlen, s, hdr_format_str, (unsigned long) &hfi, flags);
+  mutt_FormatString (dest, destlen, s, hdr_format_str, (unsigned long) &hfi,
+                     flags);
 }