fixes bad semantics (an invalid fd is -1 not 0).
[apps/madmutt.git] / recvattach.c
index 36f4a3e..b9db799 100644 (file)
@@ -8,42 +8,24 @@
  * please see the file GPL in the top level source directory.
  */
 
-#if HAVE_CONFIG_H
-# include "config.h"
-#endif
+#include <lib-lib/lib-lib.h>
+
+#include <lib-mime/mime.h>
+#include <lib-sys/unix.h>
+
+#include <lib-ui/curses.h>
+#include <lib-ui/enter.h>
+#include <lib-ui/menu.h>
+#include <lib-mx/mx.h>
+#include <lib-crypt/crypt.h>
 
 #include "mutt.h"
-#include "mutt_curses.h"
-#include "mutt_menu.h"
-#include "rfc1524.h"
-#include "mime.h"
+#include "handler.h"
+#include "recvattach.h"
 #include "attach.h"
-#include "mapping.h"
-#include "mx.h"
 #include "copy.h"
-#include "mutt_crypt.h"
-
-#include "lib/mem.h"
-#include "lib/intl.h"
-#include "lib/str.h"
-
-#include <ctype.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/wait.h>
-#include <sys/stat.h>
-#include <string.h>
-#include <errno.h>
-
-static const char *Mailbox_is_read_only = N_("Mailbox is read-only.");
-static char LastSaveFolder[_POSIX_PATH_MAX] = "";
-
-#define CHECK_READONLY if (Context->readonly) \
-{\
-    mutt_flushinp (); \
-    mutt_error _(Mailbox_is_read_only); \
-    break; \
-}
+
+#define SW    (option(OPTMBOXPANE)?SidebarWidth:0)
 
 static struct mapping_t AttachHelp[] = {
   {N_("Exit"), OP_EXIT},
@@ -51,29 +33,9 @@ static struct mapping_t AttachHelp[] = {
   {N_("Pipe"), OP_PIPE},
   {N_("Print"), OP_PRINT},
   {N_("Help"), OP_HELP},
-  {NULL}
+  {NULL, OP_NULL}
 };
 
-int mutt_extract_path (char *filename, char *path)
-{
-  char *tmp = safe_malloc (sizeof (char) * _POSIX_PATH_MAX);
-  char *help_ptr;
-
-  help_ptr = tmp;
-
-  while (*filename != '\0') {
-    if (*filename == '/') {
-      *help_ptr++ = *filename++;
-      *help_ptr++ = '\0';
-      strcat (path, tmp);
-      help_ptr = tmp;
-    }
-    *help_ptr++ = *filename++;
-  }
-  FREE (&tmp);
-  return 0;
-}
-
 void mutt_update_tree (ATTACHPTR ** idx, short idxlen)
 {
   char buf[STRING];
@@ -82,7 +44,7 @@ void mutt_update_tree (ATTACHPTR ** idx, short idxlen)
 
   for (x = 0; x < idxlen; x++) {
     idx[x]->num = x;
-    if (2 * (idx[x]->level + 2) < sizeof (buf)) {
+    if (2 * (idx[x]->level + 2) < ssizeof (buf)) {
       if (idx[x]->level) {
         s = buf + 2 * (idx[x]->level - 1);
         *s++ = (idx[x]->content->next) ? M_TREE_LTEE : M_TREE_LLCORNER;
@@ -95,13 +57,13 @@ void mutt_update_tree (ATTACHPTR ** idx, short idxlen)
     }
 
     if (idx[x]->tree) {
-      if (mutt_strcmp (idx[x]->tree, buf) != 0)
-        str_replace (&idx[x]->tree, buf);
+      if (m_strcmp(idx[x]->tree, buf) != 0)
+        m_strreplace(&idx[x]->tree, buf);
     }
     else
-      idx[x]->tree = safe_strdup (buf);
+      idx[x]->tree = m_strdup(buf);
 
-    if (2 * (idx[x]->level + 2) < sizeof (buf) && idx[x]->level) {
+    if (2 * (idx[x]->level + 2) < ssizeof (buf) && idx[x]->level) {
       s = buf + 2 * (idx[x]->level - 1);
       *s++ = (idx[x]->content->next) ? '\005' : '\006';
       *s++ = '\006';
@@ -120,7 +82,7 @@ ATTACHPTR **mutt_gen_attach_list (BODY * m,
 
   for (; m; m = m->next) {
     if (*idxlen == *idxmax) {
-      safe_realloc (&idx, sizeof (ATTACHPTR *) * ((*idxmax) += 5));
+      p_realloc(&idx, (*idxmax) += 5);
       for (i = *idxlen; i < *idxmax; i++)
         idx[i] = NULL;
     }
@@ -129,8 +91,7 @@ ATTACHPTR **mutt_gen_attach_list (BODY * m,
         && (compose
             || (parent_type == -1
                 && ascii_strcasecmp ("alternative", m->subtype)))
-        && (!(WithCrypto & APPLICATION_PGP)
-            || !mutt_is_multipart_encrypted (m))
+        && (!mutt_is_multipart_encrypted (m))
       ) {
       idx =
         mutt_gen_attach_list (m->parts, m->type, idx, idxlen, idxmax, level,
@@ -138,7 +99,7 @@ ATTACHPTR **mutt_gen_attach_list (BODY * m,
     }
     else {
       if (!idx[*idxlen])
-        idx[*idxlen] = (ATTACHPTR *) safe_calloc (1, sizeof (ATTACHPTR));
+        idx[*idxlen] = p_new(ATTACHPTR, 1);
 
       new = idx[(*idxlen)++];
       new->content = m;
@@ -147,14 +108,12 @@ ATTACHPTR **mutt_gen_attach_list (BODY * m,
       new->level = level;
 
       /* We don't support multipart messages in the compose menu yet */
-      if (!compose && !m->collapsed &&
-          ((m->type == TYPEMULTIPART && (!(WithCrypto & APPLICATION_PGP)
-                                         || !mutt_is_multipart_encrypted (m))
-           )
-           || mutt_is_message_type (m->type, m->subtype))) {
-        idx =
-          mutt_gen_attach_list (m->parts, m->type, idx, idxlen, idxmax,
-                                level + 1, compose);
+      if (!compose && !m->collapsed
+      &&  ((m->type == TYPEMULTIPART && !mutt_is_multipart_encrypted(m))
+      ||  mutt_is_message_type(m)))
+      {
+        idx = mutt_gen_attach_list (m->parts, m->type, idx, idxlen, idxmax,
+                                    level + 1, compose);
       }
     }
   }
@@ -180,21 +139,17 @@ ATTACHPTR **mutt_gen_attach_list (BODY * m,
  * %s = size
  * %u = unlink 
  */
-const char *mutt_attach_fmt (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)
+const char *
+mutt_attach_fmt(char *dest, ssize_t destlen, char op, const char *src,
+                const char *prefix, const char *ifstr, const char *elstr,
+                anytype data, format_flag flags)
 {
   char fmt[16];
-  char tmp[SHORT_STRING];
-  char charset[SHORT_STRING];
-  ATTACHPTR *aptr = (ATTACHPTR *) data;
+  char tmp[STRING];
+  char charset[STRING];
+  ATTACHPTR *aptr = data.ptr;
   int optional = (flags & M_FORMAT_OPTIONAL);
-  size_t l;
+  ssize_t l;
 
   switch (op) {
   case 'C':
@@ -226,13 +181,13 @@ const char *mutt_attach_fmt (char *dest,
         mutt_format_s (dest, destlen, prefix, aptr->content->description);
         break;
       }
-      if (mutt_is_message_type (aptr->content->type, aptr->content->subtype)
-          && MsgFmt && aptr->content->hdr) {
-        char s[SHORT_STRING];
+      if (mutt_is_message_type(aptr->content) && MsgFmt && aptr->content->hdr)
+      {
+        char s[STRING];
 
         _mutt_make_string (s, sizeof (s), MsgFmt, NULL, aptr->content->hdr,
                            M_FORMAT_FORCESUBJ | M_FORMAT_MAKEPRINT |
-                           M_FORMAT_ARROWCURSOR);
+                           (option(OPTARROWCURSOR) ? M_FORMAT_ARROWCURSOR : 0));
         if (*s) {
           mutt_format_s (dest, destlen, prefix, s);
           break;
@@ -244,8 +199,7 @@ const char *mutt_attach_fmt (char *dest,
       }
     }
     else if (aptr->content->description ||
-             (mutt_is_message_type
-              (aptr->content->type, aptr->content->subtype)
+             (mutt_is_message_type(aptr->content)
               && MsgFmt && aptr->content->hdr))
       break;
     /* FALLS THROUGH TO 'f' */
@@ -254,7 +208,7 @@ const char *mutt_attach_fmt (char *dest,
       if (aptr->content->filename && *aptr->content->filename == '/') {
         char path[_POSIX_PATH_MAX];
 
-        strfcpy (path, aptr->content->filename, sizeof (path));
+        m_strcpy(path, sizeof(path), aptr->content->filename);
         mutt_pretty_mailbox (path);
         mutt_format_s (dest, destlen, prefix, path);
       }
@@ -298,6 +252,14 @@ const char *mutt_attach_fmt (char *dest,
       snprintf (dest, destlen, fmt, aptr->num + 1);
     }
     break;
+  case 'Q':
+    if (optional)
+      optional = aptr->content->attach_qualifies;
+    else {
+      snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
+      mutt_format_s (dest, destlen, fmt, "Q");
+    }
+    break;
   case 's':
     if (flags & M_FORMAT_STAT_FILE) {
       struct stat st;
@@ -334,22 +296,29 @@ const char *mutt_attach_fmt (char *dest,
     else if (!aptr->content->unlink)
       optional = 0;
     break;
+  case 'X':
+    if (optional)
+      optional = (aptr->content->attach_count + aptr->content->attach_qualifies) != 0;
+    else {
+      snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
+      snprintf (dest, destlen, fmt, aptr->content->attach_count + aptr->content->attach_qualifies);
+    }
+    break;
   default:
     *dest = 0;
   }
 
-  if (optional)
-    mutt_FormatString (dest, destlen, ifstring, mutt_attach_fmt, data, 0);
-  else if (flags & M_FORMAT_OPTIONAL)
-    mutt_FormatString (dest, destlen, elsestring, mutt_attach_fmt, data, 0);
-  return (src);
+  if (flags & M_FORMAT_OPTIONAL)
+    m_strformat(dest, destlen, 0, optional ? ifstr : elstr,
+                mutt_attach_fmt, data, 0);
+  return src;
 }
 
-void attach_entry (char *b, size_t blen, MUTTMENU * menu, int num)
+static void attach_entry(char *b, ssize_t blen, MUTTMENU * menu, int num)
 {
-  mutt_FormatString (b, blen, NONULL (AttachFormat), mutt_attach_fmt,
-                     (unsigned long) (((ATTACHPTR **) menu->data)[num]),
-                     M_FORMAT_ARROWCURSOR);
+    m_strformat(b, blen, COLS - SW, AttachFormat, mutt_attach_fmt,
+                ((ATTACHPTR **) menu->data)[num],
+                option(OPTARROWCURSOR) ? M_FORMAT_ARROWCURSOR : 0);
 }
 
 int mutt_tag_attach (MUTTMENU * menu, int n, int m)
@@ -361,22 +330,11 @@ int mutt_tag_attach (MUTTMENU * menu, int n, int m)
   return cur->tagged - ot;
 }
 
-int mutt_is_message_type (int type, const char *subtype)
-{
-  if (type != TYPEMESSAGE)
-    return 0;
-
-  subtype = NONULL (subtype);
-  return (ascii_strcasecmp (subtype, "rfc822") == 0
-          || ascii_strcasecmp (subtype, "news") == 0);
-}
-
 static int mutt_query_save_attachment (FILE * fp, BODY * body, HEADER * hdr,
                                        char **directory)
 {
   char *prompt;
   char buf[_POSIX_PATH_MAX], tfile[_POSIX_PATH_MAX];
-  char path[_POSIX_PATH_MAX] = "";
   int is_message;
   int append = 0;
   int rc;
@@ -384,84 +342,72 @@ static int mutt_query_save_attachment (FILE * fp, BODY * body, HEADER * hdr,
 
   if (body->filename) {
     if (directory && *directory)
-      mutt_concat_path (buf, *directory, mutt_basename (body->filename),
-                        sizeof (buf));
+      mutt_concat_path(buf, sizeof(buf), *directory,
+                       mutt_basename(body->filename));
     else
-      strfcpy (buf, body->filename, sizeof (buf));
+      m_strcpy(buf, sizeof(buf), body->filename);
   }
   else if (body->hdr &&
            body->encoding != ENCBASE64 &&
            body->encoding != ENCQUOTEDPRINTABLE &&
-           mutt_is_message_type (body->type, body->subtype))
+           mutt_is_message_type(body))
     mutt_default_save (buf, sizeof (buf), body->hdr);
   else
     buf[0] = 0;
 
   prompt = _("Save to file ('#' for last used folder): ");
   while (prompt) {
-    ret =
-      mutt_get_field (prompt, buf, sizeof (buf),
-                      M_FILE | M_CLEAR | M_LASTFOLDER);
+    static char LastSaveFolder[_POSIX_PATH_MAX] = ".";
+
+    ret = mutt_get_field(prompt, buf, sizeof (buf),
+                         M_FILE | M_CLEAR | M_LASTFOLDER);
     if (((ret != 0) && (ret != 2)) || (!buf[0] && ret != 2))
       return -1;
 
     if (ret == 2) {
       char tmpbuf[_POSIX_PATH_MAX];
 
-      snprintf (tmpbuf, sizeof (tmpbuf), "%s%s", LastSaveFolder, buf);
-      strfcpy (buf, tmpbuf, sizeof (buf));
-      ret = mutt_get_field (_("Save to file: ")
-                            , buf, sizeof (buf), M_FILE);
+      snprintf (tmpbuf, sizeof (tmpbuf), "%s/%s", LastSaveFolder, buf);
+      m_strcpy(buf, sizeof(buf), tmpbuf);
+      ret = mutt_get_field(_("Save to file: "), buf, sizeof (buf), M_FILE);
       if ((ret != 0) || (!buf[0]))
         return -1;
     }
-    else {
-      mutt_extract_path (buf, path);
-      strfcpy (LastSaveFolder, path, sizeof (LastSaveFolder));
-    }
+    m_dirname(LastSaveFolder, sizeof(LastSaveFolder), buf);
 
     prompt = NULL;
-    mutt_expand_path (buf, sizeof (buf));
+    mutt_expand_path(buf, sizeof(buf));
 
-    is_message = (fp &&
-                  body->hdr &&
+    is_message = (fp && body->hdr &&
                   body->encoding != ENCBASE64 &&
                   body->encoding != ENCQUOTEDPRINTABLE &&
-                  mutt_is_message_type (body->type, body->subtype));
+                  mutt_is_message_type(body));
 
     if (is_message) {
       struct stat st;
 
       /* check to make sure that this file is really the one the user wants */
-      if ((rc = mutt_save_confirm (buf, &st)) == 1) {
-        prompt = _("Save to file: ");
-        continue;
-      }
-      else if (rc == -1)
-        return -1;
-      strfcpy (tfile, buf, sizeof (tfile));
+      rc = mutt_save_confirm(buf, &st);
+      m_strcpy(tfile, sizeof(tfile), buf);
+    } else {
+      rc = mutt_check_overwrite(body->filename, buf, tfile, sizeof(tfile),
+                                &append, directory);
     }
-    else {
-      if ((rc =
-           mutt_check_overwrite (body->filename, buf, tfile, sizeof (tfile),
-                                 &append, directory)) == -1)
-        return -1;
-      else if (rc == 1) {
-        prompt = _("Save to file: ");
-        continue;
-      }
+    if (rc == -1)
+      return -1;
+    if (rc == 1) {
+      prompt = _("Save to file: ");
+      continue;
     }
 
     mutt_message _("Saving...");
 
-    if (mutt_save_attachment
-        (fp, body, tfile, append,
-         (hdr || !is_message) ? hdr : body->hdr) == 0) {
+    if (mutt_save_attachment(fp, body, tfile, append,
+                             (hdr || !is_message) ?  hdr : body->hdr) == 0)
+    {
       mutt_message _("Attachment saved.");
-
       return 0;
-    }
-    else {
+    } else {
       prompt = _("Save to file: ");
       continue;
     }
@@ -486,7 +432,7 @@ void mutt_save_attachment_list (FILE * fp, int tag, BODY * top, HEADER * hdr,
         if (!buf[0]) {
           int append = 0;
 
-          strfcpy (buf, NONULL (top->filename), sizeof (buf));
+          m_strcpy(buf, sizeof(buf), NONULL(top->filename));
           if (mutt_get_field (_("Save to file: "), buf, sizeof (buf),
                               M_FILE | M_CLEAR) != 0 || !buf[0])
             return;
@@ -497,18 +443,17 @@ void mutt_save_attachment_list (FILE * fp, int tag, BODY * top, HEADER * hdr,
           rc = mutt_save_attachment (fp, top, tfile, append, hdr);
           if (rc == 0 && AttachSep && (fpout = fopen (tfile, "a")) != NULL) {
             fprintf (fpout, "%s", AttachSep);
-            fclose (fpout);
+            m_fclose(&fpout);
           }
         }
         else {
           rc = mutt_save_attachment (fp, top, tfile, M_SAVE_APPEND, hdr);
           if (rc == 0 && AttachSep && (fpout = fopen (tfile, "a")) != NULL) {
             fprintf (fpout, "%s", AttachSep);
-            fclose (fpout);
+            m_fclose(&fpout);
           }
         }
-      }
-      else {
+      } else {
         if (tag && menu && top->aptr) {
           menu->oldcurrent = menu->current;
           menu->current = top->aptr->num;
@@ -527,7 +472,7 @@ void mutt_save_attachment_list (FILE * fp, int tag, BODY * top, HEADER * hdr,
       break;
   }
 
-  FREE (&directory);
+  p_delete(&directory);
 
   if (tag && menu) {
     menu->oldcurrent = menu->current;
@@ -541,34 +486,32 @@ void mutt_save_attachment_list (FILE * fp, int tag, BODY * top, HEADER * hdr,
 }
 
 static void
-mutt_query_pipe_attachment (char *command, FILE * fp, BODY * body, int filter)
+mutt_query_pipe_attachment(char *command, FILE * fp, BODY * body, int afilter)
 {
   char tfile[_POSIX_PATH_MAX];
   char warning[STRING + _POSIX_PATH_MAX];
+  int tempfd = -1;
 
-  if (filter) {
-    snprintf (warning, sizeof (warning),
-              _("WARNING!  You are about to overwrite %s, continue?"),
-              body->filename);
+  if (afilter) {
+    snprintf(warning, sizeof (warning),
+             _("WARNING!  You are about to overwrite %s, continue?"),
+             body->filename);
     if (mutt_yesorno (warning, M_NO) != M_YES) {
       CLEARLINE (LINES - 1);
       return;
     }
-    mutt_mktemp (tfile);
+    tempfd = m_tempfd(tfile, sizeof(tfile), NONULL(Tempdir), NULL);
   }
-  else
-    tfile[0] = 0;
 
-  if (mutt_pipe_attachment (fp, body, command, tfile)) {
-    if (filter) {
+  if (mutt_pipe_attachment(fp, body, command, tempfd)) {
+    if (afilter) {
       mutt_unlink (body->filename);
       mutt_rename_file (tfile, body->filename);
       mutt_update_encoding (body);
       mutt_message _("Attachment filtered.");
     }
-  }
-  else {
-    if (filter && tfile[0])
+  } else if (afilter) {
+      close(tempfd);
       mutt_unlink (tfile);
   }
 }
@@ -582,14 +525,13 @@ static void pipe_attachment (FILE * fp, BODY * b, STATE * state)
     mutt_decode_attachment (b, state);
     if (AttachSep)
       state_puts (AttachSep, state);
-  }
-  else {
+  } else {
     if ((ifp = fopen (b->filename, "r")) == NULL) {
       mutt_perror ("fopen");
       return;
     }
     mutt_copy_stream (ifp, state->fpout);
-    fclose (ifp);
+    m_fclose(&ifp);
     if (AttachSep)
       state_puts (AttachSep, state);
   }
@@ -597,75 +539,76 @@ static void pipe_attachment (FILE * fp, BODY * b, STATE * state)
 
 static void
 pipe_attachment_list (char *command, FILE * fp, int tag, BODY * top,
-                      int filter, STATE * state)
+                      int afilter, STATE * state)
 {
   for (; top; top = top->next) {
     if (!tag || top->tagged) {
-      if (!filter && !option (OPTATTACHSPLIT))
+      if (!afilter && !option (OPTATTACHSPLIT))
         pipe_attachment (fp, top, state);
       else
-        mutt_query_pipe_attachment (command, fp, top, filter);
+        mutt_query_pipe_attachment (command, fp, top, afilter);
     }
     else if (top->parts)
-      pipe_attachment_list (command, fp, tag, top->parts, filter, state);
+      pipe_attachment_list (command, fp, tag, top->parts, afilter, state);
     if (!tag)
       break;
   }
 }
 
-void mutt_pipe_attachment_list (FILE * fp, int tag, BODY * top, int filter)
+void mutt_pipe_attachment_list (FILE * fp, int tag, BODY * top, int afilter)
 {
   STATE state;
-  char buf[SHORT_STRING];
+  char buf[STRING];
   pid_t thepid;
 
   if (fp)
-    filter = 0;                 /* sanity check: we can't filter in the recv case yet */
+    afilter = 0;                 /* sanity check: we can't filter in the recv case yet */
 
-  buf[0] = 0;
-  memset (&state, 0, sizeof (STATE));
+  buf[0] = '\0';
+  p_clear(&state, 1);
 
-  if (mutt_get_field ((filter ? _("Filter through: ") : _("Pipe to: ")),
+  if (mutt_get_field ((afilter ? _("Filter through: ") : _("Pipe to: ")),
                       buf, sizeof (buf), M_CMD) != 0 || !buf[0])
     return;
 
   mutt_expand_path (buf, sizeof (buf));
 
-  if (!filter && !option (OPTATTACHSPLIT)) {
+  if (!afilter && !option (OPTATTACHSPLIT)) {
     mutt_endwin (NULL);
     thepid = mutt_create_filter (buf, &state.fpout, NULL, NULL);
-    pipe_attachment_list (buf, fp, tag, top, filter, &state);
-    fclose (state.fpout);
+    pipe_attachment_list (buf, fp, tag, top, afilter, &state);
+    m_fclose(&state.fpout);
     if (mutt_wait_filter (thepid) != 0 || option (OPTWAITKEY))
       mutt_any_key_to_continue (NULL);
+  } else {
+    pipe_attachment_list (buf, fp, tag, top, afilter, &state);
   }
-  else
-    pipe_attachment_list (buf, fp, tag, top, filter, &state);
 }
 
-static int can_print (BODY * top, int tag)
+static int can_print(BODY * top, int tag)
 {
-  char type[STRING];
-
   for (; top; top = top->next) {
-    snprintf (type, sizeof (type), "%s/%s", TYPE (top), top->subtype);
+    char type[STRING];
+    int tok = mime_which_token(top->subtype, -1);
+
+    snprintf(type, sizeof(type), "%s/%s", TYPE(top), top->subtype);
+
     if (!tag || top->tagged) {
-      if (!rfc1524_mailcap_lookup (top, type, NULL, M_PRINT)) {
-        if (ascii_strcasecmp ("text/plain", top->subtype) &&
-            ascii_strcasecmp ("application/postscript", top->subtype)) {
-          if (!mutt_can_decode (top)) {
-            mutt_error (_("I dont know how to print %s attachments!"), type);
-            return (0);
-          }
-        }
+      if (!rfc1524_mailcap_lookup(top, type, NULL, M_PRINT)
+      && !(top->type == TYPETEXT && tok == MIME_PLAIN)
+      && !(top->type == TYPEAPPLICATION && tok == MIME_POSTSCRIPT)
+      && !mutt_can_decode(top))
+      {
+        mutt_error(_("I dont know how to print %s attachments!"), type);
+        return 0;
       }
     }
     else if (top->parts)
-      return (can_print (top->parts, tag));
+      return (can_print(top->parts, tag));
     if (!tag)
       break;
   }
-  return (1);
+  return 1;
 }
 
 static void print_attachment_list (FILE * fp, int tag, BODY * top,
@@ -673,36 +616,38 @@ static void print_attachment_list (FILE * fp, int tag, BODY * top,
 {
   char type[STRING];
 
-
   for (; top; top = top->next) {
     if (!tag || top->tagged) {
+      int tok = mime_which_token(top->subtype, -1);
+
       snprintf (type, sizeof (type), "%s/%s", TYPE (top), top->subtype);
       if (!option (OPTATTACHSPLIT)
           && !rfc1524_mailcap_lookup (top, type, NULL, M_PRINT)) {
-        if (!ascii_strcasecmp ("text/plain", top->subtype)
-            || !ascii_strcasecmp ("application/postscript", top->subtype))
+        if ((top->type == TYPETEXT && tok == MIME_PLAIN)
+        ||  (top->type == TYPEAPPLICATION && tok == MIME_POSTSCRIPT)) {
           pipe_attachment (fp, top, state);
-        else if (mutt_can_decode (top)) {
+        } else
+        if (mutt_can_decode (top)) {
           /* decode and print */
 
           char newfile[_POSIX_PATH_MAX] = "";
           FILE *ifp;
+          int newfile_fd;
 
-          mutt_mktemp (newfile);
-          if (mutt_decode_save_attachment (fp, top, newfile, M_PRINTING, 0) ==
-              0) {
+          newfile_fd = m_tempfd(newfile, sizeof(newfile), NONULL(Tempdir), NULL);
+          if (mutt_decode_save_attachment (fp, top, newfile_fd, M_PRINTING) == 0) {
             if ((ifp = fopen (newfile, "r")) != NULL) {
               mutt_copy_stream (ifp, state->fpout);
-              fclose (ifp);
+              m_fclose(&ifp);
               if (AttachSep)
                 state_puts (AttachSep, state);
             }
           }
           mutt_unlink (newfile);
         }
+      } else {
+        mutt_print_attachment(fp, top);
       }
-      else
-        mutt_print_attachment (fp, top);
     }
     else if (top->parts)
       print_attachment_list (fp, tag, top->parts, state);
@@ -717,8 +662,7 @@ void mutt_print_attachment_list (FILE * fp, int tag, BODY * top)
 
   pid_t thepid;
 
-  if (query_quadoption
-      (OPT_PRINT,
+  if (query_quadoption(OPT_PRINT,
        tag ? _("Print tagged attachment(s)?") : _("Print attachment?")) !=
       M_YES)
     return;
@@ -727,10 +671,10 @@ void mutt_print_attachment_list (FILE * fp, int tag, BODY * top)
     if (!can_print (top, tag))
       return;
     mutt_endwin (NULL);
-    memset (&state, 0, sizeof (STATE));
+    p_clear(&state, 1);
     thepid = mutt_create_filter (NONULL (PrintCmd), &state.fpout, NULL, NULL);
     print_attachment_list (fp, tag, top, &state);
-    fclose (state.fpout);
+    m_fclose(&state.fpout);
     if (mutt_wait_filter (thepid) != 0 || option (OPTWAITKEY))
       mutt_any_key_to_continue (NULL);
   }
@@ -738,7 +682,7 @@ void mutt_print_attachment_list (FILE * fp, int tag, BODY * top)
     print_attachment_list (fp, tag, top, &state);
 }
 
-void
+static void
 mutt_update_attach_index (BODY * cur, ATTACHPTR *** idxp,
                           short *idxlen, short *idxmax, MUTTMENU * menu)
 {
@@ -757,10 +701,8 @@ mutt_update_attach_index (BODY * cur, ATTACHPTR *** idxp,
     menu->current = menu->max - 1;
   menu_check_recenter (menu);
   menu->redraw |= REDRAW_INDEX;
-
 }
 
-
 int
 mutt_attach_display_loop (MUTTMENU * menu, int op, FILE * fp, HEADER * hdr,
                           BODY * cur, ATTACHPTR *** idxp, short *idxlen,
@@ -768,12 +710,6 @@ mutt_attach_display_loop (MUTTMENU * menu, int op, FILE * fp, HEADER * hdr,
 {
   ATTACHPTR **idx = *idxp;
 
-#if 0
-  int old_optweed = option (OPTWEED);
-
-  set_option (OPTWEED);
-#endif
-
   do {
     switch (op) {
     case OP_DISPLAY_HEADERS:
@@ -815,8 +751,7 @@ mutt_attach_display_loop (MUTTMENU * menu, int op, FILE * fp, HEADER * hdr,
       break;
       /* functions which are passed through from the pager */
     case OP_CHECK_TRADITIONAL:
-      if (!(WithCrypto & APPLICATION_PGP)
-          || (hdr && hdr->security & PGP_TRADITIONAL_CHECKED)) {
+      if (hdr && hdr->security & PGP_TRADITIONAL_CHECKED) {
         op = OP_NULL;
         break;
       }
@@ -830,10 +765,6 @@ mutt_attach_display_loop (MUTTMENU * menu, int op, FILE * fp, HEADER * hdr,
   }
   while (op != OP_NULL);
 
-#if 0
-  if (option (OPTWEED) != old_optweed)
-    toggle_option (OPTWEED);
-#endif
   return op;
 }
 
@@ -845,10 +776,9 @@ static void attach_collapse (BODY * b, short collapse, short init,
   for (; b; b = b->next) {
     i = init || b->collapsed;
     if (i && option (OPTDIGESTCOLLAPSE) && b->type == TYPEMULTIPART
-        && !ascii_strcasecmp (b->subtype, "digest"))
+        && mime_which_token(b->subtype, -1) == MIME_DIGEST)
       attach_collapse (b->parts, 1, 1, 0);
-    else if (b->type == TYPEMULTIPART
-             || mutt_is_message_type (b->type, b->subtype))
+    else if (b->type == TYPEMULTIPART || mutt_is_message_type(b))
       attach_collapse (b->parts, collapse, i, 0);
     b->collapsed = collapse;
     if (just_one)
@@ -866,27 +796,14 @@ void mutt_attach_init (BODY * b)
   }
 }
 
-static const char *Function_not_permitted =
-N_("Function not permitted in attach-message mode.");
-
-#define CHECK_ATTACH if(option(OPTATTACHMSG)) \
-                    {\
-                       mutt_flushinp (); \
-                       mutt_error _(Function_not_permitted); \
-                       break; \
-                    }
-
-
-
-
 void mutt_view_attachments (HEADER * hdr)
 {
   int secured = 0;
   int need_secured = 0;
 
-  char helpstr[SHORT_STRING];
+  char helpstr[STRING];
   MUTTMENU *menu;
-  BODY *cur;
+  BODY *cur = NULL;
   MESSAGE *msg;
   FILE *fp;
   ATTACHPTR **idx = NULL;
@@ -903,18 +820,16 @@ void mutt_view_attachments (HEADER * hdr)
   if ((msg = mx_open_message (Context, hdr->msgno)) == NULL)
     return;
 
-
-  if (WithCrypto && ((hdr->security & ENCRYPT) ||
-                     (mutt_is_application_smime (hdr->content) &
-                      SMIMEOPAQUE))) {
+  if ((hdr->security & ENCRYPT) ||
+      (mutt_is_application_smime (hdr->content) & SMIMEOPAQUE))
+  {
     need_secured = 1;
 
     if ((hdr->security & ENCRYPT) && !crypt_valid_passphrase (hdr->security)) {
       mx_close_message (&msg);
       return;
     }
-    if ((WithCrypto & APPLICATION_SMIME)
-        && (hdr->security & APPLICATION_SMIME)) {
+    if (hdr->security & APPLICATION_SMIME) {
       if (hdr->env)
         crypt_smime_getkeys (hdr->env);
 
@@ -931,14 +846,14 @@ void mutt_view_attachments (HEADER * hdr)
           cur = NULL;
           secured = !crypt_smime_decrypt_mime (_fp, &fp, _cur, &cur);
 
-          mutt_free_body (&_cur);
-          safe_fclose (&_fp);
+          body_list_wipe(&_cur);
+          m_fclose(&_fp);
         }
       }
       else
         need_secured = 0;
     }
-    if ((WithCrypto & APPLICATION_PGP) && (hdr->security & APPLICATION_PGP)) {
+    if (hdr->security & APPLICATION_PGP) {
       if (mutt_is_multipart_encrypted (hdr->content))
         secured = !crypt_pgp_decrypt_mime (msg->fp, &fp, hdr->content, &cur);
       else
@@ -948,12 +863,11 @@ void mutt_view_attachments (HEADER * hdr)
     if (need_secured && !secured) {
       mx_close_message (&msg);
       mutt_error _("Can't decrypt encrypted message!");
-
       return;
     }
   }
 
-  if (!WithCrypto || !need_secured) {
+  if (!need_secured) {
     fp = msg->fp;
     cur = hdr->content;
   }
@@ -970,9 +884,23 @@ void mutt_view_attachments (HEADER * hdr)
   attach_collapse (cur, 0, 1, 0);
   mutt_update_attach_index (cur, &idx, &idxlen, &idxmax, menu);
 
-  FOREVER {
+#define CHECK_READONLY \
+    if (Context->readonly) {                                            \
+        mutt_flushinp ();                                               \
+        mutt_error _("Mailbox is read-only.");                          \
+        break;                                                          \
+    }
+
+#define CHECK_ATTACH \
+    if (option(OPTATTACHMSG)) {                                         \
+        mutt_flushinp ();                                               \
+        mutt_error _("Function not permitted in attach-message mode."); \
+        break;                                                          \
+    }
+
+  for (;;) {
     if (op == OP_NULL)
-      op = mutt_menuLoop (menu);
+      op = mutt_menuLoop(menu);
     switch (op) {
     case OP_ATTACH_VIEW_MAILCAP:
       mutt_view_attachment (fp, idx[menu->current]->content, M_MAILCAP,
@@ -1012,21 +940,19 @@ void mutt_view_attachments (HEADER * hdr)
       break;
 
     case OP_EXTRACT_KEYS:
-      if ((WithCrypto & APPLICATION_PGP)) {
-        crypt_pgp_extract_keys_from_attachment_list (fp, menu->tagprefix,
-                                                     menu->
-                                                     tagprefix ? cur :
-                                                     idx[menu->current]->
-                                                     content);
-        menu->redraw = REDRAW_FULL;
-      }
+      crypt_pgp_extract_keys_from_attachment_list (fp, menu->tagprefix,
+                                                   menu->
+                                                   tagprefix ? cur :
+                                                   idx[menu->current]->
+                                                   content);
+      menu->redraw = REDRAW_FULL;
       break;
 
     case OP_CHECK_TRADITIONAL:
-      if ((WithCrypto & APPLICATION_PGP)
-          && crypt_pgp_check_traditional (fp, menu->tagprefix ? cur
+      if (crypt_pgp_check_traditional (fp, menu->tagprefix ? cur
                                           : idx[menu->current]->content,
-                                          menu->tagprefix)) {
+                                          menu->tagprefix))
+      {
         hdr->security = crypt_query (cur);
         menu->redraw = REDRAW_FULL;
       }
@@ -1059,14 +985,12 @@ void mutt_view_attachments (HEADER * hdr)
     case OP_DELETE:
       CHECK_READONLY;
 
-#ifdef USE_POP
       if (Context->magic == M_POP) {
         mutt_flushinp ();
         mutt_error _("Can't delete attachment from POP server.");
 
         break;
       }
-#endif
 
 #ifdef USE_NNTP
       if (Context->magic == M_NNTP) {
@@ -1077,10 +1001,9 @@ void mutt_view_attachments (HEADER * hdr)
       }
 #endif
 
-      if (WithCrypto && hdr->security) {
+      if (hdr->security & (~PGP_TRADITIONAL_CHECKED)) {
         mutt_message
-          _
-          ("Deletion of attachments from encrypted messages is unsupported.");
+          _("Deletion of attachments from encrypted messages is unsupported.");
       }
       else {
         if (!menu->tagprefix) {
@@ -1175,7 +1098,7 @@ void mutt_view_attachments (HEADER * hdr)
       CHECK_ATTACH;
 
       if (!idx[menu->current]->content->hdr->env->followup_to ||
-          safe_strcasecmp (idx[menu->current]->content->hdr->env->followup_to,
+          m_strcasecmp(idx[menu->current]->content->hdr->env->followup_to,
                            "poster")
           || query_quadoption (OPT_FOLLOWUPTOPOSTER,
                                _("Reply by mail as poster prefers?")) !=
@@ -1218,17 +1141,17 @@ void mutt_view_attachments (HEADER * hdr)
           hdr->attach_del = 1;
         if (idx[idxmax]->content)
           idx[idxmax]->content->aptr = NULL;
-        FREE (&idx[idxmax]->tree);
-        FREE (&idx[idxmax]);
+        p_delete(&idx[idxmax]->tree);
+        p_delete(&idx[idxmax]);
       }
       if (hdr->attach_del)
         hdr->changed = 1;
-      FREE (&idx);
+      p_delete(&idx);
       idxmax = 0;
 
-      if (WithCrypto && need_secured && secured) {
-        fclose (fp);
-        mutt_free_body (&cur);
+      if (need_secured && secured) {
+        m_fclose(&fp);
+        body_list_wipe(&cur);
       }
 
       mutt_menuDestroy (&menu);
@@ -1237,6 +1160,5 @@ void mutt_view_attachments (HEADER * hdr)
 
     op = OP_NULL;
   }
-
   /* not reached */
 }