|
|
1.1 root 1: ;; "RMAIL" mail reader for Emacs.
2: ;; Copyright (C) 1985 Richard M. Stallman.
3:
4: ;; This file is part of GNU Emacs.
5:
6: ;; GNU Emacs is distributed in the hope that it will be useful,
7: ;; but WITHOUT ANY WARRANTY. No author or distributor
8: ;; accepts responsibility to anyone for the consequences of using it
9: ;; or for whether it serves any particular purpose or works at all,
10: ;; unless he says so in writing. Refer to the GNU Emacs General Public
11: ;; License for full details.
12:
13: ;; Everyone is granted permission to copy, modify and redistribute
14: ;; GNU Emacs, but only under the conditions described in the
15: ;; GNU Emacs General Public License. A copy of this license is
16: ;; supposed to have been given to you along with GNU Emacs so you
17: ;; can know your rights and responsibilities. It should be in a
18: ;; file named COPYING. Among other things, the copyright notice
19: ;; and this notice must be preserved on all copies.
20:
21:
22: ;; summary things
23:
24: (defun rmail-summary ()
25: "Display a summary of all messages, one line per message."
26: (interactive)
27: (rmail-new-summary "Full summary" nil))
28:
29: (defun rmail-summary-by-labels (labels)
30: "Display a summary of all messages with one or more LABELS.
31: LABELS should be a string containing the desired labels, separated by commas."
32: (interactive "sLabels to summarize by: ")
33: (if (string= labels "")
34: (setq labels (or rmail-last-multi-labels
35: (error "No label specified"))))
36: (setq rmail-last-multi-labels labels)
37: (rmail-new-summary (concat "Summary of " labels)
38: 'rmail-message-labels-p
39: (concat ",\\(" (mail-comma-list-regexp labels) "\\),")))
40:
41: (defun rmail-summary-by-recipients (recipients &optional primary-only)
42: "Display a summary of all messages with the given RECIPIENTS.
43: Normally checks the To, From and Cc fields of headers;
44: but if PRIMARY-ONLY is non-nil (prefix arg given),
45: only look in the To and From fields.
46: RECIPIENTS is a string of names separated by commas."
47: (interactive "sRecipients to summarize by: \nP")
48: (rmail-new-summary
49: (concat "Summary of " recipients)
50: 'rmail-message-recipients-p
51: (mail-comma-list-regexp recipients) primary-only))
52:
53: (defun rmail-message-recipients-p (msg recipients &optional primary-only)
54: (save-restriction
55: (goto-char (rmail-msgbeg msg))
56: (search-forward "\n*** EOOH ***\n")
57: (narrow-to-region (point) (progn (search-forward "\n\n") (point)))
58: (or (string-match recipients (or (mail-fetch-field "To") ""))
59: (string-match recipients (or (mail-fetch-field "From") ""))
60: (if (not primary-only)
61: (string-match recipients (or (mail-fetch-field "Cc") ""))))))
62:
63: (defun rmail-new-summary (description function &rest args)
64: "Create a summary of selected messages.
65: DESCRIPTION makes part of the mode line of the summary buffer.
66: For each message, FUNCTION is applied to the message number and ARGS...
67: and if the result is non-nil, that message is included.
68: nil for FUNCTION means all messages."
69: (message "Computing summary lines...")
70: (or (and rmail-summary-buffer
71: (buffer-name rmail-summary-buffer))
72: (setq rmail-summary-buffer
73: (generate-new-buffer (concat (buffer-name) "-summary"))))
74: (let (summary-msgs)
75: (let ((msgnum 1)
76: (new-summary-line-count 0)
77: (buffer-read-only nil))
78: (save-restriction
79: (save-excursion
80: (widen)
81: (goto-char (point-min))
82: (while (>= rmail-total-messages msgnum)
83: (if (or (null function)
84: (apply function (cons msgnum args)))
85: (setq summary-msgs
86: (cons (rmail-make-summary-line msgnum)
87: summary-msgs)))
88: (setq msgnum (1+ msgnum))))))
89: (let ((sbuf rmail-summary-buffer)
90: (rbuf (current-buffer))
91: (total rmail-total-messages)
92: (mesg rmail-current-message))
93: (pop-to-buffer sbuf)
94: (let (buffer-read-only)
95: (erase-buffer)
96: (cond (summary-msgs
97: (princ (nreverse summary-msgs) sbuf)
98: (delete-char -1)
99: (subst-char-in-region 1 2 ?\( ?\ ))))
100: (setq buffer-read-only t)
101: (goto-char (point-min))
102: (rmail-summary-mode)
103: (rmail-summary-mode-line description)
104: (setq rmail-buffer rbuf
105: rmail-total-messages total)
106: (if (> total 0)
107: (rmail-summary-goto-msg mesg t))))
108: (message "Computing summary lines...done"))
109:
110: (defun rmail-make-summary-line (msg)
111: (let ((line (or (aref rmail-summary-vector (1- msg))
112: (progn
113: (setq new-summary-line-count
114: (1+ new-summary-line-count))
115: (if (zerop (% new-summary-line-count 10))
116: (message "Computing summary lines...%d"
117: new-summary-line-count))
118: (rmail-make-summary-line-1 msg)))))
119: ;; Fix up the part of the summary that says "deleted" or "unseen".
120: (aset line 4
121: (if (rmail-message-deleted-p msg) ?\D
122: (if (= ?0 (char-after (+ 3 (rmail-msgbeg msg))))
123: ?\- ?\ )))
124: line))
125:
126: (defun rmail-make-summary-line-1 (msg)
127: (goto-char (rmail-msgbeg msg))
128: (let* ((lim (save-excursion (forward-line 2) (point)))
129: pos
130: (labels
131: (progn
132: (forward-char 3)
133: (concat
134: ; (if (save-excursion (re-search-forward ",answered," lim t))
135: ; "*" "")
136: ; (if (save-excursion (re-search-forward ",filed," lim t))
137: ; "!" "")
138: (if (progn (search-forward ",,") (eolp))
139: ""
140: (concat "{"
141: (buffer-substring (point)
142: (progn (end-of-line) (point)))
143: "} ")))))
144: (line
145: (progn
146: (forward-line 1)
147: (if (looking-at "Summary-line: ")
148: (progn
149: (goto-char (match-end 0))
150: (setq line
151: (buffer-substring (point)
152: (progn (forward-line 1) (point)))))))))
153: ;; Obsolete status lines lacking a # should be flushed.
154: (and line
155: (not (string-match "#" line))
156: (progn
157: (delete-region (point)
158: (progn (forward-line -1) (point)))
159: (setq line nil)))
160: ;; If we didn't get a valid status line from the message,
161: ;; make a new one and put it in the message.
162: (or line
163: (let* ((case-fold-search t)
164: (next (rmail-msgend msg))
165: (beg (if (progn (goto-char (rmail-msgbeg msg))
166: (search-forward "\n*** EOOH ***\n" next t))
167: (point)
168: (forward-line 1)
169: (point)))
170: (end (progn (search-forward "\n\n" nil t) (point))))
171: (save-restriction
172: (narrow-to-region beg end)
173: (goto-char beg)
174: (setq line (rmail-make-basic-summary-line)))
175: (goto-char (rmail-msgbeg msg))
176: (forward-line 2)
177: (insert "Summary-line: " line)))
178: (setq pos (string-match "#" line))
179: (aset rmail-summary-vector (1- msg)
180: (concat (format "%4d " msg)
181: (substring line 0 pos)
182: labels
183: (substring line (1+ pos))))))
184:
185: (defun rmail-make-basic-summary-line ()
186: (goto-char (point-min))
187: (concat (save-excursion
188: (if (not (search-forward "Date:" nil t))
189: " "
190: (if (re-search-forward
191: "\\([^0-9:]\\)\\([0-3]?[0-9]\\)\\([ \t-_]+\\)\\([a-z][a-z][a-z]\\)"
192: (save-excursion (end-of-line) (point)) t)
193: (format "%2s-%3s"
194: (buffer-substring
195: (match-beginning 2) (match-end 2))
196: (buffer-substring
197: (match-beginning 4) (match-end 4)))
198: (if (not (re-search-forward
199: "\\([^a-z]\\)\\([a-z][a-z][a-z]\\)\\([a-z \t-_]*\\)\\([0-9][0-9]?\\)"
200: (save-excursion (end-of-line) (point)) t))
201: "??????"
202: (format "%2s-%3s"
203: (buffer-substring
204: (match-beginning 4) (match-end 4))
205: (buffer-substring
206: (match-beginning 2) (match-end 2)))))))
207: " "
208: (save-excursion
209: (if (not (search-forward "From:" nil t))
210: " "
211: (progn (skip-chars-forward " \t")
212: (let* ((from (mail-strip-quoted-names
213: (buffer-substring
214: (1- (point))
215: (progn (end-of-line)
216: (skip-chars-backward " ")
217: (point)))))
218: (len (length from))
219: (mch (string-match "[@%]" from))
220: lo)
221: (format "%25s"
222: (if (or (not mch) (<= len 25))
223: (substring from (max 0 (- len 25)))
224: (substring from
225: (setq lo (cond ((< (- mch 9) 0) 0)
226: ((< len (+ mch 16))
227: (- len 25))
228: (t (- mch 9))))
229: (min len (+ lo 25)))))))))
230: " #"
231: (if (search-forward "Subject:" nil t)
232: (progn (skip-chars-forward " \t")
233: (buffer-substring (point)
234: (progn (end-of-line)
235: (point))))
236: (re-search-forward "[\n][\n]+" nil t)
237: (buffer-substring (point) (progn (end-of-line) (point))))
238: "\n"))
239:
240: (defun rmail-summary-next-all (&optional number)
241: (interactive "p")
242: (forward-line (if number number 1))
243: (rmail-summary-goto-msg))
244:
245: (defun rmail-summary-previous-all (&optional number)
246: (interactive "p")
247: (forward-line (- (if number number 1)))
248: (rmail-summary-goto-msg))
249:
250: (defun rmail-summary-next-msg (&optional number)
251: (interactive "p")
252: (forward-line 0)
253: (and (> number 0) (forward-line 1))
254: (let ((count (if (< number 0) (- number) number))
255: (search (if (> number 0) 're-search-forward 're-search-backward))
256: end)
257: (while (and (> count 0) (funcall search "^.....[^D]" nil t))
258: (setq count (1- count)))
259: (rmail-summary-goto-msg)))
260:
261: (defun rmail-summary-previous-msg (&optional number)
262: (interactive "p")
263: (rmail-summary-next-msg (- (if number number 1))))
264:
265: (defun rmail-summary-delete-forward ()
266: (interactive)
267: (let (end)
268: (rmail-summary-goto-msg)
269: (pop-to-buffer rmail-buffer)
270: (rmail-delete-message)
271: (pop-to-buffer rmail-summary-buffer)
272: (let ((buffer-read-only nil))
273: (skip-chars-forward " ")
274: (skip-chars-forward "[0-9]")
275: (delete-char 1)
276: (insert "D"))
277: (rmail-summary-next-msg 1)))
278:
279: (defun rmail-summary-undelete ()
280: (interactive)
281: (let ((buffer-read-only nil))
282: (end-of-line)
283: (cond ((re-search-backward "\\(^ *[0-9]*\\)\\(D\\)" nil t)
284: (replace-match "\\1 ")
285: (rmail-summary-goto-msg)
286: (pop-to-buffer rmail-buffer)
287: (and (rmail-message-deleted-p rmail-current-message)
288: (rmail-undelete-previous-message))
289: (pop-to-buffer rmail-summary-buffer))
290: (t
291: (rmail-summary-goto-msg)))))
292:
293: (defun rmail-summary-mode ()
294: "RMAIL Summary Mode.
295: A subset of the Rmail mode commands are supported in this mode.
296: As commands are issued in the summary buffer the corresponding
297: mail message is displayed in the rmail buffer.
298:
299: n Move to next undeleted message, or arg messages.
300: p Move to previous undeleted message, or arg messages.
301: C-n Move to next, or forward arg messages.
302: C-p Move to previous, or previous arg messages.
303: j Jump to the message at the cursor location.
304: d Delete the message at the cursor location and move to next message.
305: u Undelete this or previous deleted message.
306: q Quit Rmail.
307: x Exit and kill the summary window.
308: space Scroll message in other window forward.
309: delete Scroll message backward.
310:
311: Entering this mode calls value of hook variable rmail-summary-mode-hook."
312: (interactive)
313: (kill-all-local-variables)
314: (make-local-variable 'rmail-buffer)
315: (make-local-variable 'rmail-total-messages)
316: (setq major-mode 'rmail-summary-mode)
317: (setq mode-name "RMAIL Summary")
318: (use-local-map rmail-summary-mode-map)
319: (setq truncate-lines t)
320: (setq buffer-read-only t)
321: (set-syntax-table text-mode-syntax-table)
322: (run-hooks 'rmail-summary-mode-hook))
323:
324: (defun rmail-summary-mode-line (description)
325: (setq mode-line-format
326: (concat "---Emacs: %17b %M %[(" description ")%]----%3p-%-")))
327:
328: (defun rmail-summary-goto-msg (&optional n nowarn)
329: (interactive "P")
330: (if (consp n) (setq n (prefix-numeric-value n)))
331: (if (eobp) (forward-line -1))
332: (beginning-of-line)
333: (let ((buf rmail-buffer)
334: (cur (point))
335: (curmsg (string-to-int (buffer-substring (point) (+ 5 (point))))))
336: (if (not n)
337: (setq n curmsg)
338: (if (< n 1)
339: (progn (message "No preceding message")
340: (setq n 1)))
341: (if (> n rmail-total-messages)
342: (progn (message "No following message")
343: (goto-char (point-max))
344: (rmail-summary-goto-msg)))
345: (goto-char (point-min))
346: (if (not (re-search-forward (concat "^ *" (int-to-string n)) nil t))
347: (progn (or nowarn (message "Message %d not found" n))
348: (setq n curmsg)
349: (goto-char cur))))
350: (beginning-of-line)
351: (skip-chars-forward " ")
352: (skip-chars-forward "0-9")
353: (save-excursion (if (= (following-char) ?-)
354: (let ((buffer-read-only nil))
355: (delete-char 1)
356: (insert " "))))
357: (beginning-of-line)
358: (pop-to-buffer buf)
359: (rmail-show-message n)
360: (pop-to-buffer rmail-summary-buffer)))
361:
362: (defvar rmail-summary-mode-map nil)
363:
364: (if rmail-summary-mode-map
365: nil
366: (setq rmail-summary-mode-map (make-keymap))
367: (suppress-keymap rmail-summary-mode-map)
368: (define-key rmail-summary-mode-map "j" 'rmail-summary-goto-msg)
369: (define-key rmail-summary-mode-map "n" 'rmail-summary-next-msg)
370: (define-key rmail-summary-mode-map "p" 'rmail-summary-previous-msg)
371: (define-key rmail-summary-mode-map "\C-n" 'rmail-summary-next-all)
372: (define-key rmail-summary-mode-map "\C-p" 'rmail-summary-previous-all)
373: (define-key rmail-summary-mode-map " " 'rmail-summary-scroll-msg-up)
374: (define-key rmail-summary-mode-map "q" 'rmail-summary-quit)
375: (define-key rmail-summary-mode-map "u" 'rmail-summary-undelete)
376: (define-key rmail-summary-mode-map "x" 'rmail-summary-exit)
377: (define-key rmail-summary-mode-map "\177" 'rmail-summary-scroll-msg-down)
378: (define-key rmail-summary-mode-map "d" 'rmail-summary-delete-forward))
379:
380: (defun rmail-summary-scroll-msg-up (&optional dist)
381: "Scroll message in top window forward"
382: (interactive "P")
383: (scroll-other-window (if (null dist)
384: nil
385: (prefix-numeric-value dist))))
386:
387: (defun rmail-summary-scroll-msg-down (&optional dist)
388: "Scroll message in top window backward"
389: (interactive "P")
390: (other-window 1)
391: (scroll-down (if (null dist)
392: nil
393: (prefix-numeric-value dist)))
394: (other-window 1))
395:
396: (defun rmail-summary-quit ()
397: "Quit out of rmail and rmail summary"
398: (interactive)
399: (rmail-summary-exit)
400: (rmail-quit))
401:
402: (defun rmail-summary-exit ()
403: "Exit rmail summary, remaining within rmail."
404: (interactive)
405: ;; Switch to the rmail buffer after burying this one.
406: ;; Tricky since variable rmail-buffer is local.
407: (pop-to-buffer (prog1 rmail-buffer (bury-buffer (current-buffer))))
408: (delete-other-windows))
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.