;;; mm-decode.el --- Functions for decoding MIME things
-;; Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+;; Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
;; MORIOKA Tomohiko <morioka@jaist.ac.jp>
(eval-and-compile
(autoload 'mm-inline-partial "mm-partial")
- (autoload 'mm-inline-external-body "mm-extern"))
+ (autoload 'mm-inline-external-body "mm-extern")
+ (autoload 'mm-insert-inline "mm-view"))
(defgroup mime-display ()
"Display of MIME in mail and news articles."
:link '(custom-manual "(emacs-mime)Customization")
+ :version "21.1"
:group 'mail
:group 'news
:group 'multimedia)
`(nth 7 ,handle))
(defmacro mm-handle-multipart-original-buffer (handle)
`(get-text-property 0 'buffer (car ,handle)))
+(defmacro mm-handle-multipart-from (handle)
+ `(get-text-property 0 'from (car ,handle)))
(defmacro mm-handle-multipart-ctl-parameter (handle parameter)
`(get-text-property 0 ,parameter (car ,handle)))
mm-inline-image
(lambda (handle)
(mm-valid-and-fit-image-p 'bmp handle)))
+ ("image/x-portable-bitmap"
+ mm-inline-image
+ (lambda (handle)
+ (mm-valid-and-fit-image-p 'pbm handle)))
("text/plain" mm-inline-text identity)
("text/enriched" mm-inline-text identity)
("text/richtext" mm-inline-text identity)
"List of media types that are to be displayed inline."
:type '(repeat string)
:group 'mime-display)
-
+
(defcustom mm-automatic-display
'("text/plain" "text/enriched" "text/richtext" "text/html"
"text/x-vcard" "image/.*" "message/delivery-status" "multipart/.*"
:type '(repeat string)
:group 'mime-display)
-(defvar mm-tmp-directory
+(defcustom mm-tmp-directory
(cond ((fboundp 'temp-directory) (temp-directory))
((boundp 'temporary-file-directory) temporary-file-directory)
("/tmp/"))
- "Where mm will store its temporary files.")
+ "Where mm will store its temporary files."
+ :type 'directory
+ :group 'mime-display)
(defcustom mm-inline-large-images nil
"If non-nil, then all images fit in the buffer."
:type 'boolean
:group 'mime-display)
+(defcustom mm-default-directory nil
+ "The default directory where mm will save files.
+If not set, `default-directory' will be used."
+ :type 'directory
+ :group 'mime-display)
+
;;; Internal variables.
(defvar mm-dissection-list nil)
(autoload 'mml2015-verify "mml2015")
(autoload 'mml2015-verify-test "mml2015")
(autoload 'mml-smime-verify "mml-smime")
+(autoload 'mml-smime-verify-test "mml-smime")
(defvar mm-verify-function-alist
'(("application/pgp-signature" mml2015-verify "PGP" mml2015-verify-test)
- ("application/pkcs7-signature" mml-smime-verify "S/MIME" nil)
- ("application/x-pkcs7-signature" mml-smime-verify "S/MIME" nil)))
-
-(defcustom mm-verify-option 'known
+ ("application/x-gnus-pgp-signature" mm-uu-pgp-signed-extract-1 "PGP"
+ mm-uu-pgp-signed-test)
+ ("application/pkcs7-signature" mml-smime-verify "S/MIME"
+ mml-smime-verify-test)
+ ("application/x-pkcs7-signature" mml-smime-verify "S/MIME"
+ mml-smime-verify-test)))
+
+(defcustom mm-verify-option 'never
"Option of verifying signed parts.
-`never', not verify; `always', always verify;
+`never', not verify; `always', always verify;
`known', only verify known protocols. Otherwise, ask user."
:type '(choice (item always)
(item never)
(autoload 'mml2015-decrypt-test "mml2015")
(defvar mm-decrypt-function-alist
- '(("application/pgp-encrypted" mml2015-decrypt "PGP" mml2015-decrypt-test)))
+ '(("application/pgp-encrypted" mml2015-decrypt "PGP" mml2015-decrypt-test)
+ ("application/x-gnus-pgp-encrypted" mm-uu-pgp-encrypted-extract-1 "PGP"
+ mm-uu-pgp-encrypted-test)))
-(defcustom mm-decrypt-option 'known
- "Option of decrypting signed parts.
-`never', not decrypt; `always', always decrypt;
+(defcustom mm-decrypt-option nil
+ "Option of decrypting encrypted parts.
+`never', not decrypt; `always', always decrypt;
`known', only decrypt known protocols. Otherwise, ask user."
:type '(choice (item always)
(item never)
"Keymap for input viewer with completion.")
;; Should we bind other key to minibuffer-complete-word?
-(define-key mm-viewer-completion-map " " 'self-insert-command)
+(define-key mm-viewer-completion-map " " 'self-insert-command)
+
+(defvar mm-viewer-completion-map
+ (let ((map (make-sparse-keymap 'mm-viewer-completion-map)))
+ (set-keymap-parent map minibuffer-local-completion-map)
+ map)
+ "Keymap for input viewer with completion.")
+
+;; Should we bind other key to minibuffer-complete-word?
+(define-key mm-viewer-completion-map " " 'self-insert-command)
;;; The functions.
(defun mm-dissect-buffer (&optional no-strict-mime)
"Dissect the current buffer and return a list of MIME handles."
(save-excursion
- (let (ct ctl type subtype cte cd description id result)
+ (let (ct ctl type subtype cte cd description id result from)
(save-restriction
(mail-narrow-to-head)
(when (or no-strict-mime
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"))))
+ from (mail-fetch-field "from")
+ id (mail-fetch-field "content-id"))
+ ;; 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
+ ;; solution, avoids most of them.
+ (if from
+ (setq from (cadr (mail-extract-address-components from))))))
(when cte
(setq cte (mail-header-strip cte)))
(if (or (not ctl)
(add-text-properties 0 (length (car ctl))
(list 'buffer (mm-copy-to-buffer))
(car ctl))
+ (add-text-properties 0 (length (car ctl))
+ (list 'from from)
+ (car ctl))
(cons (car ctl) (mm-dissect-multipart ctl))))
(t
(mm-dissect-singlepart
(match-beginning 0)
(point-max)))))
(setq boundary (concat (regexp-quote boundary) "[ \t]*$"))
- (while (re-search-forward boundary end t)
+ (while (and (< (point) end) (re-search-forward boundary end t))
(goto-char (match-beginning 0))
(when start
(save-excursion
(setq parts (nconc (list (mm-dissect-buffer t)) parts)))))
(forward-line 2)
(setq start (point)))
- (when start
+ (when (and start (< start end))
(save-excursion
(save-restriction
(narrow-to-region start end)
(mm-handle-set-undisplayer handle (cons file buffer)))
(message "Displaying %s..." (format method file))
'external)))))))
-
+
(defun mm-mailcap-command (method file type-list)
(let ((ctl (cdr type-list))
(beg 0)
(kill-buffer (get-text-property 0 'buffer handle))))
((and (listp handle)
(stringp (car handle)))
- (mm-destroy-parts (cdr handle)))
+ (mm-destroy-parts handle))
(t
(mm-destroy-part handle)))))))
(defun mm-get-part (handle)
"Return the contents of HANDLE as a string."
(mm-with-unibyte-buffer
- (mm-insert-part handle)
+ (insert (with-current-buffer (mm-handle-buffer handle)
+ (mm-with-unibyte-current-buffer-mule4
+ (buffer-string))))
+ (mm-decode-content-transfer-encoding
+ (mm-handle-encoding handle)
+ (mm-handle-media-type handle))
(buffer-string)))
(defun mm-insert-part (handle)
(set-buffer cur)
(insert-buffer-substring temp)))))))
-(defvar mm-default-directory nil)
-
(defun mm-save-part (handle)
"Write HANDLE to a file."
(let* ((name (mail-content-type-get (mm-handle-type handle) 'name))
(completing-read "Viewer: " methods))))
(when (string= method "")
(error "No method given"))
- (if (string-match "^[^% \t]+$" method)
+ (if (string-match "^[^% \t]+$" method)
(setq method (concat method " %s")))
- (mm-display-external (copy-sequence handle) method)))
+ (mm-display-external handle method)))
(defun mm-preferred-alternative (handles &optional preferred)
"Say which of HANDLES are preferred."
"xpm")
((equal type "x-xbitmap")
"xbm")
+ ((equal type "x-portable-bitmap")
+ "pbm")
(t type)))
(or (mm-handle-cache handle)
(mm-with-unibyte-buffer
(and (mm-valid-image-format-p format)
(mm-image-fit-p handle)))
-(defun mm-find-part-by-type (handles type &optional notp recursive)
+(defun mm-find-part-by-type (handles type &optional notp recursive)
"Search in HANDLES for part with TYPE.
If NOTP, returns first non-matching part.
If RECURSIVE, search recursively."
(setq handles (cdr handles)))
handle))
-(defun mm-find-raw-part-by-type (ctl type &optional notp)
+(defun mm-find-raw-part-by-type (ctl type &optional notp)
(goto-char (point-min))
- (let* ((boundary (concat "\n--" (mail-content-type-get ctl 'boundary)))
- (close-delimiter (concat (regexp-quote boundary) "--[ \t]*$"))
+ (let* ((boundary (concat "--" (mm-handle-multipart-ctl-parameter ctl
+ 'boundary)))
+ (close-delimiter (concat "^" (regexp-quote boundary) "--[ \t]*$"))
start
(end (save-excursion
(goto-char (point-max))
(match-beginning 0)
(point-max))))
result)
- (setq boundary (concat (regexp-quote boundary) "[ \t]*$"))
+ (setq boundary (concat "^" (regexp-quote boundary) "[ \t]*$"))
(while (and (not result)
(re-search-forward boundary end t))
(goto-char (match-beginning 0))
(when start
(save-excursion
(save-restriction
- (narrow-to-region start (point))
- (when (let ((ctl (ignore-errors
- (mail-header-parse-content-type
+ (narrow-to-region start (1- (point)))
+ (when (let ((ctl (ignore-errors
+ (mail-header-parse-content-type
(mail-fetch-field "content-type")))))
(if notp
(not (equal (car ctl) type))
(equal (car ctl) type)))
(setq result (buffer-substring (point-min) (point-max)))))))
- (forward-line 2)
+ (forward-line 1)
(setq start (point)))
(when (and (not result) start)
(save-excursion
(save-restriction
(narrow-to-region start end)
- (when (let ((ctl (ignore-errors
- (mail-header-parse-content-type
+ (when (let ((ctl (ignore-errors
+ (mail-header-parse-content-type
(mail-fetch-field "content-type")))))
(if notp
(not (equal (car ctl) type))
(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
+ (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) "/")))
(mm-security-handle ctl) ;; (car CTL) is the type.
protocol func functest)
- (cond
+ (cond
((equal subtype "signed")
- (unless (and (setq protocol (mail-content-type-get ctl 'protocol))
+ (unless (and (setq protocol
+ (mm-handle-multipart-ctl-parameter ctl 'protocol))
(not (equal protocol "multipart/mixed")))
;; The message is broken or draft-ietf-openpgp-multsig-01.
(let ((protocols 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
+ ((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
(save-excursion
(if func
(funcall func parts ctl)
- (mm-set-handle-multipart-parameter
- mm-security-handle 'gnus-details
+ (mm-set-handle-multipart-parameter
+ mm-security-handle 'gnus-details
(format "Unknown sign protocol (%s)" protocol))))))
((equal subtype "encrypted")
- (unless (setq protocol (mail-content-type-get ctl 'protocol))
+ (unless (setq protocol
+ (mm-handle-multipart-ctl-parameter ctl 'protocol))
;; The message is broken.
(let ((parts parts))
(while parts
- (if (assoc (mm-handle-media-type (car parts))
+ (if (assoc (mm-handle-media-type (car parts))
mm-decrypt-function-alist)
(setq protocol (mm-handle-media-type (car parts))
parts nil)
((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
+ (and func
+ (or (not (setq functest
+ (nth 3 (assoc protocol
mm-decrypt-function-alist))))
(funcall functest parts ctl))))
- (t (y-or-n-p
+ (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
+ (mm-set-handle-multipart-parameter
+ mm-security-handle 'gnus-details
(format "Unknown encrypt protocol (%s)" protocol))))))
(t nil))
parts))
+(defun mm-multiple-handles (handles)
+ (and (listp (car handles))
+ (> (length handles) 1)))
+
+(defun mm-merge-handles (handles1 handles2)
+ (append
+ (if (listp (car handles1))
+ handles1
+ (list handles1))
+ (if (listp (car handles2))
+ handles2
+ (list handles2))))
+
(provide 'mm-decode)
;;; mm-decode.el ends here