Mercurial > hg > xemacs-beta
comparison lisp/vm/vm-digest.el @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | ac2d302a0011 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:376386a54a3c |
---|---|
1 ;;; Message encapsulation | |
2 ;;; Copyright (C) 1989, 1990, 1993, 1994 Kyle E. Jones | |
3 ;;; | |
4 ;;; This program is free software; you can redistribute it and/or modify | |
5 ;;; it under the terms of the GNU General Public License as published by | |
6 ;;; the Free Software Foundation; either version 1, or (at your option) | |
7 ;;; any later version. | |
8 ;;; | |
9 ;;; This program is distributed in the hope that it will be useful, | |
10 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 ;;; GNU General Public License for more details. | |
13 ;;; | |
14 ;;; You should have received a copy of the GNU General Public License | |
15 ;;; along with this program; if not, write to the Free Software | |
16 ;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
17 | |
18 (provide 'vm-digest) | |
19 | |
20 (defun vm-no-frills-encapsulate-message (m keep-list discard-regexp) | |
21 "Encapsulate a message M for forwarding, simply. | |
22 No message encapsulation standard is used. The message is | |
23 inserted at point in the current buffer, surrounded by two dashed | |
24 start/end separator lines. Point is not moved. | |
25 | |
26 M should be a message struct for a real message, not a virtual message. | |
27 This is the message that will be encapsulated. | |
28 KEEP-LIST should be a list of regexps matching headers to keep. | |
29 DISCARD-REGEXP should be a regexp that matches headers to be discarded. | |
30 KEEP-LIST and DISCARD-REGEXP are used to order and trim the headers | |
31 to be forwarded. See the docs for vm-reorder-message-headers | |
32 to find out how KEEP-LIST and DISCARD-REGEXP are used." | |
33 (let ((target-buffer (current-buffer)) | |
34 source-buffer) | |
35 (save-restriction | |
36 ;; narrow to a zero length region to avoid interacting | |
37 ;; with anything that might have already been inserted | |
38 ;; into the buffer. | |
39 (narrow-to-region (point) (point)) | |
40 (insert "------- start of forwarded message -------\n") | |
41 (setq source-buffer (vm-buffer-of m)) | |
42 (save-excursion | |
43 (set-buffer source-buffer) | |
44 (save-restriction | |
45 (widen) | |
46 (save-excursion | |
47 (set-buffer target-buffer) | |
48 (let ((beg (point))) | |
49 (insert-buffer-substring source-buffer (vm-headers-of m) | |
50 (vm-text-end-of m)) | |
51 (goto-char beg) | |
52 (vm-reorder-message-headers nil nil "\\(X-VM-\\|Status:\\)") | |
53 (vm-reorder-message-headers nil keep-list discard-regexp))))) | |
54 (goto-char (point-max)) | |
55 (insert "------- end of forwarded message -------\n")))) | |
56 | |
57 (defun vm-rfc934-char-stuff-region (start end) | |
58 "Quote RFC 934 message separators between START and END. | |
59 START and END are buffer positions in the current buffer. | |
60 Lines beginning with `-' in the region have `- ' prepended to them." | |
61 (setq end (vm-marker end)) | |
62 (save-excursion | |
63 (goto-char start) | |
64 (while (and (< (point) end) (re-search-forward "^-" end t)) | |
65 (replace-match "- -" t t))) | |
66 (set-marker end nil)) | |
67 | |
68 (defun vm-rfc934-char-unstuff-region (start end) | |
69 "Unquote lines in between START and END as per RFC 934. | |
70 START and END are buffer positions in the current buffer. | |
71 Lines beginning with `- ' in the region have that string stripped | |
72 from them." | |
73 (setq end (vm-marker end)) | |
74 (save-excursion | |
75 (goto-char start) | |
76 (while (and (< (point) end) (re-search-forward "^- " end t)) | |
77 (replace-match "" t t) | |
78 (forward-char))) | |
79 (set-marker end nil)) | |
80 | |
81 (defun vm-rfc934-encapsulate-messages (message-list keep-list discard-regexp) | |
82 "Encapsulate the messages in MESSAGE-LIST as per RFC 934. | |
83 The resulting digest is inserted at point in the current buffer. | |
84 Point is not moved. | |
85 | |
86 MESSAGE-LIST should be a list of message structs (real or virtual). | |
87 These are the messages that will be encapsulated. | |
88 KEEP-LIST should be a list of regexps matching headers to keep. | |
89 DISCARD-REGEXP should be a regexp that matches headers to be discarded. | |
90 KEEP-LIST and DISCARD-REGEXP are used to order and trim the headers | |
91 to be forwarded. See the docs for vm-reorder-message-headers | |
92 to find out how KEEP-LIST and DISCARD-REGEXP are used." | |
93 (if message-list | |
94 (let ((target-buffer (current-buffer)) | |
95 (mlist message-list) | |
96 source-buffer m start n) | |
97 (save-restriction | |
98 ;; narrow to a zero length region to avoid interacting | |
99 ;; with anything that might have already been inserted | |
100 ;; into the buffer. | |
101 (narrow-to-region (point) (point)) | |
102 (setq start (point)) | |
103 (while mlist | |
104 (insert "---------------\n") | |
105 (setq m (vm-real-message-of (car mlist)) | |
106 source-buffer (vm-buffer-of m)) | |
107 (save-excursion | |
108 (set-buffer source-buffer) | |
109 (save-restriction | |
110 (widen) | |
111 (save-excursion | |
112 (set-buffer target-buffer) | |
113 (let ((beg (point))) | |
114 (insert-buffer-substring source-buffer (vm-headers-of m) | |
115 (vm-text-end-of m)) | |
116 (goto-char beg) | |
117 (vm-reorder-message-headers nil nil | |
118 "\\(X-VM-\\|Status:\\)") | |
119 (vm-reorder-message-headers nil keep-list discard-regexp) | |
120 (vm-rfc934-char-stuff-region beg (point-max)))))) | |
121 (goto-char (point-max)) | |
122 (insert "---------------") | |
123 (setq mlist (cdr mlist))) | |
124 (delete-region (point) (progn (beginning-of-line) (point))) | |
125 (insert "------- end -------\n") | |
126 (goto-char start) | |
127 (delete-region (point) (progn (forward-line 1) (point))) | |
128 (setq n (length message-list)) | |
129 (insert (format "------- start of %s%s(RFC 934 encapsulation) -------\n" | |
130 (if (cdr message-list) | |
131 "digest " | |
132 "forwarded message ") | |
133 (if (cdr message-list) | |
134 (format "(%d messages) " n) | |
135 ""))) | |
136 (goto-char start))))) | |
137 | |
138 (defun vm-rfc1153-char-stuff-region (start end) | |
139 "Quote RFC 1153 message separators between START and END. | |
140 START and END are buffer positions in the current buffer. | |
141 Lines consisting only of 30 hyphens have the first hyphen | |
142 converted to a space." | |
143 (setq end (vm-marker end)) | |
144 (save-excursion | |
145 (goto-char start) | |
146 (while (and (< (point) end) | |
147 (re-search-forward "^------------------------------$" end t)) | |
148 (replace-match " -----------------------------" t t))) | |
149 (set-marker end nil)) | |
150 | |
151 (defun vm-rfc1153-char-unstuff-region (start end) | |
152 "Unquote lines in between START and END as per RFC 1153. | |
153 START and END are buffer positions in the current buffer. | |
154 Lines consisting only of a space following by 29 hyphens have the space | |
155 converted to a hyphen." | |
156 (setq end (vm-marker end)) | |
157 (save-excursion | |
158 (goto-char start) | |
159 (while (and (< (point) end) | |
160 (re-search-forward "^ -----------------------------$" end t)) | |
161 (replace-match "------------------------------" t t))) | |
162 (set-marker end nil)) | |
163 | |
164 (defun vm-rfc1153-encapsulate-messages (message-list keep-list discard-regexp) | |
165 "Encapsulate the messages in MESSAGE-LIST as per RFC 1153. | |
166 The resulting digest is inserted at point in the current buffer. | |
167 Point is not moved. | |
168 | |
169 MESSAGE-LIST should be a list of message structs (real or virtual). | |
170 These are the messages that will be encapsulated. | |
171 KEEP-LIST should be a list of regexps matching headers to keep. | |
172 DISCARD-REGEXP should be a regexp that matches headers to be discarded. | |
173 KEEP-LIST and DISCARD-REGEXP are used to order and trim the headers | |
174 to be forwarded. See the docs for vm-reorder-message-headers | |
175 to find out how KEEP-LIST and DISCARD-REGEXP are used." | |
176 (if message-list | |
177 (let ((target-buffer (current-buffer)) | |
178 (mlist message-list) | |
179 source-buffer m start) | |
180 (save-restriction | |
181 ;; narrow to a zero length region to avoid interacting | |
182 ;; with anything that might have already been inserted | |
183 ;; into the buffer. | |
184 (narrow-to-region (point) (point)) | |
185 (setq start (point)) | |
186 (while mlist | |
187 (insert "---------------\n\n") | |
188 (setq m (vm-real-message-of (car mlist)) | |
189 source-buffer (vm-buffer-of m)) | |
190 (save-excursion | |
191 (set-buffer source-buffer) | |
192 (save-restriction | |
193 (widen) | |
194 (save-excursion | |
195 (set-buffer target-buffer) | |
196 (let ((beg (point))) | |
197 (insert-buffer-substring source-buffer (vm-headers-of m) | |
198 (vm-text-end-of m)) | |
199 (goto-char beg) | |
200 (vm-reorder-message-headers nil nil | |
201 "\\(X-VM-\\|Status:\\)") | |
202 (vm-reorder-message-headers nil keep-list discard-regexp) | |
203 (vm-rfc1153-char-stuff-region beg (point-max)))))) | |
204 (goto-char (point-max)) | |
205 (insert "\n---------------") | |
206 (setq mlist (cdr mlist))) | |
207 (insert "---------------\n\nEnd of this Digest\n******************\n") | |
208 (goto-char start) | |
209 (delete-region (point) (progn (forward-line 1) (point))) | |
210 (insert (format "This is an RFC 1153 digest.\n(%d message%s)\n----------------------------------------------------------------------\n" (length message-list) (if (cdr message-list) "s" ""))) | |
211 (goto-char start))))) | |
212 | |
213 (defun vm-rfc1153-or-rfc934-burst-message (m rfc1153) | |
214 "Burst messages from the digest message M. | |
215 M should be a message struct for a real message. | |
216 If RFC1153 is non-nil, assume the digest is of the form specified by | |
217 RFC 1153. Otherwise assume RFC 934 digests." | |
218 (let ((work-buffer nil) | |
219 (match t) | |
220 (prev-sep nil) | |
221 (ident-header nil) | |
222 after-prev-sep prologue-separator-regexp separator-regexp | |
223 (folder-type vm-folder-type)) | |
224 (if vm-digest-identifier-header-format | |
225 (setq ident-header (vm-sprintf 'vm-digest-identifier-header-format m))) | |
226 (if rfc1153 | |
227 (setq prologue-separator-regexp "^----------------------------------------------------------------------\n" | |
228 separator-regexp "^------------------------------\n") | |
229 (setq prologue-separator-regexp "^-[^ ].*\n" | |
230 separator-regexp "^-[^ ].*\n")) | |
231 (save-excursion | |
232 (vm-save-restriction | |
233 (widen) | |
234 (unwind-protect | |
235 (catch 'done | |
236 (setq work-buffer (generate-new-buffer "*vm-work*")) | |
237 (set-buffer work-buffer) | |
238 (insert-buffer-substring (vm-buffer-of m) | |
239 (vm-text-of m) | |
240 (vm-text-end-of m)) | |
241 (goto-char (point-min)) | |
242 (if (not (re-search-forward prologue-separator-regexp nil t)) | |
243 (throw 'done nil)) | |
244 ;; think of this as a do-while loop. | |
245 (while match | |
246 (cond ((null prev-sep) | |
247 ;; from (point-min) to end of match | |
248 ;; is the digest prologue, devour it and | |
249 ;; carry on. | |
250 (delete-region (point-min) (match-end 0))) | |
251 (t | |
252 ;; munge previous messages message separators | |
253 (let ((md (match-data))) | |
254 (unwind-protect | |
255 (vm-munge-message-separators | |
256 folder-type | |
257 after-prev-sep | |
258 (match-beginning 0)) | |
259 (store-match-data md))) | |
260 ;; eat preceding newlines | |
261 (while (= (preceding-char) ?\n) | |
262 (delete-char -1)) | |
263 ;; put one back | |
264 (insert ?\n))) | |
265 ;; insert a trailing message separator | |
266 ;; delete the digest separator | |
267 ;; insert the leading separator | |
268 (if prev-sep | |
269 (progn | |
270 (delete-region (match-beginning 0) (match-end 0)) | |
271 (insert (vm-trailing-message-separator folder-type)))) | |
272 (setq prev-sep (point)) | |
273 (insert (vm-leading-message-separator folder-type)) | |
274 (setq after-prev-sep (point)) | |
275 ;; eat trailing newlines | |
276 (while (= (following-char) ?\n) | |
277 (delete-char 1)) | |
278 (insert ident-header) | |
279 ;; try to match message separator and repeat. | |
280 (setq match (re-search-forward separator-regexp nil t))) | |
281 ;; from the last separator to eof is the digest epilogue. | |
282 ;; discard it. | |
283 (delete-region (or prev-sep (point-min)) (point-max)) | |
284 ;; Undo the quoting of the embedded message | |
285 ;; separators. This must be done before header | |
286 ;; conversions, else the Content-Length offsets might be | |
287 ;; rendered invalid by buffer size changes. | |
288 (if rfc1153 | |
289 (vm-rfc1153-char-unstuff-region (point-min) (point-max)) | |
290 (vm-rfc934-char-unstuff-region (point-min) (point-max))) | |
291 ;; do header conversions. | |
292 (let ((vm-folder-type folder-type)) | |
293 (goto-char (point-min)) | |
294 (while (vm-find-leading-message-separator) | |
295 (vm-skip-past-leading-message-separator) | |
296 (vm-convert-folder-type-headers folder-type folder-type) | |
297 (vm-find-trailing-message-separator) | |
298 (vm-skip-past-trailing-message-separator))) | |
299 ;; now insert the messages into the folder buffer | |
300 (cond ((not (zerop (buffer-size))) | |
301 (set-buffer (vm-buffer-of m)) | |
302 (let ((old-buffer-modified-p (buffer-modified-p)) | |
303 (buffer-read-only nil) | |
304 (inhibit-quit t)) | |
305 (goto-char (point-max)) | |
306 (insert-buffer-substring work-buffer) | |
307 (set-buffer-modified-p old-buffer-modified-p) | |
308 ;; return non-nil so caller knows we found some messages | |
309 t )) | |
310 ;; return nil so the caller knows we didn't find anything | |
311 (t nil))) | |
312 (and work-buffer (kill-buffer work-buffer))))))) | |
313 | |
314 (defun vm-rfc934-burst-message (m) | |
315 "Burst messages from the RFC 934 digest message M. | |
316 M should be a message struct for a real message." | |
317 (vm-rfc1153-or-rfc934-burst-message m nil)) | |
318 | |
319 (defun vm-rfc1153-burst-message (m) | |
320 "Burst messages from the RFC 1153 digest message M. | |
321 M should be a message struct for a real message." | |
322 (vm-rfc1153-or-rfc934-burst-message m t)) | |
323 | |
324 (defun vm-burst-digest (&optional digest-type) | |
325 "Burst the current message (a digest) into its individual messages. | |
326 The digest's messages are assimilated into the folder as new mail | |
327 would be. | |
328 | |
329 Optional argument DIGEST-TYPE is a string that tells VM what kind | |
330 of digest the current message is. If it is not given the value | |
331 defaults to the value of vm-digest-burst-type. When called | |
332 interactively DIGEST-TYPE will be read from the minibuffer. | |
333 | |
334 If invoked on marked messages (via vm-next-command-uses-marks), | |
335 all marked messages will be burst." | |
336 (interactive | |
337 (list | |
338 (let ((type nil) | |
339 (this-command this-command) | |
340 (last-command last-command)) | |
341 (setq type (completing-read (format "Digest type: (default %s) " | |
342 vm-digest-burst-type) | |
343 (append vm-digest-type-alist | |
344 (list '("guess"))) | |
345 'identity nil)) | |
346 (if (string= type "") | |
347 vm-digest-burst-type | |
348 type )))) | |
349 (or digest-type (setq digest-type vm-digest-burst-type)) | |
350 (vm-follow-summary-cursor) | |
351 (vm-select-folder-buffer) | |
352 (vm-check-for-killed-summary) | |
353 (vm-error-if-folder-empty) | |
354 (let ((start-buffer (current-buffer)) m totals-blurb | |
355 (mlist (vm-select-marked-or-prefixed-messages 1))) | |
356 (while mlist | |
357 (if (vm-virtual-message-p (car mlist)) | |
358 (progn | |
359 (setq m (vm-real-message-of (car mlist))) | |
360 (set-buffer (vm-buffer-of m))) | |
361 (setq m (car mlist))) | |
362 (vm-error-if-folder-read-only) | |
363 (if (equal digest-type "guess") | |
364 (progn | |
365 (setq digest-type (vm-guess-digest-type m)) | |
366 (if (null digest-type) | |
367 (error "Couldn't guess digest type.")))) | |
368 (vm-unsaved-message "Bursting %s digest..." digest-type) | |
369 (cond | |
370 ((cond ((equal digest-type "rfc934") | |
371 (vm-rfc934-burst-message m)) | |
372 ((equal digest-type "rfc1153") | |
373 (vm-rfc1153-burst-message m)) | |
374 (t (error "Unknown digest type: %s" digest-type))) | |
375 (message "Bursting %s digest... done" digest-type) | |
376 (vm-clear-modification-flag-undos) | |
377 (vm-set-buffer-modified-p t) | |
378 (vm-increment vm-modification-counter) | |
379 (and vm-delete-after-bursting | |
380 ;; if start folder was virtual, we're now in the wrong | |
381 ;; buffer. switch back. | |
382 (save-excursion | |
383 (set-buffer start-buffer) | |
384 (vm-delete-message 1))) | |
385 (vm-assimilate-new-messages t) | |
386 ;; do this now so if we error later in another iteration | |
387 ;; of the loop the summary and mode line will be correct. | |
388 (vm-update-summary-and-mode-line))) | |
389 (setq mlist (cdr mlist))) | |
390 ;; collect this data NOW, before the non-previewers read a | |
391 ;; message, alter the new message count and confuse | |
392 ;; themselves. | |
393 (setq totals-blurb (vm-emit-totals-blurb)) | |
394 (vm-display nil nil '(vm-burst-digest | |
395 vm-burst-rfc934-digest | |
396 vm-burst-rfc1153-digest) | |
397 (list this-command)) | |
398 (if (vm-thoughtfully-select-message) | |
399 (vm-preview-current-message) | |
400 (vm-update-summary-and-mode-line)) | |
401 (message totals-blurb))) | |
402 | |
403 (defun vm-burst-rfc934-digest () | |
404 "Burst an RFC 934 style digest" | |
405 (interactive) | |
406 (vm-burst-digest "rfc934")) | |
407 | |
408 (defun vm-burst-rfc1153-digest () | |
409 "Burst an RFC 1153 style digest" | |
410 (interactive) | |
411 (vm-burst-digest "rfc1153")) | |
412 | |
413 (defun vm-guess-digest-type (m) | |
414 "Guess the digest type of the message M. | |
415 M should be the message struct of a real message. | |
416 Returns either \"rfc934\" or \"rfc1153\"." | |
417 (save-excursion | |
418 (set-buffer (vm-buffer-of m)) | |
419 (save-excursion | |
420 (save-restriction | |
421 (widen) | |
422 (goto-char (vm-text-of m)) | |
423 (if (search-forward "\n----------------------------------------------------------------------\n" nil t) | |
424 "rfc1153" | |
425 "rfc934"))))) |