|
|
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: ;; Global to all RMAIL buffers. It exists primarily for the sake of
23: ;; completion. It is better to use strings with the label functions
24: ;; and let them worry about making the label.
25:
26: (defvar rmail-label-obarray (make-vector 47 0))
27:
28: ;; Named list of symbols representing valid message attributes in RMAIL.
29:
30: (defconst rmail-attributes
31: (cons 'rmail-keywords
32: (mapcar '(lambda (s) (intern s rmail-label-obarray))
33: '("deleted" "answered" "filed" "forwarded" "unseen"))))
34:
35: (defconst rmail-deleted-label (intern "deleted" rmail-label-obarray))
36:
37: ;; Named list of symbols representing valid message keywords in RMAIL.
38:
39: (defvar rmail-keywords nil)
40:
41: (defun rmail-add-label (string)
42: "Add LABEL to labels associated with current RMAIL message.
43: Completion is performed over known labels when reading."
44: (interactive (list (rmail-read-label "Add label")))
45: (rmail-set-label string t))
46:
47: (defun rmail-kill-label (string)
48: "Remove LABEL from labels associated with current RMAIL message.
49: Completion is performed over known labels when reading."
50: (interactive (list (rmail-read-label "Remove label")))
51: (rmail-set-label string nil))
52:
53: (defun rmail-read-label (prompt)
54: (if (not rmail-keywords) (rmail-parse-file-keywords))
55: (let ((result
56: (completing-read (concat prompt
57: (if rmail-last-label
58: (concat " (default "
59: (symbol-name rmail-last-label)
60: "): ")
61: ": "))
62: rmail-label-obarray
63: nil
64: nil)))
65: (if (string= result "")
66: rmail-last-label
67: (setq rmail-last-label (rmail-make-label result t)))))
68:
69: (defun rmail-set-label (l state &optional n)
70: (rmail-maybe-set-message-counters)
71: (if (not n) (setq n rmail-current-message))
72: (aset rmail-summary-vector (1- n) nil)
73: (let* ((attribute (rmail-attribute-p l))
74: (keyword (and (not attribute)
75: (or (rmail-keyword-p l)
76: (rmail-install-keyword l))))
77: (label (or attribute keyword)))
78: (if label
79: (let ((omax (- (buffer-size) (point-max)))
80: (omin (- (buffer-size) (point-min)))
81: (buffer-read-only nil)
82: (case-fold-search t))
83: (unwind-protect
84: (save-excursion
85: (widen)
86: (goto-char (rmail-msgbeg n))
87: (forward-line 1)
88: (if (not (looking-at "[01],"))
89: nil
90: (let ((start (1+ (point)))
91: (bound))
92: (narrow-to-region (point) (progn (end-of-line) (point)))
93: (setq bound (point-max))
94: (search-backward ",," nil t)
95: (if attribute
96: (setq bound (1+ (point)))
97: (setq start (1+ (point))))
98: (goto-char start)
99: (rmail-nuke-whitespace)
100: (if (re-search-forward
101: (concat "," (rmail-quote-label-name label) ",")
102: bound
103: 'move)
104: (if (not state) (replace-match ","))
105: (if state (insert (symbol-name label) ",")))
106: (if (eq label rmail-deleted-label)
107: (rmail-set-message-deleted-p n state)))))
108: (narrow-to-region (- (buffer-size) omin) (- (buffer-size) omax))
109: (if (= n rmail-current-message) (rmail-display-labels)))))))
110:
111: ;; Commented functions aren't used by RMAIL but might be nice for user
112: ;; packages that do stuff with RMAIL. Note that rmail-message-labels-p
113: ;; is in rmailsum now.
114:
115: ;(defun rmail-message-attribute-p (attribute &optional n)
116: ; "Returns t if ATTRIBUTE on NTH or current message."
117: ; (rmail-message-labels-p (rmail-make-label attribute t) n))
118:
119: ;(defun rmail-message-keyword-p (keyword &optional n)
120: ; "Returns t if KEYWORD on NTH or current message."
121: ; (rmail-message-labels-p (rmail-make-label keyword t) n t))
122:
123: ;(defun rmail-message-label-p (label &optional n)
124: ; "Returns symbol if LABEL (attribute or keyword) on NTH or current message."
125: ; (rmail-message-labels-p (rmail-make-label label t) n 'all))
126:
127: ;; Not used by RMAIL but might be nice for user package.
128:
129: ;(defun rmail-parse-message-labels (&optional n)
130: ; "Returns labels associated with NTH or current RMAIL message.
131: ;Results is a list of two lists. The first is the message attributes
132: ;and the second is the message keywords. Labels are represented as symbols."
133: ; (let ((omin (- (buffer-size) (point-min)))
134: ; (omax (- (buffer-size) (point-max)))
135: ; (result))
136: ; (unwind-protect
137: ; (save-excursion
138: ; (let ((beg (rmail-msgbeg (or n rmail-current-message))))
139: ; (widen)
140: ; (goto-char beg)
141: ; (forward-line 1)
142: ; (if (looking-at "[01],")
143: ; (save-restriction
144: ; (narrow-to-region (point) (save-excursion (end-of-line) (point)))
145: ; (rmail-nuke-whitespace)
146: ; (goto-char (1+ (point-min)))
147: ; (list (mail-parse-comma-list) (mail-parse-comma-list))))))
148: ; (narrow-to-region (- (buffer-size) omin)
149: ; (- (buffer-size) omax))
150: ; nil)))
151:
152: (defun rmail-attribute-p (s)
153: (let ((symbol (rmail-make-label s)))
154: (if (memq symbol (cdr rmail-attributes)) symbol)))
155:
156: (defun rmail-keyword-p (s)
157: (let ((symbol (rmail-make-label s)))
158: (if (memq symbol (cdr (rmail-keywords))) symbol)))
159:
160: (defun rmail-make-label (s &optional forcep)
161: (cond ((symbolp s) s)
162: (forcep (intern (downcase s) rmail-label-obarray))
163: (t (intern-soft (downcase s) rmail-label-obarray))))
164:
165: (defun rmail-force-make-label (s)
166: (intern (downcase s) rmail-label-obarray))
167:
168: (defun rmail-quote-label-name (label)
169: (regexp-quote (symbol-name (rmail-make-label label t))))
170:
171: ;; Delete all whitespace in the visible part of the buffer.
172: ;; The use of this function is unclean, and it should be flushed.
173: (defun rmail-nuke-whitespace ()
174: (save-excursion
175: (let ((buffer-read-only nil))
176: (goto-char (point-min))
177: (while (re-search-forward "[ \t]+" nil t)
178: (replace-match "")))))
179:
180:
181: ;; Motion on messages with keywords.
182:
183: (defun rmail-previous-labeled-message (n label)
184: "Show previous message with LABEL. Defaults to last labels used.
185: With prefix argument N moves backward N messages with these labels."
186: (interactive "p\nsMove to previous msg with labels: ")
187: (rmail-next-labeled-message (- n) label))
188:
189: (defun rmail-next-labeled-message (n labels)
190: "Show next message with LABEL. Defaults to last labels used.
191: With prefix argument N moves forward N messages with these labels."
192: (interactive "p\nsMove to next msg with labels: ")
193: (if (string= labels "")
194: (setq labels rmail-last-multi-labels))
195: (or labels
196: (error "No labels to find have been specified previously"))
197: (setq rmail-last-multi-labels labels)
198: (rmail-maybe-set-message-counters)
199: (let ((lastwin rmail-current-message)
200: (current rmail-current-message)
201: (regexp (concat ",\\("
202: (mail-comma-list-regexp labels)
203: "\\),")))
204: (save-restriction
205: (widen)
206: (while (and (> n 0) (< current rmail-total-messages))
207: (setq current (1+ current))
208: (if (rmail-message-labels-p current regexp)
209: (setq lastwin current n (1- n))))
210: (while (and (< n 0) (> current 1))
211: (setq current (1- current))
212: (if (rmail-message-labels-p current regexp)
213: (setq lastwin current n (1+ n)))))
214: (rmail-show-message lastwin)
215: (if (< n 0)
216: (message "No previous message with labels %s" labels))
217: (if (> n 0)
218: (message "No following message with labels %s" labels))))
219:
220: ;;; Manipulate the file's Labels option.
221:
222: ;; Return a list of symbols for all
223: ;; the keywords (labels) recorded in this file's Labels option.
224: (defun rmail-keywords ()
225: (or rmail-keywords (rmail-parse-file-keywords)))
226:
227: ;; Set rmail-keywords to a list of symbols for all
228: ;; the keywords (labels) recorded in this file's Labels option.
229: (defun rmail-parse-file-keywords ()
230: (save-restriction
231: (save-excursion
232: (widen)
233: (goto-char 1)
234: (setq rmail-keywords
235: (if (search-forward "\nLabels:" (rmail-msgbeg 1) t)
236: (progn
237: (narrow-to-region (point) (progn (end-of-line) (point)))
238: (goto-char (point-min))
239: (cons 'rmail-keywords
240: (mapcar 'rmail-force-make-label
241: (mail-parse-comma-list)))))))))
242:
243: ;; Add WORD to the list in the file's Labels option.
244: ;; Any keyword used for the first time needs this done.
245: (defun rmail-install-keyword (word)
246: (let ((keyword (rmail-make-label word t))
247: (keywords (rmail-keywords)))
248: (if (not (or (rmail-attribute-p keyword)
249: (rmail-keyword-p keyword)))
250: (let ((omin (- (buffer-size) (point-min)))
251: (omax (- (buffer-size) (point-max))))
252: (unwind-protect
253: (save-excursion
254: (widen)
255: (goto-char 1)
256: (let ((case-fold-search t)
257: (buffer-read-only nil))
258: (or (search-forward "\nLabels:" nil t)
259: (progn
260: (end-of-line)
261: (insert "\nLabels:")))
262: (delete-region (point) (progn (end-of-line) (point)))
263: (setcdr keywords (cons keyword (cdr keywords)))
264: (while (setq keywords (cdr keywords))
265: (insert (symbol-name (car keywords)) ","))
266: (delete-char -1)))
267: (narrow-to-region (- (buffer-size) omin)
268: (- (buffer-size) omax)))))
269: keyword))
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.