]> code.delx.au - gnu-emacs/blobdiff - lisp/mail/rmail.el
(report-emacs-bug-text-prompt): New variable.
[gnu-emacs] / lisp / mail / rmail.el
index aae9af2bcafa33f96680c9c18bfcfdd1e055f83d..e6dd92671e170ff993370f9823d90dafec629eac 100644 (file)
@@ -1,4 +1,4 @@
-;;; rmail.el --- main code of "RMAIL" mail reader for Emacs.
+;;; rmail.el --- main code of "RMAIL" mail reader for Emacs
 
 ;; Copyright (C) 1985,86,87,88,93,94,95,96,97,98,2000, 2001
 ;;             Free Software Foundation, Inc.
@@ -23,6 +23,8 @@
 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 ;; Boston, MA 02111-1307, USA.
 
+;;; Commentary:
+
 ;;; Code:
 
 ;; Souped up by shane@mit-ajax based on ideas of rlk@athena.mit.edu
@@ -38,6 +40,7 @@
 ;;
 
 (require 'mail-utils)
+(eval-when-compile (require 'mule-util)) ; for detect-coding-with-priority
 
 ; These variables now declared in paths.el.
 ;(defvar rmail-spool-directory "/usr/spool/mail/"
@@ -129,8 +132,8 @@ rather than deleted, after it is retrieved."
 
 ;;;###autoload
 (defcustom rmail-dont-reply-to-names nil "\
-*A regexp specifying names to prune of reply to messages.
-A value of nil means exclude your own login name as an address
+*A regexp specifying addresses to prune from a reply message.
+A value of nil means exclude your own email address as an address
 plus whatever is specified by `rmail-default-dont-reply-to-names'."
   :type '(choice regexp (const :tag "Your Name" nil))
   :group 'rmail-reply)
@@ -140,7 +143,7 @@ plus whatever is specified by `rmail-default-dont-reply-to-names'."
 A regular expression specifying part of the value of the default value of
 the variable `rmail-dont-reply-to-names', for when the user does not set
 `rmail-dont-reply-to-names' explicitly.  (The other part of the default
-value is the user's name.)
+value is the user's email address and name.)
 It is useful to set this variable in the site customization file.")
 
 ;;;###autoload
@@ -312,7 +315,7 @@ examples:
   :group 'rmail
   :version "21.1"
   :type '(repeat (sexp :tag "Directive")))
-  
+
 (defvar rmail-reply-prefix "Re: "
   "String to prepend to Subject line when replying to a message.")
 
@@ -417,6 +420,9 @@ until a user explicitly requires it."
                 (other :tag "when asked" ask))
   :group 'rmail)
 
+(defvar rmail-enable-mime-composing nil
+  "*If non-nil, RMAIL uses `rmail-insert-mime-forwarded-message-function' to forward.")
+
 ;;;###autoload
 (defvar rmail-show-mime-function nil
   "Function to show MIME decoded message of RMAIL file.
@@ -426,6 +432,15 @@ It is called with no argument.")
 ;;;###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.
+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.")
+
+;;;###autoload
+(defvar rmail-insert-mime-resent-message-function nil
+  "Function to insert a message in MIME format so it can be resent.
 This function is called if `rmail-enable-mime' is non-nil.
 It is called with one argument FORWARD-BUFFER, which is a
 buffer containing the message to forward.  The current buffer
@@ -531,7 +546,7 @@ The first parenthesized expression should match the MIME-charset name.")
     (let* ((cite-chars "[>|}]")
           (cite-prefix "A-Za-z")
           (cite-suffix (concat cite-prefix "0-9_.@-`'\"")))
-      (list '("^\\(From\\|Sender\\):" . font-lock-function-name-face)
+      (list '("^\\(From\\|Sender\\|Resent-[Ff]rom\\):" . font-lock-function-name-face)
            '("^Reply-To:.*$" . font-lock-function-name-face)
            '("^Subject:" . font-lock-comment-face)
            '("^\\(To\\|Apparently-To\\|Cc\\|Newsgroups\\):"
@@ -574,8 +589,25 @@ The first parenthesized expression should match the MIME-charset name.")
 \f
 ;;;; *** Rmail Mode ***
 
+;; This variable is dynamically bound.  The defvar is here to placate
+;; the byte compiler.
+
 (defvar rmail-enable-multibyte nil)
 
+
+(defun rmail-require-mime-maybe ()
+  "Require `rmail-mime-feature' if that is non-nil.
+Signal an error and set `rmail-mime-feature' to nil if the feature
+isn't provided."
+  (when rmail-enable-mime
+    (condition-case err
+       (require rmail-mime-feature)
+      (error
+       (message "Feature `%s' not provided" rmail-mime-feature)
+       (sit-for 1)
+       (setq rmail-enable-mime nil)))))
+
+
 ;;;###autoload
 (defun rmail (&optional file-name-arg)
   "Read and edit incoming mail.
@@ -591,19 +623,16 @@ have a chance to specify a file name with the minibuffer.
 If `rmail-display-summary' is non-nil, make a summary for this RMAIL file."
   (interactive (if current-prefix-arg
                   (list (read-file-name "Run rmail on RMAIL file: "))))
-  (if rmail-enable-mime
-      (condition-case err
-         (require rmail-mime-feature)
-       (error (message "Feature `%s' not provided" rmail-mime-feature)
-              (sit-for 1)
-              (setq rmail-enable-mime nil))))
+  (rmail-require-mime-maybe)
   (let* ((file-name (expand-file-name (or file-name-arg rmail-file-name)))
-        (existed (get-file-buffer file-name))
-        ;; This binding is necessary because we much decide if we
+        ;; Use find-buffer-visiting, not get-file-buffer, for those users
+        ;; who have find-file-visit-truename set to t.
+        (existed (find-buffer-visiting file-name))
+        ;; This binding is necessary because we must decide if we
         ;; need code conversion while the buffer is unibyte
         ;; (i.e. enable-multibyte-characters is nil).
          (rmail-enable-multibyte
-          (if existed 
+          (if existed
              (with-current-buffer existed enable-multibyte-characters)
             (default-value 'enable-multibyte-characters)))
         ;; Since the file may contain messages of different encodings
@@ -628,7 +657,7 @@ If `rmail-display-summary' is non-nil, make a summary for this RMAIL file."
                   (eq major-mode 'rmail-mode))
              (progn (rmail-forget-messages)
                     (rmail-set-message-counters))))
-      (switch-to-buffer 
+      (switch-to-buffer
        (let ((enable-local-variables nil))
         (find-file-noselect file-name))))
     (if (eq major-mode 'rmail-edit-mode)
@@ -750,11 +779,21 @@ Note:    it means the file has no messages in it.\n\^_")))
     (setq to (point))
     (unless (and coding-system
                 (coding-system-p coding-system))
-      (setq coding-system (detect-coding-region from to t)))
+      (setq coding-system
+           ;; Emacs 21.1 and later writes RMAIL files in emacs-mule, but
+           ;; earlier versions did that with the current buffer's encoding.
+           ;; So we want to favor detection of emacs-mule (whose normal
+           ;; priority is quite low), but still allow detection of other
+           ;; encodings if emacs-mule won't fit.  The call to
+           ;; detect-coding-with-priority below achieves that.
+           (car (detect-coding-with-priority
+                 from to
+                 '((coding-category-emacs-mule . emacs-mule))))))
     (unless (memq coding-system
                  '(undecided undecided-unix))
       (set-buffer-modified-p t)                ; avoid locking when decoding
-      (decode-coding-region from to coding-system)
+      (let ((buffer-undo-list t))
+       (decode-coding-region from to coding-system))
       (setq coding-system last-coding-system-used))
     (set-buffer-modified-p modifiedp)
     (setq buffer-file-coding-system nil)
@@ -993,10 +1032,23 @@ Instead, these commands are available:
 \\[rmail-summary-by-topic]   Summarize only messages with subject line regexp(s).
 \\[rmail-toggle-header]        Toggle display of complete header."
   (interactive)
-  (rmail-mode-2)
-  (rmail-set-message-counters)
-  (rmail-show-message rmail-total-messages)
-  (run-hooks 'rmail-mode-hook))
+  (let ((finding-rmail-file (not (eq major-mode 'rmail-mode))))
+    (rmail-mode-2)
+    (when (and finding-rmail-file
+              (null coding-system-for-read)
+              default-enable-multibyte-characters)
+      (let ((rmail-enable-multibyte t))
+       (rmail-require-mime-maybe)
+       (rmail-convert-file)
+       (goto-char (point-max))
+       (set-buffer-multibyte t)))
+    (rmail-set-message-counters)
+    (rmail-show-message rmail-total-messages)
+    (when finding-rmail-file
+      (when rmail-display-summary
+       (rmail-summary))
+      (rmail-construct-io-menu))
+    (run-hooks 'rmail-mode-hook)))
 
 (defun rmail-mode-2 ()
   (kill-all-local-variables)
@@ -1085,6 +1137,7 @@ Instead, these commands are available:
 
 ;; Handle M-x revert-buffer done in an rmail-mode buffer.
 (defun rmail-revert (arg noconfirm)
+  (set-buffer rmail-buffer)
   (let* ((revert-buffer-function (default-value 'revert-buffer-function))
         (rmail-enable-multibyte enable-multibyte-characters)
         ;; See similar code in `rmail'.
@@ -1094,7 +1147,8 @@ Instead, these commands are available:
        ;; If the user said "yes", and we changed something,
        ;; reparse the messages.
        (progn
-         (rmail-mode-2)
+         (set-buffer rmail-buffer)
+         (rmail-mode-2)
          ;; Convert all or part to Babyl file if possible.
          (rmail-convert-file)
          ;; We have read the file as raw-text, so the buffer is set to
@@ -1215,8 +1269,8 @@ original copy."
                   (if (consp item)
                       (progn
                         (setq command
-                              (rmail-list-to-menu (car item) (cdr item) 
-                                                  action 
+                              (rmail-list-to-menu (car item) (cdr item)
+                                                  action
                                                   (if full-name
                                                       (concat full-name "/"
                                                               (car item))
@@ -1224,10 +1278,10 @@ original copy."
                         (setq name (car item)))
                     (progn
                       (setq name item)
-                      (setq command 
+                      (setq command
                             (list 'lambda () '(interactive)
                                   (list action
-                                        (expand-file-name 
+                                        (expand-file-name
                                          (if full-name
                                              (concat full-name "/" item)
                                            item)
@@ -1236,7 +1290,7 @@ original copy."
                     (cons name command)))))
      (reverse l))
     menu))
+
 ;; This command is always "disabled" when it appears in a menu.
 (put 'rmail-disable-menu 'menu-enable ''nil)
 
@@ -1245,13 +1299,13 @@ original copy."
     (if files
        (progn
          (define-key rmail-mode-map [menu-bar classify input-menu]
-           (cons "Input Rmail File" 
-                 (rmail-list-to-menu "Input Rmail File" 
+           (cons "Input Rmail File"
+                 (rmail-list-to-menu "Input Rmail File"
                                      files
                                      'rmail-input)))
          (define-key rmail-mode-map [menu-bar classify output-menu]
-           (cons "Output Rmail File" 
-                 (rmail-list-to-menu "Output Rmail File" 
+           (cons "Output Rmail File"
+                 (rmail-list-to-menu "Output Rmail File"
                                      files
                                      'rmail-output-to-rmail-file))))
 
@@ -1494,13 +1548,13 @@ It returns t if it got any new messages."
                   (save-excursion
                     (setq errors (generate-new-buffer " *rmail loss*"))
                     (buffer-disable-undo errors)
-                    (let ((args 
-                           (append 
+                    (let ((args
+                           (append
                             (list (or rmail-movemail-program
                                       (expand-file-name "movemail"
                                                         exec-directory))
                                   nil errors nil)
-                            (if rmail-preserve-inbox 
+                            (if rmail-preserve-inbox
                                 (list "-p")
                               nil)
                             rmail-movemail-flags
@@ -1815,7 +1869,7 @@ It returns t if it got any new messages."
                      ""
                    (concat
                     "Date: \\2, \\4 \\3 \\9 \\5 "
-                   
+
                     ;; The timezone could be matched by group 7 or group 10.
                     ;; If neither of them matched, assume EST, since only
                     ;; Easterners would be so sloppy.
@@ -1840,8 +1894,8 @@ It returns t if it got any new messages."
   (goto-char beg)
   (forward-line 1)
   (if (/= (following-char) ?0)
-      (error "Bad format in RMAIL file."))
-  (let ((buffer-read-only nil)
+      (error "Bad format in RMAIL file"))
+  (let ((inhibit-read-only t)
        (delta (- (buffer-size) end)))
     (delete-char 1)
     (insert ?1)
@@ -1911,80 +1965,121 @@ Otherwise, delete all header fields whose names match `rmail-ignored-headers'."
       (forward-line 1)
       (= (following-char) ?1))))
 
+(defun rmail-msg-restore-non-pruned-header ()
+  (let ((old-point (point))
+       new-point
+       new-start
+       (inhibit-read-only t))
+    (save-excursion
+      (narrow-to-region (rmail-msgbeg rmail-current-message) (point-max))
+      (goto-char (point-min))
+      (forward-line 1)
+      ;; Change 1 to 0.
+      (delete-char 1)
+      (insert ?0)
+      ;; Insert new EOOH line at the proper place.
+      (forward-line 1)
+      (let ((case-fold-search t))
+       (while (looking-at "Summary-Line:\\|Mail-From:")
+         (forward-line 1)))
+      (insert "*** EOOH ***\n")
+      (setq new-start (point))
+      ;; Delete the old reformatted header.
+      (forward-char -1)
+      (search-forward "\n*** EOOH ***\n")
+      (forward-line -1)
+      (let ((start (point)))
+       (search-forward "\n\n")
+       (if (and (<= start old-point)
+                (<= old-point (point)))
+           (setq new-point new-start))
+       (delete-region start (point)))
+      ;; Narrow to after the new EOOH line.
+      (narrow-to-region new-start (point-max)))
+    (if new-point
+       (goto-char new-point))))
+
+(defun rmail-msg-prune-header ()
+  (let ((new-point
+        (= (point) (point-min))))
+    (save-excursion
+      (narrow-to-region (rmail-msgbeg rmail-current-message) (point-max))
+      (rmail-reformat-message (point-min) (point-max)))
+    (if new-point
+       (goto-char (point-min)))))
+
 (defun rmail-toggle-header (&optional arg)
   "Show original message header if pruned header currently shown, or vice versa.
 With argument ARG, show the message header pruned if ARG is greater than zero;
 otherwise, show it in full."
   (interactive "P")
-  (switch-to-buffer rmail-buffer)
-  (let* ((buffer-read-only nil)
-        (pruned (rmail-msg-is-pruned))
+  (let* ((pruned (with-current-buffer rmail-buffer
+                  (rmail-msg-is-pruned)))
         (prune (if arg
                    (> (prefix-numeric-value arg) 0)
                  (not pruned))))
     (if (eq pruned prune)
        t
+      (set-buffer rmail-buffer)
       (rmail-maybe-set-message-counters)
-      (let* ((window (get-buffer-window (current-buffer)))
-            (at-point-min (= (point) (point-min)))
-            (all-headers-visible (= (window-start window) (point-min)))
-            (on-header (save-excursion
-                         (and (not (search-backward "\n\n" nil t))
-                              (progn
-                                (end-of-line)
-                                (re-search-backward "^[-A-Za-z0-9]+:" nil t))
-                              (match-string 0))))
-            (old-screen-line
-             (rmail-count-screen-lines (window-start window) (point))))
-        (save-excursion
-         (narrow-to-region (rmail-msgbeg rmail-current-message) (point-max))
+      (if rmail-enable-mime
+         (let ((buffer-read-only nil))
+           (if pruned
+               (rmail-msg-restore-non-pruned-header)
+             (rmail-msg-prune-header))
+           (funcall rmail-show-mime-function))
+       (let* ((buffer-read-only nil)
+              (window (get-buffer-window (current-buffer)))
+              (at-point-min (= (point) (point-min)))
+              (all-headers-visible (= (window-start window) (point-min)))
+              (on-header
+               (save-excursion
+                 (and (not (search-backward "\n\n" nil t))
+                      (progn
+                        (end-of-line)
+                        (re-search-backward "^[-A-Za-z0-9]+:" nil t))
+                      (match-string 0))))
+              (old-screen-line
+               (rmail-count-screen-lines (window-start window) (point))))
          (if pruned
-             (let (new-start)
-               (goto-char (point-min))
-               (forward-line 1)
-               ;; Change 1 to 0.
-               (delete-char 1)
-               (insert ?0)
-               ;; Insert new EOOH line at the proper place.
-               (forward-line 1)
-               (let ((case-fold-search t))
-                 (while (looking-at "Summary-Line:\\|Mail-From:")
-                   (forward-line 1)))
-               (insert "*** EOOH ***\n")
-               (setq new-start (point))
-               ;; Delete the old reformatted header.
-               (forward-char -1)
-               (search-forward "\n*** EOOH ***\n")
-               (forward-line -1)
-               (let ((start (point)))
-                 (search-forward "\n\n")
-                 (delete-region start (point)))
-               ;; Narrow to after the new EOOH line.
-               (narrow-to-region new-start (point-max)))
-           (rmail-reformat-message (point-min) (point-max))))
-       (cond (rmail-enable-mime
-              (funcall rmail-show-mime-function))
-             (at-point-min
-              (goto-char (point-min)))
-             (on-header
-              (goto-char (point-min))
-              (search-forward "\n\n")
-              (or (re-search-backward (concat "^" (regexp-quote on-header)) nil t)
-                  (goto-char (point-min))))
-             (t
-              (save-selected-window
-                (select-window window)
-                (recenter old-screen-line)
-                (if (and all-headers-visible
-                         (not (= (window-start) (point-min))))
-                    (let ((lines-offscreen (rmail-count-screen-lines
-                                            (point-min)
-                                            (window-start window))))
-                      (recenter (min (+ old-screen-line lines-offscreen)
-                                     ;; last line of window
-                                     (- (window-height) 2)))))))))
+             (rmail-msg-restore-non-pruned-header)
+           (rmail-msg-prune-header))
+         (cond (at-point-min
+                (goto-char (point-min)))
+               (on-header
+                (goto-char (point-min))
+                (search-forward "\n\n")
+                (or (re-search-backward
+                     (concat "^" (regexp-quote on-header)) nil t)
+                    (goto-char (point-min))))
+               (t
+                (save-selected-window
+                  (select-window window)
+                  (recenter old-screen-line)
+                  (if (and all-headers-visible
+                           (not (= (window-start) (point-min))))
+                      (recenter (- (window-height) 2))))))))
       (rmail-highlight-headers))))
 
+(defun rmail-narrow-to-non-pruned-header ()
+  "Narrow to the whole (original) header of the current message."
+  (let (start end)
+    (narrow-to-region (rmail-msgbeg rmail-current-message) (point-max))
+    (goto-char (point-min))
+    (forward-line 1)
+    (if (= (following-char) ?1)
+       (progn
+         (forward-line 1)
+         (setq start (point))
+         (search-forward "*** EOOH ***\n")
+         (setq end (match-beginning 0)))
+      (forward-line 2)
+      (setq start (point))
+      (search-forward "\n\n")
+      (setq end (1- (point))))
+    (narrow-to-region start end)
+    (goto-char start)))
+
 ;; Lifted from repos-count-screen-lines.
 ;; Return number of screen lines between START and END.
 (defun rmail-count-screen-lines (start end)
@@ -2217,7 +2312,7 @@ change the invisible header text."
            (aset rmail-msgref-vector i (list i))
            (setq i (1+ i))))
        (message "Counting messages...done")))))
-       
+
 (defun rmail-set-message-counters-counter (&optional stop)
   (let ((start (point))
        next)
@@ -2296,8 +2391,12 @@ If summary buffer is currently displayed, update current message there also."
              (goto-char (point-min))
              (if (re-search-forward "^X-Coding-System: *\\(.*\\)$" nil t)
                  (let ((coding-system (intern (match-string 1))))
-                   (check-coding-system coding-system)
-                   (setq buffer-file-coding-system coding-system))
+                   (condition-case nil
+                       (progn
+                         (check-coding-system coding-system)
+                         (setq buffer-file-coding-system coding-system))
+                     (error 
+                      (setq buffer-file-coding-system nil))))
                (setq buffer-file-coding-system nil)))))
        ;; Clear the "unseen" attribute when we show a message.
        (rmail-set-attribute "unseen" nil)
@@ -2308,6 +2407,11 @@ If summary buffer is currently displayed, update current message there also."
            (search-forward "\n*** EOOH ***\n" end t)
            (narrow-to-region (point) end)))
        (goto-char (point-min))
+       (walk-windows
+        (function (lambda (window)
+                    (if (eq (window-buffer window) (current-buffer))
+                        (set-window-point window (point)))))
+        nil t)
        (rmail-display-labels)
        (if (eq rmail-enable-mime t)
            (funcall rmail-show-mime-function)
@@ -2351,43 +2455,51 @@ iso-8859, koi8-r, etc."
     (or (eq major-mode 'rmail-mode)
        (switch-to-buffer rmail-buffer))
     (save-excursion
-      (unwind-protect
-         (let ((msgbeg (rmail-msgbeg rmail-current-message))
-               (msgend (rmail-msgend rmail-current-message))
-               x-coding-header)
-           (narrow-to-region msgbeg msgend)
-           (goto-char (point-min))
-           (when (search-forward "\n*** EOOH ***\n" (point-max) t)
-             (narrow-to-region msgbeg (point)))
-           (goto-char (point-min))
-           (if (re-search-forward "^X-Coding-System: *\\(.*\\)$" nil t)
-               (let ((old-coding (intern (match-string 1)))
-                     (buffer-read-only nil))
-                 (check-coding-system old-coding)
-                 ;; Make sure the new coding system uses the same EOL
-                 ;; conversion, to prevent ^M characters from popping
-                 ;; up all over the place.
-                 (setq coding
-                       (coding-system-change-eol-conversion
-                        coding
-                        (coding-system-eol-type old-coding)))
-                 (setq x-coding-header (point-marker))
-                 (narrow-to-region msgbeg msgend)
-                 (encode-coding-region (point) msgend old-coding)
-                 (decode-coding-region (point) msgend coding)
-                 (setq last-coding-system-used coding)
-                 ;; Rewrite the coding-system header according
-                 ;; to what we did.
-                 (goto-char x-coding-header)
-                 (delete-region (point)
-                                (save-excursion
-                                  (beginning-of-line)
-                                  (point)))
-                 (insert "X-Coding-System: "
-                         (symbol-name last-coding-system-used))
-                 (set-marker x-coding-header nil)
-                 (rmail-show-message))
-             (error "No X-Coding-System header found")))))))
+      (let ((pruned (rmail-msg-is-pruned)))
+       (unwind-protect
+           (let ((msgbeg (rmail-msgbeg rmail-current-message))
+                 (msgend (rmail-msgend rmail-current-message))
+                 x-coding-header)
+             ;; We need the message headers pruned (we later restore
+             ;; the pruned stat to what it was, see the end of
+             ;; unwind-protect form).
+             (or pruned
+                 (rmail-toggle-header 1))
+             (narrow-to-region msgbeg msgend)
+             (goto-char (point-min))
+             (when (search-forward "\n*** EOOH ***\n" (point-max) t)
+               (narrow-to-region msgbeg (point)))
+             (goto-char (point-min))
+             (if (re-search-forward "^X-Coding-System: *\\(.*\\)$" nil t)
+                 (let ((old-coding (intern (match-string 1)))
+                       (buffer-read-only nil))
+                   (check-coding-system old-coding)
+                   ;; Make sure the new coding system uses the same EOL
+                   ;; conversion, to prevent ^M characters from popping
+                   ;; up all over the place.
+                   (setq coding
+                         (coding-system-change-eol-conversion
+                          coding
+                          (coding-system-eol-type old-coding)))
+                   (setq x-coding-header (point-marker))
+                   (narrow-to-region msgbeg msgend)
+                   (encode-coding-region (point) msgend old-coding)
+                   (decode-coding-region (point) msgend coding)
+                   (setq last-coding-system-used coding)
+                   ;; Rewrite the coding-system header according
+                   ;; to what we did.
+                   (goto-char x-coding-header)
+                   (delete-region (point)
+                                  (save-excursion
+                                    (beginning-of-line)
+                                    (point)))
+                   (insert "X-Coding-System: "
+                           (symbol-name last-coding-system-used))
+                   (set-marker x-coding-header nil)
+                   (rmail-show-message))
+               (error "No X-Coding-System header found")))
+         (or pruned
+             (rmail-toggle-header 0)))))))
 
 ;; Find all occurrences of certain fields, and highlight them.
 (defun rmail-highlight-headers ()
@@ -2480,7 +2592,7 @@ With prefix arg N, moves forward N messages, or backward if N is negative."
   "Show previous message whether deleted or not.
 With prefix arg N, moves backward N messages, or forward if N is negative."
   (interactive "p")
-  (rmail-next-message (- n)))  
+  (rmail-next-message (- n)))
 
 (defun rmail-next-undeleted-message (n)
   "Show following non-deleted message.
@@ -2567,7 +2679,7 @@ or forward if N is negative."
                (forward-line 1))
              (setq beg (point))
              (narrow-to-region (point) end))
-           (progn 
+           (progn
              (rfc822-goto-eoh)
              (setq end (point)))
          (setq beg (point))
@@ -2972,11 +3084,12 @@ use \\[mail-yank-original] to yank the original message into it."
             (msgnum rmail-current-message))
     (save-excursion
       (save-restriction
-       ;; If rmail-enable-mime is non-nil, we are in a
-       ;; rmail-view-buffer which doesn't contain any lines specific
-       ;; to BABYL format (e.g. "*** EOOH ***").  Thus, there's no
-       ;; need of narrowing in such a case.
-       (unless rmail-enable-mime
+       (if rmail-enable-mime
+           (narrow-to-region
+            (goto-char (point-min))
+            (if (search-forward "\n\n" nil 'move)
+                (1+ (match-beginning 0))
+              (point)))
          (widen)
          (goto-char (rmail-msgbeg rmail-current-message))
          (forward-line 1)
@@ -3154,7 +3267,7 @@ see the documentation of `rmail-resend'."
          (save-excursion
            ;; Insert after header separator--before signature if any.
            (goto-char (mail-text-start))
-           (if rmail-enable-mime
+           (if (or rmail-enable-mime rmail-enable-mime-composing)
                (funcall rmail-insert-mime-forwarded-message-function
                         forward-buffer)
              (insert "------- Start of forwarded message -------\n")
@@ -3190,7 +3303,8 @@ typically for purposes of moderating a list."
   (interactive "sResend to: ")
   (require 'sendmail)
   (require 'mailalias)
-  (unless (eq rmail-buffer (current-buffer))
+  (unless (or (eq rmail-view-buffer (current-buffer))
+             (eq rmail-buffer (current-buffer)))
     (error "Not an Rmail buffer"))
   (if (not from) (setq from user-mail-address))
   (let ((tembuf (generate-new-buffer " sendmail temp"))
@@ -3199,7 +3313,9 @@ typically for purposes of moderating a list."
     (unwind-protect
        (with-current-buffer tembuf
          ;;>> Copy message into temp buffer
-         (insert-buffer-substring mailbuf)
+         (if rmail-enable-mime
+             (funcall rmail-insert-mime-resent-message-function mailbuf)
+           (insert-buffer-substring mailbuf))
          (goto-char (point-min))
          ;; Delete any Sender field, since that's not specifiable.
          ; Only delete Sender fields in the actual header.
@@ -3236,6 +3352,8 @@ typically for purposes of moderating a list."
                    (if (and (not (vectorp mail-abbrevs))
                             (file-exists-p mail-personal-alias-file))
                        (build-mail-abbrevs))
+                   (unless mail-abbrev-syntax-table
+                     (mail-abbrev-make-syntax-table))
                    (set-syntax-table mail-abbrev-syntax-table)
                    (goto-char before)
                    (while (and (< (point) end)
@@ -3294,112 +3412,103 @@ specifying headers which should not be copied into the new message."
   (require 'mail-utils)
   (let ((rmail-this-buffer (current-buffer))
        (msgnum rmail-current-message)
-       (pruned (rmail-msg-is-pruned))
-       bounce-start bounce-end bounce-indent resending)
-    (unwind-protect
-       (progn
-         (save-excursion
-           ;; Un-prune the header; we need to search the whole thing.
-           (if pruned
-               (rmail-toggle-header 0))
-           (goto-char (rmail-msgbeg msgnum))
-           (let* ((case-fold-search t)
-                  (top (point))
-                  (content-type
-                   (save-restriction
-                     ;; Fetch any content-type header in current message
-                     (search-forward "\n\n") (narrow-to-region top (point))
-                     (mail-fetch-field "Content-Type") )) )
-             ;; Handle MIME multipart bounce messages
-             (if (and content-type 
-                      (string-match 
-                       ";[\n\t ]*boundary=\"?\\([-0-9a-z'()+_,./:=? ]+\\)\"?" 
-                       content-type))
-                 (let ((codestring
-                        (concat "\n--"
-                                (substring content-type (match-beginning 1) 
-                                           (match-end 1)))))
-                   (unless (re-search-forward mail-mime-unsent-header nil t)
-                     (error "Cannot find beginning of header in failed message"))
-                   (unless (search-forward "\n\n" nil t)
-                     (error "Cannot find start of Mime data in failed message"))
-                   (setq bounce-start (point))
-                   (if (search-forward codestring nil t)
-                       (setq bounce-end (match-beginning 0))
-                     (setq bounce-end (point-max)))
-                   )
-               ;; non-MIME bounce
-               (or (re-search-forward mail-unsent-separator nil t)
-                   (error "Cannot parse this as a failure message"))
-               (skip-chars-forward "\n")
-               ;; Support a style of failure message in which the original
-               ;; message is indented, and included within lines saying
-               ;; `Start of returned message' and `End of returned message'.
-               (if (looking-at " +Received:")
-                   (progn
-                     (setq bounce-start (point))
-                     (skip-chars-forward " ")
-                     (setq bounce-indent (- (current-column)))
-                     (goto-char (point-max))
-                     (re-search-backward "^End of returned message$" nil t)
-                     (setq bounce-end (point)))
-                 ;; One message contained a few random lines before
-                 ;; the old message header.  The first line of the
-                 ;; message started with two hyphens.  A blank line
-                 ;; followed these random lines.  The same line
-                 ;; beginning with two hyphens was possibly marking
-                 ;; the end of the message.
-                 (if (looking-at "^--")
-                     (let ((boundary (buffer-substring-no-properties
-                                      (point)
-                                      (progn (end-of-line) (point)))))
-                       (search-forward "\n\n")
-                       (skip-chars-forward "\n")
-                       (setq bounce-start (point))
-                       (goto-char (point-max))
-                       (search-backward (concat "\n\n" boundary) bounce-start t)
-                       (setq bounce-end (point)))
-                   (setq bounce-start (point)
-                         bounce-end (point-max)))
-                 (unless (search-forward "\n\n" nil t)
-                   (error "Cannot find end of header in failed message"))
-                 ))))
-         ;; Start sending new message; default header fields from original.
-         ;; Turn off the usual actions for initializing the message body
-         ;; because we want to get only the text from the failure message.
-         (let (mail-signature mail-setup-hook)
-           (if (rmail-start-mail nil nil nil nil nil rmail-this-buffer
-                                 (list (list 'rmail-mark-message
-                                             rmail-this-buffer
-                                             (aref rmail-msgref-vector msgnum)
-                                             "retried")))
-               ;; Insert original text as initial text of new draft message.
-               ;; Bind inhibit-read-only since the header delimiter
-               ;; of the previous message was probably read-only.
-               (let ((inhibit-read-only t)
-                     rmail-displayed-headers
-                     rmail-ignored-headers)
-                 (erase-buffer)
-                 (insert-buffer-substring rmail-this-buffer
-                                          bounce-start bounce-end)
-                 (goto-char (point-min))
-                 (if bounce-indent
-                     (indent-rigidly (point-min) (point-max) bounce-indent))
-                 (rmail-clear-headers rmail-retry-ignored-headers)
-                 (rmail-clear-headers "^sender:\\|^return-path:\\|^received:")
-                 (mail-sendmail-delimit-header)
-                 (save-restriction
-                   (narrow-to-region (point-min) (mail-header-end))
-                   (setq resending (mail-fetch-field "resent-to"))
-                   (if mail-self-blind
-                       (if resending
-                           (insert "Resent-Bcc: " (user-login-name) "\n")
-                         (insert "BCC: " (user-login-name) "\n"))))
-                 (goto-char (point-min))
-                 (mail-position-on-field (if resending "Resent-To" "To") t)))))
-      (with-current-buffer rmail-this-buffer
-       (if pruned
-           (rmail-toggle-header 1))))))
+       bounce-start bounce-end bounce-indent resending
+       ;; Fetch any content-type header in current message
+       ;; Must search thru the whole unpruned header.
+       (content-type
+        (save-excursion
+          (save-restriction
+            (rmail-narrow-to-non-pruned-header)
+            (mail-fetch-field "Content-Type") ))))
+    (save-excursion
+      (goto-char (point-min))
+      (let ((case-fold-search t))
+       (if (and content-type
+                (string-match
+                 ";[\n\t ]*boundary=\"?\\([-0-9a-z'()+_,./:=? ]+\\)\"?"
+                 content-type))
+           ;; Handle a MIME multipart bounce message.
+           (let ((codestring
+                  (concat "\n--"
+                          (substring content-type (match-beginning 1)
+                                     (match-end 1)))))
+             (unless (re-search-forward mail-mime-unsent-header nil t)
+               (error "Cannot find beginning of header in failed message"))
+             (unless (search-forward "\n\n" nil t)
+               (error "Cannot find start of Mime data in failed message"))
+             (setq bounce-start (point))
+             (if (search-forward codestring nil t)
+                 (setq bounce-end (match-beginning 0))
+               (setq bounce-end (point-max))))
+         ;; Non-MIME bounce.
+         (or (re-search-forward mail-unsent-separator nil t)
+             (error "Cannot parse this as a failure message"))
+         (skip-chars-forward "\n")
+         ;; Support a style of failure message in which the original
+         ;; message is indented, and included within lines saying
+         ;; `Start of returned message' and `End of returned message'.
+         (if (looking-at " +Received:")
+             (progn
+               (setq bounce-start (point))
+               (skip-chars-forward " ")
+               (setq bounce-indent (- (current-column)))
+               (goto-char (point-max))
+               (re-search-backward "^End of returned message$" nil t)
+               (setq bounce-end (point)))
+           ;; One message contained a few random lines before
+           ;; the old message header.  The first line of the
+           ;; message started with two hyphens.  A blank line
+           ;; followed these random lines.  The same line
+           ;; beginning with two hyphens was possibly marking
+           ;; the end of the message.
+           (if (looking-at "^--")
+               (let ((boundary (buffer-substring-no-properties
+                                (point)
+                                (progn (end-of-line) (point)))))
+                 (search-forward "\n\n")
+                 (skip-chars-forward "\n")
+                 (setq bounce-start (point))
+                 (goto-char (point-max))
+                 (search-backward (concat "\n\n" boundary) bounce-start t)
+                 (setq bounce-end (point)))
+             (setq bounce-start (point)
+                   bounce-end (point-max)))
+           (unless (search-forward "\n\n" nil t)
+             (error "Cannot find end of header in failed message"))))))
+    ;; We have found the message that bounced, within the current message.
+    ;; Now start sending new message; default header fields from original.
+    ;; Turn off the usual actions for initializing the message body
+    ;; because we want to get only the text from the failure message.
+    (let (mail-signature mail-setup-hook)
+      (if (rmail-start-mail nil nil nil nil nil rmail-this-buffer
+                           (list (list 'rmail-mark-message
+                                       rmail-this-buffer
+                                       (aref rmail-msgref-vector msgnum)
+                                       "retried")))
+         ;; Insert original text as initial text of new draft message.
+         ;; Bind inhibit-read-only since the header delimiter
+         ;; of the previous message was probably read-only.
+         (let ((inhibit-read-only t)
+               rmail-displayed-headers
+               rmail-ignored-headers)
+           (erase-buffer)
+           (insert-buffer-substring rmail-this-buffer
+                                    bounce-start bounce-end)
+           (goto-char (point-min))
+           (if bounce-indent
+               (indent-rigidly (point-min) (point-max) bounce-indent))
+           (rmail-clear-headers rmail-retry-ignored-headers)
+           (rmail-clear-headers "^sender:\\|^return-path:\\|^received:")
+           (mail-sendmail-delimit-header)
+           (save-restriction
+             (narrow-to-region (point-min) (mail-header-end))
+             (setq resending (mail-fetch-field "resent-to"))
+             (if mail-self-blind
+                 (if resending
+                     (insert "Resent-Bcc: " (user-login-name) "\n")
+                   (insert "BCC: " (user-login-name) "\n"))))
+           (goto-char (point-min))
+           (mail-position-on-field (if resending "Resent-To" "To") t))))))
 \f
 (defun rmail-summary-exists ()
   "Non-nil iff in an RMAIL buffer and an associated summary buffer exists.
@@ -3442,7 +3551,7 @@ This has an effect only if a summary buffer exists."
         (setq window (get-buffer-window rmail-summary-buffer))
         ;; Don't try to change the size if just one window in frame.
         (not (eq window (frame-root-window (window-frame window))))
-        (unwind-protect 
+        (unwind-protect
             (progn
               (select-window window)
               (enlarge-window (- rmail-summary-window-size (window-height))))
@@ -3452,7 +3561,6 @@ This has an effect only if a summary buffer exists."
 
 (defun rmail-fontify-buffer-function ()
   ;; This function's symbol is bound to font-lock-fontify-buffer-function.
-  (make-local-hook 'rmail-show-message-hook)
   (add-hook 'rmail-show-message-hook 'rmail-fontify-message nil t)
   ;; If we're already showing a message, fontify it now.
   (if rmail-current-message (rmail-fontify-message))
@@ -3602,7 +3710,7 @@ TEXT and INDENT are not used."
   "Set PASSWORD to be used for retrieving mail from a POP server."
   (interactive "sPassword: ")
   (if password
-      (setq rmail-encoded-pop-password 
+      (setq rmail-encoded-pop-password
            (rmail-encode-string password (emacs-pid)))
     (setq rmail-pop-password nil)
     (setq rmail-encoded-pop-password nil)))
@@ -3628,7 +3736,7 @@ restarting at the lowest byte of the mask whenever it runs out.
 Returns the encoded string.  Calling the function again with an
 encoded string (and the same mask) will decode the string."
  (setq mask (abs mask))                        ; doesn't work if negative
- (let* ((string-vector (string-to-vector string)) (i 0) 
+ (let* ((string-vector (string-to-vector string)) (i 0)
        (len (length string-vector)) (curmask mask) charmask)
    (while (< i len)
      (if (= curmask 0)