X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/181cb5fb657b4f226eb5f9f4d13d8ea9ede81268..b35b088608a02d43b39bbfd3240547d3d9de7366:/lisp/gnus/mm-decode.el diff --git a/lisp/gnus/mm-decode.el b/lisp/gnus/mm-decode.el index bcd6a80f1e..b5e4d3e38e 100644 --- a/lisp/gnus/mm-decode.el +++ b/lisp/gnus/mm-decode.el @@ -1,7 +1,6 @@ ;;; mm-decode.el --- Functions for decoding MIME things -;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, -;; 2007, 2008, 2009, 2010 Free Software Foundation, Inc. +;; Copyright (C) 1998-2013 Free Software Foundation, Inc. ;; Author: Lars Magne Ingebrigtsen ;; MORIOKA Tomohiko @@ -42,6 +41,10 @@ (autoload 'mm-extern-cache-contents "mm-extern") (autoload 'mm-insert-inline "mm-view") +(autoload 'mm-archive-decoders "mm-archive") +(autoload 'mm-archive-dissect-and-inline "mm-archive") +(autoload 'mm-dissect-archive "mm-archive") + (defvar gnus-current-window-configuration) (add-hook 'gnus-exit-gnus-hook 'mm-destroy-postponed-undisplay-list) @@ -115,14 +118,14 @@ "Render of HTML contents. It is one of defined renderer types, or a rendering function. The defined renderer types are: -`shr': use Gnus simple HTML renderer; -`gnus-w3m' : use Gnus renderer based on w3m; -`w3m' : use emacs-w3m; -`w3m-standalone': use w3m; +`shr': use the built-in Gnus HTML renderer; +`gnus-w3m': use Gnus renderer based on w3m; +`w3m': use emacs-w3m; +`w3m-standalone': use plain w3m; `links': use links; -`lynx' : use lynx; -`w3' : use Emacs/W3; -`html2text' : use html2text; +`lynx': use lynx; +`w3': use Emacs/W3; +`html2text': use html2text; nil : use external viewer (default web browser)." :version "24.1" :type '(choice (const shr) @@ -196,7 +199,7 @@ before the external MIME handler is invoked." ("image/tiff" mm-inline-image (lambda (handle) - (mm-valid-and-fit-image-p 'tiff handle)) ) + (mm-valid-and-fit-image-p 'tiff handle))) ("image/xbm" mm-inline-image (lambda (handle) @@ -224,20 +227,17 @@ before the external MIME handler is invoked." ("text/plain" mm-inline-text identity) ("text/enriched" mm-inline-text identity) ("text/richtext" mm-inline-text identity) - ("text/x-patch" mm-display-patch-inline - (lambda (handle) - ;; If the diff-mode.el package is installed, the function is - ;; autoloaded. Checking (locate-library "diff-mode") would be trying - ;; to cater to broken installations. OTOH checking the function - ;; makes it possible to install another package which provides an - ;; alternative implementation of diff-mode. --Stef - (fboundp 'diff-mode))) + ("text/x-patch" mm-display-patch-inline identity) ;; In case mime.types uses x-diff (as does Debian's mime-support-3.40). - ("text/x-diff" mm-display-patch-inline - (lambda (handle) (fboundp 'diff-mode))) + ("text/x-diff" mm-display-patch-inline identity) ("application/emacs-lisp" mm-display-elisp-inline identity) ("application/x-emacs-lisp" mm-display-elisp-inline identity) + ("application/x-shellscript" mm-display-shell-script-inline identity) + ("application/x-sh" mm-display-shell-script-inline identity) + ("text/x-sh" mm-display-shell-script-inline identity) + ("application/javascript" mm-display-javascript-inline identity) ("text/dns" mm-display-dns-inline identity) + ("text/x-org" mm-display-org-inline identity) ("text/html" mm-inline-text-html (lambda (handle) @@ -252,6 +252,8 @@ before the external MIME handler is invoked." ("message/partial" mm-inline-partial identity) ("message/external-body" mm-inline-external-body identity) ("text/.*" mm-inline-text identity) + ("application/x-.?tar\\(-.*\\)?" mm-archive-dissect-and-inline identity) + ("application/zip" mm-archive-dissect-and-inline identity) ("audio/wav" mm-inline-audio (lambda (handle) (and (or (featurep 'nas-sound) (featurep 'native-sound)) @@ -269,6 +271,21 @@ before the external MIME handler is invoked." ("multipart/alternative" ignore identity) ("multipart/mixed" ignore identity) ("multipart/related" ignore identity) + ("image/.*" + mm-inline-image + (lambda (handle) + (and (mm-valid-image-format-p 'imagemagick) + (mm-with-unibyte-buffer + (mm-insert-part handle) + (let ((image + (ignore-errors + (if (fboundp 'create-image) + (create-image (buffer-string) 'imagemagick 'data-p) + (mm-create-image-xemacs + (mm-handle-media-subtype handle)))))) + (when image + (setcar (cdr handle) (list "image/imagemagick")) + (mm-image-fit-p handle))))))) ;; Disable audio and image ("audio/.*" ignore ignore) ("image/.*" ignore ignore) @@ -287,6 +304,9 @@ before the external MIME handler is invoked." "application/pgp-signature" "application/x-pkcs7-signature" "application/pkcs7-signature" "application/x-pkcs7-mime" "application/pkcs7-mime" + "application/x-gtar-compressed" + "application/x-tar" + "application/zip" ;; Mutt still uses this even though it has already been withdrawn. "application/pgp") "List of media types that are to be displayed inline. @@ -313,7 +333,8 @@ 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\\'" + "text/x-org") "A list of MIME types to be displayed automatically." :type '(repeat regexp) :group 'mime-display) @@ -349,7 +370,7 @@ to: (\"text/html\" \"text/richtext\") Adding \"image/.*\" might also be useful. Spammers use it as the -prefered part of multipart/alternative messages. See also +preferred part of multipart/alternative messages. See also `gnus-buttonized-mime-types', to which adding \"multipart/alternative\" enables you to choose manually one of two types those mails include." :type '(repeat regexp) ;; See `mm-preferred-alternative-precedence'. @@ -437,6 +458,7 @@ If not set, `default-directory' will be used." (defvar mm-last-shell-command "") (defvar mm-content-id-alist nil) (defvar mm-postponed-undisplay-list nil) +(defvar mm-inhibit-auto-detect-attachment nil) ;; According to RFC2046, in particular, in a digest, the default ;; Content-Type value for a body part is changed from "text/plain" to @@ -556,7 +578,9 @@ Postpone undisplaying of viewers for types in (autoload 'message-fetch-field "message") (defun mm-dissect-buffer (&optional no-strict-mime loose-mime from) - "Dissect the current buffer and return a list of MIME handles." + "Dissect the current buffer and return a list of MIME handles. +If NO-STRICT-MIME, don't require the message to have a +MIME-Version header before proceeding." (save-excursion (let (ct ctl type subtype cte cd description id result) (save-restriction @@ -567,7 +591,13 @@ Postpone undisplaying of viewers for types in (setq ct (mail-fetch-field "content-type") ctl (and ct (mail-header-parse-content-type ct)) cte (mail-fetch-field "content-transfer-encoding") - cd (mail-fetch-field "content-disposition") + cd (or (mail-fetch-field "content-disposition") + (when (and ctl + (eq 'mm-inline-text + (cadr (mm-assoc-string-match + mm-inline-media-tests + (car ctl))))) + "inline")) ;; Newlines in description should be stripped so as ;; not to break the MIME tag into two or more lines. description (message-fetch-field "content-description") @@ -624,7 +654,7 @@ Postpone undisplaying of viewers for types in no-strict-mime (and cd (mail-header-parse-content-disposition cd)) description id) - ctl)))) + ctl from)))) (when id (when (string-match " *<\\(.*\\)> *" id) (setq id (match-string 1 id))) @@ -636,8 +666,26 @@ Postpone undisplaying of viewers for types in (if (equal "text/plain" (car ctl)) (assoc 'format ctl) t)) - (mm-make-handle - (mm-copy-to-buffer) ctl cte nil cdl description nil id))) + ;; Guess what the type of application/octet-stream parts should + ;; really be. + (let ((filename (cdr (assq 'filename (cdr cdl))))) + (when (and (not mm-inhibit-auto-detect-attachment) + (equal (car ctl) "application/octet-stream") + filename + (string-match "\\.\\([^.]+\\)$" filename)) + (let ((new-type (mailcap-extension-to-mime (match-string 1 filename)))) + (when new-type + (setcar ctl new-type))))) + (let ((handle + (mm-make-handle + (mm-copy-to-buffer) ctl cte nil cdl description nil id)) + (decoder (assoc (car ctl) (mm-archive-decoders)))) + (if (and decoder + ;; Do automatic decoding + (cadr decoder) + (executable-find (caddr decoder))) + (mm-dissect-archive handle) + handle)))) (defun mm-dissect-multipart (ctl from) (goto-char (point-min)) @@ -648,7 +696,9 @@ Postpone undisplaying of viewers for types in (goto-char (point-max)) (if (re-search-backward close-delimiter nil t) (match-beginning 0) - (point-max))))) + (point-max)))) + (mm-inhibit-auto-detect-attachment + (equal (car ctl) "multipart/encrypted"))) (setq boundary (concat (regexp-quote boundary) "[ \t]*$")) (while (and (< (point) end) (re-search-forward boundary end t)) (goto-char (match-beginning 0)) @@ -666,7 +716,7 @@ Postpone undisplaying of viewers for types in (save-restriction (narrow-to-region start end) (setq parts (nconc (list (mm-dissect-buffer t nil from)) parts))))) - (mm-possibly-verify-or-decrypt (nreverse parts) ctl))) + (mm-possibly-verify-or-decrypt (nreverse parts) ctl from))) (defun mm-copy-to-buffer () "Copy the contents of the current buffer to a fresh buffer." @@ -719,23 +769,29 @@ external if displayed external." (mail-content-type-get (mm-handle-type handle) 'name) "")) - (external mm-enable-external)) - (if (and (mm-inlinable-p ehandle) - (mm-inlined-p ehandle)) - (progn - (forward-line 1) - (mm-display-inline handle) - 'inline) - (when (or method - (not no-default)) - (if (and (not method) - (equal "text" (car (split-string type "/")))) - (progn - (forward-line 1) - (mm-insert-inline handle (mm-get-part handle)) - 'inline) - (setq external - (and method ;; If nil, we always use "save". + (external mm-enable-external) + (decoder (assoc (car (mm-handle-type handle)) + (mm-archive-decoders)))) + (cond + ((and decoder + (executable-find (caddr decoder))) + (mm-archive-dissect-and-inline handle) + 'inline) + ((and (mm-inlinable-p ehandle) + (mm-inlined-p ehandle)) + (forward-line 1) + (mm-display-inline handle) + 'inline) + ((or method + (not no-default)) + (if (and (not method) + (equal "text" (car (split-string type "/")))) + (progn + (forward-line 1) + (mm-insert-inline handle (mm-get-part handle)) + 'inline) + (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) @@ -748,12 +804,12 @@ external if displayed external." (concat " \"" (format method filename) "\"") "") - "? ")))))) - (if external - (mm-display-external - handle (or method 'mailcap-save-binary-file)) + "? ")))))) + (if external (mm-display-external - handle 'mailcap-save-binary-file))))))))) + handle (or method 'mailcap-save-binary-file)) + (mm-display-external + handle 'mailcap-save-binary-file))))))))) (declare-function gnus-configure-windows "gnus-win" (setting &optional force)) (defvar mailcap-mime-extensions) ; mailcap-mime-info autoloads @@ -901,46 +957,38 @@ external if displayed external." shell-command-switch command) (set-process-sentinel (get-buffer-process buffer) - (lexical-let ;; Don't use `let'. - ;; Function used to remove temp file and directory. - ((fn `(lambda nil - ;; Don't use `ignore-errors'. - (condition-case nil - (delete-file ,file) - (error)) - (condition-case nil - (delete-directory - ,(file-name-directory file)) - (error)))) - ;; Form uses to kill the process buffer and - ;; remove the undisplayer. - (fm `(progn - (kill-buffer ,buffer) - ,(macroexpand - (list 'mm-handle-set-undisplayer - (list 'quote handle) - nil)))) - ;; Message to be issued when the process exits. - (done (format "Displaying %s...done" command)) - ;; In particular, the timer object (which is - ;; a vector in Emacs but is a list in XEmacs) - ;; requires that it is lexically scoped. - (timer (run-at-time 2.0 nil 'ignore))) - (if (featurep 'xemacs) - (lambda (process state) - (when (eq 'exit (process-status process)) - (if (memq timer itimer-list) - (set-itimer-function timer fn) - (funcall fn)) - (ignore-errors (eval fm)) - (message "%s" done))) - (lambda (process state) - (when (eq 'exit (process-status process)) - (if (memq timer timer-list) - (timer-set-function timer fn) - (funcall fn)) - (ignore-errors (eval fm)) - (message "%s" done))))))) + (lexical-let ((outbuf outbuf) + (file file) + (buffer buffer) + (command command) + (handle handle)) + (run-at-time + 30.0 nil + (lambda () + (ignore-errors + (delete-file file)) + (ignore-errors + (delete-directory (file-name-directory file))))) + (lambda (process state) + (when (eq (process-status process) 'exit) + (condition-case nil + (delete-file file) + (error)) + (condition-case nil + (delete-directory (file-name-directory file)) + (error)) + (when (buffer-live-p outbuf) + (with-current-buffer outbuf + (let ((buffer-read-only nil) + (point (point))) + (forward-line 2) + (mm-insert-inline + handle (with-current-buffer buffer + (buffer-string))) + (goto-char point)))) + (when (buffer-live-p buffer) + (kill-buffer buffer))) + (message "Displaying %s...done" command))))) (mm-handle-set-external-undisplayer handle (cons file buffer))) (message "Displaying %s..." command)) @@ -1336,7 +1384,7 @@ Use CMD as the process." (mailcap-mime-info type 'all))) (method (let ((minibuffer-local-completion-map mm-viewer-completion-map)) - (gnus-completing-read "Viewer" methods)))) + (completing-read "Viewer: " methods)))) (when (string= method "") (error "No method given")) (if (string-match "^[^% \t]+$" method) @@ -1367,13 +1415,19 @@ Use CMD as the process." (defun mm-preferred-alternative-precedence (handles) "Return the precedence based on HANDLES and `mm-discouraged-alternatives'." - (let ((seq (nreverse (mapcar #'mm-handle-media-type - handles)))) - (dolist (disc (reverse mm-discouraged-alternatives)) - (dolist (elem (copy-sequence seq)) - (when (string-match disc elem) - (setq seq (nconc (delete elem seq) (list elem)))))) - seq)) + (setq handles (reverse handles)) + (dolist (disc (reverse mm-discouraged-alternatives)) + (dolist (handle (copy-sequence handles)) + (when (string-match disc (mm-handle-media-type handle)) + (setq handles (nconc (delete handle handles) (list handle)))))) + ;; Remove empty parts. + (dolist (handle (copy-sequence handles)) + (when (and (bufferp (mm-handle-buffer handle)) + (not (with-current-buffer (mm-handle-buffer handle) + (goto-char (point-min)) + (re-search-forward "[^ \t\n]" nil t)))) + (setq handles (nconc (delete handle handles) (list handle))))) + (mapcar #'mm-handle-media-type handles)) (defun mm-get-content-id (id) "Return the handle(s) referred to by ID." @@ -1470,8 +1524,8 @@ be determined." (let ((image (mm-get-image handle))) (or (not image) (if (featurep 'xemacs) - ;; XEmacs' glyphs can actually tell us about their width, so - ;; lets be nice and smart about them. + ;; XEmacs's glyphs can actually tell us about their width, so + ;; let's be nice and smart about them. (or mm-inline-large-images (and (<= (glyph-width image) (window-pixel-width)) (<= (glyph-height image) (window-pixel-height)))) @@ -1569,7 +1623,7 @@ If RECURSIVE, search recursively." (autoload 'mm-view-pkcs7 "mm-view") -(defun mm-possibly-verify-or-decrypt (parts ctl) +(defun mm-possibly-verify-or-decrypt (parts ctl &optional from) (let ((type (car ctl)) (subtype (cadr (split-string (car ctl) "/"))) (mm-security-handle ctl) ;; (car CTL) is the type. @@ -1584,7 +1638,7 @@ If RECURSIVE, search recursively." ((eq mm-decrypt-option 'known) t) (t (y-or-n-p (format "Decrypt (S/MIME) part? ")))) - (mm-view-pkcs7 parts)) + (mm-view-pkcs7 parts from)) (setq parts (mm-dissect-buffer t))))) ((equal subtype "signed") (unless (and (setq protocol @@ -1687,23 +1741,27 @@ If RECURSIVE, search recursively." (start end &optional base-url)) (declare-function shr-insert-document "shr" (dom)) (defvar shr-blocked-images) +(defvar gnus-inhibit-images) (autoload 'gnus-blocked-images "gnus-art") (defun mm-shr (handle) ;; Require since we bind its variables. (require 'shr) (let ((article-buffer (current-buffer)) - (shr-blocked-images (if (and (boundp 'gnus-summary-buffer) - (buffer-name gnus-summary-buffer)) - (with-current-buffer gnus-summary-buffer - (gnus-blocked-images)) - shr-blocked-images)) (shr-content-function (lambda (id) (let ((handle (mm-get-content-id id))) (when handle (mm-with-part handle (buffer-string)))))) - charset) + shr-inhibit-images shr-blocked-images charset char) + (if (and (boundp 'gnus-summary-buffer) + (bufferp gnus-summary-buffer) + (buffer-name gnus-summary-buffer)) + (with-current-buffer gnus-summary-buffer + (setq shr-inhibit-images gnus-inhibit-images + shr-blocked-images (gnus-blocked-images))) + (setq shr-inhibit-images gnus-inhibit-images + shr-blocked-images (gnus-blocked-images))) (unless handle (setq handle (mm-dissect-buffer t))) (setq charset (mail-content-type-get (mm-handle-type handle) 'charset)) @@ -1711,14 +1769,33 @@ If RECURSIVE, search recursively." (narrow-to-region (point) (point)) (shr-insert-document (mm-with-part handle - (when (and charset - (setq charset (mm-charset-to-coding-system charset)) - (not (eq charset 'ascii))) - (insert (prog1 - (mm-decode-coding-string (buffer-string) charset) - (erase-buffer) - (mm-enable-multibyte)))) + (insert (prog1 + (if (and charset + (setq charset + (mm-charset-to-coding-system charset + nil t)) + (not (eq charset 'ascii))) + (mm-decode-coding-string (buffer-string) charset) + (mm-string-as-multibyte (buffer-string))) + (erase-buffer) + (mm-enable-multibyte))) + (goto-char (point-min)) + (setq case-fold-search t) + (while (re-search-forward + "&#\\(?:x\\([89][0-9a-f]\\)\\|\\(1[2-5][0-9]\\)\\);" nil t) + (when (setq char + (cdr (assq (if (match-beginning 1) + (string-to-number (match-string 1) 16) + (string-to-number (match-string 2))) + mm-extra-numeric-entities))) + (replace-match (char-to-string char)))) + ;; Remove "soft hyphens". + (goto-char (point-min)) + (while (search-forward "­" nil t) + (replace-match "" t t)) (libxml-parse-html-region (point-min) (point-max)))) + (unless (bobp) + (insert "\n")) (mm-handle-set-undisplayer handle `(lambda () @@ -1726,6 +1803,17 @@ If RECURSIVE, search recursively." (delete-region ,(point-min-marker) ,(point-max-marker)))))))) +(defun mm-handle-filename (handle) + "Return filename of HANDLE if any." + (or (mail-content-type-get (mm-handle-type handle) + 'name) + (mail-content-type-get (mm-handle-disposition handle) + 'filename))) + (provide 'mm-decode) +;; Local Variables: +;; coding: iso-8859-1 +;; End: + ;;; mm-decode.el ends here