;;; mm-decode.el --- Functions for decoding MIME things
-;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-;; 2005, 2006 Free Software Foundation, Inc.
+;; Copyright (C) 1998-2012 Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
;; MORIOKA Tomohiko <morioka@jaist.ac.jp>
;; This file is part of GNU Emacs.
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
-;; any later version.
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;;; Code:
+;; For Emacs <22.2 and XEmacs.
+(eval-and-compile
+ (unless (fboundp 'declare-function) (defmacro declare-function (&rest r))))
+
(require 'mail-parse)
-(require 'mailcap)
(require 'mm-bodies)
+(require 'mm-archive)
(eval-when-compile (require 'cl)
(require 'term))
-(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"))
+(autoload 'gnus-map-function "gnus-util")
+(autoload 'gnus-replace-in-string "gnus-util")
+(autoload 'gnus-read-shell-command "gnus-util")
+
+(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)
,disposition ,description ,cache ,id))
(defcustom mm-text-html-renderer
- (cond ((locate-library "w3") 'w3)
- ((executable-find "w3m") (if (locate-library "w3m")
- 'w3m
- 'w3m-standalone))
+ (cond ((fboundp 'libxml-parse-html-region) 'shr)
+ ((executable-find "w3m") 'gnus-w3m)
((executable-find "links") 'links)
((executable-find "lynx") 'lynx)
- (t 'html2text))
+ ((locate-library "w3") 'w3)
+ ((locate-library "html2text") 'html2text)
+ (t nil))
"Render of HTML contents.
It is one of defined renderer types, or a rendering function.
The defined renderer types are:
-`w3' : use Emacs/W3;
-`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;
-`html2text' : use html2text;
-nil : use external viewer."
- :version "22.1"
- :type '(choice (const w3)
- (const w3m)
- (const w3m-standalone)
+`lynx': use lynx;
+`w3': use Emacs/W3;
+`html2text': use html2text;
+nil : use external viewer (default web browser)."
+ :version "24.1"
+ :type '(choice (const shr)
+ (const gnus-w3m)
+ (const w3)
+ (const w3m :tag "emacs-w3m")
+ (const w3m-standalone :tag "standalone w3m" )
(const links)
(const lynx)
(const html2text)
- (const nil)
+ (const nil :tag "External viewer")
(function))
: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 HTML contents with
the <img> tags. It has no effect on Emacs/w3. See also the
("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)
("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 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)
- (or mm-inline-text-html-renderer
- mm-text-html-renderer)))
+ mm-text-html-renderer))
("text/x-vcard"
mm-inline-text-vcard
(lambda (handle)
("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))
("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)
"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.
"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)
(\"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'.
:group 'mime-display)
(defcustom mm-inline-large-images nil
- "If non-nil, then all images fit in the buffer."
- :type 'boolean
+ "If t, then all images fit in the buffer.
+If 'resize, try to resize the images so they fit."
+ :type '(radio
+ (const :tag "Inline large images as they are." t)
+ (const :tag "Resize large images." resize)
+ (const :tag "Do not inline large images." nil))
:group 'mime-display)
-(defvar mm-file-name-rewrite-functions
+(defcustom mm-file-name-rewrite-functions
'(mm-file-name-delete-control mm-file-name-delete-gotchas)
- "*List of functions used for rewriting file names of MIME parts.
+ "List of functions used for rewriting file names of MIME parts.
Each function takes a file name as input and returns a file name.
-Ready-made functions include
-`mm-file-name-delete-control'
-`mm-file-name-delete-gotchas'
-`mm-file-name-delete-whitespace',
-`mm-file-name-trim-whitespace',
-`mm-file-name-collapse-whitespace',
-`mm-file-name-replace-whitespace',
-`capitalize', `downcase', `upcase', and
-`upcase-initials'.")
+Ready-made functions include `mm-file-name-delete-control',
+`mm-file-name-delete-gotchas' (you should not remove these two
+functions), `mm-file-name-delete-whitespace',
+`mm-file-name-trim-whitespace', `mm-file-name-collapse-whitespace',
+`mm-file-name-replace-whitespace', `capitalize', `downcase',
+`upcase', and `upcase-initials'."
+ :type '(list (set :inline t
+ (const mm-file-name-delete-control)
+ (const mm-file-name-delete-gotchas)
+ (const mm-file-name-delete-whitespace)
+ (const mm-file-name-trim-whitespace)
+ (const mm-file-name-collapse-whitespace)
+ (const mm-file-name-replace-whitespace)
+ (const capitalize)
+ (const downcase)
+ (const upcase)
+ (const upcase-initials)
+ (repeat :inline t
+ :tag "Function"
+ function)))
+ :version "23.1" ;; No Gnus
+ :group 'mime-display)
+
(defvar mm-path-name-rewrite-functions nil
"*List of functions for rewriting the full file names of MIME parts.
(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)
(message "Destroying external MIME viewers")
(mm-destroy-parts mm-postponed-undisplay-list)))
+(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."
(save-excursion
(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")
- description (mail-fetch-field "content-description")
+ 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")
id (mail-fetch-field "content-id"))
(unless from
(setq from (mail-fetch-field "from")))
;; creates unibyte buffers. This `if', though not a perfect
;; solution, avoids most of them.
(if from
- (setq from (cadr (mail-extract-address-components from))))))
+ (setq from (cadr (mail-extract-address-components from))))
+ (if description
+ (setq description (mail-decode-encoded-word-string
+ description)))))
(if (or (not ctl)
(not (string-match "/" (car ctl))))
(mm-dissect-singlepart
description)
(setq type (split-string (car ctl) "/"))
(setq subtype (cadr type)
- type (pop type))
+ type (car type))
(setq
result
(cond
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)))
(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 (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))
(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."
- (save-excursion
- (let ((obuf (current-buffer))
- beg)
- (goto-char (point-min))
- (search-forward-regexp "^\n" nil t)
- (setq beg (point))
- (set-buffer
- ;; Preserve the data's unibyteness (for url-insert-file-contents).
- (let ((default-enable-multibyte-characters (mm-multibyte-p)))
- (generate-new-buffer " *mm*")))
+ (let ((obuf (current-buffer))
+ (mb (mm-multibyte-p))
+ beg)
+ (goto-char (point-min))
+ (search-forward-regexp "^\n" nil t)
+ (setq beg (point))
+ (with-current-buffer
+ (generate-new-buffer " *mm*")
+ ;; Preserve the data's unibyteness (for url-insert-file-contents).
+ (mm-set-buffer-multibyte mb)
(insert-buffer-substring obuf beg)
(current-buffer))))
(goto-char (point-max)))
(mapcar 'mm-display-parts handle))))
-(defun mm-display-part (handle &optional no-default)
+(autoload 'mailcap-parse-mailcaps "mailcap")
+(autoload 'mailcap-mime-info "mailcap")
+
+(defun mm-display-part (handle &optional no-default force)
"Display the MIME part represented by HANDLE.
Returns nil if the part is removed; inline if displayed inline;
external if displayed external."
(save-excursion
(mailcap-parse-mailcaps)
- (if (mm-handle-displayed-p handle)
+ (if (and (not force)
+ (mm-handle-displayed-p handle))
(mm-remove-part handle)
(let* ((ehandle (if (equal (mm-handle-media-type handle)
"message/external-body")
(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)
(concat
" \"" (format method filename) "\"")
"")
- "? ")))))
- (setq external t)
- (setq external nil))
+ "? "))))))
(if external
(mm-display-external
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
+
(defun mm-display-external (handle method)
"Display HANDLE using METHOD."
(let ((outbuf (current-buffer)))
(set-buffer (generate-new-buffer " *mm*"))
(setq method nil))
(mm-insert-part handle)
+ (mm-add-meta-html-tag handle)
(let ((win (get-buffer-window cur t)))
(when win
(select-window win)))
(mm-handle-set-undisplayer handle mm)))))
;; The function is a string to be executed.
(mm-insert-part handle)
+ (mm-add-meta-html-tag handle)
(let* ((dir (mm-make-temp-file
(expand-file-name "emm." mm-tmp-directory) 'dir))
(filename (or
(copiousoutput (assoc "copiousoutput" mime-info))
file buffer)
;; We create a private sub-directory where we store our files.
- (set-file-modes dir 448)
+ (set-file-modes dir #o700)
(if filename
(setq file (expand-file-name
(gnus-map-function mm-file-name-rewrite-functions
nil suffix))))
(let ((coding-system-for-write mm-binary-coding-system))
(write-region (point-min) (point-max) file nil 'nomesg))
+ ;; The fi