Update copyright statement.
[gnus] / lisp / mm-decode.el
index 5dcadd6..f347a5c 100644 (file)
@@ -1,5 +1,6 @@
 ;;; mm-decode.el --- Functions for decoding MIME things
-;; Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+;; Copyright (C) 1998, 1999, 2000, 2001, 2002,
+;;        2003 Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;;     MORIOKA Tomohiko <morioka@jaist.ac.jp>
 
 ;;; Commentary:
 
-;; Jaap-Henk Hoepman (jhh@xs4all.nl):
-;;
-;; Added support for delayed destroy of external MIME viewers. All external
-;; viewers for mime types in mm-keep-viewer-alive-types will remain active
-;; after switching articles or groups, and will only be removed when exiting
-;; gnus.
-;;
-
 ;;; Code:
 
 (require 'mail-parse)
@@ -39,6 +32,7 @@
                   (require 'term))
 
 (eval-and-compile
+  (autoload 'executable-find "executable")
   (autoload 'mm-inline-partial "mm-partial")
   (autoload 'mm-inline-external-body "mm-extern")
   (autoload 'mm-insert-inline "mm-view"))
   `(list ,buffer ,type ,encoding ,undisplayer
         ,disposition ,description ,cache ,id))
 
+(defcustom mm-text-html-renderer
+  (cond ((locate-library "w3") 'w3)
+       ((locate-library "w3m") 'w3m)
+       ((executable-find "links") 'links)
+       ((executable-find "lynx") 'lynx)
+       (t 'html2text))
+  "Render of HTML contents.
+It is one of defined renderer types, or a rendering function.
+The defined renderer types are:
+`w3'   : using Emacs/W3;
+`w3m'  : using emacs-w3m;
+`links': using links;
+`lynx' : using lynx;
+`html2text' : using html2text;
+nil    : using external viewer."
+  :type '(choice (const w3)
+                (const w3m)
+                (const links)
+                (const lynx)
+                (const html2text)
+                (const nil)
+                (function))
+  :version "21.3"
+  :group 'mime-display)
+
+(defvar mm-inline-text-html-renderer nil
+  "Function used for rendering inline HTML contents.
+It is suggested to customize `mm-text-html-renderer' instead.")
+
+(defcustom mm-inline-text-html-with-images nil
+  "If non-nil, Gnus will allow retrieving images in the HTML contents
+with <img> tags.  It has no effect on Emacs/w3.  See also
+the documentation for the option `mm-w3m-safe-url-regexp'."
+  :type 'boolean
+  :group 'mime-display)
+
+(defcustom mm-w3m-safe-url-regexp "\\`cid:"
+  "Regexp that matches safe url names.  Some HTML mails might have a
+trick of spammers using <img> tags.  It is likely to be intended to
+verify whether you have read the mail.  You can prevent your personal
+informations from leaking by setting this to the regexp which matches
+the safe url names.  The value of the variable `w3m-safe-url-regexp'
+will be bound with this value.  You may set this value to nil if you
+consider all the urls to be safe."
+  :type '(choice (regexp :tag "Regexp")
+                (const :tag "All URLs are safe" nil))
+  :group 'mime-display)
+
+(defcustom mm-inline-text-html-with-w3m-keymap t
+  "If non-nil, use emacs-w3m command keys in the article buffer."
+  :type 'boolean
+  :group 'mime-display)
+
 (defcustom mm-inline-media-tests
   '(("image/jpeg"
      mm-inline-image
      mm-inline-image
      (lambda (handle)
        (mm-valid-and-fit-image-p 'xpm handle)))
-    ("image/x-pixmap"
+    ("image/x-xpixmap"
      mm-inline-image
      (lambda (handle)
        (mm-valid-and-fit-image-p 'xpm handle)))
      (lambda (handle)
        (locate-library "diff-mode")))
     ("application/emacs-lisp" mm-display-elisp-inline identity)
+    ("application/x-emacs-lisp" mm-display-elisp-inline identity)
     ("text/html"
-     mm-inline-text
+     mm-inline-text-html
      (lambda (handle)
-       (locate-library "w3")))
+       (or mm-inline-text-html-renderer
+          mm-text-html-renderer)))
     ("text/x-vcard"
-     mm-inline-text
+     mm-inline-text-vcard
      (lambda (handle)
        (or (featurep 'vcard)
           (locate-library "vcard"))))
     ("application/pgp-signature" ignore identity)
     ("application/x-pkcs7-signature" ignore identity)
     ("application/pkcs7-signature" ignore identity)
-    ("application/x-pkcs7-mime" mm-view-pkcs7 identity)
-    ("application/pkcs7-mime" mm-view-pkcs7 identity)
+    ("application/x-pkcs7-mime" ignore identity)
+    ("application/pkcs7-mime" ignore identity)
     ("multipart/alternative" ignore identity)
     ("multipart/mixed" ignore identity)
     ("multipart/related" ignore identity)
 (defcustom mm-inlined-types
   '("image/.*" "text/.*" "message/delivery-status" "message/rfc822"
     "message/partial" "message/external-body" "application/emacs-lisp"
+    "application/x-emacs-lisp"
     "application/pgp-signature" "application/x-pkcs7-signature"
     "application/pkcs7-signature" "application/x-pkcs7-mime"
     "application/pkcs7-mime")
@@ -217,7 +267,8 @@ when selecting a different article."
   '("text/plain" "text/enriched" "text/richtext" "text/html"
     "text/x-vcard" "image/.*" "message/delivery-status" "multipart/.*"
     "message/rfc822" "text/x-patch" "application/pgp-signature"
-    "application/emacs-lisp" "application/x-pkcs7-signature"
+    "application/emacs-lisp" "application/x-emacs-lisp"
+    "application/x-pkcs7-signature"
     "application/pkcs7-signature" "application/x-pkcs7-mime"
     "application/pkcs7-mime")
   "A list of MIME types to be displayed automatically."
@@ -226,7 +277,9 @@ when selecting a different article."
 
 (defcustom mm-attachment-override-types '("text/x-vcard"
                                          "application/pkcs7-mime"
-                                         "application/x-pkcs7-mime")
+                                         "application/x-pkcs7-mime"
+                                         "application/pkcs7-signature"
+                                         "application/x-pkcs7-signature")
   "Types to have \"attachment\" ignored if they can be displayed inline."
   :type '(repeat string)
   :group 'mime-display)
@@ -279,13 +332,21 @@ Ready-made functions include
 `capitalize', `downcase', `upcase', and
 `upcase-initials'.")
 
+(defvar mm-path-name-rewrite-functions nil
+  "*List of functions used for rewriting path names of MIME parts.
+This is used when viewing parts externally , and is meant for
+transforming the path name so that non-compliant programs can
+find the file where it's saved.
+
+Each function takes a file name as input and returns a file name.")
+
 (defvar mm-file-name-replace-whitespace nil
   "String used for replacing whitespace characters; default is `\"_\"'.")
 
 (defcustom mm-default-directory nil
   "The default directory where mm will save files.
 If not set, `default-directory' will be used."
-  :type 'directory
+  :type '(choice directory (const :tag "Default" nil))
   :group 'mime-display)
 
 (defcustom mm-external-terminal-program "xterm"
@@ -295,7 +356,6 @@ If not set, `default-directory' will be used."
 
 ;;; Internal variables.
 
-(defvar mm-dissection-list nil)
 (defvar mm-last-shell-command "")
 (defvar mm-content-id-alist nil)
 (defvar mm-postponed-undisplay-list nil)
@@ -406,16 +466,18 @@ for types in mm-keep-viewer-alive-types."
     (mm-handle-set-undisplayer handle function)))
 
 (defun mm-destroy-postponed-undisplay-list ()
-  (message "Destroying external MIME viewers")
-  (mm-destroy-parts mm-postponed-undisplay-list))
+  (when mm-postponed-undisplay-list
+    (message "Destroying external MIME viewers")
+    (mm-destroy-parts mm-postponed-undisplay-list)))
 
-(defun mm-dissect-buffer (&optional no-strict-mime)
+(defun mm-dissect-buffer (&optional no-strict-mime loose-mime)
   "Dissect the current buffer and return a list of MIME handles."
   (save-excursion
     (let (ct ctl type subtype cte cd description id result from)
       (save-restriction
        (mail-narrow-to-head)
        (when (or no-strict-mime
+                 loose-mime
                  (mail-fetch-field "mime-version"))
          (setq ct (mail-fetch-field "content-type")
                ctl (ignore-errors (mail-header-parse-content-type ct))
@@ -456,10 +518,10 @@ for types in mm-keep-viewer-alive-types."
                                  (mm-alist-to-plist (cdr ctl)) (car ctl))
 
             ;; what really needs to be done here is a way to link a
-       ;; MIME handle back to it's parent MIME handle (in a multilevel
+            ;; MIME handle back to it's parent MIME handle (in a multilevel
             ;; MIME article).  That would probably require changing
-        ;; the mm-handle API so we simply store the multipart buffert
-       ;; name as a text property of the "multipart/whatever" string.
+            ;; the mm-handle API so we simply store the multipart buffert
+            ;; name as a text property of the "multipart/whatever" string.
             (add-text-properties 0 (length (car ctl))
                                  (list 'buffer (mm-copy-to-buffer))
                                  (car ctl))
@@ -468,14 +530,17 @@ for types in mm-keep-viewer-alive-types."
                                  (car ctl))
             (cons (car ctl) (mm-dissect-multipart ctl))))
          (t
-          (mm-dissect-singlepart
-           ctl
-           (and cte (intern (downcase (mail-header-remove-whitespace
-                                       (mail-header-remove-comments
-                                        cte)))))
-           no-strict-mime
-           (and cd (ignore-errors (mail-header-parse-content-disposition cd)))
-           description id))))
+          (mm-possibly-verify-or-decrypt
+           (mm-dissect-singlepart
+            ctl
+            (and cte (intern (downcase (mail-header-remove-whitespace
+                                        (mail-header-remove-comments
+                                         cte)))))
+            no-strict-mime
+            (and cd (ignore-errors
+                      (mail-header-parse-content-disposition cd)))
+            description id)
+           ctl))))
        (when id
          (when (string-match " *<\\(.*\\)> *" id)
            (setq id (match-string 1 id)))
@@ -487,16 +552,8 @@ for types in mm-keep-viewer-alive-types."
            (if (equal "text/plain" (car ctl))
                (assoc 'format ctl)
              t))
-    (let ((res (mm-make-handle
-               (mm-copy-to-buffer) ctl cte nil cdl description nil id)))
-      (push (car res) mm-dissection-list)
-      res)))
-
-(defun mm-remove-all-parts ()
-  "Remove all MIME handles."
-  (interactive)
-  (mapcar 'mm-remove-part mm-dissection-list)
-  (setq mm-dissection-list nil))
+    (mm-make-handle
+     (mm-copy-to-buffer) ctl cte nil cdl description nil id)))
 
 (defun mm-dissect-multipart (ctl)
   (goto-char (point-min))
@@ -516,7 +573,9 @@ for types in mm-keep-viewer-alive-types."
          (save-restriction
            (narrow-to-region start (point))
            (setq parts (nconc (list (mm-dissect-buffer t)) parts)))))
-      (forward-line 2)
+      (end-of-line 2)
+      (or (looking-at boundary)
+         (forward-line 1))
       (setq start (point)))
     (when (and start (< start end))
       (save-excursion
@@ -607,100 +666,105 @@ external if displayed external."
                  (mm-handle-set-undisplayer handle mm)))))
        ;; The function is a string to be executed.
        (mm-insert-part handle)
-       (let* ((dir (make-temp-name (expand-file-name "emm." mm-tmp-directory)))
-              (filename (mail-content-type-get
-                         (mm-handle-disposition handle) 'filename))
+       (let* ((dir (mm-make-temp-file
+                    (expand-file-name "emm." mm-tmp-directory) 'dir))
+              (filename (or
+                         (mail-content-type-get
+                          (mm-handle-disposition handle) 'filename)
+                         (mail-content-type-get
+                          (mm-handle-type handle) 'name)))
               (mime-info (mailcap-mime-info
                           (mm-handle-media-type handle) t))
               (needsterm (or (assoc "needsterm" mime-info)
                              (assoc "needsterminal" mime-info)))
               (copiousoutput (assoc "copiousoutput" mime-info))
               file buffer)
-       ;; We create a private sub-directory where we store our files.
-         (make-directory dir)
+         ;; We create a private sub-directory where we store our files.
          (set-file-modes dir 448)
          (if filename
-             (setq file (expand-file-name (file-name-nondirectory filename)
-                                          dir))
-           (setq file (make-temp-name (expand-file-name "mm." dir))))
+             (setq file (expand-file-name
+                         (gnus-map-function mm-file-name-rewrite-functions
+                                            (file-name-nondirectory filename))
+                         dir))
+           (setq file (mm-make-temp-file (expand-file-name "mm." dir))))
          (let ((coding-system-for-write mm-binary-coding-system))
            (write-region (point-min) (point-max) file nil 'nomesg))
          (message "Viewing with %s" method)
-         (cond (needsterm
-                (unwind-protect
-                    (if window-system
-                        (start-process "*display*" nil
-                                       mm-external-terminal-program
-                                       "-e" shell-file-name
-                                       shell-command-switch
-                                       (mm-mailcap-command
-                                        method file (mm-handle-type handle)))
-                      (require 'term)
-                      (require 'gnus-win)
-                      (set-buffer
-                       (setq buffer
-                             (make-term "display"
-                                        shell-file-name
-                                        nil
-                                        shell-command-switch
-                                        (mm-mailcap-command
-                                         method file
-                                         (mm-handle-type handle)))))
-                      (term-mode)
-                      (term-char-mode)
-                      (set-process-sentinel
-                       (get-buffer-process buffer)
-                       `(lambda (process state)
-                          (if (eq 'exit (process-status process))
-                              (gnus-configure-windows
-                               ',gnus-current-window-configuration))))
-                      (gnus-configure-windows 'display-term))
-                  (mm-handle-set-external-undisplayer handle (cons file buffer)))
-                (message "Displaying %s..." (format method file))
-                'external)
-               (copiousoutput
-                (with-current-buffer outbuf
-                  (forward-line 1)
-                  (mm-insert-inline
-                   handle
-                   (unwind-protect
-                       (progn
-                         (call-process shell-file-name nil
-                                       (setq buffer
-                                             (generate-new-buffer " *mm*"))
-                                       nil
-                                       shell-command-switch
-                                       (mm-mailcap-command
-                                        method file (mm-handle-type handle)))
-                         (if (buffer-live-p buffer)
-                             (save-excursion
-                               (set-buffer buffer)
-                               (buffer-string))))
-                     (progn
-                       (ignore-errors (delete-file file))
-                       (ignore-errors (delete-directory
-                                       (file-name-directory file)))
-                       (ignore-errors (kill-buffer buffer))))))
-                'inline)
-               (t
-                (unwind-protect
-                    (start-process "*display*"
-                                   (setq buffer
-                                         (generate-new-buffer " *mm*"))
-                                   shell-file-name
-                                   shell-command-switch
-                                   (mm-mailcap-command
-                                    method file (mm-handle-type handle)))
-                  (mm-handle-set-external-undisplayer handle (cons file buffer)))
-                (message "Displaying %s..." (format method file))
-                'external)))))))
+         (cond
+          (needsterm
+           (let ((command (mm-mailcap-command
+                           method file (mm-handle-type handle))))
+             (unwind-protect
+                 (if window-system
+                     (start-process "*display*" nil
+                                    mm-external-terminal-program
+                                    "-e" shell-file-name
+                                    shell-command-switch command)
+                   (require 'term)
+                   (require 'gnus-win)
+                   (set-buffer
+                    (setq buffer
+                          (make-term "display"
+                                     shell-file-name
+                                     nil
+                                     shell-command-switch command)))
+                   (term-mode)
+                   (term-char-mode)
+                   (set-process-sentinel
+                    (get-buffer-process buffer)
+                    `(lambda (process state)
+                       (if (eq 'exit (process-status process))
+                           (gnus-configure-windows
+                            ',gnus-current-window-configuration))))
+                   (gnus-configure-windows 'display-term))
+               (mm-handle-set-external-undisplayer handle (cons file buffer)))
+             (message "Displaying %s..." command))
+           'external)
+          (copiousoutput
+           (with-current-buffer outbuf
+             (forward-line 1)
+             (mm-insert-inline
+              handle
+              (unwind-protect
+                  (progn
+                    (call-process shell-file-name nil
+                                  (setq buffer
+                                        (generate-new-buffer " *mm*"))
+                                  nil
+                                  shell-command-switch
+                                  (mm-mailcap-command
+                                   method file (mm-handle-type handle)))
+                    (if (buffer-live-p buffer)
+                        (save-excursion
+                          (set-buffer buffer)
+                          (buffer-string))))
+                (progn
+                  (ignore-errors (delete-file file))
+                  (ignore-errors (delete-directory
+                                  (file-name-directory file)))
+                  (ignore-errors (kill-buffer buffer))))))
+           'inline)
+          (t
+           (let ((command (mm-mailcap-command
+                           method file (mm-handle-type handle))))
+             (unwind-protect
+                 (start-process "*display*"
+                                (setq buffer
+                                      (generate-new-buffer " *mm*"))
+                                shell-file-name
+                                shell-command-switch command)
+               (mm-handle-set-external-undisplayer
+                handle (cons file buffer)))
+             (message "Displaying %s..." command))
+           'external)))))))
 
 (defun mm-mailcap-command (method file type-list)
   (let ((ctl (cdr type-list))
        (beg 0)
        (uses-stdin t)
        out sub total)
-    (while (string-match "%{\\([^}]+\\)}\\|%s\\|%t\\|%%" method beg)
+    (while (string-match "%{\\([^}]+\\)}\\|'%s'\\|\"%s\"\\|%s\\|%t\\|%%"
+                        method beg)
       (push (substring method beg (match-beginning 0)) out)
       (setq beg (match-end 0)
            total (match-string 0 method)
@@ -708,18 +772,23 @@ external if displayed external."
       (cond
        ((string= total "%%")
        (push "%" out))
-       ((string= total "%s")
+       ((or (string= total "%s")
+           ;; We do our own quoting.
+           (string= total "'%s'")
+           (string= total "\"%s\""))
        (setq uses-stdin nil)
-       (push (mm-quote-arg file) out))
+       (push (mm-quote-arg
+              (gnus-map-function mm-path-name-rewrite-functions file)) out))
        ((string= total "%t")
        (push (mm-quote-arg (car type-list)) out))
        (t
        (push (mm-quote-arg (or (cdr (assq (intern sub) ctl)) "")) out))))
     (push (substring method beg (length method)) out)
-    (if uses-stdin
-       (progn
-         (push "<" out)
-         (push (mm-quote-arg file) out)))
+    (when uses-stdin
+      (push "<" out)
+      (push (mm-quote-arg
+            (gnus-map-function mm-path-name-rewrite-functions file))
+           out))
     (mapconcat 'identity (nreverse out) "")))
 
 (defun mm-remove-parts (handles)
@@ -877,7 +946,7 @@ external if displayed external."
   "Return the contents of HANDLE as a string."
   (mm-with-unibyte-buffer
     (insert (with-current-buffer (mm-handle-buffer handle)
-             (mm-with-unibyte-current-buffer-mule4
+             (mm-with-unibyte-current-buffer
                (buffer-string))))
     (mm-decode-content-transfer-encoding
      (mm-handle-encoding handle)
@@ -948,9 +1017,8 @@ like underscores."
                                        (file-name-nondirectory filename))))
     (setq file
          (read-file-name "Save MIME part to: "
-                         (expand-file-name
-                          (or filename name "")
-                          (or mm-default-directory default-directory))))
+                         (or mm-default-directory default-directory)
+                         nil nil (or filename name "")))
     (setq mm-default-directory (file-name-directory file))
     (and (or (not (file-exists-p file))
             (yes-or-no-p (format "File %s already exists; overwrite? "
@@ -961,8 +1029,7 @@ like underscores."
 
 (defun mm-save-part-to-file (handle file)
   (mm-with-unibyte-buffer
-    (or (mm-insert-part handle)
-       (error "Error with message"))
+    (mm-insert-part handle)
     (let ((coding-system-for-write 'binary)
          ;; Don't re-compress .gz & al.  Arguably we should make
          ;; `file-name-handler-alist' nil, but that would chop
@@ -1085,34 +1152,37 @@ be determined."
                      ;; Avoid testing `make-glyph' since W3 may define
                      ;; a bogus version of it.
                      (if (fboundp 'create-image)
-                         (create-image (buffer-string) 
+                         (create-image (buffer-string)
                                        (or (mm-image-type-from-buffer)
                                            (intern type))
                                        'data-p)
-                       (cond
-                        ((equal type "xbm")
-                         ;; xbm images require special handling, since
-                         ;; the only way to create glyphs from these
-                         ;; (without a ton of work) is to write them
-                         ;; out to a file, and then create a file
-                         ;; specifier.
-                         (let ((file (make-temp-name
-                                      (expand-file-name "emm.xbm"
-                                                        mm-tmp-directory))))
-                           (unwind-protect
-                               (progn
-                                 (write-region (point-min) (point-max) file)
-                                 (make-glyph (list (cons 'x file))))
-                             (ignore-errors
-                               (delete-file file)))))
-                        (t
-                         (make-glyph
-                          (vector 
-                           (or (mm-image-type-from-buffer)
-                               (intern type))
-                           :data (buffer-string))))))))
+                       (mm-create-image-xemacs type))))
            (mm-handle-set-cache handle spec))))))
 
+(defun mm-create-image-xemacs (type)
+  (cond
+   ((equal type "xbm")
+    ;; xbm images require special handling, since
+    ;; the only way to create glyphs from these
+    ;; (without a ton of work) is to write them
+    ;; out to a file, and then create a file
+    ;; specifier.
+    (let ((file (mm-make-temp-file
+                (expand-file-name "emm.xbm"
+                                  mm-tmp-directory))))
+      (unwind-protect
+         (progn
+           (write-region (point-min) (point-max) file)
+           (make-glyph (list (cons 'x file))))
+       (ignore-errors
+         (delete-file file)))))
+   (t
+    (make-glyph
+     (vector
+      (or (mm-image-type-from-buffer)
+         (intern type))
+      :data (buffer-string))))))
+
 (defun mm-image-fit-p (handle)
   "Say whether the image in HANDLE will fit the current window."
   (let ((image (mm-get-image handle)))
@@ -1212,15 +1282,27 @@ If RECURSIVE, search recursively."
 
 (defsubst mm-set-handle-multipart-parameter (handle parameter value)
   ;; HANDLE could be a CTL.
-  (if handle
-      (put-text-property 0 (length (car handle)) parameter value
-                        (car handle))))
+  (when handle
+    (put-text-property 0 (length (car handle)) parameter value
+                      (car handle))))
 
 (defun mm-possibly-verify-or-decrypt (parts ctl)
-  (let ((subtype (cadr (split-string (car ctl) "/")))
+  (let ((type (car ctl))
+       (subtype (cadr (split-string (car ctl) "/")))
        (mm-security-handle ctl) ;; (car CTL) is the type.
        protocol func functest)
     (cond
+     ((or (equal type "application/x-pkcs7-mime")
+         (equal type "application/pkcs7-mime"))
+      (with-temp-buffer
+       (when (and (cond
+                   ((eq mm-decrypt-option 'never) nil)
+                   ((eq mm-decrypt-option 'always) t)
+                   ((eq mm-decrypt-option 'known) t)
+                   (t (y-or-n-p
+                       (format "Decrypt (S/MIME) part? "))))
+                  (mm-view-pkcs7 parts))
+         (setq parts (mm-dissect-buffer t)))))
      ((equal subtype "signed")
       (unless (and (setq protocol
                         (mm-handle-multipart-ctl-parameter ctl 'protocol))
@@ -1235,25 +1317,26 @@ If RECURSIVE, search recursively."
                      protocols nil)
              (setq protocols (cdr protocols))))))
       (setq func (nth 1 (assoc protocol mm-verify-function-alist)))
-      (if (cond
-          ((eq mm-verify-option 'never) nil)
-          ((eq mm-verify-option 'always) t)
-          ((eq mm-verify-option 'known)
-           (and func
-                (or (not (setq functest
-                               (nth 3 (assoc protocol
-                                             mm-verify-function-alist))))
-                    (funcall functest parts ctl))))
-          (t (y-or-n-p
+      (when (cond
+            ((eq mm-verify-option 'never) nil)
+            ((eq mm-verify-option 'always) t)
+            ((eq mm-verify-option 'known)
+             (and func
+                  (or (not (setq functest
+                                 (nth 3 (assoc protocol
+                                               mm-verify-function-alist))))
+                      (funcall functest parts ctl))))
+            (t
+             (y-or-n-p
               (format "Verify signed (%s) part? "
                       (or (nth 2 (assoc protocol mm-verify-function-alist))
                           (format "protocol=%s" protocol))))))
-         (save-excursion
-           (if func
-               (funcall func parts ctl)
-             (mm-set-handle-multipart-parameter
-              mm-security-handle 'gnus-details
-              (format "Unknown sign protocol (%s)" protocol))))))
+       (save-excursion
+         (if func
+             (funcall func parts ctl)
+           (mm-set-handle-multipart-parameter
+            mm-security-handle 'gnus-details
+            (format "Unknown sign protocol (%s)" protocol))))))
      ((equal subtype "encrypted")
       (unless (setq protocol
                    (mm-handle-multipart-ctl-parameter ctl 'protocol))
@@ -1266,25 +1349,26 @@ If RECURSIVE, search recursively."
                      parts nil)
              (setq parts (cdr parts))))))
       (setq func (nth 1 (assoc protocol mm-decrypt-function-alist)))
-      (if (cond
-          ((eq mm-decrypt-option 'never) nil)
-          ((eq mm-decrypt-option 'always) t)
-          ((eq mm-decrypt-option 'known)
-           (and func
-                (or (not (setq functest
-                               (nth 3 (assoc protocol
-                                             mm-decrypt-function-alist))))
-                    (funcall functest parts ctl))))
-          (t (y-or-n-p
+      (when (cond
+            ((eq mm-decrypt-option 'never) nil)
+            ((eq mm-decrypt-option 'always) t)
+            ((eq mm-decrypt-option 'known)
+             (and func
+                  (or (not (setq functest
+                                 (nth 3 (assoc protocol
+                                               mm-decrypt-function-alist))))
+                      (funcall functest parts ctl))))
+            (t
+             (y-or-n-p
               (format "Decrypt (%s) part? "
                       (or (nth 2 (assoc protocol mm-decrypt-function-alist))
                           (format "protocol=%s" protocol))))))
-         (save-excursion
-           (if func
-               (setq parts (funcall func parts ctl))
-             (mm-set-handle-multipart-parameter
-              mm-security-handle 'gnus-details
-              (format "Unknown encrypt protocol (%s)" protocol))))))
+       (save-excursion
+         (if func
+             (setq parts (funcall func parts ctl))
+           (mm-set-handle-multipart-parameter
+            mm-security-handle 'gnus-details
+            (format "Unknown encrypt protocol (%s)" protocol))))))
      (t nil))
     parts))