Auto-commit of loaddefs files.
[bpt/emacs.git] / lisp / mail / rmail.el
index 7fe5383..08c612c 100644 (file)
@@ -91,6 +91,7 @@ its character representation and its display representation.")
 (defvar messages-head)
 (defvar total-messages)
 (defvar tool-bar-map)
 (defvar messages-head)
 (defvar total-messages)
 (defvar tool-bar-map)
+(defvar mail-encode-mml)
 
 (defvar rmail-header-style 'normal
   "The current header display style choice, one of
 
 (defvar rmail-header-style 'normal
   "The current header display style choice, one of
@@ -193,6 +194,7 @@ please report it with \\[report-emacs-bug].")
 
 (declare-function mail-dont-reply-to "mail-utils" (destinations))
 (declare-function rmail-update-summary "rmailsum" (&rest ignore))
 
 (declare-function mail-dont-reply-to "mail-utils" (destinations))
 (declare-function rmail-update-summary "rmailsum" (&rest ignore))
+(declare-function rmail-mime-toggle-hidden "rmailmm" ())
 
 (defun rmail-probe (prog)
   "Determine what flavor of movemail PROG is.
 
 (defun rmail-probe (prog)
   "Determine what flavor of movemail PROG is.
@@ -349,7 +351,7 @@ If nil, display all header fields except those matched by
   :group 'rmail-headers)
 
 ;;;###autoload
   :group 'rmail-headers)
 
 ;;;###autoload
-(defcustom rmail-retry-ignored-headers (purecopy "^x-authentication-warning:\\|^x-detected-operating-system:\\|^x-spam[-a-z]*:\\|content-type:\\|content-transfer-encoding:\\|mime-version:")
+(defcustom rmail-retry-ignored-headers (purecopy "^x-authentication-warning:\\|^x-detected-operating-system:\\|^x-spam[-a-z]*:\\|content-type:\\|content-transfer-encoding:\\|mime-version:\\|message-id:")
   "Headers that should be stripped when retrying a failed message."
   :type '(choice regexp (const nil :tag "None"))
   :group 'rmail-headers
   "Headers that should be stripped when retrying a failed message."
   :type '(choice regexp (const nil :tag "None"))
   :group 'rmail-headers
@@ -503,7 +505,7 @@ FIELD is the plain text name of a field in the message, such as
 \"subject\" or \"from\".  A FIELD of \"to\" will automatically include
 all text from the \"cc\" field as well.
 
 \"subject\" or \"from\".  A FIELD of \"to\" will automatically include
 all text from the \"cc\" field as well.
 
-REGEXP is an expression to match in the preceeding specified FIELD.
+REGEXP is an expression to match in the preceding specified FIELD.
 FIELD/REGEXP pairs continue in the list.
 
 examples:
 FIELD/REGEXP pairs continue in the list.
 
 examples:
@@ -629,33 +631,29 @@ Element N specifies the summary line for message N+1.")
 This is set to nil by default.")
 
 (defcustom rmail-enable-mime t
 This is set to nil by default.")
 
 (defcustom rmail-enable-mime t
-  "If non-nil, RMAIL uses MIME features.
-If the value is t, RMAIL automatically shows MIME decoded message.
-If the value is neither t nor nil, RMAIL does not show MIME decoded message
-until a user explicitly requires it.
-
-Even if the value is non-nil, you can't use MIME features
-unless the feature specified by `rmail-mime-feature' is available."
-  :type '(choice (const :tag "on" t)
-                (const :tag "off" nil)
-                (other :tag "when asked" ask))
+  "If non-nil, RMAIL automatically displays decoded MIME messages.
+For this to work, the feature specified by `rmail-mime-feature' must
+be available."
+  :type 'boolean
   :version "23.3"
   :group 'rmail)
 
   :version "23.3"
   :group 'rmail)
 
-(defvar rmail-enable-mime-composing nil
-  "*If non-nil, RMAIL uses `rmail-insert-mime-forwarded-message-function' to forward.")
+(defcustom rmail-enable-mime-composing t
+  "If non-nil, use `rmail-insert-mime-forwarded-message-function' to forward."
+  :type 'boolean
+  :version "24.1"                      ; nil -> t
+  :group 'rmail)
 
 
-;; FIXME unused.
 (defvar rmail-show-mime-function nil
 (defvar rmail-show-mime-function nil
-  "Function to show MIME decoded message of RMAIL file.
+  "Function of no argument called to show a decoded MIME message.
 This function is called when `rmail-enable-mime' is non-nil.
 This function is called when `rmail-enable-mime' is non-nil.
-It is called with no argument.")
+The package providing MIME support should set this.")
 
 ;;;###autoload
 (defvar rmail-insert-mime-forwarded-message-function nil
   "Function to insert a message in MIME format so it can be forwarded.
 
 ;;;###autoload
 (defvar rmail-insert-mime-forwarded-message-function nil
   "Function to insert a message in MIME format so it can be forwarded.
-This function is called if `rmail-enable-mime' or
-`rmail-enable-mime-composing' is non-nil.
+This function is called if `rmail-enable-mime' and
+`rmail-enable-mime-composing' are non-nil.
 It is called with one argument FORWARD-BUFFER, which is a
 buffer containing the message to forward.  The current buffer
 is the outgoing mail buffer.")
 It is called with one argument FORWARD-BUFFER, which is a
 buffer containing the message to forward.  The current buffer
 is the outgoing mail buffer.")
@@ -685,13 +683,18 @@ where MSG is the message number, REGEXP is the regular
 expression, LIMIT is the position specifying the end of header.")
 
 (defvar rmail-mime-feature 'rmailmm
 expression, LIMIT is the position specifying the end of header.")
 
 (defvar rmail-mime-feature 'rmailmm
-  "Feature to require to load MIME support in Rmail.
-When starting Rmail, if `rmail-enable-mime' is non-nil,
-this feature is required with `require'.
-
-The default value is `rmailmm'")
-
-;; FIXME this is unused.
+  "Feature to require for MIME support in Rmail.
+When starting Rmail, if `rmail-enable-mime' is non-nil, this
+feature is loaded with `require'.  The default value is `rmailmm'.
+
+The library should set the variable `rmail-show-mime-function'
+to an appropriate value, and optionally also set
+`rmail-search-mime-message-function',
+`rmail-search-mime-header-function',
+`rmail-insert-mime-forwarded-message-function', and
+`rmail-insert-mime-resent-message-function'.")
+
+;; FIXME this is unused since 23.1.
 (defvar rmail-decode-mime-charset t
   "*Non-nil means a message is decoded by MIME's charset specification.
 If this variable is nil, or the message has not MIME specification,
 (defvar rmail-decode-mime-charset t
   "*Non-nil means a message is decoded by MIME's charset specification.
 If this variable is nil, or the message has not MIME specification,
@@ -701,6 +704,9 @@ If the variable `rmail-enable-mime' is non-nil, this variable is
 ignored, and all the decoding work is done by a feature specified by
 the variable `rmail-mime-feature'.")
 
 ignored, and all the decoding work is done by a feature specified by
 the variable `rmail-mime-feature'.")
 
+(make-obsolete-variable 'rmail-decode-mime-charset
+                       "it does nothing." "23.1")
+
 (defvar rmail-mime-charset-pattern
   (concat "^content-type:[ \t]*text/plain;"
          "\\(?:[ \t\n]*\\(?:format\\|delsp\\)=\"?[-a-z0-9]+\"?;\\)*"
 (defvar rmail-mime-charset-pattern
   (concat "^content-type:[ \t]*text/plain;"
          "\\(?:[ \t\n]*\\(?:format\\|delsp\\)=\"?[-a-z0-9]+\"?;\\)*"
@@ -835,10 +841,10 @@ isn't provided."
        (display-warning
        'rmail
        (format "Although MIME support is requested
        (display-warning
        'rmail
        (format "Although MIME support is requested
-by setting `rmail-enable-mime' to non-nil, the required feature
+through `rmail-enable-mime' being non-nil, the required feature
 `%s' (the value of `rmail-mime-feature')
 is not available in the current session.
 `%s' (the value of `rmail-mime-feature')
 is not available in the current session.
-So, the MIME support is turned off for the moment."
+So, MIME support is turned off for the moment."
                rmail-mime-feature)
        :warning)
        (setq rmail-enable-mime nil)))))
                rmail-mime-feature)
        :warning)
        (setq rmail-enable-mime nil)))))
@@ -1007,6 +1013,7 @@ The buffer is expected to be narrowed to just the header of the message."
     (define-key map "\e\C-l" 'rmail-summary-by-labels)
     (define-key map "\e\C-r" 'rmail-summary-by-recipients)
     (define-key map "\e\C-s" 'rmail-summary-by-regexp)
     (define-key map "\e\C-l" 'rmail-summary-by-labels)
     (define-key map "\e\C-r" 'rmail-summary-by-recipients)
     (define-key map "\e\C-s" 'rmail-summary-by-regexp)
+    (define-key map "\e\C-f" 'rmail-summary-by-senders)
     (define-key map "\e\C-t" 'rmail-summary-by-topic)
     (define-key map "m"      'rmail-mail)
     (define-key map "\em"    'rmail-retry-failure)
     (define-key map "\e\C-t" 'rmail-summary-by-topic)
     (define-key map "m"      'rmail-mail)
     (define-key map "\em"    'rmail-retry-failure)
@@ -1034,8 +1041,8 @@ The buffer is expected to be narrowed to just the header of the message."
     (define-key map "/"      'rmail-end-of-message)
     (define-key map "<"      'rmail-first-message)
     (define-key map ">"      'rmail-last-message)
     (define-key map "/"      'rmail-end-of-message)
     (define-key map "<"      'rmail-first-message)
     (define-key map ">"      'rmail-last-message)
-    (define-key map " "      'scroll-up)
-    (define-key map "\177"   'scroll-down)
+    (define-key map " "      'scroll-up-command)
+    (define-key map "\177"   'scroll-down-command)
     (define-key map "?"      'describe-mode)
     (define-key map "\C-c\C-s\C-d" 'rmail-sort-by-date)
     (define-key map "\C-c\C-s\C-s" 'rmail-sort-by-subject)
     (define-key map "?"      'describe-mode)
     (define-key map "\C-c\C-s\C-d" 'rmail-sort-by-date)
     (define-key map "\C-c\C-s\C-s" 'rmail-sort-by-subject)
@@ -1309,9 +1316,14 @@ Create the buffer if necessary."
   (if (and (local-variable-p 'rmail-view-buffer)
           (buffer-live-p rmail-view-buffer))
       rmail-view-buffer
   (if (and (local-variable-p 'rmail-view-buffer)
           (buffer-live-p rmail-view-buffer))
       rmail-view-buffer
-    (generate-new-buffer
-     (format " *message-viewer %s*"
-            (file-name-nondirectory (or buffer-file-name (buffer-name)))))))
+    (let ((newbuf
+          (generate-new-buffer
+           (format " *message-viewer %s*"
+                   (file-name-nondirectory
+                    (or buffer-file-name (buffer-name)))))))
+      (with-current-buffer newbuf
+       (add-hook 'kill-buffer-hook 'rmail-view-buffer-kill-buffer-hook nil t))
+      newbuf)))
 
 (defun rmail-swap-buffers ()
   "Swap text between current buffer and `rmail-view-buffer'.
 
 (defun rmail-swap-buffers ()
   "Swap text between current buffer and `rmail-view-buffer'.
@@ -1371,7 +1383,14 @@ If so restore the actual mbox message collection."
     (message "Marking buffer unmodified to avoid rewriting Babyl file as mbox file")))
 
 (defun rmail-mode-kill-buffer-hook ()
     (message "Marking buffer unmodified to avoid rewriting Babyl file as mbox file")))
 
 (defun rmail-mode-kill-buffer-hook ()
-  (if (buffer-live-p rmail-view-buffer) (kill-buffer rmail-view-buffer)))
+  ;; Turn off the hook on the view buffer, so we can kill it, then kill it.
+  (if (buffer-live-p rmail-view-buffer)
+      (with-current-buffer rmail-view-buffer
+       (setq kill-buffer-hook nil)
+       (kill-buffer rmail-view-buffer))))
+
+(defun rmail-view-buffer-kill-buffer-hook ()
+  (error "Can't kill message view buffer by itself"))
 
 ;; Set up the permanent locals associated with an Rmail file.
 (defun rmail-perm-variables ()
 
 ;; Set up the permanent locals associated with an Rmail file.
 (defun rmail-perm-variables ()
@@ -1444,7 +1463,8 @@ If so restore the actual mbox message collection."
   (make-local-variable 'file-precious-flag)
   (setq file-precious-flag t)
   (make-local-variable 'desktop-save-buffer)
   (make-local-variable 'file-precious-flag)
   (setq file-precious-flag t)
   (make-local-variable 'desktop-save-buffer)
-  (setq desktop-save-buffer t))
+  (setq desktop-save-buffer t)
+  (setq next-error-move-function 'rmail-next-error-move))
 \f
 ;; Handle M-x revert-buffer done in an rmail-mode buffer.
 (defun rmail-revert (arg noconfirm)
 \f
 ;; Handle M-x revert-buffer done in an rmail-mode buffer.
 (defun rmail-revert (arg noconfirm)
@@ -1705,10 +1725,12 @@ not be a new one).  It returns non-nil if it got any new messages."
                (setq all-files (cdr all-files)))
              ;; Put them back in their original order.
              (setq files (nreverse files))
                (setq all-files (cdr all-files)))
              ;; Put them back in their original order.
              (setq files (nreverse files))
-             ;; In case of brain damage caused by require-final-newline.
              (goto-char (point-max))
              (goto-char (point-max))
-             (skip-chars-backward " \t\n")
-             (delete-region (point) (point-max))
+             ;; Make sure we end with a blank line unless there are
+             ;; no messages, as required by mbox format (Bug#9974).
+             (unless (bobp)
+               (while (not (looking-back "\n\n"))
+                 (insert "\n")))
              (setq found (or
                           (rmail-get-new-mail-1 file-name files delete-files)
                           found))))
              (setq found (or
                           (rmail-get-new-mail-1 file-name files delete-files)
                           found))))
@@ -2008,22 +2030,12 @@ Value is the size of the newly read mail after conversion."
                  (rmail-unrmail-new-mail-maybe
                   tofile
                   (nth 1 (insert-file-contents tofile))))
                  (rmail-unrmail-new-mail-maybe
                   tofile
                   (nth 1 (insert-file-contents tofile))))
-           ;; Determine if a pair of newline message separators need
-           ;; to be added to the new collection of messages.  This is
-           ;; the case for all new message collections added to a
-           ;; non-empty mail file.
-           (unless (zerop size)
-             (save-restriction
-               (let ((start (point-min)))
-                 (widen)
-                 (unless (eq start (point-min))
-                   (goto-char start)
-                   (insert "\n\n")
-                   (setq size (+ 2 size))))))
            (goto-char (point-max))
            (goto-char (point-max))
-           (or (= (preceding-char) ?\n)
-               (zerop size)
-               (insert ?\n))
+           ;; Make sure the read-in mbox data properly ends with a
+           ;; blank line unless it is of size 0.
+           (unless (zerop size)
+             (while (not (looking-back "\n\n"))
+               (insert "\n")))
            (if (not (and rmail-preserve-inbox (string= file tofile)))
                (setq delete-files (cons tofile delete-files)))))
       (message "")
            (if (not (and rmail-preserve-inbox (string= file tofile)))
                (setq delete-files (cons tofile delete-files)))))
       (message "")
@@ -2063,7 +2075,7 @@ Call with point at the end of the message."
 (defun rmail-add-mbox-headers ()
   "Validate the RFC2822 format for the new messages.
 Point should be at the first new message.
 (defun rmail-add-mbox-headers ()
   "Validate the RFC2822 format for the new messages.
 Point should be at the first new message.
-An error is signalled if the new messages are not RFC2822
+An error is signaled if the new messages are not RFC2822
 compliant.
 Unless an Rmail attribute header already exists, add it to the
 new messages.  Return the number of new messages."
 compliant.
 Unless an Rmail attribute header already exists, add it to the
 new messages.  Return the number of new messages."
@@ -2306,11 +2318,11 @@ change; nil means current message."
 ;;;; *** Rmail Message Selection And Support ***
 
 (defun rmail-msgend (n)
 ;;;; *** Rmail Message Selection And Support ***
 
 (defun rmail-msgend (n)
-  "Return the start position for message number N."
+  "Return the end position for message number N."
   (marker-position (aref rmail-message-vector (1+ n))))
 
 (defun rmail-msgbeg (n)
   (marker-position (aref rmail-message-vector (1+ n))))
 
 (defun rmail-msgbeg (n)
-  "Return the end position for message number N."
+  "Return the start position for message number N."
   (marker-position (aref rmail-message-vector n)))
 
 (defun rmail-apply-in-message (msgnum function &rest args)
   (marker-position (aref rmail-message-vector n)))
 
 (defun rmail-apply-in-message (msgnum function &rest args)
@@ -2432,7 +2444,7 @@ Output a helpful message unless NOMSG is non-nil."
        ;; the entry for message N+1, which marks
        ;; the end of message N.  (N = number of messages).
        (setq messages-head (list (point-marker)))
        ;; the entry for message N+1, which marks
        ;; the end of message N.  (N = number of messages).
        (setq messages-head (list (point-marker)))
-       (setq messages-after-point 
+       (setq messages-after-point
              (or (rmail-set-message-counters-counter (min (point) point-save))
                  0))
 
              (or (rmail-set-message-counters-counter (min (point) point-save))
                  0))
 
@@ -2594,6 +2606,8 @@ Ask the user whether to add that list name to `mail-mailing-lists'."
   "Return nil if there is mail, else \"No mail.\"."
   (if (zerop rmail-total-messages)
       (save-excursion
   "Return nil if there is mail, else \"No mail.\"."
   (if (zerop rmail-total-messages)
       (save-excursion
+       ;; Eg we deleted all the messages, so remove the old N/M mark.
+       (with-current-buffer rmail-buffer (setq mode-line-process nil))
        (with-current-buffer rmail-view-buffer
          (erase-buffer)
          "No mail."))))
        (with-current-buffer rmail-view-buffer
          (erase-buffer)
          "No mail."))))
@@ -2669,8 +2683,11 @@ The current mail message becomes the message displayed."
            (t (setq rmail-current-message msg)))
       (with-current-buffer rmail-buffer
        (setq header-style rmail-header-style)
            (t (setq rmail-current-message msg)))
       (with-current-buffer rmail-buffer
        (setq header-style rmail-header-style)
-       ;; Mark the message as seen
-       (rmail-set-attribute rmail-unseen-attr-index nil)
+       ;; Mark the message as seen, but preserve buffer modified flag.
+       (let ((modiff (buffer-modified-p)))
+         (rmail-set-attribute rmail-unseen-attr-index nil)
+         (unless modiff
+           (restore-buffer-modified-p modiff)))
        ;; bracket the message in the mail
        ;; buffer and determine the coding system the transfer encoding.
        (rmail-swap-buffers-maybe)
        ;; bracket the message in the mail
        ;; buffer and determine the coding system the transfer encoding.
        (rmail-swap-buffers-maybe)
@@ -2687,6 +2704,7 @@ The current mail message becomes the message displayed."
          ;; inspect this value to determine how to toggle.
          (set (make-local-variable 'rmail-header-style) header-style))
        (if (and rmail-enable-mime
          ;; inspect this value to determine how to toggle.
          (set (make-local-variable 'rmail-header-style) header-style))
        (if (and rmail-enable-mime
+                rmail-show-mime-function
                 (re-search-forward "mime-version: 1.0" nil t))
            (let ((rmail-buffer mbox-buf)
                  (rmail-view-buffer view-buf))
                 (re-search-forward "mime-version: 1.0" nil t))
            (let ((rmail-buffer mbox-buf)
                  (rmail-view-buffer view-buf))
@@ -3016,15 +3034,97 @@ or forward if N is negative."
   (rmail-maybe-set-message-counters)
   (rmail-show-message rmail-total-messages))
 
   (rmail-maybe-set-message-counters)
   (rmail-show-message rmail-total-messages))
 
-(defun rmail-what-message ()
-  "For debugging Rmail: find the message number that point is in."
+(defun rmail-next-error-move (msg-pos bad-marker)
+  "Move to an error locus (probably grep hit) in an Rmail buffer.
+MSG-POS is a marker pointing at the error message in the grep buffer.
+BAD-MARKER is a marker that ought to point at where to move to,
+but probably is garbage."
+
+  (let* ((message-loc (compilation--message->loc
+                      (get-text-property msg-pos 'compilation-message
+                                         (marker-buffer msg-pos))))
+        (column (car message-loc))
+        (linenum (cadr message-loc))
+        line-text
+        pos
+        msgnum msgbeg msgend
+        header-field
+        line-number-within)
+
+    ;; Look at the whole Rmail file.
+    (rmail-swap-buffers-maybe)
+
+    (save-restriction
+      (widen)
+      (save-excursion
+       ;; Find the line that the error message points at.
+       (goto-char (point-min))
+       (forward-line (1- linenum))
+       (setq pos (point))
+
+       ;; Find the text at the start of the line,
+       ;; before the first = sign.
+       ;; This text has a good chance of being also in the
+       ;; decoded message.
+       (save-excursion
+         (skip-chars-forward "^=\n")
+         (setq line-text (buffer-substring pos (point))))
+
+       ;; Find which message this position is in,
+       ;; and the limits of that message.
+       (setq msgnum (rmail-what-message pos))
+       (setq msgbeg (rmail-msgbeg msgnum))
+       (setq msgend (rmail-msgend msgnum))
+
+       ;; Find which header this locus is in,
+       ;; or if it's in the message body,
+       ;; and the line-based position within that.
+       (goto-char msgbeg)
+       (let ((header-end msgend))
+         (if (search-forward "\n\n" nil t)
+             (setq header-end (point)))
+         (if (>= pos header-end)
+             (setq line-number-within
+                   (count-lines header-end pos))
+           (goto-char pos)
+           (unless (looking-at "^[^ \t]")
+             (re-search-backward "^[^ \t]"))
+           (looking-at "[^:\n]*[:\n]")
+           (setq header-field (match-string 0)
+                 line-number-within (count-lines (point) pos))))))
+
+    ;; Display the right message.
+    (rmail-show-message msgnum)
+
+    ;; Move to the right position within the displayed message.
+    ;; Or at least try.  The decoded message's lines may not
+    ;; correspond to the lines in the inbox file.
+    (goto-char (point-min))
+    (if header-field
+       (progn
+         (re-search-forward (concat "^" (regexp-quote header-field)) nil t)
+         (forward-line line-number-within))
+      (search-forward "\n\n" nil t)
+      (if (re-search-forward (concat "^" (regexp-quote line-text)) nil t)
+         (goto-char (match-beginning 0))))
+    (if (eobp)
+       ;; If the decoded message doesn't have enough lines,
+       ;; go to the beginning rather than the end.
+       (goto-char (point-min))
+      ;; Otherwise, go to the right column.
+      (if column
+         (forward-char column)))))
+
+(defun rmail-what-message (&optional pos)
+  "Return message number POS (or point) is in."
   (let* ((high rmail-total-messages)
          (mid (/ high 2))
          (low 1)
   (let* ((high rmail-total-messages)
          (mid (/ high 2))
          (low 1)
-         (where (with-current-buffer (if (rmail-buffers-swapped-p)
-                                         rmail-view-buffer
-                                       (current-buffer))
-                  (point))))
+         (where (or pos
+                   (with-current-buffer (if (rmail-buffers-swapped-p)
+                                            rmail-view-buffer
+                                          (current-buffer))
+                     (point)))))
     (while (> (- high low) 1)
       (if (>= where (rmail-msgbeg mid))
           (setq low mid)
     (while (> (- high low) 1)
       (if (>= where (rmail-msgbeg mid))
           (setq low mid)
@@ -3039,10 +3139,9 @@ or forward if N is negative."
   ;; This is adequate because its only caller, rmail-search,
   ;; unswaps the buffers.
   (goto-char (rmail-msgbeg msg))
   ;; This is adequate because its only caller, rmail-search,
   ;; unswaps the buffers.
   (goto-char (rmail-msgbeg msg))
-  (if rmail-enable-mime
-      (if rmail-search-mime-message-function
-          (funcall rmail-search-mime-message-function msg regexp)
-        (error "You must set `rmail-search-mime-message-function'"))
+  (if (and rmail-enable-mime
+          rmail-search-mime-message-function)
+      (funcall rmail-search-mime-message-function msg regexp)
     (re-search-forward regexp (rmail-msgend msg) t)))
 
 (defvar rmail-search-last-regexp nil)
     (re-search-forward regexp (rmail-msgend msg) t)))
 
 (defvar rmail-search-last-regexp nil)
@@ -3162,6 +3261,7 @@ Interactively, empty argument means use same regexp used last time."
 Simplifying the subject means stripping leading and trailing whitespace,
 and typical reply prefixes such as Re:."
   (let ((subject (or (rmail-get-header "Subject" msgnum) "")))
 Simplifying the subject means stripping leading and trailing whitespace,
 and typical reply prefixes such as Re:."
   (let ((subject (or (rmail-get-header "Subject" msgnum) "")))
+    (setq subject (rfc2047-decode-string subject))
     (if (string-match "\\`[ \t]+" subject)
        (setq subject (substring subject (match-end 0))))
     (if (string-match rmail-reply-regexp subject)
     (if (string-match "\\`[ \t]+" subject)
        (setq subject (substring subject (match-end 0))))
     (if (string-match rmail-reply-regexp subject)
@@ -3455,15 +3555,15 @@ does not pop any summary buffer."
     (if (stringp subject) (setq subject (rfc2047-decode-string subject)))
     (prog1
        (compose-mail to subject other-headers noerase
     (if (stringp subject) (setq subject (rfc2047-decode-string subject)))
     (prog1
        (compose-mail to subject other-headers noerase
-                     switch-function yank-action sendactions
-                     '(rmail-mail-return))
+                     switch-function yank-action sendactions)
       (if (eq switch-function 'switch-to-buffer-other-frame)
          ;; This is not a standard frame parameter; nothing except
          ;; sendmail.el looks at it.
            (modify-frame-parameters (selected-frame)
                                   '((mail-dedicated-frame . t)))))))
 
       (if (eq switch-function 'switch-to-buffer-other-frame)
          ;; This is not a standard frame parameter; nothing except
          ;; sendmail.el looks at it.
            (modify-frame-parameters (selected-frame)
                                   '((mail-dedicated-frame . t)))))))
 
-(defun rmail-mail-return ()
+(defun rmail-mail-return (&optional newbuf)
+  "NEWBUF is a buffer to switch to."
   (cond
    ;; If there is only one visible frame with no special handling,
    ;; consider deleting the mail window to return to Rmail.
   (cond
    ;; If there is only one visible frame with no special handling,
    ;; consider deleting the mail window to return to Rmail.
@@ -3488,7 +3588,8 @@ does not pop any summary buffer."
       (if rmail-flag
          ;; If the Rmail buffer has a summary, show that.
          (if summary-buffer (switch-to-buffer summary-buffer)
       (if rmail-flag
          ;; If the Rmail buffer has a summary, show that.
          (if summary-buffer (switch-to-buffer summary-buffer)
-           (delete-window)))))
+           (delete-window))
+       (switch-to-buffer newbuf))))
    ;; If the frame was probably made for this buffer, the user
    ;; probably wants to delete it now.
    ((display-multi-frame-p)
    ;; If the frame was probably made for this buffer, the user
    ;; probably wants to delete it now.
    ((display-multi-frame-p)
@@ -3707,9 +3808,18 @@ see the documentation of `rmail-resend'."
            ;; Insert after header separator--before signature if any.
            (rfc822-goto-eoh)
            (forward-line 1)
            ;; Insert after header separator--before signature if any.
            (rfc822-goto-eoh)
            (forward-line 1)
-           (if (or rmail-enable-mime rmail-enable-mime-composing)
-               (funcall rmail-insert-mime-forwarded-message-function
-                        forward-buffer)
+           (if (and rmail-enable-mime rmail-enable-mime-composing
+                    rmail-insert-mime-forwarded-message-function)
+               (prog1
+                   (funcall rmail-insert-mime-forwarded-message-function
+                            forward-buffer)
+                 ;; rmail-insert-mime-forwarded-message-function
+                 ;; works by inserting MML tags into forward-buffer.
+                 ;; The MUA will need to convert it to MIME before
+                 ;; sending.  mail-encode-mml tells them to do that.
+                 ;; message.el does that automagically.
+                 (or (eq mail-user-agent 'message-user-agent)
+                     (setq mail-encode-mml t)))
              (insert "------- Start of forwarded message -------\n")
              ;; Quote lines with `- ' if they start with `-'.
              (let ((beg (point)) end)
              (insert "------- Start of forwarded message -------\n")
              ;; Quote lines with `- ' if they start with `-'.
              (let ((beg (point)) end)
@@ -3755,10 +3865,9 @@ typically for purposes of moderating a list."
     (unwind-protect
        (with-current-buffer tembuf
          ;;>> Copy message into temp buffer
     (unwind-protect
        (with-current-buffer tembuf
          ;;>> Copy message into temp buffer
-         (if rmail-enable-mime
-              (if rmail-insert-mime-resent-message-function
+         (if (and rmail-enable-mime
+                  rmail-insert-mime-resent-message-function)
                   (funcall rmail-insert-mime-resent-message-function mailbuf)
                   (funcall rmail-insert-mime-resent-message-function mailbuf)
-                (error "You must set `rmail-insert-mime-resent-message-function'"))
            (insert-buffer-substring mailbuf))
          (goto-char (point-min))
          ;; Delete any Sender field, since that's not specifiable.
            (insert-buffer-substring mailbuf))
          (goto-char (point-min))
          ;; Delete any Sender field, since that's not specifiable.
@@ -4162,7 +4271,7 @@ TEXT and INDENT are not used."
    ;; rmail-output expands non-absolute filenames against rmail-default-file.
    ;; What is the point of that, anyway?
    (rmail-output (expand-file-name token))))
    ;; rmail-output expands non-absolute filenames against rmail-default-file.
    ;; What is the point of that, anyway?
    (rmail-output (expand-file-name token))))
-
+\f
 ;; Functions for setting, getting and encoding the POP password.
 ;; The password is encoded to prevent it from being easily accessible
 ;; to "prying eyes."  Obviously, this encoding isn't "real security,"
 ;; Functions for setting, getting and encoding the POP password.
 ;; The password is encoded to prevent it from being easily accessible
 ;; to "prying eyes."  Obviously, this encoding isn't "real security,"
@@ -4213,6 +4322,85 @@ encoded string (and the same mask) will decode the string."
      (setq i (1+ i)))
    (concat string-vector)))
 
      (setq i (1+ i)))
    (concat string-vector)))
 
+(defun rmail-epa-decrypt ()
+  "Decrypt OpenPGP armors in current message."
+  (interactive)
+
+  ;; Save the current buffer here for cleanliness, in case we
+  ;; change it in one of the calls to `epa-decrypt-region'.
+
+  (save-excursion
+    (let (decrypts)
+      (goto-char (point-min))
+
+      ;; In case the encrypted data is inside a mime attachment,
+      ;; show it.  This is a kludge; to be clean, it should not
+      ;; modify the buffer, but I don't see how to do that.
+      (when (search-forward "octet-stream" nil t)
+       (beginning-of-line)
+       (forward-button 1)
+       (if (looking-at "Show")
+           (rmail-mime-toggle-hidden)))
+
+      ;; Now find all armored messages in the buffer
+      ;; and decrypt them one by one.
+      (goto-char (point-min))
+      (while (re-search-forward "-----BEGIN PGP MESSAGE-----$" nil t)
+       (let ((coding-system-for-read coding-system-for-read)
+             armor-start armor-end after-end)
+         (setq armor-start (match-beginning 0)
+               armor-end (re-search-forward "^-----END PGP MESSAGE-----$"
+                                            nil t))
+         (unless armor-end
+           (error "Encryption armor beginning has no matching end"))
+         (goto-char armor-start)
+
+         ;; Because epa--find-coding-system-for-mime-charset not autoloaded.
+         (require 'epa)
+
+         ;; Use the charset specified in the armor.
+         (unless coding-system-for-read
+           (if (re-search-forward "^Charset: \\(.*\\)" armor-end t)
+               (setq coding-system-for-read
+                     (epa--find-coding-system-for-mime-charset
+                      (intern (downcase (match-string 1)))))))
+
+         ;; Advance over this armor.
+         (goto-char armor-end)
+         (setq after-end (- (point-max) armor-end))
+
+         ;; Decrypt it, maybe in place, maybe making new buffer.
+         (epa-decrypt-region
+          armor-start armor-end
+          ;; Call back this function to prepare the output.
+          (lambda ()
+            (let ((inhibit-read-only t))
+              (delete-region armor-start armor-end)
+              (goto-char armor-start)
+              (current-buffer))))
+
+         (push (list armor-start (- (point-max) after-end))
+               decrypts)))
+
+      (when (and decrypts (rmail-buffers-swapped-p))
+       (when (y-or-n-p "Replace the original message? ")
+         (setq decrypts (nreverse decrypts))
+         (let ((beg (rmail-msgbeg rmail-current-message))
+               (end (rmail-msgend rmail-current-message))
+               (from-buffer (current-buffer)))
+           (with-current-buffer rmail-view-buffer
+             (narrow-to-region beg end)
+             (goto-char (point-min))
+             (dolist (d decrypts)
+               (if (re-search-forward "-----BEGIN PGP MESSAGE-----$" nil t)
+                   (let (armor-start armor-end)
+                     (setq armor-start (match-beginning 0)
+                           armor-end (re-search-forward "^-----END PGP MESSAGE-----$"
+                                                        nil t))
+                     (when armor-end
+                       (delete-region armor-start armor-end)
+                       (insert-buffer-substring from-buffer (nth 0 d) (nth 1 d)))))))))))))
+\f
 ;;;;  Desktop support
 
 (defun rmail-restore-desktop-buffer (desktop-buffer-file-name
 ;;;;  Desktop support
 
 (defun rmail-restore-desktop-buffer (desktop-buffer-file-name
@@ -4261,7 +4449,7 @@ encoded string (and the same mask) will decode the string."
 ;;; Start of automatically extracted autoloads.
 \f
 ;;;### (autoloads (rmail-edit-current-message) "rmailedit" "rmailedit.el"
 ;;; Start of automatically extracted autoloads.
 \f
 ;;;### (autoloads (rmail-edit-current-message) "rmailedit" "rmailedit.el"
-;;;;;;  "090ad9432c3bf9a6098bb9c3d7c71baf")
+;;;;;;  "7f9bff22ed0bbac561c97fd1e3ab503d")
 ;;; Generated autoloads from rmailedit.el
 
 (autoload 'rmail-edit-current-message "rmailedit" "\
 ;;; Generated autoloads from rmailedit.el
 
 (autoload 'rmail-edit-current-message "rmailedit" "\
@@ -4316,28 +4504,29 @@ With prefix argument N moves forward N messages with these labels.
 
 ;;;***
 \f
 
 ;;;***
 \f
-;;;### (autoloads (rmail-mime) "rmailmm" "rmailmm.el" "04902da045706fb7f2b0915529ed161b")
+;;;### (autoloads (rmail-mime) "rmailmm" "rmailmm.el" "3aa9747bf925bd2cd450f4b1f9c7cd03")
 ;;; Generated autoloads from rmailmm.el
 
 (autoload 'rmail-mime "rmailmm" "\
 ;;; Generated autoloads from rmailmm.el
 
 (autoload 'rmail-mime "rmailmm" "\
-Toggle displaying of a MIME message.
-
-The actualy behavior depends on the value of `rmail-enable-mime'.
+Toggle the display of a MIME message.
 
 
-If `rmail-enable-mime' is t (default), this command change the
-displaying of a MIME message between decoded presentation form
-and raw data.
+The actual behavior depends on the value of `rmail-enable-mime'.
 
 
-With ARG, toggle the displaying of the current MIME entity only.
+If `rmail-enable-mime' is non-nil (the default), this command toggles
+the display of a MIME message between decoded presentation form and
+raw data.  With optional prefix argument ARG, it toggles the display only
+of the MIME entity at point, if there is one.  The optional argument
+STATE forces a particular display state, rather than toggling.
+`raw' forces raw mode, any other non-nil value forces decoded mode.
 
 
-If `rmail-enable-mime' is nil, this creates a temporary
-\"*RMAIL*\" buffer holding a decoded copy of the message.  Inline
-content-types are handled according to
-`rmail-mime-media-type-handlers-alist'.  By default, this
-displays text and multipart messages, and offers to download
-attachments as specfied by `rmail-mime-attachment-dirs-alist'.
+If `rmail-enable-mime' is nil, this creates a temporary \"*RMAIL*\"
+buffer holding a decoded copy of the message. Inline content-types are
+handled according to `rmail-mime-media-type-handlers-alist'.
+By default, this displays text and multipart messages, and offers to
+download attachments as specified by `rmail-mime-attachment-dirs-alist'.
+The arguments ARG and STATE have no effect in this case.
 
 
-\(fn &optional ARG)" t nil)
+\(fn &optional ARG STATE)" t nil)
 
 ;;;***
 \f
 
 ;;;***
 \f
@@ -4417,7 +4606,7 @@ If prefix argument REVERSE is non-nil, sorts in reverse order.
 \f
 ;;;### (autoloads (rmail-summary-by-senders rmail-summary-by-topic
 ;;;;;;  rmail-summary-by-regexp rmail-summary-by-recipients rmail-summary-by-labels
 \f
 ;;;### (autoloads (rmail-summary-by-senders rmail-summary-by-topic
 ;;;;;;  rmail-summary-by-regexp rmail-summary-by-recipients rmail-summary-by-labels
-;;;;;;  rmail-summary) "rmailsum" "rmailsum.el" "3817e21639db697abe5832d3223ecfc2")
+;;;;;;  rmail-summary) "rmailsum" "rmailsum.el" "1375d6512b953c0d7c3bde52192f4055")
 ;;; Generated autoloads from rmailsum.el
 
 (autoload 'rmail-summary "rmailsum" "\
 ;;; Generated autoloads from rmailsum.el
 
 (autoload 'rmail-summary "rmailsum" "\