diff options
| author | Chong Yidong | 2008-12-13 14:19:56 +0000 |
|---|---|---|
| committer | Chong Yidong | 2008-12-13 14:19:56 +0000 |
| commit | 7635ef3856717a023d81ef246b2a4023c9eff7e6 (patch) | |
| tree | 94399475968d558ad0e9850a10d21557ed884c1a | |
| parent | f047d0db1973d73fdb8b9bbfd8e60540f7efc361 (diff) | |
| download | emacs-7635ef3856717a023d81ef246b2a4023c9eff7e6.tar.gz emacs-7635ef3856717a023d81ef246b2a4023c9eff7e6.zip | |
(pmail-output-to-babyl-file): Rewrite, assuming mbox
internal format.
(pmail-convert-to-babyl-format, pmail-nuke-pinhead-header): New
functions, moved from pmail.el.
| -rw-r--r-- | lisp/mail/pmailout.el | 283 |
1 files changed, 219 insertions, 64 deletions
diff --git a/lisp/mail/pmailout.el b/lisp/mail/pmailout.el index 11965f9dfac..f0d0ae9c361 100644 --- a/lisp/mail/pmailout.el +++ b/lisp/mail/pmailout.el | |||
| @@ -171,79 +171,234 @@ Note: it means the file has no messages in it.\n\^_")) | |||
| 171 | (if (pmail-message-deleted-p pmail-current-message) | 171 | (if (pmail-message-deleted-p pmail-current-message) |
| 172 | (progn (setq redelete t) | 172 | (progn (setq redelete t) |
| 173 | (pmail-set-attribute pmail-deleted-attr-index nil))) | 173 | (pmail-set-attribute pmail-deleted-attr-index nil))) |
| 174 | (save-restriction | 174 | (let ((coding-system-for-write |
| 175 | (widen) | 175 | (or pmail-file-coding-system |
| 176 | ;; Decide whether to append to a file or to an Emacs buffer. | 176 | 'emacs-mule-unix)) |
| 177 | (save-excursion | 177 | cur beg end) |
| 178 | (let ((buf (find-buffer-visiting file-name)) | 178 | (pmail-swap-buffers-maybe) |
| 179 | (cur (current-buffer)) | 179 | (setq cur (current-buffer)) |
| 180 | (beg (1+ (pmail-msgbeg pmail-current-message))) | 180 | (save-restriction |
| 181 | (end (1+ (pmail-msgend pmail-current-message))) | 181 | (save-excursion |
| 182 | (coding-system-for-write | 182 | (widen) |
| 183 | (or pmail-file-coding-system | 183 | (setq beg (pmail-msgbeg pmail-current-message) |
| 184 | 'emacs-mule-unix))) | 184 | end (pmail-msgend pmail-current-message)) |
| 185 | (if (not buf) | 185 | ;; Output to a file. |
| 186 | ;; Output to a file. | 186 | (set-buffer (get-buffer-create " pmail-out-temp")) |
| 187 | (if pmail-fields-not-to-output | 187 | (insert-buffer-substring cur beg end) |
| 188 | ;; Delete some fields while we output. | 188 | (if pmail-fields-not-to-output |
| 189 | (let ((obuf (current-buffer))) | 189 | (pmail-delete-unwanted-fields)) |
| 190 | (set-buffer (get-buffer-create " pmail-out-temp")) | 190 | ;; Convert to Babyl format. |
| 191 | (insert-buffer-substring obuf beg end) | 191 | (pmail-convert-to-babyl-format) |
| 192 | (pmail-delete-unwanted-fields) | 192 | (append-to-file (point-min) (point-max) file-name) |
| 193 | (append-to-file (point-min) (point-max) file-name) | 193 | (set-buffer cur) |
| 194 | (set-buffer obuf) | 194 | (kill-buffer (get-buffer " pmail-out-temp"))))) |
| 195 | (kill-buffer (get-buffer " pmail-out-temp"))) | ||
| 196 | (append-to-file beg end file-name)) | ||
| 197 | (if (eq buf (current-buffer)) | ||
| 198 | (error "Can't output message to same file it's already in")) | ||
| 199 | ;; File has been visited, in buffer BUF. | ||
| 200 | (set-buffer buf) | ||
| 201 | (let ((buffer-read-only nil) | ||
| 202 | (msg (and (boundp 'pmail-current-message) | ||
| 203 | pmail-current-message))) | ||
| 204 | ;; If MSG is non-nil, buffer is in PMAIL mode. | ||
| 205 | (if msg | ||
| 206 | (progn | ||
| 207 | ;; Turn on auto save mode, if it's off in this | ||
| 208 | ;; buffer but enabled by default. | ||
| 209 | (and (not buffer-auto-save-file-name) | ||
| 210 | auto-save-default | ||
| 211 | (auto-save-mode t)) | ||
| 212 | (pmail-maybe-set-message-counters) | ||
| 213 | (widen) | ||
| 214 | (narrow-to-region (point-max) (point-max)) | ||
| 215 | (insert-buffer-substring cur beg end) | ||
| 216 | (goto-char (point-min)) | ||
| 217 | (widen) | ||
| 218 | (search-backward "\n\^_") | ||
| 219 | (narrow-to-region (point) (point-max)) | ||
| 220 | (pmail-delete-unwanted-fields) | ||
| 221 | (pmail-count-new-messages t) | ||
| 222 | (if (pmail-summary-exists) | ||
| 223 | (pmail-select-summary | ||
| 224 | (pmail-update-summary))) | ||
| 225 | (pmail-show-message msg)) | ||
| 226 | ;; Output file not in pmail mode => just insert at the end. | ||
| 227 | (narrow-to-region (point-min) (1+ (buffer-size))) | ||
| 228 | (goto-char (point-max)) | ||
| 229 | (insert-buffer-substring cur beg end) | ||
| 230 | (pmail-delete-unwanted-fields))))))) | ||
| 231 | (pmail-set-attribute pmail-filed-attr-index t)) | 195 | (pmail-set-attribute pmail-filed-attr-index t)) |
| 232 | (if redelete (pmail-set-attribute pmail-deleted-attr-index t)))) | 196 | (if redelete (pmail-set-attribute pmail-deleted-attr-index t)))) |
| 233 | (setq count (1- count)) | 197 | (setq count (1- count)) |
| 234 | (if pmail-delete-after-output | 198 | (if pmail-delete-after-output |
| 235 | (unless | 199 | (unless (if (and (= count 0) stay) |
| 236 | (if (and (= count 0) stay) | 200 | (pmail-delete-message) |
| 237 | (pmail-delete-message) | 201 | (pmail-delete-forward)) |
| 238 | (pmail-delete-forward)) | ||
| 239 | (setq count 0)) | 202 | (setq count 0)) |
| 240 | (if (> count 0) | 203 | (if (> count 0) |
| 241 | (unless | 204 | (unless (if (not stay) |
| 242 | (if (not stay) (pmail-next-undeleted-message 1)) | 205 | (pmail-next-undeleted-message 1)) |
| 243 | (setq count 0))))))) | 206 | (setq count 0)))))) |
| 207 | (pmail-show-message)) | ||
| 244 | 208 | ||
| 245 | (defalias 'pmail-output-to-pmail-file 'pmail-output-to-babyl-file) | 209 | (defalias 'pmail-output-to-pmail-file 'pmail-output-to-babyl-file) |
| 246 | 210 | ||
| 211 | (defun pmail-convert-to-babyl-format () | ||
| 212 | (let ((count 0) start | ||
| 213 | (case-fold-search nil) | ||
| 214 | (buffer-undo-list t)) | ||
| 215 | (goto-char (point-min)) | ||
| 216 | (save-restriction | ||
| 217 | (while (not (eobp)) | ||
| 218 | (setq start (point)) | ||
| 219 | (unless (looking-at "^From ") | ||
| 220 | (error "Invalid mbox message")) | ||
| 221 | (insert "\^L\n0, unseen,,\n*** EOOH ***\n") | ||
| 222 | (pmail-nuke-pinhead-header) | ||
| 223 | ;; If this message has a Content-Length field, | ||
| 224 | ;; skip to the end of the contents. | ||
| 225 | (let* ((header-end (save-excursion | ||
| 226 | (and (re-search-forward "\n\n" nil t) | ||
| 227 | (1- (point))))) | ||
| 228 | (case-fold-search t) | ||
| 229 | (quoted-printable-header-field-end | ||
| 230 | (save-excursion | ||
| 231 | (re-search-forward | ||
| 232 | "^content-transfer-encoding:\\(\n?[\t ]\\)*quoted-printable\\(\n?[\t ]\\)*" | ||
| 233 | header-end t))) | ||
| 234 | (base64-header-field-end | ||
| 235 | (and | ||
| 236 | ;; Don't decode non-text data. | ||
| 237 | (save-excursion | ||
| 238 | (re-search-forward | ||
| 239 | "^content-type:\\(\n?[\t ]\\)\\(text\\|message\\)/" | ||
| 240 | header-end t)) | ||
| 241 | (save-excursion | ||
| 242 | (re-search-forward | ||
| 243 | "^content-transfer-encoding:\\(\n?[\t ]\\)*base64\\(\n?[\t ]\\)*" | ||
| 244 | header-end t)))) | ||
| 245 | (size | ||
| 246 | ;; Get the numeric value from the Content-Length field. | ||
| 247 | (save-excursion | ||
| 248 | ;; Back up to end of prev line, | ||
| 249 | ;; in case the Content-Length field comes first. | ||
| 250 | (forward-char -1) | ||
| 251 | (and (search-forward "\ncontent-length: " | ||
| 252 | header-end t) | ||
| 253 | (let ((beg (point)) | ||
| 254 | (eol (progn (end-of-line) (point)))) | ||
| 255 | (string-to-number (buffer-substring beg eol))))))) | ||
| 256 | (and size | ||
| 257 | (if (and (natnump size) | ||
| 258 | (<= (+ header-end size) (point-max)) | ||
| 259 | ;; Make sure this would put us at a position | ||
| 260 | ;; that we could continue from. | ||
| 261 | (save-excursion | ||
| 262 | (goto-char (+ header-end size)) | ||
| 263 | (skip-chars-forward "\n") | ||
| 264 | (or (eobp) | ||
| 265 | (and (looking-at "BABYL OPTIONS:") | ||
| 266 | (search-forward "\n\^_" nil t)) | ||
| 267 | (and (looking-at "\^L") | ||
| 268 | (search-forward "\n\^_" nil t)) | ||
| 269 | (let ((case-fold-search t)) | ||
| 270 | (looking-at pmail-mmdf-delim1)) | ||
| 271 | (looking-at "From ")))) | ||
| 272 | (goto-char (+ header-end size)) | ||
| 273 | (message "Ignoring invalid Content-Length field") | ||
| 274 | (sit-for 1 0 t))) | ||
| 275 | (if (let ((case-fold-search nil)) | ||
| 276 | (re-search-forward | ||
| 277 | (concat "^[\^_]?\\(" | ||
| 278 | pmail-unix-mail-delimiter | ||
| 279 | "\\|" | ||
| 280 | pmail-mmdf-delim1 "\\|" | ||
| 281 | "^BABYL OPTIONS:\\|" | ||
| 282 | "\^L\n[01],\\)") nil t)) | ||
| 283 | (goto-char (match-beginning 1)) | ||
| 284 | (goto-char (point-max))) | ||
| 285 | (setq count (1+ count)) | ||
| 286 | (if quoted-printable-header-field-end | ||
| 287 | (save-excursion | ||
| 288 | (unless (mail-unquote-printable-region | ||
| 289 | header-end (point) nil t t) | ||
| 290 | (message "Malformed MIME quoted-printable message")) | ||
| 291 | ;; Change "quoted-printable" to "8bit", | ||
| 292 | ;; to reflect the decoding we just did. | ||
| 293 | (goto-char quoted-printable-header-field-end) | ||
| 294 | (delete-region (point) (search-backward ":")) | ||
| 295 | (insert ": 8bit"))) | ||
| 296 | (if base64-header-field-end | ||
| 297 | (save-excursion | ||
| 298 | (when (condition-case nil | ||
| 299 | (progn | ||
| 300 | (base64-decode-region | ||
| 301 | (1+ header-end) | ||
| 302 | (save-excursion | ||
| 303 | ;; Prevent base64-decode-region | ||
| 304 | ;; from removing newline characters. | ||
| 305 | (skip-chars-backward "\n\t ") | ||
| 306 | (point))) | ||
| 307 | t) | ||
| 308 | (error nil)) | ||
| 309 | ;; Change "base64" to "8bit", to reflect the | ||
| 310 | ;; decoding we just did. | ||
| 311 | (goto-char base64-header-field-end) | ||
| 312 | (delete-region (point) (search-backward ":")) | ||
| 313 | (insert ": 8bit"))))) | ||
| 314 | (save-excursion | ||
| 315 | (save-restriction | ||
| 316 | (narrow-to-region start (point)) | ||
| 317 | (goto-char (point-min)) | ||
| 318 | (while (search-forward "\n\^_" nil t) ; single char | ||
| 319 | (replace-match "\n^_")))) ; 2 chars: "^" and "_" | ||
| 320 | ;; This is for malformed messages that don't end in newline. | ||
| 321 | ;; There shouldn't be any, but some users say occasionally | ||
| 322 | ;; there are some. | ||
| 323 | (or (bolp) (newline)) | ||
| 324 | (insert ?\^_) | ||
| 325 | (setq last-coding-system-used nil) | ||
| 326 | (or pmail-enable-mime | ||
| 327 | (not pmail-enable-multibyte) | ||
| 328 | (let ((mime-charset | ||
| 329 | (if (and pmail-decode-mime-charset | ||
| 330 | (save-excursion | ||
| 331 | (goto-char start) | ||
| 332 | (search-forward "\n\n" nil t) | ||
| 333 | (let ((case-fold-search t)) | ||
| 334 | (re-search-backward | ||
| 335 | pmail-mime-charset-pattern | ||
| 336 | start t)))) | ||
| 337 | (intern (downcase (match-string 1)))))) | ||
| 338 | (pmail-decode-region start (point) mime-charset))) | ||
| 339 | (save-excursion | ||
| 340 | (goto-char start) | ||
| 341 | (forward-line 3) | ||
| 342 | (insert "X-Coding-System: " | ||
| 343 | (symbol-name last-coding-system-used) | ||
| 344 | "\n")) | ||
| 345 | (narrow-to-region (point) (point-max)) | ||
| 346 | (and (= 0 (% count 10)) | ||
| 347 | (message "Converting to Babyl format...%d" count)))))) | ||
| 348 | |||
| 349 | ;; Delete the "From ..." line, creating various other headers with | ||
| 350 | ;; information from it if they don't already exist. Now puts the | ||
| 351 | ;; original line into a mail-from: header line for debugging and for | ||
| 352 | ;; use by the pmail-output function. | ||
| 353 | (defun pmail-nuke-pinhead-header () | ||
| 354 | (save-excursion | ||
| 355 | (save-restriction | ||
| 356 | (let ((start (point)) | ||
| 357 | (end (progn | ||
| 358 | (condition-case () | ||
| 359 | (search-forward "\n\n") | ||
| 360 | (error | ||
| 361 | (goto-char (point-max)) | ||
| 362 | (insert "\n\n"))) | ||
| 363 | (point))) | ||
| 364 | has-from has-date) | ||
| 365 | (narrow-to-region start end) | ||
| 366 | (let ((case-fold-search t)) | ||
| 367 | (goto-char start) | ||
| 368 | (setq has-from (search-forward "\nFrom:" nil t)) | ||
| 369 | (goto-char start) | ||
| 370 | (setq has-date (and (search-forward "\nDate:" nil t) (point))) | ||
| 371 | (goto-char start)) | ||
| 372 | (let ((case-fold-search nil)) | ||
| 373 | (if (re-search-forward (concat "^" pmail-unix-mail-delimiter) nil t) | ||
| 374 | (replace-match | ||
| 375 | (concat | ||
| 376 | "Mail-from: \\&" | ||
| 377 | ;; Keep and reformat the date if we don't | ||
| 378 | ;; have a Date: field. | ||
| 379 | (if has-date | ||
| 380 | "" | ||
| 381 | (concat | ||
| 382 | "Date: \\2, \\4 \\3 \\9 \\5 " | ||
| 383 | |||
| 384 | ;; The timezone could be matched by group 7 or group 10. | ||
| 385 | ;; If neither of them matched, assume EST, since only | ||
| 386 | ;; Easterners would be so sloppy. | ||
| 387 | ;; It's a shame the substitution can't use "\\10". | ||
| 388 | (cond | ||
| 389 | ((/= (match-beginning 7) (match-end 7)) "\\7") | ||
| 390 | ((/= (match-beginning 10) (match-end 10)) | ||
| 391 | (buffer-substring (match-beginning 10) | ||
| 392 | (match-end 10))) | ||
| 393 | (t "EST")) | ||
| 394 | "\n")) | ||
| 395 | ;; Keep and reformat the sender if we don't | ||
| 396 | ;; have a From: field. | ||
| 397 | (if has-from | ||
| 398 | "" | ||
| 399 | "From: \\1\n")) | ||
| 400 | t))))))) | ||
| 401 | |||
| 247 | ;;;###autoload | 402 | ;;;###autoload |
| 248 | (defcustom pmail-fields-not-to-output nil | 403 | (defcustom pmail-fields-not-to-output nil |
| 249 | "*Regexp describing fields to exclude when outputting a message to a file." | 404 | "*Regexp describing fields to exclude when outputting a message to a file." |