(woman-mode-line-format): Delete constant.
[bpt/emacs.git] / lisp / mail / rmailsum.el
index 37d5f92..9c64712 100644 (file)
@@ -1,6 +1,7 @@
 ;;; rmailsum.el --- make summary buffers for the mail reader
 
-;; Copyright (C) 1985, 1993, 1994, 1995 Free Software Foundation, Inc.
+;; Copyright (C) 1985, 1993, 1994, 1995, 1996, 2000, 2001
+;;   Free Software Foundation, Inc.
 
 ;; Maintainer: FSF
 ;; Keywords: mail
@@ -18,8 +19,9 @@
 ;; GNU General Public License for more details.
 
 ;; 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, 675 Mass Ave, Cambridge, MA 02139, USA.
+;; 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.
 
 ;;; Commentary:
 
 
 ;;; Code:
 
+;; For rmail-select-summary
+(require 'rmail)
+
+;;;###autoload
+(defcustom rmail-summary-scroll-between-messages t
+  "*Non-nil means Rmail summary scroll commands move between messages."
+  :type 'boolean
+  :group 'rmail-summary)
+
+;;;###autoload
+(defcustom rmail-summary-line-count-flag t
+  "*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.
-    ("{ \\([^}]+\\),}" 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.")
 
 ;; Entry points for making a summary buffer.
 (defun rmail-update-summary (&rest ignore)
   (apply (car rmail-summary-redo) (cdr rmail-summary-redo)))
 
+;;;###autoload
 (defun rmail-summary ()
   "Display a summary of all messages, one line per message."
   (interactive)
   (rmail-new-summary "All" '(rmail-summary) nil))
 
+;;;###autoload
 (defun rmail-summary-by-labels (labels)
   "Display a summary of all messages with one or more LABELS.
 LABELS should be a string containing the desired labels, separated by commas."
@@ -63,6 +82,7 @@ LABELS should be a string containing the desired labels, separated by commas."
                     'rmail-message-labels-p
                     (concat ", \\(" (mail-comma-list-regexp labels) "\\),")))
 
+;;;###autoload
 (defun rmail-summary-by-recipients (recipients &optional primary-only)
   "Display a summary of all messages with the given RECIPIENTS.
 Normally checks the To, From and Cc fields of headers;
@@ -76,6 +96,7 @@ RECIPIENTS is a string of regexps separated by commas."
    'rmail-message-recipients-p
    (mail-comma-list-regexp recipients) primary-only))
 
+;;;###autoload
 (defun rmail-summary-by-regexp (regexp)
   "Display a summary of all messages according to regexp REGEXP.
 If the regular expression is found in the header of the message
@@ -84,7 +105,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)
@@ -94,10 +115,11 @@ Emacs will list the header line in the RMAIL-summary."
 ;; rmail-summary-by-topic
 ;; 1989 R.A. Schnitzler
 
+;;;###autoload
 (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")
@@ -110,14 +132,18 @@ SUBJECT is a string of regexps separated by commas."
 (defun rmail-message-subject-p (msg subject &optional whole-message)
   (save-restriction
     (goto-char (rmail-msgbeg msg))
-    (search-forward "\n*** EOOH ***\n")
+    (search-forward "\n*** EOOH ***\n" (rmail-msgend msg) 'move)
     (narrow-to-region
      (point)
      (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)
   "Display a summary of all messages with the given SENDERS.
 SENDERS is a string of names separated by commas."
@@ -150,9 +176,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
@@ -184,8 +209,12 @@ 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)
                (total rmail-total-messages))
            (set-buffer sumbuf)
            ;; Set up the summary buffer's contents.
@@ -199,25 +228,32 @@ nil for FUNCTION means all messages."
            (setq buffer-read-only t)
            (rmail-summary-mode)
            (make-local-variable 'minor-mode-alist)
-           (setq minor-mode-alist (list '(t (concat ": " description))))
+           (setq minor-mode-alist (list (list t (concat ": " description))))
            (setq rmail-buffer rbuf
+                 rmail-view-buffer vbuf
                  rmail-summary-redo redo-form
                  rmail-total-messages total))))
       (setq rmail-summary-buffer sumbuf))
     ;; Now display the summary buffer and go to the right place in it.
     (or was-in-summary
-       (if (and (one-window-p)
-                pop-up-windows (not pop-up-frames))
-           ;; If there is just one window, put the summary on the top.
-           (progn
-             (split-window)
-             (select-window (next-window (frame-first-window)))
-             (pop-to-buffer sumbuf)
-             ;; If pop-to-buffer did not use that window, delete that
-             ;; window.  (This can happen if it uses another frame.)
-             (if (not (eq sumbuf (window-buffer (frame-first-window))))
-                 (delete-other-windows)))
-         (pop-to-buffer sumbuf)))
+       (progn
+         (if (and (one-window-p)
+                  pop-up-windows (not pop-up-frames))
+             ;; If there is just one window, put the summary on the top.
+             (progn
+               (split-window (selected-window) rmail-summary-window-size)
+               (select-window (next-window (frame-first-window)))
+               (pop-to-buffer sumbuf)
+               ;; If pop-to-buffer did not use that window, delete that
+               ;; window.  (This can happen if it uses another frame.)
+               (if (not (eq sumbuf (window-buffer (frame-first-window))))
+                   (delete-other-windows)))
+           (pop-to-buffer sumbuf))
+         (set-buffer rmail-buffer)
+         ;; This is how rmail makes the summary buffer reappear.
+         ;; We do this here to make the window the proper size.
+         (rmail-select-summary nil)
+         (set-buffer rmail-summary-buffer)))
     (rmail-summary-goto-msg mesg t t)
     (rmail-summary-construct-io-menu)
     (message "Computing summary lines...done")))
@@ -234,12 +270,20 @@ nil for FUNCTION means all messages."
                                 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))))
                ?\- ?\ )))
     line))
 
+;;;###autoload
+(defcustom rmail-summary-line-decoder (function identity)
+  "*Function to decode summary-line.
+
+By default, `identity' is set."
+  :type 'function
+  :group 'rmail-summary)
+
 (defun rmail-make-summary-line-1 (msg)
   (goto-char (rmail-msgbeg msg))
   (let* ((lim (save-excursion (forward-line 2) (point)))
@@ -256,8 +300,12 @@ nil for FUNCTION means all messages."
                 ""
               (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)
@@ -294,10 +342,30 @@ nil for FUNCTION means all messages."
          (insert "Summary-line: " line)))
     (setq pos (string-match "#" line))
     (aset rmail-summary-vector (1- msg)
-         (concat (format "%4d  " msg)
-                 (substring line 0 pos)
-                 labels
-                 (substring line (1+ pos))))))
+         (funcall rmail-summary-line-decoder
+                  (concat (format "%5d  " msg)
+                          (substring line 0 pos)
+                          labels
+                          (substring line (1+ pos)))))
+    ))
+
+;;;###autoload
+(defcustom rmail-user-mail-address-regexp nil
+  "*Regexp matching user mail addresses.
+If non-nil, this variable is used to identify the correspondent
+when receiving new mail.  If it matches the address of the sender,
+the recipient is taken as correspondent of a mail.
+If nil \(default value\), your `user-login-name' and `user-mail-address'
+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 addresses.
+
+Setting this variable has an effect only before reading a mail."
+  :type '(choice (const :tag "None" nil) regexp)
+  :group 'rmail-retrieve
+  :version "21.1")
 
 (defun rmail-make-basic-summary-line ()
   (goto-char (point-min))
@@ -307,54 +375,77 @@ nil for FUNCTION means all messages."
              (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]\\)"
+                     (save-excursion (end-of-line) (point)) t)
+                    (format "%2s%2s%2s"
+                            (buffer-substring
+                             (match-beginning 2) (match-end 2))
+                            (buffer-substring
+                             (match-beginning 3) (match-end 3))
+                            (buffer-substring
+                             (match-beginning 4) (match-end 4))))
                    (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 (concat "^"
-                                         (regexp-quote (user-login-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"
@@ -366,7 +457,27 @@ nil for FUNCTION means all messages."
                                                     (- len 25))
                                                    (t (- mch 14))))
                                     (min len (+ lo 25))))))))
-         "  #"
+          (if rmail-summary-line-count-flag
+             (save-excursion
+               (save-restriction
+                 (widen)
+                 (let ((beg (rmail-msgbeg msgnum))
+                       (end (rmail-msgend msgnum))
+                       lines)
+                   (save-excursion
+                     (goto-char beg)
+                     ;; Count only lines in the reformatted header,
+                     ;; if we have reformatted it.
+                     (search-forward "\n*** EOOH ***\n" end t)
+                     (setq lines (count-lines (point) end)))
+                   (format (cond
+                            ((<= lines     9) "   [%d]")
+                            ((<= lines    99) "  [%d]")
+                            ((<= lines   999) " [%3d]")
+                            (t             "[%d]"))
+                           lines))))
+            " ")
+         " #"                          ;The # is part of the format.
          (if (re-search-forward "^Subject:" nil t)
              (progn (skip-chars-forward " \t")
                     (buffer-substring (point)
@@ -409,27 +520,36 @@ messages, or backward if NUMBER is negative."
                                      non-del-msg-found)))
       (setq count (1- count))))
   (beginning-of-line)
-  (display-buffer rmail-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: ")
-  (save-excursion
-    (set-buffer rmail-buffer)
-    (rmail-next-labeled-message n labels)))
+  (let (msg)
+    (save-excursion
+      (set-buffer rmail-buffer)
+      (rmail-next-labeled-message n labels)
+      (setq msg rmail-current-message))
+    (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: ")
-  (save-excursion
-    (set-buffer rmail-buffer)
-    (rmail-previous-labeled-message n labels)))
+  (let (msg)
+    (save-excursion
+      (set-buffer rmail-buffer)
+      (rmail-previous-labeled-message n labels)
+      (setq msg rmail-current-message))
+    (rmail-summary-goto-msg msg)))
 
 (defun rmail-summary-next-same-subject (n)
   "Go to the next message in the summary having the same subject.
@@ -441,12 +561,12 @@ If N is negative, go backwards."
     (save-excursion
       (set-buffer rmail-buffer)
       (setq subject (mail-fetch-field "Subject"))
-      (setq search-regexp (concat "^Subject: *\\(Re: *\\)?"
-                                 (regexp-quote subject)
-                                 "\n"))
       (setq i rmail-current-message))
     (if (string-match "Re:[ \t]*" subject)
        (setq subject (substring subject (match-end 0))))
+    (setq search-regexp (concat "^Subject: *\\(Re: *\\)?"
+                               (regexp-quote subject)
+                               "\n"))
     (save-excursion
       (while (and (/= n 0)
                  (if forward
@@ -460,9 +580,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)
@@ -491,17 +611,20 @@ If N is negative, go forwards instead."
 \f
 ;; Delete and undelete summary commands.
 
-(defun rmail-summary-delete-forward (&optional backward)
+(defun rmail-summary-delete-forward (&optional count)
   "Delete this message and move to next nondeleted one.
 Deleted messages stay in the file until the \\[rmail-expunge] command is given.
-With prefix argument, delete and move backward."
-  (interactive "P")
-  (let (end)
-    (rmail-summary-goto-msg)
-    (pop-to-buffer rmail-buffer)
-    (rmail-delete-message)
-    (let ((del-msg rmail-current-message))
-      (pop-to-buffer rmail-summary-buffer)
+A prefix argument serves as a repeat count;
+a negative argument means to delete and move backward."
+  (interactive "p")
+  (unless (numberp count) (setq count 1))
+  (let (end del-msg
+           (backward (< count 0)))
+    (while (/= count 0)
+      (rmail-summary-goto-msg)
+      (with-current-buffer rmail-buffer
+       (rmail-delete-message)
+       (setq del-msg rmail-current-message))
       (rmail-summary-mark-deleted del-msg)
       (while (and (not (if backward (bobp) (eobp)))
                  (save-excursion (beginning-of-line)
@@ -509,15 +632,20 @@ With prefix argument, delete and move backward."
        (forward-line (if backward -1 1)))
       ;; It looks ugly to move to the empty line at end of buffer.
       (and (eobp) (not backward)
-          (forward-line -1)))))
+          (forward-line -1))
+      (setq count
+           (if (> count 0) (1- count) (1+ count))))))
 
-(defun rmail-summary-delete-backward ()
+(defun rmail-summary-delete-backward (&optional count)
   "Delete this message and move to previous nondeleted one.
-Deleted messages stay in the file until the \\[rmail-expunge] command is given."
-  (interactive)
-  (rmail-summary-delete-forward t))
+Deleted messages stay in the file until the \\[rmail-expunge] command is given.
+A prefix argument serves as a repeat count;
+a negative argument means to delete and move forward."
+  (interactive "p")
+  (rmail-summary-delete-forward (- count)))
 
 (defun rmail-summary-mark-deleted (&optional n undel)
+  ;; Since third arg is t, this only alters the summary, not the Rmail buf.
   (and n (rmail-summary-goto-msg n t t))
   (or (eobp)
       (not (overlay-get rmail-summary-overlay 'face))
@@ -553,9 +681,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))))))
 
@@ -609,7 +741,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)
@@ -618,29 +750,36 @@ Commands for sorting the summary:
   (setq buffer-read-only t)
   (set-syntax-table text-mode-syntax-table)
   (make-local-variable 'rmail-buffer)
+  (make-local-variable 'rmail-view-buffer)
   (make-local-variable 'rmail-total-messages)
   (make-local-variable 'rmail-current-message)
   (setq rmail-current-message nil)
   (make-local-variable 'rmail-summary-redo)
   (setq rmail-summary-redo nil)
   (make-local-variable 'revert-buffer-function)
-  (make-local-variable '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 ()
   (use-local-map text-mode-map)
-  (remove-hook 'post-command-hook 'rmail-summary-rmail-update)
+  (remove-hook 'post-command-hook 'rmail-summary-rmail-update t)
   (setq revert-buffer-function nil))
 
 (defun rmail-summary-enable ()
   (use-local-map rmail-summary-mode-map)
-  (add-hook 'post-command-hook 'rmail-summary-rmail-update)
+  (add-hook 'post-command-hook 'rmail-summary-rmail-update nil t)
   (setq revert-buffer-function 'rmail-update-summary))
 
+(defvar rmail-summary-put-back-unseen nil
+  "Used for communicating between calls to `rmail-summary-rmail-update'.
+If it moves to a message within an Incremental Search, and removes
+the `unseen' attribute from that message, it sets this flag
+so that if the next motion between messages is in the same Incremental
+Search, the `unseen' attribute is restored.")
+
 ;; Show in Rmail the message described by the summary line that point is on,
 ;; but only if the Rmail buffer is already visible.
 ;; This is a post-command-hook in summary buffers.
@@ -652,18 +791,43 @@ Commands for sorting the summary:
          (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'.
+       (if (not isearch-mode)
+           (setq rmail-summary-put-back-unseen nil))
+
        (or (eq rmail-current-message msg-num)
-           (let ((window (get-buffer-window rmail-buffer))
+           (let ((window (get-buffer-window rmail-view-buffer t))
                  (owin (selected-window)))
+             (if isearch-mode
+                 (save-excursion
+                   (set-buffer rmail-buffer)
+                   ;; If we first saw the previous message in this search,
+                   ;; and we have gone to a different message while searching,
+                   ;; put back `unseen' on the former one.
+                   (if rmail-summary-put-back-unseen
+                       (rmail-set-attribute "unseen" t
+                                            rmail-current-message))
+                   ;; Arrange to do that later, for the new current message,
+                   ;; if it still has `unseen'.
+                   (setq rmail-summary-put-back-unseen
+                         (rmail-message-labels-p msg-num ", ?\\(unseen\\),")))
+               (setq rmail-summary-put-back-unseen nil))
+
+             ;; Go to the desired message.
              (setq rmail-current-message msg-num)
+
+             ;; Update the summary to show the message has been seen.
              (if (= (following-char) ?-)
                  (progn
                    (delete-char 1)
                    (insert " ")))
+
              (if window
                  ;; Using save-window-excursion would cause the new value
                  ;; of point to get lost.
@@ -684,7 +848,10 @@ Commands for sorting the summary:
     nil
   (setq rmail-summary-mode-map (make-keymap))
   (suppress-keymap rmail-summary-mode-map)
+
+  (define-key rmail-summary-mode-map [mouse-2] 'rmail-summary-mouse-goto-message)
   (define-key rmail-summary-mode-map "a"      'rmail-summary-add-label)
+  (define-key rmail-summary-mode-map "b"      'rmail-summary-bury)
   (define-key rmail-summary-mode-map "c"      'rmail-summary-continue)
   (define-key rmail-summary-mode-map "d"      'rmail-summary-delete-forward)
   (define-key rmail-summary-mode-map "\C-d"   'rmail-summary-delete-backward)
@@ -694,6 +861,7 @@ Commands for sorting the summary:
   (define-key rmail-summary-mode-map "h"      'rmail-summary)
   (define-key rmail-summary-mode-map "i"      'rmail-summary-input)
   (define-key rmail-summary-mode-map "j"      'rmail-summary-goto-msg)
+  (define-key rmail-summary-mode-map "\C-m"   'rmail-summary-goto-msg)
   (define-key rmail-summary-mode-map "k"      'rmail-summary-kill-label)
   (define-key rmail-summary-mode-map "l"      'rmail-summary-by-labels)
   (define-key rmail-summary-mode-map "\e\C-h" 'rmail-summary)
@@ -712,14 +880,15 @@ Commands for sorting the summary:
   (define-key rmail-summary-mode-map "\ep"    'rmail-summary-previous-all)
   (define-key rmail-summary-mode-map "\e\C-p" 'rmail-summary-previous-labeled-message)
   (define-key rmail-summary-mode-map "q"      'rmail-summary-quit)
+  (define-key rmail-summary-mode-map "Q"      'rmail-summary-wipe)
   (define-key rmail-summary-mode-map "r"      'rmail-summary-reply)
   (define-key rmail-summary-mode-map "s"      'rmail-summary-expunge-and-save)
   (define-key rmail-summary-mode-map "\es"    'rmail-summary-search)
   (define-key rmail-summary-mode-map "t"      'rmail-summary-toggle-header)
   (define-key rmail-summary-mode-map "u"      'rmail-summary-undelete)
   (define-key rmail-summary-mode-map "\M-u"   'rmail-summary-undelete-many)
-  (define-key rmail-summary-mode-map "w"      'rmail-summary-wipe)
   (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-first-message)
   (define-key rmail-summary-mode-map ">"      'rmail-summary-last-message)
@@ -741,7 +910,7 @@ Commands for sorting the summary:
   (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.
@@ -763,6 +932,9 @@ Commands for sorting the summary:
 (define-key rmail-summary-mode-map [menu-bar classify output-menu]
   '(nil))
 
+(define-key rmail-summary-mode-map [menu-bar classify output-body]
+  '("Output (body)..." . rmail-summary-output-body))
+
 (define-key rmail-summary-mode-map [menu-bar classify output-inbox]
   '("Output (inbox)..." . rmail-summary-output))
 
@@ -778,6 +950,9 @@ Commands for sorting the summary:
 (define-key rmail-summary-mode-map [menu-bar summary]
   (cons "Summary" (make-sparse-keymap "Summary")))
 
+(define-key rmail-summary-mode-map [menu-bar summary senders]
+  '("By Senders..." . rmail-summary-by-senders))
+
 (define-key rmail-summary-mode-map [menu-bar summary labels]
   '("By Labels..." . rmail-summary-by-labels))
 
@@ -863,8 +1038,21 @@ Commands for sorting the summary:
   '("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")
+  (goto-char (posn-point (event-end event)))
+  (rmail-summary-goto-msg))
 
 (defun rmail-summary-goto-msg (&optional n nowarn skip-rmail)
+  "Go to message N in the summary buffer and the Rmail buffer.
+If N is nil, use the message corresponding to point in the summary
+and move to that message in the Rmail buffer.
+
+If NOWARN, don't say anything if N is out of range.
+If SKIP-RMAIL, don't do anything to the Rmail buffer."
   (interactive "P")
   (if (consp n) (setq n (prefix-numeric-value n)))
   (if (eobp) (forward-line -1))
@@ -873,9 +1061,9 @@ Commands for sorting the summary:
         (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.
@@ -886,12 +1074,13 @@ Commands for sorting the summary:
       (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)))
+                (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)
@@ -942,7 +1131,7 @@ advance to the next message."
   (interactive "P")
   (if (eq dist '-)
       (rmail-summary-scroll-msg-down 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)
@@ -954,21 +1143,22 @@ advance to the next message."
                        (end-of-line)
                        (eobp)))
                  (select-window rmail-summary-window)))
-             (rmail-summary-next-msg (or dist 1))
-           (let ((other-window-scroll-buffer rmail-buffer))
+             (if (not rmail-summary-scroll-between-messages)
+                 (error "End of buffer")
+               (rmail-summary-next-msg (or dist 1)))
+           (let ((other-window-scroll-buffer rmail-view-buffer))
              (scroll-other-window dist)))
-       ;; This forces rmail-buffer to be sized correctly later.
-       (display-buffer rmail-buffer)
-       (setq rmail-current-message nil)))))
+       ;; If it isn't visible at all, show the beginning.
+       (rmail-summary-beginning-of-message)))))
 
 (defun rmail-summary-scroll-msg-down (&optional dist)
   "Scroll the Rmail window backward.
-If the Rmail window is displaying the beginning of a message,
-advance to the previous message."
+If the Rmail window is now displaying the beginning of a message,
+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)
@@ -979,20 +1169,42 @@ advance to the previous message."
                      (beginning-of-line)
                      (bobp))
                  (select-window rmail-summary-window)))
-             (rmail-summary-previous-msg (or dist 1))
-           (let ((other-window-scroll-buffer rmail-buffer))
+             (if (not rmail-summary-scroll-between-messages)
+                 (error "Beginning of buffer")
+               (rmail-summary-previous-msg (or dist 1)))
+           (let ((other-window-scroll-buffer rmail-view-buffer))
              (scroll-other-window-down dist)))
-       ;; This forces rmail-buffer to be sized correctly later.
-       (display-buffer rmail-buffer)
-       (setq rmail-current-message nil)))))
+       ;; If it isn't visible at all, show the beginning.
+       (rmail-summary-beginning-of-message)))))
 
 (defun rmail-summary-beginning-of-message ()
   "Show current message from the beginning."
   (interactive)
-  (pop-to-buffer rmail-buffer)
+  (if (and (one-window-p) (not pop-up-frames))
+      ;; If there is just one window, put the summary on the top.
+      (let ((buffer rmail-view-buffer))
+       (split-window (selected-window) rmail-summary-window-size)
+       (select-window (frame-first-window))
+       (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-view-buffer))
   (beginning-of-buffer)
   (pop-to-buffer rmail-summary-buffer))
 
+(defun rmail-summary-bury ()
+  "Bury the Rmail buffer and the Rmail summary buffer."
+  (interactive)
+  (let ((buffer-to-bury (current-buffer)))
+    (let (window)
+      (while (setq window (get-buffer-window rmail-buffer))
+       (set-window-buffer window (other-buffer rmail-buffer)))
+      (bury-buffer rmail-buffer))
+    (switch-to-buffer (other-buffer buffer-to-bury))
+    (bury-buffer buffer-to-bury)))
+
 (defun rmail-summary-quit ()
   "Quit out of Rmail and Rmail summary."
   (interactive)
@@ -1003,7 +1215,7 @@ advance 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)))
@@ -1016,7 +1228,8 @@ advance to the previous message."
   (interactive)
   (save-excursion
     (set-buffer rmail-buffer)
-    (rmail-only-expunge))
+    (when (rmail-expunge-confirmed)
+      (rmail-only-expunge)))
   (rmail-update-summary))
 
 (defun rmail-summary-expunge-and-save ()
@@ -1024,24 +1237,33 @@ advance to the previous message."
   (interactive)
   (save-excursion
     (set-buffer rmail-buffer)
-    (rmail-only-expunge))
+    (when (rmail-expunge-confirmed)
+      (rmail-only-expunge)))
   (rmail-update-summary)
   (save-excursion
     (set-buffer rmail-buffer)
     (save-buffer))
   (set-buffer-modified-p nil))
 
-(defun rmail-summary-get-new-mail ()
-  "Get new mail and recompute summary headers."
-  (interactive)
+(defun rmail-summary-get-new-mail (&optional file-name)
+  "Get new mail and recompute summary headers.
+
+Optionally you can specify the file to get new mail from.  In this case,
+the file of new mail is not changed or deleted.  Noninteractively, you can
+pass the inbox file name as an argument.  Interactively, a prefix
+argument says to read a file name and use that file as the inbox."
+  (interactive
+   (list (if current-prefix-arg
+            (read-file-name "Get new mail from file: "))))
   (let (msg)
     (save-excursion
       (set-buffer rmail-buffer)
-      (rmail-get-new-mail)
+      (rmail-get-new-mail file-name)
       ;; Get the proper new message number.
       (setq msg rmail-current-message))
     ;; Make sure that message is displayed.
-    (rmail-summary-goto-msg msg)))
+    (or (zerop msg)
+       (rmail-summary-goto-msg msg))))
 
 (defun rmail-summary-input (filename)
   "Run Rmail on file FILENAME."
@@ -1154,12 +1376,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)))
@@ -1192,6 +1414,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
@@ -1202,9 +1430,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."
@@ -1221,14 +1447,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.
@@ -1240,9 +1464,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."
@@ -1260,12 +1482,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)))
@@ -1276,20 +1496,60 @@ see the documentation of `rmail-resend'."
 \f
 ;; Summary output commands.
 
-(defun rmail-summary-output-to-rmail-file (&optional file-name)
+(defun rmail-summary-output-to-rmail-file (&optional file-name n)
   "Append the current message to an Rmail file named FILE-NAME.
 If the file does not exist, ask if it should be created.
 If file is being visited, the message is appended to the Emacs
-buffer visiting that file."
-  (interactive)
-  (save-excursion
-    (set-buffer rmail-buffer)
-    (let ((rmail-delete-after-output nil))
-      (if file-name
-         (rmail-output-to-rmail-file file-name)
-       (call-interactively 'rmail-output-to-rmail-file))))
-  (if rmail-delete-after-output
-      (rmail-summary-delete-forward nil)))
+buffer visiting that file.
+
+A prefix argument N says to output N consecutive messages
+starting with the current one.  Deleted messages are skipped and don't count."
+  (interactive
+   (progn (require 'rmailout)
+         (list (rmail-output-read-rmail-file-name)
+               (prefix-numeric-value current-prefix-arg))))
+  (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))
+         (rmail-output-to-rmail-file file-name 1)))
+      (if rmail-delete-after-output
+         (rmail-summary-delete-forward nil)
+       (if (< i n)
+           (rmail-summary-next-msg 1))))))
+
+(defun rmail-summary-output (&optional file-name n)
+  "Append this message to Unix mail file named FILE-NAME.
+
+A prefix argument N says to output N consecutive messages
+starting with the current one.  Deleted messages are skipped and don't count."
+  (interactive
+   (progn (require 'rmailout)
+         (list (rmail-output-read-file-name)
+               (prefix-numeric-value current-prefix-arg))))
+  (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))
+         (rmail-output file-name 1)))
+      (if rmail-delete-after-output
+         (rmail-summary-delete-forward nil)
+       (if (< i n)
+           (rmail-summary-next-msg 1))))))
 
 (defun rmail-summary-output-menu ()
   "Output current message to another Rmail file, chosen with a menu.
@@ -1304,31 +1564,37 @@ The variables `rmail-secondary-file-directory' and
   (if rmail-delete-after-output
       (rmail-summary-delete-forward nil)))
 
-(defun rmail-summary-output ()
-  "Append this message to Unix mail file named FILE-NAME."
-  (interactive)
-  (save-excursion
-    (set-buffer rmail-buffer)
-    (let ((rmail-delete-after-output nil))
-      (call-interactively 'rmail-output)))
-  (if rmail-delete-after-output
-      (rmail-summary-delete-forward nil)))
-
 (defun rmail-summary-construct-io-menu ()
   (let ((files (rmail-find-all-files rmail-secondary-file-directory)))
-    (if (listp files)
+    (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" 
-                                     (cdr files) 
+           (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" 
-                                     (cdr files) 
-                                     'rmail-summary-output-to-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]
+       '("Input Rmail File" . rmail-disable-menu))
+      (define-key rmail-summary-mode-map [menu-bar classify output-menu]
+       '("Output Rmail File" . rmail-disable-menu)))))
+
+(defun rmail-summary-output-body (&optional file-name)
+  "Write this message body to the file FILE-NAME.
+FILE-NAME defaults, interactively, from the Subject field of the message."
+  (interactive)
+  (save-excursion
+    (set-buffer rmail-buffer)
+    (let ((rmail-delete-after-output nil))
+      (if file-name
+         (rmail-output-body-to-file file-name)
+       (call-interactively 'rmail-output-body-to-file))))
+  (if rmail-delete-after-output
+      (rmail-summary-delete-forward nil)))
 \f
 ;; Sorting messages in Rmail Summary buffer.
 
@@ -1368,14 +1634,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)
@@ -1387,4 +1653,7 @@ KEYWORDS is a comma-separated list of labels."
               (funcall sortfun reverse))
       (select-window selwin))))
 
+(provide 'rmailsum)
+
+;;; arch-tag: 556079ee-75c1-47f5-9884-2e0a0bc6c5a1
 ;;; rmailsum.el ends here