Sync with semi-1_13.
[elisp/semi.git] / mime-play.el
index 8c72112..38d6cfa 100644 (file)
@@ -1,6 +1,6 @@
 ;;; mime-play.el --- Playback processing module for mime-view.el
 
 ;;; mime-play.el --- Playback processing module for mime-view.el
 
-;; Copyright (C) 1994,1995,1996,1997,1998 Free Software Foundation, Inc.
+;; Copyright (C) 1994,1995,1996,1997,1998,1999 Free Software Foundation, Inc.
 
 ;; Author: MORIOKA Tomohiko <morioka@jaist.ac.jp>
 ;; Created: 1995/9/26 (separated from tm-view.el)
 
 ;; Author: MORIOKA Tomohiko <morioka@jaist.ac.jp>
 ;; Created: 1995/9/26 (separated from tm-view.el)
 (require 'filename)
 
 (eval-when-compile
 (require 'filename)
 
 (eval-when-compile
-  (require 'mime-text)
   (condition-case nil
       (require 'bbdb)
   (condition-case nil
       (require 'bbdb)
-    (error (defvar bbdb-buffer-name nil))
-    ))
+    (error (defvar bbdb-buffer-name nil)))
+  )
+
+(defcustom mime-save-directory "~/"
+  "*Name of the directory where MIME entity will be saved in.
+If t, it means current directory."
+  :group 'mime-view
+  :type '(choice (const :tag "Current directory" t)
+                (directory)))
 
 
-(defvar mime-acting-situation-examples nil)
+(defvar mime-acting-situation-example-list nil)
+
+(defvar mime-acting-situation-example-list-max-size 16)
 
 (defun mime-save-acting-situation-examples ()
   (let* ((file mime-acting-situation-examples-file)
 
 (defun mime-save-acting-situation-examples ()
   (let* ((file mime-acting-situation-examples-file)
           (erase-buffer)
           (insert ";;; " (file-name-nondirectory file) "\n")
           (insert "\n;; This file is generated automatically by "
           (erase-buffer)
           (insert ";;; " (file-name-nondirectory file) "\n")
           (insert "\n;; This file is generated automatically by "
-                  mime-view-version-string "\n\n")
+                  mime-view-version "\n\n")
          (insert ";;; Code:\n\n")
          (insert ";;; Code:\n\n")
-         (pp `(setq mime-acting-situation-examples
-                    ',mime-acting-situation-examples)
+         (pp `(setq mime-acting-situation-example-list
+                    ',mime-acting-situation-example-list)
              (current-buffer))
          (insert "\n;;; "
                   (file-name-nondirectory file)
              (current-buffer))
          (insert "\n;;; "
                   (file-name-nondirectory file)
 
 (add-hook 'kill-emacs-hook 'mime-save-acting-situation-examples)
 
 
 (add-hook 'kill-emacs-hook 'mime-save-acting-situation-examples)
 
-  
+(defun mime-reduce-acting-situation-examples ()
+  (let ((len (length mime-acting-situation-example-list))
+       i ir ic j jr jc ret
+       dest d-i d-j
+       (max-sim 0) sim
+       min-det-ret det-ret
+       min-det-org det-org
+       min-freq freq)
+    (setq i 0
+         ir mime-acting-situation-example-list)
+    (while (< i len)
+      (setq ic (car ir)
+           j 0
+           jr mime-acting-situation-example-list)
+      (while (< j len)
+       (unless (= i j)
+         (setq jc (car jr))
+         (setq ret (mime-compare-situation-with-example (car ic)(car jc))
+               sim (car ret)
+               det-ret (+ (length (car ic))(length (car jc)))
+               det-org (length (cdr ret))
+               freq (+ (cdr ic)(cdr jc)))
+         (cond ((< max-sim sim)
+                (setq max-sim sim
+                      min-det-ret det-ret
+                      min-det-org det-org
+                      min-freq freq
+                      d-i i
+                      d-j j
+                      dest (cons (cdr ret) freq))
+                )
+               ((= max-sim sim)
+                (cond ((> min-det-ret det-ret)
+                       (setq min-det-ret det-ret
+                             min-det-org det-org
+                             min-freq freq
+                             d-i i
+                             d-j j
+                             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))
+                              )
+                             ((= min-det-org det-org)
+                              (cond ((> min-freq freq)
+                                     (setq min-freq freq
+                                           d-i i
+                                           d-j j
+                                           dest (cons (cdr ret) freq))
+                                     ))
+                              ))
+                       ))
+                ))
+         )
+       (setq jr (cdr jr)
+             j (1+ j)))
+      (setq ir (cdr ir)
+           i (1+ i)))
+    (if (> d-i d-j)
+       (setq i d-i
+             d-i d-j
+             d-j i))
+    (setq jr (nthcdr (1- d-j) mime-acting-situation-example-list))
+    (setcdr jr (cddr jr))
+    (if (= d-i 0)
+       (setq mime-acting-situation-example-list
+             (cdr mime-acting-situation-example-list))
+      (setq ir (nthcdr (1- d-i) mime-acting-situation-example-list))
+      (setcdr ir (cddr ir))
+      )
+    (if (setq ir (assoc (car dest) mime-acting-situation-example-list))
+       (setcdr ir (+ (cdr ir)(cdr dest)))
+      (setq mime-acting-situation-example-list
+           (cons dest mime-acting-situation-example-list))
+      )))
+
+
 ;;; @ content decoder
 ;;;
 
 ;;; @ content decoder
 ;;;
 
-(defvar mime-preview-after-decoded-position nil)
-
-(defun mime-preview-play-current-entity (&optional mode)
+;;;###autoload
+(defun mime-preview-play-current-entity (&optional ignore-examples mode)
   "Play current entity.
 It decodes current entity to call internal or external method.  The
 method is selected from variable `mime-acting-condition'.
   "Play current entity.
 It decodes current entity to call internal or external method.  The
 method is selected from variable `mime-acting-condition'.
+If IGNORE-EXAMPLES (C-u prefix) is specified, this function ignores
+`mime-acting-situation-example-list'.
 If MODE is specified, play as it.  Default MODE is \"play\"."
 If MODE is specified, play as it.  Default MODE is \"play\"."
-  (interactive)
-  (or mode
-      (setq mode "play"))
+  (interactive "P")
   (let ((entity (get-text-property (point) 'mime-view-entity)))
     (if entity
   (let ((entity (get-text-property (point) 'mime-view-entity)))
     (if entity
-       (let ((the-buf (current-buffer))
-             (raw-buffer (mime-entity-buffer entity)))
-         (setq mime-preview-after-decoded-position (point))
-         (set-buffer raw-buffer)
-         (mime-raw-play-entity entity mode)
-         (when (eq (current-buffer) raw-buffer)
-           (set-buffer the-buf)
-           (goto-char mime-preview-after-decoded-position)
-           )))))
+       (let ((situation
+              (get-text-property (point) 'mime-view-situation)))
+         (or mode
+             (setq mode "play"))
+         (setq situation 
+               (if (assq 'mode situation)
+                   (put-alist 'mode mode (copy-alist situation))
+                 (cons (cons 'mode mode)
+                       situation)))
+         (if ignore-examples
+             (setq situation
+                   (cons (cons 'ignore-examples ignore-examples)
+                         situation)))
+         (mime-play-entity entity situation)
+         ))))
 
 (defun mime-sort-situation (situation)
   (sort situation
 
 (defun mime-sort-situation (situation)
   (sort situation
@@ -96,23 +190,26 @@ If MODE is specified, play as it.  Default MODE is \"play\"."
                  (order '((type . 1)
                           (subtype . 2)
                           (mode . 3)
                  (order '((type . 1)
                           (subtype . 2)
                           (mode . 3)
-                          (major-mode . 4)))
+                          (method . 4)
+                          (major-mode . 5)
+                          (disposition-type . 6)
+                          ))
                  a-order b-order)
              (if (symbolp a-t)
                  (let ((ret (assq a-t order)))
                    (if ret
                        (setq a-order (cdr ret))
                  a-order b-order)
              (if (symbolp a-t)
                  (let ((ret (assq a-t order)))
                    (if ret
                        (setq a-order (cdr ret))
-                     (setq a-order 5)
+                     (setq a-order 7)
                      ))
                      ))
-               (setq a-order 6)
+               (setq a-order 8)
                )
              (if (symbolp b-t)
                  (let ((ret (assq b-t order)))
                    (if ret
                        (setq b-order (cdr ret))
                )
              (if (symbolp b-t)
                  (let ((ret (assq b-t order)))
                    (if ret
                        (setq b-order (cdr ret))
-                     (setq b-order 5)
+                     (setq b-order 7)
                      ))
                      ))
-               (setq b-order 6)
+               (setq b-order 8)
                )
              (if (= a-order b-order)
                  (string< (format "%s" a-t)(format "%s" b-t))
                )
              (if (= a-order b-order)
                  (string< (format "%s" a-t)(format "%s" b-t))
@@ -120,41 +217,101 @@ If MODE is specified, play as it.  Default MODE is \"play\"."
              )))
   )
 
              )))
   )
 
-(defsubst mime-delq-null-situation (situations field)
+(defsubst mime-delq-null-situation (situations field
+                                              &optional ignored-value)
   (let (dest)
     (while situations
   (let (dest)
     (while situations
-      (let ((situation (car situations)))
-       (if (assq field situation)
-           (setq dest (cons situation dest))
-         ))
+      (let* ((situation (car situations))
+            (cell (assq field situation)))
+       (if cell
+           (or (eq (cdr cell) ignored-value)
+               (setq dest (cons situation dest))
+               )))
       (setq situations (cdr situations)))
     dest))
 
       (setq situations (cdr situations)))
     dest))
 
-(defun mime-raw-play-entity (entity &optional mode)
+(defun mime-compare-situation-with-example (situation example)
+  (let ((example (copy-alist example))
+       (match 0))
+    (while situation
+      (let* ((cell (car situation))
+            (key (car cell))
+            (ecell (assoc key example)))
+       (when ecell
+         (if (equal cell ecell)
+             (setq match (1+ match))
+           (setq example (delq ecell example))
+           ))
+       )
+      (setq situation (cdr situation))
+      )
+    (cons match example)
+    ))
+
+;;;###autoload
+(defun mime-play-entity (entity &optional situation ignored-method)
   "Play entity specified by ENTITY.
 It decodes the entity to call internal or external method.  The method
 is selected from variable `mime-acting-condition'.  If MODE is
 specified, play as it.  Default MODE is \"play\"."
   "Play entity specified by ENTITY.
 It decodes the entity to call internal or external method.  The method
 is selected from variable `mime-acting-condition'.  If MODE is
 specified, play as it.  Default MODE is \"play\"."
-  (let (method cal ret)
-    (setq cal (mime-entity-situation entity))
-    (if mode
-       (setq cal (cons (cons 'mode mode) cal))
-      )
+  (let (method ret)
+    (in-calist-package 'mime-view)
     (setq ret
     (setq ret
-         (or (ctree-match-calist mime-acting-situation-examples cal)
-             (ctree-match-calist-partially mime-acting-situation-examples
-                                           cal)
-             cal))
-    (setq ret
-         (or (mime-delq-null-situation
-              (ctree-find-calist mime-acting-condition ret
-                                 mime-view-find-every-acting-situation)
-              'method)
-             (mime-delq-null-situation
-              (ctree-find-calist mime-acting-condition cal
-                                 mime-view-find-every-acting-situation)
-              'method)
-             ))
+         (mime-delq-null-situation
+          (ctree-find-calist mime-acting-condition
+                             (mime-entity-situation entity situation)
+                             mime-view-find-every-acting-situation)
+          'method ignored-method))
+    (or (assq 'ignore-examples situation)
+       (if (cdr ret)
+           (let ((rest ret)
+                 (max-score 0)
+                 (max-escore 0)
+                 max-examples
+                 max-situations)
+             (while rest
+               (let ((situation (car rest))
+                     (examples mime-acting-situation-example-list))
+                 (while examples
+                   (let* ((ret
+                           (mime-compare-situation-with-example
+                            situation (caar examples)))
+                          (ret-score (car ret)))
+                     (cond ((> ret-score max-score)
+                            (setq max-score ret-score
+                                  max-escore (cdar examples)
+                                  max-examples (list (cdr ret))
+                                  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))
+                                   )
+                                  ((= (cdar examples) max-escore)
+                                   (setq max-examples
+                                         (cons (cdr ret) max-examples))
+                                   (or (member situation max-situations)
+                                       (setq max-situations
+                                             (cons situation max-situations)))
+                                   )))))
+                   (setq examples (cdr examples))))
+               (setq rest (cdr rest)))
+             (when max-situations
+               (setq ret max-situations)
+               (while max-examples
+                 (let* ((example (car max-examples))
+                        (cell
+                         (assoc example mime-acting-situation-example-list)))
+                   (if cell
+                       (setcdr cell (1+ (cdr cell)))
+                     (setq mime-acting-situation-example-list
+                           (cons (cons example 0)
+                                 mime-acting-situation-example-list))
+                     ))
+                 (setq max-examples (cdr max-examples))
+                 )))))
     (cond ((cdr ret)
           (setq ret (select-menu-alist
                      "Methods"
     (cond ((cdr ret)
           (setq ret (select-menu-alist
                      "Methods"
@@ -166,7 +323,7 @@ specified, play as it.  Default MODE is \"play\"."
                                  situation)))
                              ret)))
           (setq ret (mime-sort-situation ret))
                                  situation)))
                              ret)))
           (setq ret (mime-sort-situation ret))
-          (ctree-set-calist-strictly 'mime-acting-situation-examples ret)
+          (add-to-list 'mime-acting-situation-example-list (cons ret 0))
           )
          (t
           (setq ret (car ret))
           )
          (t
           (setq ret (car ret))
@@ -179,12 +336,16 @@ specified, play as it.  Default MODE is \"play\"."
          ((stringp method)
           (mime-activate-mailcap-method entity ret)
           )
          ((stringp method)
           (mime-activate-mailcap-method entity ret)
           )
-         ((and (listp method)(stringp (car method)))
-          (mime-activate-external-method entity ret)
-          )
+          ;; ((and (listp method)(stringp (car method)))
+          ;;  (mime-activate-external-method entity ret)
+          ;;  )
          (t
           (mime-show-echo-buffer "No method are specified for %s\n"
          (t
           (mime-show-echo-buffer "No method are specified for %s\n"
-                                 (mime-entity-type/subtype entity))
+                                 (mime-type/subtype-string
+                                  (cdr (assq 'type situation))
+                                  (cdr (assq 'subtype situation))))
+          (if (y-or-n-p "Do you want to save current entity to disk?")
+              (mime-save-content entity situation))
           ))
     ))
 
           ))
     ))
 
@@ -195,33 +356,28 @@ specified, play as it.  Default MODE is \"play\"."
 (defvar mime-mailcap-method-filename-alist nil)
 
 (defun mime-activate-mailcap-method (entity situation)
 (defvar mime-mailcap-method-filename-alist nil)
 
 (defun mime-activate-mailcap-method (entity situation)
-  (save-excursion
-    (save-restriction
-      (let ((start (mime-entity-point-min entity))
-           (end (mime-entity-point-max entity)))
-       (narrow-to-region start end)
-       (goto-char start)
-       (let ((method (cdr (assoc 'method situation)))
-             (name (expand-file-name (mime-raw-get-filename situation)
-                                     mime-temp-directory)))
-         (mime-write-decoded-region (if (re-search-forward "^$" end t)
-                                        (1+ (match-end 0))
-                                      (point-min))
-                                    end name
-                                    (cdr (assq 'encoding situation)))
-         (message "External method is starting...")
-         (let ((process
-                (let ((command
-                       (mailcap-format-command
-                        method
-                        (cons (cons 'filename name) situation))))
-                  (start-process command mime-echo-buffer-name
-                                 shell-file-name shell-command-switch command)
-                  )))
-           (set-alist 'mime-mailcap-method-filename-alist process name)
-           (set-process-sentinel process 'mime-mailcap-method-sentinel)
-           )
-         )))))
+  (let ((method (cdr (assoc 'method situation)))
+       (name (mime-entity-safe-filename entity)))
+    (setq name
+         (if (and name (not (string= name "")))
+             (expand-file-name name temporary-file-directory)
+           (make-temp-name
+            (expand-file-name "EMI" temporary-file-directory))
+           ))
+    (mime-write-entity-content entity name)
+    (message "External method is starting...")
+    (let ((process
+          (let ((command
+                 (mailcap-format-command
+                  method
+                  (cons (cons 'filename name) situation))))
+            (start-process command mime-echo-buffer-name
+                           shell-file-name shell-command-switch command)
+            )))
+      (set-alist 'mime-mailcap-method-filename-alist process name)
+      (set-process-sentinel process 'mime-mailcap-method-sentinel)
+      )
+    ))
 
 (defun mime-mailcap-method-sentinel (process event)
   (let ((file (cdr (assq process mime-mailcap-method-filename-alist))))
 
 (defun mime-mailcap-method-sentinel (process event)
   (let ((file (cdr (assq process mime-mailcap-method-filename-alist))))
@@ -231,63 +387,8 @@ specified, play as it.  Default MODE is \"play\"."
   (remove-alist 'mime-mailcap-method-filename-alist process)
   (message (format "%s %s" process event)))
 
   (remove-alist 'mime-mailcap-method-filename-alist process)
   (message (format "%s %s" process event)))
 
-(defun mime-activate-external-method (entity cal)
-  (save-excursion
-    (save-restriction
-      (let ((beg (mime-entity-point-min entity))
-           (end (mime-entity-point-max entity)))
-       (narrow-to-region beg end)
-       (goto-char beg)
-       (let ((method (cdr (assoc 'method cal)))
-             (name (mime-raw-get-filename cal)))
-         (if method
-             (let ((file (make-temp-name
-                          (expand-file-name "TM" mime-temp-directory)))
-                   b args)
-               (if (nth 1 method)
-                   (setq b beg)
-                 (setq b
-                       (if (re-search-forward "^$" nil t)
-                           (1+ (match-end 0))
-                         (point-min)
-                         ))
-                 )
-               (goto-char b)
-               (write-region b end file)
-               (message "External method is starting...")
-               (setq cal (put-alist
-                          'name (replace-as-filename name) cal))
-               (setq cal (put-alist 'file file cal))
-               (setq args (nconc
-                           (list (car method)
-                                 mime-echo-buffer-name (car method)
-                                 )
-                           (mime-make-external-method-args
-                            cal (cdr (cdr method)))
-                           ))
-               (apply (function start-process) args)
-               (mime-show-echo-buffer)
-               ))
-         )))))
-
-(defun mime-make-external-method-args (cal format)
-  (mapcar (function
-          (lambda (arg)
-            (if (stringp arg)
-                arg
-              (let* ((item (eval arg))
-                     (ret (cdr (assoc item cal)))
-                     )
-                (if ret
-                    ret
-                  (if (eq item 'encoding)
-                      "7bit"
-                    ""))
-                ))
-            ))
-         format))
-
-(defvar mime-echo-window-is-shared-with-bbdb t
+(defvar mime-echo-window-is-shared-with-bbdb
+  (module-installed-p 'bbdb)
   "*If non-nil, mime-echo window is shared with BBDB window.")
 
 (defvar mime-echo-window-height
   "*If non-nil, mime-echo window is shared with BBDB window.")
 
 (defvar mime-echo-window-height
@@ -302,33 +403,45 @@ Otherwise `mime-show-echo-buffer' uses it as height of mime-echo
 window.")
 
 (defun mime-show-echo-buffer (&rest forms)
 window.")
 
 (defun mime-show-echo-buffer (&rest forms)
-  "Show mime-echo buffer to display MIME-playing information."
+  "Show mime-echo buffer to display MIME-playing information.
+It returns the list of window, start and end positions of inserted text.
+A window height of the buffer `mime-echo-buffer-name' will be determined
+by `mime-echo-window-height' (its value or its return value) whenever
+this function is called."
   (get-buffer-create mime-echo-buffer-name)
   (let ((the-win (selected-window))
        (win (get-buffer-window mime-echo-buffer-name))
   (get-buffer-create mime-echo-buffer-name)
   (let ((the-win (selected-window))
        (win (get-buffer-window mime-echo-buffer-name))
-       )
-    (or win
-       (if (and mime-echo-window-is-shared-with-bbdb
-                (boundp 'bbdb-buffer-name)
-                (setq win (get-buffer-window bbdb-buffer-name))
-                )
-           (set-window-buffer win mime-echo-buffer-name)
-         (select-window (get-buffer-window mime-preview-buffer))
-         (setq win (split-window-vertically
-                    (- (window-height)
-                       (if (functionp mime-echo-window-height)
-                           (funcall mime-echo-window-height)
-                         mime-echo-window-height)
-                       )))
-         (set-window-buffer win mime-echo-buffer-name)
-         ))
-    (select-window win)
-    (goto-char (point-max))
+       (height (if (functionp mime-echo-window-height)
+                   (funcall mime-echo-window-height)
+                 mime-echo-window-height))
+       (window-min-height 1)
+       start)
+    (if win
+       (progn
+         (select-window win)
+         (enlarge-window (max 0 (- height (window-height))))
+         )
+      (unless (and mime-echo-window-is-shared-with-bbdb
+                  (condition-case nil
+                      (select-window
+                       (setq win (get-buffer-window bbdb-buffer-name))
+                       )
+                    (error nil)))
+       (select-window (get-buffer-window (or mime-preview-buffer
+                                             (current-buffer))))
+       (setq win (split-window-vertically (- (window-height) height)))
+       (set-window-buffer win mime-echo-buffer-name)
+       (select-window win)
+       ))
+    (goto-char (setq start (point-max)))
     (if forms
     (if forms
-       (insert (apply (function format) forms))
-      )
-    (select-window the-win)
-    ))
+       (let ((buffer-read-only nil))
+         (insert (apply (function format) forms))
+         ))
+    (prog1
+       (list win start (point))
+      (select-window the-win)
+      )))
 
 
 ;;; @ file name
 
 
 ;;; @ file name
@@ -344,70 +457,87 @@ window.")
   (concat (regexp-* mime-view-file-name-char-regexp)
          "\\(\\." mime-view-file-name-char-regexp "+\\)*"))
 
   (concat (regexp-* mime-view-file-name-char-regexp)
          "\\(\\." mime-view-file-name-char-regexp "+\\)*"))
 
-(defun mime-raw-get-original-filename (param)
-  (or (if (member (cdr (assq 'encoding param))
-                 mime-view-uuencode-encoding-name-list)
-         (mime-raw-get-uu-filename))
-      (let (ret)
-       (or (if (or (and (setq ret (mime-read-Content-Disposition))
-                        (setq ret
-                              (assoc
-                               "filename"
-                               (mime-content-disposition-parameters ret)))
-                        )
-                   (setq ret (assoc "name" param))
-                   (setq ret (assoc "x-name" param))
-                   )
-               (std11-strip-quoted-string (cdr ret))
-             )
-           (if (setq ret
-                     (std11-find-field-body '("Content-Description"
-                                              "Subject")))
-               (if (or (string-match mime-view-file-name-regexp-1 ret)
-                       (string-match mime-view-file-name-regexp-2 ret))
-                   (substring ret (match-beginning 0)(match-end 0))
-                 ))
-           ))
-      ))
-
-(defun mime-raw-get-filename (param)
-  (replace-as-filename (mime-raw-get-original-filename param))
-  )
+(defun mime-entity-safe-filename (entity)
+  (let ((filename
+        (or (mime-entity-filename entity)
+            (let ((subj
+                   (or (mime-entity-read-field entity 'Content-Description)
+                       (mime-entity-read-field entity 'Subject))))
+              (if (and subj
+                       (or (string-match mime-view-file-name-regexp-1 subj)
+                           (string-match mime-view-file-name-regexp-2 subj)))
+                  (substring subj (match-beginning 0)(match-end 0))
+                )))))
+    (if filename
+       (replace-as-filename filename)
+      )))
 
 
 ;;; @ file extraction
 ;;;
 
 
 
 ;;; @ file extraction
 ;;;
 
-(defun mime-method-to-save (entity cal)
-  (let ((beg (mime-entity-point-min entity))
-       (end (mime-entity-point-max entity)))
-    (goto-char beg)
-    (let* ((name (save-restriction
-                  (narrow-to-region beg end)
-                  (mime-raw-get-filename cal)
-                  ))
-          (encoding (or (cdr (assq 'encoding cal)) "7bit"))
-          (filename (if (and name (not (string-equal name "")))
-                        (expand-file-name name
-                                          (save-window-excursion
-                                            (call-interactively
-                                             (function
-                                              (lambda (dir)
-                                                (interactive "DDirectory: ")
-                                                dir)))))
-                      (save-window-excursion
-                        (call-interactively
-                         (function
-                          (lambda (file)
-                            (interactive "FFilename: ")
-                            (expand-file-name file)))))))
-          )
-      (if (file-exists-p filename)
-         (or (yes-or-no-p (format "File %s exists. Save anyway? " filename))
-             (error "")))
-      (re-search-forward "\n\n")
-      (mime-write-decoded-region (match-end 0) end filename encoding)
-      )))
+(defun mime-save-content (entity situation)
+  (let ((name (or (mime-entity-safe-filename entity)
+                 (format "%s" (mime-entity-media-type entity))))
+       (dir (if (eq t mime-save-directory)
+                default-directory
+              mime-save-directory))
+       filename)
+    (setq filename (read-file-name
+                   (concat "File name: (default "
+                           (file-name-nondirectory name) ") ")
+                   dir
+                   (concat (file-name-as-directory dir)
+                           (file-name-nondirectory name))))
+    (if (file-directory-p filename)
+       (setq filename (concat (file-name-as-directory filename)
+                              (file-name-nondirectory name))))
+    (if (file-exists-p filename)
+       (or (yes-or-no-p (format "File %s exists. Save anyway? " filename))
+           (error "")))
+    (mime-write-entity-content entity (expand-file-name filename))
+    ))
+
+
+;;; @ file detection
+;;;
+
+(defvar mime-magic-type-alist
+  '(("^\377\330\377[\340\356]..JFIF"   image jpeg)
+    ("^\211PNG"                                image png)
+    ("^GIF8[79]"                       image gif)
+    ("^II\\*\000"                      image tiff)
+    ("^MM\000\\*"                      image tiff)
+    ("^MThd"                           audio midi)
+    ("^\000\000\001\263"               video mpeg)
+    )
+  "*Alist of regexp about magic-number vs. corresponding media-types.
+Each element looks like (REGEXP TYPE SUBTYPE).
+REGEXP is a regular expression to match against the beginning of the
+content of entity.
+TYPE is symbol to indicate primary type of media-type.
+SUBTYPE is symbol to indicate subtype of media-type.")
+
+(defun mime-detect-content (entity situation)
+  (let (type subtype)
+    (let ((mdata (mime-entity-content entity))
+         (rest mime-magic-type-alist))
+      (while (not (let ((cell (car rest)))
+                   (if cell
+                       (if (string-match (car cell) mdata)
+                           (setq type (nth 1 cell)
+                                 subtype (nth 2 cell))
+                         )
+                     t)))
+       (setq rest (cdr rest))))
+    (setq situation (del-alist 'method (copy-alist situation)))
+    (mime-play-entity entity
+                     (if type
+                         (put-alist 'type type
+                                    (put-alist 'subtype subtype
+                                               situation))
+                       situation)
+                     'mime-detect-content)))
 
 
 ;;; @ mail/news message
 
 
 ;;; @ mail/news message
@@ -416,100 +546,71 @@ window.")
 (defun mime-preview-quitting-method-for-mime-show-message-mode ()
   "Quitting method for mime-view.
 It is registered to variable `mime-preview-quitting-method-alist'."
 (defun mime-preview-quitting-method-for-mime-show-message-mode ()
   "Quitting method for mime-view.
 It is registered to variable `mime-preview-quitting-method-alist'."
-  (let ((mother mime-mother-buffer)
-       (win-conf mime-preview-original-window-configuration)
-       )
-    (kill-buffer mime-raw-buffer)
+  (let ((raw-buffer (mime-entity-buffer
+                    (get-text-property (point-min) 'mime-view-entity)))
+       (mother mime-mother-buffer)
+       (win-conf mime-preview-original-window-configuration))
+    (kill-buffer raw-buffer)
     (mime-preview-kill-buffer)
     (set-window-configuration win-conf)
     (pop-to-buffer mother)
     ))
 
     (mime-preview-kill-buffer)
     (set-window-configuration win-conf)
     (pop-to-buffer mother)
     ))
 
-(defun mime-method-to-display-message/rfc822 (entity cal)
-  (let* ((beg (mime-entity-point-min entity))
-        (end (mime-entity-point-max entity))
-        (cnum (mime-raw-point-to-entity-number beg))
-        (new-name (format "%s-%s" (buffer-name) cnum))
-        (mother mime-preview-buffer)
-        (representation-type
-         (cdr (or (assq major-mode mime-raw-representation-type-alist)
-                  (assq t mime-raw-representation-type-alist))))
-        str)
-    (setq str (buffer-substring beg end))
-    (switch-to-buffer new-name)
-    (erase-buffer)
-    (insert str)
-    (goto-char (point-min))
-    (if (re-search-forward "^\n" nil t)
-       (delete-region (point-min) (match-end 0))
-      )
-    (setq major-mode 'mime-show-message-mode)
-    (setq mime-raw-representation-type representation-type)
-    (mime-view-mode mother)
-    ))
+(defun mime-view-message/rfc822 (entity situation)
+  (let* ((new-name
+         (format "%s-%s" (buffer-name) (mime-entity-number entity)))
+        (mother (current-buffer))
+        (children (car (mime-entity-children entity)))
+        (preview-buffer
+         (mime-display-message
+          children new-name mother nil
+          (cdr (assq 'major-mode
+                     (get-text-property (point) 'mime-view-situation))))))
+    (or (get-buffer-window preview-buffer)
+       (let ((m-win (get-buffer-window mother)))
+         (if m-win
+             (set-window-buffer m-win preview-buffer)
+           (switch-to-buffer preview-buffer)
+           )))))
 
 
 ;;; @ message/partial
 ;;;
 
 
 
 ;;; @ message/partial
 ;;;
 
-(defun mime-raw-write-region (start end filename)
-  "Write current region into specified file.
-When called from a program, takes three arguments:
-START, END and FILENAME.  START and END are buffer positions.
-It refer `mime-raw-representation-type' or `major-mode
-mime-raw-representation-type-alist'.  If it is `binary', region is
-saved as binary.  Otherwise the region is saved by `write-region'."
-  (let ((presentation-type
-        (or mime-raw-representation-type
-            (cdr (or (assq major-mode mime-raw-representation-type-alist)
-                     (assq t mime-raw-representation-type-alist))))))
-    (if (eq presentation-type 'binary)
-       (write-region-as-binary start end filename)
-      (write-region start end filename)
-      )))
-
-(defun mime-method-to-store-message/partial (entity cal)
-  (goto-char (mime-entity-point-min entity))
+(defun mime-store-message/partial-piece (entity cal)
   (let* ((root-dir
          (expand-file-name
   (let* ((root-dir
          (expand-file-name
-          (concat "m-prts-" (user-login-name)) mime-temp-directory))
+          (concat "m-prts-" (user-login-name)) temporary-file-directory))
         (id (cdr (assoc "id" cal)))
         (number (cdr (assoc "number" cal)))
         (total (cdr (assoc "total" cal)))
         file
         (id (cdr (assoc "id" cal)))
         (number (cdr (assoc "number" cal)))
         (total (cdr (assoc "total" cal)))
         file
-        (mother mime-preview-buffer)
-        )
+        (mother (current-buffer)))
     (or (file-exists-p root-dir)
     (or (file-exists-p root-dir)
-       (make-directory root-dir)
-       )
+       (make-directory root-dir))
     (setq id (replace-as-filename id))
     (setq root-dir (concat root-dir "/" id))
     (or (file-exists-p root-dir)
     (setq id (replace-as-filename id))
     (setq root-dir (concat root-dir "/" id))
     (or (file-exists-p root-dir)
-       (make-directory root-dir)
-       )
+       (make-directory root-dir))
     (setq file (concat root-dir "/FULL"))
     (if (file-exists-p file)
        (let ((full-buf (get-buffer-create "FULL"))
              (pwin (or (get-buffer-window mother)
                        (get-largest-window)))
     (setq file (concat root-dir "/FULL"))
     (if (file-exists-p file)
        (let ((full-buf (get-buffer-create "FULL"))
              (pwin (or (get-buffer-window mother)
                        (get-largest-window)))
-             )
+             pbuf)
          (save-window-excursion
            (set-buffer full-buf)
            (erase-buffer)
            (as-binary-input-file (insert-file-contents file))
            (setq major-mode 'mime-show-message-mode)
          (save-window-excursion
            (set-buffer full-buf)
            (erase-buffer)
            (as-binary-input-file (insert-file-contents file))
            (setq major-mode 'mime-show-message-mode)
-           (mime-view-mode mother)
+           (mime-view-buffer (current-buffer) nil mother)
+           (setq pbuf (current-buffer))
            )
            )
-         (set-window-buffer pwin
-                            (save-excursion
-                              (set-buffer full-buf)
-                              mime-preview-buffer))
+         (set-window-buffer pwin pbuf)
          (select-window pwin)
          )
          (select-window pwin)
          )
-      (re-search-forward "^$")
-      (goto-char (1+ (match-end 0)))
       (setq file (concat root-dir "/" number))
       (setq file (concat root-dir "/" number))
-      (mime-raw-write-region (point) (mime-entity-point-max entity) file)
+      (mime-write-entity-body entity file)
       (let ((total-file (concat root-dir "/CT")))
        (setq total
              (if total
       (let ((total-file (concat root-dir "/CT")))
        (setq total
              (if total
@@ -537,7 +638,9 @@ saved as binary.  Otherwise the region is saved by `write-region'."
                         (kill-buffer (current-buffer))
                         )))
                )))
                         (kill-buffer (current-buffer))
                         )))
                )))
-      (if (and total (> total 0))
+      (if (and total (> total 0)
+              (>= (length (directory-files root-dir nil "^[0-9]+$" t))
+                  total))
          (catch 'tag
            (save-excursion
              (set-buffer (get-buffer-create mime-temp-buffer-name))
          (catch 'tag
            (save-excursion
              (set-buffer (get-buffer-create mime-temp-buffer-name))
@@ -568,16 +671,11 @@ saved as binary.  Otherwise the region is saved by `write-region'."
                  (and (file-exists-p file)
                       (delete-file file)
                       ))
                  (and (file-exists-p file)
                       (delete-file file)
                       ))
-               (save-window-excursion
-                 (setq major-mode 'mime-show-message-mode)
-                 (mime-view-mode mother)
-                 )
                (let ((pwin (or (get-buffer-window mother)
                (let ((pwin (or (get-buffer-window mother)
-                               (get-largest-window)
-                               ))
-                     (pbuf (save-excursion
-                             (set-buffer full-buf)
-                             mime-preview-buffer)))
+                               (get-largest-window)))
+                     (pbuf (mime-display-message
+                            (mime-open-entity 'buffer (current-buffer))
+                            nil mother nil 'mime-show-message-mode)))
                  (set-window-buffer pwin pbuf)
                  (select-window pwin)
                  )))))
                  (set-window-buffer pwin pbuf)
                  (select-window pwin)
                  )))))
@@ -600,40 +698,45 @@ saved as binary.  Otherwise the region is saved by `write-region'."
     (dired dir)
     ))
 
     (dired dir)
     ))
 
-(defun mime-method-to-display-message/external-ftp (entity cal)
+(defun mime-view-message/external-anon-ftp (entity cal)
   (let* ((site (cdr (assoc "site" cal)))
         (directory (cdr (assoc "directory" cal)))
         (name (cdr (assoc "name" cal)))
         (pathname (concat "/anonymous@" site ":" directory)))
   (let* ((site (cdr (assoc "site" cal)))
         (directory (cdr (assoc "directory" cal)))
         (name (cdr (assoc "name" cal)))
         (pathname (concat "/anonymous@" site ":" directory)))
-    (message (concat "Accessing " (expand-file-name name pathname) "..."))
+    (message (concat "Accessing " (expand-file-name name pathname) " ..."))
     (funcall mime-raw-dired-function pathname)
     (goto-char (point-min))
     (search-forward name)
     ))
 
     (funcall mime-raw-dired-function pathname)
     (goto-char (point-min))
     (search-forward name)
     ))
 
+(defvar mime-raw-browse-url-function mime-browse-url-function)
+
+(defun mime-view-message/external-url (entity cal)
+  (let ((url (cdr (assoc "url" cal))))
+    (message (concat "Accessing " url " ..."))
+    (funcall mime-raw-browse-url-function url)))
+
 
 ;;; @ rot13-47
 ;;;
 
 
 ;;; @ rot13-47
 ;;;
 
-(defun mime-method-to-display-caesar (entity situation)
+(defun mime-view-caesar (entity situation)
   "Internal method for mime-view to display ROT13-47-48 message."
   "Internal method for mime-view to display ROT13-47-48 message."
-  (let* ((new-name (format "%s-%s" (buffer-name)
-                          (mime-entity-number entity)))
-        (mother mime-preview-buffer))
-    (let ((pwin (or (get-buffer-window mother)
-                   (get-largest-window)))
-         (buf (get-buffer-create new-name)))
-      (set-window-buffer pwin buf)
-      (set-buffer buf)
-      (select-window pwin)
+  (let ((buf (get-buffer-create
+             (format "%s-%s" (buffer-name) (mime-entity-number entity)))))
+    (with-current-buffer buf
+      (setq buffer-read-only nil)
+      (erase-buffer)
+      (mime-insert-text-content entity)
+      (mule-caesar-region (point-min) (point-max))
+      (set-buffer-modified-p nil)
       )
       )
-    (setq buffer-read-only nil)
-    (erase-buffer)
-    (mime-text-insert-decoded-body entity)
-    (mule-caesar-region (point-min) (point-max))
-    (set-buffer-modified-p nil)
-    (set-buffer mother)
-    (view-buffer new-name)
+    (let ((win (get-buffer-window (current-buffer))))
+      (or (eq (selected-window) win)
+         (select-window (or win (get-largest-window)))
+         ))
+    (view-buffer buf)
+    (goto-char (point-min))
     ))
 
 
     ))
 
 
@@ -652,8 +755,15 @@ saved as binary.  Otherwise the region is saved by `write-region'."
            (insert-file-contents file)
            (eval-buffer)
            ;; format check
            (insert-file-contents file)
            (eval-buffer)
            ;; format check
-           (or (eq (car mime-acting-situation-examples) 'type)
-               (setq mime-acting-situation-examples nil))
+           (condition-case nil
+               (let ((i 0))
+                 (while (and (> (length mime-acting-situation-example-list)
+                                mime-acting-situation-example-list-max-size)
+                             (< i 16))
+                   (mime-reduce-acting-situation-examples)
+                   (setq i (1+ i))
+                   ))
+             (error (setq mime-acting-situation-example-list nil)))
            )
        (kill-buffer buffer))))
 
            )
        (kill-buffer buffer))))