*** empty log message ***
[bpt/emacs.git] / lisp / mail / rmailsum.el
CommitLineData
76550a57 1;;; rmailsum.el --- make summary buffers for the mail reader
aae56ea7 2
36c5e617
GM
3;; Copyright (C) 1985, 1993, 1994, 1995, 1996, 2000
4;; Free Software Foundation, Inc.
9750e079 5
e5167999 6;; Maintainer: FSF
d7b4d18f 7;; Keywords: mail
e5167999 8
4d4d11cc
JB
9;; This file is part of GNU Emacs.
10
11;; GNU Emacs is free software; you can redistribute it and/or modify
12;; it under the terms of the GNU General Public License as published by
e5167999 13;; the Free Software Foundation; either version 2, or (at your option)
4d4d11cc
JB
14;; any later version.
15
16;; GNU Emacs is distributed in the hope that it will be useful,
17;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19;; GNU General Public License for more details.
20
21;; You should have received a copy of the GNU General Public License
b578f267
EN
22;; along with GNU Emacs; see the file COPYING. If not, write to the
23;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24;; Boston, MA 02111-1307, USA.
4d4d11cc 25
aae56ea7
ER
26;;; Commentary:
27
d41d75fb
RS
28;; Extended by Bob Weiner of Motorola
29;; Provided all commands from rmail-mode in rmail-summary-mode and made key
30;; bindings in both modes wholly compatible.
31
aae56ea7
ER
32;;; Code:
33
6e626f7e
RS
34;; For rmail-select-summary
35(require 'rmail)
36
be2e861f 37;;;###autoload
0a01a04e
RS
38(defcustom rmail-summary-scroll-between-messages t
39 "*Non-nil means Rmail summary scroll commands move between messages."
40 :type 'boolean
41 :group 'rmail-summary)
be2e861f 42
ea7bddc4 43;;;###autoload
0a01a04e
RS
44(defcustom rmail-summary-line-count-flag t
45 "*Non-nil if Rmail summary should show the number of lines in each message."
46 :type 'boolean
47 :group 'rmail-summary)
ea7bddc4 48
1a6bc985 49(defvar rmail-summary-font-lock-keywords
be94c30c
SM
50 '(("^....D.*" . font-lock-string-face) ; Deleted.
51 ("^....-.*" . font-lock-type-face) ; Unread.
1a6bc985
RS
52 ;; Neither of the below will be highlighted if either of the above are:
53 ("^....[^D-] \\(......\\)" 1 font-lock-keyword-face) ; Date.
af595444 54 ("{ \\([^\n}]+\\),}" 1 font-lock-comment-face)) ; Labels.
1a6bc985
RS
55 "Additional expressions to highlight in Rmail Summary mode.")
56
d41d75fb 57;; Entry points for making a summary buffer.
4d4d11cc 58
d41d75fb
RS
59;; Regenerate the contents of the summary
60;; using the same selection criterion as last time.
61;; M-x revert-buffer in a summary buffer calls this function.
62(defun rmail-update-summary (&rest ignore)
63 (apply (car rmail-summary-redo) (cdr rmail-summary-redo)))
4d4d11cc 64
d2288651 65;;;###autoload
4d4d11cc
JB
66(defun rmail-summary ()
67 "Display a summary of all messages, one line per message."
68 (interactive)
d41d75fb 69 (rmail-new-summary "All" '(rmail-summary) nil))
4d4d11cc 70
d2288651 71;;;###autoload
4d4d11cc
JB
72(defun rmail-summary-by-labels (labels)
73 "Display a summary of all messages with one or more LABELS.
74LABELS should be a string containing the desired labels, separated by commas."
75 (interactive "sLabels to summarize by: ")
76 (if (string= labels "")
77 (setq labels (or rmail-last-multi-labels
78 (error "No label specified"))))
79 (setq rmail-last-multi-labels labels)
80 (rmail-new-summary (concat "labels " labels)
d41d75fb 81 (list 'rmail-summary-by-labels labels)
4d4d11cc
JB
82 'rmail-message-labels-p
83 (concat ", \\(" (mail-comma-list-regexp labels) "\\),")))
84
d2288651 85;;;###autoload
4d4d11cc
JB
86(defun rmail-summary-by-recipients (recipients &optional primary-only)
87 "Display a summary of all messages with the given RECIPIENTS.
88Normally checks the To, From and Cc fields of headers;
89but if PRIMARY-ONLY is non-nil (prefix arg given),
90 only look in the To and From fields.
d41d75fb 91RECIPIENTS is a string of regexps separated by commas."
4d4d11cc
JB
92 (interactive "sRecipients to summarize by: \nP")
93 (rmail-new-summary
94 (concat "recipients " recipients)
d41d75fb 95 (list 'rmail-summary-by-recipients recipients primary-only)
4d4d11cc
JB
96 'rmail-message-recipients-p
97 (mail-comma-list-regexp recipients) primary-only))
98
d2288651 99;;;###autoload
4d4d11cc
JB
100(defun rmail-summary-by-regexp (regexp)
101 "Display a summary of all messages according to regexp REGEXP.
102If the regular expression is found in the header of the message
103\(including in the date and other lines, as well as the subject line),
104Emacs will list the header line in the RMAIL-summary."
105 (interactive "sRegexp to summarize by: ")
106 (if (string= regexp "")
107 (setq regexp (or rmail-last-regexp
d41d75fb 108 (error "No regexp specified."))))
4d4d11cc
JB
109 (setq rmail-last-regexp regexp)
110 (rmail-new-summary (concat "regexp " regexp)
d41d75fb 111 (list 'rmail-summary-by-regexp regexp)
4d4d11cc
JB
112 'rmail-message-regexp-p
113 regexp))
114
d41d75fb
RS
115;; rmail-summary-by-topic
116;; 1989 R.A. Schnitzler
117
d2288651 118;;;###autoload
d41d75fb
RS
119(defun rmail-summary-by-topic (subject &optional whole-message)
120 "Display a summary of all messages with the given SUBJECT.
121Normally checks the Subject field of headers;
122but if WHOLE-MESSAGE is non-nil (prefix arg given),
123 look in the whole message.
124SUBJECT is a string of regexps separated by commas."
125 (interactive "sTopics to summarize by: \nP")
126 (rmail-new-summary
127 (concat "about " subject)
128 (list 'rmail-summary-by-topic subject whole-message)
129 'rmail-message-subject-p
130 (mail-comma-list-regexp subject) whole-message))
131
132(defun rmail-message-subject-p (msg subject &optional whole-message)
133 (save-restriction
134 (goto-char (rmail-msgbeg msg))
10a0a250 135 (search-forward "\n*** EOOH ***\n" (rmail-msgend msg) 'move)
d41d75fb
RS
136 (narrow-to-region
137 (point)
e90b6d92 138 (progn (search-forward (if whole-message "\^_" "\n\n")) (point)))
d41d75fb
RS
139 (goto-char (point-min))
140 (if whole-message (re-search-forward subject nil t)
141 (string-match subject (or (mail-fetch-field "Subject") "")) )))
cad1e93b 142
d2288651 143;;;###autoload
cad1e93b
RS
144(defun rmail-summary-by-senders (senders)
145 "Display a summary of all messages with the given SENDERS.
146SENDERS is a string of names separated by commas."
147 (interactive "sSenders to summarize by: ")
148 (rmail-new-summary
149 (concat "senders " senders)
84fa8eb5 150 (list 'rmail-summary-by-senders senders)
cad1e93b
RS
151 'rmail-message-senders-p
152 (mail-comma-list-regexp senders)))
153
154(defun rmail-message-senders-p (msg senders)
155 (save-restriction
156 (goto-char (rmail-msgbeg msg))
157 (search-forward "\n*** EOOH ***\n")
158 (narrow-to-region (point) (progn (search-forward "\n\n") (point)))
159 (string-match senders (or (mail-fetch-field "From") ""))))
4d4d11cc 160\f
d41d75fb
RS
161;; General making of a summary buffer.
162
163(defvar rmail-summary-symbol-number 0)
164
165(defun rmail-new-summary (description redo-form function &rest args)
4d4d11cc
JB
166 "Create a summary of selected messages.
167DESCRIPTION makes part of the mode line of the summary buffer.
168For each message, FUNCTION is applied to the message number and ARGS...
169and if the result is non-nil, that message is included.
170nil for FUNCTION means all messages."
171 (message "Computing summary lines...")
d41d75fb
RS
172 (let (sumbuf mesg was-in-summary)
173 (save-excursion
174 ;; Go to the Rmail buffer.
175 (if (eq major-mode 'rmail-summary-mode)
176 (progn
177 (setq was-in-summary t)
178 (set-buffer rmail-buffer)))
179 ;; Find its summary buffer, or make one.
deb5848d
RS
180 (setq sumbuf
181 (if (and rmail-summary-buffer
182 (buffer-name rmail-summary-buffer))
183 rmail-summary-buffer
184 (generate-new-buffer (concat (buffer-name) "-summary"))))
d41d75fb 185 (setq mesg rmail-current-message)
d41d75fb
RS
186 ;; Filter the messages; make or get their summary lines.
187 (let ((summary-msgs ())
188 (new-summary-line-count 0))
189 (let ((msgnum 1)
36f41915
KH
190 (buffer-read-only nil)
191 (old-min (point-min-marker))
192 (old-max (point-max-marker)))
193 ;; Can't use save-restriction here; that doesn't work if we
194 ;; plan to modify text outside the original restriction.
195 (save-excursion
196 (widen)
197 (goto-char (point-min))
198 (while (>= rmail-total-messages msgnum)
199 (if (or (null function)
200 (apply function (cons msgnum args)))
201 (setq summary-msgs
202 (cons (cons msgnum (rmail-make-summary-line msgnum))
203 summary-msgs)))
204 (setq msgnum (1+ msgnum)))
205 (setq summary-msgs (nreverse summary-msgs)))
206 (narrow-to-region old-min old-max))
deb5848d
RS
207 ;; Temporarily, while summary buffer is unfinished,
208 ;; we "don't have" a summary.
209 (setq rmail-summary-buffer nil)
210 (save-excursion
211 (let ((rbuf (current-buffer))
db56d71e 212 (vbuf rmail-view-buffer)
deb5848d
RS
213 (total rmail-total-messages))
214 (set-buffer sumbuf)
215 ;; Set up the summary buffer's contents.
216 (let ((buffer-read-only nil))
217 (erase-buffer)
218 (while summary-msgs
219 (princ (cdr (car summary-msgs)) sumbuf)
220 (setq summary-msgs (cdr summary-msgs)))
221 (goto-char (point-min)))
222 ;; Set up the rest of its state and local variables.
223 (setq buffer-read-only t)
224 (rmail-summary-mode)
225 (make-local-variable 'minor-mode-alist)
73d8f1de 226 (setq minor-mode-alist (list (list t (concat ": " description))))
deb5848d 227 (setq rmail-buffer rbuf
db56d71e 228 rmail-view-buffer vbuf
deb5848d
RS
229 rmail-summary-redo redo-form
230 rmail-total-messages total))))
231 (setq rmail-summary-buffer sumbuf))
d41d75fb
RS
232 ;; Now display the summary buffer and go to the right place in it.
233 (or was-in-summary
6e626f7e
RS
234 (progn
235 (if (and (one-window-p)
236 pop-up-windows (not pop-up-frames))
237 ;; If there is just one window, put the summary on the top.
238 (progn
239 (split-window (selected-window) rmail-summary-window-size)
240 (select-window (next-window (frame-first-window)))
241 (pop-to-buffer sumbuf)
242 ;; If pop-to-buffer did not use that window, delete that
243 ;; window. (This can happen if it uses another frame.)
244 (if (not (eq sumbuf (window-buffer (frame-first-window))))
245 (delete-other-windows)))
246 (pop-to-buffer sumbuf))
247 (set-buffer rmail-buffer)
248 ;; This is how rmail makes the summary buffer reappear.
249 ;; We do this here to make the window the proper size.
250 (rmail-select-summary nil)
251 (set-buffer rmail-summary-buffer)))
d41d75fb 252 (rmail-summary-goto-msg mesg t t)
88aabab3 253 (rmail-summary-construct-io-menu)
d41d75fb
RS
254 (message "Computing summary lines...done")))
255\f
256;; Low levels of generating a summary.
4d4d11cc
JB
257
258(defun rmail-make-summary-line (msg)
259 (let ((line (or (aref rmail-summary-vector (1- msg))
260 (progn
261 (setq new-summary-line-count
262 (1+ new-summary-line-count))
263 (if (zerop (% new-summary-line-count 10))
264 (message "Computing summary lines...%d"
265 new-summary-line-count))
266 (rmail-make-summary-line-1 msg)))))
267 ;; Fix up the part of the summary that says "deleted" or "unseen".
268 (aset line 4
269 (if (rmail-message-deleted-p msg) ?\D
270 (if (= ?0 (char-after (+ 3 (rmail-msgbeg msg))))
271 ?\- ?\ )))
272 line))
273
db56d71e 274;;;###autoload
0a01a04e 275(defcustom rmail-summary-line-decoder (function identity)
db56d71e
KH
276 "*Function to decode summary-line.
277
0a01a04e
RS
278By default, `identity' is set."
279 :type 'function
280 :group 'rmail-summary)
db56d71e 281
4d4d11cc
JB
282(defun rmail-make-summary-line-1 (msg)
283 (goto-char (rmail-msgbeg msg))
284 (let* ((lim (save-excursion (forward-line 2) (point)))
285 pos
286 (labels
287 (progn
288 (forward-char 3)
289 (concat
290; (if (save-excursion (re-search-forward ",answered," lim t))
291; "*" "")
292; (if (save-excursion (re-search-forward ",filed," lim t))
293; "!" "")
294 (if (progn (search-forward ",,") (eolp))
295 ""
296 (concat "{"
297 (buffer-substring (point)
298 (progn (end-of-line) (point)))
299 "} ")))))
300 (line
301 (progn
302 (forward-line 1)
303 (if (looking-at "Summary-line: ")
304 (progn
305 (goto-char (match-end 0))
306 (setq line
307 (buffer-substring (point)
308 (progn (forward-line 1) (point)))))))))
309 ;; Obsolete status lines lacking a # should be flushed.
310 (and line
311 (not (string-match "#" line))
312 (progn
313 (delete-region (point)
314 (progn (forward-line -1) (point)))
315 (setq line nil)))
316 ;; If we didn't get a valid status line from the message,
317 ;; make a new one and put it in the message.
318 (or line
319 (let* ((case-fold-search t)
320 (next (rmail-msgend msg))
321 (beg (if (progn (goto-char (rmail-msgbeg msg))
322 (search-forward "\n*** EOOH ***\n" next t))
323 (point)
324 (forward-line 1)
325 (point)))
326 (end (progn (search-forward "\n\n" nil t) (point))))
327 (save-restriction
328 (narrow-to-region beg end)
329 (goto-char beg)
330 (setq line (rmail-make-basic-summary-line)))
331 (goto-char (rmail-msgbeg msg))
332 (forward-line 2)
333 (insert "Summary-line: " line)))
334 (setq pos (string-match "#" line))
335 (aset rmail-summary-vector (1- msg)
db56d71e
KH
336 (funcall rmail-summary-line-decoder
337 (concat (format "%4d " msg)
338 (substring line 0 pos)
339 labels
340 (substring line (1+ pos)))))
341 ))
4d4d11cc 342
36c5e617
GM
343;;;###autoload
344(defcustom rmail-user-mail-address-regexp nil
345 "*Regexp matching user mail addresses.
346If non-nil, this variable is used to identify the correspondent
347when receiving new mail. If it matches the address of the sender,
348the recipient is taken as correspondent of a mail.
349If nil \(default value\), your `user-login-name' and `user-mail-address'
350are used to exclude yourself as correspondent.
351
352Usually you don't have to set this variable, except if you collect mails
353sent by you under different user names.
354Then it should be a regexp matching your mail adresses.
355
356Setting this variable has an effect only before reading a mail."
357 :type '(choice (const :tag "None" nil) regexp)
358 :group 'rmail-retrieve
359 :version "21.1")
360
4d4d11cc
JB
361(defun rmail-make-basic-summary-line ()
362 (goto-char (point-min))
363 (concat (save-excursion
364 (if (not (re-search-forward "^Date:" nil t))
365 " "
366 (cond ((re-search-forward "\\([^0-9:]\\)\\([0-3]?[0-9]\\)\\([- \t_]+\\)\\([adfjmnos][aceopu][bcglnprtvy]\\)"
367 (save-excursion (end-of-line) (point)) t)
368 (format "%2d-%3s"
369 (string-to-int (buffer-substring
370 (match-beginning 2)
371 (match-end 2)))
372 (buffer-substring
373 (match-beginning 4) (match-end 4))))
374 ((re-search-forward "\\([^a-z]\\)\\([adfjmnos][acepou][bcglnprtvy]\\)\\([-a-z \t_]*\\)\\([0-9][0-9]?\\)"
375 (save-excursion (end-of-line) (point)) t)
376 (format "%2d-%3s"
377 (string-to-int (buffer-substring
378 (match-beginning 4)
379 (match-end 4)))
380 (buffer-substring
381 (match-beginning 2) (match-end 2))))
15065a0f
MB
382 ((re-search-forward "\\(19\\|20\\)\\([0-9][0-9]\\)-\\([01][0-9]\\)-\\([0-3][0-9]\\)"
383 (save-excursion (end-of-line) (point)) t)
384 (format "%2s%2s%2s"
385 (buffer-substring
386 (match-beginning 2) (match-end 2))
387 (buffer-substring
388 (match-beginning 3) (match-end 3))
389 (buffer-substring
390 (match-beginning 4) (match-end 4))))
4d4d11cc
JB
391 (t "??????"))))
392 " "
393 (save-excursion
394 (if (not (re-search-forward "^From:[ \t]*" nil t))
395 " "
396 (let* ((from (mail-strip-quoted-names
397 (buffer-substring
398 (1- (point))
4f5d303b
RS
399 ;; Get all the lines of the From field
400 ;; so that we get a whole comment if there is one,
401 ;; so that mail-strip-quoted-names can discard it.
402 (let ((opoint (point)))
403 (while (progn (forward-line 1)
404 (looking-at "[ \t]")))
405 ;; Back up over newline, then trailing spaces or tabs
406 (forward-char -1)
407 (skip-chars-backward " \t")
408 (point)))))
409 len mch lo)
36c5e617
GM
410 (if (string-match
411 (or rmail-user-mail-address-regexp
412 (concat "^\\("
413 (regexp-quote (user-login-name))
414 "\\($\\|@\\)\\|"
415 (regexp-quote
416 ;; Don't lose if run from init file
417 ;; where user-mail-address is not
418 ;; set yet.
419 (or user-mail-address
420 (concat (user-login-name) "@"
421 (or mail-host-address
422 (system-name)))))
423 "\\>\\)"))
424 from)
4d4d11cc
JB
425 (save-excursion
426 (goto-char (point-min))
427 (if (not (re-search-forward "^To:[ \t]*" nil t))
428 nil
429 (setq from
430 (concat "to: "
431 (mail-strip-quoted-names
432 (buffer-substring
433 (point)
434 (progn (end-of-line)
435 (skip-chars-backward " \t")
436 (point)))))))))
437 (setq len (length from))
438 (setq mch (string-match "[@%]" from))
439 (format "%25s"
440 (if (or (not mch) (<= len 25))
441 (substring from (max 0 (- len 25)))
442 (substring from
95412165
RS
443 (setq lo (cond ((< (- mch 14) 0) 0)
444 ((< len (+ mch 11))
4d4d11cc 445 (- len 25))
95412165 446 (t (- mch 14))))
4d4d11cc 447 (min len (+ lo 25))))))))
4f21aa66 448 (if rmail-summary-line-count-flag
ea7bddc4
RS
449 (save-excursion
450 (save-restriction
451 (widen)
452 (let ((beg (rmail-msgbeg msgnum))
453 (end (rmail-msgend msgnum))
454 lines)
455 (save-excursion
456 (goto-char beg)
457 ;; Count only lines in the reformatted header,
458 ;; if we have reformatted it.
459 (search-forward "\n*** EOOH ***\n" end t)
460 (setq lines (count-lines (point) end)))
461 (format (cond
462 ((<= lines 9) " [%d]")
463 ((<= lines 99) " [%d]")
464 ((<= lines 999) " [%3d]")
465 (t "[%d]"))
466 lines))))
467 " ")
972a769b 468 " #" ;The # is part of the format.
4d4d11cc
JB
469 (if (re-search-forward "^Subject:" nil t)
470 (progn (skip-chars-forward " \t")
471 (buffer-substring (point)
472 (progn (end-of-line)
473 (point))))
474 (re-search-forward "[\n][\n]+" nil t)
475 (buffer-substring (point) (progn (end-of-line) (point))))
476 "\n"))
d41d75fb
RS
477\f
478;; Simple motion in a summary buffer.
4d4d11cc
JB
479
480(defun rmail-summary-next-all (&optional number)
481 (interactive "p")
bb694792 482 (forward-line (if number number 1))
cc101382
RS
483 ;; It doesn't look nice to move forward past the last message line.
484 (and (eobp) (> number 0)
485 (forward-line -1))
bb694792 486 (display-buffer rmail-buffer))
4d4d11cc
JB
487
488(defun rmail-summary-previous-all (&optional number)
489 (interactive "p")
bb694792 490 (forward-line (- (if number number 1)))
cc101382
RS
491 ;; It doesn't look nice to move forward past the last message line.
492 (and (eobp) (< number 0)
493 (forward-line -1))
bb694792 494 (display-buffer rmail-buffer))
4d4d11cc
JB
495
496(defun rmail-summary-next-msg (&optional number)
d41d75fb
RS
497 "Display next non-deleted msg from rmail file.
498With optional prefix argument NUMBER, moves forward this number of non-deleted
499messages, or backward if NUMBER is negative."
4d4d11cc
JB
500 (interactive "p")
501 (forward-line 0)
b37767e7 502 (and (> number 0) (end-of-line))
4d4d11cc
JB
503 (let ((count (if (< number 0) (- number) number))
504 (search (if (> number 0) 're-search-forward 're-search-backward))
d41d75fb
RS
505 (non-del-msg-found nil))
506 (while (and (> count 0) (setq non-del-msg-found
682ac5eb 507 (or (funcall search "^....[^D]" nil t)
d41d75fb 508 non-del-msg-found)))
bb694792 509 (setq count (1- count))))
b37767e7 510 (beginning-of-line)
db56d71e
KH
511 (display-buffer rmail-view-buffer)
512 )
4d4d11cc
JB
513
514(defun rmail-summary-previous-msg (&optional number)
515 (interactive "p")
516 (rmail-summary-next-msg (- (if number number 1))))
517
d41d75fb
RS
518(defun rmail-summary-next-labeled-message (n labels)
519 "Show next message with LABEL. Defaults to last labels used.
520With prefix argument N moves forward N messages with these labels."
521 (interactive "p\nsMove to next msg with labels: ")
d69006df
KH
522 (let (msg)
523 (save-excursion
524 (set-buffer rmail-buffer)
525 (rmail-next-labeled-message n labels)
526 (setq msg rmail-current-message))
527 (rmail-summary-goto-msg msg)))
d41d75fb
RS
528
529(defun rmail-summary-previous-labeled-message (n labels)
530 "Show previous message with LABEL. Defaults to last labels used.
531With prefix argument N moves backward N messages with these labels."
532 (interactive "p\nsMove to previous msg with labels: ")
d69006df
KH
533 (let (msg)
534 (save-excursion
535 (set-buffer rmail-buffer)
536 (rmail-previous-labeled-message n labels)
537 (setq msg rmail-current-message))
538 (rmail-summary-goto-msg msg)))
71d97b56
RS
539
540(defun rmail-summary-next-same-subject (n)
541 "Go to the next message in the summary having the same subject.
542With prefix argument N, do this N times.
543If N is negative, go backwards."
544 (interactive "p")
545 (let (subject search-regexp i found
546 (forward (> n 0)))
547 (save-excursion
548 (set-buffer rmail-buffer)
549 (setq subject (mail-fetch-field "Subject"))
71d97b56
RS
550 (setq i rmail-current-message))
551 (if (string-match "Re:[ \t]*" subject)
552 (setq subject (substring subject (match-end 0))))
5be36e20
RS
553 (setq search-regexp (concat "^Subject: *\\(Re: *\\)?"
554 (regexp-quote subject)
555 "\n"))
71d97b56
RS
556 (save-excursion
557 (while (and (/= n 0)
558 (if forward
559 (not (eobp))
560 (not (bobp))))
561 (let (done)
562 (while (and (not done)
563 (if forward
564 (not (eobp))
565 (not (bobp))))
566 ;; Advance thru summary.
567 (forward-line (if forward 1 -1))
568 ;; Get msg number of this line.
569 (setq i (string-to-int
570 (buffer-substring (point)
571 (min (point-max) (+ 5 (point))))))
572 ;; See if that msg has desired subject.
573 (save-excursion
574 (set-buffer rmail-buffer)
575 (save-restriction
576 (widen)
577 (goto-char (rmail-msgbeg i))
578 (search-forward "\n*** EOOH ***\n")
579 (let ((beg (point)) end)
580 (search-forward "\n\n")
581 (setq end (point))
582 (goto-char beg)
583 (setq done (re-search-forward search-regexp end t))))))
584 (if done (setq found i)))
585 (setq n (if forward (1- n) (1+ n)))))
586 (if found
587 (rmail-summary-goto-msg found)
588 (error "No %s message with same subject"
589 (if forward "following" "previous")))))
590
591(defun rmail-summary-previous-same-subject (n)
592 "Go to the previous message in the summary having the same subject.
593With prefix argument N, do this N times.
594If N is negative, go forwards instead."
595 (interactive "p")
596 (rmail-summary-next-same-subject (- n)))
d41d75fb
RS
597\f
598;; Delete and undelete summary commands.
599
93cba994 600(defun rmail-summary-delete-forward (&optional count)
d41d75fb
RS
601 "Delete this message and move to next nondeleted one.
602Deleted messages stay in the file until the \\[rmail-expunge] command is given.
93cba994
RS
603A prefix argument serves as a repeat count;
604a negative argument means to delete and move backward."
605 (interactive "p")
ecb4dd9a 606 (unless (numberp count) (setq count 1))
93cba994
RS
607 (let (end del-msg
608 (backward (< count 0)))
609 (while (/= count 0)
610 (rmail-summary-goto-msg)
611 (with-current-buffer rmail-buffer
612 (rmail-delete-message)
613 (setq del-msg rmail-current-message))
92a38267
RS
614 (rmail-summary-mark-deleted del-msg)
615 (while (and (not (if backward (bobp) (eobp)))
94eeb96a 616 (save-excursion (beginning-of-line)
7434015f 617 (looking-at " *[0-9]+D")))
cdbea8ca
RS
618 (forward-line (if backward -1 1)))
619 ;; It looks ugly to move to the empty line at end of buffer.
620 (and (eobp) (not backward)
93cba994
RS
621 (forward-line -1))
622 (setq count
623 (if (> count 0) (1- count) (1+ count))))))
4d4d11cc 624
93cba994 625(defun rmail-summary-delete-backward (&optional count)
d41d75fb 626 "Delete this message and move to previous nondeleted one.
93cba994
RS
627Deleted messages stay in the file until the \\[rmail-expunge] command is given.
628A prefix argument serves as a repeat count;
629a negative argument means to delete and move forward."
630 (interactive "p")
631 (rmail-summary-delete-forward (- count)))
4d4d11cc 632
d41d75fb 633(defun rmail-summary-mark-deleted (&optional n undel)
85bd1ac6 634 ;; Since third arg is t, this only alters the summary, not the Rmail buf.
fedc33f7
RS
635 (and n (rmail-summary-goto-msg n t t))
636 (or (eobp)
4fb6f90f 637 (not (overlay-get rmail-summary-overlay 'face))
fedc33f7
RS
638 (let ((buffer-read-only nil))
639 (skip-chars-forward " ")
640 (skip-chars-forward "[0-9]")
641 (if undel
642 (if (looking-at "D")
643 (progn (delete-char 1) (insert " ")))
644 (delete-char 1)
645 (insert "D"))))
d41d75fb
RS
646 (beginning-of-line))
647
648(defun rmail-summary-mark-undeleted (n)
649 (rmail-summary-mark-deleted n t))
650
651(defun rmail-summary-deleted-p (&optional n)
652 (save-excursion
653 (and n (rmail-summary-goto-msg n nil t))
654 (skip-chars-forward " ")
655 (skip-chars-forward "[0-9]")
656 (looking-at "D")))
4d4d11cc 657
d41d75fb
RS
658(defun rmail-summary-undelete (&optional arg)
659 "Undelete current message.
660Optional prefix ARG means undelete ARG previous messages."
661 (interactive "p")
662 (if (/= arg 1)
663 (rmail-summary-undelete-many arg)
5ed1243c
RS
664 (let ((buffer-read-only nil)
665 (opoint (point)))
d41d75fb
RS
666 (end-of-line)
667 (cond ((re-search-backward "\\(^ *[0-9]*\\)\\(D\\)" nil t)
668 (replace-match "\\1 ")
669 (rmail-summary-goto-msg)
670 (pop-to-buffer rmail-buffer)
671 (and (rmail-message-deleted-p rmail-current-message)
672 (rmail-undelete-previous-message))
5ed1243c
RS
673 (pop-to-buffer rmail-summary-buffer))
674 (t (goto-char opoint))))))
d41d75fb
RS
675
676(defun rmail-summary-undelete-many (&optional n)
677 "Undelete all deleted msgs, optional prefix arg N means undelete N prev msgs."
678 (interactive "P")
679 (save-excursion
680 (set-buffer rmail-buffer)
681 (let* ((init-msg (if n rmail-current-message rmail-total-messages))
682 (rmail-current-message init-msg)
683 (n (or n rmail-total-messages))
684 (msgs-undeled 0))
685 (while (and (> rmail-current-message 0)
686 (< msgs-undeled n))
687 (if (rmail-message-deleted-p rmail-current-message)
688 (progn (rmail-set-attribute "deleted" nil)
689 (setq msgs-undeled (1+ msgs-undeled))))
690 (setq rmail-current-message (1- rmail-current-message)))
691 (set-buffer rmail-summary-buffer)
692 (setq rmail-current-message init-msg msgs-undeled 0)
693 (while (and (> rmail-current-message 0)
694 (< msgs-undeled n))
695 (if (rmail-summary-deleted-p rmail-current-message)
696 (progn (rmail-summary-mark-undeleted rmail-current-message)
697 (setq msgs-undeled (1+ msgs-undeled))))
698 (setq rmail-current-message (1- rmail-current-message))))
699 (rmail-summary-goto-msg)))
700\f
4d4d11cc
JB
701;; Rmail Summary mode is suitable only for specially formatted data.
702(put 'rmail-summary-mode 'mode-class 'special)
703
704(defun rmail-summary-mode ()
d41d75fb
RS
705 "Rmail Summary Mode is invoked from Rmail Mode by using \\<rmail-mode-map>\\[rmail-summary].
706As commands are issued in the summary buffer, they are applied to the
707corresponding mail messages in the rmail buffer.
708
709All normal editing commands are turned off.
9cd78473
RS
710Instead, nearly all the Rmail mode commands are available,
711though many of them move only among the messages in the summary.
d41d75fb 712
9cd78473
RS
713These additional commands exist:
714
715\\[rmail-summary-undelete-many] Undelete all or prefix arg deleted messages.
716\\[rmail-summary-wipe] Delete the summary and go to the Rmail buffer.
717
718Commands for sorting the summary:
719
720\\[rmail-summary-sort-by-date] Sort by date.
721\\[rmail-summary-sort-by-subject] Sort by subject.
722\\[rmail-summary-sort-by-author] Sort by author.
723\\[rmail-summary-sort-by-recipient] Sort by recipient.
724\\[rmail-summary-sort-by-correspondent] Sort by correspondent.
ebdf372b
KH
725\\[rmail-summary-sort-by-lines] Sort by lines.
726\\[rmail-summary-sort-by-keywords] Sort by keywords."
4d4d11cc
JB
727 (interactive)
728 (kill-all-local-variables)
4d4d11cc
JB
729 (setq major-mode 'rmail-summary-mode)
730 (setq mode-name "RMAIL Summary")
4d4d11cc
JB
731 (setq truncate-lines t)
732 (setq buffer-read-only t)
733 (set-syntax-table text-mode-syntax-table)
d41d75fb 734 (make-local-variable 'rmail-buffer)
db56d71e 735 (make-local-variable 'rmail-view-buffer)
d41d75fb
RS
736 (make-local-variable 'rmail-total-messages)
737 (make-local-variable 'rmail-current-message)
738 (setq rmail-current-message nil)
739 (make-local-variable 'rmail-summary-redo)
740 (setq rmail-summary-redo nil)
741 (make-local-variable 'revert-buffer-function)
c28baa2a 742 (make-local-hook 'post-command-hook)
d16df573
SM
743 (make-local-variable 'font-lock-defaults)
744 (setq font-lock-defaults '(rmail-summary-font-lock-keywords t))
0732dfa5 745 (rmail-summary-enable)
4d4d11cc
JB
746 (run-hooks 'rmail-summary-mode-hook))
747
0732dfa5
KH
748;; Summary features need to be disabled during edit mode.
749(defun rmail-summary-disable ()
56b25713 750 (use-local-map text-mode-map)
c28baa2a 751 (remove-hook 'post-command-hook 'rmail-summary-rmail-update t)
56b25713 752 (setq revert-buffer-function nil))
0732dfa5
KH
753
754(defun rmail-summary-enable ()
56b25713 755 (use-local-map rmail-summary-mode-map)
c28baa2a 756 (add-hook 'post-command-hook 'rmail-summary-rmail-update nil t)
56b25713 757 (setq revert-buffer-function 'rmail-update-summary))
0732dfa5 758
5be36e20
RS
759(defvar rmail-summary-put-back-unseen nil
760 "Used for communicating between calls to `rmail-summary-rmail-update'.
761If it moves to a message within an Incremental Search, and removes
762the `unseen' attribute from that message, it sets this flag
763so that if the next motion between messages is in the same Incremental
764Search, the `unseen' attribute is restored.")
765
bb694792
RS
766;; Show in Rmail the message described by the summary line that point is on,
767;; but only if the Rmail buffer is already visible.
d41d75fb
RS
768;; This is a post-command-hook in summary buffers.
769(defun rmail-summary-rmail-update ()
10e09db4
KH
770 (let (buffer-read-only)
771 (save-excursion
772 ;; If at end of buffer, pretend we are on the last text line.
773 (if (eobp)
774 (forward-line -1))
775 (beginning-of-line)
776 (skip-chars-forward " ")
777 (let ((msg-num (string-to-int (buffer-substring
778 (point)
779 (progn (skip-chars-forward "0-9")
780 (point))))))
5be36e20
RS
781 ;; Always leave `unseen' removed
782 ;; if we get out of isearch mode.
783 ;; Don't let a subsequent isearch restore that `unseen'.
784 (if (not isearch-mode)
785 (setq rmail-summary-put-back-unseen nil))
786
10e09db4 787 (or (eq rmail-current-message msg-num)
8efaaf11 788 (let ((window (get-buffer-window rmail-view-buffer t))
10e09db4 789 (owin (selected-window)))
5be36e20
RS
790 (if isearch-mode
791 (save-excursion
792 (set-buffer rmail-buffer)
793 ;; If we first saw the previous message in this search,
794 ;; and we have gone to a different message while searching,
795 ;; put back `unseen' on the former one.
1dbd9103 796 (if rmail-summary-put-back-unseen
c9aa3ef8
KH
797 (rmail-set-attribute "unseen" t
798 rmail-current-message))
5be36e20
RS
799 ;; Arrange to do that later, for the new current message,
800 ;; if it still has `unseen'.
801 (setq rmail-summary-put-back-unseen
802 (rmail-message-labels-p msg-num ", ?\\(unseen\\),")))
803 (setq rmail-summary-put-back-unseen nil))
804
805 ;; Go to the desired message.
10e09db4 806 (setq rmail-current-message msg-num)
5be36e20
RS
807
808 ;; Update the summary to show the message has been seen.
10e09db4
KH
809 (if (= (following-char) ?-)
810 (progn
811 (delete-char 1)
812 (insert " ")))
5be36e20 813
10e09db4
KH
814 (if window
815 ;; Using save-window-excursion would cause the new value
980d43b6
RS
816 ;; of point to get lost.
817 (unwind-protect
818 (progn
819 (select-window window)
bc454f08 820 (rmail-show-message msg-num t))
10e09db4 821 (select-window owin))
dca46072
RS
822 (if (buffer-name rmail-buffer)
823 (save-excursion
824 (set-buffer rmail-buffer)
4fb6f90f
RS
825 (rmail-show-message msg-num t))))))
826 (rmail-summary-update-highlight nil)))))
d41d75fb
RS
827\f
828(defvar rmail-summary-mode-map nil)
829
830(if rmail-summary-mode-map
831 nil
832 (setq rmail-summary-mode-map (make-keymap))
833 (suppress-keymap rmail-summary-mode-map)
4ab455e6
RS
834
835 (define-key rmail-summary-mode-map [mouse-2] 'rmail-summary-mouse-goto-message)
d41d75fb 836 (define-key rmail-summary-mode-map "a" 'rmail-summary-add-label)
00f3d57d 837 (define-key rmail-summary-mode-map "b" 'rmail-summary-bury)
d41d75fb
RS
838 (define-key rmail-summary-mode-map "c" 'rmail-summary-continue)
839 (define-key rmail-summary-mode-map "d" 'rmail-summary-delete-forward)
840 (define-key rmail-summary-mode-map "\C-d" 'rmail-summary-delete-backward)
841 (define-key rmail-summary-mode-map "e" 'rmail-summary-edit-current-message)
842 (define-key rmail-summary-mode-map "f" 'rmail-summary-forward)
843 (define-key rmail-summary-mode-map "g" 'rmail-summary-get-new-mail)
844 (define-key rmail-summary-mode-map "h" 'rmail-summary)
845 (define-key rmail-summary-mode-map "i" 'rmail-summary-input)
846 (define-key rmail-summary-mode-map "j" 'rmail-summary-goto-msg)
6d6c336c 847 (define-key rmail-summary-mode-map "\C-m" 'rmail-summary-goto-msg)
d41d75fb
RS
848 (define-key rmail-summary-mode-map "k" 'rmail-summary-kill-label)
849 (define-key rmail-summary-mode-map "l" 'rmail-summary-by-labels)
850 (define-key rmail-summary-mode-map "\e\C-h" 'rmail-summary)
851 (define-key rmail-summary-mode-map "\e\C-l" 'rmail-summary-by-labels)
852 (define-key rmail-summary-mode-map "\e\C-r" 'rmail-summary-by-recipients)
853 (define-key rmail-summary-mode-map "\e\C-s" 'rmail-summary-by-regexp)
854 (define-key rmail-summary-mode-map "\e\C-t" 'rmail-summary-by-topic)
855 (define-key rmail-summary-mode-map "m" 'rmail-summary-mail)
856 (define-key rmail-summary-mode-map "\M-m" 'rmail-summary-retry-failure)
857 (define-key rmail-summary-mode-map "n" 'rmail-summary-next-msg)
d41d75fb
RS
858 (define-key rmail-summary-mode-map "\en" 'rmail-summary-next-all)
859 (define-key rmail-summary-mode-map "\e\C-n" 'rmail-summary-next-labeled-message)
860 (define-key rmail-summary-mode-map "o" 'rmail-summary-output-to-rmail-file)
861 (define-key rmail-summary-mode-map "\C-o" 'rmail-summary-output)
862 (define-key rmail-summary-mode-map "p" 'rmail-summary-previous-msg)
d41d75fb
RS
863 (define-key rmail-summary-mode-map "\ep" 'rmail-summary-previous-all)
864 (define-key rmail-summary-mode-map "\e\C-p" 'rmail-summary-previous-labeled-message)
865 (define-key rmail-summary-mode-map "q" 'rmail-summary-quit)
d5bafc55 866 (define-key rmail-summary-mode-map "Q" 'rmail-summary-wipe)
d41d75fb
RS
867 (define-key rmail-summary-mode-map "r" 'rmail-summary-reply)
868 (define-key rmail-summary-mode-map "s" 'rmail-summary-expunge-and-save)
869 (define-key rmail-summary-mode-map "\es" 'rmail-summary-search)
870 (define-key rmail-summary-mode-map "t" 'rmail-summary-toggle-header)
871 (define-key rmail-summary-mode-map "u" 'rmail-summary-undelete)
872 (define-key rmail-summary-mode-map "\M-u" 'rmail-summary-undelete-many)
d41d75fb 873 (define-key rmail-summary-mode-map "x" 'rmail-summary-expunge)
d5bafc55 874 (define-key rmail-summary-mode-map "w" 'rmail-summary-output-body)
d41d75fb
RS
875 (define-key rmail-summary-mode-map "." 'rmail-summary-beginning-of-message)
876 (define-key rmail-summary-mode-map "<" 'rmail-summary-first-message)
877 (define-key rmail-summary-mode-map ">" 'rmail-summary-last-message)
878 (define-key rmail-summary-mode-map " " 'rmail-summary-scroll-msg-up)
879 (define-key rmail-summary-mode-map "\177" 'rmail-summary-scroll-msg-down)
880 (define-key rmail-summary-mode-map "?" 'describe-mode)
71d97b56
RS
881 (define-key rmail-summary-mode-map "\C-c\C-n" 'rmail-summary-next-same-subject)
882 (define-key rmail-summary-mode-map "\C-c\C-p" 'rmail-summary-previous-same-subject)
e45fce03
RS
883 (define-key rmail-summary-mode-map "\C-c\C-s\C-d"
884 'rmail-summary-sort-by-date)
885 (define-key rmail-summary-mode-map "\C-c\C-s\C-s"
886 'rmail-summary-sort-by-subject)
887 (define-key rmail-summary-mode-map "\C-c\C-s\C-a"
888 'rmail-summary-sort-by-author)
889 (define-key rmail-summary-mode-map "\C-c\C-s\C-r"
890 'rmail-summary-sort-by-recipient)
891 (define-key rmail-summary-mode-map "\C-c\C-s\C-c"
892 'rmail-summary-sort-by-correspondent)
893 (define-key rmail-summary-mode-map "\C-c\C-s\C-l"
894 'rmail-summary-sort-by-lines)
ebdf372b
KH
895 (define-key rmail-summary-mode-map "\C-c\C-s\C-k"
896 'rmail-summary-sort-by-keywords)
d41d75fb
RS
897 )
898\f
e7a00c25
RS
899;;; Menu bar bindings.
900
901(define-key rmail-summary-mode-map [menu-bar] (make-sparse-keymap))
902
903(define-key rmail-summary-mode-map [menu-bar classify]
904 (cons "Classify" (make-sparse-keymap "Classify")))
905
dca46072
RS
906(define-key rmail-summary-mode-map [menu-bar classify output-menu]
907 '("Output (Rmail Menu)..." . rmail-summary-output-menu))
908
909(define-key rmail-summary-mode-map [menu-bar classify input-menu]
0e520d74 910 '("Input Rmail File (menu)..." . rmail-input-menu))
dca46072 911
aa138cb4
RS
912(define-key rmail-summary-mode-map [menu-bar classify input-menu]
913 '(nil))
914
915(define-key rmail-summary-mode-map [menu-bar classify output-menu]
916 '(nil))
917
d5bafc55
RS
918(define-key rmail-summary-mode-map [menu-bar classify output-body]
919 '("Output (body)..." . rmail-summary-output-body))
920
e7a00c25 921(define-key rmail-summary-mode-map [menu-bar classify output-inbox]
29e6129e 922 '("Output (inbox)..." . rmail-summary-output))
e7a00c25
RS
923
924(define-key rmail-summary-mode-map [menu-bar classify output]
29e6129e 925 '("Output (Rmail)..." . rmail-summary-output-to-rmail-file))
e7a00c25
RS
926
927(define-key rmail-summary-mode-map [menu-bar classify kill-label]
29e6129e 928 '("Kill Label..." . rmail-summary-kill-label))
e7a00c25
RS
929
930(define-key rmail-summary-mode-map [menu-bar classify add-label]
29e6129e 931 '("Add Label..." . rmail-summary-add-label))
e7a00c25
RS
932
933(define-key rmail-summary-mode-map [menu-bar summary]
934 (cons "Summary" (make-sparse-keymap "Summary")))
935
c1046d18
RS
936(define-key rmail-summary-mode-map [menu-bar summary senders]
937 '("By Senders..." . rmail-summary-by-senders))
938
e7a00c25 939(define-key rmail-summary-mode-map [menu-bar summary labels]
29e6129e 940 '("By Labels..." . rmail-summary-by-labels))
e7a00c25
RS
941
942(define-key rmail-summary-mode-map [menu-bar summary recipients]
29e6129e 943 '("By Recipients..." . rmail-summary-by-recipients))
e7a00c25
RS
944
945(define-key rmail-summary-mode-map [menu-bar summary topic]
29e6129e 946 '("By Topic..." . rmail-summary-by-topic))
e7a00c25
RS
947
948(define-key rmail-summary-mode-map [menu-bar summary regexp]
29e6129e 949 '("By Regexp..." . rmail-summary-by-regexp))
e7a00c25
RS
950
951(define-key rmail-summary-mode-map [menu-bar summary all]
952 '("All" . rmail-summary))
953
954(define-key rmail-summary-mode-map [menu-bar mail]
955 (cons "Mail" (make-sparse-keymap "Mail")))
956
e76bca6c 957(define-key rmail-summary-mode-map [menu-bar mail rmail-summary-get-new-mail]
b0d3522a
RS
958 '("Get New Mail" . rmail-summary-get-new-mail))
959
c0d133a6 960(define-key rmail-summary-mode-map [menu-bar mail lambda]
b0d3522a 961 '("----"))
aba6cc35 962
e7a00c25
RS
963(define-key rmail-summary-mode-map [menu-bar mail continue]
964 '("Continue" . rmail-summary-continue))
965
b0d3522a 966(define-key rmail-summary-mode-map [menu-bar mail resend]
4986bd38 967 '("Re-send..." . rmail-summary-resend))
b0d3522a 968
e7a00c25
RS
969(define-key rmail-summary-mode-map [menu-bar mail forward]
970 '("Forward" . rmail-summary-forward))
971
972(define-key rmail-summary-mode-map [menu-bar mail retry]
973 '("Retry" . rmail-summary-retry-failure))
974
975(define-key rmail-summary-mode-map [menu-bar mail reply]
976 '("Reply" . rmail-summary-reply))
977
978(define-key rmail-summary-mode-map [menu-bar mail mail]
979 '("Mail" . rmail-summary-mail))
980
981(define-key rmail-summary-mode-map [menu-bar delete]
982 (cons "Delete" (make-sparse-keymap "Delete")))
983
984(define-key rmail-summary-mode-map [menu-bar delete expunge/save]
985 '("Expunge/Save" . rmail-summary-expunge-and-save))
986
987(define-key rmail-summary-mode-map [menu-bar delete expunge]
988 '("Expunge" . rmail-summary-expunge))
989
990(define-key rmail-summary-mode-map [menu-bar delete undelete]
991 '("Undelete" . rmail-summary-undelete))
992
993(define-key rmail-summary-mode-map [menu-bar delete delete]
994 '("Delete" . rmail-summary-delete-forward))
995
996(define-key rmail-summary-mode-map [menu-bar move]
997 (cons "Move" (make-sparse-keymap "Move")))
998
999(define-key rmail-summary-mode-map [menu-bar move search-back]
29e6129e 1000 '("Search Back..." . rmail-summary-search-backward))
e7a00c25
RS
1001
1002(define-key rmail-summary-mode-map [menu-bar move search]
29e6129e 1003 '("Search..." . rmail-summary-search))
e7a00c25
RS
1004
1005(define-key rmail-summary-mode-map [menu-bar move previous]
1006 '("Previous Nondeleted" . rmail-summary-previous-msg))
1007
1008(define-key rmail-summary-mode-map [menu-bar move next]
1009 '("Next Nondeleted" . rmail-summary-next-msg))
1010
1011(define-key rmail-summary-mode-map [menu-bar move last]
1012 '("Last" . rmail-summary-last-message))
1013
1014(define-key rmail-summary-mode-map [menu-bar move first]
1015 '("First" . rmail-summary-first-message))
1016
1017(define-key rmail-summary-mode-map [menu-bar move previous]
1018 '("Previous" . rmail-summary-previous-all))
1019
1020(define-key rmail-summary-mode-map [menu-bar move next]
1021 '("Next" . rmail-summary-next-all))
1022\f
4197af8a 1023(defvar rmail-summary-overlay nil)
212daf13 1024(put 'rmail-summary-overlay 'permanent-local t)
4197af8a 1025
4ab455e6
RS
1026(defun rmail-summary-mouse-goto-message (event)
1027 "Select the message whose summary line you click on."
1028 (interactive "@e")
1029 (goto-char (posn-point (event-end event)))
1030 (rmail-summary-goto-msg))
85bd1ac6 1031
d41d75fb 1032(defun rmail-summary-goto-msg (&optional n nowarn skip-rmail)
4ab455e6
RS
1033 "Go to message N in the summary buffer and the Rmail buffer.
1034If N is nil, use the message corresponding to point in the summary
1035and move to that message in the Rmail buffer.
1036
1037If NOWARN, don't say anything if N is out of range.
1038If SKIP-RMAIL, don't do anything to the Rmail buffer."
4d4d11cc
JB
1039 (interactive "P")
1040 (if (consp n) (setq n (prefix-numeric-value n)))
1041 (if (eobp) (forward-line -1))
1042 (beginning-of-line)
132ad564
RS
1043 (let* ((obuf (current-buffer))
1044 (buf rmail-buffer)
1045 (cur (point))
1046 message-not-found
1047 (curmsg (string-to-int
1048 (buffer-substring (point)
1049 (min (point-max) (+ 5 (point))))))
1050 (total (save-excursion (set-buffer buf) rmail-total-messages)))
4197af8a
RS
1051 ;; If message number N was specified, find that message's line
1052 ;; or set message-not-found.
1053 ;; If N wasn't specified or that message can't be found.
1054 ;; set N by default.
4d4d11cc
JB
1055 (if (not n)
1056 (setq n curmsg)
1057 (if (< n 1)
1058 (progn (message "No preceding message")
1059 (setq n 1)))
132ad564 1060 (if (> n total)
4d4d11cc
JB
1061 (progn (message "No following message")
1062 (goto-char (point-max))
85bd1ac6 1063 (rmail-summary-goto-msg nil nowarn skip-rmail)))
4d4d11cc 1064 (goto-char (point-min))
4dc7e43b 1065 (if (not (re-search-forward (format "^%4d[^0-9]" n) nil t))
4d4d11cc
JB
1066 (progn (or nowarn (message "Message %d not found" n))
1067 (setq n curmsg)
4197af8a 1068 (setq message-not-found t)
4d4d11cc
JB
1069 (goto-char cur))))
1070 (beginning-of-line)
1071 (skip-chars-forward " ")
1072 (skip-chars-forward "0-9")
1073 (save-excursion (if (= (following-char) ?-)
1074 (let ((buffer-read-only nil))
1075 (delete-char 1)
1076 (insert " "))))
4fb6f90f 1077 (rmail-summary-update-highlight message-not-found)
4d4d11cc 1078 (beginning-of-line)
d41d75fb
RS
1079 (if skip-rmail
1080 nil
857ff384
RS
1081 (let ((selwin (selected-window)))
1082 (unwind-protect
1083 (progn (pop-to-buffer buf)
1084 (rmail-show-message n))
c7b5ca27
RS
1085 (select-window selwin)
1086 ;; The actions above can alter the current buffer. Preserve it.
1087 (set-buffer obuf))))))
4fb6f90f
RS
1088
1089;; Update the highlighted line in an rmail summary buffer.
1090;; That should be current. We highlight the line point is on.
1091;; If NOT-FOUND is non-nil, we turn off highlighting.
1092(defun rmail-summary-update-highlight (not-found)
1093 ;; Make sure we have an overlay to use.
1094 (or rmail-summary-overlay
1095 (progn
1096 (make-local-variable 'rmail-summary-overlay)
1097 (setq rmail-summary-overlay (make-overlay (point) (point)))))
1098 ;; If this message is in the summary, use the overlay to highlight it.
1099 ;; Otherwise, don't highlight anything.
1100 (if not-found
1101 (overlay-put rmail-summary-overlay 'face nil)
1102 (move-overlay rmail-summary-overlay
1103 (save-excursion (beginning-of-line)
1104 (skip-chars-forward " ")
1105 (point))
1106 (save-excursion (end-of-line) (point)))
1107 (overlay-put rmail-summary-overlay 'face 'highlight)))
d41d75fb 1108\f
4d4d11cc 1109(defun rmail-summary-scroll-msg-up (&optional dist)
3753ab6f
RS
1110 "Scroll the Rmail window forward.
1111If the Rmail window is displaying the end of a message,
1112advance to the next message."
4d4d11cc 1113 (interactive "P")
3753ab6f
RS
1114 (if (eq dist '-)
1115 (rmail-summary-scroll-msg-down nil)
db56d71e 1116 (let ((rmail-buffer-window (get-buffer-window rmail-view-buffer)))
3753ab6f
RS
1117 (if rmail-buffer-window
1118 (if (let ((rmail-summary-window (selected-window)))
1119 (select-window rmail-buffer-window)
1120 (prog1
1121 ;; Is EOB visible in the buffer?
1122 (save-excursion
1123 (let ((ht (window-height (selected-window))))
1124 (move-to-window-line (- ht 2))
1125 (end-of-line)
1126 (eobp)))
1127 (select-window rmail-summary-window)))
be2e861f
RS
1128 (if (not rmail-summary-scroll-between-messages)
1129 (error "End of buffer")
1130 (rmail-summary-next-msg (or dist 1)))
db56d71e 1131 (let ((other-window-scroll-buffer rmail-view-buffer))
3753ab6f 1132 (scroll-other-window dist)))
37eb1878
RS
1133 ;; If it isn't visible at all, show the beginning.
1134 (rmail-summary-beginning-of-message)))))
4d4d11cc
JB
1135
1136(defun rmail-summary-scroll-msg-down (&optional dist)
3753ab6f 1137 "Scroll the Rmail window backward.
37eb1878
RS
1138If the Rmail window is now displaying the beginning of a message,
1139move to the previous message."
4d4d11cc 1140 (interactive "P")
3753ab6f
RS
1141 (if (eq dist '-)
1142 (rmail-summary-scroll-msg-up nil)
1143 (let ((rmail-buffer-window (get-buffer-window rmail-buffer)))
1144 (if rmail-buffer-window
1145 (if (let ((rmail-summary-window (selected-window)))
1146 (select-window rmail-buffer-window)
1147 (prog1
1148 ;; Is BOB visible in the buffer?
1149 (save-excursion
1150 (move-to-window-line 0)
1151 (beginning-of-line)
1152 (bobp))
1153 (select-window rmail-summary-window)))
be2e861f
RS
1154 (if (not rmail-summary-scroll-between-messages)
1155 (error "Beginning of buffer")
1156 (rmail-summary-previous-msg (or dist 1)))
3753ab6f
RS
1157 (let ((other-window-scroll-buffer rmail-buffer))
1158 (scroll-other-window-down dist)))
37eb1878
RS
1159 ;; If it isn't visible at all, show the beginning.
1160 (rmail-summary-beginning-of-message)))))
d41d75fb
RS
1161
1162(defun rmail-summary-beginning-of-message ()
1163 "Show current message from the beginning."
1164 (interactive)
37eb1878
RS
1165 (if (and (one-window-p) (not pop-up-frames))
1166 ;; If there is just one window, put the summary on the top.
1167 (let ((buffer rmail-buffer))
1168 (split-window (selected-window) rmail-summary-window-size)
1169 (select-window (frame-first-window))
1170 (pop-to-buffer rmail-buffer)
1171 ;; If pop-to-buffer did not use that window, delete that
1172 ;; window. (This can happen if it uses another frame.)
1173 (or (eq buffer (window-buffer (next-window (frame-first-window))))
1174 (delete-other-windows)))
1175 (pop-to-buffer rmail-buffer))
d41d75fb
RS
1176 (beginning-of-buffer)
1177 (pop-to-buffer rmail-summary-buffer))
4d4d11cc 1178
00f3d57d
RS
1179(defun rmail-summary-bury ()
1180 "Bury the Rmail buffer and the Rmail summary buffer."
1181 (interactive)
1182 (let ((buffer-to-bury (current-buffer)))
1183 (let (window)
1184 (while (setq window (get-buffer-window rmail-buffer))
1185 (set-window-buffer window (other-buffer rmail-buffer)))
1186 (bury-buffer rmail-buffer))
1187 (switch-to-buffer (other-buffer buffer-to-bury))
1188 (bury-buffer buffer-to-bury)))
1189
4d4d11cc 1190(defun rmail-summary-quit ()
d41d75fb 1191 "Quit out of Rmail and Rmail summary."
4d4d11cc 1192 (interactive)
d41d75fb 1193 (rmail-summary-wipe)
4d4d11cc
JB
1194 (rmail-quit))
1195
d41d75fb
RS
1196(defun rmail-summary-wipe ()
1197 "Kill and wipe away Rmail summary, remaining within Rmail."
4d4d11cc 1198 (interactive)
d41d75fb 1199 (save-excursion (set-buffer rmail-buffer) (setq rmail-summary-buffer nil))
9cd78473 1200 (let ((local-rmail-buffer rmail-buffer))
d41d75fb
RS
1201 (kill-buffer (current-buffer))
1202 ;; Delete window if not only one.
1203 (if (not (eq (selected-window) (next-window nil 'no-minibuf)))
1204 (delete-window))
9cd78473
RS
1205 ;; Switch windows to the rmail buffer, or switch to it in this window.
1206 (pop-to-buffer local-rmail-buffer)))
d41d75fb
RS
1207
1208(defun rmail-summary-expunge ()
1209 "Actually erase all deleted messages and recompute summary headers."
1210 (interactive)
1211 (save-excursion
1212 (set-buffer rmail-buffer)
1213 (rmail-only-expunge))
1214 (rmail-update-summary))
1215
1216(defun rmail-summary-expunge-and-save ()
1217 "Expunge and save RMAIL file."
1218 (interactive)
1219 (save-excursion
1220 (set-buffer rmail-buffer)
b37767e7
RS
1221 (rmail-only-expunge))
1222 (rmail-update-summary)
1223 (save-excursion
980d43b6 1224 (set-buffer rmail-buffer)
ccc341de
KH
1225 (save-buffer))
1226 (set-buffer-modified-p nil))
d41d75fb 1227
3198a3d5
RS
1228(defun rmail-summary-get-new-mail (&optional file-name)
1229 "Get new mail and recompute summary headers.
1230
1231Optionally you can specify the file to get new mail from. In this case,
1232the file of new mail is not changed or deleted. Noninteractively, you can
1233pass the inbox file name as an argument. Interactively, a prefix
1234argument says to read a file name and use that file as the inbox."
1235 (interactive
1236 (list (if current-prefix-arg
1237 (read-file-name "Get new mail from file: "))))
b37767e7
RS
1238 (let (msg)
1239 (save-excursion
1240 (set-buffer rmail-buffer)
3198a3d5 1241 (rmail-get-new-mail file-name)
b37767e7
RS
1242 ;; Get the proper new message number.
1243 (setq msg rmail-current-message))
1244 ;; Make sure that message is displayed.
8d908f84
RS
1245 (or (zerop msg)
1246 (rmail-summary-goto-msg msg))))
d41d75fb
RS
1247
1248(defun rmail-summary-input (filename)
1249 "Run Rmail on file FILENAME."
1250 (interactive "FRun rmail on RMAIL file: ")
b37767e7
RS
1251 ;; We switch windows here, then display the other Rmail file there.
1252 (pop-to-buffer rmail-buffer)
1253 (rmail filename))
d41d75fb
RS
1254
1255(defun rmail-summary-first-message ()
1256 "Show first message in Rmail file from summary buffer."
1257 (interactive)
1258 (beginning-of-buffer))
1259
1260(defun rmail-summary-last-message ()
1261 "Show last message in Rmail file from summary buffer."
1262 (interactive)
1263 (end-of-buffer)
1264 (forward-line -1))
1265
1266(defvar rmail-summary-edit-map nil)
1267(if rmail-summary-edit-map
1268 nil
1269 (setq rmail-summary-edit-map
ae06ea79 1270 (nconc (make-sparse-keymap) text-mode-map))
d41d75fb
RS
1271 (define-key rmail-summary-edit-map "\C-c\C-c" 'rmail-cease-edit)
1272 (define-key rmail-summary-edit-map "\C-c\C-]" 'rmail-abort-edit))
1273
1274(defun rmail-summary-edit-current-message ()
1275 "Edit the contents of this message."
1276 (interactive)
1277 (pop-to-buffer rmail-buffer)
1278 (rmail-edit-current-message)
1279 (use-local-map rmail-summary-edit-map))
1280
1281(defun rmail-summary-cease-edit ()
1282 "Finish editing message, then go back to Rmail summary buffer."
1283 (interactive)
1284 (rmail-cease-edit)
1285 (pop-to-buffer rmail-summary-buffer))
1286
1287(defun rmail-summary-abort-edit ()
1288 "Abort edit of current message; restore original contents.
1289Go back to summary buffer."
1290 (interactive)
1291 (rmail-abort-edit)
1292 (pop-to-buffer rmail-summary-buffer))
1293
e7a00c25
RS
1294(defun rmail-summary-search-backward (regexp &optional n)
1295 "Show message containing next match for REGEXP.
1296Prefix argument gives repeat count; negative argument means search
1297backwards (through earlier messages).
1298Interactively, empty argument means use same regexp used last time."
1299 (interactive
1300 (let* ((reversep (>= (prefix-numeric-value current-prefix-arg) 0))
1301 (prompt
1302 (concat (if reversep "Reverse " "") "Rmail search (regexp): "))
1303 regexp)
1304 (if rmail-search-last-regexp
1305 (setq prompt (concat prompt
1306 "(default "
1307 rmail-search-last-regexp
1308 ") ")))
1309 (setq regexp (read-string prompt))
1310 (cond ((not (equal regexp ""))
1311 (setq rmail-search-last-regexp regexp))
1312 ((not rmail-search-last-regexp)
1313 (error "No previous Rmail search string")))
1314 (list rmail-search-last-regexp
1315 (prefix-numeric-value current-prefix-arg))))
1316 ;; Don't use save-excursion because that prevents point from moving
1317 ;; properly in the summary buffer.
1318 (let ((buffer (current-buffer)))
1319 (unwind-protect
1320 (progn
1321 (set-buffer rmail-buffer)
1322 (rmail-search regexp (- n)))
1323 (set-buffer buffer))))
1324
d41d75fb
RS
1325(defun rmail-summary-search (regexp &optional n)
1326 "Show message containing next match for REGEXP.
1327Prefix argument gives repeat count; negative argument means search
1328backwards (through earlier messages).
1329Interactively, empty argument means use same regexp used last time."
1330 (interactive
1331 (let* ((reversep (< (prefix-numeric-value current-prefix-arg) 0))
1332 (prompt
1333 (concat (if reversep "Reverse " "") "Rmail search (regexp): "))
1334 regexp)
1335 (if rmail-search-last-regexp
1336 (setq prompt (concat prompt
1337 "(default "
1338 rmail-search-last-regexp
1339 ") ")))
1340 (setq regexp (read-string prompt))
1341 (cond ((not (equal regexp ""))
1342 (setq rmail-search-last-regexp regexp))
1343 ((not rmail-search-last-regexp)
1344 (error "No previous Rmail search string")))
1345 (list rmail-search-last-regexp
1346 (prefix-numeric-value current-prefix-arg))))
e7a00c25
RS
1347 ;; Don't use save-excursion because that prevents point from moving
1348 ;; properly in the summary buffer.
1349 (let ((buffer (current-buffer)))
1350 (unwind-protect
1351 (progn
1352 (set-buffer rmail-buffer)
1353 (rmail-search regexp n))
1354 (set-buffer buffer))))
d41d75fb
RS
1355
1356(defun rmail-summary-toggle-header ()
1357 "Show original message header if pruned header currently shown, or vice versa."
1358 (interactive)
1359 (save-excursion
1360 (set-buffer rmail-buffer)
387f203c
RS
1361 (rmail-toggle-header))
1362 ;; Inside save-excursion, some changes to point in the RMAIL buffer are lost.
1363 ;; Set point to point-min in the RMAIL buffer, if it is visible.
1364 (let ((window (get-buffer-window rmail-buffer)))
1365 (if window
1366 ;; Using save-window-excursion would lose the new value of point.
1367 (let ((owin (selected-window)))
1368 (unwind-protect
1369 (progn
1370 (select-window window)
1371 (goto-char (point-min)))
1372 (select-window owin))))))
1373
d41d75fb
RS
1374
1375(defun rmail-summary-add-label (label)
1376 "Add LABEL to labels associated with current Rmail message.
1377Completion is performed over known labels when reading."
980d43b6
RS
1378 (interactive (list (save-excursion
1379 (set-buffer rmail-buffer)
1380 (rmail-read-label "Add label"))))
d41d75fb
RS
1381 (save-excursion
1382 (set-buffer rmail-buffer)
1383 (rmail-add-label label)))
1384
1385(defun rmail-summary-kill-label (label)
1386 "Remove LABEL from labels associated with current Rmail message.
1387Completion is performed over known labels when reading."
980d43b6
RS
1388 (interactive (list (save-excursion
1389 (set-buffer rmail-buffer)
1390 (rmail-read-label "Kill label"))))
d41d75fb
RS
1391 (save-excursion
1392 (set-buffer rmail-buffer)
1393 (rmail-set-label label nil)))
1394\f
1395;;;; *** Rmail Summary Mailing Commands ***
1396
1397(defun rmail-summary-mail ()
1398 "Send mail in another window.
1399While composing the message, use \\[mail-yank-original] to yank the
1400original message into it."
1401 (interactive)
4c11ca80
RS
1402 (let ((window (get-buffer-window rmail-buffer)))
1403 (if window
1404 (select-window window)
1405 (set-buffer rmail-buffer)))
1406 (rmail-start-mail nil nil nil nil nil (current-buffer))
d41d75fb
RS
1407 (use-local-map (copy-keymap (current-local-map)))
1408 (define-key (current-local-map)
1409 "\C-c\C-c" 'rmail-summary-send-and-exit))
1410
1411(defun rmail-summary-continue ()
1412 "Continue composing outgoing message previously being composed."
1413 (interactive)
4c11ca80
RS
1414 (let ((window (get-buffer-window rmail-buffer)))
1415 (if window
1416 (select-window window)
1417 (set-buffer rmail-buffer)))
db1d3cf7 1418 (rmail-start-mail t))
d41d75fb
RS
1419
1420(defun rmail-summary-reply (just-sender)
1421 "Reply to the current message.
1422Normally include CC: to all other recipients of original message;
db1d3cf7
KH
1423prefix argument means ignore them. While composing the reply,
1424use \\[mail-yank-original] to yank the original message into it."
d41d75fb 1425 (interactive "P")
4c11ca80
RS
1426 (let ((window (get-buffer-window rmail-buffer)))
1427 (if window
1428 (select-window window)
1429 (set-buffer rmail-buffer)))
db1d3cf7
KH
1430 (rmail-reply just-sender)
1431 (use-local-map (copy-keymap (current-local-map)))
1432 (define-key (current-local-map)
1433 "\C-c\C-c" 'rmail-summary-send-and-exit))
d41d75fb
RS
1434
1435(defun rmail-summary-retry-failure ()
1436 "Edit a mail message which is based on the contents of the current message.
1437For a message rejected by the mail system, extract the interesting headers and
1438the body of the original message; otherwise copy the current message."
1439 (interactive)
4c11ca80
RS
1440 (let ((window (get-buffer-window rmail-buffer)))
1441 (if window
1442 (select-window window)
1443 (set-buffer rmail-buffer)))
db1d3cf7
KH
1444 (rmail-retry-failure)
1445 (use-local-map (copy-keymap (current-local-map)))
1446 (define-key (current-local-map)
1447 "\C-c\C-c" 'rmail-summary-send-and-exit))
d41d75fb
RS
1448
1449(defun rmail-summary-send-and-exit ()
1450 "Send mail reply and return to summary buffer."
1451 (interactive)
1452 (mail-send-and-exit t))
1453
18e90c58
RS
1454(defun rmail-summary-forward (resend)
1455 "Forward the current message to another user.
1456With prefix argument, \"resend\" the message instead of forwarding it;
1457see the documentation of `rmail-resend'."
1458 (interactive "P")
d41d75fb 1459 (save-excursion
4c11ca80
RS
1460 (let ((window (get-buffer-window rmail-buffer)))
1461 (if window
1462 (select-window window)
1463 (set-buffer rmail-buffer)))
18e90c58 1464 (rmail-forward resend)
d41d75fb
RS
1465 (use-local-map (copy-keymap (current-local-map)))
1466 (define-key (current-local-map)
1467 "\C-c\C-c" 'rmail-summary-send-and-exit)))
4986bd38
RS
1468
1469(defun rmail-summary-resend ()
1470 "Resend current message using 'rmail-resend'."
1471 (interactive)
1472 (save-excursion
4c11ca80
RS
1473 (let ((window (get-buffer-window rmail-buffer)))
1474 (if window
1475 (select-window window)
1476 (set-buffer rmail-buffer)))
4986bd38 1477 (call-interactively 'rmail-resend)))
d41d75fb
RS
1478\f
1479;; Summary output commands.
1480
48afa9cd 1481(defun rmail-summary-output-to-rmail-file (&optional file-name n)
d41d75fb
RS
1482 "Append the current message to an Rmail file named FILE-NAME.
1483If the file does not exist, ask if it should be created.
1484If file is being visited, the message is appended to the Emacs
05422245
KH
1485buffer visiting that file.
1486
1487A prefix argument N says to output N consecutive messages
1488starting with the current one. Deleted messages are skipped and don't count."
f9e3db55
RS
1489 (interactive
1490 (progn (require 'rmailout)
1491 (list (rmail-output-read-rmail-file-name)
1492 (prefix-numeric-value current-prefix-arg))))
f256f63e
KH
1493 (let ((i 0) prev-msg)
1494 (while
1495 (and (< i n)
1496 (progn (rmail-summary-goto-msg)
1497 (not (eq prev-msg
1498 (setq prev-msg
1499 (with-current-buffer rmail-buffer
1500 rmail-current-message))))))
f9e3db55 1501 (setq i (1+ i))
f9e3db55
RS
1502 (with-current-buffer rmail-buffer
1503 (let ((rmail-delete-after-output nil))
1504 (rmail-output-to-rmail-file file-name 1)))
1505 (if rmail-delete-after-output
1506 (rmail-summary-delete-forward nil)
1507 (if (< i n)
1508 (rmail-summary-next-msg 1))))))
1509
1510(defun rmail-summary-output (&optional file-name n)
1511 "Append this message to Unix mail file named FILE-NAME.
1512
1513A prefix argument N says to output N consecutive messages
1514starting with the current one. Deleted messages are skipped and don't count."
1515 (interactive
1516 (progn (require 'rmailout)
1517 (list (rmail-output-read-file-name)
1518 (prefix-numeric-value current-prefix-arg))))
1519 (let ((i 0))
1520 (while (< i n)
1521 (setq i (1+ i))
1522 (with-current-buffer rmail-buffer
1523 (let ((rmail-delete-after-output nil))
1524 (rmail-output file-name 1)))
1525 (if rmail-delete-after-output
1526 (rmail-summary-delete-forward nil)
1527 (if (< i n)
1528 (rmail-summary-next-msg 1))))))
d41d75fb 1529
dca46072
RS
1530(defun rmail-summary-output-menu ()
1531 "Output current message to another Rmail file, chosen with a menu.
1532Also set the default for subsequent \\[rmail-output-to-rmail-file] commands.
1533The variables `rmail-secondary-file-directory' and
1534`rmail-secondary-file-regexp' control which files are offered in the menu."
1535 (interactive)
1536 (save-excursion
1537 (set-buffer rmail-buffer)
1538 (let ((rmail-delete-after-output nil))
1539 (call-interactively 'rmail-output-menu)))
1540 (if rmail-delete-after-output
1541 (rmail-summary-delete-forward nil)))
1542
aa138cb4
RS
1543(defun rmail-summary-construct-io-menu ()
1544 (let ((files (rmail-find-all-files rmail-secondary-file-directory)))
cb4903bc 1545 (if files
aa138cb4
RS
1546 (progn
1547 (define-key rmail-summary-mode-map [menu-bar classify input-menu]
1548 (cons "Input Rmail File"
1549 (rmail-list-to-menu "Input Rmail File"
cb4903bc 1550 files
aa138cb4
RS
1551 'rmail-summary-input)))
1552 (define-key rmail-summary-mode-map [menu-bar classify output-menu]
1553 (cons "Output Rmail File"
1554 (rmail-list-to-menu "Output Rmail File"
cb4903bc
RS
1555 files
1556 'rmail-summary-output-to-rmail-file))))
1557 (define-key rmail-summary-mode-map [menu-bar classify input-menu]
1558 '("Input Rmail File" . rmail-disable-menu))
1559 (define-key rmail-summary-mode-map [menu-bar classify output-menu]
1560 '("Output Rmail File" . rmail-disable-menu)))))
aa138cb4 1561
d5bafc55
RS
1562(defun rmail-summary-output-body (&optional file-name)
1563 "Write this message body to the file FILE-NAME.
1564FILE-NAME defaults, interactively, from the Subject field of the message."
1565 (interactive)
1566 (save-excursion
1567 (set-buffer rmail-buffer)
1568 (let ((rmail-delete-after-output nil))
1569 (if file-name
1570 (rmail-output-body-to-file file-name)
1571 (call-interactively 'rmail-output-body-to-file))))
1572 (if rmail-delete-after-output
1573 (rmail-summary-delete-forward nil)))
e45fce03
RS
1574\f
1575;; Sorting messages in Rmail Summary buffer.
1576
1577(defun rmail-summary-sort-by-date (reverse)
1578 "Sort messages of current Rmail summary by date.
1579If prefix argument REVERSE is non-nil, sort them in reverse order."
1580 (interactive "P")
1581 (rmail-sort-from-summary (function rmail-sort-by-date) reverse))
1582
1583(defun rmail-summary-sort-by-subject (reverse)
1584 "Sort messages of current Rmail summary by subject.
1585If prefix argument REVERSE is non-nil, sort them in reverse order."
1586 (interactive "P")
1587 (rmail-sort-from-summary (function rmail-sort-by-subject) reverse))
1588
1589(defun rmail-summary-sort-by-author (reverse)
1590 "Sort messages of current Rmail summary by author.
1591If prefix argument REVERSE is non-nil, sort them in reverse order."
1592 (interactive "P")
1593 (rmail-sort-from-summary (function rmail-sort-by-author) reverse))
1594
1595(defun rmail-summary-sort-by-recipient (reverse)
1596 "Sort messages of current Rmail summary by recipient.
1597If prefix argument REVERSE is non-nil, sort them in reverse order."
1598 (interactive "P")
1599 (rmail-sort-from-summary (function rmail-sort-by-recipient) reverse))
1600
1601(defun rmail-summary-sort-by-correspondent (reverse)
1602 "Sort messages of current Rmail summary by other correspondent.
1603If prefix argument REVERSE is non-nil, sort them in reverse order."
1604 (interactive "P")
1605 (rmail-sort-from-summary (function rmail-sort-by-correspondent) reverse))
1606
1607(defun rmail-summary-sort-by-lines (reverse)
1608 "Sort messages of current Rmail summary by lines of the message.
1609If prefix argument REVERSE is non-nil, sort them in reverse order."
1610 (interactive "P")
1611 (rmail-sort-from-summary (function rmail-sort-by-lines) reverse))
1612
ebdf372b
KH
1613(defun rmail-summary-sort-by-keywords (reverse labels)
1614 "Sort messages of current Rmail summary by keywords.
1615If prefix argument REVERSE is non-nil, sort them in reverse order.
1616KEYWORDS is a comma-separated list of labels."
1617 (interactive "P\nsSort by labels: ")
1618 (rmail-sort-from-summary
1619 (function (lambda (reverse)
1620 (rmail-sort-by-keywords reverse labels)))
1621 reverse))
1622
e45fce03
RS
1623(defun rmail-sort-from-summary (sortfun reverse)
1624 "Sort Rmail messages from Summary buffer and update it after sorting."
1625 (require 'rmailsort)
2a527e48
KH
1626 (let ((selwin (selected-window)))
1627 (unwind-protect
1628 (progn (pop-to-buffer rmail-buffer)
1629 (funcall sortfun reverse))
1630 (select-window selwin))))
c88ab9ce 1631
020c9ca5
DL
1632(provide 'rmailsum)
1633
c88ab9ce 1634;;; rmailsum.el ends here