Sync with semi-1_14 branch.
[elisp/semi.git] / mime-view.el
index 46ffab0..1f53690 100644 (file)
@@ -22,8 +22,8 @@
 
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
 
 ;;; Code:
 
@@ -78,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)
 ;;;
@@ -400,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 "
@@ -417,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))
@@ -425,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)))))
 
@@ -628,6 +631,19 @@ Each elements are regexp of field-name.")
 (define-calist-field-match-method
   'body #'mime-calist::field-match-method-as-default-rule)
 
+(defun mime-calist::field-match-method-ignore-case (calist
+                                                   field-type field-value)
+  (let ((s-field (assoc field-type calist)))
+    (cond ((null s-field)
+          (cons (cons field-type field-value) calist))
+         ((eq field-value t)
+          calist)
+         ((string= (downcase (cdr s-field)) (downcase field-value))
+          calist))))
+
+(define-calist-field-match-method
+  'access-type #'mime-calist::field-match-method-ignore-case)
+
 
 (defvar mime-preview-condition nil
   "Condition-tree about how to display entity.")
@@ -902,19 +918,61 @@ 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)
-  (insert
-   (decode-mime-charset-string
-    (mime-decode-string
-     (mime-entity-body entity)
-     (mime-view-default-content-transfer-encoding entity situation))
-    (mime-view-default-mime-charset entity situation)
-    'CRLF)))
+  (let (compression-info)
+    (cond
+     ((and (mime-entity-filename entity)
+          (featurep 'jka-compr)
+          (jka-compr-installed-p)
+          (setq compression-info (jka-compr-get-compression-info
+                                  (mime-entity-filename entity))))
+      (insert
+       (mime-view-filter-text-content
+       (mime-view-entity-content entity situation)
+       (jka-compr-info-uncompress-program compression-info)
+       (jka-compr-info-uncompress-args compression-info))))
+     ((or (assq '*encoding situation)  ;should be specified by user
+         (assq '*charset situation))   ;should be specified by user
+      (insert
+       (decode-mime-charset-string
+       (mime-view-entity-content entity situation)
+       (mime-view-guess-charset entity situation)
+       'CRLF)))
+     (t
+      (mime-insert-text-content entity)))))
+
+;;; stolen (and renamed) from `mime-display-gzipped' of EMY 1.13.
+(defun mime-view-filter-text-content (content program args)
+  (with-temp-buffer
+    (static-cond
+     ((featurep 'xemacs)
+      (insert content)
+      (apply #'binary-to-text-funcall
+            mime-view-automatic-conversion
+            #'call-process-region (point-min)(point-max)
+            program t t args))
+     (t
+      (if (not (multibyte-string-p content))
+         (set-buffer-multibyte nil))
+      (insert content)
+      (apply #'binary-funcall
+            #'call-process-region (point-min)(point-max)
+            program t t args)
+      (set-buffer-multibyte t)
+      (decode-coding-region (point-min)(point-max)
+                           mime-view-automatic-conversion)))
+    (buffer-string)))
 
 ;;; stolen (and renamed) from mm-view.el.
 (defun mime-view-insert-fontified-text-content (entity situation
@@ -923,24 +981,32 @@ MEDIA-TYPE must be (TYPE . SUBTYPE), TYPE or t.  t means default."
   ;; 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-view-insert-text-content entity situation)
-      (unwind-protect
-         (progn
-           (if mode
-               (funcall mode)
-             (if (setq filename (mime-entity-filename entity))
-                 (set-visited-file-name filename))
-             (set-auto-mode))
-           (let ((font-lock-verbose nil))
-             ;; I find font-lock a bit too verbose.
-             (font-lock-fontify-buffer))
+    (unwind-protect
+       (progn
+         (save-current-buffer
+           (set-buffer buffer)
+           (buffer-disable-undo)
+           (kill-all-local-variables)
+           (mime-view-insert-text-content entity situation)
+           (require 'font-lock)
+           (let ((font-lock-maximum-size nil)
+                 ;; Disable support modes, e.g., jit-lock, lazy-lock, etc.
+                 (font-lock-mode-hook nil)
+                 (font-lock-support-mode nil)
+                 ;; I find font-lock a bit too verbose.
+                 (font-lock-verbose nil))
+             (cond (mode
+                    (funcall mode))
+                   ((setq filename (mime-entity-filename entity))
+                    (let ((buffer-file-name
+                           (expand-file-name (file-name-nondirectory filename)
+                                             temporary-file-directory)))
+                      (set-auto-mode))))
+             ;; The mode function might have already turned on font-lock.
+             (unless (symbol-value 'font-lock-mode)
+               (font-lock-fontify-buffer)))
            ;; By default, XEmacs font-lock uses non-duplicable text
            ;; properties.  This code forces all the text properties
            ;; to be copied along with the text.
@@ -949,8 +1015,8 @@ 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
@@ -1176,7 +1242,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)
@@ -1418,15 +1484,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
@@ -1443,9 +1513,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
@@ -1453,12 +1522,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)))
 
@@ -1494,13 +1565,13 @@ It decodes current entity to call internal or external method as
 It calls following-method selected from variable
 `mime-preview-following-method-alist'."
   (interactive)
-  (let ((entity (mime-preview-find-boundary-info t))
-       p-beg p-end
-       pb-beg)
-    (setq p-beg (aref entity 0)
-         p-end (aref entity 1)
-         entity (aref entity 2))
-    (if (get-text-property p-beg 'mime-view-entity-body)
+  (let* ((boundary-info (mime-preview-find-boundary-info t))
+        (p-beg (aref boundary-info 0))
+        (p-end (aref boundary-info 1))
+        (entity (aref boundary-info 2))
+        pb-beg)
+    (if (or (get-text-property p-beg 'mime-view-entity-body)
+           (null entity))
        (setq pb-beg p-beg)
       (setq pb-beg
            (next-single-property-change
@@ -1508,7 +1579,7 @@ It calls following-method selected from variable
             (or (next-single-property-change p-beg 'mime-view-entity)
                 p-end))))
     (let* ((mode (mime-preview-original-major-mode 'recursive))
-          (entity-node-id (mime-entity-node-id entity))
+          (entity-node-id (and entity (mime-entity-node-id entity)))
           (new-name
            (format "%s-%s" (buffer-name) (reverse entity-node-id)))
           new-buf
@@ -1521,7 +1592,8 @@ It calls following-method selected from variable
        (insert-buffer-substring the-buf pb-beg p-end)
        (goto-char (point-min))
        (let ((current-entity
-              (if (and (eq (mime-entity-media-type entity) 'message)
+              (if (and entity
+                       (eq (mime-entity-media-type entity) 'message)
                        (eq (mime-entity-media-subtype entity) 'rfc822))
                   (car (mime-entity-children entity))
                 entity)))
@@ -1558,9 +1630,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
@@ -1716,15 +1787,15 @@ If LINES is negative, scroll up LINES lines."
 ;;; @@ display
 ;;;
 
-(defun mime-view-default-content-transfer-encoding (entity situation)
+(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-content-transfer-encoding (entity situation)
+(defun mime-view-read-encoding (entity situation)
   (let* ((default-encoding
-          (mime-view-default-content-transfer-encoding entity situation))
+          (mime-view-guess-encoding entity situation))
         (encoding
          (completing-read
           "Content Transfer Encoding: "
@@ -1733,40 +1804,38 @@ If LINES is negative, scroll up LINES lines."
                (string= encoding default-encoding))
       encoding)))
 
-(defun mime-view-default-mime-charset (entity situation)
-  (or (cdr (assq '*mime-charset situation))
-      (static-if (fboundp 'coding-system-to-mime-charset)
-         ;; might be specified by `universal-coding-system-argument'.
+(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)))
-      (let ((charset-param
-            (mime-content-type-parameter
-             (mime-entity-content-type entity)
-             "charset")))
-       (if charset-param
-           (intern (downcase charset-param))))
+      (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-mime-charset (entity situation)
+(defun mime-view-read-charset (entity situation)
   (static-if (featurep 'mule)
-      (let* ((default-mime-charset
-              (mime-view-default-mime-charset entity situation))
-            (mime-charset
+      (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-mime-charset)))))
-       (unless (eq mime-charset default-mime-charset)
-         mime-charset))
-    default-mime-charset))
+                                      (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 encoding mime-charset)
+       entity p-beg p-end encoding charset)
     (setq p-beg (aref situation 0)
          p-end (aref situation 1)
          entity (aref situation 2)
@@ -1785,11 +1854,10 @@ If LINES is negative, scroll up LINES lines."
                               situation))
     (when (and current-prefix-arg
               (eq (cdr (assq sym situation)) 'visible))
-      (if (setq encoding (mime-view-read-content-transfer-encoding
-                         entity situation))
-         (put-alist '*encoding encoding situation))
-      (if (setq mime-charset (mime-view-read-mime-charset entity situation))
-         (put-alist '*mime-charset mime-charset situation)))
+      (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)