(mime-entity-parent): New function; abolish `mime-raw-entity-parent'.
[elisp/semi.git] / mime-view.el
index feae505..ab76cb8 100644 (file)
@@ -3,8 +3,8 @@
 ;; Copyright (C) 1995,1996,1997,1998 Free Software Foundation, Inc.
 
 ;; Author: MORIOKA Tomohiko <morioka@jaist.ac.jp>
 ;; Copyright (C) 1995,1996,1997,1998 Free Software Foundation, Inc.
 
 ;; Author: MORIOKA Tomohiko <morioka@jaist.ac.jp>
-;; Created: 1994/7/13
-;;     Renamed: 1994/8/31 from tm-body.el
+;; Created: 1994/07/13
+;;     Renamed: 1994/08/31 from tm-body.el
 ;;     Renamed: 1997/02/19 from tm-view.el
 ;; Keywords: MIME, multimedia, mail, news
 
 ;;     Renamed: 1997/02/19 from tm-view.el
 ;; Keywords: MIME, multimedia, mail, news
 
 (require 'mel)
 (require 'eword-decode)
 (require 'mime-parse)
 (require 'mel)
 (require 'eword-decode)
 (require 'mime-parse)
-(require 'mime-text)
+(require 'semi-def)
+(require 'calist)
+(require 'alist)
+(require 'mailcap)
 
 
 ;;; @ version
 ;;;
 
 (defconst mime-view-version-string
 
 
 ;;; @ version
 ;;;
 
 (defconst mime-view-version-string
-  `,(concat "SEMI MIME-View "
-           (mapconcat #'number-to-string (cdr semi-version) ".")
-           " (" (car semi-version) ")"))
+  `,(concat (car mime-module-version) " MIME-View "
+           (mapconcat #'number-to-string (cddr mime-module-version) ".")
+           " (" (cadr mime-module-version) ")"))
 
 
 ;;; @ variables
 ;;;
 
 
 
 ;;; @ variables
 ;;;
 
-(defvar mime-acting-condition
-  '(((type . text)(subtype . plain)
-     (method "tm-plain" nil 'file "" 'encoding 'mode 'name)
-     (mode "play" "print")
-     )
-    ((type . text)(subtype . html)
-     (method "tm-html" nil 'file "" 'encoding 'mode 'name)
-     (mode . "play")
-     )
-    ((type . text)(subtype . x-rot13-47)
-     (method . mime-method-to-display-caesar)
-     (mode . "play")
-     )
-    ((type . text)(subtype . x-rot13-47-48)
-     (method . mime-method-to-display-caesar)
-     (mode . "play")
-     )
-
-    ((type . audio)(subtype . basic)
-     (method "tm-au"    nil 'file "" 'encoding 'mode 'name)
-     (mode . "play")
-     )
-    
-    ((type . image)
-     (method "tm-image" nil 'file "" 'encoding 'mode 'name)
-     (mode "play" "print")
-     )
-    
-    ((type . video)(subtype . mpeg)
-     (method "tm-mpeg"  nil 'file "" 'encoding 'mode 'name)
-     (mode . "play")
-     )
-    
-    ((type . application)(subtype . postscript)
-     (method "tm-ps" nil 'file "" 'encoding 'mode 'name)
-     (mode "play" "print")
-     )
-    ((type . application)(subtype . octet-stream)
-     (method . mime-method-to-save)(mode "play" "print")
-     )
-
-    ((type . message)(subtype . external-body)
-     ("access-type" . "anon-ftp")
-     (method . mime-method-to-display-message/external-ftp)
-     )
-    ((type . message)(subtype . rfc822)
-     (method . mime-method-to-display-message/rfc822)
-     (mode . "play")
-     )
-    ((type . message)(subtype . partial)
-     (method . mime-method-to-store-message/partial)
-     (mode . "play")
-     )
-    
-    ((method "metamail" t "-m" "tm" "-x" "-d" "-z" "-e" 'file)
-     (mode . "play")
-     )
-    ((method . mime-method-to-save)(mode . "extract"))
-    ))
+(defgroup mime-view nil
+  "MIME view mode"
+  :group 'mime)
 
 
-(defvar mime-view-childrens-header-showing-Content-Type-list
-  '("message/rfc822" "message/news"))
+(defcustom mime-view-find-every-acting-situation t
+  "*Find every available acting-situation if non-nil."
+  :group 'mime-view
+  :type 'boolean)
 
 
-(defvar mime-view-visible-media-type-list
-  '("text/plain" nil "text/richtext" "text/enriched"
-    "text/rfc822-headers"
-    "text/x-latex" "application/x-latex"
-    "message/delivery-status"
-    "application/pgp" "text/x-pgp"
-    "application/octet-stream"
-    "application/x-selection" "application/x-comment")
-  "*List of media-types to be able to display in MIME-View buffer.
-Each elements are string of TYPE/SUBTYPE, e.g. \"text/plain\".")
+(defcustom mime-acting-situation-examples-file "~/.mime-example"
+  "*File name of example about acting-situation demonstrated by user."
+  :group 'mime-view
+  :type 'file)
 
 
-(defvar mime-view-content-button-visible-ctype-list
-  '("application/pgp"))
 
 
-(defvar mime-view-uuencode-encoding-name-list '("x-uue" "x-uuencode"))
+;;; @ buffer local variables
+;;;
 
 
-(defvar mime-view-ignored-field-list
-  '(".*Received" ".*Path" ".*Id" "References"
-    "Replied" "Errors-To"
-    "Lines" "Sender" ".*Host" "Xref"
-    "Content-Type" "Precedence"
-    "Status" "X-VM-.*")
-  "All fields that match this list will be hidden in MIME preview buffer.
-Each elements are regexp of field-name. [mime-view.el]")
+;;; @@ in raw-buffer
+;;;
 
 
-(defvar mime-view-ignored-field-regexp
-  (concat "^"
-         (apply (function regexp-or) mime-view-ignored-field-list)
-         ":"))
+(defvar mime-raw-message-info nil
+  "Information about structure of message.
+Please use reference function `mime-entity-SLOT' to get value of SLOT.
 
 
-(defvar mime-view-visible-field-list '("Dnas.*" "Message-Id")
-  "All fields that match this list will be displayed in MIME preview buffer.
-Each elements are regexp of field-name.")
+Following is a list of slots of the structure:
 
 
-(defvar mime-view-redisplay nil)
+buffer                 buffer includes this entity (buffer).
+node-id                        node-id (list of integers)
+header-start           minimum point of header in raw-buffer
+header-end             maximum point of header in raw-buffer
+body-start             minimum point of body in raw-buffer
+body-end               maximum point of body in raw-buffer
+content-type           content-type (content-type)
+content-disposition    content-disposition (content-disposition)
+encoding               Content-Transfer-Encoding (string or nil)
+children               entities included in this entity (list of entity)
 
 
-(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.         ]]"
-    ))
+If an entity includes other entities in its body, such as multipart or
+message/rfc822, `mime-entity' structures of them are included in
+`children', so the `mime-entity' structure become a tree.")
+(make-variable-buffer-local 'mime-raw-message-info)
 
 
 
 
-;;; @@ entity button
+(defvar mime-preview-buffer nil
+  "MIME-preview buffer corresponding with the (raw) buffer.")
+(make-variable-buffer-local 'mime-preview-buffer)
+
+
+(defvar mime-raw-representation-type nil
+  "Representation-type of mime-raw-buffer.
+It must be nil, `binary' or `cooked'.
+If it is nil, `mime-raw-representation-type-alist' is used as default
+value.
+Notice that this variable is usually used as buffer local variable in
+raw-buffer.")
+
+(make-variable-buffer-local 'mime-raw-representation-type)
+
+(defvar mime-raw-representation-type-alist
+  '((mime-show-message-mode     . binary)
+    (mime-temp-message-mode     . binary)
+    (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'.
+This value is overridden by buffer local variable
+`mime-raw-representation-type' if it is not nil.")
+
+
+;;; @@ in preview-buffer
 ;;;
 
 ;;;
 
-(defun mime-view-insert-entity-button (rcnum cinfo
-                                            media-type media-subtype params
-                                            subj encoding)
-  "Insert entity-button."
-  (mime-insert-button
-   (let ((access-type (assoc "access-type" params))
-        (num (or (cdr (assoc "x-part-number" params))
-                 (if (consp rcnum)
-                     (mapconcat (function
-                                 (lambda (num)
-                                   (format "%s" (1+ num))
-                                   ))
-                                (reverse rcnum) ".")
-                   "0"))
-             ))
-     (cond (access-type
-           (let ((server (assoc "server" params)))
-             (setq access-type (cdr access-type))
-             (if server
-                 (format "%s %s ([%s] %s)"
-                         num subj access-type (cdr server))
+(defvar mime-mother-buffer nil
+  "Mother buffer corresponding with the (MIME-preview) buffer.
+If current MIME-preview buffer is generated by other buffer, such as
+message/partial, it is called `mother-buffer'.")
+(make-variable-buffer-local 'mime-mother-buffer)
+
+(defvar mime-raw-buffer nil
+  "Raw buffer corresponding with the (MIME-preview) buffer.")
+(make-variable-buffer-local 'mime-raw-buffer)
+
+(defvar mime-preview-original-major-mode nil
+  "Major-mode of mime-raw-buffer.")
+(make-variable-buffer-local 'mime-preview-original-major-mode)
+
+(defvar mime-preview-original-window-configuration nil
+  "Window-configuration before mime-view-mode is called.")
+(make-variable-buffer-local 'mime-preview-original-window-configuration)
+
+
+;;; @ entity information
+;;;
+
+(defsubst mime-raw-find-entity-from-node-id (entity-node-id
+                                            &optional message-info)
+  "Return entity from ENTITY-NODE-ID in mime-raw-buffer.
+If optional argument MESSAGE-INFO is not specified,
+`mime-raw-message-info' is used."
+  (mime-raw-find-entity-from-number (reverse entity-node-id) message-info))
+
+(defun mime-raw-find-entity-from-number (entity-number &optional message-info)
+  "Return entity from ENTITY-NUMBER in mime-raw-buffer.
+If optional argument MESSAGE-INFO is not specified,
+`mime-raw-message-info' is used."
+  (or message-info
+      (setq message-info mime-raw-message-info))
+  (if (eq entity-number t)
+      message-info
+    (let ((sn (car entity-number)))
+      (if (null sn)
+         message-info
+       (let ((rc (nth sn (mime-entity-children message-info))))
+         (if rc
+             (mime-raw-find-entity-from-number (cdr entity-number) rc)
+           ))
+       ))))
+
+(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-raw-message-info' is used."
+  (or message-info
+      (setq message-info mime-raw-message-info))
+  (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))))
+
+(defsubst mime-raw-point-to-entity-node-id (point &optional message-info)
+  "Return entity-node-id from POINT in mime-raw-buffer.
+If optional argument MESSAGE-INFO is not specified,
+`mime-raw-message-info' is used."
+  (mime-entity-node-id (mime-raw-find-entity-from-point point message-info)))
+
+(defsubst mime-raw-point-to-entity-number (point &optional message-info)
+  "Return entity-number from POINT in mime-raw-buffer.
+If optional argument MESSAGE-INFO is not specified,
+`mime-raw-message-info' is used."
+  (reverse (mime-raw-point-to-entity-node-id point message-info)))
+
+(defsubst mime-entity-parent (entity &optional message-info)
+  "Return mother entity of ENTITY.
+If optional argument MESSAGE-INFO is not specified,
+`mime-raw-message-info' in buffer of ENTITY is used."
+  (mime-raw-find-entity-from-node-id
+   (cdr (mime-entity-node-id entity))
+   (or message-info
+       (save-excursion
+        (set-buffer (mime-entity-buffer entity))
+        mime-raw-message-info))))
+
+(defun mime-raw-flatten-message-info (&optional message-info)
+  "Return list of entity in mime-raw-buffer.
+If optional argument MESSAGE-INFO is not specified,
+`mime-raw-message-info' is used."
+  (or message-info
+      (setq message-info mime-raw-message-info))
+  (let ((dest (list message-info))
+       (rcl (mime-entity-children message-info)))
+    (while rcl
+      (setq dest (nconc dest (mime-raw-flatten-message-info (car rcl))))
+      (setq rcl (cdr rcl)))
+    dest))
+
+
+;;; @ presentation of preview
+;;;
+
+;;; @@ entity-button
+;;;
+
+;;; @@@ predicate function
+;;;
+
+(defun mime-view-entity-button-visible-p (entity message-info)
+  "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 message-info)))
+                  (or (not (eq (mime-entity-media-type mother-entity)
+                               'multipart))
+                      (not (eq (mime-entity-media-subtype mother-entity)
+                               'encrypted)))
+                  )
+                )))))
+
+;;; @@@ entity button generator
+;;;
+
+(defun mime-view-insert-entity-button (entity message-info subj)
+  "Insert entity-button of ENTITY."
+  (let ((entity-node-id (mime-entity-node-id entity))
+       (params (mime-entity-parameters entity)))
+    (mime-insert-button
+     (let ((access-type (assoc "access-type" params))
+          (num (or (cdr (assoc "x-part-number" params))
+                   (if (consp entity-node-id)
+                       (mapconcat (function
+                                   (lambda (num)
+                                     (format "%s" (1+ num))
+                                     ))
+                                  (reverse entity-node-id) ".")
+                     "0"))
+               ))
+       (cond (access-type
+             (let ((server (assoc "server" params)))
+               (setq access-type (cdr access-type))
+               (if server
+                   (format "%s %s ([%s] %s)"
+                           num subj access-type (cdr server))
                (let ((site (cdr (assoc "site" params)))
                      (dir (cdr (assoc "directory" params)))
                      )
                (let ((site (cdr (assoc "site" params)))
                      (dir (cdr (assoc "directory" params)))
                      )
@@ -189,7 +284,10 @@ Each elements are regexp of field-name.")
                  )))
            )
           (t
                  )))
            )
           (t
-           (let ((charset (cdr (assoc "charset" params))))
+           (let ((media-type (mime-entity-media-type entity))
+                 (media-subtype (mime-entity-media-subtype entity))
+                 (charset (cdr (assoc "charset" params)))
+                 (encoding (mime-entity-encoding entity)))
              (concat
               num " " subj
               (let ((rest
              (concat
               num " " subj
               (let ((rest
@@ -205,33 +303,44 @@ Each elements are regexp of field-name.")
                     "\n\t")
                 rest)))
            )))
                     "\n\t")
                 rest)))
            )))
-   (function mime-preview-play-current-entity))
+     (function mime-preview-play-current-entity))
+    ))
+
+
+;;; @@ entity-header
+;;;
+
+;;; @@@ entity header filter
+;;;
+
+(defvar mime-view-content-header-filter-alist nil)
+
+(defun mime-view-default-content-header-filter ()
+  (mime-view-cut-header)
+  (eword-decode-header)
   )
 
   )
 
-(defun mime-view-entity-button-function (rcnum cinfo
-                                              media-type media-subtype
-                                              params subj encoding)
-  "Insert entity button conditionally.
-Please redefine this function if you want to change default setting."
-  (or (null rcnum)
-      (and (eq media-type 'application)
-          (or (eq media-subtype 'x-selection)
-              (and (eq media-subtype 'octet-stream)
-                   (let ((entity-info
-                          (mime-article/rcnum-to-cinfo (cdr rcnum) cinfo)))
-                     (and (eq (mime-entity-info-media-type entity-info)
-                              'multipart)
-                          (eq (mime-entity-info-media-subtype entity-info)
-                              'encrypted)
-                          )))))
-      (mime-view-insert-entity-button
-       rcnum cinfo media-type media-subtype params subj encoding)
-      ))
-
-
-;;; @@ content header filter
+;;; @@@ entity field cutter
 ;;;
 
 ;;;
 
+(defvar mime-view-ignored-field-list
+  '(".*Received" ".*Path" ".*Id" "References"
+    "Replied" "Errors-To"
+    "Lines" "Sender" ".*Host" "Xref"
+    "Content-Type" "Precedence"
+    "Status" "X-VM-.*")
+  "All fields that match this list will be hidden in MIME preview buffer.
+Each elements are regexp of field-name.")
+
+(defvar mime-view-ignored-field-regexp
+  (concat "^"
+         (apply (function regexp-or) mime-view-ignored-field-list)
+         ":"))
+
+(defvar mime-view-visible-field-list '("Dnas.*" "Message-Id")
+  "All fields that match this list will be displayed in MIME preview buffer.
+Each elements are regexp of field-name.")
+
 (defun mime-view-cut-header ()
   (goto-char (point-min))
   (while (re-search-forward mime-view-ignored-field-regexp nil t)
 (defun mime-view-cut-header ()
   (goto-char (point-min))
   (while (re-search-forward mime-view-ignored-field-regexp nil t)
@@ -253,103 +362,376 @@ Please redefine this function if you want to change default setting."
                           (point-max))))
        ))))
 
                           (point-max))))
        ))))
 
-(defun mime-view-default-content-header-filter ()
-  (mime-view-cut-header)
-  (eword-decode-header)
-  )
-
-(defvar mime-view-content-header-filter-alist nil)
-
 
 
-;;; @@ content filter
+;;; @@ entity-body
 ;;;
 
 ;;;
 
-(defvar mime-view-content-filter-alist
-  '(("text/enriched" . mime-view-filter-for-text/enriched)
-    ("text/richtext" . mime-view-filter-for-text/richtext)
-    (t . mime-view-filter-for-text/plain)
-    )
-  "Alist of media-types vs. corresponding MIME-View filter functions.
-Each element looks like (TYPE/SUBTYPE . FUNCTION) or (t . FUNCTION).
-TYPE/SUBTYPE is a string of media-type and FUNCTION is a filter
-function.  t means default media-type.")
-
-
-;;; @@ entity separator
+;;; @@@ predicate function
 ;;;
 
 ;;;
 
-(defun mime-view-entity-separator-function (rcnum cinfo
-                                                 media-type media-subtype
-                                                 params subj)
-  "Insert entity separator conditionally.
-Please redefine this function if you want to change default setting."
-  (or (mime-view-header-visible-p rcnum cinfo)
-      (mime-view-body-visible-p rcnum cinfo media-type media-subtype)
-      (progn
-       (goto-char (point-max))
-       (insert "\n")
-       )))
-
-
-;;; @@ buffer local variables
+(defun mime-calist::field-match-method-as-default-rule (calist
+                                                       field-type field-value)
+  (let ((s-field (assq field-type calist)))
+    (cond ((null s-field)
+          (cons (cons field-type field-value) calist)
+          )
+         (t calist))))
+
+(define-calist-field-match-method
+  'header #'mime-calist::field-match-method-as-default-rule)
+
+(define-calist-field-match-method
+  'body #'mime-calist::field-match-method-as-default-rule)
+
+
+(defvar mime-preview-condition nil
+  "Condition-tree about how to display entity.")
+
+(ctree-set-calist-strictly
+ 'mime-preview-condition '((type . application)(subtype . octet-stream)
+                          (encoding . nil)
+                          (body . visible)))
+(ctree-set-calist-strictly
+ 'mime-preview-condition '((type . application)(subtype . octet-stream)
+                          (encoding . "7bit")
+                          (body . visible)))
+(ctree-set-calist-strictly
+ 'mime-preview-condition '((type . application)(subtype . octet-stream)
+                          (encoding . "8bit")
+                          (body . visible)))
+
+(ctree-set-calist-strictly
+ 'mime-preview-condition '((type . application)(subtype . pgp)
+                          (body . visible)))
+
+(ctree-set-calist-strictly
+ 'mime-preview-condition '((type . application)(subtype . x-latex)
+                          (body . visible)))
+
+(ctree-set-calist-strictly
+ 'mime-preview-condition '((type . application)(subtype . x-selection)
+                          (body . visible)))
+
+(ctree-set-calist-strictly
+ 'mime-preview-condition '((type . application)(subtype . x-comment)
+                          (body . visible)))
+
+(ctree-set-calist-strictly
+ 'mime-preview-condition '((type . message)(subtype . delivery-status)
+                          (body . visible)))
+
+(ctree-set-calist-strictly
+ 'mime-preview-condition
+ '((body . visible)
+   (body-presentation-method . mime-preview-text/plain)))
+
+(ctree-set-calist-strictly
+ 'mime-preview-condition
+ '((type . nil)
+   (body . visible)
+   (body-presentation-method . mime-preview-text/plain)))
+
+(ctree-set-calist-strictly
+ 'mime-preview-condition
+ '((type . text)(subtype . enriched)
+   (body . visible)
+   (body-presentation-method . mime-preview-text/enriched)))
+
+(ctree-set-calist-strictly
+ 'mime-preview-condition
+ '((type . text)(subtype . richtext)
+   (body . visible)
+   (body-presentation-method . mime-preview-text/richtext)))
+
+(ctree-set-calist-strictly
+ 'mime-preview-condition
+ '((type . text)(subtype . t)
+   (body . visible)
+   (body-presentation-method . mime-preview-text/plain)))
+
+(ctree-set-calist-strictly
+ 'mime-preview-condition
+ '((type . multipart)(subtype . alternative)
+   (body . visible)
+   (body-presentation-method . mime-preview-multipart/alternative)))
+
+(ctree-set-calist-strictly
+ 'mime-preview-condition '((type . message)(subtype . partial)
+                          (body-presentation-method
+                           . mime-preview-message/partial-button)))
+
+(ctree-set-calist-strictly
+ 'mime-preview-condition '((type . message)(subtype . rfc822)
+                          (body-presentation-method . nil)
+                          (childrens-situation (header . visible)
+                                               (entity-button . invisible))))
+
+(ctree-set-calist-strictly
+ 'mime-preview-condition '((type . message)(subtype . news)
+                          (body-presentation-method . nil)
+                          (childrens-situation (header . visible)
+                                               (entity-button . invisible))))
+
+
+;;; @@@ entity presentation
 ;;;
 
 ;;;
 
-;;; @@@ in raw buffer
-;;;
+(autoload 'mime-preview-text/plain "mime-text")
+(autoload 'mime-preview-text/enriched "mime-text")
+(autoload 'mime-preview-text/richtext "mime-text")
 
 
-(defvar mime-raw-entity-info
-  "Information about structure of message.
-Please use reference function `mime-entity-info-SLOT' to get value of
-SLOT.
-
-Following is a list of slots of the structure:
+(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.         ]]"
+    ))
 
 
-rcnum          reversed content-number (list)
-point-min      beginning point of region in raw-buffer
-point-max      end point of region in raw-buffer
-type           media-type (symbol)
-subtype                media-subtype (symbol)
-type/subtype   media-type/subtype (string or nil)
-parameters     parameter of Content-Type field (association list)
-encoding       Content-Transfer-Encoding (string or nil)
-children       entities included in this entity (list of content-infos)
+(defun mime-preview-message/partial-button (&optional entity situation)
+  (save-restriction
+    (goto-char (point-max))
+    (if (not (search-backward "\n\n" nil t))
+       (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)
+    ))
 
 
-If an entity includes other entities in its body, such as multipart or
-message/rfc822, entity-infos of other entities are included in
-`children', so entity-info become a tree.")
-(make-variable-buffer-local 'mime-raw-entity-info)
+(defun mime-preview-multipart/mixed (entity situation)
+  (let ((children (mime-entity-children entity))
+       (default-situation
+         (cdr (assq 'childrens-situation situation))))
+    (while children
+      (mime-view-display-entity (car children)
+                               (save-excursion
+                                 (set-buffer mime-raw-buffer)
+                                 mime-raw-message-info)
+                               mime-raw-buffer (current-buffer)
+                               default-situation)
+      (setq children (cdr children))
+      )))
 
 
-(defvar mime-view-buffer nil
-  "MIME View buffer corresponding with the (raw) buffer.")
-(make-variable-buffer-local 'mime-view-buffer)
+(defcustom mime-view-type-subtype-score-alist
+  '(((text . enriched) . 3)
+    ((text . richtext) . 2)
+    ((text . plain)    . 1)
+    (t . 0))
+  "Alist MEDIA-TYPE vs corresponding score.
+MEDIA-TYPE must be (TYPE . SUBTYPE), TYPE or t.  t means default."
+  :group 'mime-view
+  :type '(repeat (cons (choice :tag "Media-Type"
+                              (item :tag "Type/Subtype"
+                                    (cons symbol symbol))
+                              (item :tag "Type" symbol)
+                              (item :tag "Default" t))
+                      integer)))
+
+(defun mime-preview-multipart/alternative (entity situation)
+  (let* ((children (mime-entity-children entity))
+        (default-situation
+          (cdr (assq 'childrens-situation situation)))
+        (i 0)
+        (p 0)
+        (max-score 0)
+        (situations
+         (mapcar (function
+                  (lambda (child)
+                    (let ((situation
+                           (or (ctree-match-calist
+                                mime-preview-condition
+                                (append
+                                 (or (mime-entity-content-type child)
+                                     (make-mime-content-type 'text 'plain))
+                                 (list* (cons 'encoding
+                                              (mime-entity-encoding child))
+                                        (cons 'major-mode major-mode)
+                                        default-situation)))
+                               default-situation)))
+                      (if (cdr (assq 'body-presentation-method situation))
+                          (let ((score
+                                 (cdr
+                                  (or (assoc
+                                       (cons
+                                        (cdr (assq 'type situation))
+                                        (cdr (assq 'subtype situation)))
+                                       mime-view-type-subtype-score-alist)
+                                      (assq
+                                       (cdr (assq 'type situation))
+                                       mime-view-type-subtype-score-alist)
+                                      (assq
+                                       t
+                                       mime-view-type-subtype-score-alist)
+                                      ))))
+                            (if (> score max-score)
+                                (setq p i
+                                      max-score score)
+                              )))
+                      (setq i (1+ i))
+                      situation)
+                    ))
+                 children)))
+    (setq i 0)
+    (while children
+      (let ((situation (car situations)))
+       (mime-view-display-entity (car children)
+                                 (save-excursion
+                                   (set-buffer mime-raw-buffer)
+                                   mime-raw-message-info)
+                                 mime-raw-buffer (current-buffer)
+                                 default-situation
+                                 (if (= i p)
+                                     situation
+                                   (del-alist 'body-presentation-method
+                                              (copy-alist situation))))
+       )
+      (setq children (cdr children)
+           situations (cdr situations)
+           i (1+ i))
+      )))
 
 
 
 
-;;; @@@ in view buffer
+;;; @ acting-condition
 ;;;
 
 ;;;
 
-(defvar mime-mother-buffer nil
-  "Mother buffer corresponding with the (MIME-View) buffer.
-If current MIME-View buffer is generated by other buffer, such as
-message/partial, it is called `mother-buffer'.")
-(make-variable-buffer-local 'mime-mother-buffer)
-
-(defvar mime-raw-buffer nil
-  "Raw buffer corresponding with the (MIME-View) buffer.")
-(make-variable-buffer-local 'mime-raw-buffer)
-
-(defvar mime-view-original-major-mode nil
-  "Major-mode in mime-raw-buffer.")
-(make-variable-buffer-local 'mime-view-original-major-mode)
-
-(make-variable-buffer-local 'mime::preview/original-window-configuration)
-
+(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))
+           )
+         (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))
+       )))
 
 
-;;; @@ quitting method
+;; (ctree-set-calist-strictly
+;;  'mime-acting-condition
+;;  '((type . t)(subtype . t)(mode . "extract")
+;;    (method . mime-method-to-save)))
+(ctree-set-calist-with-default
+ 'mime-acting-condition
+ '((mode . "extract")
+   (method . mime-method-to-save)))
+
+;; (ctree-set-calist-strictly
+;;  'mime-acting-condition
+;;  '((type . text)(subtype . plain)(mode . "play")
+;;    (method "tm-plain" nil 'file "" 'encoding 'mode 'name)
+;;    ))
+;; (ctree-set-calist-strictly
+;;  'mime-acting-condition
+;;  '((type . text)(subtype . plain)(mode . "print")
+;;    (method "tm-plain" nil 'file "" 'encoding 'mode 'name)
+;;    ))
+;; (ctree-set-calist-strictly
+;;  'mime-acting-condition
+;;  '((type . text)(subtype . html)(mode . "play")
+;;    (method "tm-html" nil 'file "" 'encoding 'mode 'name)
+;;    ))
+(ctree-set-calist-strictly
+ 'mime-acting-condition
+ '((type . text)(subtype . x-rot13-47)(mode . "play")
+   (method . mime-method-to-display-caesar)
+   ))
+(ctree-set-calist-strictly
+ 'mime-acting-condition
+ '((type . text)(subtype . x-rot13-47-48)(mode . "play")
+   (method . mime-method-to-display-caesar)
+   ))
+
+;; (ctree-set-calist-strictly
+;;  'mime-acting-condition
+;;  '((type . audio)(subtype . basic)(mode . "play")
+;;    (method "tm-au" nil 'file "" 'encoding 'mode 'name)
+;;    ))
+
+;; (ctree-set-calist-strictly
+;;  'mime-acting-condition
+;;  '((type . image)(mode . "play")
+;;    (method "tm-image" nil 'file "" 'encoding 'mode 'name)
+;;    ))
+;; (ctree-set-calist-strictly
+;;  'mime-acting-condition
+;;  '((type . image)(mode . "print")
+;;    (method "tm-image" nil 'file "" 'encoding 'mode 'name)
+;;    ))
+
+;; (ctree-set-calist-strictly
+;;  'mime-acting-condition
+;;  '((type . video)(subtype . mpeg)(mode . "play")
+;;    (method "tm-mpeg" nil 'file "" 'encoding 'mode 'name)
+;;    ))
+
+;; (ctree-set-calist-strictly
+;;  'mime-acting-condition
+;;  '((type . application)(subtype . postscript)(mode . "play")
+;;    (method "tm-ps" nil 'file "" 'encoding 'mode 'name)
+;;    ))
+;; (ctree-set-calist-strictly
+;;  'mime-acting-condition
+;;  '((type . application)(subtype . postscript)(mode . "print")
+;;    (method "tm-ps" nil 'file "" 'encoding 'mode 'name)
+;;    ))
+
+(ctree-set-calist-strictly
+ 'mime-acting-condition
+ '((type . message)(subtype . rfc822)(mode . "play")
+   (method . mime-method-to-display-message/rfc822)
+   ))
+(ctree-set-calist-strictly
+ 'mime-acting-condition
+ '((type . message)(subtype . partial)(mode . "play")
+   (method . mime-method-to-store-message/partial)
+   ))
+
+(ctree-set-calist-strictly
+ 'mime-acting-condition
+ '((type . message)(subtype . external-body)
+   ("access-type" . "anon-ftp")
+   (method . mime-method-to-display-message/external-ftp)
+   ))
+
+(ctree-set-calist-strictly
+ 'mime-acting-condition
+ '((type . application)(subtype . octet-stream)
+   (method . mime-method-to-save)
+   ))
+
+
+;;; @ quitting method
 ;;;
 
 ;;;
 
-(defvar mime-view-quitting-method-alist
+(defvar mime-preview-quitting-method-alist
   '((mime-show-message-mode
   '((mime-show-message-mode
-     . mime-view-quitting-method-for-mime-show-message-mode))
+     . mime-preview-quitting-method-for-mime-show-message-mode))
   "Alist of major-mode vs. quitting-method of mime-view.")
 
 (defvar mime-view-over-to-previous-method-alist nil)
   "Alist of major-mode vs. quitting-method of mime-view.")
 
 (defvar mime-view-over-to-previous-method-alist nil)
@@ -359,7 +741,7 @@ message/partial, it is called `mother-buffer'.")
   "Alist of major-mode vs. show-summary-method.")
 
 
   "Alist of major-mode vs. show-summary-method.")
 
 
-;;; @@ following method
+;;; @ following method
 ;;;
 
 (defvar mime-view-following-method-alist nil
 ;;;
 
 (defvar mime-view-following-method-alist nil
@@ -369,7 +751,7 @@ message/partial, it is called `mother-buffer'.")
   '("From"))
 
 
   '("From"))
 
 
-;;; @@ X-Face
+;;; @ X-Face
 ;;;
 
 ;; hack from Gnus 5.0.4.
 ;;;
 
 ;; hack from Gnus 5.0.4.
@@ -401,9 +783,17 @@ The compressed face will be piped to this command.")
          ))))
 
 
          ))))
 
 
+;;; @ miscellaneous
+;;;
+
+(defvar mime-view-uuencode-encoding-name-list '("x-uue" "x-uuencode"))
+
+
 ;;; @ buffer setup
 ;;;
 
 ;;; @ buffer setup
 ;;;
 
+(defvar mime-view-redisplay nil)
+
 (defun mime-view-setup-buffers (&optional ctl encoding ibuf obuf)
   (if ibuf
       (progn
 (defun mime-view-setup-buffers (&optional ctl encoding ibuf obuf)
   (if ibuf
       (progn
@@ -411,13 +801,11 @@ The compressed face will be piped to this command.")
        (set-buffer ibuf)
        ))
   (or mime-view-redisplay
        (set-buffer ibuf)
        ))
   (or mime-view-redisplay
-      (setq mime-raw-entity-info (mime-parse-message ctl encoding))
+      (setq mime-raw-message-info (mime-parse-message ctl encoding))
       )
       )
-  (let* ((cinfo mime-raw-entity-info)
-        (pcl (mime/flatten-content-info cinfo))
-        (the-buf (current-buffer))
-        (mode major-mode)
-        )
+  (let ((message-info mime-raw-message-info)
+       (the-buf (current-buffer))
+       (mode major-mode))
     (or obuf
        (setq obuf (concat "*Preview-" (buffer-name the-buf) "*")))
     (set-buffer (get-buffer-create obuf))
     (or obuf
        (setq obuf (concat "*Preview-" (buffer-name the-buf) "*")))
     (set-buffer (get-buffer-create obuf))
@@ -426,240 +814,143 @@ The compressed face will be piped to this command.")
       (widen)
       (erase-buffer)
       (setq mime-raw-buffer the-buf)
       (widen)
       (erase-buffer)
       (setq mime-raw-buffer the-buf)
-      (setq mime-view-original-major-mode mode)
+      (setq mime-preview-original-major-mode mode)
       (setq major-mode 'mime-view-mode)
       (setq mode-name "MIME-View")
       (setq major-mode 'mime-view-mode)
       (setq mode-name "MIME-View")
-      (while pcl
-       (mime-view-display-entity (car pcl) cinfo the-buf obuf)
-       (setq pcl (cdr pcl))
-       )
+      (mime-view-display-entity message-info message-info
+                               the-buf obuf
+                               '((entity-button . invisible)
+                                 (header . visible)
+                                 ))
       (set-buffer-modified-p nil)
       )
     (setq buffer-read-only t)
     (set-buffer the-buf)
     )
       (set-buffer-modified-p nil)
       )
     (setq buffer-read-only t)
     (set-buffer the-buf)
     )
-  (setq mime-view-buffer obuf)
+  (setq mime-preview-buffer obuf)
   )
 
   )
 
-(defun mime-view-display-entity (content cinfo ibuf obuf)
-  "Display entity from content-info CONTENT."
-  (let* ((beg (mime-entity-info-point-min content))
-        (end (mime-entity-info-point-max content))
-        (media-type (mime-entity-info-media-type content))
-        (media-subtype (mime-entity-info-media-subtype content))
-        (ctype (if media-type
-                   (if media-subtype
-                       (format "%s/%s" media-type media-subtype)
-                     (symbol-name media-type)
-                     )))
-        (params (mime-entity-info-parameters content))
-        (encoding (mime-entity-info-encoding content))
-        (rcnum (mime-entity-info-rnum content))
-        he e nb ne subj)
+(defun mime-view-display-entity (entity message-info ibuf obuf
+                                       default-situation
+                                       &optional situation)
+  (let* ((start (mime-entity-point-min entity))
+        (end (mime-entity-point-max entity))
+         (content-type (mime-entity-content-type entity))
+         (encoding (mime-entity-encoding entity))
+        end-of-header e nb ne subj)
     (set-buffer ibuf)
     (set-buffer ibuf)
-    (goto-char beg)
-    (setq he (if (re-search-forward "^$" nil t)
-                (1+ (match-end 0))
-              end))
-    (if (> he end)
-       (setq he end)
+    (goto-char start)
+    (setq end-of-header (if (re-search-forward "^$" nil t)
+                           (1+ (match-end 0))
+                         end))
+    (if (> end-of-header end)
+       (setq end-of-header end)
       )
     (save-restriction
       )
     (save-restriction
-      (narrow-to-region beg end)
-      (setq subj
-           (eword-decode-string
-            (mime-article/get-subject params encoding)))
-      )
-    (set-buffer obuf)
-    (setq nb (point))
-    (narrow-to-region nb nb)
-    (mime-view-entity-button-function
-     rcnum cinfo media-type media-subtype params subj encoding)
-    (if (mime-view-header-visible-p rcnum cinfo)
-       (mime-view-display-header beg he)
+      (narrow-to-region start end)
+      (setq subj (eword-decode-string (mime-raw-get-subject entity)))
       )
       )
-    (if (and (null rcnum)
-            (member
-             ctype mime-view-content-button-visible-ctype-list))
-       (save-excursion
-         (goto-char (point-max))
-         (mime-view-insert-entity-button
-          rcnum cinfo media-type media-subtype params subj encoding)
-         ))
-    (cond ((mime-view-body-visible-p rcnum cinfo media-type media-subtype)
-          (mime-view-display-body he end
-                                     rcnum cinfo ctype params subj encoding)
-          )
-         ((and (eq media-type 'message)(eq media-subtype 'partial))
-          (mime-view-insert-message/partial-button)
-          )
-         ((and (null rcnum)
-               (null (mime-entity-info-children cinfo))
-               )
-          (goto-char (point-max))
-          (mime-view-insert-entity-button
-           rcnum cinfo media-type media-subtype params subj encoding)
-          ))
-    (mime-view-entity-separator-function
-     rcnum cinfo media-type media-subtype params subj)
-    (setq ne (point-max))
-    (widen)
-    (put-text-property nb ne 'mime-view-raw-buffer ibuf)
-    (put-text-property nb ne 'mime-view-cinfo content)
-    (goto-char ne)
-    ))
-
-(defun mime-view-display-header (beg end)
-  (save-restriction
-    (narrow-to-region (point)(point))
-    (insert-buffer-substring mime-raw-buffer beg end)
-    (let ((f (cdr (assq mime-view-original-major-mode
-                       mime-view-content-header-filter-alist))))
-      (if (functionp f)
-         (funcall f)
-       (mime-view-default-content-header-filter)
-       ))
-    (run-hooks 'mime-view-content-header-filter-hook)
-    ))
-
-(defun mime-view-display-body (beg end rcnum cinfo ctype params subj encoding)
-  (save-restriction
-    (narrow-to-region (point-max)(point-max))
-    (insert-buffer-substring mime-raw-buffer beg end)
-    (let ((f (cdr (or (assoc ctype mime-view-content-filter-alist)
-                     (assq t mime-view-content-filter-alist)))))
-      (and (functionp f)
-          (funcall f ctype params encoding)
-          )
+    (or situation
+       (setq situation
+             (or (ctree-match-calist mime-preview-condition
+                                     (append
+                                      (or content-type
+                                          (make-mime-content-type
+                                           'text 'plain))
+                                      (list* (cons 'encoding   encoding)
+                                             (cons 'major-mode major-mode)
+                                             default-situation)))
+                 default-situation)))
+    (let ((button-is-invisible
+          (eq (cdr (assq 'entity-button situation)) 'invisible))
+         (header-is-visible
+          (eq (cdr (assq 'header situation)) 'visible))
+         (body-presentation-method
+          (cdr (assq 'body-presentation-method situation)))
+         (children (mime-entity-children entity)))
+      (set-buffer obuf)
+      (setq nb (point))
+      (narrow-to-region nb nb)
+      (or button-is-invisible
+         (if (mime-view-entity-button-visible-p entity message-info)
+             (mime-view-insert-entity-button entity message-info subj)
+           ))
+      (if header-is-visible
+         (save-restriction
+           (narrow-to-region (point)(point))
+           (insert-buffer-substring mime-raw-buffer start end-of-header)
+           (let ((f (cdr (assq mime-preview-original-major-mode
+                               mime-view-content-header-filter-alist))))
+             (if (functionp f)
+                 (funcall f)
+               (mime-view-default-content-header-filter)
+               ))
+           (run-hooks 'mime-view-content-header-filter-hook)
+           ))
+      (cond ((eq body-presentation-method 'with-filter)
+            (let ((body-filter (cdr (assq 'body-filter situation))))
+              (save-restriction
+                (narrow-to-region (point-max)(point-max))
+                (insert-buffer-substring mime-raw-buffer end-of-header end)
+                (funcall body-filter situation)
+                )))
+           (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 message-info subj)
+              )
+            (or header-is-visible
+                (progn
+                  (goto-char (point-max))
+                  (insert "\n")
+                  ))
+            ))
+      (setq ne (point-max))
+      (widen)
+      (put-text-property nb ne 'mime-view-raw-buffer ibuf)
+      (put-text-property nb ne 'mime-view-entity entity)
+      (goto-char ne)
+      (if children
+         (if (functionp body-presentation-method)
+             (funcall body-presentation-method entity situation)
+           (mime-preview-multipart/mixed entity situation)
+           ))
       )))
 
       )))
 
-(defun mime-view-insert-message/partial-button ()
-  (save-restriction
-    (goto-char (point-max))
-    (if (not (search-backward "\n\n" nil t))
-       (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)
-                    (function mime-preview-play-current-entity))
-    ))
-
-(defun mime-article/get-uu-filename (param &optional encoding)
-  (if (member (or encoding
-                 (cdr (assq 'encoding param))
-                 )
-             mime-view-uuencode-encoding-name-list)
-      (save-excursion
-       (or (if (re-search-forward "^begin [0-9]+ " nil t)
-               (if (looking-at ".+$")
-                   (buffer-substring (match-beginning 0)(match-end 0))
-                 ))
-           ""))
-    ))
+(defun mime-raw-get-uu-filename ()
+  (save-excursion
+    (if (re-search-forward "^begin [0-9]+ " nil t)
+       (if (looking-at ".+$")
+           (buffer-substring (match-beginning 0)(match-end 0))
+         ))))
 
 
-(defun mime-article/get-subject (param &optional encoding)
+(defun mime-raw-get-subject (entity)
   (or (std11-find-field-body '("Content-Description" "Subject"))
   (or (std11-find-field-body '("Content-Description" "Subject"))
-      (let (ret)
-       (if (or (and (setq ret (mime/Content-Disposition))
-                    (setq ret (assoc "filename" (cdr ret)))
-                    )
-               (setq ret (assoc "name" param))
-               (setq ret (assoc "x-name" param))
-               )
-           (std11-strip-quoted-string (cdr ret))
-         ))
-      (mime-article/get-uu-filename param encoding)
+      (let ((ret (mime-entity-content-disposition entity)))
+       (and ret
+            (setq ret (mime-content-disposition-filename ret))
+            (std11-strip-quoted-string ret)
+            ))
+      (let ((ret (mime-entity-content-type entity)))
+       (and ret
+            (setq ret
+                  (cdr
+                   (let ((param (mime-content-type-parameters ret)))
+                     (or (assoc "name" param)
+                         (assoc "x-name" param))
+                     )))
+            (std11-strip-quoted-string ret)
+            ))
+      (if (member (mime-entity-encoding entity)
+                 mime-view-uuencode-encoding-name-list)
+         (mime-raw-get-uu-filename))
       ""))
 
 
       ""))
 
 
-;;; @ entity information
-;;;
-
-(defun mime-article/point-content-number (p &optional cinfo)
-  (or cinfo
-      (setq cinfo mime-raw-entity-info)
-      )
-  (let ((b (mime-entity-info-point-min cinfo))
-       (e (mime-entity-info-point-max cinfo))
-       (c (mime-entity-info-children cinfo))
-       )
-    (if (and (<= b p)(<= p e))
-       (or (let (co ret (sn 0))
-             (catch 'tag
-               (while c
-                 (setq co (car c))
-                 (setq ret (mime-article/point-content-number p co))
-                 (cond ((eq ret t) (throw 'tag (list sn)))
-                       (ret (throw 'tag (cons sn ret)))
-                       )
-                 (setq c (cdr c))
-                 (setq sn (1+ sn))
-                 )))
-           t))))
-
-(defsubst mime-article/rcnum-to-cinfo (rnum &optional cinfo)
-  (mime-article/cnum-to-cinfo (reverse rnum) cinfo)
-  )
-
-(defun mime-article/cnum-to-cinfo (cn &optional cinfo)
-  (or cinfo
-      (setq cinfo mime-raw-entity-info)
-      )
-  (if (eq cn t)
-      cinfo
-    (let ((sn (car cn)))
-      (if (null sn)
-         cinfo
-       (let ((rc (nth sn (mime-entity-info-children cinfo))))
-         (if rc
-             (mime-article/cnum-to-cinfo (cdr cn) rc)
-           ))
-       ))))
-
-(defun mime/flatten-content-info (&optional cinfo)
-  (or cinfo
-      (setq cinfo mime-raw-entity-info)
-      )
-  (let ((dest (list cinfo))
-       (rcl (mime-entity-info-children cinfo))
-       )
-    (while rcl
-      (setq dest (nconc dest (mime/flatten-content-info (car rcl))))
-      (setq rcl (cdr rcl))
-      )
-    dest))
-
-
-;;; @@ predicate functions
-;;;
-
-(defun mime-view-header-visible-p (rcnum cinfo)
-  "Return non-nil if header of current entity is visible."
-  (or (null rcnum)
-      (member (mime-entity-info-type/subtype
-              (mime-article/rcnum-to-cinfo (cdr rcnum) cinfo))
-             mime-view-childrens-header-showing-Content-Type-list)
-      ))
-
-(defun mime-view-body-visible-p (rcnum cinfo media-type media-subtype)
-  (let ((ctype (if media-type
-                  (if media-subtype
-                      (format "%s/%s" media-type media-subtype)
-                    (symbol-name media-type)
-                    ))))
-    (and (member ctype mime-view-visible-media-type-list)
-        (if (and (eq media-type 'application)
-                 (eq media-subtype 'octet-stream))
-            (let ((ccinfo (mime-article/rcnum-to-cinfo rcnum cinfo)))
-              (member (mime-entity-info-encoding ccinfo)
-                      '(nil "7bit" "8bit"))
-              )
-          t))
-    ))
-
-
 ;;; @ MIME viewer mode
 ;;;
 
 ;;; @ MIME viewer mode
 ;;;
 
@@ -672,8 +963,8 @@ The compressed face will be piped to this command.")
     (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)
     (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-view-print-current-entity)
-    (x-face     "Show X Face"             mime-view-display-x-face)
+    (print      "Print current entity"    mime-preview-print-current-entity)
+    (x-face     "Show X Face"             mime-preview-display-x-face)
     )
   "Menu for MIME Viewer")
 
     )
   "Menu for MIME Viewer")
 
@@ -727,15 +1018,15 @@ The compressed face will be piped to this command.")
     (define-key mime-view-mode-map
       "e"        (function mime-preview-extract-current-entity))
     (define-key mime-view-mode-map
     (define-key mime-view-mode-map
       "e"        (function mime-preview-extract-current-entity))
     (define-key mime-view-mode-map
-      "\C-c\C-p" (function mime-view-print-current-entity))
+      "\C-c\C-p" (function mime-preview-print-current-entity))
     (define-key mime-view-mode-map
     (define-key mime-view-mode-map
-      "a"        (function mime-view-follow-current-entity))
+      "a"        (function mime-preview-follow-current-entity))
     (define-key mime-view-mode-map
     (define-key mime-view-mode-map
-      "q"        (function mime-view-quit))
+      "q"        (function mime-preview-quit))
     (define-key mime-view-mode-map
     (define-key mime-view-mode-map
-      "h"        (function mime-view-show-summary))
+      "h"        (function mime-preview-show-summary))
     (define-key mime-view-mode-map
     (define-key mime-view-mode-map
-      "\C-c\C-x" (function mime-view-kill-buffer))
+      "\C-c\C-x" (function mime-preview-kill-buffer))
     ;; (define-key mime-view-mode-map
     ;;   "<"        (function beginning-of-buffer))
     ;; (define-key mime-view-mode-map
     ;; (define-key mime-view-mode-map
     ;;   "<"        (function beginning-of-buffer))
     ;; (define-key mime-view-mode-map
@@ -828,13 +1119,14 @@ button-2 Move to point under the mouse cursor
        )
     (prog1
        (switch-to-buffer ret)
        )
     (prog1
        (switch-to-buffer ret)
-      (setq mime::preview/original-window-configuration win-conf)
+      (setq mime-preview-original-window-configuration win-conf)
       (if mother
          (progn
            (setq mime-mother-buffer mother)
            ))
       (mime-view-define-keymap default-keymap-or-function)
       (if mother
          (progn
            (setq mime-mother-buffer mother)
            ))
       (mime-view-define-keymap default-keymap-or-function)
-      (let ((point (next-single-property-change (point-min) 'mime-view-cinfo)))
+      (let ((point
+            (next-single-property-change (point-min) 'mime-view-entity)))
        (if point
            (goto-char point)
          (goto-char (point-min))
        (if point
            (goto-char point)
          (goto-char (point-min))
@@ -859,7 +1151,7 @@ It decodes current entity to call internal or external method as
   (mime-preview-play-current-entity "extract")
   )
 
   (mime-preview-play-current-entity "extract")
   )
 
-(defun mime-view-print-current-entity ()
+(defun mime-preview-print-current-entity ()
   "Print current entity (maybe).
 It decodes current entity to call internal or external method as
 \"print\" mode.  The method is selected from variable
   "Print current entity (maybe).
 It decodes current entity to call internal or external method as
 \"print\" mode.  The method is selected from variable
@@ -872,49 +1164,50 @@ It decodes current entity to call internal or external method as
 ;;; @@ following
 ;;;
 
 ;;; @@ following
 ;;;
 
-(defun mime-view-get-original-major-mode ()
+(defun mime-preview-original-major-mode ()
   "Return major-mode of original buffer.
 If a current buffer has mime-mother-buffer, return original major-mode
 of the mother-buffer."
   (if mime-mother-buffer
       (save-excursion
        (set-buffer mime-mother-buffer)
   "Return major-mode of original buffer.
 If a current buffer has mime-mother-buffer, return original major-mode
 of the mother-buffer."
   (if mime-mother-buffer
       (save-excursion
        (set-buffer mime-mother-buffer)
-       (mime-view-get-original-major-mode)
+       (mime-preview-original-major-mode)
        )
        )
-    mime-view-original-major-mode))
+    mime-preview-original-major-mode))
 
 
-(defun mime-view-follow-current-entity ()
+(defun mime-preview-follow-current-entity ()
   "Write follow message to current entity.
 It calls following-method selected from variable
 `mime-view-following-method-alist'."
   (interactive)
   "Write follow message to current entity.
 It calls following-method selected from variable
 `mime-view-following-method-alist'."
   (interactive)
-  (let ((root-cinfo (get-text-property (point-min) 'mime-view-cinfo))
-       cinfo)
-    (while (null (setq cinfo (get-text-property (point) 'mime-view-cinfo)))
+  (let (entity)
+    (while (null (setq entity
+                      (get-text-property (point) 'mime-view-entity)))
       (backward-char)
       )
       (backward-char)
       )
-    (let* ((p-beg (previous-single-property-change (point) 'mime-view-cinfo))
+    (let* ((p-beg
+           (previous-single-property-change (point) 'mime-view-entity))
           p-end
           p-end
-          (rcnum (mime-entity-info-rnum cinfo))
-          (len (length rcnum))
+          (entity-node-id (mime-entity-node-id entity))
+          (len (length entity-node-id))
           )
       (cond ((null p-beg)
             (setq p-beg
                   (if (eq (next-single-property-change (point-min)
           )
       (cond ((null p-beg)
             (setq p-beg
                   (if (eq (next-single-property-change (point-min)
-                                                       'mime-view-cinfo)
+                                                       'mime-view-entity)
                           (point))
                       (point)
                     (point-min)))
             )
                           (point))
                       (point)
                     (point-min)))
             )
-           ((eq (next-single-property-change p-beg 'mime-view-cinfo)
+           ((eq (next-single-property-change p-beg 'mime-view-entity)
                 (point))
             (setq p-beg (point))
             ))
                 (point))
             (setq p-beg (point))
             ))
-      (setq p-end (next-single-property-change p-beg 'mime-view-cinfo))
+      (setq p-end (next-single-property-change p-beg 'mime-view-entity))
       (cond ((null p-end)
             (setq p-end (point-max))
             )
       (cond ((null p-end)
             (setq p-end (point-max))
             )
-           ((null rcnum)
+           ((null entity-node-id)
             (setq p-end (point-max))
             )
            (t
             (setq p-end (point-max))
             )
            (t
@@ -924,12 +1217,13 @@ It calls following-method selected from variable
                 (let (e)
                   (while (setq e
                                (next-single-property-change
                 (let (e)
                   (while (setq e
                                (next-single-property-change
-                                (point) 'mime-view-cinfo))
+                                (point) 'mime-view-entity))
                     (goto-char e)
                     (goto-char e)
-                    (let ((rc (mime-entity-info-rnum
+                    (let ((rc (mime-entity-node-id
                                (get-text-property (point)
                                (get-text-property (point)
-                                                  'mime-view-cinfo))))
-                      (or (equal rcnum (nthcdr (- (length rc) len) rc))
+                                                  'mime-view-entity))))
+                      (or (equal entity-node-id
+                                 (nthcdr (- (length rc) len) rc))
                           (throw 'tag nil)
                           ))
                     (setq p-end e)
                           (throw 'tag nil)
                           ))
                     (setq p-end e)
@@ -937,8 +1231,9 @@ It calls following-method selected from variable
                 (setq p-end (point-max))
                 ))
             ))
                 (setq p-end (point-max))
                 ))
             ))
-      (let* ((mode (mime-view-get-original-major-mode))
-            (new-name (format "%s-%s" (buffer-name) (reverse rcnum)))
+      (let* ((mode (mime-preview-original-major-mode))
+            (new-name
+             (format "%s-%s" (buffer-name) (reverse entity-node-id)))
             new-buf
             (the-buf (current-buffer))
             (a-buf mime-raw-buffer)
             new-buf
             (the-buf (current-buffer))
             (a-buf mime-raw-buffer)
@@ -948,40 +1243,34 @@ It calls following-method selected from variable
          (erase-buffer)
          (insert-buffer-substring the-buf p-beg p-end)
          (goto-char (point-min))
          (erase-buffer)
          (insert-buffer-substring the-buf p-beg p-end)
          (goto-char (point-min))
-         (if (mime-view-header-visible-p rcnum root-cinfo)
-             (delete-region (goto-char (point-min))
-                            (if (re-search-forward "^$" nil t)
-                                (match-end 0)
-                              (point-min)))
-           )
-         (goto-char (point-min))
-         (insert "\n")
-         (goto-char (point-min))
-         (let ((rcnum (mime-entity-info-rnum cinfo)) ci str)
+          (let ((entity-node-id (mime-entity-node-id entity)) ci str)
            (while (progn
            (while (progn
-                    (setq str
-                          (save-excursion
-                            (set-buffer a-buf)
-                            (setq ci (mime-article/rcnum-to-cinfo rcnum))
-                            (save-restriction
-                              (narrow-to-region
-                               (mime-entity-info-point-min ci)
-                               (mime-entity-info-point-max ci)
-                               )
-                              (std11-header-string-except
-                               (concat "^"
-                                       (apply (function regexp-or) fields)
-                                       ":") ""))))
+                    (setq
+                     str
+                     (save-excursion
+                       (set-buffer a-buf)
+                       (setq
+                        ci
+                        (mime-raw-find-entity-from-node-id entity-node-id))
+                       (save-restriction
+                         (narrow-to-region
+                          (mime-entity-point-min ci)
+                          (mime-entity-point-max ci)
+                          )
+                         (std11-header-string-except
+                          (concat "^"
+                                  (apply (function regexp-or) fields)
+                                  ":") ""))))
                     (if (and
                     (if (and
-                         (eq (mime-entity-info-media-type ci) 'message)
-                         (eq (mime-entity-info-media-subtype ci) 'rfc822))
+                         (eq (mime-entity-media-type ci) 'message)
+                         (eq (mime-entity-media-subtype ci) 'rfc822))
                         nil
                       (if str
                           (insert str)
                         )
                         nil
                       (if str
                           (insert str)
                         )
-                      rcnum))
+                      entity-node-id))
              (setq fields (std11-collect-field-names)
              (setq fields (std11-collect-field-names)
-                   rcnum (cdr rcnum))
+                   entity-node-id (cdr entity-node-id))
              )
            )
          (let ((rest mime-view-following-required-fields-list))
              )
            )
          (let ((rest mime-view-following-required-fields-list))
@@ -1018,7 +1307,7 @@ It calls following-method selected from variable
 ;;; @@ X-Face
 ;;;
 
 ;;; @@ X-Face
 ;;;
 
-(defun mime-view-display-x-face ()
+(defun mime-preview-display-x-face ()
   (interactive)
   (save-window-excursion
     (set-buffer mime-raw-buffer)
   (interactive)
   (save-window-excursion
     (set-buffer mime-raw-buffer)
@@ -1031,25 +1320,26 @@ It calls following-method selected from variable
 
 (defun mime-preview-move-to-upper ()
   "Move to upper entity.
 
 (defun mime-preview-move-to-upper ()
   "Move to upper entity.
-If there is no upper entity, call function `mime-view-quit'."
+If there is no upper entity, call function `mime-preview-quit'."
   (interactive)
   (let (cinfo)
   (interactive)
   (let (cinfo)
-    (while (null (setq cinfo (get-text-property (point) 'mime-view-cinfo)))
+    (while (null (setq cinfo
+                      (get-text-property (point) 'mime-view-entity)))
       (backward-char)
       )
       (backward-char)
       )
-    (let ((r (mime-article/rcnum-to-cinfo
-             (cdr (mime-entity-info-rnum cinfo))
-             (get-text-property 1 'mime-view-cinfo)))
+    (let ((r (mime-raw-find-entity-from-node-id
+             (cdr (mime-entity-node-id cinfo))
+             (get-text-property 1 'mime-view-entity)))
          point)
       (catch 'tag
        (while (setq point (previous-single-property-change
          point)
       (catch 'tag
        (while (setq point (previous-single-property-change
-                           (point) 'mime-view-cinfo))
+                           (point) 'mime-view-entity))
          (goto-char point)
          (goto-char point)
-         (if (eq r (get-text-property (point) 'mime-view-cinfo))
+         (if (eq r (get-text-property (point) 'mime-view-entity))
              (throw 'tag t)
            )
          )
              (throw 'tag t)
            )
          )
-       (mime-view-quit)
+       (mime-preview-quit)
        ))))
 
 (defun mime-preview-move-to-previous ()
        ))))
 
 (defun mime-preview-move-to-previous ()
@@ -1057,13 +1347,17 @@ If there is no upper entity, call function `mime-view-quit'."
 If there is no previous entity, it calls function registered in
 variable `mime-view-over-to-previous-method-alist'."
   (interactive)
 If there is no previous entity, it calls function registered in
 variable `mime-view-over-to-previous-method-alist'."
   (interactive)
-  (while (null (get-text-property (point) 'mime-view-cinfo))
+  (while (null (get-text-property (point) 'mime-view-entity))
     (backward-char)
     )
     (backward-char)
     )
-  (let ((point (previous-single-property-change (point) 'mime-view-cinfo)))
+  (let ((point (previous-single-property-change (point) 'mime-view-entity)))
     (if point
     (if point
-       (goto-char point)
-      (let ((f (assq mime-view-original-major-mode
+       (if (get-text-property (1- point) 'mime-view-entity)
+           (goto-char point)
+         (goto-char (1- point))
+         (mime-preview-move-to-previous)
+         )
+      (let ((f (assq mime-preview-original-major-mode
                     mime-view-over-to-previous-method-alist)))
        (if f
            (funcall (cdr f))
                     mime-view-over-to-previous-method-alist)))
        (if f
            (funcall (cdr f))
@@ -1075,10 +1369,17 @@ variable `mime-view-over-to-previous-method-alist'."
 If there is no previous entity, it calls function registered in
 variable `mime-view-over-to-next-method-alist'."
   (interactive)
 If there is no previous entity, it calls function registered in
 variable `mime-view-over-to-next-method-alist'."
   (interactive)
-  (let ((point (next-single-property-change (point) 'mime-view-cinfo)))
+  (while (null (get-text-property (point) 'mime-view-entity))
+    (forward-char)
+    )
+  (let ((point (next-single-property-change (point) 'mime-view-entity)))
     (if point
     (if point
-       (goto-char point)
-      (let ((f (assq mime-view-original-major-mode
+       (progn
+         (goto-char point)
+         (if (null (get-text-property point 'mime-view-entity))
+             (mime-preview-move-to-next)
+           ))
+      (let ((f (assq mime-preview-original-major-mode
                     mime-view-over-to-next-method-alist)))
        (if f
            (funcall (cdr f))
                     mime-view-over-to-next-method-alist)))
        (if f
            (funcall (cdr f))
@@ -1094,13 +1395,13 @@ If reached to (point-max), it calls function registered in variable
       (setq h (1- (window-height)))
       )
   (if (= (point) (point-max))
       (setq h (1- (window-height)))
       )
   (if (= (point) (point-max))
-      (let ((f (assq mime-view-original-major-mode
+      (let ((f (assq mime-preview-original-major-mode
                      mime-view-over-to-next-method-alist)))
         (if f
             (funcall (cdr f))
           ))
     (let ((point
                      mime-view-over-to-next-method-alist)))
         (if f
             (funcall (cdr f))
           ))
     (let ((point
-          (or (next-single-property-change (point) 'mime-view-cinfo)
+          (or (next-single-property-change (point) 'mime-view-entity)
               (point-max))))
       (forward-line h)
       (if (> (point) point)
               (point-max))))
       (forward-line h)
       (if (> (point) point)
@@ -1117,7 +1418,7 @@ If reached to (point-min), it calls function registered in variable
       (setq h (1- (window-height)))
       )
   (if (= (point) (point-min))
       (setq h (1- (window-height)))
       )
   (if (= (point) (point-min))
-      (let ((f (assq mime-view-original-major-mode
+      (let ((f (assq mime-preview-original-major-mode
                      mime-view-over-to-previous-method-alist)))
         (if f
             (funcall (cdr f))
                      mime-view-over-to-previous-method-alist)))
         (if f
             (funcall (cdr f))
@@ -1125,10 +1426,10 @@ If reached to (point-min), it calls function registered in variable
     (let (point)
       (save-excursion
        (catch 'tag
     (let (point)
       (save-excursion
        (catch 'tag
-         (while (> (point) 1)
+         (while (not (bobp))
            (if (setq point
                      (previous-single-property-change (point)
            (if (setq point
                      (previous-single-property-change (point)
-                                                      'mime-view-cinfo))
+                                                      'mime-view-entity))
                (throw 'tag t)
              )
            (backward-char)
                (throw 'tag t)
              )
            (backward-char)
@@ -1154,29 +1455,29 @@ If reached to (point-min), it calls function registered in variable
 ;;; @@ quitting
 ;;;
 
 ;;; @@ quitting
 ;;;
 
-(defun mime-view-quit ()
-  "Quit from MIME-View buffer.
+(defun mime-preview-quit ()
+  "Quit from MIME-preview buffer.
 It calls function registered in variable
 It calls function registered in variable
-`mime-view-quitting-method-alist'."
+`mime-preview-quitting-method-alist'."
   (interactive)
   (interactive)
-  (let ((r (assq mime-view-original-major-mode
-                mime-view-quitting-method-alist)))
+  (let ((r (assq mime-preview-original-major-mode
+                mime-preview-quitting-method-alist)))
     (if r
        (funcall (cdr r))
       )))
 
     (if r
        (funcall (cdr r))
       )))
 
-(defun mime-view-show-summary ()
+(defun mime-preview-show-summary ()
   "Show summary.
 It calls function registered in variable
 `mime-view-show-summary-method'."
   (interactive)
   "Show summary.
 It calls function registered in variable
 `mime-view-show-summary-method'."
   (interactive)
-  (let ((r (assq mime-view-original-major-mode
+  (let ((r (assq mime-preview-original-major-mode
                 mime-view-show-summary-method)))
     (if r
        (funcall (cdr r))
       )))
 
                 mime-view-show-summary-method)))
     (if r
        (funcall (cdr r))
       )))
 
-(defun mime-view-kill-buffer ()
+(defun mime-preview-kill-buffer ()
   (interactive)
   (kill-buffer (current-buffer))
   )
   (interactive)
   (kill-buffer (current-buffer))
   )