* mime-play.el (mime-play-entity): Use return value of
[elisp/semi.git] / mime-view.el
index acb9e2d..4cedeff 100644 (file)
@@ -1,6 +1,6 @@
 ;;; mime-view.el --- interactive MIME viewer for GNU Emacs
 
-;; Copyright (C) 1995,1996,1997,1998,1999,2000 Free Software Foundation, Inc.
+;; Copyright (C) 1995,96,97,98,99,2000 Free Software Foundation, Inc.
 
 ;; Author: MORIOKA Tomohiko <tomo@m17n.org>
 ;; Created: 1994/07/13
 
 ;;; 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
@@ -52,9 +54,6 @@
   "MIME view mode"
   :group 'mime)
 
-(defvar mime-view-find-every-situations t
-  "*Find every available situations if non-nil.")
-
 (defcustom mime-situation-examples-file "~/.mime-example"
   "*File name of situation-examples demonstrated by user."
   :group 'mime-view
@@ -70,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)
 ;;;
@@ -82,35 +92,13 @@ 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
 `binary' or `cooked'.")
 
 
-;; (defun mime-raw-find-entity-from-point (point &optional message-info)
-;;   "Return entity from POINT in mime-raw-buffer.
-;; If optional argument MESSAGE-INFO is not specified,
-;; `mime-message-structure' is used."
-;;   (or message-info
-;;       (setq message-info mime-message-structure))
-;;   (if (and (<= (mime-entity-point-min message-info) point)
-;;            (<= point (mime-entity-point-max message-info)))
-;;       (let ((children (mime-entity-children message-info)))
-;;         (catch 'tag
-;;           (while children
-;;             (let ((ret
-;;                    (mime-raw-find-entity-from-point point (car children))))
-;;               (if ret
-;;                   (throw 'tag ret)
-;;                 ))
-;;             (setq children (cdr children)))
-;;           message-info))))
-;; (make-obsolete 'mime-raw-find-entity-from-point "don't use it.")
-
-
 ;;; @ in preview-buffer (presentation space)
 ;;;
 
@@ -136,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))
@@ -157,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)
@@ -180,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))
@@ -224,15 +208,14 @@ mother-buffer."
     situation))
 
 (defsubst mime-delq-null-situation (situations field
-                                              &optional ignored-value)
+                                              &rest ignored-values)
   (let (dest)
     (while situations
       (let* ((situation (car situations))
             (cell (assq field situation)))
        (if cell
-           (or (eq (cdr cell) ignored-value)
-               (setq dest (cons situation dest))
-               )))
+           (or (memq (cdr cell) ignored-values)
+               (setq dest (cons situation dest)))))
       (setq situations (cdr situations)))
     dest))
 
@@ -246,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
@@ -264,41 +243,36 @@ 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
-                             &optional required-name ignored-value)
+                             &optional required-name ignored-value
+                             every-situations)
   (let (ret)
     (in-calist-package 'mime-view)
     (setq ret
          (ctree-find-calist condition entity-situation
-                            mime-view-find-every-situations))
+                            every-situations))
     (if required-name
-       (setq ret (mime-delq-null-situation ret required-name ignored-value)))
+       (setq ret (mime-delq-null-situation ret required-name
+                                           ignored-value t)))
     (or (assq 'ignore-examples entity-situation)
        (if (cdr ret)
            (let ((rest ret)
@@ -318,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
@@ -345,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
@@ -363,7 +332,7 @@ mother-buffer."
 
 (defvar mime-preview-situation-example-list nil)
 (defvar mime-preview-situation-example-list-max-size 16)
-(defvar mime-preview-situation-example-condition nil)
+;; (defvar mime-preview-situation-example-condition nil)
 
 (defun mime-find-entity-preview-situation (entity
                                           &optional default-situation)
@@ -381,34 +350,86 @@ mother-buffer."
   
 (defvar mime-acting-situation-example-list nil)
 (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)
-            (buffer (get-buffer-create " *mime-example*")))
-       (unwind-protect
-           (save-excursion
-             (set-buffer buffer)
-             (setq buffer-file-name file)
-             (erase-buffer)
-             (insert ";;; " (file-name-nondirectory file) "\n")
-             (insert "\n;; This file is generated automatically by "
-                     mime-view-version "\n\n")
-             (insert ";;; Code:\n\n")
-             (if mime-preview-situation-example-list
-                 (pp `(setq mime-preview-situation-example-list
-                            ',mime-preview-situation-example-list)
-                     (current-buffer)))
-             (if mime-acting-situation-example-list
-                 (pp `(setq mime-acting-situation-example-list
-                            ',mime-acting-situation-example-list)
-                     (current-buffer)))
-             (insert "\n;;; "
-                     (file-name-nondirectory file)
-                     " ends here.\n")
-             (save-buffer))
-         (kill-buffer buffer)))))
+      (let ((file mime-situation-examples-file))
+       (with-temp-buffer
+         (insert ";;; " (file-name-nondirectory file) "\n")
+         (insert "\n;; This file is generated automatically by "
+                 mime-view-version "\n\n")
+         (insert ";;; Code:\n\n")
+         (if mime-preview-situation-example-list
+             (pp `(setq mime-preview-situation-example-list
+                        ',mime-preview-situation-example-list)
+                 (current-buffer)))
+         (if mime-acting-situation-example-list
+             (pp `(setq mime-acting-situation-example-list
+                        ',mime-acting-situation-example-list)
+                 (current-buffer)))
+         (insert "\n;;; "
+                 (file-name-nondirectory file)
+                 " ends here.\n")
+          (static-cond
+          ((boundp 'buffer-file-coding-system)
+           (setq buffer-file-coding-system
+                 mime-situation-examples-file-coding-system))
+          ((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)))))
 
 (add-hook 'kill-emacs-hook 'mime-save-situation-examples)
 
@@ -441,8 +462,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
@@ -450,27 +470,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)
@@ -485,8 +498,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)))
@@ -505,21 +517,21 @@ mother-buffer."
 ;;; @@@ predicate function
 ;;;
 
-(defun mime-view-entity-button-visible-p (entity)
-  "Return non-nil if header of ENTITY is visible.
-Please redefine this function if you want to change default setting."
-  (let ((media-type (mime-entity-media-type entity))
-       (media-subtype (mime-entity-media-subtype entity)))
-    (or (not (eq media-type 'application))
-       (and (not (eq media-subtype 'x-selection))
-            (or (not (eq media-subtype 'octet-stream))
-                (let ((mother-entity (mime-entity-parent entity)))
-                  (or (not (eq (mime-entity-media-type mother-entity)
-                               'multipart))
-                      (not (eq (mime-entity-media-subtype mother-entity)
-                               'encrypted)))
-                  )
-                )))))
+;; (defun mime-view-entity-button-visible-p (entity)
+;;   "Return non-nil if header of ENTITY is visible.
+;; Please redefine this function if you want to change default setting."
+;;   (let ((media-type (mime-entity-media-type entity))
+;;         (media-subtype (mime-entity-media-subtype entity)))
+;;     (or (not (eq media-type 'application))
+;;         (and (not (eq media-subtype 'x-selection))
+;;              (or (not (eq media-subtype 'octet-stream))
+;;                  (let ((mother-entity (mime-entity-parent entity)))
+;;                    (or (not (eq (mime-entity-media-type mother-entity)
+;;                                 'multipart))
+;;                        (not (eq (mime-entity-media-subtype mother-entity)
+;;                                 'encrypted)))
+;;                    )
+;;                  )))))
 
 ;;; @@@ entity button generator
 ;;;
@@ -535,11 +547,9 @@ Please redefine this function if you want to change default setting."
                    (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))
@@ -548,15 +558,12 @@ Please redefine this function if you want to change default setting."
                            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))
@@ -575,10 +582,8 @@ Please redefine this function if you want to change default setting."
                                ""))))
                 (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
@@ -616,8 +621,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
@@ -668,6 +672,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)
@@ -696,6 +709,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)))
@@ -707,21 +726,38 @@ Each elements are regexp of field-name.")
    (body-presentation-method . mime-display-multipart/alternative)))
 
 (ctree-set-calist-strictly
- 'mime-preview-condition '((type . message)(subtype . partial)
-                          (body-presentation-method
-                           . mime-display-message/partial-button)))
+ 'mime-preview-condition
+ '((type . multipart)(subtype . related)
+   (body . visible)
+   (body-presentation-method . mime-display-multipart/related)))
 
 (ctree-set-calist-strictly
- 'mime-preview-condition '((type . message)(subtype . rfc822)
-                          (body-presentation-method . nil)
-                          (childrens-situation (header . visible)
-                                               (entity-button . invisible))))
+ 'mime-preview-condition
+ '((type . multipart)(subtype . t)
+   (body . visible)
+   (body-presentation-method . mime-display-multipart/mixed)))
 
 (ctree-set-calist-strictly
- 'mime-preview-condition '((type . message)(subtype . news)
-                          (body-presentation-method . nil)
-                          (childrens-situation (header . visible)
-                                               (entity-button . invisible))))
+ 'mime-preview-condition
+ '((type . message)(subtype . partial)
+   (body . visible)
+   (body-presentation-method . mime-display-message/partial-button)))
+
+(ctree-set-calist-strictly
+ 'mime-preview-condition
+ '((type . message)(subtype . rfc822)
+   (body . visible)
+   (body-presentation-method . mime-display-multipart/mixed)
+   (childrens-situation (header . visible)
+                       (entity-button . invisible))))
+
+(ctree-set-calist-strictly
+ 'mime-preview-condition
+ '((type . message)(subtype . news)
+   (body . visible)
+   (body-presentation-method . mime-display-multipart/mixed)
+   (childrens-situation (header . visible)
+                       (entity-button . invisible))))
 
 
 ;;; @@@ entity presentation
@@ -730,60 +766,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))
@@ -795,8 +824,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)
@@ -845,15 +873,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
@@ -861,13 +886,122 @@ MEDIA-TYPE must be (TYPE . SUBTYPE), TYPE or t.  t means default."
            (situation (car situations)))
        (mime-display-entity child (if (= i p)
                                       situation
-                                    (del-alist 'body-presentation-method
-                                               (copy-alist situation))))
-       )
+                                    (put-alist 'body 'invisible
+                                               (copy-alist situation)))))
       (setq children (cdr children)
            situations (cdr situations)
-           i (1+ i))
-      )))
+           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))))
+    (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)
+           (if mode
+               (funcall mode)
+             (if (setq filename (mime-entity-filename entity))
+                 (unwind-protect
+                     (progn
+                       (setq buffer-file-name filename)
+                       (set-auto-mode))
+                   (setq buffer-file-name nil))))
+           (let ((font-lock-verbose nil))
+             ;; I find font-lock a bit too verbose.
+             (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
@@ -876,41 +1010,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
@@ -920,44 +1058,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
@@ -993,7 +1124,6 @@ MEDIA-TYPE must be (TYPE . SUBTYPE), TYPE or t.  t means default."
   (or preview-buffer
       (setq preview-buffer (current-buffer)))
   (let* (e nb ne nhb nbb)
-    (mime-goto-header-start-point entity)
     (in-calist-package 'mime-view)
     (or situation
        (setq situation
@@ -1006,121 +1136,97 @@ MEDIA-TYPE must be (TYPE . SUBTYPE), TYPE or t.  t means default."
           (eq (cdr (or (assq '*header situation)
                        (assq 'header situation)))
               'visible))
-         (header-presentation-method
-          (or (cdr (assq 'header-presentation-method situation))
-              (cdr (assq (cdr (assq 'major-mode situation))
-                         mime-header-presentation-method-alist))))
-         (body-presentation-method
-          (cdr (assq 'body-presentation-method situation)))
+         (body-is-visible
+          (eq (cdr (or (assq '*body situation)
+                       (assq 'body situation)))
+              'visible))
          (children (mime-entity-children entity)))
       (set-buffer preview-buffer)
       (setq nb (point))
       (narrow-to-region nb nb)
       (or button-is-invisible
-         (if (mime-view-entity-button-visible-p entity)
-             (mime-view-insert-entity-button entity)
-           ))
-      (when header-is-visible
-       (setq nhb (point))
-       (if header-presentation-method
-           (funcall header-presentation-method entity situation)
-         (mime-insert-header entity
-                             mime-view-ignored-field-list
-                             mime-view-visible-field-list))
-       (run-hooks 'mime-display-header-hook)
-       (put-text-property nhb (point-max) 'mime-view-entity-header entity)
-       (goto-char (point-max))
-       (insert "\n")
-       )
+          ;; (if (mime-view-entity-button-visible-p entity)
+         (mime-view-insert-entity-button entity)
+          ;;   )
+         )
+      (if header-is-visible
+         (let ((header-presentation-method
+                (or (cdr (assq 'header-presentation-method situation))
+                    (cdr (assq (cdr (assq 'major-mode situation))
+                               mime-header-presentation-method-alist)))))
+           (setq nhb (point))
+           (if header-presentation-method
+               (funcall header-presentation-method entity situation)
+             (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))
+           (insert "\n")))
       (setq nbb (point))
-      (cond (children)
-            ((functionp body-presentation-method)
-            (funcall body-presentation-method entity situation)
-            )
-           (t
-            (when button-is-invisible
-              (goto-char (point-max))
-              (mime-view-insert-entity-button entity)
-              )
-            (or header-is-visible
-                (progn
-                  (goto-char (point-max))
-                  (insert "\n")
-                  ))
-            ))
+      (unless children
+       (if body-is-visible
+           (let ((body-presentation-method
+                  (cdr (assq 'body-presentation-method situation))))
+             (if (functionp body-presentation-method)
+                 (funcall body-presentation-method entity situation)
+               (mime-display-text/plain entity situation)))
+         (when button-is-invisible
+           (goto-char (point-max))
+           (mime-view-insert-entity-button entity))
+         (unless header-is-visible
+           (goto-char (point-max))
+           (insert "\n"))))
       (setq ne (point-max))
       (widen)
       (put-text-property nb ne 'mime-view-entity entity)
       (put-text-property nb ne 'mime-view-situation situation)
       (put-text-property nbb ne 'mime-view-entity-body entity)
       (goto-char ne)
-      (if children
-         (if (functionp body-presentation-method)
-             (funcall body-presentation-method entity situation)
-           (mime-display-multipart/mixed entity situation)
-           ))
-      )))
+      (if (and children body-is-visible)
+         (let ((body-presentation-method
+                (cdr (assq 'body-presentation-method situation))))
+           (if (functionp body-presentation-method)
+               (funcall body-presentation-method 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
@@ -1147,8 +1253,28 @@ MEDIA-TYPE must be (TYPE . SUBTYPE), TYPE or t.  t means default."
       "e"        (function mime-preview-extract-current-entity))
     (define-key mime-view-mode-map
       "\C-c\C-p" (function mime-preview-print-current-entity))
+
+    (define-key mime-view-mode-map
+      "\C-c\C-t\C-f" (function mime-preview-toggle-header))
+    (define-key mime-view-mode-map
+      "\C-c\C-th" (function mime-preview-toggle-header))
+    (define-key mime-view-mode-map
+      "\C-c\C-t\C-c" (function mime-preview-toggle-content))
+
     (define-key mime-view-mode-map
-      "\C-ch" (function mime-preview-toggle-header))
+      "\C-c\C-v\C-f" (function mime-preview-show-header))
+    (define-key mime-view-mode-map
+      "\C-c\C-vh" (function mime-preview-show-header))
+    (define-key mime-view-mode-map
+      "\C-c\C-v\C-c" (function mime-preview-show-content))
+
+    (define-key mime-view-mode-map
+      "\C-c\C-d\C-f" (function mime-preview-hide-header))
+    (define-key mime-view-mode-map
+      "\C-c\C-dh" (function mime-preview-hide-header))
+    (define-key mime-view-mode-map
+      "\C-c\C-d\C-c" (function mime-preview-hide-content))
+
     (define-key mime-view-mode-map
       "a"        (function mime-preview-follow-current-entity))
     (define-key mime-view-mode-map
@@ -1168,40 +1294,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."
@@ -1212,17 +1315,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
@@ -1233,23 +1334,27 @@ 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
        (setq preview-buffer
              (concat "*Preview-" (mime-entity-name message) "*")))
     (or original-major-mode
-       (setq original-major-mode
-             (with-current-buffer (mime-entity-header-buffer message)
-               major-mode)))
+       (setq original-major-mode major-mode))
     (let ((inhibit-read-only t))
       (set-buffer (get-buffer-create preview-buffer))
       (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")
@@ -1258,14 +1363,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)
@@ -1293,11 +1401,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))
@@ -1308,8 +1414,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
@@ -1345,19 +1450,14 @@ 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
@@ -1379,37 +1479,32 @@ 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))
-          )
+          (setq p-end (point-max)))
          (get-mother
           (save-excursion
             (goto-char p-end)
             (catch 'tag
-              (let (e)
+              (let (e i)
                 (while (setq e
                              (next-single-property-change
                               (point) 'mime-view-entity))
                   (goto-char e)
                   (let ((rc (mime-entity-node-id
-                             (get-text-property (point)
+                             (get-text-property (1- (point))
                                                 'mime-view-entity))))
-                    (or (equal entity-node-id
-                               (nthcdr (- (length rc) len) rc))
+                    (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 (point-max))))))
     (vector p-beg p-end entity)))
 
 
@@ -1425,8 +1520,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).
@@ -1434,8 +1528,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
@@ -1448,15 +1541,17 @@ It calls following-method selected from variable
   (interactive)
   (let ((entity (mime-preview-find-boundary-info t))
        p-beg p-end
-       ph-end)
+       pb-beg)
     (setq p-beg (aref entity 0)
          p-end (aref entity 1)
          entity (aref entity 2))
-    (setq ph-end
-         (previous-single-property-change p-end 'mime-view-entity-header))
-    (if (or (null ph-end)
-           (< ph-end p-beg))
-       (setq ph-end p-beg))
+    (if (get-text-property p-beg 'mime-view-entity-body)
+       (setq pb-beg p-beg)
+      (setq pb-beg
+           (next-single-property-change
+            p-beg 'mime-view-entity-body nil
+            (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))
           (new-name
@@ -1467,46 +1562,24 @@ It calls following-method selected from variable
       (save-excursion
        (set-buffer (setq new-buf (get-buffer-create new-name)))
        (erase-buffer)
-       (insert-buffer-substring the-buf ph-end p-end)
-       (when (= ph-end p-beg)
-         (goto-char (point-min))
-         (insert ?\n))
+       (insert ?\n)
+       (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)
                        (eq (mime-entity-media-subtype entity) 'rfc822))
                   (car (mime-entity-children entity))
-                entity))
-             str)
+                entity)))
          (while (and current-entity
-                     (progn
-                       (setq str
-                             (with-current-buffer
-                                 (mime-entity-header-buffer current-entity)
-                               (save-restriction
-                                 (narrow-to-region
-                                  (mime-entity-header-start-point
-                                   current-entity)
-                                  (mime-entity-header-end-point
-                                   current-entity))
-                                 (std11-header-string-except
-                                  (concat
-                                   "^"
-                                   (apply (function regexp-or) fields)
-                                   ":") ""))))
-                       (if (and (eq (mime-entity-media-type
-                                     current-entity) 'message)
-                                (eq (mime-entity-media-subtype
-                                     current-entity) 'rfc822))
-                           nil
-                         (if str
-                             (insert str)
-                           )
-                         t)))
+                     (if (and (eq (mime-entity-media-type
+                                   current-entity) 'message)
+                              (eq (mime-entity-media-subtype
+                                   current-entity) 'rfc822))
+                         nil
+                       (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
@@ -1524,21 +1597,15 @@ 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))
-           ))
-       (mime-decode-header-in-buffer)
-       )
+                     (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))
-         ))
-      )))
+           mode)))))))
 
 
 ;;; @@ moving
@@ -1551,8 +1618,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
@@ -1569,11 +1635,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.
@@ -1582,8 +1645,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)))
@@ -1600,14 +1662,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.
@@ -1616,8 +1675,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)))
@@ -1635,14 +1693,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.
@@ -1653,8 +1708,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)))
@@ -1666,8 +1720,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.
@@ -1678,8 +1731,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)))
@@ -1691,52 +1743,129 @@ 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-preview-toggle-header ()
-  (interactive)
+(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))
+                                      #'mime-charset-p 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))
-       entity p-beg p-end)
+       (sym (intern (concat "*" (symbol-name type))))
+       entity p-beg p-end encoding charset)
     (setq p-beg (aref situation 0)
          p-end (aref situation 1)
          entity (aref situation 2)
          situation (get-text-property p-beg 'mime-view-situation))
-    (let ((cell (assq '*header situation)))
-      (if (null cell)
-         (setq cell (assq 'header situation)))
-      (if (eq (cdr cell) 'visible)
-         (setq situation (put-alist '*header 'invisible situation))
-       (setq situation (put-alist '*header 'visible situation))))
+    (cond ((eq display 'invisible)
+          (setq display nil))
+         (display)
+         (t
+          (setq display
+                (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)
        (mime-display-entity entity situation)))
-    ;; (ctree-set-calist-strictly 'mime-preview-condition situation)
     (let ((ret (assoc situation mime-preview-situation-example-list)))
       (if ret
          (setcdr ret (1+ (cdr ret)))
        (add-to-list 'mime-preview-situation-example-list
                     (cons situation 0))))))
 
+(defun mime-preview-toggle-header (&optional force-visible)
+  (interactive "P")
+  (mime-preview-toggle-display 'header force-visible))
+
+(defun mime-preview-toggle-content (&optional force-visible)
+  (interactive "P")
+  (mime-preview-toggle-display 'body force-visible))
+
+(defun mime-preview-show-header ()
+  (interactive)
+  (mime-preview-toggle-display 'header 'visible))
+
+(defun mime-preview-show-content ()
+  (interactive)
+  (mime-preview-toggle-display 'body 'visible))
+
+(defun mime-preview-hide-header ()
+  (interactive)
+  (mime-preview-toggle-display 'header 'invisible))
+
+(defun mime-preview-hide-content ()
+  (interactive)
+  (mime-preview-toggle-display 'body 'invisible))
+
     
 ;;; @@ quitting
 ;;;
@@ -1749,13 +1878,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
@@ -1763,44 +1890,11 @@ It calls function registered in variable
 
 (provide 'mime-view)
 
-(let* ((file mime-situation-examples-file)
-       (buffer (get-buffer-create " *mime-example*")))
-  (if (file-readable-p file)
-      (unwind-protect
-         (save-excursion
-           (set-buffer buffer)
-           (erase-buffer)
-           (insert-file-contents file)
-           (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)))
-           )
-       (kill-buffer buffer))))
+(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