;;; 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.
(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)
(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)
(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
;; 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)
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))
(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
(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))
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)
(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))))))
\\[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)
(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
;; 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
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 "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 "\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)
(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.
(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))
(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))
(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)
(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)))))
(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))
"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)))
(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 ()
(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.
(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)))
\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
(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."
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.
(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."
(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'."
\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.
(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
(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.
(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)
(funcall sortfun reverse))
(select-window selwin))))
+(provide 'rmailsum)
+
;;; rmailsum.el ends here