lisp/window.el (window--state-get-1): Workaround for bug#14527.
[bpt/emacs.git] / lisp / mail / rmailmm.el
index 31e34cd..350e3da 100644 (file)
@@ -1,6 +1,6 @@
 ;;; rmailmm.el --- MIME decoding and display stuff for RMAIL
 
-;; Copyright (C) 2006-201 Free Software Foundation, Inc.
+;; Copyright (C) 2006-2013 Free Software Foundation, Inc.
 
 ;; Author: Alexander Pohoyda
 ;;     Alex Schroeder
@@ -320,7 +320,7 @@ The value is a vector [INDEX HEADER TAGLINE BODY END], where
            (setq index 2))
        ;; If the tagline is displayed, get past it to the body.
        (if (rmail-mime-display-tagline current)
-           ;; The next foward-line call must be in sync with how
+           ;; The next forward-line call must be in sync with how
            ;; `rmail-mime-insert-tagline' formats the tagline.  The
            ;; body begins after the empty line that ends the tagline.
            (forward-line 3))
@@ -389,13 +389,13 @@ Use `raw' for raw mode, and any other non-nil value for decoded mode."
        ;; Enter the raw mode.
        (rmail-mime-raw-mode entity)
       ;; Enter the shown mode.
-      (rmail-mime-shown-mode entity))
-    (let ((inhibit-read-only t)
-         (modified (buffer-modified-p)))
-      (save-excursion
-       (goto-char (aref segment 1))
-       (rmail-mime-insert entity)
-       (restore-buffer-modified-p modified)))))
+      (rmail-mime-shown-mode entity)
+      (let ((inhibit-read-only t)
+           (modified (buffer-modified-p)))
+       (save-excursion
+         (goto-char (aref segment 1))
+         (rmail-mime-insert entity)
+         (restore-buffer-modified-p modified))))))
 
 (defun rmail-mime-toggle-hidden ()
   "Hide or show the body of the MIME-entity at point."
@@ -612,23 +612,6 @@ HEADER is a header component of a MIME-entity object (see
          (rmail-mime-insert-decoded-text entity)))
     (put-text-property beg (point) 'rmail-mime-entity entity)))
 
-;; FIXME move to the test/ directory?
-(defun test-rmail-mime-handler ()
-  "Test of a mail using no MIME parts at all."
-  (let ((mail "To: alex@gnu.org
-Content-Type: text/plain; charset=koi8-r
-Content-Transfer-Encoding: 8bit
-MIME-Version: 1.0
-
-\372\304\322\301\327\323\324\327\325\312\324\305\41"))
-    (switch-to-buffer (get-buffer-create "*test*"))
-    (erase-buffer)
-    (set-buffer-multibyte nil)
-    (insert mail)
-    (rmail-mime-show t)
-    (set-buffer-multibyte t)))
-
-
 (defun rmail-mime-insert-image (entity)
   "Decode and insert the image body of MIME-entity ENTITY."
   (let* ((content-type (car (rmail-mime-entity-type entity)))
@@ -813,27 +796,6 @@ directly."
                 (rmail-mime-insert-decoded-text entity)))))
     (put-text-property beg (point) 'rmail-mime-entity entity)))
 
-(defun test-rmail-mime-bulk-handler ()
-  "Test of a mail used as an example in RFC 2183."
-  (let ((mail "Content-Type: image/jpeg
-Content-Disposition: attachment; filename=genome.jpeg;
-  modification-date=\"Wed, 12 Feb 1997 16:29:51 -0500\";
-Content-Description: a complete map of the human genome
-Content-Transfer-Encoding: base64
-
-iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAMAAABg3Am1AAAABGdBTUEAALGPC/xhBQAAAAZQ
-TFRF////AAAAVcLTfgAAAPZJREFUeNq9ldsOwzAIQ+3//+l1WlvA5ZLsoUiTto4TB+ISoAjy
-+ITfRBfcAmgRFFeAm+J6uhdKdFhFWUgDkFsK0oUp/9G2//Kj7Jx+5tSKOdBscgUYiKHRS/me
-WATQdRUvAK0Bnmshmtn79PpaLBbbOZkjKvRnjRZoRswOkG1wFchKew2g9wXVJVZL/m4+B+vv
-9AxQQR2Q33SgAYJzzVACdAWjAfRYzYFO9n6SLnydtQHSMxYDMAKqZ/8FS/lTK+zuq3CtK64L
-UDwbgUEAUmk2Zyg101d6PhCDySgAvTvDgKiuOrc4dLxUb7UMnhGIexyI+d6U+ABuNAP4Simx
-lgAAAABJRU5ErkJggg==
-"))
-    (switch-to-buffer (get-buffer-create "*test*"))
-    (erase-buffer)
-    (insert mail)
-    (rmail-mime-show)))
-
 (defun rmail-mime-multipart-handler (content-type
                                     content-disposition
                                     content-transfer-encoding)
@@ -870,7 +832,7 @@ The other arguments are the same as `rmail-mime-multipart-handler'."
   (let ((boundary (cdr (assq 'boundary content-type)))
        (subtype (cadr (split-string (car content-type) "/")))
        (index 0)
-       beg end next entities truncated)
+       beg end next entities truncated last)
     (unless boundary
       (rmail-mm-get-boundary-error-message
        "No boundary defined" content-type content-disposition
@@ -905,7 +867,13 @@ The other arguments are the same as `rmail-mime-multipart-handler'."
               ;; Handle the rest of the truncated message
               ;; (if it isn't empty) by pretending that the boundary
               ;; appears at the end of the message.
-              (and (save-excursion
+              ;; We use `last' to distinguish this from the more
+              ;; likely situation of there being an epilogue
+              ;; after the last boundary, which should be ignored.
+              ;; See rmailmm-test-multipart-handler for an example,
+              ;; and also bug#10101.
+              (and (not last)
+                   (save-excursion
                      (skip-chars-forward "\n")
                      (> (point-max) (point)))
                    (setq truncated t end (point-max))))
@@ -913,7 +881,8 @@ The other arguments are the same as `rmail-mime-multipart-handler'."
       ;; epilogue, else hide the boundary only.  Use a marker for
       ;; `next' because `rmail-mime-show' may change the buffer.
       (cond ((looking-at "--[ \t]*$")
-            (setq next (point-max-marker)))
+            (setq next (point-max-marker)
+                  last t))
            ((looking-at "[ \t]*\n")
             (setq next (copy-marker (match-end 0) t)))
            (truncated
@@ -971,37 +940,6 @@ The other arguments are the same as `rmail-mime-multipart-handler'."
                (rmail-mime-hidden-mode child)))))
       entities)))
 
-(defun test-rmail-mime-multipart-handler ()
-  "Test of a mail used as an example in RFC 2046."
-  (let ((mail "From: Nathaniel Borenstein <nsb@bellcore.com>
-To: Ned Freed <ned@innosoft.com>
-Date: Sun, 21 Mar 1993 23:56:48 -0800 (PST)
-Subject: Sample message
-MIME-Version: 1.0
-Content-type: multipart/mixed; boundary=\"simple boundary\"
-
-This is the preamble.  It is to be ignored, though it
-is a handy place for composition agents to include an
-explanatory note to non-MIME conformant readers.
-
---simple boundary
-
-This is implicitly typed plain US-ASCII text.
-It does NOT end with a linebreak.
---simple boundary
-Content-type: text/plain; charset=us-ascii
-
-This is explicitly typed plain US-ASCII text.
-It DOES end with a linebreak.
-
---simple boundary--
-
-This is the epilogue.  It is also to be ignored."))
-    (switch-to-buffer (get-buffer-create "*test*"))
-    (erase-buffer)
-    (insert mail)
-    (rmail-mime-show t)))
-
 (defun rmail-mime-insert-multipart (entity)
   "Presentation handler for a multipart MIME entity."
   (let ((current (aref (rmail-mime-entity-display entity) 0))
@@ -1281,7 +1219,7 @@ available."
          (if (rmail-mime-display-header current)
              (delete-char (- (aref segment 2) (aref segment 1))))
          (insert-buffer-substring rmail-mime-mbox-buffer
-                                    (aref header 0) (aref header 1)))
+                                  (aref header 0) (aref header 1)))
        ;; tagline
        (if (rmail-mime-display-tagline current)
            (delete-char (- (aref segment 3) (aref segment 2))))
@@ -1330,15 +1268,19 @@ The arguments ARG and STATE have no effect in this case."
   (interactive (list current-prefix-arg nil))
   (if rmail-enable-mime
       (with-current-buffer rmail-buffer
-       (if (rmail-mime-message-p)
-           (let ((rmail-mime-mbox-buffer rmail-view-buffer)
-                 (rmail-mime-view-buffer rmail-buffer)
-                 (entity (get-text-property
-                          (progn
-                            (or arg (goto-char (point-min)))
-                            (point)) 'rmail-mime-entity)))
-             (if (or (not arg) entity) (rmail-mime-toggle-raw state)))
-         (message "Not a MIME message")))
+       (if (or (rmail-mime-message-p)
+               (get-text-property (point-min) 'rmail-mime-hidden))
+           (let* ((hidden (get-text-property (point-min) 'rmail-mime-hidden))
+                  (desired-hidden (if state (eq state 'raw) (not hidden))))
+             (unless (eq hidden desired-hidden)
+               (if (not desired-hidden)
+                   (rmail-show-message rmail-current-message)
+                 (let ((rmail-enable-mime nil)
+                       (inhibit-read-only t))
+                   (rmail-show-message rmail-current-message)
+                   (add-text-properties (point-min) (point-max) '(rmail-mime-hidden t))))))
+         (message "Not a MIME message, just toggling headers")
+         (rmail-toggle-header)))
     (let* ((data (rmail-apply-in-message rmail-current-message 'buffer-string))
           (buf (get-buffer-create "*RMAIL*"))
           (rmail-mime-mbox-buffer rmail-view-buffer)
@@ -1368,26 +1310,40 @@ The arguments ARG and STATE have no effect in this case."
        (rmail-mime-mbox-buffer rmail-buffer)
        (rmail-mime-view-buffer rmail-view-buffer)
        (rmail-mime-coding-system nil))
+    ;; If ENTITY is not a vector, it is a string describing an error.
     (if (vectorp entity)
        (with-current-buffer rmail-mime-view-buffer
          (erase-buffer)
-         (rmail-mime-insert entity)
-         (if (consp rmail-mime-coding-system)
-             ;; Decoding is done by rfc2047-decode-region only for a
-             ;; header.  But, as the used coding system may have been
-             ;; overridden by mm-charset-override-alist, we can't
-             ;; trust (car rmail-mime-coding-system).  So, here we
-             ;; try the decoding again with mm-charset-override-alist
-             ;; bound to nil.
-             (let ((mm-charset-override-alist nil))
-               (setq rmail-mime-coding-system
-                     (rmail-mime-find-header-encoding
-                      (rmail-mime-entity-header entity)))))
-         (set-buffer-file-coding-system
-          (if rmail-mime-coding-system
-              (coding-system-base rmail-mime-coding-system)
-            'undecided)
-          t t))
+         ;; This condition-case is for catching an error in the
+         ;; internal MIME decoding (e.g. incorrect BASE64 form) that
+         ;; may be signaled by rmail-mime-insert.
+         ;; FIXME: The current code doesn't set a proper error symbol
+         ;; in ERR.  We must find a way to propagate a correct error
+         ;; symbol that is caused in the very deep code of text
+         ;; decoding (e.g. an error by base64-decode-region called by
+         ;; post-read-conversion function of utf-7).
+         (condition-case err
+             (progn
+               (rmail-mime-insert entity)
+               (if (consp rmail-mime-coding-system)
+                   ;; Decoding is done by rfc2047-decode-region only for a
+                   ;; header.  But, as the used coding system may have been
+                   ;; overridden by mm-charset-override-alist, we can't
+                   ;; trust (car rmail-mime-coding-system).  So, here we
+                   ;; try the decoding again with mm-charset-override-alist
+                   ;; bound to nil.
+                   (let ((mm-charset-override-alist nil))
+                     (setq rmail-mime-coding-system
+                           (rmail-mime-find-header-encoding
+                            (rmail-mime-entity-header entity)))))
+               (set-buffer-file-coding-system
+                (if rmail-mime-coding-system
+                    (coding-system-base rmail-mime-coding-system)
+                  'undecided)
+                t t))
+           (error (setq entity (format "%s" err))))))
+    ;; Re-check ENTITY.  It may be set to an error string.
+    (when (stringp entity)
       ;; Decoding failed.  ENTITY is an error message.  Insert the
       ;; original message body as is, and show warning.
       (let ((region (with-current-buffer rmail-mime-mbox-buffer
@@ -1409,14 +1365,15 @@ The arguments ARG and STATE have no effect in this case."
 (defun rmail-insert-mime-forwarded-message (forward-buffer)
   "Insert the message in FORWARD-BUFFER as a forwarded message.
 This is the usual value of `rmail-insert-mime-forwarded-message-function'."
-  (let ((message-buffer
-        (with-current-buffer forward-buffer
-          (if rmail-buffer-swapped
-              forward-buffer
-            rmail-view-buffer))))
-    (save-restriction
-      (narrow-to-region (point) (point))
-      (message-forward-make-body-mime message-buffer))))
+  (let (contents-buffer start end)
+    (with-current-buffer forward-buffer
+      (setq contents-buffer
+           (if rmail-buffer-swapped
+               rmail-view-buffer
+             forward-buffer)
+           start (rmail-msgbeg rmail-current-message)
+           end (rmail-msgend rmail-current-message)))
+    (message-forward-make-body-mime contents-buffer start end)))
 
 (setq rmail-insert-mime-forwarded-message-function
       'rmail-insert-mime-forwarded-message)