]> code.delx.au - gnu-emacs/blob - lisp/mail/rmailsum.el
(rmail-summary-wipe): If rmail buffer is not visible,
[gnu-emacs] / lisp / mail / rmailsum.el
1 ;;; rmailsum.el --- make summary buffers for the mail reader
2
3 ;; Copyright (C) 1985, 1993 Free Software Foundation, Inc.
4
5 ;; Maintainer: FSF
6 ;; Keywords: mail
7
8 ;; This file is part of GNU Emacs.
9
10 ;; GNU Emacs is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation; either version 2, or (at your option)
13 ;; any later version.
14
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
19
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs; see the file COPYING. If not, write to
22 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23
24 ;;; Commentary:
25
26 ;; Extended by Bob Weiner of Motorola
27 ;; Provided all commands from rmail-mode in rmail-summary-mode and made key
28 ;; bindings in both modes wholly compatible.
29
30 ;;; Code:
31
32 ;; Entry points for making a summary buffer.
33
34 ;; Regenerate the contents of the summary
35 ;; using the same selection criterion as last time.
36 ;; M-x revert-buffer in a summary buffer calls this function.
37 (defun rmail-update-summary (&rest ignore)
38 (apply (car rmail-summary-redo) (cdr rmail-summary-redo)))
39
40 (defun rmail-summary ()
41 "Display a summary of all messages, one line per message."
42 (interactive)
43 (rmail-new-summary "All" '(rmail-summary) nil))
44
45 (defun rmail-summary-by-labels (labels)
46 "Display a summary of all messages with one or more LABELS.
47 LABELS should be a string containing the desired labels, separated by commas."
48 (interactive "sLabels to summarize by: ")
49 (if (string= labels "")
50 (setq labels (or rmail-last-multi-labels
51 (error "No label specified"))))
52 (setq rmail-last-multi-labels labels)
53 (rmail-new-summary (concat "labels " labels)
54 (list 'rmail-summary-by-labels labels)
55 'rmail-message-labels-p
56 (concat ", \\(" (mail-comma-list-regexp labels) "\\),")))
57
58 (defun rmail-summary-by-recipients (recipients &optional primary-only)
59 "Display a summary of all messages with the given RECIPIENTS.
60 Normally checks the To, From and Cc fields of headers;
61 but if PRIMARY-ONLY is non-nil (prefix arg given),
62 only look in the To and From fields.
63 RECIPIENTS is a string of regexps separated by commas."
64 (interactive "sRecipients to summarize by: \nP")
65 (rmail-new-summary
66 (concat "recipients " recipients)
67 (list 'rmail-summary-by-recipients recipients primary-only)
68 'rmail-message-recipients-p
69 (mail-comma-list-regexp recipients) primary-only))
70
71 (defun rmail-summary-by-regexp (regexp)
72 "Display a summary of all messages according to regexp REGEXP.
73 If the regular expression is found in the header of the message
74 \(including in the date and other lines, as well as the subject line),
75 Emacs will list the header line in the RMAIL-summary."
76 (interactive "sRegexp to summarize by: ")
77 (if (string= regexp "")
78 (setq regexp (or rmail-last-regexp
79 (error "No regexp specified."))))
80 (setq rmail-last-regexp regexp)
81 (rmail-new-summary (concat "regexp " regexp)
82 (list 'rmail-summary-by-regexp regexp)
83 'rmail-message-regexp-p
84 regexp))
85
86 ;; rmail-summary-by-topic
87 ;; 1989 R.A. Schnitzler
88
89 (defun rmail-summary-by-topic (subject &optional whole-message)
90 "Display a summary of all messages with the given SUBJECT.
91 Normally checks the Subject field of headers;
92 but if WHOLE-MESSAGE is non-nil (prefix arg given),
93 look in the whole message.
94 SUBJECT is a string of regexps separated by commas."
95 (interactive "sTopics to summarize by: \nP")
96 (rmail-new-summary
97 (concat "about " subject)
98 (list 'rmail-summary-by-topic subject whole-message)
99 'rmail-message-subject-p
100 (mail-comma-list-regexp subject) whole-message))
101
102 (defun rmail-message-subject-p (msg subject &optional whole-message)
103 (save-restriction
104 (goto-char (rmail-msgbeg msg))
105 (search-forward "\n*** EOOH ***\n")
106 (narrow-to-region
107 (point)
108 (progn (search-forward (if whole-message "\^_" "\n\n")) (point)))
109 (goto-char (point-min))
110 (if whole-message (re-search-forward subject nil t)
111 (string-match subject (or (mail-fetch-field "Subject") "")) )))
112
113 (defun rmail-summary-by-senders (senders)
114 "Display a summary of all messages with the given SENDERS.
115 SENDERS is a string of names separated by commas."
116 (interactive "sSenders to summarize by: ")
117 (rmail-new-summary
118 (concat "senders " senders)
119 'rmail-message-senders-p
120 (mail-comma-list-regexp senders)))
121
122 (defun rmail-message-senders-p (msg senders)
123 (save-restriction
124 (goto-char (rmail-msgbeg msg))
125 (search-forward "\n*** EOOH ***\n")
126 (narrow-to-region (point) (progn (search-forward "\n\n") (point)))
127 (string-match senders (or (mail-fetch-field "From") ""))))
128 \f
129 ;; General making of a summary buffer.
130
131 (defvar rmail-summary-symbol-number 0)
132
133 (defun rmail-new-summary (description redo-form function &rest args)
134 "Create a summary of selected messages.
135 DESCRIPTION makes part of the mode line of the summary buffer.
136 For each message, FUNCTION is applied to the message number and ARGS...
137 and if the result is non-nil, that message is included.
138 nil for FUNCTION means all messages."
139 (message "Computing summary lines...")
140 (let (sumbuf mesg was-in-summary)
141 (save-excursion
142 ;; Go to the Rmail buffer.
143 (if (eq major-mode 'rmail-summary-mode)
144 (progn
145 (setq was-in-summary t)
146 (set-buffer rmail-buffer)))
147 ;; Find its summary buffer, or make one.
148 (setq sumbuf
149 (if (and rmail-summary-buffer
150 (buffer-name rmail-summary-buffer))
151 rmail-summary-buffer
152 (generate-new-buffer (concat (buffer-name) "-summary"))))
153 (setq mesg rmail-current-message)
154 ;; Filter the messages; make or get their summary lines.
155 (let ((summary-msgs ())
156 (new-summary-line-count 0))
157 (let ((msgnum 1)
158 (buffer-read-only nil))
159 (save-restriction
160 (save-excursion
161 (widen)
162 (goto-char (point-min))
163 (while (>= rmail-total-messages msgnum)
164 (if (or (null function)
165 (apply function (cons msgnum args)))
166 (setq summary-msgs
167 (cons (cons msgnum (rmail-make-summary-line msgnum))
168 summary-msgs)))
169 (setq msgnum (1+ msgnum)))
170 (setq summary-msgs (nreverse summary-msgs)))))
171 ;; Temporarily, while summary buffer is unfinished,
172 ;; we "don't have" a summary.
173 (setq rmail-summary-buffer nil)
174 (save-excursion
175 (let ((rbuf (current-buffer))
176 (total rmail-total-messages))
177 (set-buffer sumbuf)
178 ;; Set up the summary buffer's contents.
179 (let ((buffer-read-only nil))
180 (erase-buffer)
181 (while summary-msgs
182 (princ (cdr (car summary-msgs)) sumbuf)
183 (setq summary-msgs (cdr summary-msgs)))
184 (goto-char (point-min)))
185 ;; Set up the rest of its state and local variables.
186 (setq buffer-read-only t)
187 (rmail-summary-mode)
188 (make-local-variable 'minor-mode-alist)
189 (setq minor-mode-alist (list '(t (concat ": " description))))
190 (setq rmail-buffer rbuf
191 rmail-summary-redo redo-form
192 rmail-total-messages total))))
193 (setq rmail-summary-buffer sumbuf))
194 ;; Now display the summary buffer and go to the right place in it.
195 (or was-in-summary
196 (pop-to-buffer sumbuf))
197 (rmail-summary-goto-msg mesg t t)
198 (message "Computing summary lines...done")))
199 \f
200 ;; Low levels of generating a summary.
201
202 (defun rmail-make-summary-line (msg)
203 (let ((line (or (aref rmail-summary-vector (1- msg))
204 (progn
205 (setq new-summary-line-count
206 (1+ new-summary-line-count))
207 (if (zerop (% new-summary-line-count 10))
208 (message "Computing summary lines...%d"
209 new-summary-line-count))
210 (rmail-make-summary-line-1 msg)))))
211 ;; Fix up the part of the summary that says "deleted" or "unseen".
212 (aset line 4
213 (if (rmail-message-deleted-p msg) ?\D
214 (if (= ?0 (char-after (+ 3 (rmail-msgbeg msg))))
215 ?\- ?\ )))
216 line))
217
218 (defun rmail-make-summary-line-1 (msg)
219 (goto-char (rmail-msgbeg msg))
220 (let* ((lim (save-excursion (forward-line 2) (point)))
221 pos
222 (labels
223 (progn
224 (forward-char 3)
225 (concat
226 ; (if (save-excursion (re-search-forward ",answered," lim t))
227 ; "*" "")
228 ; (if (save-excursion (re-search-forward ",filed," lim t))
229 ; "!" "")
230 (if (progn (search-forward ",,") (eolp))
231 ""
232 (concat "{"
233 (buffer-substring (point)
234 (progn (end-of-line) (point)))
235 "} ")))))
236 (line
237 (progn
238 (forward-line 1)
239 (if (looking-at "Summary-line: ")
240 (progn
241 (goto-char (match-end 0))
242 (setq line
243 (buffer-substring (point)
244 (progn (forward-line 1) (point)))))))))
245 ;; Obsolete status lines lacking a # should be flushed.
246 (and line
247 (not (string-match "#" line))
248 (progn
249 (delete-region (point)
250 (progn (forward-line -1) (point)))
251 (setq line nil)))
252 ;; If we didn't get a valid status line from the message,
253 ;; make a new one and put it in the message.
254 (or line
255 (let* ((case-fold-search t)
256 (next (rmail-msgend msg))
257 (beg (if (progn (goto-char (rmail-msgbeg msg))
258 (search-forward "\n*** EOOH ***\n" next t))
259 (point)
260 (forward-line 1)
261 (point)))
262 (end (progn (search-forward "\n\n" nil t) (point))))
263 (save-restriction
264 (narrow-to-region beg end)
265 (goto-char beg)
266 (setq line (rmail-make-basic-summary-line)))
267 (goto-char (rmail-msgbeg msg))
268 (forward-line 2)
269 (insert "Summary-line: " line)))
270 (setq pos (string-match "#" line))
271 (aset rmail-summary-vector (1- msg)
272 (concat (format "%4d " msg)
273 (substring line 0 pos)
274 labels
275 (substring line (1+ pos))))))
276
277 (defun rmail-make-basic-summary-line ()
278 (goto-char (point-min))
279 (concat (save-excursion
280 (if (not (re-search-forward "^Date:" nil t))
281 " "
282 (cond ((re-search-forward "\\([^0-9:]\\)\\([0-3]?[0-9]\\)\\([- \t_]+\\)\\([adfjmnos][aceopu][bcglnprtvy]\\)"
283 (save-excursion (end-of-line) (point)) t)
284 (format "%2d-%3s"
285 (string-to-int (buffer-substring
286 (match-beginning 2)
287 (match-end 2)))
288 (buffer-substring
289 (match-beginning 4) (match-end 4))))
290 ((re-search-forward "\\([^a-z]\\)\\([adfjmnos][acepou][bcglnprtvy]\\)\\([-a-z \t_]*\\)\\([0-9][0-9]?\\)"
291 (save-excursion (end-of-line) (point)) t)
292 (format "%2d-%3s"
293 (string-to-int (buffer-substring
294 (match-beginning 4)
295 (match-end 4)))
296 (buffer-substring
297 (match-beginning 2) (match-end 2))))
298 (t "??????"))))
299 " "
300 (save-excursion
301 (if (not (re-search-forward "^From:[ \t]*" nil t))
302 " "
303 (let* ((from (mail-strip-quoted-names
304 (buffer-substring
305 (1- (point))
306 (progn (end-of-line)
307 (skip-chars-backward " \t")
308 (point)))))
309 len mch lo)
310 (if (string-match (concat "^"
311 (regexp-quote (user-login-name))
312 "\\($\\|@\\)")
313 from)
314 (save-excursion
315 (goto-char (point-min))
316 (if (not (re-search-forward "^To:[ \t]*" nil t))
317 nil
318 (setq from
319 (concat "to: "
320 (mail-strip-quoted-names
321 (buffer-substring
322 (point)
323 (progn (end-of-line)
324 (skip-chars-backward " \t")
325 (point)))))))))
326 (setq len (length from))
327 (setq mch (string-match "[@%]" from))
328 (format "%25s"
329 (if (or (not mch) (<= len 25))
330 (substring from (max 0 (- len 25)))
331 (substring from
332 (setq lo (cond ((< (- mch 9) 0) 0)
333 ((< len (+ mch 16))
334 (- len 25))
335 (t (- mch 9))))
336 (min len (+ lo 25))))))))
337 " #"
338 (if (re-search-forward "^Subject:" nil t)
339 (progn (skip-chars-forward " \t")
340 (buffer-substring (point)
341 (progn (end-of-line)
342 (point))))
343 (re-search-forward "[\n][\n]+" nil t)
344 (buffer-substring (point) (progn (end-of-line) (point))))
345 "\n"))
346 \f
347 ;; Simple motion in a summary buffer.
348
349 (defun rmail-summary-next-all (&optional number)
350 (interactive "p")
351 (forward-line (if number number 1))
352 (display-buffer rmail-buffer))
353
354 (defun rmail-summary-previous-all (&optional number)
355 (interactive "p")
356 (forward-line (- (if number number 1)))
357 (display-buffer rmail-buffer))
358
359 (defun rmail-summary-next-msg (&optional number)
360 "Display next non-deleted msg from rmail file.
361 With optional prefix argument NUMBER, moves forward this number of non-deleted
362 messages, or backward if NUMBER is negative."
363 (interactive "p")
364 (forward-line 0)
365 (and (> number 0) (end-of-line))
366 (let ((count (if (< number 0) (- number) number))
367 (search (if (> number 0) 're-search-forward 're-search-backward))
368 (non-del-msg-found nil))
369 (while (and (> count 0) (setq non-del-msg-found
370 (or (funcall search "^....[^D]" nil t)
371 non-del-msg-found)))
372 (setq count (1- count))))
373 (beginning-of-line)
374 (display-buffer rmail-buffer))
375
376 (defun rmail-summary-previous-msg (&optional number)
377 (interactive "p")
378 (rmail-summary-next-msg (- (if number number 1))))
379
380 (defun rmail-summary-next-labeled-message (n labels)
381 "Show next message with LABEL. Defaults to last labels used.
382 With prefix argument N moves forward N messages with these labels."
383 (interactive "p\nsMove to next msg with labels: ")
384 (save-excursion
385 (set-buffer rmail-buffer)
386 (rmail-next-labeled-message n labels)))
387
388 (defun rmail-summary-previous-labeled-message (n labels)
389 "Show previous message with LABEL. Defaults to last labels used.
390 With prefix argument N moves backward N messages with these labels."
391 (interactive "p\nsMove to previous msg with labels: ")
392 (save-excursion
393 (set-buffer rmail-buffer)
394 (rmail-previous-labeled-message n labels)))
395 \f
396 ;; Delete and undelete summary commands.
397
398 (defun rmail-summary-delete-forward (&optional backward)
399 "Delete this message and move to next nondeleted one.
400 Deleted messages stay in the file until the \\[rmail-expunge] command is given.
401 With prefix argument, delete and move backward."
402 (interactive "P")
403 (let (end)
404 (rmail-summary-goto-msg)
405 (pop-to-buffer rmail-buffer)
406 (rmail-delete-forward backward)
407 (pop-to-buffer rmail-summary-buffer)))
408
409 (defun rmail-summary-delete-backward ()
410 "Delete this message and move to previous nondeleted one.
411 Deleted messages stay in the file until the \\[rmail-expunge] command is given."
412 (interactive)
413 (rmail-summary-delete-forward t))
414
415 (defun rmail-summary-mark-deleted (&optional n undel)
416 (and n (rmail-summary-goto-msg n t t))
417 (or (eobp)
418 (let ((buffer-read-only nil))
419 (skip-chars-forward " ")
420 (skip-chars-forward "[0-9]")
421 (if undel
422 (if (looking-at "D")
423 (progn (delete-char 1) (insert " ")))
424 (delete-char 1)
425 (insert "D"))))
426 (beginning-of-line))
427
428 (defun rmail-summary-mark-undeleted (n)
429 (rmail-summary-mark-deleted n t))
430
431 (defun rmail-summary-deleted-p (&optional n)
432 (save-excursion
433 (and n (rmail-summary-goto-msg n nil t))
434 (skip-chars-forward " ")
435 (skip-chars-forward "[0-9]")
436 (looking-at "D")))
437
438 (defun rmail-summary-undelete (&optional arg)
439 "Undelete current message.
440 Optional prefix ARG means undelete ARG previous messages."
441 (interactive "p")
442 (if (/= arg 1)
443 (rmail-summary-undelete-many arg)
444 (let ((buffer-read-only nil))
445 (end-of-line)
446 (cond ((re-search-backward "\\(^ *[0-9]*\\)\\(D\\)" nil t)
447 (replace-match "\\1 ")
448 (rmail-summary-goto-msg)
449 (pop-to-buffer rmail-buffer)
450 (and (rmail-message-deleted-p rmail-current-message)
451 (rmail-undelete-previous-message))
452 (pop-to-buffer rmail-summary-buffer))))))
453
454 (defun rmail-summary-undelete-many (&optional n)
455 "Undelete all deleted msgs, optional prefix arg N means undelete N prev msgs."
456 (interactive "P")
457 (save-excursion
458 (set-buffer rmail-buffer)
459 (let* ((init-msg (if n rmail-current-message rmail-total-messages))
460 (rmail-current-message init-msg)
461 (n (or n rmail-total-messages))
462 (msgs-undeled 0))
463 (while (and (> rmail-current-message 0)
464 (< msgs-undeled n))
465 (if (rmail-message-deleted-p rmail-current-message)
466 (progn (rmail-set-attribute "deleted" nil)
467 (setq msgs-undeled (1+ msgs-undeled))))
468 (setq rmail-current-message (1- rmail-current-message)))
469 (set-buffer rmail-summary-buffer)
470 (setq rmail-current-message init-msg msgs-undeled 0)
471 (while (and (> rmail-current-message 0)
472 (< msgs-undeled n))
473 (if (rmail-summary-deleted-p rmail-current-message)
474 (progn (rmail-summary-mark-undeleted rmail-current-message)
475 (setq msgs-undeled (1+ msgs-undeled))))
476 (setq rmail-current-message (1- rmail-current-message))))
477 (rmail-summary-goto-msg)))
478 \f
479 ;; Rmail Summary mode is suitable only for specially formatted data.
480 (put 'rmail-summary-mode 'mode-class 'special)
481
482 (defun rmail-summary-mode ()
483 "Rmail Summary Mode is invoked from Rmail Mode by using \\<rmail-mode-map>\\[rmail-summary].
484 As commands are issued in the summary buffer, they are applied to the
485 corresponding mail messages in the rmail buffer.
486
487 All normal editing commands are turned off.
488 Instead, nearly all the Rmail mode commands are available,
489 though many of them move only among the messages in the summary.
490
491 These additional commands exist:
492
493 \\[rmail-summary-undelete-many] Undelete all or prefix arg deleted messages.
494 \\[rmail-summary-wipe] Delete the summary and go to the Rmail buffer.
495
496 Commands for sorting the summary:
497
498 \\[rmail-summary-sort-by-date] Sort by date.
499 \\[rmail-summary-sort-by-subject] Sort by subject.
500 \\[rmail-summary-sort-by-author] Sort by author.
501 \\[rmail-summary-sort-by-recipient] Sort by recipient.
502 \\[rmail-summary-sort-by-correspondent] Sort by correspondent.
503 \\[rmail-summary-sort-by-lines] Sort by lines."
504 (interactive)
505 (kill-all-local-variables)
506 (setq major-mode 'rmail-summary-mode)
507 (setq mode-name "RMAIL Summary")
508 (use-local-map rmail-summary-mode-map)
509 (setq truncate-lines t)
510 (setq buffer-read-only t)
511 (set-syntax-table text-mode-syntax-table)
512 (make-local-variable 'rmail-buffer)
513 (make-local-variable 'rmail-total-messages)
514 (make-local-variable 'rmail-current-message)
515 (setq rmail-current-message nil)
516 (make-local-variable 'rmail-summary-redo)
517 (setq rmail-summary-redo nil)
518 (make-local-variable 'revert-buffer-function)
519 (setq revert-buffer-function 'rmail-update-summary)
520 (make-local-variable 'post-command-hook)
521 (add-hook 'post-command-hook 'rmail-summary-rmail-update)
522 (run-hooks 'rmail-summary-mode-hook))
523
524 ;; Show in Rmail the message described by the summary line that point is on,
525 ;; but only if the Rmail buffer is already visible.
526 ;; This is a post-command-hook in summary buffers.
527 (defun rmail-summary-rmail-update ()
528 (if (get-buffer-window rmail-buffer)
529 (let (buffer-read-only)
530 (save-excursion
531 (beginning-of-line)
532 (skip-chars-forward " ")
533 (let ((beg (point))
534 msg-num
535 (buf rmail-buffer))
536 (skip-chars-forward "0-9")
537 (setq msg-num (string-to-int (buffer-substring beg (point))))
538 (or (eq rmail-current-message msg-num)
539 (let (go-where window (owin (selected-window)))
540 (setq rmail-current-message msg-num)
541 (if (= (following-char) ?-)
542 (progn
543 (delete-char 1)
544 (insert " ")))
545 (setq window (display-buffer rmail-buffer))
546 ;; Using save-window-excursion caused the new value
547 ;; of point to get lost.
548 (unwind-protect
549 (progn
550 (select-window window)
551 (rmail-show-message msg-num))
552 (select-window owin)))))))))
553 \f
554 (defvar rmail-summary-mode-map nil)
555
556 (if rmail-summary-mode-map
557 nil
558 (setq rmail-summary-mode-map (make-keymap))
559 (suppress-keymap rmail-summary-mode-map)
560 (define-key rmail-summary-mode-map "a" 'rmail-summary-add-label)
561 (define-key rmail-summary-mode-map "c" 'rmail-summary-continue)
562 (define-key rmail-summary-mode-map "d" 'rmail-summary-delete-forward)
563 (define-key rmail-summary-mode-map "\C-d" 'rmail-summary-delete-backward)
564 (define-key rmail-summary-mode-map "e" 'rmail-summary-edit-current-message)
565 (define-key rmail-summary-mode-map "f" 'rmail-summary-forward)
566 (define-key rmail-summary-mode-map "g" 'rmail-summary-get-new-mail)
567 (define-key rmail-summary-mode-map "h" 'rmail-summary)
568 (define-key rmail-summary-mode-map "i" 'rmail-summary-input)
569 (define-key rmail-summary-mode-map "j" 'rmail-summary-goto-msg)
570 (define-key rmail-summary-mode-map "k" 'rmail-summary-kill-label)
571 (define-key rmail-summary-mode-map "l" 'rmail-summary-by-labels)
572 (define-key rmail-summary-mode-map "\e\C-h" 'rmail-summary)
573 (define-key rmail-summary-mode-map "\e\C-l" 'rmail-summary-by-labels)
574 (define-key rmail-summary-mode-map "\e\C-r" 'rmail-summary-by-recipients)
575 (define-key rmail-summary-mode-map "\e\C-s" 'rmail-summary-by-regexp)
576 (define-key rmail-summary-mode-map "\e\C-t" 'rmail-summary-by-topic)
577 (define-key rmail-summary-mode-map "m" 'rmail-summary-mail)
578 (define-key rmail-summary-mode-map "\M-m" 'rmail-summary-retry-failure)
579 (define-key rmail-summary-mode-map "n" 'rmail-summary-next-msg)
580 (define-key rmail-summary-mode-map "\en" 'rmail-summary-next-all)
581 (define-key rmail-summary-mode-map "\e\C-n" 'rmail-summary-next-labeled-message)
582 (define-key rmail-summary-mode-map "o" 'rmail-summary-output-to-rmail-file)
583 (define-key rmail-summary-mode-map "\C-o" 'rmail-summary-output)
584 (define-key rmail-summary-mode-map "p" 'rmail-summary-previous-msg)
585 (define-key rmail-summary-mode-map "\ep" 'rmail-summary-previous-all)
586 (define-key rmail-summary-mode-map "\e\C-p" 'rmail-summary-previous-labeled-message)
587 (define-key rmail-summary-mode-map "q" 'rmail-summary-quit)
588 (define-key rmail-summary-mode-map "r" 'rmail-summary-reply)
589 (define-key rmail-summary-mode-map "s" 'rmail-summary-expunge-and-save)
590 (define-key rmail-summary-mode-map "\es" 'rmail-summary-search)
591 (define-key rmail-summary-mode-map "t" 'rmail-summary-toggle-header)
592 (define-key rmail-summary-mode-map "u" 'rmail-summary-undelete)
593 (define-key rmail-summary-mode-map "\M-u" 'rmail-summary-undelete-many)
594 (define-key rmail-summary-mode-map "w" 'rmail-summary-wipe)
595 (define-key rmail-summary-mode-map "x" 'rmail-summary-expunge)
596 (define-key rmail-summary-mode-map "." 'rmail-summary-beginning-of-message)
597 (define-key rmail-summary-mode-map "<" 'rmail-summary-first-message)
598 (define-key rmail-summary-mode-map ">" 'rmail-summary-last-message)
599 (define-key rmail-summary-mode-map " " 'rmail-summary-scroll-msg-up)
600 (define-key rmail-summary-mode-map "\177" 'rmail-summary-scroll-msg-down)
601 (define-key rmail-summary-mode-map "?" 'describe-mode)
602 (define-key rmail-summary-mode-map "\C-c\C-s\C-d"
603 'rmail-summary-sort-by-date)
604 (define-key rmail-summary-mode-map "\C-c\C-s\C-s"
605 'rmail-summary-sort-by-subject)
606 (define-key rmail-summary-mode-map "\C-c\C-s\C-a"
607 'rmail-summary-sort-by-author)
608 (define-key rmail-summary-mode-map "\C-c\C-s\C-r"
609 'rmail-summary-sort-by-recipient)
610 (define-key rmail-summary-mode-map "\C-c\C-s\C-c"
611 'rmail-summary-sort-by-correspondent)
612 (define-key rmail-summary-mode-map "\C-c\C-s\C-l"
613 'rmail-summary-sort-by-lines)
614 )
615 \f
616 ;;; Menu bar bindings.
617
618 (define-key rmail-summary-mode-map [menu-bar] (make-sparse-keymap))
619
620 (define-key rmail-summary-mode-map [menu-bar classify]
621 (cons "Classify" (make-sparse-keymap "Classify")))
622
623 (define-key rmail-summary-mode-map [menu-bar classify output-inbox]
624 '("Output (inbox)" . rmail-summary-output))
625
626 (define-key rmail-summary-mode-map [menu-bar classify output]
627 '("Output (Rmail)" . rmail-summary-output-to-rmail-file))
628
629 (define-key rmail-summary-mode-map [menu-bar classify kill-label]
630 '("Kill Label" . rmail-summary-kill-label))
631
632 (define-key rmail-summary-mode-map [menu-bar classify add-label]
633 '("Add Label" . rmail-summary-add-label))
634
635 (define-key rmail-summary-mode-map [menu-bar summary]
636 (cons "Summary" (make-sparse-keymap "Summary")))
637
638 (define-key rmail-summary-mode-map [menu-bar summary labels]
639 '("By Labels" . rmail-summary-by-labels))
640
641 (define-key rmail-summary-mode-map [menu-bar summary recipients]
642 '("By Recipients" . rmail-summary-by-recipients))
643
644 (define-key rmail-summary-mode-map [menu-bar summary topic]
645 '("By Topic" . rmail-summary-by-topic))
646
647 (define-key rmail-summary-mode-map [menu-bar summary regexp]
648 '("By Regexp" . rmail-summary-by-regexp))
649
650 (define-key rmail-summary-mode-map [menu-bar summary all]
651 '("All" . rmail-summary))
652
653 (define-key rmail-summary-mode-map [menu-bar mail]
654 (cons "Mail" (make-sparse-keymap "Mail")))
655
656 (define-key rmail-summary-mode-map [menu-bar mail continue]
657 '("Continue" . rmail-summary-continue))
658
659 (define-key rmail-summary-mode-map [menu-bar mail forward]
660 '("Forward" . rmail-summary-forward))
661
662 (define-key rmail-summary-mode-map [menu-bar mail retry]
663 '("Retry" . rmail-summary-retry-failure))
664
665 (define-key rmail-summary-mode-map [menu-bar mail reply]
666 '("Reply" . rmail-summary-reply))
667
668 (define-key rmail-summary-mode-map [menu-bar mail mail]
669 '("Mail" . rmail-summary-mail))
670
671 (define-key rmail-summary-mode-map [menu-bar delete]
672 (cons "Delete" (make-sparse-keymap "Delete")))
673
674 (define-key rmail-summary-mode-map [menu-bar delete expunge/save]
675 '("Expunge/Save" . rmail-summary-expunge-and-save))
676
677 (define-key rmail-summary-mode-map [menu-bar delete expunge]
678 '("Expunge" . rmail-summary-expunge))
679
680 (define-key rmail-summary-mode-map [menu-bar delete undelete]
681 '("Undelete" . rmail-summary-undelete))
682
683 (define-key rmail-summary-mode-map [menu-bar delete delete]
684 '("Delete" . rmail-summary-delete-forward))
685
686 (define-key rmail-summary-mode-map [menu-bar move]
687 (cons "Move" (make-sparse-keymap "Move")))
688
689 (define-key rmail-summary-mode-map [menu-bar move search-back]
690 '("Search Back" . rmail-summary-search-backward))
691
692 (define-key rmail-summary-mode-map [menu-bar move search]
693 '("Search" . rmail-summary-search))
694
695 (define-key rmail-summary-mode-map [menu-bar move previous]
696 '("Previous Nondeleted" . rmail-summary-previous-msg))
697
698 (define-key rmail-summary-mode-map [menu-bar move next]
699 '("Next Nondeleted" . rmail-summary-next-msg))
700
701 (define-key rmail-summary-mode-map [menu-bar move last]
702 '("Last" . rmail-summary-last-message))
703
704 (define-key rmail-summary-mode-map [menu-bar move first]
705 '("First" . rmail-summary-first-message))
706
707 (define-key rmail-summary-mode-map [menu-bar move previous]
708 '("Previous" . rmail-summary-previous-all))
709
710 (define-key rmail-summary-mode-map [menu-bar move next]
711 '("Next" . rmail-summary-next-all))
712 \f
713 (defun rmail-summary-goto-msg (&optional n nowarn skip-rmail)
714 (interactive "P")
715 (if (consp n) (setq n (prefix-numeric-value n)))
716 (if (eobp) (forward-line -1))
717 (beginning-of-line)
718 (let ((buf rmail-buffer)
719 (cur (point))
720 (curmsg (string-to-int
721 (buffer-substring (point)
722 (min (point-max) (+ 5 (point)))))))
723 (if (not n)
724 (setq n curmsg)
725 (if (< n 1)
726 (progn (message "No preceding message")
727 (setq n 1)))
728 (if (> n rmail-total-messages)
729 (progn (message "No following message")
730 (goto-char (point-max))
731 (rmail-summary-goto-msg)))
732 (goto-char (point-min))
733 (if (not (re-search-forward (concat "^ *" (int-to-string n)) nil t))
734 (progn (or nowarn (message "Message %d not found" n))
735 (setq n curmsg)
736 (goto-char cur))))
737 (beginning-of-line)
738 (skip-chars-forward " ")
739 (skip-chars-forward "0-9")
740 (save-excursion (if (= (following-char) ?-)
741 (let ((buffer-read-only nil))
742 (delete-char 1)
743 (insert " "))))
744 (beginning-of-line)
745 (if skip-rmail
746 nil
747 (pop-to-buffer buf)
748 (rmail-show-message n)
749 (pop-to-buffer rmail-summary-buffer))))
750 \f
751 (defun rmail-summary-scroll-msg-up (&optional dist)
752 "Scroll other window forward."
753 (interactive "P")
754 (scroll-other-window dist))
755
756 (defun rmail-summary-scroll-msg-down (&optional dist)
757 "Scroll other window backward."
758 (interactive "P")
759 (scroll-other-window
760 (cond ((eq dist '-) nil)
761 ((null dist) '-)
762 (t (- (prefix-numeric-value dist))))))
763
764 (defun rmail-summary-beginning-of-message ()
765 "Show current message from the beginning."
766 (interactive)
767 (pop-to-buffer rmail-buffer)
768 (beginning-of-buffer)
769 (pop-to-buffer rmail-summary-buffer))
770
771 (defun rmail-summary-quit ()
772 "Quit out of Rmail and Rmail summary."
773 (interactive)
774 (rmail-summary-wipe)
775 (rmail-quit))
776
777 (defun rmail-summary-wipe ()
778 "Kill and wipe away Rmail summary, remaining within Rmail."
779 (interactive)
780 (save-excursion (set-buffer rmail-buffer) (setq rmail-summary-buffer nil))
781 (let ((local-rmail-buffer rmail-buffer))
782 (kill-buffer (current-buffer))
783 ;; Delete window if not only one.
784 (if (not (eq (selected-window) (next-window nil 'no-minibuf)))
785 (delete-window))
786 ;; Switch windows to the rmail buffer, or switch to it in this window.
787 (pop-to-buffer local-rmail-buffer)))
788
789 (defun rmail-summary-expunge ()
790 "Actually erase all deleted messages and recompute summary headers."
791 (interactive)
792 (save-excursion
793 (set-buffer rmail-buffer)
794 (rmail-only-expunge))
795 (rmail-update-summary))
796
797 (defun rmail-summary-expunge-and-save ()
798 "Expunge and save RMAIL file."
799 (interactive)
800 (save-excursion
801 (set-buffer rmail-buffer)
802 (rmail-only-expunge))
803 (rmail-update-summary)
804 (save-excursion
805 (set-buffer rmail-buffer)
806 (save-buffer)))
807
808 (defun rmail-summary-get-new-mail ()
809 "Get new mail and recompute summary headers."
810 (interactive)
811 (let (msg)
812 (save-excursion
813 (set-buffer rmail-buffer)
814 (rmail-get-new-mail)
815 ;; Get the proper new message number.
816 (setq msg rmail-current-message))
817 ;; Make sure that message is displayed.
818 (rmail-summary-goto-msg msg)))
819
820 (defun rmail-summary-input (filename)
821 "Run Rmail on file FILENAME."
822 (interactive "FRun rmail on RMAIL file: ")
823 ;; We switch windows here, then display the other Rmail file there.
824 (pop-to-buffer rmail-buffer)
825 (rmail filename))
826
827 (defun rmail-summary-first-message ()
828 "Show first message in Rmail file from summary buffer."
829 (interactive)
830 (beginning-of-buffer))
831
832 (defun rmail-summary-last-message ()
833 "Show last message in Rmail file from summary buffer."
834 (interactive)
835 (end-of-buffer)
836 (forward-line -1))
837
838 (defvar rmail-summary-edit-map nil)
839 (if rmail-summary-edit-map
840 nil
841 (setq rmail-summary-edit-map
842 (nconc (make-sparse-keymap) text-mode-map))
843 (define-key rmail-summary-edit-map "\C-c\C-c" 'rmail-cease-edit)
844 (define-key rmail-summary-edit-map "\C-c\C-]" 'rmail-abort-edit))
845
846 (defun rmail-summary-edit-current-message ()
847 "Edit the contents of this message."
848 (interactive)
849 (pop-to-buffer rmail-buffer)
850 (rmail-edit-current-message)
851 (use-local-map rmail-summary-edit-map))
852
853 (defun rmail-summary-cease-edit ()
854 "Finish editing message, then go back to Rmail summary buffer."
855 (interactive)
856 (rmail-cease-edit)
857 (pop-to-buffer rmail-summary-buffer))
858
859 (defun rmail-summary-abort-edit ()
860 "Abort edit of current message; restore original contents.
861 Go back to summary buffer."
862 (interactive)
863 (rmail-abort-edit)
864 (pop-to-buffer rmail-summary-buffer))
865
866 (defun rmail-summary-search-backward (regexp &optional n)
867 "Show message containing next match for REGEXP.
868 Prefix argument gives repeat count; negative argument means search
869 backwards (through earlier messages).
870 Interactively, empty argument means use same regexp used last time."
871 (interactive
872 (let* ((reversep (>= (prefix-numeric-value current-prefix-arg) 0))
873 (prompt
874 (concat (if reversep "Reverse " "") "Rmail search (regexp): "))
875 regexp)
876 (if rmail-search-last-regexp
877 (setq prompt (concat prompt
878 "(default "
879 rmail-search-last-regexp
880 ") ")))
881 (setq regexp (read-string prompt))
882 (cond ((not (equal regexp ""))
883 (setq rmail-search-last-regexp regexp))
884 ((not rmail-search-last-regexp)
885 (error "No previous Rmail search string")))
886 (list rmail-search-last-regexp
887 (prefix-numeric-value current-prefix-arg))))
888 ;; Don't use save-excursion because that prevents point from moving
889 ;; properly in the summary buffer.
890 (let ((buffer (current-buffer)))
891 (unwind-protect
892 (progn
893 (set-buffer rmail-buffer)
894 (rmail-search regexp (- n)))
895 (set-buffer buffer))))
896
897 (defun rmail-summary-search (regexp &optional n)
898 "Show message containing next match for REGEXP.
899 Prefix argument gives repeat count; negative argument means search
900 backwards (through earlier messages).
901 Interactively, empty argument means use same regexp used last time."
902 (interactive
903 (let* ((reversep (< (prefix-numeric-value current-prefix-arg) 0))
904 (prompt
905 (concat (if reversep "Reverse " "") "Rmail search (regexp): "))
906 regexp)
907 (if rmail-search-last-regexp
908 (setq prompt (concat prompt
909 "(default "
910 rmail-search-last-regexp
911 ") ")))
912 (setq regexp (read-string prompt))
913 (cond ((not (equal regexp ""))
914 (setq rmail-search-last-regexp regexp))
915 ((not rmail-search-last-regexp)
916 (error "No previous Rmail search string")))
917 (list rmail-search-last-regexp
918 (prefix-numeric-value current-prefix-arg))))
919 ;; Don't use save-excursion because that prevents point from moving
920 ;; properly in the summary buffer.
921 (let ((buffer (current-buffer)))
922 (unwind-protect
923 (progn
924 (set-buffer rmail-buffer)
925 (rmail-search regexp n))
926 (set-buffer buffer))))
927
928 (defun rmail-summary-toggle-header ()
929 "Show original message header if pruned header currently shown, or vice versa."
930 (interactive)
931 (save-excursion
932 (set-buffer rmail-buffer)
933 (rmail-toggle-header)))
934
935 (defun rmail-summary-add-label (label)
936 "Add LABEL to labels associated with current Rmail message.
937 Completion is performed over known labels when reading."
938 (interactive (list (save-excursion
939 (set-buffer rmail-buffer)
940 (rmail-read-label "Add label"))))
941 (save-excursion
942 (set-buffer rmail-buffer)
943 (rmail-add-label label)))
944
945 (defun rmail-summary-kill-label (label)
946 "Remove LABEL from labels associated with current Rmail message.
947 Completion is performed over known labels when reading."
948 (interactive (list (save-excursion
949 (set-buffer rmail-buffer)
950 (rmail-read-label "Kill label"))))
951 (save-excursion
952 (set-buffer rmail-buffer)
953 (rmail-set-label label nil)))
954 \f
955 ;;;; *** Rmail Summary Mailing Commands ***
956
957 (defun rmail-summary-mail ()
958 "Send mail in another window.
959 While composing the message, use \\[mail-yank-original] to yank the
960 original message into it."
961 (interactive)
962 (mail-other-window nil nil nil nil nil rmail-buffer)
963 (use-local-map (copy-keymap (current-local-map)))
964 (define-key (current-local-map)
965 "\C-c\C-c" 'rmail-summary-send-and-exit))
966
967 (defun rmail-summary-continue ()
968 "Continue composing outgoing message previously being composed."
969 (interactive)
970 (mail-other-window t))
971
972 (defun rmail-summary-reply (just-sender)
973 "Reply to the current message.
974 Normally include CC: to all other recipients of original message;
975 prefix argument means ignore them.
976 While composing the reply, use \\[mail-yank-original] to yank the
977 original message into it."
978 (interactive "P")
979 (let (mailbuf)
980 (save-window-excursion
981 (set-buffer rmail-buffer)
982 (rmail-reply just-sender)
983 (setq mailbuf (current-buffer)))
984 (pop-to-buffer mailbuf)
985 (use-local-map (copy-keymap (current-local-map)))
986 (define-key (current-local-map)
987 "\C-c\C-c" 'rmail-summary-send-and-exit)))
988
989 (defun rmail-summary-retry-failure ()
990 "Edit a mail message which is based on the contents of the current message.
991 For a message rejected by the mail system, extract the interesting headers and
992 the body of the original message; otherwise copy the current message."
993 (interactive)
994 (let (mailbuf)
995 (save-window-excursion
996 (set-buffer rmail-buffer)
997 (rmail-retry-failure)
998 (setq mailbuf (current-buffer)))
999 (pop-to-buffer mailbuf)
1000 (use-local-map (copy-keymap (current-local-map)))
1001 (define-key (current-local-map)
1002 "\C-c\C-c" 'rmail-summary-send-and-exit)))
1003
1004 (defun rmail-summary-send-and-exit ()
1005 "Send mail reply and return to summary buffer."
1006 (interactive)
1007 (mail-send-and-exit t))
1008
1009 (defun rmail-summary-forward (resend)
1010 "Forward the current message to another user.
1011 With prefix argument, \"resend\" the message instead of forwarding it;
1012 see the documentation of `rmail-resend'."
1013 (interactive "P")
1014 (save-excursion
1015 (set-buffer rmail-buffer)
1016 (rmail-forward resend)
1017 (use-local-map (copy-keymap (current-local-map)))
1018 (define-key (current-local-map)
1019 "\C-c\C-c" 'rmail-summary-send-and-exit)))
1020 \f
1021 ;; Summary output commands.
1022
1023 (defun rmail-summary-output-to-rmail-file ()
1024 "Append the current message to an Rmail file named FILE-NAME.
1025 If the file does not exist, ask if it should be created.
1026 If file is being visited, the message is appended to the Emacs
1027 buffer visiting that file."
1028 (interactive)
1029 (save-excursion
1030 (set-buffer rmail-buffer)
1031 (call-interactively 'rmail-output-to-rmail-file)))
1032
1033 (defun rmail-summary-output ()
1034 "Append this message to Unix mail file named FILE-NAME."
1035 (interactive)
1036 (save-excursion
1037 (set-buffer rmail-buffer)
1038 (call-interactively 'rmail-output)))
1039 \f
1040 ;; Sorting messages in Rmail Summary buffer.
1041
1042 (defun rmail-summary-sort-by-date (reverse)
1043 "Sort messages of current Rmail summary by date.
1044 If prefix argument REVERSE is non-nil, sort them in reverse order."
1045 (interactive "P")
1046 (rmail-sort-from-summary (function rmail-sort-by-date) reverse))
1047
1048 (defun rmail-summary-sort-by-subject (reverse)
1049 "Sort messages of current Rmail summary by subject.
1050 If prefix argument REVERSE is non-nil, sort them in reverse order."
1051 (interactive "P")
1052 (rmail-sort-from-summary (function rmail-sort-by-subject) reverse))
1053
1054 (defun rmail-summary-sort-by-author (reverse)
1055 "Sort messages of current Rmail summary by author.
1056 If prefix argument REVERSE is non-nil, sort them in reverse order."
1057 (interactive "P")
1058 (rmail-sort-from-summary (function rmail-sort-by-author) reverse))
1059
1060 (defun rmail-summary-sort-by-recipient (reverse)
1061 "Sort messages of current Rmail summary by recipient.
1062 If prefix argument REVERSE is non-nil, sort them in reverse order."
1063 (interactive "P")
1064 (rmail-sort-from-summary (function rmail-sort-by-recipient) reverse))
1065
1066 (defun rmail-summary-sort-by-correspondent (reverse)
1067 "Sort messages of current Rmail summary by other correspondent.
1068 If prefix argument REVERSE is non-nil, sort them in reverse order."
1069 (interactive "P")
1070 (rmail-sort-from-summary (function rmail-sort-by-correspondent) reverse))
1071
1072 (defun rmail-summary-sort-by-lines (reverse)
1073 "Sort messages of current Rmail summary by lines of the message.
1074 If prefix argument REVERSE is non-nil, sort them in reverse order."
1075 (interactive "P")
1076 (rmail-sort-from-summary (function rmail-sort-by-lines) reverse))
1077
1078 (defun rmail-sort-from-summary (sortfun reverse)
1079 "Sort Rmail messages from Summary buffer and update it after sorting."
1080 (require 'rmailsort)
1081 (pop-to-buffer rmail-buffer)
1082 (funcall sortfun reverse)
1083 (rmail-summary))
1084
1085 ;;; rmailsum.el ends here