* gnus-bookmark.el (gnus-bookmark-jump): Don't mark unrelated articles
[gnus] / lisp / mm-decode.el
index 7cd7339..b03bde2 100644 (file)
@@ -35,6 +35,7 @@
 (eval-and-compile
   (autoload 'mm-inline-partial "mm-partial")
   (autoload 'mm-inline-external-body "mm-extern")
+  (autoload 'mm-extern-cache-contents "mm-extern")
   (autoload 'mm-insert-inline "mm-view"))
 
 (defvar gnus-current-window-configuration)
   `(setcar (nthcdr 3 ,handle) ,function))
 (defmacro mm-handle-disposition (handle)
   `(nth 4 ,handle))
-(defmacro mm-handle-set-disposition (handle disposition)
-  `(setcar (nthcdr 4 ,handle) ,disposition))
 (defmacro mm-handle-description (handle)
   `(nth 5 ,handle))
-(defmacro mm-handle-set-description (handle description)
-  `(setcar (nthcdr 5 ,handle) ,description))
 (defmacro mm-handle-cache (handle)
   `(nth 6 ,handle))
 (defmacro mm-handle-set-cache (handle contents)
@@ -310,7 +307,7 @@ when selecting a different article."
     "application/pkcs7-signature" "application/x-pkcs7-mime"
     "application/pkcs7-mime"
     ;; Mutt still uses this even though it has already been withdrawn.
-    "application/pgp")
+    "application/pgp\\'")
   "A list of MIME types to be displayed automatically."
   :type '(repeat regexp)
   :group 'mime-display)
@@ -439,7 +436,11 @@ If not set, `default-directory' will be used."
 (defcustom mm-verify-option 'never
   "Option of verifying signed parts.
 `never', not verify; `always', always verify;
-`known', only verify known protocols.  Otherwise, ask user."
+`known', only verify known protocols.  Otherwise, ask user.
+
+When set to `always' or `known', you should add
+\"multipart/signed\" to `gnus-buttonized-mime-types' to see
+result of the verification."
   :version "22.1"
   :type '(choice (item always)
                 (item never)
@@ -538,13 +539,13 @@ Postpone undisplaying of viewers for types in
                  loose-mime
                  (mail-fetch-field "mime-version"))
          (setq ct (mail-fetch-field "content-type")
-               ctl (ignore-errors (mail-header-parse-content-type ct))
+               ctl (and ct (mail-header-parse-content-type ct))
                cte (mail-fetch-field "content-transfer-encoding")
                cd (mail-fetch-field "content-disposition")
                description (mail-fetch-field "content-description")
                id (mail-fetch-field "content-id"))
          (unless from
-               (setq from (mail-fetch-field "from")))
+           (setq from (mail-fetch-field "from")))
          ;; FIXME: In some circumstances, this code is running within
          ;; an unibyte macro.  mail-extract-address-components
          ;; creates unibyte buffers. This `if', though not a perfect
@@ -557,11 +558,11 @@ Postpone undisplaying of viewers for types in
           (list mm-dissect-default-type)
           (and cte (intern (downcase (mail-header-strip cte))))
           no-strict-mime
-          (and cd (ignore-errors (mail-header-parse-content-disposition cd)))
+          (and cd (mail-header-parse-content-disposition cd))
           description)
        (setq type (split-string (car ctl) "/"))
        (setq subtype (cadr type)
-             type (pop type))
+             type (car type))
        (setq
         result
         (cond
@@ -590,8 +591,7 @@ Postpone undisplaying of viewers for types in
             ctl
             (and cte (intern (downcase (mail-header-strip cte))))
             no-strict-mime
-            (and cd (ignore-errors
-                      (mail-header-parse-content-disposition cd)))
+            (and cd (mail-header-parse-content-disposition cd))
             description id)
            ctl))))
        (when id
@@ -639,16 +639,15 @@ Postpone undisplaying of viewers for types in
 
 (defun mm-copy-to-buffer ()
   "Copy the contents of the current buffer to a fresh buffer."
-  (save-excursion
     (let ((obuf (current-buffer))
          beg)
       (goto-char (point-min))
       (search-forward-regexp "^\n" nil t)
       (setq beg (point))
-      (set-buffer
+    (with-current-buffer
        ;; Preserve the data's unibyteness (for url-insert-file-contents).
        (let ((default-enable-multibyte-characters (mm-multibyte-p)))
-        (generate-new-buffer " *mm*")))
+          (generate-new-buffer " *mm*"))
       (insert-buffer-substring obuf beg)
       (current-buffer))))
 
@@ -670,7 +669,14 @@ external if displayed external."
     (mailcap-parse-mailcaps)
     (if (mm-handle-displayed-p handle)
        (mm-remove-part handle)
-      (let* ((type (mm-handle-media-type handle))
+      (let* ((ehandle (if (equal (mm-handle-media-type handle)
+                                "message/external-body")
+                         (progn
+                           (unless (mm-handle-cache handle)
+                             (mm-extern-cache-contents handle))
+                           (mm-handle-cache handle))
+                       handle))
+            (type (mm-handle-media-type ehandle))
             (method (mailcap-mime-info type))
             (filename (or (mail-content-type-get
                            (mm-handle-disposition handle) 'filename)
@@ -678,8 +684,8 @@ external if displayed external."
                            (mm-handle-type handle) 'name)
                           "<file>"))
             (external mm-enable-external))
-       (if (and (mm-inlinable-p handle)
-                (mm-inlined-p handle))
+       (if (and (mm-inlinable-p ehandle)
+                (mm-inlined-p ehandle))
            (progn
              (forward-line 1)
              (mm-display-inline handle)
@@ -687,12 +693,13 @@ external if displayed external."
          (when (or method
                    (not no-default))
            (if (and (not method)
-                    (equal "text" (car (split-string type))))
+                    (equal "text" (car (split-string type "/"))))
                (progn
                  (forward-line 1)
                  (mm-insert-inline handle (mm-get-part handle))
                  'inline)
-             (if (and method ;; If nil, we always use "save".
+             (setq external
+                    (and method ;; If nil, we always use "save".
                       (stringp method) ;; 'mailcap-save-binary-file
                       (or (eq mm-enable-external t)
                           (and (eq mm-enable-external 'ask)
@@ -705,9 +712,7 @@ external if displayed external."
                                      (concat
                                       " \"" (format method filename) "\"")
                                    "")
-                                 "? ")))))
-                 (setq external t)
-               (setq external nil))
+                                    "? "))))))
              (if external
                  (mm-display-external
                   handle (or method 'mailcap-save-binary-file))
@@ -768,19 +773,18 @@ external if displayed external."
                          (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 ((newname
-                  ;; Use nametemplate (defined in RFC1524) if it is
-                  ;; specified in mailcap.
-                  (if (assoc "nametemplate" mime-info)
-                      (format (cdr (assoc "nametemplate" mime-info)) file)
-                    ;; Add a suffix according to `mailcap-mime-extensions'.
-                    (concat file (car (rassoc (mm-handle-media-type handle)
-                                              mailcap-mime-extensions))))))
-             (unless (string-equal file newname)
-               (when (file-exists-p file)
-                 (rename-file file newname))
-               (setq file newname))))
+           ;; Use nametemplate (defined in RFC1524) if it is specified
+           ;; in mailcap.
+           (let ((suffix (cdr (assoc "nametemplate" mime-info))))
+             (if (and suffix
+                      (string-match "\\`%s\\(\\..+\\)\\'" suffix))
+                 (setq suffix (match-string 1 suffix))
+               ;; Otherwise, use a suffix according to
+               ;; `mailcap-mime-extensions'.
+               (setq suffix (car (rassoc (mm-handle-media-type handle)
+                                         mailcap-mime-extensions))))
+             (setq file (mm-make-temp-file (expand-file-name "mm." dir)
+                                           nil suffix))))
          (let ((coding-system-for-write mm-binary-coding-system))
            (write-region (point-min) (point-max) file nil 'nomesg))
          (message "Viewing with %s" method)
@@ -1011,10 +1015,12 @@ external if displayed external."
              methods nil)))
     result))
 
-(defun mm-inlinable-p (handle)
-  "Say whether HANDLE can be displayed inline."
+(defun mm-inlinable-p (handle &optional type)
+  "Say whether HANDLE can be displayed inline.
+TYPE is the mime-type of the object; it defaults to the one given
+in HANDLE."
+  (unless type (setq type (mm-handle-media-type handle)))
   (let ((alist mm-inline-media-tests)
-       (type (mm-handle-media-type handle))
        test)
     (while alist
       (when (string-match (caar alist) type)
@@ -1082,19 +1088,44 @@ external if displayed external."
 ;;; Functions for outputting parts
 ;;;
 
-(defun mm-get-part (handle)
-  "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
-               (buffer-string))))
-    (mm-decode-content-transfer-encoding
-     (mm-handle-encoding handle)
-     (mm-handle-media-type handle))
-    (buffer-string)))
-
-(defun mm-insert-part (handle)
-  "Insert the contents of HANDLE in the current buffer."
+(defmacro mm-with-part (handle &rest forms)
+  "Run FORMS in the temp buffer containing the contents of HANDLE."
+  `(let* ((handle ,handle)
+         ;; The multibyteness of the temp buffer should be turned on
+         ;; if inserting a multibyte string.  Contrarily, the buffer's
+         ;; multibyteness should be off if inserting a unibyte string,
+         ;; especially if a string contains 8bit data.
+         (default-enable-multibyte-characters
+           (with-current-buffer (mm-handle-buffer handle)
+             (mm-multibyte-p))))
+     (with-temp-buffer
+       (insert-buffer-substring (mm-handle-buffer handle))
+       (mm-disable-multibyte)
+       (mm-decode-content-transfer-encoding
+       (mm-handle-encoding handle)
+       (mm-handle-media-type handle))
+       ,@forms)))
+(put 'mm-with-part 'lisp-indent-function 1)
+(put 'mm-with-part 'edebug-form-spec '(body))
+
+(defun mm-get-part (handle &optional no-cache)
+  "Return the contents of HANDLE as a string.
+If NO-CACHE is non-nil, cached contents of a message/external-body part
+are ignored."
+  (if (and (not no-cache)
+          (equal (mm-handle-media-type handle) "message/external-body"))
+      (progn
+       (unless (mm-handle-cache handle)
+         (mm-extern-cache-contents handle))
+       (with-current-buffer (mm-handle-buffer (mm-handle-cache handle))
+         (buffer-string)))
+    (mm-with-part handle
+      (buffer-string))))
+
+(defun mm-insert-part (handle &optional no-cache)
+  "Insert the contents of HANDLE in the current buffer.
+If NO-CACHE is non-nil, cached contents of a message/external-body part
+are ignored."
   (save-excursion
     (insert
      (cond ((eq (mail-content-type-get (mm-handle-type handle) 'charset)
@@ -1102,9 +1133,9 @@ external if displayed external."
            (with-current-buffer (mm-handle-buffer handle)
              (buffer-string)))
           ((mm-multibyte-p)
-           (mm-string-as-multibyte (mm-get-part handle)))
+           (mm-string-as-multibyte (mm-get-part handle no-cache)))
           (t
-           (mm-get-part handle))))))
+           (mm-get-part handle no-cache))))))
 
 (defun mm-file-name-delete-whitespace (file-name)
   "Remove all whitespace characters from FILE-NAME."
@@ -1147,18 +1178,19 @@ string if you do not like underscores."
 (defun mm-save-part (handle &optional prompt)
   "Write HANDLE to a file.
 PROMPT overrides the default one used to ask user for a file name."
-  (let* ((name (mail-content-type-get (mm-handle-type handle) 'name))
-        (filename (mail-content-type-get
-                   (mm-handle-disposition handle) 'filename))
-        file)
+  (let ((filename (or (mail-content-type-get
+                      (mm-handle-disposition handle) 'filename)
+                     (mail-content-type-get
+                      (mm-handle-type handle) 'name)))
+       file)
     (when filename
       (setq filename (gnus-map-function mm-file-name-rewrite-functions
                                        (file-name-nondirectory filename))))
     (setq file
          (mm-with-multibyte
-           (read-file-name (or prompt "Save MIME part to: ")
-                           (or mm-default-directory default-directory)
-                           nil nil (or filename name ""))))
+          (read-file-name (or prompt "Save MIME part to: ")
+                          (or mm-default-directory default-directory)
+                          nil nil (or filename ""))))
     (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? "
@@ -1312,8 +1344,8 @@ be determined."
     ;; out to a file, and then create a file
     ;; specifier.
     (let ((file (mm-make-temp-file
-                (expand-file-name "emm.xbm"
-                                  mm-tmp-directory))))
+                (expand-file-name "emm" mm-tmp-directory)
+                nil ".xbm")))
       (unwind-protect
          (progn
            (write-region (point-min) (point-max) file)
@@ -1400,9 +1432,8 @@ If RECURSIVE, search recursively."
        (save-excursion
          (save-restriction
            (narrow-to-region start (1- (point)))
-           (when (let ((ctl (ignore-errors
-                              (mail-header-parse-content-type
-                               (mail-fetch-field "content-type")))))
+           (when (let* ((ct (mail-fetch-field "content-type"))
+                        (ctl (and ct (mail-header-parse-content-type ct))))
                    (if notp
                        (not (equal (car ctl) type))
                      (equal (car ctl) type)))
@@ -1413,9 +1444,8 @@ If RECURSIVE, search recursively."
       (save-excursion
        (save-restriction
          (narrow-to-region start end)
-         (when (let ((ctl (ignore-errors
-                            (mail-header-parse-content-type
-                             (mail-fetch-field "content-type")))))
+         (when (let* ((ct (mail-fetch-field "content-type"))
+                      (ctl (and ct (mail-header-parse-content-type ct))))
                  (if notp
                      (not (equal (car ctl) type))
                    (equal (car ctl) type)))