Mercurial > emacs
changeset 98313:c7eef45e0d32
First pass at handling decoding the mbox message into the view buffer.
author | Paul Reilly <pmr@pajato.com> |
---|---|
date | Tue, 23 Sep 2008 11:30:17 +0000 |
parents | d8a3b46ba292 |
children | 7fafc74e823f |
files | lisp/mail/pmail.el |
diffstat | 1 files changed, 132 insertions(+), 71 deletions(-) [+] |
line wrap: on
line diff
--- a/lisp/mail/pmail.el Tue Sep 23 08:25:44 2008 +0000 +++ b/lisp/mail/pmail.el Tue Sep 23 11:30:17 2008 +0000 @@ -910,7 +910,7 @@ (pmail-maybe-set-message-counters) (unwind-protect (unless (and (not file-name-arg) (pmail-get-new-mail)) - (pmail-show-message (pmail-first-unseen-message))) + (pmail-show-message-maybe (pmail-first-unseen-message))) (progn (if pmail-display-summary (pmail-summary)) (pmail-construct-io-menu) @@ -984,6 +984,18 @@ Note: If you are seeing it in pmail, Note: it means the file has no messages in it.\n\^_"))) +(defun pmail-get-coding-system () + "Return a suitable coding system to use for the mail message in +the region." + (let ((content-type-header (mail-fetch-field "content-type")) + separator) + (save-excursion + (setq separator (search-forward "\n\n"))) + (if (and content-type-header + (string-match pmail-mime-charset-pattern content-type-header)) + (substring content-type-header (match-beginning 1) (match-end 1)) + 'undecided))) + ;; Decode Babyl formatted part at the head of current buffer by ;; pmail-file-coding-system, or if it is nil, do auto conversion. @@ -1036,7 +1048,7 @@ (define-key pmail-mode-map "g" 'pmail-get-new-mail) (define-key pmail-mode-map "h" 'pmail-summary) (define-key pmail-mode-map "i" 'pmail-input) - (define-key pmail-mode-map "j" 'pmail-show-message) + (define-key pmail-mode-map "j" 'pmail-show-message-maybe) (define-key pmail-mode-map "k" 'pmail-kill-label) (define-key pmail-mode-map "l" 'pmail-summary-by-labels) (define-key pmail-mode-map "\e\C-h" 'pmail-summary) @@ -1252,7 +1264,7 @@ \\[pmail-previous-message] Move to Previous message whether deleted or not. \\[pmail-first-message] Move to the first message in Pmail file. \\[pmail-last-message] Move to the last message in Pmail file. -\\[pmail-show-message] Jump to message specified by numeric position in file. +\\[pmail-show-message-maybe] Jump to message specified by numeric position in file. \\[pmail-search] Search for string and show message it is found in. \\[pmail-delete-forward] Delete this message, move to next nondeleted. \\[pmail-delete-backward] Delete this message, move to previous nondeleted. @@ -1298,7 +1310,7 @@ (goto-char (point-max)) (set-buffer-multibyte t))) (pmail-set-message-counters) - (pmail-show-message pmail-total-messages) + (pmail-show-message-maybe pmail-total-messages) (when finding-pmail-file (when pmail-display-summary (pmail-summary)) @@ -1339,7 +1351,10 @@ (make-local-variable 'pmail-buffer) (setq pmail-buffer (current-buffer)) (make-local-variable 'pmail-view-buffer) - (setq pmail-view-buffer (pmail-generate-viewer-buffer)) + (save-excursion + (setq pmail-view-buffer (pmail-generate-viewer-buffer)) + (set-buffer pmail-view-buffer) + (set-buffer-multibyte t)) (make-local-variable 'pmail-summary-buffer) (make-local-variable 'pmail-summary-vector) (make-local-variable 'pmail-current-message) @@ -1421,7 +1436,7 @@ (set-buffer-multibyte t)) (goto-char (point-max)) (pmail-set-message-counters) - (pmail-show-message pmail-total-messages) + (pmail-show-message-maybe pmail-total-messages) (run-hooks 'pmail-mode-hook)))) ;; Return a list of files from this buffer's Mail: option. @@ -1501,7 +1516,7 @@ (goto-char (pmail-msgend pmail-current-message)) (insert string) (pmail-forget-messages) - (pmail-show-message number) + (pmail-show-message-maybe number) (message "Message duplicated"))) ;;;###autoload @@ -1774,12 +1789,12 @@ ;; Move to the first new message ;; unless we have other unseen messages before it. - (pmail-show-message (pmail-first-unseen-message)) + (pmail-show-message-maybe (pmail-first-unseen-message)) (run-hooks 'pmail-after-get-new-mail-hook) (setq found t)))) found) ;; Don't leave the buffer screwed up if we get a disk-full error. - (or found (pmail-show-message))))) + (or found (pmail-show-message-maybe))))) (defun pmail-parse-url (file) "Parse the supplied URL. Return (list MAILBOX-NAME REMOTE PASSWORD GOT-PASSWORD) @@ -1976,13 +1991,13 @@ ;; Decode the region specified by FROM and TO by CODING. ;; If CODING is nil or an invalid coding system, decode by `undecided'. -(defun pmail-decode-region (from to coding) +(defun pmail-decode-region (from to coding &optional destination) (if (or (not coding) (not (coding-system-p coding))) (setq coding 'undecided)) ;; Use -dos decoding, to remove ^M characters left from base64 or ;; rogue qp-encoded text. - (decode-coding-region from to - (coding-system-change-eol-conversion coding 1)) + (decode-coding-region + from to (coding-system-change-eol-conversion coding 1) destination) ;; Don't reveal the fact we used -dos decoding, as users generally ;; will not expect the PMAIL buffer to use DOS EOL format. (setq buffer-file-coding-system @@ -2382,8 +2397,7 @@ copy all header fields whose names do not match `rmail-ignored-headers' (unless they also match `rmail-nonignored-headers')." - (let ((result "") - (header-start-regexp "\n[^ \t]") + (let ((header-start-regexp "\n[^ \t]") lim) (with-current-buffer pmail-buffer (when (search-forward "\n\n" nil t) @@ -2398,7 +2412,7 @@ (cond ;; Handle the case where all headers should be copied. ((eq pmail-header-style 'full) - (setq result (buffer-substring beg (point-max)))) + (prepend-to-buffer pmail-view-buffer beg (point-max))) ;; Handle the case where the headers matching the diplayed ;; headers regexp should be copied. ((and pmail-displayed-headers (null ignored-headers)) @@ -2408,7 +2422,7 @@ (1+ (match-beginning 0)) (point-max)))) (when (looking-at pmail-displayed-headers) - (setq result (concat result (buffer-substring (point) lim)))) + (append-to-buffer pmail-view-buffer (point) lim)) (goto-char lim))) ;; Handle the ignored headers. ((or ignored-headers (setq ignored-headers pmail-ignored-headers)) @@ -2420,19 +2434,9 @@ (if (and (looking-at ignored-headers) (not (looking-at pmail-nonignored-headers))) (goto-char lim) - (setq result (concat result (buffer-substring (point) lim))) + (append-to-buffer pmail-view-buffer (point) lim) (goto-char lim)))) - (t (error "No headers selected for display!")))))) - result)) - -(defun pmail-copy-body (beg end) - "Return the message body to be displayed in the view buffer. -BEG and END marks the start and end positions of the message in -the mail buffer." - (with-current-buffer pmail-buffer - (if (search-forward "\n\n" nil t) - (buffer-substring (point) end) - (error "Invalid message format: no header/body separator")))) + (t (error "No headers selected for display!")))))))) (defun pmail-toggle-header (&optional arg) "Show original message header if pruned header currently shown, or vice versa. @@ -2444,7 +2448,7 @@ ((and (numberp arg) (> arg 0)) 'normal) ((eq pmail-header-style 'full) 'normal) (t 'full))) - (pmail-show-message)) + (pmail-show-message-maybe)) ;; Lifted from repos-count-screen-lines. ;; Return number of screen lines between START and END. @@ -2750,7 +2754,7 @@ (let ((pmail-show-message-hook (list (function (lambda () (goto-char (point-min))))))) - (pmail-show-message pmail-current-message))) + (pmail-show-message-maybe pmail-current-message))) (defun pmail-end-of-message () "Show bottom of current message." @@ -2759,7 +2763,7 @@ (list (function (lambda () (goto-char (point-max)) (recenter (1- (window-height)))))))) - (pmail-show-message pmail-current-message))) + (pmail-show-message-maybe pmail-current-message))) (defun pmail-unknown-mail-followup-to () "Handle a \"Mail-Followup-To\" header field with an unknown mailing list. @@ -2801,7 +2805,7 @@ (buffer-swap-text pmail-view-buffer) (setq pmail-buffers-swapped-p nil)))) -(defun pmail-show-message (&optional n no-summary) +(defun pmail-show-message-maybe (&optional n no-summary) "Show message number N (prefix argument), counting from start of file. If summary buffer is currently displayed, update current message there also." (interactive "p") @@ -2816,39 +2820,10 @@ (with-current-buffer pmail-view-buffer (erase-buffer) (setq blurb "No mail."))) - (if (not n) - (setq n pmail-current-message) - (cond ((<= n 0) - (setq n 1 - pmail-current-message 1 - blurb "No previous message")) - ((> n pmail-total-messages) - (setq n pmail-total-messages - pmail-current-message pmail-total-messages - blurb "No following message")) - (t - (setq pmail-current-message n)))) - (let ((buf pmail-buffer) - (beg (pmail-msgbeg n)) - (end (pmail-msgend n)) - headers body) - (goto-char beg) - (setq headers (pmail-copy-headers beg end) - body (pmail-copy-body beg end)) - (pmail-set-attribute pmail-unseen-attr-index nil) - (with-current-buffer pmail-view-buffer - (erase-buffer) - (insert headers "\n") - (pmail-highlight-headers) - (insert body) - (goto-char (point-min))))) + (setq blurb (pmail-show-message n))) (when mail-mailing-lists (pmail-unknown-mail-followup-to)) (if transient-mark-mode (deactivate-mark)) - (pmail-display-labels) - (buffer-swap-text pmail-view-buffer) - (setq pmail-buffers-swapped-p t) - (run-hooks 'pmail-show-message-hook) ;; If there is a summary buffer, try to move to this message ;; in that buffer. But don't complain if this message ;; is not mentioned in the summary. @@ -2863,6 +2838,93 @@ (if blurb (message blurb)))) +(defun pmail-is-text-p () + "Return t if the region contains a text message, nil +otherwise." + (save-excursion + (let ((text-regexp "\\(text\\|message\\)/") + (content-type-header (mail-fetch-field "content-type"))) + ;; The message is text if either there is no content type header + ;; (a default of "text/plain; charset=US-ASCII" is assumed) or + ;; the base content type is either text or message. + (or (not content-type-header) + (string-match text-regexp content-type-header))))) + +(defun pmail-show-message (&optional msg) + "Show message MSG using a special view buffer. +Return text to display in the minibuffer if MSG is out of +range (displaying a reasonable choice as well), nil otherwise. +The current mail message becomes the message displayed." + (let ((mbox-buf pmail-buffer) + (view-buf pmail-view-buffer) + blurb beg end body-start coding-system character-coding is-text-message) + (if (not msg) + (setq msg pmail-current-message)) + (cond ((<= msg 0) + (setq msg 1 + pmail-current-message 1 + blurb "No previous message")) + ((> msg pmail-total-messages) + (setq msg pmail-total-messages + pmail-current-message pmail-total-messages + blurb "No following message")) + (t (setq pmail-current-message msg))) + (with-current-buffer pmail-buffer + ;; Mark the message as seen, bracket the message in the mail + ;; buffer and determine the coding system the transfer encoding. + (pmail-set-attribute pmail-unseen-attr-index nil) + (setq beg (pmail-msgbeg msg) + end (pmail-msgend msg)) + (widen) + (narrow-to-region beg end) + (goto-char beg) + (setq body-start (search-forward "\n\n" nil t)) + (narrow-to-region beg (point)) + (goto-char beg) + (setq character-coding (mail-fetch-field "content-transfer-encoding") + is-text-message (pmail-is-text-p) + coding-system (pmail-get-coding-system)) + (widen) + (narrow-to-region beg end) + ;; Decode the message body into an empty view buffer using a + ;; unibyte temporary buffer where the character decoding takes + ;; place. + (with-current-buffer pmail-view-buffer + (erase-buffer)) + (with-temp-buffer + (set-buffer-multibyte nil) + (insert-buffer-substring mbox-buf body-start end) + (cond + ((string= character-coding "quoted-printable") + (mail-unquote-printable-region (point-min) (point-max))) + ((and (string= character-coding "base64") is-text-message) + (base64-decode-region (point-min) (point-max))) + ((eq character-coding 'uuencode) + (error "Not supported yet.")) + (t)) + (pmail-decode-region (point-min) (point-max) coding-system view-buf)) + ;; Copy the headers to the front of the message view buffer. + (with-current-buffer pmail-view-buffer + (goto-char (point-min))) + (pmail-copy-headers beg end) + ;; Add the separator (blank line) between headers and body; + ;; highlight the message, activate any URL like text and add + ;; special highlighting for and quoted material. + (with-current-buffer pmail-view-buffer + (insert "\n") + (goto-char (point-min)) + (pmail-highlight-headers) + ;(pmail-activate-urls) + ;(pmail-process-quoted-material) + ) + ;; Update the mode-line with message status information and swap + ;; the view buffer/mail buffer contents. + (pmail-display-labels) + (buffer-swap-text pmail-view-buffer) + (setq pmail-buffers-swapped-p t) + (run-hooks 'pmail-show-message-hook)) + blurb)) + ;; Find all occurrences of certain fields, and highlight them. (defun pmail-highlight-headers () ;; Do this only if the system supports faces. @@ -2950,7 +3012,7 @@ (interactive "p") (set-buffer pmail-buffer) (pmail-maybe-set-message-counters) - (pmail-show-message (+ pmail-current-message n))) + (pmail-show-message-maybe (+ pmail-current-message n))) (defun pmail-previous-message (n) "Show previous message whether deleted or not. @@ -2978,7 +3040,7 @@ (if (not (pmail-message-deleted-p current)) (setq lastwin current n (1+ n)))) (if (/= lastwin pmail-current-message) - (progn (pmail-show-message lastwin) + (progn (pmail-show-message-maybe lastwin) t) (if (< n 0) (message "No previous nondeleted message")) @@ -2997,13 +3059,13 @@ "Show first message in file." (interactive) (pmail-maybe-set-message-counters) - (pmail-show-message 1)) + (pmail-show-message-maybe (< 1 pmail-total-messages))) (defun pmail-last-message () "Show last message in file." (interactive) (pmail-maybe-set-message-counters) - (pmail-show-message pmail-total-messages)) + (pmail-show-message-maybe pmail-total-messages)) (defun pmail-what-message () (let ((where (point)) @@ -3113,7 +3175,7 @@ (setq n (+ n (if reversep 1 -1))))) (if win (progn - (pmail-show-message msg) + (pmail-show-message-maybe msg) ;; Search forward (if this is a normal search) or backward ;; (if this is a reverse search) through this message to ;; position point. This search may fail because REGEXP @@ -3245,7 +3307,7 @@ (if done (setq found i))) (setq n (if forward (1- n) (1+ n)))))) (if found - (pmail-show-message found) + (pmail-show-message-maybe found) (error "No %s message with same subject" (if forward "following" "previous"))))) @@ -3281,7 +3343,7 @@ (if (= msg 0) (error "No previous deleted message") (if (/= msg pmail-current-message) - (pmail-show-message msg)) + (pmail-show-message-maybe msg)) (pmail-set-attribute pmail-deleted-attr-index nil) (if (pmail-summary-exists) (save-excursion @@ -3416,8 +3478,7 @@ (if (not win) (narrow-to-region (- (buffer-size) omin) (- (buffer-size) omax))) (if (not dont-show) - (pmail-show-message - (if (zerop pmail-current-message) 1 nil))) + (pmail-show-message-maybe (< pmail-current-message pmail-total-messages))) (pmail-swap-buffers-maybe) (if pmail-enable-mime (goto-char (+ (point-min) opoint))