Merge from emacs-24; up to 2014-05-15T16:55:18Z!jan.h.d@swipnet.se
[bpt/emacs.git] / lisp / mail / rmailsum.el
index b942e90..af08d0f 100644 (file)
@@ -1,10 +1,11 @@
 ;;; rmailsum.el --- make summary buffers for the mail reader
 
-;; Copyright (C) 1985, 1993, 1994, 1995, 1996, 2000, 2001, 2002, 2003,
-;;   2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+;; Copyright (C) 1985, 1993-1996, 2000-2014 Free Software Foundation,
+;; Inc.
 
-;; Maintainer: FSF
+;; Maintainer: emacs-devel@gnu.org
 ;; Keywords: mail
+;; Package: rmail
 
 ;; This file is part of GNU Emacs.
 
@@ -64,7 +65,197 @@ Setting this option to nil might speed up the generation of summaries."
   "Overlay used to highlight the current message in the Rmail summary.")
 (put 'rmail-summary-overlay 'permanent-local t)
 
-(defvar rmail-summary-mode-map nil
+(defvar rmail-summary-mode-map
+  (let ((map (make-keymap)))
+    (suppress-keymap map)
+    (define-key map [mouse-2] 'rmail-summary-mouse-goto-message)
+    (define-key map "a"      'rmail-summary-add-label)
+    (define-key map "b"      'rmail-summary-bury)
+    (define-key map "c"      'rmail-summary-continue)
+    (define-key map "d"      'rmail-summary-delete-forward)
+    (define-key map "\C-d"   'rmail-summary-delete-backward)
+    (define-key map "e"      'rmail-summary-edit-current-message)
+    (define-key map "f"      'rmail-summary-forward)
+    (define-key map "g"      'rmail-summary-get-new-mail)
+    (define-key map "h"      'rmail-summary)
+    (define-key map "i"      'rmail-summary-input)
+    (define-key map "j"      'rmail-summary-goto-msg)
+    (define-key map "\C-m"   'rmail-summary-goto-msg)
+    (define-key map "k"      'rmail-summary-kill-label)
+    (define-key map "l"      'rmail-summary-by-labels)
+    (define-key map "\e\C-h" 'rmail-summary)
+    (define-key map "\e\C-l" 'rmail-summary-by-labels)
+    (define-key map "\e\C-r" 'rmail-summary-by-recipients)
+    (define-key map "\e\C-s" 'rmail-summary-by-regexp)
+    ;; `f' for "from".
+    (define-key map "\e\C-f" 'rmail-summary-by-senders)
+    (define-key map "\e\C-t" 'rmail-summary-by-topic)
+    (define-key map "m"      'rmail-summary-mail)
+    (define-key map "\M-m"   'rmail-summary-retry-failure)
+    (define-key map "n"      'rmail-summary-next-msg)
+    (define-key map "\en"    'rmail-summary-next-all)
+    (define-key map "\e\C-n" 'rmail-summary-next-labeled-message)
+    (define-key map "o"      'rmail-summary-output)
+    (define-key map "\C-o"   'rmail-summary-output-as-seen)
+    (define-key map "p"      'rmail-summary-previous-msg)
+    (define-key map "\ep"    'rmail-summary-previous-all)
+    (define-key map "\e\C-p" 'rmail-summary-previous-labeled-message)
+    (define-key map "q"      'rmail-summary-quit)
+    (define-key map "Q"      'rmail-summary-wipe)
+    (define-key map "r"      'rmail-summary-reply)
+    (define-key map "s"      'rmail-summary-expunge-and-save)
+    ;; See rms's comment in rmail.el
+    ;; (define-key map "\er"    'rmail-summary-search-backward)
+    (define-key map "\es"    'rmail-summary-search)
+    (define-key map "t"      'rmail-summary-toggle-header)
+    (define-key map "u"      'rmail-summary-undelete)
+    (define-key map "\M-u"   'rmail-summary-undelete-many)
+    (define-key map "x"      'rmail-summary-expunge)
+    (define-key map "w"      'rmail-summary-output-body)
+    (define-key map "v"      'rmail-mime)
+    (define-key map "."      'rmail-summary-beginning-of-message)
+    (define-key map "/"      'rmail-summary-end-of-message)
+    (define-key map "<"      'rmail-summary-first-message)
+    (define-key map ">"      'rmail-summary-last-message)
+    (define-key map " "      'rmail-summary-scroll-msg-up)
+    (define-key map [?\S-\ ] 'rmail-summary-scroll-msg-down)
+    (define-key map "\177"   'rmail-summary-scroll-msg-down)
+    (define-key map "?"      'describe-mode)
+    (define-key map "\C-c\C-n" 'rmail-summary-next-same-subject)
+    (define-key map "\C-c\C-p" 'rmail-summary-previous-same-subject)
+    (define-key map "\C-c\C-s\C-d" 'rmail-summary-sort-by-date)
+    (define-key map "\C-c\C-s\C-s" 'rmail-summary-sort-by-subject)
+    (define-key map "\C-c\C-s\C-a" 'rmail-summary-sort-by-author)
+    (define-key map "\C-c\C-s\C-r" 'rmail-summary-sort-by-recipient)
+    (define-key map "\C-c\C-s\C-c" 'rmail-summary-sort-by-correspondent)
+    (define-key map "\C-c\C-s\C-l" 'rmail-summary-sort-by-lines)
+    (define-key map "\C-c\C-s\C-k" 'rmail-summary-sort-by-labels)
+    (define-key map "\C-x\C-s" 'rmail-summary-save-buffer)
+
+    ;; Menu bar bindings.
+
+    (define-key map [menu-bar] (make-sparse-keymap))
+
+    (define-key map [menu-bar classify]
+      (cons "Classify" (make-sparse-keymap "Classify")))
+
+    (define-key map [menu-bar classify output-menu]
+      '("Output (Rmail Menu)..." . rmail-summary-output-menu))
+
+    (define-key map [menu-bar classify input-menu]
+      '("Input Rmail File (menu)..." . rmail-input-menu))
+
+    (define-key map [menu-bar classify input-menu]
+      '(nil))
+
+    (define-key map [menu-bar classify output-menu]
+      '(nil))
+
+    (define-key map [menu-bar classify output-body]
+      '("Output body..." . rmail-summary-output-body))
+
+    (define-key map [menu-bar classify output-inbox]
+      '("Output..." . rmail-summary-output))
+
+    (define-key map [menu-bar classify output]
+      '("Output as seen..." . rmail-summary-output-as-seen))
+
+    (define-key map [menu-bar classify kill-label]
+      '("Kill Label..." . rmail-summary-kill-label))
+
+    (define-key map [menu-bar classify add-label]
+      '("Add Label..." . rmail-summary-add-label))
+
+    (define-key map [menu-bar summary]
+      (cons "Summary" (make-sparse-keymap "Summary")))
+
+    (define-key map [menu-bar summary senders]
+      '("By Senders..." . rmail-summary-by-senders))
+
+    (define-key map [menu-bar summary labels]
+      '("By Labels..." . rmail-summary-by-labels))
+
+    (define-key map [menu-bar summary recipients]
+      '("By Recipients..." . rmail-summary-by-recipients))
+
+    (define-key map [menu-bar summary topic]
+      '("By Topic..." . rmail-summary-by-topic))
+
+    (define-key map [menu-bar summary regexp]
+      '("By Regexp..." . rmail-summary-by-regexp))
+
+    (define-key map [menu-bar summary all]
+      '("All" . rmail-summary))
+
+    (define-key map [menu-bar mail]
+      (cons "Mail" (make-sparse-keymap "Mail")))
+
+    (define-key map [menu-bar mail rmail-summary-get-new-mail]
+      '("Get New Mail" . rmail-summary-get-new-mail))
+
+    (define-key map [menu-bar mail lambda]
+      '("----"))
+
+    (define-key map [menu-bar mail continue]
+      '("Continue" . rmail-summary-continue))
+
+    (define-key map [menu-bar mail resend]
+      '("Re-send..." . rmail-summary-resend))
+
+    (define-key map [menu-bar mail forward]
+      '("Forward" . rmail-summary-forward))
+
+    (define-key map [menu-bar mail retry]
+      '("Retry" . rmail-summary-retry-failure))
+
+    (define-key map [menu-bar mail reply]
+      '("Reply" . rmail-summary-reply))
+
+    (define-key map [menu-bar mail mail]
+      '("Mail" . rmail-summary-mail))
+
+    (define-key map [menu-bar delete]
+      (cons "Delete" (make-sparse-keymap "Delete")))
+
+    (define-key map [menu-bar delete expunge/save]
+      '("Expunge/Save" . rmail-summary-expunge-and-save))
+
+    (define-key map [menu-bar delete expunge]
+      '("Expunge" . rmail-summary-expunge))
+
+    (define-key map [menu-bar delete undelete]
+      '("Undelete" . rmail-summary-undelete))
+
+    (define-key map [menu-bar delete delete]
+      '("Delete" . rmail-summary-delete-forward))
+
+    (define-key map [menu-bar move]
+      (cons "Move" (make-sparse-keymap "Move")))
+
+    (define-key map [menu-bar move search-back]
+      '("Search Back..." . rmail-summary-search-backward))
+
+    (define-key map [menu-bar move search]
+      '("Search..." . rmail-summary-search))
+
+    (define-key map [menu-bar move previous]
+      '("Previous Nondeleted" . rmail-summary-previous-msg))
+
+    (define-key map [menu-bar move next]
+      '("Next Nondeleted" . rmail-summary-next-msg))
+
+    (define-key map [menu-bar move last]
+      '("Last" . rmail-summary-last-message))
+
+    (define-key map [menu-bar move first]
+      '("First" . rmail-summary-first-message))
+
+    (define-key map [menu-bar move previous]
+      '("Previous" . rmail-summary-previous-all))
+
+    (define-key map [menu-bar move next]
+      '("Next" . rmail-summary-next-all))
+    map)
   "Keymap used in Rmail summary mode.")
 
 ;; Entry points for making a summary buffer.
@@ -79,9 +270,7 @@ Setting this option to nil might speed up the generation of summaries."
 (defun rmail-summary ()
   "Display a summary of all messages, one line per message."
   (interactive)
-  (rmail-new-summary "All" '(rmail-summary) nil)
-  (unless (get-buffer-window rmail-buffer)
-    (rmail-summary-beginning-of-message)))
+  (rmail-new-summary "All" '(rmail-summary) nil))
 
 ;;;###autoload
 (defun rmail-summary-by-labels (labels)
@@ -155,10 +344,9 @@ Emacs will list the message in the summary."
 (defun rmail-message-regexp-p-1 (msg regexp)
   ;; Search functions can expect to start from the beginning.
   (narrow-to-region (point) (save-excursion (search-forward "\n\n") (point)))
-  (if rmail-enable-mime
-      (if rmail-search-mime-header-function
-         (funcall rmail-search-mime-header-function msg regexp (point))
-       (error "You must set `rmail-search-mime-header-function'"))
+  (if (and rmail-enable-mime
+          rmail-search-mime-header-function)
+      (funcall rmail-search-mime-header-function msg regexp (point))
     (re-search-forward regexp nil t)))
 
 ;;;###autoload
@@ -206,22 +394,27 @@ SENDERS is a string of regexps separated by commas."
 
 (defvar rmail-new-summary-line-count)
 
-(defun rmail-new-summary (desc redo func &rest args)
+(defun rmail-new-summary (desc redo function &rest args)
   "Create a summary of selected messages.
-DESC makes part of the mode line of the summary buffer. REDO is form ...
-For each message, FUNC is applied to the message number and ARGS...
-and if the result is non-nil, that message is included.
-nil for FUNCTION means all messages."
+DESC makes part of the mode line of the summary buffer.
+REDO is what to put in `rmail-summary-redo'; usually
+its car is the function that called `rmail-new-summary'
+and its cdr is the arguments passed to that function.
+
+For each message, applies FUNCTION to the message number and ARGS...,
+and if the result is non-nil, it includes that message in the summary.
+If FUNCTION is nil, includes all messages."
   (message "Computing summary lines...")
   (unless rmail-buffer
     (error "No RMAIL buffer found"))
-  (let (mesg was-in-summary)
-    (if (eq major-mode 'rmail-summary-mode)
+  (let (mesg was-in-summary sumbuf)
+    (if (derived-mode-p 'rmail-summary-mode)
        (setq was-in-summary t))
     (with-current-buffer rmail-buffer
-      (if (zerop (setq mesg rmail-current-message))
-         (error "No messages to summarize"))
-      (setq rmail-summary-buffer (rmail-new-summary-1 desc redo func args)))
+      (setq rmail-summary-buffer (rmail-new-summary-1 desc redo function args)
+           ;; r-s-b is buffer-local.
+           sumbuf rmail-summary-buffer
+           mesg rmail-current-message))
     ;; Now display the summary buffer and go to the right place in it.
     (unless was-in-summary
       (if (and (one-window-p)
@@ -231,30 +424,29 @@ nil for FUNCTION means all messages."
          (progn
            (split-window (selected-window) rmail-summary-window-size)
            (select-window (next-window (frame-first-window)))
-           (rmail-pop-to-buffer rmail-summary-buffer)
+           (rmail-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 rmail-summary-buffer
-                        (window-buffer (frame-first-window))))
+           (if (not (eq sumbuf (window-buffer (frame-first-window))))
                (delete-other-windows)))
-       (rmail-pop-to-buffer rmail-summary-buffer))
+       (rmail-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))
+      (set-buffer sumbuf))
     (rmail-summary-goto-msg mesg t t)
     (rmail-summary-construct-io-menu)
     (message "Computing summary lines...done")))
 
-(defun rmail-new-summary-1 (description form function args)
+(defun rmail-new-summary-1 (description redo function args)
   "Filter messages to obtain summary lines.
 DESCRIPTION is added to the mode line.
 
 Return the summary buffer by invoking FUNCTION on each message
-passing the message number and ARGS...
+passing the message number and ARGS.
 
-REDO is a form ...
+REDO is what to put in `rmail-summary-redo'.
 
 The current buffer must be a Rmail buffer either containing a
 collection of mbox formatted messages or displaying a single
@@ -281,8 +473,8 @@ message."
                (widen)
                (goto-char (point-min))
                (while (>= total msgnum)
-                 ;; Go back to the Rmail buffer so
-                 ;; so FUNCTION and rmail-get-summary can see its local vars.
+                 ;; Go back to the Rmail buffer so FUNCTION and
+                 ;; rmail-get-summary can see its local vars.
                  (with-current-buffer main-buffer
                    ;; First test whether to include this message.
                    (if (or (null function)
@@ -301,12 +493,8 @@ message."
     ;; Temporarily, while summary buffer is unfinished,
     ;; we "don't have" a summary.
     (setq rmail-summary-buffer nil)
-    (unless summary-msgs
-      (kill-buffer sumbuf)
-      (error "Nothing to summarize"))
     ;; I have not a clue what this clause is doing.  If you read this
-    ;; chunk of code and have a clue, then please email that clue to
-    ;; pmr@pajato.com
+    ;; chunk of code and have a clue, then please  write it here.
     (if rmail-enable-mime
        (with-current-buffer rmail-buffer
          (setq rmail-summary-buffer nil)))
@@ -327,7 +515,7 @@ message."
        (make-local-variable 'minor-mode-alist)
        (setq minor-mode-alist (list (list t (concat ": " description))))
        (setq rmail-buffer rbuf
-             rmail-summary-redo form
+             rmail-summary-redo redo
              rmail-total-messages total)))
     sumbuf))
 
@@ -579,6 +767,12 @@ the message being processed."
                                              (point)))))))))
               (if (null from)
                   "                         "
+                ;; We are going to return only 25 characters of the
+                ;; address, so make sure it is RFC2047 decoded before
+                ;; taking its substring.  This is important when the address is not on the same line as the name, e.g.:
+                ;; To: =?UTF-8?Q?=C5=A0t=C4=9Bp=C3=A1n_?= =?UTF-8?Q?N=C4=9Bmec?=
+                ;; <stepnem@gmail.com>
+                (setq from (rfc2047-decode-string from))
                 (setq len (length from))
                 (setq mch (string-match "[@%]" from))
                 (format "%25s"
@@ -596,7 +790,7 @@ the message being processed."
                 (setq pos (point))
                 (forward-line 1)
                 (setq str (buffer-substring pos (1- (point))))
-                (while (looking-at "\\s ")
+                (while (looking-at "[ \t]")
                   (setq str (concat str " " 
                                     (buffer-substring (match-end 0)
                                                       (line-end-position))))
@@ -720,7 +914,10 @@ a negative argument means to delete and move backward."
   (unless (numberp count) (setq count 1))
   (let (end del-msg
            (backward (< count 0)))
-    (while (/= count 0)
+    (while (and (/= count 0)
+               ;; Don't waste time if we are at the beginning
+               ;; and trying to go backward.
+               (not (and backward (bobp))))
       (rmail-summary-goto-msg)
       (with-current-buffer rmail-buffer
        (rmail-delete-message)
@@ -730,11 +927,13 @@ a negative argument means to delete and move backward."
                  (save-excursion (beginning-of-line)
                                  (looking-at " *[0-9]+D")))
        (forward-line (if backward -1 1)))
+      (setq count
+           (if (> count 0) (1- count) (1+ count)))
       ;; It looks ugly to move to the empty line at end of buffer.
+      ;; And don't waste time after hitting the end.
       (and (eobp) (not backward)
-          (forward-line -1))
-      (setq count
-           (if (> count 0) (1- count) (1+ count))))))
+          (progn (setq count 0)
+                 (forward-line -1))))))
 
 (defun rmail-summary-delete-backward (&optional count)
   "Delete this message and move to previous nondeleted one.
@@ -745,8 +944,9 @@ a negative argument means to delete and move forward."
   (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))
+  (and n (not (eq n (rmail-summary-msg-number)))
+       ;; Since third arg is t, this only alters summary, not the Rmail buf.
+       (rmail-summary-goto-msg n t t))
   (or (eobp)
       (not (overlay-get rmail-summary-overlay 'face))
       (let ((buffer-read-only nil))
@@ -757,9 +957,9 @@ a negative argument means to delete and move forward."
                (progn (delete-char 1) (insert " ")))
          (delete-char 1)
          (insert "D"))
-       ;; Register a new summary line.
+       ;; Discard cached new summary line.
        (with-current-buffer rmail-buffer
-         (aset rmail-summary-vector (1- n) (rmail-create-summary-line n)))))
+         (aset rmail-summary-vector (1- n) nil))))
   (beginning-of-line))
 
 (defun rmail-summary-update-line (n)
@@ -808,7 +1008,7 @@ Optional prefix ARG means undelete ARG previous messages."
                 (set-buffer rmail-buffer)
               (rmail-pop-to-buffer rmail-buffer))
             (and (rmail-message-deleted-p rmail-current-message)
-                 (rmail-undelete-previous-message))
+                 (rmail-undelete-previous-message 1))
             (if rmail-enable-mime
                 (rmail-pop-to-buffer rmail-buffer))
             (rmail-pop-to-buffer rmail-summary-buffer))
@@ -817,31 +1017,40 @@ Optional prefix ARG means undelete ARG previous messages."
 (defun rmail-summary-undelete-many (&optional n)
   "Undelete all deleted msgs, optional prefix arg N means undelete N prev msgs."
   (interactive "P")
-  (with-current-buffer rmail-buffer
-    (let* ((init-msg (if n rmail-current-message rmail-total-messages))
-          (rmail-current-message init-msg)
-          (n (or n rmail-total-messages))
-          (msgs-undeled 0))
-      (while (and (> rmail-current-message 0)
-                 (< msgs-undeled n))
-       (if (rmail-message-deleted-p rmail-current-message)
-           (progn (rmail-set-attribute rmail-deleted-attr-index nil)
-                  (setq msgs-undeled (1+ msgs-undeled))))
-       (setq rmail-current-message (1- rmail-current-message)))
-      (set-buffer rmail-summary-buffer)
-      (setq rmail-current-message init-msg msgs-undeled 0)
-      (while (and (> rmail-current-message 0)
-                 (< msgs-undeled n))
-       (if (rmail-summary-deleted-p rmail-current-message)
-           (progn (rmail-summary-mark-undeleted rmail-current-message)
-                  (setq msgs-undeled (1+ msgs-undeled))))
-       (setq rmail-current-message (1- rmail-current-message))))
-    (rmail-summary-goto-msg)))
+  (if n
+      (while (and (> n 0) (not (eobp)))
+       (rmail-summary-goto-msg)
+       (let (del-msg)
+         (when (rmail-summary-deleted-p)
+           (with-current-buffer rmail-buffer
+             (rmail-undelete-previous-message 1)
+             (setq del-msg rmail-current-message))
+           (rmail-summary-mark-undeleted del-msg)))
+       (while (and (not (eobp))
+                   (save-excursion (beginning-of-line)
+                                   (looking-at " *[0-9]+ ")))
+         (forward-line 1))
+       (setq n (1- n)))
+    (rmail-summary-goto-msg 1)
+    (dotimes (i rmail-total-messages)
+      (rmail-summary-goto-msg)
+      (let (del-msg)
+       (when (rmail-summary-deleted-p)
+         (with-current-buffer rmail-buffer
+           (rmail-undelete-previous-message 1)
+           (setq del-msg rmail-current-message))
+         (rmail-summary-mark-undeleted del-msg)))
+      (if (not (eobp))
+         (forward-line 1))))
+
+  ;; It looks ugly to move to the empty line at end of buffer.
+  (and (eobp)
+       (forward-line -1)))
 \f
 ;; Rmail Summary mode is suitable only for specially formatted data.
 (put 'rmail-summary-mode 'mode-class 'special)
 
-(defun rmail-summary-mode ()
+(define-derived-mode rmail-summary-mode special-mode "RMAIL Summary"
   "Rmail Summary Mode is invoked from Rmail Mode by using \\<rmail-mode-map>\\[rmail-summary].
 As commands are issued in the summary buffer, they are applied to the
 corresponding mail messages in the rmail buffer.
@@ -864,10 +1073,6 @@ Commands for sorting the summary:
 \\[rmail-summary-sort-by-correspondent] Sort by correspondent.
 \\[rmail-summary-sort-by-lines] Sort by lines.
 \\[rmail-summary-sort-by-labels] Sort by labels."
-  (interactive)
-  (kill-all-local-variables)
-  (setq major-mode 'rmail-summary-mode)
-  (setq mode-name "RMAIL Summary")
   (setq truncate-lines t)
   (setq buffer-read-only t)
   (set-syntax-table text-mode-syntax-table)
@@ -880,8 +1085,7 @@ Commands for sorting the summary:
   (make-local-variable 'revert-buffer-function)
   (make-local-variable 'font-lock-defaults)
   (setq font-lock-defaults '(rmail-summary-font-lock-keywords t))
-  (rmail-summary-enable)
-  (run-mode-hooks 'rmail-summary-mode-hook))
+  (rmail-summary-enable))
 
 ;; Summary features need to be disabled during edit mode.
 (defun rmail-summary-disable ()
@@ -931,57 +1135,59 @@ Search, the `unseen' attribute is restored.")
          (forward-line -1))
       (beginning-of-line)
       (skip-chars-forward " ")
-      (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 t))
-                 (owin (selected-window)))
-             (if isearch-mode
-                 (progn
-                   ;; 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.
-                   (when rmail-summary-put-back-unseen
-                     (rmail-set-attribute rmail-unseen-attr-index t
-                                          rmail-current-message)
-                     (save-excursion
-                       (goto-char rmail-summary-put-back-unseen)
-                       (rmail-summary-mark-seen rmail-current-message t t)))
-                   ;; Arrange to do that later, for the new current message,
-                   ;; if it still has `unseen'.
-                   (setq rmail-summary-put-back-unseen
-                         (if (rmail-message-unseen-p msg-num)
-                             (point))))
-               (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.
-             (rmail-summary-mark-seen msg-num t)
-             (if window
-                 ;; Using save-window-excursion would cause the new value
-                 ;; of point to get lost.
-                 (unwind-protect
-                     (progn
-                       (select-window window)
-                       (rmail-show-message msg-num t))
-                   (select-window owin))
-               (if (buffer-name rmail-buffer)
-                   (with-current-buffer rmail-buffer
-                     (rmail-show-message msg-num t))))
-             ;; In linum mode, the message buffer must be specially
-             ;; updated (Bug#4878).
-             (and (fboundp 'linum-update)
-                  (buffer-name rmail-buffer)
-                  (linum-update rmail-buffer))))
-       (rmail-summary-update-highlight nil)))))
+      ;; If the summary is empty, don't do anything.
+      (unless (eobp)
+       (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 t))
+                   (owin (selected-window)))
+               (if isearch-mode
+                   (progn
+                     ;; 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.
+                     (when rmail-summary-put-back-unseen
+                       (rmail-set-attribute rmail-unseen-attr-index t
+                                            rmail-current-message)
+                       (save-excursion
+                         (goto-char rmail-summary-put-back-unseen)
+                         (rmail-summary-mark-seen rmail-current-message t t)))
+                     ;; Arrange to do that later, for the new current message,
+                     ;; if it still has `unseen'.
+                     (setq rmail-summary-put-back-unseen
+                           (if (rmail-message-unseen-p msg-num)
+                               (point))))
+                 (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.
+               (rmail-summary-mark-seen msg-num t)
+               (if window
+                   ;; Using save-window-excursion would cause the new value
+                   ;; of point to get lost.
+                   (unwind-protect
+                       (progn
+                         (select-window window)
+                         (rmail-show-message msg-num t))
+                     (select-window owin))
+                 (if (buffer-name rmail-buffer)
+                     (with-current-buffer rmail-buffer
+                       (rmail-show-message msg-num t))))
+               ;; In linum mode, the message buffer must be specially
+               ;; updated (Bug#4878).
+               (and (fboundp 'linum-update)
+                    (buffer-name rmail-buffer)
+                    (linum-update rmail-buffer))))
+         (rmail-summary-update-highlight nil))))))
 
 (defun rmail-summary-save-buffer ()
   "Save the buffer associated with this RMAIL summary."
@@ -990,207 +1196,6 @@ Search, the `unseen' attribute is restored.")
     (save-excursion
       (switch-to-buffer rmail-buffer)
       (save-buffer))))
-
-\f
-(if rmail-summary-mode-map
-    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)
-  (define-key rmail-summary-mode-map "e"      'rmail-summary-edit-current-message)
-  (define-key rmail-summary-mode-map "f"      'rmail-summary-forward)
-  (define-key rmail-summary-mode-map "g"      'rmail-summary-get-new-mail)
-  (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)
-  (define-key rmail-summary-mode-map "\e\C-l" 'rmail-summary-by-labels)
-  (define-key rmail-summary-mode-map "\e\C-r" 'rmail-summary-by-recipients)
-  (define-key rmail-summary-mode-map "\e\C-s" 'rmail-summary-by-regexp)
-  ;; `f' for "from".
-  (define-key rmail-summary-mode-map "\e\C-f" 'rmail-summary-by-senders)
-  (define-key rmail-summary-mode-map "\e\C-t" 'rmail-summary-by-topic)
-  (define-key rmail-summary-mode-map "m"      'rmail-summary-mail)
-  (define-key rmail-summary-mode-map "\M-m"   'rmail-summary-retry-failure)
-  (define-key rmail-summary-mode-map "n"      'rmail-summary-next-msg)
-  (define-key rmail-summary-mode-map "\en"    'rmail-summary-next-all)
-  (define-key rmail-summary-mode-map "\e\C-n" 'rmail-summary-next-labeled-message)
-  (define-key rmail-summary-mode-map "o"      'rmail-summary-output)
-  (define-key rmail-summary-mode-map "\C-o"   'rmail-summary-output-as-seen)
-  (define-key rmail-summary-mode-map "p"      'rmail-summary-previous-msg)
-  (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)
-  ;; See rms's comment in rmail.el
-;;;  (define-key rmail-summary-mode-map "\er"    'rmail-summary-search-backward)
-  (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 "x"      'rmail-summary-expunge)
-  (define-key rmail-summary-mode-map "w"      'rmail-summary-output-body)
-  (define-key rmail-summary-mode-map "v"      'rmail-mime)
-  (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)
-  (define-key rmail-summary-mode-map "\177"   'rmail-summary-scroll-msg-down)
-  (define-key rmail-summary-mode-map "?"      'describe-mode)
-  (define-key rmail-summary-mode-map "\C-c\C-n" 'rmail-summary-next-same-subject)
-  (define-key rmail-summary-mode-map "\C-c\C-p" 'rmail-summary-previous-same-subject)
-  (define-key rmail-summary-mode-map "\C-c\C-s\C-d"
-    'rmail-summary-sort-by-date)
-  (define-key rmail-summary-mode-map "\C-c\C-s\C-s"
-    'rmail-summary-sort-by-subject)
-  (define-key rmail-summary-mode-map "\C-c\C-s\C-a"
-    'rmail-summary-sort-by-author)
-  (define-key rmail-summary-mode-map "\C-c\C-s\C-r"
-    'rmail-summary-sort-by-recipient)
-  (define-key rmail-summary-mode-map "\C-c\C-s\C-c"
-    'rmail-summary-sort-by-correspondent)
-  (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-labels)
-  (define-key rmail-summary-mode-map "\C-x\C-s" 'rmail-summary-save-buffer)
-  )
-\f
-;;; Menu bar bindings.
-
-(define-key rmail-summary-mode-map [menu-bar] (make-sparse-keymap))
-
-(define-key rmail-summary-mode-map [menu-bar classify]
-  (cons "Classify" (make-sparse-keymap "Classify")))
-
-(define-key rmail-summary-mode-map [menu-bar classify output-menu]
-  '("Output (Rmail Menu)..." . rmail-summary-output-menu))
-
-(define-key rmail-summary-mode-map [menu-bar classify input-menu]
-  '("Input Rmail File (menu)..." . rmail-input-menu))
-
-(define-key rmail-summary-mode-map [menu-bar classify input-menu]
-  '(nil))
-
-(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..." . rmail-summary-output))
-
-(define-key rmail-summary-mode-map [menu-bar classify output]
-  '("Output as seen..." . rmail-summary-output-as-seen))
-
-(define-key rmail-summary-mode-map [menu-bar classify kill-label]
-  '("Kill Label..." . rmail-summary-kill-label))
-
-(define-key rmail-summary-mode-map [menu-bar classify add-label]
-  '("Add Label..." . rmail-summary-add-label))
-
-(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))
-
-(define-key rmail-summary-mode-map [menu-bar summary recipients]
-  '("By Recipients..." . rmail-summary-by-recipients))
-
-(define-key rmail-summary-mode-map [menu-bar summary topic]
-  '("By Topic..." . rmail-summary-by-topic))
-
-(define-key rmail-summary-mode-map [menu-bar summary regexp]
-  '("By Regexp..." . rmail-summary-by-regexp))
-
-(define-key rmail-summary-mode-map [menu-bar summary all]
-  '("All" . rmail-summary))
-
-(define-key rmail-summary-mode-map [menu-bar mail]
-  (cons "Mail" (make-sparse-keymap "Mail")))
-
-(define-key rmail-summary-mode-map [menu-bar mail rmail-summary-get-new-mail]
-  '("Get New Mail" . rmail-summary-get-new-mail))
-
-(define-key rmail-summary-mode-map [menu-bar mail lambda]
-  '("----"))
-
-(define-key rmail-summary-mode-map [menu-bar mail continue]
-  '("Continue" . rmail-summary-continue))
-
-(define-key rmail-summary-mode-map [menu-bar mail resend]
-  '("Re-send..." . rmail-summary-resend))
-
-(define-key rmail-summary-mode-map [menu-bar mail forward]
-  '("Forward" . rmail-summary-forward))
-
-(define-key rmail-summary-mode-map [menu-bar mail retry]
-  '("Retry" . rmail-summary-retry-failure))
-
-(define-key rmail-summary-mode-map [menu-bar mail reply]
-  '("Reply" . rmail-summary-reply))
-
-(define-key rmail-summary-mode-map [menu-bar mail mail]
-  '("Mail" . rmail-summary-mail))
-
-(define-key rmail-summary-mode-map [menu-bar delete]
-  (cons "Delete" (make-sparse-keymap "Delete")))
-
-(define-key rmail-summary-mode-map [menu-bar delete expunge/save]
-  '("Expunge/Save" . rmail-summary-expunge-and-save))
-
-(define-key rmail-summary-mode-map [menu-bar delete expunge]
-  '("Expunge" . rmail-summary-expunge))
-
-(define-key rmail-summary-mode-map [menu-bar delete undelete]
-  '("Undelete" . rmail-summary-undelete))
-
-(define-key rmail-summary-mode-map [menu-bar delete delete]
-  '("Delete" . rmail-summary-delete-forward))
-
-(define-key rmail-summary-mode-map [menu-bar move]
-  (cons "Move" (make-sparse-keymap "Move")))
-
-(define-key rmail-summary-mode-map [menu-bar move search-back]
-  '("Search Back..." . rmail-summary-search-backward))
-
-(define-key rmail-summary-mode-map [menu-bar move search]
-  '("Search..." . rmail-summary-search))
-
-(define-key rmail-summary-mode-map [menu-bar move previous]
-  '("Previous Nondeleted" . rmail-summary-previous-msg))
-
-(define-key rmail-summary-mode-map [menu-bar move next]
-  '("Next Nondeleted" . rmail-summary-next-msg))
-
-(define-key rmail-summary-mode-map [menu-bar move last]
-  '("Last" . rmail-summary-last-message))
-
-(define-key rmail-summary-mode-map [menu-bar move first]
-  '("First" . rmail-summary-first-message))
-
-(define-key rmail-summary-mode-map [menu-bar move previous]
-  '("Previous" . rmail-summary-previous-all))
-
-(define-key rmail-summary-mode-map [menu-bar move next]
-  '("Next" . rmail-summary-next-all))
 \f
 (defun rmail-summary-mouse-goto-message (event)
   "Select the message whose summary line you click on."
@@ -1198,6 +1203,13 @@ Search, the `unseen' attribute is restored.")
   (goto-char (posn-point (event-end event)))
   (rmail-summary-goto-msg))
 
+(defun rmail-summary-msg-number ()
+  (save-excursion
+    (beginning-of-line)
+    (string-to-number
+     (buffer-substring (point)
+                      (min (point-max) (+ 6 (point)))))))
+
 (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
@@ -1218,6 +1230,10 @@ Returns non-nil if message N was found."
                  (buffer-substring (point)
                                    (min (point-max) (+ 6 (point))))))
         (total (with-current-buffer buf rmail-total-messages)))
+    ;; CURMSG should be nil when there's no current summary message
+    ;; (for instance, if the summary is empty).
+    (if (= curmsg 0)
+       (setq curmsg nil))
     ;; If message number N was specified, find that message's line
     ;; or set message-not-found.
     ;; If N wasn't specified or that message can't be found.
@@ -1238,17 +1254,20 @@ Returns non-nil if message N was found."
                 (setq n curmsg)
                 (setq message-not-found t)
                 (goto-char cur))))
-    (rmail-summary-mark-seen n)
-    (rmail-summary-update-highlight message-not-found)
-    (beginning-of-line)
-    (unless skip-rmail
-      (let ((selwin (selected-window)))
-       (unwind-protect
-           (progn (rmail-pop-to-buffer buf)
-                  (rmail-show-message n))
-         (select-window selwin)
-         ;; The actions above can alter the current buffer.  Preserve it.
-         (set-buffer obuf))))
+    ;; N can be nil now, along with CURMSG,
+    ;; if the summary is empty.
+    (when n
+      (rmail-summary-mark-seen n)
+      (rmail-summary-update-highlight message-not-found)
+      (beginning-of-line)
+      (unless skip-rmail
+       (let ((selwin (selected-window)))
+         (unwind-protect
+             (progn (rmail-pop-to-buffer buf)
+                    (rmail-show-message n))
+           (select-window selwin)
+           ;; The actions above can alter the current buffer.  Preserve it.
+           (set-buffer obuf)))))
     (not message-not-found)))
 
 ;; Update the highlighted line in an rmail summary buffer.
@@ -1286,7 +1305,7 @@ advance to the next message."
                (prog1
                    ;; Is EOB visible in the buffer?
                    (save-excursion
-                     (let ((ht (window-height (selected-window))))
+                     (let ((ht (window-height)))
                        (move-to-window-line (- ht 2))
                        (end-of-line)
                        (eobp)))
@@ -1808,7 +1827,7 @@ If prefix argument REVERSE is non-nil, sorts in reverse order."
   "Sort messages of current Rmail summary by other correspondent.
 This uses either the \"From\", \"Sender\", \"To\", or
 \"Apparently-To\" header, downcased.  Uses the first header not
-excluded by `rmail-dont-reply-to-names'.  If prefix argument
+excluded by `mail-dont-reply-to-names'.  If prefix argument
 REVERSE is non-nil, sorts in reverse order."
   (interactive "P")
   (rmail-sort-from-summary (function rmail-sort-by-correspondent) reverse))
@@ -1846,5 +1865,4 @@ the summary is only showing a subset of messages."
 ;; generated-autoload-file: "rmail.el"
 ;; End:
 
-;; arch-tag: 80b0a27a-a50d-4f37-9466-83d32d1e0ca8
 ;;; rmailsum.el ends here