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