* mime-edit.el (mime-edit-temp-message-buffer): Define.
[elisp/semi.git] / mime-view.el
index 582c81e..c97f93d 100644 (file)
@@ -32,6 +32,7 @@
 (require 'calist)
 (require 'alist)
 (require 'mime-conf)
+(require 'mcharset)
 
 (eval-when-compile (require 'static))
 
@@ -77,6 +78,8 @@ buttom. Nil means don't scroll at all."
   :group 'mime-view
   :type '(repeat file))
 
+(defvar mime-view-automatic-conversion 'undecided)
+
 
 ;;; @ in raw-buffer (representation space)
 ;;;
@@ -399,7 +402,8 @@ mother-buffer."
 (defun mime-save-situation-examples ()
   (if (or mime-preview-situation-example-list
          mime-acting-situation-example-list)
-      (let ((file mime-situation-examples-file))
+      (let ((file mime-situation-examples-file)
+           print-length print-level)
        (with-temp-buffer
          (insert ";;; " (file-name-nondirectory file) "\n")
          (insert "\n;; This file is generated automatically by "
@@ -416,7 +420,7 @@ mother-buffer."
          (insert "\n;;; "
                  (file-name-nondirectory file)
                  " ends here.\n")
-          (static-cond
+         (static-cond
           ((boundp 'buffer-file-coding-system)
            (setq buffer-file-coding-system
                  mime-situation-examples-file-coding-system))
@@ -424,7 +428,7 @@ mother-buffer."
            (setq file-coding-system
                  mime-situation-examples-file-coding-system)))
          ;; (setq buffer-file-coding-system
-          ;;       mime-situation-examples-file-coding-system)
+         ;;       mime-situation-examples-file-coding-system)
          (setq buffer-file-name file)
          (save-buffer)))))
 
@@ -766,8 +770,8 @@ Each elements are regexp of field-name.")
     (condition-case nil
        (if (and mime-preview-inline-fontify
                 (mime-entity-filename entity)) ;should be an attachment.
-           (mime-display-inline-fontify entity)
-         (mime-insert-text-content entity))
+           (mime-view-insert-fontified-text-content entity situation)
+         (mime-view-insert-text-content entity situation))
       (error (progn
               (message "Can't decode current entity.")
               (sit-for 1))))
@@ -784,7 +788,7 @@ Each elements are regexp of field-name.")
 (defun mime-display-text/richtext (entity situation)
   (save-restriction
     (narrow-to-region (point-max)(point-max))
-    (mime-insert-text-content entity)
+    (mime-view-insert-text-content entity situation)
     (run-hooks 'mime-text-decode-hook)
     (let ((beg (point-min)))
       (remove-text-properties beg (point-max) '(face nil))
@@ -793,7 +797,7 @@ Each elements are regexp of field-name.")
 (defun mime-display-text/enriched (entity situation)
   (save-restriction
     (narrow-to-region (point-max)(point-max))
-    (mime-insert-text-content entity)
+    (mime-view-insert-text-content entity situation)
     (run-hooks 'mime-text-decode-hook)
     (let ((beg (point-min)))
       (remove-text-properties beg (point-max) '(face nil))
@@ -901,32 +905,87 @@ MEDIA-TYPE must be (TYPE . SUBTYPE), TYPE or t.  t means default."
                    (car (mime-entity-children entity))))
         (original-major-mode-cell (assq 'major-mode situation))
         (default-situation (cdr (assq 'childrens-situation situation))))
-    (if original-major-mode-cell
-       (setq default-situation
-             (cons original-major-mode-cell default-situation)))
-    (mime-display-entity start nil default-situation)))
+    (when start
+      (if original-major-mode-cell
+         (setq default-situation
+               (cons original-major-mode-cell default-situation)))
+      (mime-display-entity start nil default-situation))))
+
+(defun mime-view-entity-content (entity situation)
+  (mime-decode-string
+   (mime-entity-body entity)
+   (mime-view-guess-encoding entity situation)))
+  
+(defun mime-view-insert-text-content (entity situation)
+  (let (compression-info)
+    (cond
+     ((and (mime-entity-filename entity)
+          (featurep 'jka-compr)
+          (jka-compr-installed-p)
+          (setq compression-info (jka-compr-get-compression-info
+                                  (mime-entity-filename entity))))
+      (insert
+       (mime-view-filter-text-content
+       (mime-view-entity-content entity situation)
+       (jka-compr-info-uncompress-program compression-info)
+       (jka-compr-info-uncompress-args compression-info))))
+     ((or (assq '*encoding situation)  ;should be specified by user
+         (assq '*charset situation))   ;should be specified by user
+      (insert
+       (decode-mime-charset-string
+       (mime-view-entity-content entity situation)
+       (mime-view-guess-charset entity situation)
+       'CRLF)))
+     (t
+      (mime-insert-text-content entity)))))
+
+;;; stolen (and renamed) from `mime-display-gzipped' of EMY 1.13.
+(defun mime-view-filter-text-content (content program args)
+  (with-temp-buffer
+    (static-cond
+     ((featurep 'xemacs)
+      (insert content)
+      (apply #'binary-to-text-funcall
+            mime-view-automatic-conversion
+            #'call-process-region (point-min)(point-max)
+            program t t args))
+     (t
+      (if (not (multibyte-string-p content))
+         (set-buffer-multibyte nil))
+      (insert content)
+      (apply #'binary-funcall
+            #'call-process-region (point-min)(point-max)
+            program t t args)
+      (set-buffer-multibyte t)
+      (decode-coding-region (point-min)(point-max)
+                           mime-view-automatic-conversion)))
+    (buffer-string)))
 
 ;;; stolen (and renamed) from mm-view.el.
-(defun mime-display-inline-fontify (entity &optional mode)
+(defun mime-view-insert-fontified-text-content (entity situation
+                                                      &optional mode)
   ;; XEmacs @#$@ version of font-lock refuses to fully turn itself
   ;; on for buffers whose name begins with " ".  That's why we use
   ;; save-current-buffer/get-buffer-create rather than
   ;; with-temp-buffer.
-  (let ((buffer (get-buffer-create "*fontification*"))
+  (let ((buffer (generate-new-buffer "*fontification*"))
        filename)
-    (save-current-buffer
-      (set-buffer buffer)
-      (buffer-disable-undo)
-      (kill-all-local-variables)
-      (erase-buffer)
-      (mime-insert-text-content entity)
-      (unwind-protect
-         (progn
+    (unwind-protect
+       (progn
+         (save-current-buffer
+           (set-buffer buffer)
+           (buffer-disable-undo)
+           (kill-all-local-variables)
+           (mime-view-insert-text-content entity situation)
            (if mode
                (funcall mode)
              (if (setq filename (mime-entity-filename entity))
-                 (set-visited-file-name filename))
-             (set-auto-mode))
+                 (unwind-protect
+                     (progn
+                       (setq buffer-file-name filename)
+                       (set-auto-mode))
+                   (setq buffer-file-name nil))))
+           (require 'font-lock)
            (let ((font-lock-verbose nil))
              ;; I find font-lock a bit too verbose.
              (font-lock-fontify-buffer))
@@ -938,13 +997,13 @@ MEDIA-TYPE must be (TYPE . SUBTYPE), TYPE or t.  t means default."
                             (set-extent-property ext 'duplicable t)
                             nil)
                           nil nil nil nil nil 'text-prop)))
-       (set-visited-file-name nil)))
-    (insert-buffer-substring buffer)))
+         (insert-buffer-substring buffer))
+      (kill-buffer buffer))))
 
 (defun mime-display-application/emacs-lisp (entity situation)
   (save-restriction
     (narrow-to-region (point-max)(point-max))
-    (mime-display-inline-fontify entity 'emacs-lisp-mode)
+    (mime-view-insert-fontified-text-content entity situation 'emacs-lisp-mode)
     (run-hooks 'mime-text-decode-hook 'mime-display-text/plain-hook)))
 
 
@@ -1165,7 +1224,7 @@ MEDIA-TYPE must be (TYPE . SUBTYPE), TYPE or t.  t means default."
   (when (boundp 'widget-keymap)
     (set-keymap-parent (current-local-map) widget-keymap)))
 
-(add-hook 'mime-view-define-keymap-hook 'mime-view-maybe-inherit-widget-keymap)
+(add-hook 'mime-view-mode-hook 'mime-view-maybe-inherit-widget-keymap)
          
 (defun mime-view-define-keymap (&optional default)
   (let ((mime-view-mode-map (if (keymapp default)
@@ -1407,15 +1466,19 @@ button-2        Move to point under the mouse cursor
 ;;; @@ utility
 ;;;
 
-(defun mime-preview-find-boundary-info (&optional get-mother)
+(defun mime-preview-find-boundary-info (&optional with-children)
+  "Return boundary information of current part.
+If WITH-CHILDREN, refer boundary surrounding current part and its branches."
   (let (entity
        p-beg p-end
        entity-node-id len)
-    (while (null (setq entity
-                      (get-text-property (point) 'mime-view-entity)))
+    (while (and
+           (null (setq entity
+                       (get-text-property (point) 'mime-view-entity)))
+           (> (point) (point-min)))
       (backward-char))
     (setq p-beg (previous-single-property-change (point) 'mime-view-entity))
-    (setq entity-node-id (mime-entity-node-id entity))
+    (setq entity-node-id (and entity (mime-entity-node-id entity)))
     (setq len (length entity-node-id))
     (cond ((null p-beg)
           (setq p-beg
@@ -1432,9 +1495,8 @@ button-2  Move to point under the mouse cursor
           (setq p-end (point-max)))
          ((null entity-node-id)
           (setq p-end (point-max)))
-         (get-mother
+         (with-children
           (save-excursion
-            (goto-char p-end)
             (catch 'tag
               (let (e i)
                 (while (setq e
@@ -1442,12 +1504,14 @@ button-2        Move to point under the mouse cursor
                               (point) 'mime-view-entity))
                   (goto-char e)
                   (let ((rc (mime-entity-node-id
-                             (get-text-property (1- (point))
+                             (get-text-property (point)
                                                 'mime-view-entity))))
                     (or (and (>= (setq i (- (length rc) len)) 0)
                              (equal entity-node-id (nthcdr i rc)))
                         (throw 'tag nil)))
-                  (setq p-end e)))
+                  (setq p-end (or (next-single-property-change
+                                   (point) 'mime-view-entity)
+                                  (point-max)))))
               (setq p-end (point-max))))))
     (vector p-beg p-end entity)))
 
@@ -1483,13 +1547,13 @@ It decodes current entity to call internal or external method as
 It calls following-method selected from variable
 `mime-preview-following-method-alist'."
   (interactive)
-  (let ((entity (mime-preview-find-boundary-info t))
-       p-beg p-end
-       pb-beg)
-    (setq p-beg (aref entity 0)
-         p-end (aref entity 1)
-         entity (aref entity 2))
-    (if (get-text-property p-beg 'mime-view-entity-body)
+  (let* ((boundary-info (mime-preview-find-boundary-info t))
+        (p-beg (aref boundary-info 0))
+        (p-end (aref boundary-info 1))
+        (entity (aref boundary-info 2))
+        pb-beg)
+    (if (or (get-text-property p-beg 'mime-view-entity-body)
+           (null entity))
        (setq pb-beg p-beg)
       (setq pb-beg
            (next-single-property-change
@@ -1497,7 +1561,7 @@ It calls following-method selected from variable
             (or (next-single-property-change p-beg 'mime-view-entity)
                 p-end))))
     (let* ((mode (mime-preview-original-major-mode 'recursive))
-          (entity-node-id (mime-entity-node-id entity))
+          (entity-node-id (and entity (mime-entity-node-id entity)))
           (new-name
            (format "%s-%s" (buffer-name) (reverse entity-node-id)))
           new-buf
@@ -1510,7 +1574,8 @@ It calls following-method selected from variable
        (insert-buffer-substring the-buf pb-beg p-end)
        (goto-char (point-min))
        (let ((current-entity
-              (if (and (eq (mime-entity-media-type entity) 'message)
+              (if (and entity
+                       (eq (mime-entity-media-type entity) 'message)
                        (eq (mime-entity-media-subtype entity) 'rfc822))
                   (car (mime-entity-children entity))
                 entity)))
@@ -1547,9 +1612,8 @@ It calls following-method selected from variable
        (if (functionp f)
            (funcall f new-buf)
          (message
-          (format
-           "Sorry, following method for %s is not implemented yet."
-           mode)))))))
+          "Sorry, following method for %s is not implemented yet."
+           mode))))))
 
 
 ;;; @@ moving
@@ -1705,10 +1769,55 @@ If LINES is negative, scroll up LINES lines."
 ;;; @@ display
 ;;;
 
+(defun mime-view-guess-encoding (entity situation)
+  (or (cdr (assq '*encoding situation))
+      (cdr (assq 'encoding situation))
+      (mime-entity-encoding entity)
+      "7bit"))
+
+(defun mime-view-read-encoding (entity situation)
+  (let* ((default-encoding
+          (mime-view-guess-encoding entity situation))
+        (encoding
+         (completing-read
+          "Content Transfer Encoding: "
+          (mime-encoding-alist) nil t default-encoding)))
+    (unless (or (string= encoding "")
+               (string= encoding default-encoding))
+      encoding)))
+
+(defun mime-view-guess-charset (entity situation)
+  (or (static-if (fboundp 'coding-system-to-mime-charset)
+         ;; might be overridden by `universal-coding-system-argument'.
+         (and coding-system-for-read
+              (coding-system-to-mime-charset coding-system-for-read)))
+      (cdr (assq '*charset situation))
+      (cdr (assq 'charset situation))
+      (let ((charset (cdr (assoc "charset" (mime-entity-parameters entity)))))
+       (if charset
+           (intern (downcase charset))))
+      default-mime-charset))
+
+(defun mime-view-read-charset (entity situation)
+  (static-if (featurep 'mule)
+      (let* ((default-charset
+              (mime-view-guess-charset entity situation))
+            (charset
+             (intern (completing-read "MIME-charset: "
+                                      (mapcar
+                                       (lambda (sym)
+                                         (list (symbol-name sym)))
+                                       (mime-charset-list))
+                                      nil t
+                                      (symbol-name default-charset)))))
+       (unless (eq charset default-charset)
+         charset))
+    default-charset))
+
 (defun mime-preview-toggle-display (type &optional display)
-  (let ((situation (mime-preview-find-boundary-info))
+  (let ((situation (mime-preview-find-boundary-info t))
        (sym (intern (concat "*" (symbol-name type))))
-       entity p-beg p-end)
+       entity p-beg p-end encoding charset)
     (setq p-beg (aref situation 0)
          p-end (aref situation 1)
          entity (aref situation 2)
@@ -1718,13 +1827,19 @@ If LINES is negative, scroll up LINES lines."
          (display)
          (t
           (setq display
-                (eq (cdr (or (assq sym situation)
-                             (assq type situation)))
-                    'invisible))))
+                (memq (cdr (or (assq sym situation)
+                               (assq type situation)))
+                      '(nil invisible)))))
     (setq situation (put-alist sym (if display
                                       'visible
                                     'invisible)
                               situation))
+    (when (and current-prefix-arg
+              (eq (cdr (assq sym situation)) 'visible))
+      (if (setq encoding (mime-view-read-encoding entity situation))
+         (setq situation (put-alist '*encoding encoding situation)))
+      (if (setq charset (mime-view-read-charset entity situation))
+         (setq situation (put-alist '*charset charset situation))))
     (save-excursion
       (let ((inhibit-read-only t))
        (delete-region p-beg p-end)