Sync with semi-1_14.
[elisp/semi.git] / mime-view.el
index eeb39e2..1f53690 100644 (file)
 
 ;; 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