]> code.delx.au - gnu-emacs/blobdiff - lisp/mail/rmailsum.el
(makeinfo-compile): Use `compilation-start'. Set `next-error-function'
[gnu-emacs] / lisp / mail / rmailsum.el
index 7a5304da6f48e418d1916cdcbce1a3b5a23b66b4..129f3f485289ebd9c1637764ffcf624134af2492 100644 (file)
@@ -1,7 +1,7 @@
 ;;; rmailsum.el --- make summary buffers for the mail reader
 
-;; Copyright (C) 1985, 1993, 1994, 1995, 1996, 2000
-;;   Free Software Foundation, Inc.
+;; Copyright (C) 1985, 1993, 1994, 1995, 1996, 2000, 2001, 2002, 2003,
+;;   2004, 2005 Free Software Foundation, Inc.
 
 ;; Maintainer: FSF
 ;; Keywords: mail
@@ -20,8 +20,8 @@
 
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
 
 ;;; Commentary:
 
 
 ;;;###autoload
 (defcustom rmail-summary-line-count-flag t
-  "*Non-nil if Rmail summary should show the number of lines in each message."
+  "*Non-nil means Rmail summary should show the number of lines in each message."
   :type 'boolean
   :group 'rmail-summary)
 
 (defvar rmail-summary-font-lock-keywords
-  '(("^....D.*" . font-lock-string-face)                       ; Deleted.
-    ("^....-.*" . font-lock-type-face)                         ; Unread.
+  '(("^.....D.*" . font-lock-string-face)                      ; Deleted.
+    ("^.....-.*" . font-lock-type-face)                                ; Unread.
     ;; Neither of the below will be highlighted if either of the above are:
-    ("^....[^D-] \\(......\\)" 1 font-lock-keyword-face)       ; Date.
-    ("{ \\([^\n}]+\\),}" 1 font-lock-comment-face))            ; Labels.
+    ("^.....[^D-] \\(......\\)" 1 font-lock-keyword-face)      ; Date.
+    ("{ \\([^\n}]+\\) }" 1 font-lock-comment-face))            ; Labels.
   "Additional expressions to highlight in Rmail Summary mode.")
 
+(defvar rmail-summary-redo
+  "(FUNCTION . ARGS) to regenerate this Rmail summary buffer.")
+
+(defvar rmail-summary-overlay nil)
+(put 'rmail-summary-overlay 'permanent-local t)
+
+(defvar rmail-summary-mode-map nil)
+
 ;; Entry points for making a summary buffer.
 
 ;; Regenerate the contents of the summary
@@ -105,7 +113,7 @@ Emacs will list the header line in the RMAIL-summary."
   (interactive "sRegexp to summarize by: ")
   (if (string= regexp "")
       (setq regexp (or rmail-last-regexp
-                        (error "No regexp specified."))))
+                        (error "No regexp specified"))))
   (setq rmail-last-regexp regexp)
   (rmail-new-summary (concat "regexp " regexp)
                     (list 'rmail-summary-by-regexp regexp)
@@ -119,7 +127,7 @@ Emacs will list the header line in the RMAIL-summary."
 (defun rmail-summary-by-topic (subject &optional whole-message)
   "Display a summary of all messages with the given SUBJECT.
 Normally checks the Subject field of headers;
-but if WHOLE-MESSAGE is non-nil (prefix arg given), 
+but if WHOLE-MESSAGE is non-nil (prefix arg given),
  look in the whole message.
 SUBJECT is a string of regexps separated by commas."
   (interactive "sTopics to summarize by: \nP")
@@ -138,7 +146,10 @@ SUBJECT is a string of regexps separated by commas."
      (progn (search-forward (if whole-message "\^_" "\n\n")) (point)))
     (goto-char (point-min))
     (if whole-message (re-search-forward subject nil t)
-      (string-match subject (or (mail-fetch-field "Subject") "")) )))
+      (string-match subject (let ((subj (mail-fetch-field "Subject")))
+                             (if subj
+                                 (funcall rmail-summary-line-decoder subj)
+                               ""))))))
 
 ;;;###autoload
 (defun rmail-summary-by-senders (senders)
@@ -162,6 +173,8 @@ SENDERS is a string of names separated by commas."
 
 (defvar rmail-summary-symbol-number 0)
 
+(defvar rmail-new-summary-line-count)
+
 (defun rmail-new-summary (description redo-form function &rest args)
   "Create a summary of selected messages.
 DESCRIPTION makes part of the mode line of the summary buffer.
@@ -173,9 +186,8 @@ nil for FUNCTION means all messages."
     (save-excursion
       ;; Go to the Rmail buffer.
       (if (eq major-mode 'rmail-summary-mode)
-         (progn
-           (setq was-in-summary t)
-           (set-buffer rmail-buffer)))
+         (setq was-in-summary t))
+      (set-buffer rmail-buffer)
       ;; Find its summary buffer, or make one.
       (setq sumbuf
            (if (and rmail-summary-buffer
@@ -185,7 +197,7 @@ nil for FUNCTION means all messages."
       (setq mesg rmail-current-message)
       ;; Filter the messages; make or get their summary lines.
       (let ((summary-msgs ())
-           (new-summary-line-count 0))
+           (rmail-new-summary-line-count 0))
        (let ((msgnum 1)
              (buffer-read-only nil)
              (old-min (point-min-marker))
@@ -207,6 +219,9 @@ nil for FUNCTION means all messages."
        ;; Temporarily, while summary buffer is unfinished,
        ;; we "don't have" a summary.
        (setq rmail-summary-buffer nil)
+       (if rmail-enable-mime
+           (with-current-buffer rmail-view-buffer
+             (setq rmail-summary-buffer nil)))
        (save-excursion
          (let ((rbuf (current-buffer))
                (vbuf rmail-view-buffer)
@@ -258,14 +273,14 @@ nil for FUNCTION means all messages."
 (defun rmail-make-summary-line (msg)
   (let ((line (or (aref rmail-summary-vector (1- msg))
                  (progn
-                   (setq new-summary-line-count
-                         (1+ new-summary-line-count))
-                   (if (zerop (% new-summary-line-count 10))
+                   (setq rmail-new-summary-line-count
+                         (1+ rmail-new-summary-line-count))
+                   (if (zerop (% rmail-new-summary-line-count 10))
                        (message "Computing summary lines...%d"
-                                new-summary-line-count))
+                                rmail-new-summary-line-count))
                    (rmail-make-summary-line-1 msg)))))
     ;; Fix up the part of the summary that says "deleted" or "unseen".
-    (aset line 4
+    (aset line 5
          (if (rmail-message-deleted-p msg) ?\D
            (if (= ?0 (char-after (+ 3 (rmail-msgbeg msg))))
                ?\- ?\ )))
@@ -295,8 +310,12 @@ By default, `identity' is set."
                 ""
               (concat "{"
                       (buffer-substring (point)
-                                        (progn (end-of-line) (point)))
-                      "} ")))))
+                                        (progn (end-of-line)
+                                               (backward-char)
+                                               (if (looking-at ",")
+                                                   (point)
+                                                 (1+ (point)))))
+                      " } ")))))
         (line
          (progn
            (forward-line 1)
@@ -334,7 +353,7 @@ By default, `identity' is set."
     (setq pos (string-match "#" line))
     (aset rmail-summary-vector (1- msg)
          (funcall rmail-summary-line-decoder
-                  (concat (format "%4d  " msg)
+                  (concat (format "%5d  " msg)
                           (substring line 0 pos)
                           labels
                           (substring line (1+ pos)))))
@@ -351,7 +370,7 @@ are used to exclude yourself as correspondent.
 
 Usually you don't have to set this variable, except if you collect mails
 sent by you under different user names.
-Then it should be a regexp matching your mail adresses.
+Then it should be a regexp matching your mail addresses.
 
 Setting this variable has an effect only before reading a mail."
   :type '(choice (const :tag "None" nil) regexp)
@@ -366,17 +385,17 @@ Setting this variable has an effect only before reading a mail."
              (cond ((re-search-forward "\\([^0-9:]\\)\\([0-3]?[0-9]\\)\\([- \t_]+\\)\\([adfjmnos][aceopu][bcglnprtvy]\\)"
                      (save-excursion (end-of-line) (point)) t)
                     (format "%2d-%3s"
-                            (string-to-int (buffer-substring
-                                            (match-beginning 2)
-                                            (match-end 2)))
+                            (string-to-number (buffer-substring
+                                                (match-beginning 2)
+                                                (match-end 2)))
                             (buffer-substring
                              (match-beginning 4) (match-end 4))))
                    ((re-search-forward "\\([^a-z]\\)\\([adfjmnos][acepou][bcglnprtvy]\\)\\([-a-z \t_]*\\)\\([0-9][0-9]?\\)"
                      (save-excursion (end-of-line) (point)) t)
                     (format "%2d-%3s"
-                            (string-to-int (buffer-substring
-                                            (match-beginning 4)
-                                            (match-end 4)))
+                            (string-to-number (buffer-substring
+                                                (match-beginning 4)
+                                                (match-end 4)))
                             (buffer-substring
                              (match-beginning 2) (match-end 2))))
                    ((re-search-forward "\\(19\\|20\\)\\([0-9][0-9]\\)-\\([01][0-9]\\)-\\([0-3][0-9]\\)"
@@ -391,49 +410,52 @@ Setting this variable has an effect only before reading a mail."
                    (t "??????"))))
          "  "
          (save-excursion
-           (if (not (re-search-forward "^From:[ \t]*" nil t))
-               "                         "
-             (let* ((from (mail-strip-quoted-names
-                           (buffer-substring
-                            (1- (point))
-                            ;; Get all the lines of the From field
-                            ;; so that we get a whole comment if there is one,
-                            ;; so that mail-strip-quoted-names can discard it.
-                            (let ((opoint (point)))
-                              (while (progn (forward-line 1)
-                                            (looking-at "[ \t]")))
-                              ;; Back up over newline, then trailing spaces or tabs
-                              (forward-char -1)
-                              (skip-chars-backward " \t")
-                              (point)))))
-                     len mch lo)
-               (if (string-match 
-                    (or rmail-user-mail-address-regexp 
-                        (concat "^\\("
-                                (regexp-quote (user-login-name))
-                                "\\($\\|@\\)\\|"
-                                (regexp-quote
-                                 ;; Don't lose if run from init file
-                                 ;; where user-mail-address is not
-                                 ;; set yet.
-                                 (or user-mail-address
-                                     (concat (user-login-name) "@"
-                                             (or mail-host-address
-                                                 (system-name)))))
-                                "\\>\\)"))
-                    from)
-                   (save-excursion
-                     (goto-char (point-min))
-                     (if (not (re-search-forward "^To:[ \t]*" nil t))
-                         nil
-                       (setq from
-                             (concat "to: "
-                                     (mail-strip-quoted-names
-                                      (buffer-substring
-                                       (point)
-                                       (progn (end-of-line)
-                                              (skip-chars-backward " \t")
-                                              (point)))))))))
+           (let* ((from (and (re-search-forward "^From:[ \t]*" nil t)
+                             (mail-strip-quoted-names
+                              (buffer-substring
+                               (1- (point))
+                               ;; Get all the lines of the From field
+                               ;; so that we get a whole comment if there is one,
+                               ;; so that mail-strip-quoted-names can discard it.
+                               (let ((opoint (point)))
+                                 (while (progn (forward-line 1)
+                                               (looking-at "[ \t]")))
+                                 ;; Back up over newline, then trailing spaces or tabs
+                                 (forward-char -1)
+                                 (skip-chars-backward " \t")
+                                 (point))))))
+                  len mch lo)
+             (if (or (null from)
+                     (string-match
+                      (or rmail-user-mail-address-regexp
+                          (concat "^\\("
+                                  (regexp-quote (user-login-name))
+                                  "\\($\\|@\\)\\|"
+                                  (regexp-quote
+                                   ;; Don't lose if run from init file
+                                   ;; where user-mail-address is not
+                                   ;; set yet.
+                                   (or user-mail-address
+                                       (concat (user-login-name) "@"
+                                               (or mail-host-address
+                                                   (system-name)))))
+                                  "\\>\\)"))
+                      from))
+                 ;; No From field, or it's this user.
+                 (save-excursion
+                   (goto-char (point-min))
+                   (if (not (re-search-forward "^To:[ \t]*" nil t))
+                       nil
+                     (setq from
+                           (concat "to: "
+                                   (mail-strip-quoted-names
+                                    (buffer-substring
+                                     (point)
+                                     (progn (end-of-line)
+                                            (skip-chars-backward " \t")
+                                            (point)))))))))
+             (if (null from)
+                 "                         "
                (setq len (length from))
                (setq mch (string-match "[@%]" from))
                (format "%25s"
@@ -508,15 +530,17 @@ messages, or backward if NUMBER is negative."
                                      non-del-msg-found)))
       (setq count (1- count))))
   (beginning-of-line)
-  (display-buffer rmail-view-buffer)
-  )
+  (display-buffer rmail-view-buffer))
 
 (defun rmail-summary-previous-msg (&optional number)
+  "Display previous non-deleted msg from rmail file.
+With optional prefix argument NUMBER, moves backward this number of
+non-deleted messages."
   (interactive "p")
   (rmail-summary-next-msg (- (if number number 1))))
 
 (defun rmail-summary-next-labeled-message (n labels)
-  "Show next message with LABEL.  Defaults to last labels used.
+  "Show next message with LABELS.  Defaults to last labels used.
 With prefix argument N moves forward N messages with these labels."
   (interactive "p\nsMove to next msg with labels: ")
   (let (msg)
@@ -527,7 +551,7 @@ With prefix argument N moves forward N messages with these labels."
     (rmail-summary-goto-msg msg)))
 
 (defun rmail-summary-previous-labeled-message (n labels)
-  "Show previous message with LABEL.  Defaults to last labels used.
+  "Show previous message with LABELS.  Defaults to last labels used.
 With prefix argument N moves backward N messages with these labels."
   (interactive "p\nsMove to previous msg with labels: ")
   (let (msg)
@@ -566,9 +590,9 @@ If N is negative, go backwards."
            ;; Advance thru summary.
            (forward-line (if forward 1 -1))
            ;; Get msg number of this line.
-           (setq i (string-to-int
+           (setq i (string-to-number
                     (buffer-substring (point)
-                                      (min (point-max) (+ 5 (point))))))
+                                      (min (point-max) (+ 6 (point))))))
            ;; See if that msg has desired subject.
            (save-excursion
              (set-buffer rmail-buffer)
@@ -667,9 +691,13 @@ Optional prefix ARG means undelete ARG previous messages."
       (cond ((re-search-backward "\\(^ *[0-9]*\\)\\(D\\)" nil t)
             (replace-match "\\1 ")
             (rmail-summary-goto-msg)
-            (pop-to-buffer rmail-buffer)
+            (if rmail-enable-mime
+                (set-buffer rmail-buffer)
+              (pop-to-buffer rmail-buffer))
             (and (rmail-message-deleted-p rmail-current-message)
                  (rmail-undelete-previous-message))
+            (if rmail-enable-mime
+                (pop-to-buffer rmail-view-buffer))
             (pop-to-buffer rmail-summary-buffer))
            (t (goto-char opoint))))))
 
@@ -723,7 +751,7 @@ Commands for sorting the summary:
 \\[rmail-summary-sort-by-recipient] Sort by recipient.
 \\[rmail-summary-sort-by-correspondent] Sort by correspondent.
 \\[rmail-summary-sort-by-lines] Sort by lines.
-\\[rmail-summary-sort-by-keywords] Sort by keywords."
+\\[rmail-summary-sort-by-labels] Sort by labels."
   (interactive)
   (kill-all-local-variables)
   (setq major-mode 'rmail-summary-mode)
@@ -739,11 +767,10 @@ Commands for sorting the summary:
   (make-local-variable 'rmail-summary-redo)
   (setq rmail-summary-redo nil)
   (make-local-variable 'revert-buffer-function)
-  (make-local-hook 'post-command-hook)
   (make-local-variable 'font-lock-defaults)
   (setq font-lock-defaults '(rmail-summary-font-lock-keywords t))
   (rmail-summary-enable)
-  (run-hooks 'rmail-summary-mode-hook))
+  (run-mode-hooks 'rmail-summary-mode-hook))
 
 ;; Summary features need to be disabled during edit mode.
 (defun rmail-summary-disable ()
@@ -774,10 +801,10 @@ Search, the `unseen' attribute is restored.")
          (forward-line -1))
       (beginning-of-line)
       (skip-chars-forward " ")
-      (let ((msg-num (string-to-int (buffer-substring
-                                    (point)
-                                    (progn (skip-chars-forward "0-9")
-                                           (point))))))
+      (let ((msg-num (string-to-number (buffer-substring
+                                        (point)
+                                        (progn (skip-chars-forward "0-9")
+                                               (point))))))
        ;; Always leave `unseen' removed
        ;; if we get out of isearch mode.
        ;; Don't let a subsequent isearch restore that `unseen'.
@@ -825,8 +852,6 @@ Search, the `unseen' attribute is restored.")
                      (rmail-show-message msg-num t))))))
        (rmail-summary-update-highlight nil)))))
 \f
-(defvar rmail-summary-mode-map nil)
-
 (if rmail-summary-mode-map
     nil
   (setq rmail-summary-mode-map (make-keymap))
@@ -873,6 +898,7 @@ Search, the `unseen' attribute is restored.")
   (define-key rmail-summary-mode-map "x"      'rmail-summary-expunge)
   (define-key rmail-summary-mode-map "w"      'rmail-summary-output-body)
   (define-key rmail-summary-mode-map "."      'rmail-summary-beginning-of-message)
+  (define-key rmail-summary-mode-map "/"      'rmail-summary-end-of-message)
   (define-key rmail-summary-mode-map "<"      'rmail-summary-first-message)
   (define-key rmail-summary-mode-map ">"      'rmail-summary-last-message)
   (define-key rmail-summary-mode-map " "      'rmail-summary-scroll-msg-up)
@@ -893,7 +919,7 @@ Search, the `unseen' attribute is restored.")
   (define-key rmail-summary-mode-map "\C-c\C-s\C-l"
     'rmail-summary-sort-by-lines)
   (define-key rmail-summary-mode-map "\C-c\C-s\C-k"
-    'rmail-summary-sort-by-keywords)
+    'rmail-summary-sort-by-labels)
   )
 \f
 ;;; Menu bar bindings.
@@ -1020,9 +1046,6 @@ Search, the `unseen' attribute is restored.")
 (define-key rmail-summary-mode-map [menu-bar move next]
   '("Next" . rmail-summary-next-all))
 \f
-(defvar rmail-summary-overlay nil)
-(put 'rmail-summary-overlay 'permanent-local t)
-
 (defun rmail-summary-mouse-goto-message (event)
   "Select the message whose summary line you click on."
   (interactive "@e")
@@ -1044,9 +1067,9 @@ If SKIP-RMAIL, don't do anything to the Rmail buffer."
         (buf rmail-buffer)
         (cur (point))
         message-not-found
-        (curmsg (string-to-int
+        (curmsg (string-to-number
                  (buffer-substring (point)
-                                   (min (point-max) (+ 5 (point))))))
+                                   (min (point-max) (+ 6 (point))))))
         (total (save-excursion (set-buffer buf) rmail-total-messages)))
     ;; If message number N was specified, find that message's line
     ;; or set message-not-found.
@@ -1057,12 +1080,13 @@ If SKIP-RMAIL, don't do anything to the Rmail buffer."
       (if (< n 1)
          (progn (message "No preceding message")
                 (setq n 1)))
-      (if (> n total)
+      (if (and (> n total)
+              (> total 0))
          (progn (message "No following message")
                 (goto-char (point-max))
                 (rmail-summary-goto-msg nil nowarn skip-rmail)))
       (goto-char (point-min))
-      (if (not (re-search-forward (format "^%4d[^0-9]" n) nil t))
+      (if (not (re-search-forward (format "^%5d[^0-9]" n) nil t))
          (progn (or nowarn (message "Message %d not found" n))
                 (setq n curmsg)
                 (setq message-not-found t)
@@ -1140,7 +1164,7 @@ move to the previous message."
   (interactive "P")
   (if (eq dist '-)
       (rmail-summary-scroll-msg-up nil)
-    (let ((rmail-buffer-window (get-buffer-window rmail-buffer)))
+    (let ((rmail-buffer-window (get-buffer-window rmail-view-buffer)))
       (if rmail-buffer-window
          (if (let ((rmail-summary-window (selected-window)))
                (select-window rmail-buffer-window)
@@ -1154,7 +1178,7 @@ move to the previous message."
              (if (not rmail-summary-scroll-between-messages)
                  (error "Beginning of buffer")
                (rmail-summary-previous-msg (or dist 1)))
-           (let ((other-window-scroll-buffer rmail-buffer))
+           (let ((other-window-scroll-buffer rmail-view-buffer))
              (scroll-other-window-down dist)))
        ;; If it isn't visible at all, show the beginning.
        (rmail-summary-beginning-of-message)))))
@@ -1162,18 +1186,35 @@ move to the previous message."
 (defun rmail-summary-beginning-of-message ()
   "Show current message from the beginning."
   (interactive)
+  (rmail-summary-show-message 'BEG))
+
+(defun rmail-summary-end-of-message ()
+  "Show bottom of current message."
+  (interactive)
+  (rmail-summary-show-message 'END))
+
+(defun rmail-summary-show-message (where)
+  "Show current mail message.
+Position it according to WHERE which can be BEG or END"
   (if (and (one-window-p) (not pop-up-frames))
       ;; If there is just one window, put the summary on the top.
-      (let ((buffer rmail-buffer))
+      (let ((buffer rmail-view-buffer))
        (split-window (selected-window) rmail-summary-window-size)
        (select-window (frame-first-window))
-       (pop-to-buffer rmail-buffer)
+       (pop-to-buffer rmail-view-buffer)
        ;; If pop-to-buffer did not use that window, delete that
        ;; window.  (This can happen if it uses another frame.)
        (or (eq buffer (window-buffer (next-window (frame-first-window))))
            (delete-other-windows)))
-    (pop-to-buffer rmail-buffer))
-  (beginning-of-buffer)
+    (pop-to-buffer rmail-view-buffer))
+  (cond
+   ((eq where 'BEG)
+       (goto-char (point-min))
+       (search-forward "\n\n"))
+   ((eq where 'END)
+       (goto-char (point-max))
+       (recenter (1- (window-height))))
+   )
   (pop-to-buffer rmail-summary-buffer))
 
 (defun rmail-summary-bury ()
@@ -1197,7 +1238,7 @@ move to the previous message."
   "Kill and wipe away Rmail summary, remaining within Rmail."
   (interactive)
   (save-excursion (set-buffer rmail-buffer) (setq rmail-summary-buffer nil))
-  (let ((local-rmail-buffer rmail-buffer))
+  (let ((local-rmail-buffer rmail-view-buffer))
     (kill-buffer (current-buffer))
     ;; Delete window if not only one.
     (if (not (eq (selected-window) (next-window nil 'no-minibuf)))
@@ -1257,12 +1298,14 @@ argument says to read a file name and use that file as the inbox."
 (defun rmail-summary-first-message ()
   "Show first message in Rmail file from summary buffer."
   (interactive)
-  (beginning-of-buffer))
+  (with-no-warnings
+    (beginning-of-buffer)))
 
 (defun rmail-summary-last-message ()
   "Show last message in Rmail file from summary buffer."
   (interactive)
-  (end-of-buffer)
+  (with-no-warnings
+    (end-of-buffer))
   (forward-line -1))
 
 (defvar rmail-summary-edit-map nil)
@@ -1358,12 +1401,12 @@ Interactively, empty argument means use same regexp used last time."
 (defun rmail-summary-toggle-header ()
   "Show original message header if pruned header currently shown, or vice versa."
   (interactive)
-  (save-excursion
+  (save-window-excursion
     (set-buffer rmail-buffer)
     (rmail-toggle-header))
   ;; Inside save-excursion, some changes to point in the RMAIL buffer are lost.
   ;; Set point to point-min in the RMAIL buffer, if it is visible.
-  (let ((window (get-buffer-window rmail-buffer)))
+  (let ((window (get-buffer-window rmail-view-buffer)))
     (if window
         ;; Using save-window-excursion would lose the new value of point.
         (let ((owin (selected-window)))
@@ -1396,6 +1439,12 @@ Completion is performed over known labels when reading."
 \f
 ;;;; *** Rmail Summary Mailing Commands ***
 
+(defun rmail-summary-override-mail-send-and-exit ()
+  "Replace bindings to `mail-send-and-exit' with `rmail-summary-send-and-exit'."
+  (use-local-map (copy-keymap (current-local-map)))
+  (dolist (key (where-is-internal 'mail-send-and-exit))
+    (define-key (current-local-map) key 'rmail-summary-send-and-exit)))
+
 (defun rmail-summary-mail ()
   "Send mail in another window.
 While composing the message, use \\[mail-yank-original] to yank the
@@ -1406,9 +1455,7 @@ original message into it."
        (select-window window)
       (set-buffer rmail-buffer)))
   (rmail-start-mail nil nil nil nil nil (current-buffer))
-  (use-local-map (copy-keymap (current-local-map)))
-  (define-key (current-local-map)
-    "\C-c\C-c" 'rmail-summary-send-and-exit))
+  (rmail-summary-override-mail-send-and-exit))
 
 (defun rmail-summary-continue ()
   "Continue composing outgoing message previously being composed."
@@ -1425,14 +1472,12 @@ Normally include CC: to all other recipients of original message;
 prefix argument means ignore them.  While composing the reply,
 use \\[mail-yank-original] to yank the original message into it."
   (interactive "P")
-  (let ((window (get-buffer-window rmail-buffer)))
+  (let ((window (get-buffer-window rmail-view-buffer)))
     (if window
        (select-window window)
-      (set-buffer rmail-buffer)))
+      (set-buffer rmail-view-buffer)))
   (rmail-reply just-sender)
-  (use-local-map (copy-keymap (current-local-map)))
-  (define-key (current-local-map)
-    "\C-c\C-c" 'rmail-summary-send-and-exit))
+  (rmail-summary-override-mail-send-and-exit))
 
 (defun rmail-summary-retry-failure ()
   "Edit a mail message which is based on the contents of the current message.
@@ -1444,9 +1489,7 @@ the body of the original message; otherwise copy the current message."
        (select-window window)
       (set-buffer rmail-buffer)))
   (rmail-retry-failure)
-  (use-local-map (copy-keymap (current-local-map)))
-  (define-key (current-local-map)
-    "\C-c\C-c" 'rmail-summary-send-and-exit))
+  (rmail-summary-override-mail-send-and-exit))
 
 (defun rmail-summary-send-and-exit ()
   "Send mail reply and return to summary buffer."
@@ -1464,12 +1507,10 @@ see the documentation of `rmail-resend'."
          (select-window window)
        (set-buffer rmail-buffer)))
     (rmail-forward resend)
-    (use-local-map (copy-keymap (current-local-map)))
-    (define-key (current-local-map)
-      "\C-c\C-c" 'rmail-summary-send-and-exit)))
+    (rmail-summary-override-mail-send-and-exit)))
 
 (defun rmail-summary-resend ()
-  "Resend current message using 'rmail-resend'."
+  "Resend current message using `rmail-resend'."
   (interactive)
   (save-excursion
     (let ((window (get-buffer-window rmail-buffer)))
@@ -1493,12 +1534,12 @@ starting with the current one.  Deleted messages are skipped and don't count."
          (list (rmail-output-read-rmail-file-name)
                (prefix-numeric-value current-prefix-arg))))
   (let ((i 0) prev-msg)
-    (while 
+    (while
        (and (< i n)
             (progn (rmail-summary-goto-msg)
                    (not (eq prev-msg
                             (setq prev-msg
-                                  (with-current-buffer rmail-buffer 
+                                  (with-current-buffer rmail-buffer
                                     rmail-current-message))))))
       (setq i (1+ i))
       (with-current-buffer rmail-buffer
@@ -1518,8 +1559,14 @@ starting with the current one.  Deleted messages are skipped and don't count."
    (progn (require 'rmailout)
          (list (rmail-output-read-file-name)
                (prefix-numeric-value current-prefix-arg))))
-  (let ((i 0))
-    (while (< i n)
+  (let ((i 0) prev-msg)
+    (while
+       (and (< i n)
+            (progn (rmail-summary-goto-msg)
+                   (not (eq prev-msg
+                            (setq prev-msg
+                                  (with-current-buffer rmail-buffer
+                                    rmail-current-message))))))
       (setq i (1+ i))
       (with-current-buffer rmail-buffer
        (let ((rmail-delete-after-output nil))
@@ -1547,13 +1594,13 @@ The variables `rmail-secondary-file-directory' and
     (if files
        (progn
          (define-key rmail-summary-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-summary-input)))
          (define-key rmail-summary-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-summary-output-to-rmail-file))))
       (define-key rmail-summary-mode-map [menu-bar classify input-menu]
@@ -1612,14 +1659,14 @@ If prefix argument REVERSE is non-nil, sort them in reverse order."
   (interactive "P")
   (rmail-sort-from-summary (function rmail-sort-by-lines) reverse))
 
-(defun rmail-summary-sort-by-keywords (reverse labels)
-  "Sort messages of current Rmail summary by keywords.
+(defun rmail-summary-sort-by-labels (reverse labels)
+  "Sort messages of current Rmail summary by labels.
 If prefix argument REVERSE is non-nil, sort them in reverse order.
 KEYWORDS is a comma-separated list of labels."
   (interactive "P\nsSort by labels: ")
   (rmail-sort-from-summary
    (function (lambda (reverse)
-              (rmail-sort-by-keywords reverse labels)))
+              (rmail-sort-by-labels reverse labels)))
    reverse))
 
 (defun rmail-sort-from-summary (sortfun reverse)
@@ -1633,4 +1680,5 @@ KEYWORDS is a comma-separated list of labels."
 
 (provide 'rmailsum)
 
+;;; arch-tag: 556079ee-75c1-47f5-9884-2e0a0bc6c5a1
 ;;; rmailsum.el ends here