(term-mode, term-check-proc, term-input-sender, term-simple-send,
[bpt/emacs.git] / lisp / mail / undigest.el
CommitLineData
d501f516
ER
1;;; undigest.el --- digest-cracking support for the RMAIL mail reader
2
3af9d2cf
FP
3;; Copyright (C) 1985, 1986, 1994, 1996, 2002
4;; Free Software Foundation, Inc.
58142744 5
e5167999 6;; Maintainer: FSF
d7b4d18f 7;; Keywords: mail
e5167999 8
0d20f9a0
JB
9;; This file is part of GNU Emacs.
10
11;; GNU Emacs is free software; you can redistribute it and/or modify
12;; it under the terms of the GNU General Public License as published by
e5167999 13;; the Free Software Foundation; either version 2, or (at your option)
0d20f9a0
JB
14;; any later version.
15
16;; GNU Emacs is distributed in the hope that it will be useful,
17;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19;; GNU General Public License for more details.
20
21;; You should have received a copy of the GNU General Public License
b578f267
EN
22;; along with GNU Emacs; see the file COPYING. If not, write to the
23;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24;; Boston, MA 02111-1307, USA.
0d20f9a0 25
e5167999
ER
26;;; Commentary:
27
3af9d2cf 28;; See Internet RFC 934 and RFC 1153
96f428d1 29;; Also limited support for MIME digest encapsulation
e5167999
ER
30
31;;; Code:
0d20f9a0 32
4fe9b563
KH
33(require 'rmail)
34
47687ab8
FP
35(defconst rmail-mail-separator
36 "\^_\^L\n0, unseen,,\n*** EOOH ***\n"
37 "String for separating messages in an rmail file.")
38
a34804da
FP
39(defcustom rmail-forward-separator-regex
40 "^----.*\\([Ff]orwarded\\|[Oo]riginal\\).*[Mm]essage"
41 "*Regexp to match the string that introduces forwarded messages.
42This is not a header, but a string contained in the body of the message.
43You may need to customise it for local needs."
44 :type 'regexp
45 :group 'rmail-headers)
46
47687ab8 47\f
3af9d2cf
FP
48(defconst rmail-digest-methods
49 '(rmail-digest-parse-mime
50 rmail-digest-parse-rfc1153strict
51 rmail-digest-parse-rfc1153sloppy
52 rmail-digest-parse-rfc934)
47687ab8 53 "List of digest parsing functions, first tried first.
3af9d2cf 54
47687ab8
FP
55These functions operate on the current narrowing, and take no argument.
56A function returns nil if it cannot parse the digest. If it can, it
3af9d2cf
FP
57returns a list of cons pairs containing the start and end positions of
58each undigestified message as markers.")
59
3af9d2cf
FP
60(defun rmail-digest-parse-mime ()
61 (goto-char (point-min))
62 (when (let ((head-end (progn (search-forward "\n\n" nil t) (point))))
63 (goto-char (point-min))
64 (and head-end
65 (re-search-forward
66 (concat
67 "^Content-type: multipart/digest;"
68 "\\s-* boundary=\"?\\([^\";\n]+\\)[\";\n]") head-end t)
69 (search-forward (match-string 1) nil t)))
70 ;; Ok, prolog separator found
71 (let ((start (make-marker))
72 (end (make-marker))
73 (separator (concat "\n--" (match-string 0) "\n\n"))
74 result)
75 (while (search-forward separator nil t)
76 (move-marker start (match-beginning 0))
77 (move-marker end (match-end 0))
78 (add-to-list 'result (cons (copy-marker start) (copy-marker end t))))
79 ;; Return the list of marker pairs
80 (nreverse result))))
81
82(defun rmail-digest-parse-rfc1153strict ()
83 "Parse following strictly the method defined in RFC 1153.
84See rmail-digest-methods."
85 (rmail-digest-rfc1153
86 "^-\\{70\\}\n\n"
87 "^\n-\\{30\\}\n\n"
88 "^\n-\\{30\\}\n\nEnd of .* Digest.*\n\\*\\{15,\\}\n+\'"))
89
90(defun rmail-digest-parse-rfc1153sloppy ()
91 "Parse using the method defined in RFC 1153, allowing for some sloppiness.
92See rmail-digest-methods."
93 (rmail-digest-rfc1153
94 "^-\\{55,\\}\n\n"
95 "^\n-\\{27,\\}\n\n"
96 "^\n-\\{27,\\}\n\nEnd of"))
97
98(defun rmail-digest-rfc1153 (prolog-sep message-sep trailer-sep)
99 (goto-char (point-min))
100 (when (re-search-forward prolog-sep nil t)
101 ;; Ok, prolog separator found
102 (let ((start (make-marker))
103 (end (make-marker))
104 separator result)
105 (move-marker start (match-beginning 0))
106 (move-marker end (match-end 0))
107 (setq result (cons (copy-marker start) (copy-marker end t)))
108 (when (re-search-forward message-sep nil t)
109 ;; Ok, at least one message separator found
110 (setq separator (match-string 0))
111 (when (re-search-forward trailer-sep nil t)
112 ;; Wonderful, we found a trailer, too. Now, go on splitting
113 ;; the digest into separate rmail messages
114 (goto-char (cdar result))
115 (while (search-forward separator nil t)
116 (move-marker start (match-beginning 0))
117 (move-marker end (match-end 0))
118 (add-to-list 'result
119 (cons (copy-marker start) (copy-marker end t))))
120 ;; Undo masking of separators inside digestified messages
121 (goto-char (point-min))
122 (while (search-forward
123 (replace-regexp-in-string "\n-" "\n " separator) nil t)
124 (replace-match separator))
125 ;; Return the list of marker pairs
126 (nreverse result))))))
127
128(defun rmail-digest-parse-rfc934 ()
129 (goto-char (point-min))
130 (when (re-search-forward "^\n?-[^ ].*\n\n?" nil t)
131 ;; Message separator found
132 (let ((start (make-marker))
133 (end (make-marker))
134 (separator (match-string 0))
135 result)
136 (goto-char (point-min))
137 (while (search-forward separator nil t)
138 (move-marker start (match-beginning 0))
139 (move-marker end (match-end 0))
140 (add-to-list 'result (cons (copy-marker start) (copy-marker end t))))
141 ;; Undo masking of separators inside digestified messages
142 (goto-char (point-min))
143 (while (search-forward "\n- -" nil t)
144 (replace-match "\n-"))
145 ;; Return the list of marker pairs
146 (nreverse result))))
147
372a91d7 148;;;###autoload
0d20f9a0
JB
149(defun undigestify-rmail-message ()
150 "Break up a digest message into its constituent messages.
151Leaves original message, deleted, before the undigestified messages."
152 (interactive)
add0c454
RS
153 (with-current-buffer rmail-buffer
154 (widen)
add0c454
RS
155 (let ((error t)
156 (buffer-read-only nil))
3af9d2cf
FP
157 (goto-char (rmail-msgend rmail-current-message))
158 (let ((msg-copy (buffer-substring (rmail-msgbeg rmail-current-message)
159 (rmail-msgend rmail-current-message))))
160 (narrow-to-region (point) (point))
161 (insert msg-copy))
162 (narrow-to-region (point-min) (1- (point-max)))
add0c454
RS
163 (unwind-protect
164 (progn
165 (save-restriction
166 (goto-char (point-min))
167 (delete-region (point-min)
3af9d2cf 168 (progn (search-forward "\n*** EOOH ***\n" nil t)
add0c454 169 (point)))
47687ab8 170 (insert "\n" rmail-mail-separator)
add0c454
RS
171 (narrow-to-region (point)
172 (point-max))
3af9d2cf
FP
173 (let ((fill-prefix "")
174 (case-fold-search t)
175 digest-name type start end separator fun-list sep-list)
176 (setq digest-name (mail-strip-quoted-names
177 (save-restriction
178 (search-forward "\n\n" nil 'move)
179 (setq start (point))
180 (narrow-to-region (point-min) start)
181 (or (mail-fetch-field "Reply-To")
182 (mail-fetch-field "To")
183 (mail-fetch-field "Apparently-To")
184 (mail-fetch-field "From")))))
185 (unless digest-name
186 (error "Message is not a digest--bad header"))
187
188 (setq fun-list rmail-digest-methods)
189 (while (and fun-list
190 (null (setq sep-list (funcall (car fun-list)))))
191 (setq fun-list (cdr fun-list)))
192 (unless sep-list
193 (error "Message is not a digest--no messages found"))
194
195 ;;; Split the digest into separate rmail messages
196 (while sep-list
197 (let ((start (caar sep-list))
198 (end (cdar sep-list)))
199 (delete-region start end)
200 (goto-char start)
47687ab8 201 (insert rmail-mail-separator)
3af9d2cf
FP
202 (search-forward "\n\n" (caar (cdr sep-list)) 'move)
203 (save-restriction
204 (narrow-to-region end (point))
205 (unless (mail-fetch-field "To")
206 (goto-char start)
207 (insert "To: " digest-name "\n")))
208 (set-marker start nil)
209 (set-marker end nil))
210 (setq sep-list (cdr sep-list)))))
211
add0c454
RS
212 (setq error nil)
213 (message "Message successfully undigestified")
214 (let ((n rmail-current-message))
215 (rmail-forget-messages)
216 (rmail-show-message n)
217 (rmail-delete-forward)
218 (if (rmail-summary-exists)
219 (rmail-select-summary
220 (rmail-update-summary)))))
221 (cond (error
222 (narrow-to-region (point-min) (1+ (point-max)))
223 (delete-region (point-min) (point-max))
224 (rmail-show-message rmail-current-message)))))))
47687ab8 225\f
372a91d7 226;;;###autoload
9f606031
KH
227(defun unforward-rmail-message ()
228 "Extract a forwarded message from the containing message.
229This puts the forwarded message into a separate rmail message
230following the containing message."
231 (interactive)
add0c454 232 ;; If we are in a summary buffer, switch to the Rmail buffer.
47687ab8
FP
233 (unwind-protect
234 (with-current-buffer rmail-buffer
47687ab8 235 (goto-char (point-min))
89dac01f
FP
236 (narrow-to-region (point)
237 (save-excursion (search-forward "\n\n") (point)))
47687ab8 238 (let ((buffer-read-only nil)
89dac01f
FP
239 (old-fwd-from (mail-fetch-field "Forwarded-From" nil nil t))
240 (old-fwd-date (mail-fetch-field "Forwarded-Date" nil nil t))
241 (fwd-from (mail-fetch-field "From"))
242 (fwd-date (mail-fetch-field "Date"))
e49ba701 243 beg end prefix forward-msg)
89dac01f
FP
244 (narrow-to-region (rmail-msgbeg rmail-current-message)
245 (rmail-msgend rmail-current-message))
246 (goto-char (point-min))
a34804da 247 (cond ((re-search-forward rmail-forward-separator-regex nil t)
47687ab8 248 (forward-line 1)
59cb5b9b 249 (skip-chars-forward "\n")
47687ab8
FP
250 (setq beg (point))
251 (setq end (if (re-search-forward "^----.*[^- \t\n]" nil t)
252 (match-beginning 0) (point-max)))
253 (setq forward-msg
254 (replace-regexp-in-string
255 "^- -" "-" (buffer-substring beg end))))
85e94996 256 ((and (re-search-forward "^\\(> ?\\)[a-zA-Z-]+: .*\n" nil t)
47687ab8 257 (setq beg (match-beginning 0))
baad7c13 258 (setq prefix (match-string-no-properties 1))
85e94996 259 (goto-char beg)
47687ab8 260 (looking-at (concat "\\(" prefix ".+\n\\)*"
baad7c13 261 prefix "Date: ."))
85e94996
FP
262 (looking-at (concat "\\(" prefix ".+\n\\)*"
263 prefix "From: .+\n"
264 "\\(" prefix ".+\n\\)*"
47687ab8
FP
265 "\\(> ?\\)?\n" prefix)))
266 (re-search-forward "^[^>\n]" nil 'move)
267 (backward-char)
268 (skip-chars-backward " \t\n")
269 (forward-line 1)
270 (setq end (point))
271 (setq forward-msg
272 (replace-regexp-in-string
273 (if (string= prefix ">") "^>" "> ?")
274 "" (buffer-substring beg end))))
275 (t
276 (error "No forwarded message found")))
277 (widen)
278 (goto-char (rmail-msgend rmail-current-message))
279 (narrow-to-region (point) (point))
280 (insert rmail-mail-separator)
281 (narrow-to-region (point) (point))
89dac01f
FP
282 (while old-fwd-from
283 (insert "Forwarded-From: " (car old-fwd-from) "\n")
284 (insert "Forwarded-Date: " (car old-fwd-date) "\n")
285 (setq old-fwd-from (cdr old-fwd-from))
286 (setq old-fwd-date (cdr old-fwd-date)))
287 (insert "Forwarded-From: " fwd-from "\n")
288 (insert "Forwarded-Date: " fwd-date "\n")
47687ab8
FP
289 (insert forward-msg)
290 (save-restriction
291 (goto-char (point-min))
292 (re-search-forward "\n$" nil 'move)
293 (narrow-to-region (point-min) (point))
294 (goto-char (point-min))
295 (while (not (eobp))
296 (unless (looking-at "^[a-zA-Z-]+: ")
297 (insert "\t"))
298 (forward-line)))
299 (goto-char (point-min))))
e49ba701
KS
300 (let ((n rmail-current-message))
301 (rmail-forget-messages)
302 (rmail-show-message n))
47687ab8
FP
303 (if (rmail-summary-exists)
304 (rmail-select-summary
305 (rmail-update-summary)))))
306
9f606031 307
896546cd
RS
308(provide 'undigest)
309
ab5796a9 310;;; arch-tag: 3a28b9fb-c1f5-43ef-9278-285f3e4b874d
d501f516 311;;; undigest.el ends here