X-Git-Url: http://git.chise.org/gitweb/?a=blobdiff_plain;f=mime-view.el;h=1f53690d85b436c4b947e5d40d3d325d0e6bb9b7;hb=refs%2Fheads%2Femiko-1_14;hp=eeb39e2bab6ab59027de76925d3f664deed11208;hpb=bed6824648cdf07d80c42165edea620f52a8d724;p=elisp%2Fsemi.git diff --git a/mime-view.el b/mime-view.el index eeb39e2..1f53690 100644 --- a/mime-view.el +++ b/mime-view.el @@ -22,17 +22,19 @@ ;; 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., 59 Temple Place - Suite 330, -;; Boston, MA 02111-1307, USA. +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. ;;; Code: -(require 'emu) (require 'mime) (require 'semi-def) (require 'calist) (require 'alist) -(require 'mailcap) +(require 'mime-conf) +(require 'mcharset) + +(eval-when-compile (require 'static)) ;;; @ version @@ -67,6 +69,17 @@ buttom. Nil means don't scroll at all." (const :tag "On" t) (sexp :tag "Situation" 1))) +(defcustom mime-view-mailcap-files + (let ((files '("/etc/mailcap" "/usr/etc/mailcap" "~/.mailcap"))) + (or (member mime-mailcap-file files) + (setq files (cons mime-mailcap-file files))) + files) + "List of mailcap files." + :group 'mime-view + :type '(repeat file)) + +(defvar mime-view-automatic-conversion 'undecided) + ;;; @ in raw-buffer (representation space) ;;; @@ -79,8 +92,7 @@ buttom. Nil means don't scroll at all." (defvar mime-raw-representation-type-alist '((mime-show-message-mode . binary) (mime-temp-message-mode . binary) - (t . cooked) - ) + (t . cooked)) "Alist of major-mode vs. representation-type of mime-raw-buffer. Each element looks like (SYMBOL . REPRESENTATION-TYPE). SYMBOL is major-mode or t. t means default. REPRESENTATION-TYPE must be @@ -112,8 +124,7 @@ mother-buffer." (if (and recursive mime-mother-buffer) (save-excursion (set-buffer mime-mother-buffer) - (mime-preview-original-major-mode recursive) - ) + (mime-preview-original-major-mode recursive)) (cdr (assq 'major-mode (get-text-property (or point (if (> (point) (buffer-size)) @@ -133,15 +144,13 @@ mother-buffer." (setq rest (or (mime-entity-content-type entity) (make-mime-content-type 'text 'plain)) situation (cons (car rest) situation) - rest (cdr rest)) - ) + rest (cdr rest))) (unless (assq 'subtype situation) (or rest (setq rest (or (cdr (mime-entity-content-type entity)) '((subtype . plain))))) (setq situation (cons (car rest) situation) - rest (cdr rest)) - ) + rest (cdr rest))) (while rest (setq param (car rest)) (or (assoc (car param) situation) @@ -156,8 +165,7 @@ mother-buffer." (setq situation (cons (cons 'disposition-type (mime-content-disposition-type rest)) situation) - rest (mime-content-disposition-parameters rest)) - )) + rest (mime-content-disposition-parameters rest)))) (while rest (setq param (car rest) name (car param)) @@ -207,8 +215,7 @@ mother-buffer." (cell (assq field situation))) (if cell (or (memq (cdr cell) ignored-values) - (setq dest (cons situation dest)) - ))) + (setq dest (cons situation dest))))) (setq situations (cdr situations))) dest)) @@ -222,13 +229,9 @@ mother-buffer." (when ecell (if (equal cell ecell) (setq match (1+ match)) - (setq example (delq ecell example)) - )) - ) - (setq situation (cdr situation)) - ) - (cons match example) - )) + (setq example (delq ecell example))))) + (setq situation (cdr situation))) + (cons match example))) (defun mime-sort-situation (situation) (sort situation @@ -240,30 +243,23 @@ mother-buffer." (mode . 3) (method . 4) (major-mode . 5) - (disposition-type . 6) - )) + (disposition-type . 6))) a-order b-order) (if (symbolp a-t) (let ((ret (assq a-t order))) (if ret (setq a-order (cdr ret)) - (setq a-order 7) - )) - (setq a-order 8) - ) + (setq a-order 7))) + (setq a-order 8)) (if (symbolp b-t) (let ((ret (assq b-t order))) (if ret (setq b-order (cdr ret)) - (setq b-order 7) - )) - (setq b-order 8) - ) + (setq b-order 7))) + (setq b-order 8)) (if (= a-order b-order) (string< (format "%s" a-t)(format "%s" b-t)) - (< a-order b-order)) - ))) - ) + (< a-order b-order)))))) (defun mime-unify-situations (entity-situation condition situation-examples @@ -296,21 +292,18 @@ mother-buffer." (setq max-score ret-score max-escore (cdar examples) max-examples (list (cdr ret)) - max-situations (list situation)) - ) + max-situations (list situation))) ((= ret-score max-score) (cond ((> (cdar examples) max-escore) (setq max-escore (cdar examples) max-examples (list (cdr ret)) - max-situations (list situation)) - ) + max-situations (list situation))) ((= (cdar examples) max-escore) (setq max-examples (cons (cdr ret) max-examples)) (or (member situation max-situations) (setq max-situations - (cons situation max-situations))) - ))))) + (cons situation max-situations)))))))) (setq examples (cdr examples)))) (setq rest (cdr rest))) (when max-situations @@ -323,10 +316,8 @@ mother-buffer." (setcdr cell (1+ (cdr cell))) (setq situation-examples (cons (cons example 0) - situation-examples)) - )) - (setq max-examples (cdr max-examples)) - ))))) + situation-examples)))) + (setq max-examples (cdr max-examples))))))) (cons ret situation-examples) ;; ret: list of situations ;; situation-examples: new examples (notoce that contents of @@ -361,10 +352,58 @@ mother-buffer." (defvar mime-acting-situation-example-list-max-size 16) (defvar mime-situation-examples-file-coding-system nil) +(defun mime-view-read-situation-examples-file (&optional file) + (or file + (setq file mime-situation-examples-file)) + (if (and file + (file-readable-p file)) + (with-temp-buffer + (insert-file-contents file) + (setq mime-situation-examples-file-coding-system + (static-cond + ((boundp 'buffer-file-coding-system) + (symbol-value 'buffer-file-coding-system)) + ((boundp 'file-coding-system) + (symbol-value 'file-coding-system)) + (t nil)) + ;; (and (boundp 'buffer-file-coding-system) + ;; buffer-file-coding-system) + ) + (condition-case error + (eval-buffer) + (error (message "%s is broken: %s" file (cdr error)))) + ;; format check + (condition-case nil + (let ((i 0)) + (while (and (> (length mime-preview-situation-example-list) + mime-preview-situation-example-list-max-size) + (< i 16)) + (setq mime-preview-situation-example-list + (mime-reduce-situation-examples + mime-preview-situation-example-list)) + (setq i (1+ i)))) + (error (setq mime-preview-situation-example-list nil))) + ;; (let ((rest mime-preview-situation-example-list)) + ;; (while rest + ;; (ctree-set-calist-strictly 'mime-preview-condition + ;; (caar rest)) + ;; (setq rest (cdr rest)))) + (condition-case nil + (let ((i 0)) + (while (and (> (length mime-acting-situation-example-list) + mime-acting-situation-example-list-max-size) + (< i 16)) + (setq mime-acting-situation-example-list + (mime-reduce-situation-examples + mime-acting-situation-example-list)) + (setq i (1+ i)))) + (error (setq mime-acting-situation-example-list nil)))))) + (defun mime-save-situation-examples () (if (or mime-preview-situation-example-list mime-acting-situation-example-list) - (let ((file mime-situation-examples-file)) + (let ((file mime-situation-examples-file) + print-length print-level) (with-temp-buffer (insert ";;; " (file-name-nondirectory file) "\n") (insert "\n;; This file is generated automatically by " @@ -388,6 +427,8 @@ mother-buffer." ((boundp 'file-coding-system) (setq file-coding-system mime-situation-examples-file-coding-system))) + ;; (setq buffer-file-coding-system + ;; mime-situation-examples-file-coding-system) (setq buffer-file-name file) (save-buffer))))) @@ -422,8 +463,7 @@ mother-buffer." min-freq freq d-i i d-j j - dest (cons (cdr ret) freq)) - ) + dest (cons (cdr ret) freq))) ((= max-sim sim) (cond ((> min-det-ret det-ret) (setq min-det-ret det-ret @@ -431,27 +471,20 @@ mother-buffer." min-freq freq d-i i d-j j - dest (cons (cdr ret) freq)) - ) + dest (cons (cdr ret) freq))) ((= min-det-ret det-ret) (cond ((> min-det-org det-org) (setq min-det-org det-org min-freq freq d-i i d-j j - dest (cons (cdr ret) freq)) - ) + dest (cons (cdr ret) freq))) ((= min-det-org det-org) (cond ((> min-freq freq) (setq min-freq freq d-i i d-j j - dest (cons (cdr ret) freq)) - )) - )) - )) - )) - ) + dest (cons (cdr ret) freq))))))))))) (setq jr (cdr jr) j (1+ j))) (setq ir (cdr ir) @@ -466,8 +499,7 @@ mother-buffer." (setq situation-examples (cdr situation-examples)) (setq ir (nthcdr (1- d-i) situation-examples)) - (setcdr ir (cddr ir)) - ) + (setcdr ir (cddr ir))) (if (setq ir (assoc (car dest) situation-examples)) (progn (setcdr ir (+ (cdr ir)(cdr dest))) @@ -516,11 +548,9 @@ mother-buffer." (if (consp entity-node-id) (mapconcat (function (lambda (num) - (format "%s" (1+ num)) - )) + (format "%s" (1+ num)))) (reverse entity-node-id) ".") - "0")) - )) + "0")))) (cond (access-type (let ((server (assoc "server" params))) (setq access-type (cdr access-type)) @@ -529,15 +559,12 @@ mother-buffer." num subject access-type (cdr server)) (let ((site (cdr (assoc "site" params))) (dir (cdr (assoc "directory" params))) - (url (cdr (assoc "url" params))) - ) + (url (cdr (assoc "url" params)))) (if url (format "%s %s ([%s] %s)" num subject access-type url) (format "%s %s ([%s] %s:%s)" - num subject access-type site dir)) - ))) - ) + num subject access-type site dir)))))) (t (let ((media-type (mime-entity-media-type entity)) (media-subtype (mime-entity-media-subtype entity)) @@ -556,10 +583,8 @@ mother-buffer." "")))) (if (>= (+ (current-column)(length rest))(window-width)) "\n\t") - rest))) - ))) - (function mime-preview-play-current-entity)) - )) + rest)))))) + (function mime-preview-play-current-entity)))) ;;; @@ entity-header @@ -597,8 +622,7 @@ Each elements are regexp of field-name.") field-type field-value) (let ((s-field (assq field-type calist))) (cond ((null s-field) - (cons (cons field-type field-value) calist) - ) + (cons (cons field-type field-value) calist)) (t calist)))) (define-calist-field-match-method @@ -607,6 +631,19 @@ Each elements are regexp of field-name.") (define-calist-field-match-method 'body #'mime-calist::field-match-method-as-default-rule) +(defun mime-calist::field-match-method-ignore-case (calist + field-type field-value) + (let ((s-field (assoc field-type calist))) + (cond ((null s-field) + (cons (cons field-type field-value) calist)) + ((eq field-value t) + calist) + ((string= (downcase (cdr s-field)) (downcase field-value)) + calist)))) + +(define-calist-field-match-method + 'access-type #'mime-calist::field-match-method-ignore-case) + (defvar mime-preview-condition nil "Condition-tree about how to display entity.") @@ -649,6 +686,15 @@ Each elements are regexp of field-name.") '((body . visible) (body-presentation-method . mime-display-text/plain))) +(defvar mime-preview-fill-flowed-text + (module-installed-p 'flow-fill) + "If non-nil, fill RFC2646 \"flowed\" text.") + +(autoload 'fill-flowed "flow-fill") + +(defvar mime-preview-inline-fontify t + "If non-nil, fontify the inline part.") + (ctree-set-calist-strictly 'mime-preview-condition '((type . nil) @@ -677,6 +723,12 @@ Each elements are regexp of field-name.") (ctree-set-calist-strictly 'mime-preview-condition + '((type . application)(subtype . emacs-lisp) + (body . visible) + (body-presentation-method . mime-display-application/emacs-lisp))) + +(ctree-set-calist-strictly + 'mime-preview-condition '((type . text)(subtype . t) (body . visible) (body-presentation-method . mime-display-text/plain))) @@ -689,6 +741,12 @@ Each elements are regexp of field-name.") (ctree-set-calist-strictly 'mime-preview-condition + '((type . multipart)(subtype . related) + (body . visible) + (body-presentation-method . mime-display-multipart/related))) + +(ctree-set-calist-strictly + 'mime-preview-condition '((type . multipart)(subtype . t) (body . visible) (body-presentation-method . mime-display-multipart/mixed))) @@ -722,60 +780,53 @@ Each elements are regexp of field-name.") (defun mime-display-text/plain (entity situation) (save-restriction (narrow-to-region (point-max)(point-max)) - (mime-insert-text-content entity) + (condition-case nil + (if (and mime-preview-inline-fontify + (mime-entity-filename entity)) ;should be an attachment. + (mime-view-insert-fontified-text-content entity situation) + (mime-view-insert-text-content entity situation)) + (error (progn + (message "Can't decode current entity.") + (sit-for 1)))) (run-hooks 'mime-text-decode-hook) (goto-char (point-max)) (if (not (eq (char-after (1- (point))) ?\n)) - (insert "\n") - ) + (insert "\n")) + (if (and mime-preview-fill-flowed-text + (equal (cdr (assoc "format" situation)) "flowed")) + (fill-flowed)) (mime-add-url-buttons) - (run-hooks 'mime-display-text/plain-hook) - )) + (run-hooks 'mime-display-text/plain-hook))) (defun mime-display-text/richtext (entity situation) (save-restriction (narrow-to-region (point-max)(point-max)) - (mime-insert-text-content entity) + (mime-view-insert-text-content entity situation) (run-hooks 'mime-text-decode-hook) (let ((beg (point-min))) (remove-text-properties beg (point-max) '(face nil)) - (richtext-decode beg (point-max)) - ))) + (richtext-decode beg (point-max))))) (defun mime-display-text/enriched (entity situation) (save-restriction (narrow-to-region (point-max)(point-max)) - (mime-insert-text-content entity) + (mime-view-insert-text-content entity situation) (run-hooks 'mime-text-decode-hook) (let ((beg (point-min))) (remove-text-properties beg (point-max) '(face nil)) - (enriched-decode beg (point-max)) - ))) - + (enriched-decode beg (point-max))))) (defvar mime-view-announcement-for-message/partial - (if (and (>= emacs-major-version 19) window-system) - "\ -\[[ This is message/partial style split message. ]] -\[[ Please press `v' key in this buffer ]] -\[[ or click here by mouse button-2. ]]" - "\ -\[[ This is message/partial style split message. ]] -\[[ Please press `v' key in this buffer. ]]" - )) + "This is message/partial style split message.") (defun mime-display-message/partial-button (&optional entity situation) (save-restriction (goto-char (point-max)) (if (not (search-backward "\n\n" nil t)) - (insert "\n") - ) + (insert "\n")) (goto-char (point-max)) - (narrow-to-region (point-max)(point-max)) - (insert mime-view-announcement-for-message/partial) - (mime-add-button (point-min)(point-max) - #'mime-preview-play-current-entity) - )) + (mime-insert-button mime-view-announcement-for-message/partial + #'mime-preview-play-current-entity))) (defun mime-display-multipart/mixed (entity situation) (let ((children (mime-entity-children entity)) @@ -787,8 +838,7 @@ Each elements are regexp of field-name.") (cons original-major-mode-cell default-situation))) (while children (mime-display-entity (car children) nil default-situation) - (setq children (cdr children)) - ))) + (setq children (cdr children))))) (defcustom mime-view-type-subtype-score-alist '(((text . enriched) . 3) @@ -837,15 +887,12 @@ MEDIA-TYPE must be (TYPE . SUBTYPE), TYPE or t. t means default." mime-view-type-subtype-score-alist) (assq t - mime-view-type-subtype-score-alist) - )))) + mime-view-type-subtype-score-alist))))) (if (> score max-score) (setq p i - max-score score) - ))) + max-score score)))) (setq i (1+ i)) - situation) - )) + situation))) children)) (setq i 0) (while children @@ -859,6 +906,124 @@ MEDIA-TYPE must be (TYPE . SUBTYPE), TYPE or t. t means default." situations (cdr situations) i (1+ i))))) +(defun mime-display-multipart/related (entity situation) + (let* ((param-start (mime-parse-msg-id + (std11-lexical-analyze + (cdr (assoc "start" + (mime-content-type-parameters + (mime-entity-content-type entity))))))) + (start (or (and param-start (mime-find-entity-from-content-id + param-start + entity)) + (car (mime-entity-children entity)))) + (original-major-mode-cell (assq 'major-mode situation)) + (default-situation (cdr (assq 'childrens-situation situation)))) + (when start + (if original-major-mode-cell + (setq default-situation + (cons original-major-mode-cell default-situation))) + (mime-display-entity start nil default-situation)))) + +(defun mime-view-entity-content (entity situation) + (mime-decode-string + (mime-entity-body entity) + (mime-view-guess-encoding entity situation))) + +(defun mime-view-insert-text-content (entity situation) + (let (compression-info) + (cond + ((and (mime-entity-filename entity) + (featurep 'jka-compr) + (jka-compr-installed-p) + (setq compression-info (jka-compr-get-compression-info + (mime-entity-filename entity)))) + (insert + (mime-view-filter-text-content + (mime-view-entity-content entity situation) + (jka-compr-info-uncompress-program compression-info) + (jka-compr-info-uncompress-args compression-info)))) + ((or (assq '*encoding situation) ;should be specified by user + (assq '*charset situation)) ;should be specified by user + (insert + (decode-mime-charset-string + (mime-view-entity-content entity situation) + (mime-view-guess-charset entity situation) + 'CRLF))) + (t + (mime-insert-text-content entity))))) + +;;; stolen (and renamed) from `mime-display-gzipped' of EMY 1.13. +(defun mime-view-filter-text-content (content program args) + (with-temp-buffer + (static-cond + ((featurep 'xemacs) + (insert content) + (apply #'binary-to-text-funcall + mime-view-automatic-conversion + #'call-process-region (point-min)(point-max) + program t t args)) + (t + (if (not (multibyte-string-p content)) + (set-buffer-multibyte nil)) + (insert content) + (apply #'binary-funcall + #'call-process-region (point-min)(point-max) + program t t args) + (set-buffer-multibyte t) + (decode-coding-region (point-min)(point-max) + mime-view-automatic-conversion))) + (buffer-string))) + +;;; stolen (and renamed) from mm-view.el. +(defun mime-view-insert-fontified-text-content (entity situation + &optional mode) + ;; XEmacs @#$@ version of font-lock refuses to fully turn itself + ;; on for buffers whose name begins with " ". That's why we use + ;; save-current-buffer/get-buffer-create rather than + ;; with-temp-buffer. + (let ((buffer (generate-new-buffer "*fontification*")) + filename) + (unwind-protect + (progn + (save-current-buffer + (set-buffer buffer) + (buffer-disable-undo) + (kill-all-local-variables) + (mime-view-insert-text-content entity situation) + (require 'font-lock) + (let ((font-lock-maximum-size nil) + ;; Disable support modes, e.g., jit-lock, lazy-lock, etc. + (font-lock-mode-hook nil) + (font-lock-support-mode nil) + ;; I find font-lock a bit too verbose. + (font-lock-verbose nil)) + (cond (mode + (funcall mode)) + ((setq filename (mime-entity-filename entity)) + (let ((buffer-file-name + (expand-file-name (file-name-nondirectory filename) + temporary-file-directory))) + (set-auto-mode)))) + ;; The mode function might have already turned on font-lock. + (unless (symbol-value 'font-lock-mode) + (font-lock-fontify-buffer))) + ;; By default, XEmacs font-lock uses non-duplicable text + ;; properties. This code forces all the text properties + ;; to be copied along with the text. + (static-when (fboundp 'extent-list) + (map-extents (lambda (ext ignored) + (set-extent-property ext 'duplicable t) + nil) + nil nil nil nil nil 'text-prop))) + (insert-buffer-substring buffer)) + (kill-buffer buffer)))) + +(defun mime-display-application/emacs-lisp (entity situation) + (save-restriction + (narrow-to-region (point-max)(point-max)) + (mime-view-insert-fontified-text-content entity situation 'emacs-lisp-mode) + (run-hooks 'mime-text-decode-hook 'mime-display-text/plain-hook))) + ;;; @ acting-condition ;;; @@ -866,41 +1031,45 @@ MEDIA-TYPE must be (TYPE . SUBTYPE), TYPE or t. t means default." (defvar mime-acting-condition nil "Condition-tree about how to process entity.") -(if (file-readable-p mailcap-file) - (let ((entries (mailcap-parse-file))) - (while entries - (let ((entry (car entries)) - view print shared) - (while entry - (let* ((field (car entry)) - (field-type (car field))) - (cond ((eq field-type 'view) (setq view field)) - ((eq field-type 'print) (setq print field)) - ((memq field-type '(compose composetyped edit))) - (t (setq shared (cons field shared)))) - ) - (setq entry (cdr entry)) +(defun mime-view-read-mailcap-files (&optional files) + (or files + (setq files mime-view-mailcap-files)) + (let (entries file) + (while files + (setq file (car files)) + (if (file-readable-p file) + (setq entries (append entries (mime-parse-mailcap-file file)))) + (setq files (cdr files))) + (while entries + (let ((entry (car entries)) + view print shared) + (while entry + (let* ((field (car entry)) + (field-type (car field))) + (cond ((eq field-type 'view) (setq view field)) + ((eq field-type 'print) (setq print field)) + ((memq field-type '(compose composetyped edit))) + (t (setq shared (cons field shared)))) ) - (setq shared (nreverse shared)) - (ctree-set-calist-with-default - 'mime-acting-condition - (append shared (list '(mode . "play")(cons 'method (cdr view))))) - (if print - (ctree-set-calist-with-default - 'mime-acting-condition - (append shared - (list '(mode . "print")(cons 'method (cdr view)))) - )) - ) - (setq entries (cdr entries)) - ))) + (setq entry (cdr entry))) + (setq shared (nreverse shared)) + (ctree-set-calist-with-default + 'mime-acting-condition + (append shared (list '(mode . "play")(cons 'method (cdr view))))) + (if print + (ctree-set-calist-with-default + 'mime-acting-condition + (append shared + (list '(mode . "print")(cons 'method (cdr view))))))) + (setq entries (cdr entries))))) + +(mime-view-read-mailcap-files) (ctree-set-calist-strictly 'mime-acting-condition '((type . application)(subtype . octet-stream) (mode . "play") - (method . mime-detect-content) - )) + (method . mime-detect-content))) (ctree-set-calist-with-default 'mime-acting-condition @@ -910,44 +1079,37 @@ MEDIA-TYPE must be (TYPE . SUBTYPE), TYPE or t. t means default." (ctree-set-calist-strictly 'mime-acting-condition '((type . text)(subtype . x-rot13-47)(mode . "play") - (method . mime-view-caesar) - )) + (method . mime-view-caesar))) (ctree-set-calist-strictly 'mime-acting-condition '((type . text)(subtype . x-rot13-47-48)(mode . "play") - (method . mime-view-caesar) - )) + (method . mime-view-caesar))) (ctree-set-calist-strictly 'mime-acting-condition '((type . message)(subtype . rfc822)(mode . "play") - (method . mime-view-message/rfc822) - )) + (method . mime-view-message/rfc822))) (ctree-set-calist-strictly 'mime-acting-condition '((type . message)(subtype . partial)(mode . "play") - (method . mime-store-message/partial-piece) - )) + (method . mime-store-message/partial-piece))) (ctree-set-calist-strictly 'mime-acting-condition '((type . message)(subtype . external-body) ("access-type" . "anon-ftp") - (method . mime-view-message/external-anon-ftp) - )) + (method . mime-view-message/external-anon-ftp))) (ctree-set-calist-strictly 'mime-acting-condition '((type . message)(subtype . external-body) ("access-type" . "url") - (method . mime-view-message/external-url) - )) + (method . mime-view-message/external-url))) (ctree-set-calist-strictly 'mime-acting-condition '((type . application)(subtype . octet-stream) - (method . mime-save-content) - )) + (method . mime-save-content))) ;;; @ quitting method @@ -1019,6 +1181,7 @@ MEDIA-TYPE must be (TYPE . SUBTYPE), TYPE or t. t means default." (mime-insert-header entity mime-view-ignored-field-list mime-view-visible-field-list)) + (mime-add-url-buttons) (run-hooks 'mime-display-header-hook) (put-text-property nhb (point-max) 'mime-view-entity-header entity) (goto-char (point-max)) @@ -1033,12 +1196,10 @@ MEDIA-TYPE must be (TYPE . SUBTYPE), TYPE or t. t means default." (mime-display-text/plain entity situation))) (when button-is-invisible (goto-char (point-max)) - (mime-view-insert-entity-button entity) - ) + (mime-view-insert-entity-button entity)) (unless header-is-visible (goto-char (point-max)) - (insert "\n")) - )) + (insert "\n")))) (setq ne (point-max)) (widen) (put-text-property nb ne 'mime-view-entity entity) @@ -1050,69 +1211,43 @@ MEDIA-TYPE must be (TYPE . SUBTYPE), TYPE or t. t means default." (cdr (assq 'body-presentation-method situation)))) (if (functionp body-presentation-method) (funcall body-presentation-method entity situation) - (mime-display-multipart/mixed entity situation)))) - ))) + (mime-display-multipart/mixed entity situation))))))) ;;; @ MIME viewer mode ;;; -(defconst mime-view-menu-title "MIME-View") -(defconst mime-view-menu-list - '((up "Move to upper entity" mime-preview-move-to-upper) - (previous "Move to previous entity" mime-preview-move-to-previous) - (next "Move to next entity" mime-preview-move-to-next) - (scroll-down "Scroll-down" mime-preview-scroll-down-entity) - (scroll-up "Scroll-up" mime-preview-scroll-up-entity) - (play "Play current entity" mime-preview-play-current-entity) - (extract "Extract current entity" mime-preview-extract-current-entity) - (print "Print current entity" mime-preview-print-current-entity) - ) +(defconst mime-view-popup-menu-list + '("MIME-View" + ["Move to upper entity" mime-preview-move-to-upper] + ["Move to previous entity" mime-preview-move-to-previous] + ["Move to next entity" mime-preview-move-to-next] + ["Scroll-down" mime-preview-scroll-down-entity] + ["Scroll-up" mime-preview-scroll-up-entity] + ["Play current entity" mime-preview-play-current-entity] + ["Extract current entity" mime-preview-extract-current-entity] + ["Print current entity" mime-preview-print-current-entity]) "Menu for MIME Viewer") -(cond ((featurep 'xemacs) - (defvar mime-view-xemacs-popup-menu - (cons mime-view-menu-title - (mapcar (function - (lambda (item) - (vector (nth 1 item)(nth 2 item) t) - )) - mime-view-menu-list))) - (defun mime-view-xemacs-popup-menu (event) - "Popup the menu in the MIME Viewer buffer" - (interactive "e") - (select-window (event-window event)) - (set-buffer (event-buffer event)) - (popup-menu 'mime-view-xemacs-popup-menu)) - (defvar mouse-button-2 'button2) - ) - (t - (defvar mime-view-popup-menu - (let ((menu (make-sparse-keymap mime-view-menu-title))) - (nconc menu - (mapcar (function - (lambda (item) - (list (intern (nth 1 item)) 'menu-item - (nth 1 item)(nth 2 item)) - )) - mime-view-menu-list)))) - (defun mime-view-popup-menu (event) - "Popup the menu in the MIME Viewer buffer" - (interactive "@e") - (let ((menu mime-view-popup-menu) events func) - (setq events (x-popup-menu t menu)) - (and events - (setq func (lookup-key menu (apply #'vector events))) - (commandp func) - (funcall func)))) - (defvar mouse-button-2 [mouse-2]) - )) - +(defun mime-view-popup-menu (event) + "Popup the menu in the MIME Viewer buffer" + (interactive "@e") + (mime-popup-menu-popup mime-view-popup-menu-list event)) + +;;; The current local map is taken precendence over `widget-keymap', +;;; because GNU Emacs' widget implementation doesn't set `local-map' property. +;;; So we need to specify derivation. +(defvar widget-keymap) +(defun mime-view-maybe-inherit-widget-keymap () + (when (boundp 'widget-keymap) + (set-keymap-parent (current-local-map) widget-keymap))) + +(add-hook 'mime-view-mode-hook 'mime-view-maybe-inherit-widget-keymap) + (defun mime-view-define-keymap (&optional default) (let ((mime-view-mode-map (if (keymapp default) (copy-keymap default) - (make-sparse-keymap) - ))) + (make-sparse-keymap)))) (define-key mime-view-mode-map "u" (function mime-preview-move-to-upper)) (define-key mime-view-mode-map @@ -1180,40 +1315,17 @@ MEDIA-TYPE must be (TYPE . SUBTYPE), TYPE or t. t means default." (define-key mime-view-mode-map [backspace] (function mime-preview-scroll-down-entity)) (if (functionp default) - (cond ((featurep 'xemacs) - (set-keymap-default-binding mime-view-mode-map default) - ) - (t - (setq mime-view-mode-map - (append mime-view-mode-map (list (cons t default)))) - ))) - (if mouse-button-2 - (define-key mime-view-mode-map - mouse-button-2 (function mime-button-dispatcher)) - ) - (cond ((featurep 'xemacs) - (define-key mime-view-mode-map - mouse-button-3 (function mime-view-xemacs-popup-menu)) - ) - ((>= emacs-major-version 19) - (define-key mime-view-mode-map - mouse-button-3 (function mime-view-popup-menu)) - (define-key mime-view-mode-map [menu-bar mime-view] - (cons mime-view-menu-title - (make-sparse-keymap mime-view-menu-title))) - (mapcar (function - (lambda (item) - (define-key mime-view-mode-map - (vector 'menu-bar 'mime-view (car item)) - (cons (nth 1 item)(nth 2 item)) - ) - )) - (reverse mime-view-menu-list) - ) - )) - (use-local-map mime-view-mode-map) - (run-hooks 'mime-view-define-keymap-hook) - )) + (if (featurep 'xemacs) + (set-keymap-default-binding mime-view-mode-map default) + (setq mime-view-mode-map + (append mime-view-mode-map (list (cons t default)))))) + (define-key mime-view-mode-map + [down-mouse-3] (function mime-view-popup-menu)) + ;; (run-hooks 'mime-view-define-keymap-hook) + mime-view-mode-map)) + +(defvar mime-view-mode-default-map (mime-view-define-keymap)) + (defsubst mime-maybe-hide-echo-buffer () "Clear mime-echo buffer and delete window for it." @@ -1224,17 +1336,15 @@ MEDIA-TYPE must be (TYPE . SUBTYPE), TYPE or t. t means default." (erase-buffer) (let ((win (get-buffer-window buf))) (if win - (delete-window win) - )) - (bury-buffer buf) - )))) + (delete-window win))) + (bury-buffer buf))))) (defvar mime-view-redisplay nil) ;;;###autoload (defun mime-display-message (message &optional preview-buffer mother default-keymap-or-function - original-major-mode) + original-major-mode keymap) "View MESSAGE in MIME-View mode. Optional argument PREVIEW-BUFFER specifies the buffer of the @@ -1245,7 +1355,14 @@ Optional argument MOTHER specifies mother-buffer of the preview-buffer. Optional argument DEFAULT-KEYMAP-OR-FUNCTION is nil, keymap or function. If it is a keymap, keymap of MIME-View mode will be added to it. If it is a function, it will be bound as default binding of -keymap of MIME-View mode." +keymap of MIME-View mode. + +Optional argument ORIGINAL-MAJOR-MODE is major-mode of representation +buffer of MESSAGE. If it is nil, current `major-mode' is used. + +Optional argument KEYMAP is keymap of MIME-View mode. If it is +non-nil, DEFAULT-KEYMAP-OR-FUNCTION is ignored. If it is nil, +`mime-view-mode-default-map' is used." (mime-maybe-hide-echo-buffer) (let ((win-conf (current-window-configuration))) (or preview-buffer @@ -1258,8 +1375,7 @@ keymap of MIME-View mode." (widen) (erase-buffer) (if mother - (setq mime-mother-buffer mother) - ) + (setq mime-mother-buffer mother)) (setq mime-preview-original-window-configuration win-conf) (setq major-mode 'mime-view-mode) (setq mode-name "MIME-View") @@ -1268,14 +1384,17 @@ keymap of MIME-View mode." (header . visible) (major-mode . ,original-major-mode)) preview-buffer) - (mime-view-define-keymap default-keymap-or-function) + (use-local-map + (or keymap + (if default-keymap-or-function + (mime-view-define-keymap default-keymap-or-function) + mime-view-mode-default-map))) (let ((point (next-single-property-change (point-min) 'mime-view-entity))) (if point (goto-char point) (goto-char (point-min)) - (search-forward "\n\n" nil t) - )) + (search-forward "\n\n" nil t))) (run-hooks 'mime-view-mode-hook) (set-buffer-modified-p nil) (setq buffer-read-only t) @@ -1303,11 +1422,9 @@ message. It must be nil, `binary' or `cooked'. If it is nil, (save-excursion (set-buffer raw-buffer) (cdr (or (assq major-mode mime-raw-representation-type-alist) - (assq t mime-raw-representation-type-alist))) - ))) + (assq t mime-raw-representation-type-alist)))))) (if (eq representation-type 'binary) - (setq representation-type 'buffer) - ) + (setq representation-type 'buffer)) (setq preview-buffer (mime-display-message (mime-open-entity representation-type raw-buffer) preview-buffer mother default-keymap-or-function)) @@ -1318,8 +1435,7 @@ message. It must be nil, `binary' or `cooked'. If it is nil, (let ((m-win (and mother (get-buffer-window mother)))) (if m-win (set-window-buffer m-win preview-buffer) - (switch-to-buffer preview-buffer) - )))))) + (switch-to-buffer preview-buffer))))))) (defun mime-view-mode (&optional mother ctl encoding raw-buffer preview-buffer @@ -1355,33 +1471,32 @@ button-2 Move to point under the mouse cursor (or (assq major-mode mime-raw-representation-type-alist) (assq t mime-raw-representation-type-alist))))) (if (eq type 'binary) - (setq type 'buffer) - ) + (setq type 'buffer)) (setq mime-message-structure (mime-open-entity type raw-buffer)) (or (mime-entity-content-type mime-message-structure) - (mime-entity-set-content-type-internal - mime-message-structure ctl)) - ) + (mime-entity-set-content-type mime-message-structure ctl))) (or (mime-entity-encoding mime-message-structure) - (mime-entity-set-encoding-internal mime-message-structure encoding)) - )) + (mime-entity-set-encoding mime-message-structure encoding)))) (mime-display-message mime-message-structure preview-buffer - mother default-keymap-or-function) - ) + mother default-keymap-or-function)) ;;; @@ utility ;;; -(defun mime-preview-find-boundary-info (&optional get-mother) +(defun mime-preview-find-boundary-info (&optional with-children) + "Return boundary information of current part. +If WITH-CHILDREN, refer boundary surrounding current part and its branches." (let (entity p-beg p-end entity-node-id len) - (while (null (setq entity - (get-text-property (point) 'mime-view-entity))) + (while (and + (null (setq entity + (get-text-property (point) 'mime-view-entity))) + (> (point) (point-min))) (backward-char)) (setq p-beg (previous-single-property-change (point) 'mime-view-entity)) - (setq entity-node-id (mime-entity-node-id entity)) + (setq entity-node-id (and entity (mime-entity-node-id entity))) (setq len (length entity-node-id)) (cond ((null p-beg) (setq p-beg @@ -1389,22 +1504,17 @@ button-2 Move to point under the mouse cursor 'mime-view-entity) (point)) (point) - (point-min))) - ) + (point-min)))) ((eq (next-single-property-change p-beg 'mime-view-entity) (point)) - (setq p-beg (point)) - )) + (setq p-beg (point)))) (setq p-end (next-single-property-change p-beg 'mime-view-entity)) (cond ((null p-end) - (setq p-end (point-max)) - ) + (setq p-end (point-max))) ((null entity-node-id) - (setq p-end (point-max)) - ) - (get-mother + (setq p-end (point-max))) + (with-children (save-excursion - (goto-char p-end) (catch 'tag (let (e i) (while (setq e @@ -1412,14 +1522,15 @@ button-2 Move to point under the mouse cursor (point) 'mime-view-entity)) (goto-char e) (let ((rc (mime-entity-node-id - (get-text-property (1- (point)) + (get-text-property (point) 'mime-view-entity)))) (or (and (>= (setq i (- (length rc) len)) 0) (equal entity-node-id (nthcdr i rc))) (throw 'tag nil))) - (setq p-end e))) - (setq p-end (point-max)))) - )) + (setq p-end (or (next-single-property-change + (point) 'mime-view-entity) + (point-max))))) + (setq p-end (point-max)))))) (vector p-beg p-end entity))) @@ -1435,8 +1546,7 @@ It decodes current entity to call internal or external method as \"extract\" mode. The method is selected from variable `mime-acting-condition'." (interactive "P") - (mime-preview-play-current-entity ignore-examples "extract") - ) + (mime-preview-play-current-entity ignore-examples "extract")) (defun mime-preview-print-current-entity (&optional ignore-examples) "Print current entity (maybe). @@ -1444,8 +1554,7 @@ It decodes current entity to call internal or external method as \"print\" mode. The method is selected from variable `mime-acting-condition'." (interactive "P") - (mime-preview-play-current-entity ignore-examples "print") - ) + (mime-preview-play-current-entity ignore-examples "print")) ;;; @@ following @@ -1456,13 +1565,13 @@ It decodes current entity to call internal or external method as It calls following-method selected from variable `mime-preview-following-method-alist'." (interactive) - (let ((entity (mime-preview-find-boundary-info t)) - p-beg p-end - pb-beg) - (setq p-beg (aref entity 0) - p-end (aref entity 1) - entity (aref entity 2)) - (if (get-text-property p-beg 'mime-view-entity-body) + (let* ((boundary-info (mime-preview-find-boundary-info t)) + (p-beg (aref boundary-info 0)) + (p-end (aref boundary-info 1)) + (entity (aref boundary-info 2)) + pb-beg) + (if (or (get-text-property p-beg 'mime-view-entity-body) + (null entity)) (setq pb-beg p-beg) (setq pb-beg (next-single-property-change @@ -1470,7 +1579,7 @@ It calls following-method selected from variable (or (next-single-property-change p-beg 'mime-view-entity) p-end)))) (let* ((mode (mime-preview-original-major-mode 'recursive)) - (entity-node-id (mime-entity-node-id entity)) + (entity-node-id (and entity (mime-entity-node-id entity))) (new-name (format "%s-%s" (buffer-name) (reverse entity-node-id))) new-buf @@ -1483,7 +1592,8 @@ It calls following-method selected from variable (insert-buffer-substring the-buf pb-beg p-end) (goto-char (point-min)) (let ((current-entity - (if (and (eq (mime-entity-media-type entity) 'message) + (if (and entity + (eq (mime-entity-media-type entity) 'message) (eq (mime-entity-media-subtype entity) 'rfc822)) (car (mime-entity-children entity)) entity))) @@ -1496,8 +1606,7 @@ It calls following-method selected from variable (mime-insert-header current-entity fields) t)) (setq fields (std11-collect-field-names) - current-entity (mime-entity-parent current-entity)) - )) + current-entity (mime-entity-parent current-entity)))) (let ((rest mime-view-following-required-fields-list) field-name ret) (while rest @@ -1515,20 +1624,14 @@ It calls following-method selected from variable entity field-name)))) (setq entity (mime-entity-parent entity))))) (if ret - (insert (concat field-name ": " ret "\n")) - ))) - (setq rest (cdr rest)) - )) - ) + (insert (concat field-name ": " ret "\n"))))) + (setq rest (cdr rest))))) (let ((f (cdr (assq mode mime-preview-following-method-alist)))) (if (functionp f) (funcall f new-buf) (message - (format - "Sorry, following method for %s is not implemented yet." - mode)) - )) - ))) + "Sorry, following method for %s is not implemented yet." + mode)))))) ;;; @@ moving @@ -1541,8 +1644,7 @@ If there is no upper entity, call function `mime-preview-quit'." (let (cinfo) (while (null (setq cinfo (get-text-property (point) 'mime-view-entity))) - (backward-char) - ) + (backward-char)) (let ((r (mime-entity-parent cinfo)) point) (catch 'tag @@ -1559,11 +1661,8 @@ If there is no upper entity, call function `mime-preview-quit'." (beginning-of-line) (point))))) (recenter next-screen-context-lines)) - (throw 'tag t) - ) - ) - (mime-preview-quit) - )))) + (throw 'tag t))) + (mime-preview-quit))))) (defun mime-preview-move-to-previous () "Move to previous entity. @@ -1572,8 +1671,7 @@ variable `mime-preview-over-to-previous-method-alist'." (interactive) (while (and (not (bobp)) (null (get-text-property (point) 'mime-view-entity))) - (backward-char) - ) + (backward-char)) (let ((point (previous-single-property-change (point) 'mime-view-entity))) (if (and point (>= point (point-min))) @@ -1590,14 +1688,11 @@ variable `mime-preview-over-to-previous-method-alist'." (point))))) (recenter (* -1 next-screen-context-lines)))) (goto-char (1- point)) - (mime-preview-move-to-previous) - ) + (mime-preview-move-to-previous)) (let ((f (assq (mime-preview-original-major-mode) mime-preview-over-to-previous-method-alist))) (if f - (funcall (cdr f)) - )) - ))) + (funcall (cdr f))))))) (defun mime-preview-move-to-next () "Move to next entity. @@ -1606,8 +1701,7 @@ variable `mime-preview-over-to-next-method-alist'." (interactive) (while (and (not (eobp)) (null (get-text-property (point) 'mime-view-entity))) - (forward-char) - ) + (forward-char)) (let ((point (next-single-property-change (point) 'mime-view-entity))) (if (and point (<= point (point-max))) @@ -1625,14 +1719,11 @@ variable `mime-preview-over-to-next-method-alist'." (* -1 next-screen-context-lines)) (beginning-of-line) (point))))) - (recenter next-screen-context-lines)) - )) + (recenter next-screen-context-lines)))) (let ((f (assq (mime-preview-original-major-mode) mime-preview-over-to-next-method-alist))) (if f - (funcall (cdr f)) - )) - ))) + (funcall (cdr f))))))) (defun mime-preview-scroll-up-entity (&optional h) "Scroll up current entity. @@ -1643,8 +1734,7 @@ If reached to (point-max), it calls function registered in variable (let ((f (assq (mime-preview-original-major-mode) mime-preview-over-to-next-method-alist))) (if f - (funcall (cdr f)) - )) + (funcall (cdr f)))) (let ((point (or (next-single-property-change (point) 'mime-view-entity) (point-max))) @@ -1656,8 +1746,7 @@ If reached to (point-max), it calls function registered in variable (condition-case nil (scroll-up h) (end-of-buffer - (goto-char (point-max))))) - ))) + (goto-char (point-max)))))))) (defun mime-preview-scroll-down-entity (&optional h) "Scroll down current entity. @@ -1668,8 +1757,7 @@ If reached to (point-min), it calls function registered in variable (let ((f (assq (mime-preview-original-major-mode) mime-preview-over-to-previous-method-alist))) (if f - (funcall (cdr f)) - )) + (funcall (cdr f)))) (let ((point (or (previous-single-property-change (point) 'mime-view-entity) (point-min))) @@ -1681,31 +1769,73 @@ If reached to (point-min), it calls function registered in variable (condition-case nil (scroll-down h) (beginning-of-buffer - (goto-char (point-min))))) - ))) + (goto-char (point-min)))))))) (defun mime-preview-next-line-entity (&optional lines) "Scroll up one line (or prefix LINES lines). If LINES is negative, scroll down LINES lines." (interactive "p") - (mime-preview-scroll-up-entity (or lines 1)) - ) + (mime-preview-scroll-up-entity (or lines 1))) (defun mime-preview-previous-line-entity (&optional lines) "Scrroll down one line (or prefix LINES lines). If LINES is negative, scroll up LINES lines." (interactive "p") - (mime-preview-scroll-down-entity (or lines 1)) - ) + (mime-preview-scroll-down-entity (or lines 1))) ;;; @@ display ;;; +(defun mime-view-guess-encoding (entity situation) + (or (cdr (assq '*encoding situation)) + (cdr (assq 'encoding situation)) + (mime-entity-encoding entity) + "7bit")) + +(defun mime-view-read-encoding (entity situation) + (let* ((default-encoding + (mime-view-guess-encoding entity situation)) + (encoding + (completing-read + "Content Transfer Encoding: " + (mime-encoding-alist) nil t default-encoding))) + (unless (or (string= encoding "") + (string= encoding default-encoding)) + encoding))) + +(defun mime-view-guess-charset (entity situation) + (or (static-if (fboundp 'coding-system-to-mime-charset) + ;; might be overridden by `universal-coding-system-argument'. + (and coding-system-for-read + (coding-system-to-mime-charset coding-system-for-read))) + (cdr (assq '*charset situation)) + (cdr (assq 'charset situation)) + (let ((charset (cdr (assoc "charset" (mime-entity-parameters entity))))) + (if charset + (intern (downcase charset)))) + default-mime-charset)) + +(defun mime-view-read-charset (entity situation) + (static-if (featurep 'mule) + (let* ((default-charset + (mime-view-guess-charset entity situation)) + (charset + (intern (completing-read "MIME-charset: " + (mapcar + (lambda (sym) + (list (symbol-name sym))) + (mime-charset-list)) + nil t + (symbol-name default-charset))))) + (unless (eq charset default-charset) + charset)) + default-charset)) + (defun mime-preview-toggle-display (type &optional display) - (let ((situation (mime-preview-find-boundary-info)) + (let ((situation (mime-preview-find-boundary-info t)) (sym (intern (concat "*" (symbol-name type)))) - entity p-beg p-end) + entity p-beg p-end encoding charset) (setq p-beg (aref situation 0) p-end (aref situation 1) entity (aref situation 2) @@ -1715,13 +1845,19 @@ If LINES is negative, scroll up LINES lines." (display) (t (setq display - (eq (cdr (or (assq sym situation) - (assq type situation))) - 'invisible)))) + (memq (cdr (or (assq sym situation) + (assq type situation))) + '(nil invisible))))) (setq situation (put-alist sym (if display 'visible 'invisible) situation)) + (when (and current-prefix-arg + (eq (cdr (assq sym situation)) 'visible)) + (if (setq encoding (mime-view-read-encoding entity situation)) + (setq situation (put-alist '*encoding encoding situation))) + (if (setq charset (mime-view-read-charset entity situation)) + (setq situation (put-alist '*charset charset situation)))) (save-excursion (let ((inhibit-read-only t)) (delete-region p-beg p-end) @@ -1768,13 +1904,11 @@ It calls function registered in variable (let ((r (assq (mime-preview-original-major-mode) mime-preview-quitting-method-alist))) (if r - (funcall (cdr r)) - ))) + (funcall (cdr r))))) (defun mime-preview-kill-buffer () (interactive) - (kill-buffer (current-buffer)) - ) + (kill-buffer (current-buffer))) ;;; @ end @@ -1782,43 +1916,11 @@ It calls function registered in variable (provide 'mime-view) -(let ((file mime-situation-examples-file)) - (if (file-readable-p file) - (with-temp-buffer - (insert-file-contents file) - (setq mime-situation-examples-file-coding-system - (static-cond - ((boundp 'buffer-file-coding-system) - (symbol-value 'buffer-file-coding-system)) - ((boundp 'file-coding-system) - (symbol-value 'file-coding-system)) - (t nil))) - (eval-buffer) - ;; format check - (condition-case nil - (let ((i 0)) - (while (and (> (length mime-preview-situation-example-list) - mime-preview-situation-example-list-max-size) - (< i 16)) - (setq mime-preview-situation-example-list - (mime-reduce-situation-examples - mime-preview-situation-example-list)) - (setq i (1+ i)))) - (error (setq mime-preview-situation-example-list nil))) - ;; (let ((rest mime-preview-situation-example-list)) - ;; (while rest - ;; (ctree-set-calist-strictly 'mime-preview-condition - ;; (caar rest)) - ;; (setq rest (cdr rest)))) - (condition-case nil - (let ((i 0)) - (while (and (> (length mime-acting-situation-example-list) - mime-acting-situation-example-list-max-size) - (< i 16)) - (setq mime-acting-situation-example-list - (mime-reduce-situation-examples - mime-acting-situation-example-list)) - (setq i (1+ i)))) - (error (setq mime-acting-situation-example-list nil)))))) +(eval-when-compile + (setq mime-situation-examples-file nil) + ;; to avoid to read situation-examples-file at compile time. + ) + +(mime-view-read-situation-examples-file) ;;; mime-view.el ends here