Some fixes to follow coding conventions in files maintained by FSF.
[bpt/emacs.git] / lisp / mail / rmailsum.el
index 076a3d2..9bcdd0c 100644 (file)
@@ -1,6 +1,7 @@
 ;;; rmailsum.el --- make summary buffers for the mail reader
 
-;; Copyright (C) 1985, 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
+;; Copyright (C) 1985, 1993, 1994, 1995, 1996, 2000, 2001
+;;   Free Software Foundation, Inc.
 
 ;; Maintainer: FSF
 ;; Keywords: mail
 (require 'rmail)
 
 ;;;###autoload
-(defvar rmail-summary-scroll-between-messages t
-  "*Non-nil means Rmail summary scroll commands move between messages.")
+(defcustom rmail-summary-scroll-between-messages t
+  "*Non-nil means Rmail summary scroll commands move between messages."
+  :type 'boolean
+  :group 'rmail-summary)
 
 ;;;###autoload
-(defvar rmail-summary-line-count-flag t
-  "*Non-nil if Rmail summary should show the number of lines in each message.")
+(defcustom rmail-summary-line-count-flag t
+  "*Non-nil if 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.
     ;; 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.
+    ("{ \\([^\n}]+\\),}" 1 font-lock-comment-face))            ; Labels.
   "Additional expressions to highlight in Rmail Summary mode.")
 
 ;; Entry points for making a summary buffer.
@@ -100,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)
@@ -127,13 +132,16 @@ 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)
@@ -168,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
@@ -202,6 +209,9 @@ nil for FUNCTION means all messages."
        ;; Temporarily, while summary buffer is unfinished,
        ;; we "don't have" a summary.
        (setq rmail-summary-buffer nil)
+       (if rmail-enable-mime
+           (with-current-buffer rmail-view-buffer
+             (setq rmail-summary-buffer nil)))
        (save-excursion
          (let ((rbuf (current-buffer))
                (vbuf rmail-view-buffer)
@@ -267,10 +277,12 @@ nil for FUNCTION means all messages."
     line))
 
 ;;;###autoload
-(defvar rmail-summary-line-decoder (function identity)
+(defcustom rmail-summary-line-decoder (function identity)
   "*Function to decode summary-line.
 
-By default, `identity' is set.")
+By default, `identity' is set."
+  :type 'function
+  :group 'rmail-summary)
 
 (defun rmail-make-summary-line-1 (msg)
   (goto-char (rmail-msgbeg msg))
@@ -333,6 +345,24 @@ By default, `identity' is set.")
                           (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 adresses.
+
+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))
   (concat (save-excursion
@@ -382,19 +412,21 @@ By default, `identity' is set.")
                               (skip-chars-backward " \t")
                               (point)))))
                      len mch lo)
-               (if (string-match (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)
+               (if (string-match 
+                    (or rmail-user-mail-address-regexp 
+                        (concat "^\\("
+                                (regexp-quote (user-login-name))
+                                "\\($\\|@\\)\\|"
+                                (regexp-quote
+                                 ;; Don't lose if run from init file
+                                 ;; where user-mail-address is not
+                                 ;; set yet.
+                                 (or user-mail-address
+                                     (concat (user-login-name) "@"
+                                             (or mail-host-address
+                                                 (system-name)))))
+                                "\\>\\)"))
+                    from)
                    (save-excursion
                      (goto-char (point-min))
                      (if (not (re-search-forward "^To:[ \t]*" nil t))
@@ -576,6 +608,7 @@ 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 backward."
   (interactive "p")
+  (unless (numberp count) (setq count 1))
   (let (end del-msg
            (backward (< count 0)))
     (while (/= count 0)
@@ -639,9 +672,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))))))
 
@@ -695,7 +732,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)
@@ -757,7 +794,7 @@ Search, the `unseen' attribute is restored.")
            (setq rmail-summary-put-back-unseen nil))
 
        (or (eq rmail-current-message msg-num)
-           (let ((window (get-buffer-window rmail-view-buffer))
+           (let ((window (get-buffer-window rmail-view-buffer t))
                  (owin (selected-window)))
              (if isearch-mode
                  (save-excursion
@@ -765,8 +802,9 @@ Search, the `unseen' attribute is restored.")
                    ;; 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.
-                   (rmail-set-attribute "unseen" t
-                                        rmail-current-message)
+                   (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
@@ -802,6 +840,8 @@ Search, the `unseen' attribute is restored.")
     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)
@@ -813,6 +853,7 @@ Search, the `unseen' attribute is restored.")
   (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)
@@ -831,14 +872,15 @@ Search, the `unseen' attribute is restored.")
   (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)
@@ -860,7 +902,7 @@ Search, the `unseen' attribute is restored.")
   (define-key rmail-summary-mode-map "\C-c\C-s\C-l"
     'rmail-summary-sort-by-lines)
   (define-key rmail-summary-mode-map "\C-c\C-s\C-k"
-    'rmail-summary-sort-by-keywords)
+    'rmail-summary-sort-by-labels)
   )
 \f
 ;;; Menu bar bindings.
@@ -882,6 +924,9 @@ Search, the `unseen' attribute is restored.")
 (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))
 
@@ -987,15 +1032,19 @@ Search, the `unseen' attribute is restored.")
 (defvar rmail-summary-overlay nil)
 (put 'rmail-summary-overlay 'permanent-local t)
 
-;; Go to message N in the summary buffer which is current,
-;; and in the corresponding 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.
+(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))
@@ -1100,7 +1149,7 @@ move to the previous message."
   (interactive "P")
   (if (eq dist '-)
       (rmail-summary-scroll-msg-up nil)
-    (let ((rmail-buffer-window (get-buffer-window rmail-buffer)))
+    (let ((rmail-buffer-window (get-buffer-window rmail-view-buffer)))
       (if rmail-buffer-window
          (if (let ((rmail-summary-window (selected-window)))
                (select-window rmail-buffer-window)
@@ -1114,7 +1163,7 @@ move to the previous message."
              (if (not rmail-summary-scroll-between-messages)
                  (error "Beginning of buffer")
                (rmail-summary-previous-msg (or dist 1)))
-           (let ((other-window-scroll-buffer rmail-buffer))
+           (let ((other-window-scroll-buffer rmail-view-buffer))
              (scroll-other-window-down dist)))
        ;; If it isn't visible at all, show the beginning.
        (rmail-summary-beginning-of-message)))))
@@ -1124,15 +1173,15 @@ move to the previous message."
   (interactive)
   (if (and (one-window-p) (not pop-up-frames))
       ;; If there is just one window, put the summary on the top.
-      (let ((buffer rmail-buffer))
+      (let ((buffer rmail-view-buffer))
        (split-window (selected-window) rmail-summary-window-size)
        (select-window (frame-first-window))
-       (pop-to-buffer rmail-buffer)
+       (pop-to-buffer rmail-view-buffer)
        ;; If pop-to-buffer did not use that window, delete that
        ;; window.  (This can happen if it uses another frame.)
        (or (eq buffer (window-buffer (next-window (frame-first-window))))
            (delete-other-windows)))
-    (pop-to-buffer rmail-buffer))
+    (pop-to-buffer rmail-view-buffer))
   (beginning-of-buffer)
   (pop-to-buffer rmail-summary-buffer))
 
@@ -1157,7 +1206,7 @@ move to the previous message."
   "Kill and wipe away Rmail summary, remaining within Rmail."
   (interactive)
   (save-excursion (set-buffer rmail-buffer) (setq rmail-summary-buffer nil))
-  (let ((local-rmail-buffer rmail-buffer))
+  (let ((local-rmail-buffer rmail-view-buffer))
     (kill-buffer (current-buffer))
     ;; Delete window if not only one.
     (if (not (eq (selected-window) (next-window nil 'no-minibuf)))
@@ -1170,7 +1219,8 @@ move 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 ()
@@ -1178,20 +1228,28 @@ move 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.
@@ -1309,12 +1367,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)))
@@ -1347,6 +1405,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
@@ -1357,9 +1421,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."
@@ -1376,14 +1438,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.
@@ -1395,9 +1455,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."
@@ -1415,9 +1473,7 @@ 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'."
@@ -1431,20 +1487,54 @@ 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))
+    (while (< i n)
+      (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.
@@ -1459,16 +1549,6 @@ 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 files
@@ -1488,6 +1568,18 @@ The variables `rmail-secondary-file-directory' and
       (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.
 
@@ -1527,14 +1619,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)
@@ -1546,4 +1638,6 @@ KEYWORDS is a comma-separated list of labels."
               (funcall sortfun reverse))
       (select-window selwin))))
 
+(provide 'rmailsum)
+
 ;;; rmailsum.el ends here