Mercurial > hg > xemacs-beta
diff lisp/vm/vm-mime.el @ 54:05472e90ae02 r19-16-pre2
Import from CVS: tag r19-16-pre2
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:57:55 +0200 |
parents | 8b8b7f3559a2 |
children |
line wrap: on
line diff
--- a/lisp/vm/vm-mime.el Mon Aug 13 08:57:25 2007 +0200 +++ b/lisp/vm/vm-mime.el Mon Aug 13 08:57:55 2007 +0200 @@ -38,9 +38,12 @@ (defun vm-mm-layout-body-end (e) (aref e 9)) (defun vm-mm-layout-parts (e) (aref e 10)) (defun vm-mm-layout-cache (e) (aref e 11)) +;; if display of MIME part fails, error string will be here. +(defun vm-mm-layout-display-error (e) (aref e 12)) (defun vm-set-mm-layout-type (e type) (aset e 0 type)) (defun vm-set-mm-layout-cache (e c) (aset e 11 c)) +(defun vm-set-mm-layout-display-error (e c) (aset e 12 c)) (defun vm-mm-layout (m) (or (vm-mime-layout-of m) @@ -104,7 +107,7 @@ (defun vm-mime-charset-decode-region (charset start end) (or (markerp end) (setq end (vm-marker end))) - (cond ((vm-xemacs-mule-p) + (cond (vm-xemacs-mule-p (if (eq (device-type) 'x) (let ((buffer-read-only nil) (cell (cdr (vm-string-assoc @@ -344,7 +347,7 @@ ((looking-at "\n") ; soft line break (forward-char)) ((looking-at "\r") - ;; assume the user's goatfucking + ;; assume the user's goatloving ;; delivery software didn't convert ;; from Internet's CRLF newline ;; convention to the local LF @@ -391,7 +394,9 @@ (vm-increment cols)) ((or (< char 33) (> char 126) (= char 61) (and quote-from (= cols 0) (let ((case-fold-search nil)) - (looking-at "From ")))) + (looking-at "From "))) + (and (= cols 0) (= char ?.) + (looking-at "\\.\\(\n\\|\\'\\)"))) (vm-insert-char ?= 1 nil work-buffer) (vm-insert-char (car (rassq (lsh char -4) hex-digit-alist)) 1 nil work-buffer) @@ -526,85 +531,7 @@ (vm-with-string-as-temp-buffer string 'vm-reencode-mime-encoded-words) string )) -(defun vm-mime-parse-content-header (string &optional sepchar keep-quotes) - (if (null string) - () - (let ((work-buffer nil)) - (save-excursion - (unwind-protect - (let ((list nil) - (nonspecials "^\"\\( \t\n\r\f") - start s char sp+sepchar) - (if sepchar - (setq nonspecials (concat nonspecials (list sepchar)) - sp+sepchar (concat "\t\f\n\r " (list sepchar)))) - (setq work-buffer (generate-new-buffer "*vm-work*")) - (buffer-disable-undo work-buffer) - (set-buffer work-buffer) - (insert string) - (goto-char (point-min)) - (skip-chars-forward "\t\f\n\r ") - (setq start (point)) - (while (not (eobp)) - (skip-chars-forward nonspecials) - (setq char (following-char)) - (cond ((looking-at "[ \t\n\r\f]") - (delete-char 1)) - ((= char ?\\) - (forward-char 1) - (if (not (eobp)) - (forward-char 1))) - ((and sepchar (= char sepchar)) - (setq s (buffer-substring start (point))) - (if (or (null (string-match "^[\t\f\n\r ]+$" s)) - (not (string= s ""))) - (setq list (cons s list))) - (skip-chars-forward sp+sepchar) - (setq start (point))) - ((looking-at " \t\n\r\f") - (skip-chars-forward " \t\n\r\f")) - ((= char ?\") - (let ((done nil)) - (if keep-quotes - (forward-char 1) - (delete-char 1)) - (while (not done) - (if (null (re-search-forward "[\\\"]" nil t)) - (setq done t) - (setq char (char-after (1- (point)))) - (cond ((char-equal char ?\\) - (delete-char -1) - (if (eobp) - (setq done t) - (forward-char 1))) - (t (if (not keep-quotes) - (delete-char -1)) - (setq done t))))))) - ((= char ?\() - (let ((done nil) - (pos (point)) - (parens 1)) - (forward-char 1) - (while (not done) - (if (null (re-search-forward "[\\()]" nil t)) - (setq done t) - (setq char (char-after (1- (point)))) - (cond ((char-equal char ?\\) - (if (eobp) - (setq done t) - (forward-char 1))) - ((char-equal char ?\() - (setq parens (1+ parens))) - (t - (setq parens (1- parens) - done (zerop parens)))))) - (delete-region pos (point)))))) - (setq s (buffer-substring start (point))) - (if (and (null (string-match "^[\t\f\n\r ]+$" s)) - (not (string= s ""))) - (setq list (cons s list))) - (nreverse list)) - (and work-buffer (kill-buffer work-buffer))))))) +(fset 'vm-mime-parse-content-header 'vm-parse-structured-header) (defun vm-mime-get-header-contents (header-name-regexp) (let ((contents nil) @@ -641,7 +568,9 @@ encoding (or (vm-get-header-contents m "Content-Transfer-Encoding:") "7bit") - encoding (car (vm-mime-parse-content-header encoding)) + encoding (or (car + (vm-mime-parse-content-header encoding)) + "7bit") id (vm-get-header-contents m "Content-ID:") id (car (vm-mime-parse-content-header id)) description (vm-get-header-contents @@ -670,7 +599,8 @@ encoding (or (vm-mime-get-header-contents "Content-Transfer-Encoding:") default-encoding) - encoding (car (vm-mime-parse-content-header encoding)) + encoding (or (car (vm-mime-parse-content-header encoding)) + default-encoding) id (vm-mime-get-header-contents "Content-ID:") id (car (vm-mime-parse-content-header id)) description (vm-mime-get-header-contents @@ -745,7 +675,7 @@ (narrow-to-region (point) (point-max)) (vm-mime-parse-entity-safe nil c-t c-t-e))) - nil ))) + nil nil ))) (t (goto-char (point-min)) (or (re-search-forward "^\n\\|\n\\'" nil t) @@ -756,7 +686,7 @@ (vm-marker (point-min)) (vm-marker (point)) (vm-marker (point-max)) - nil nil )))) + nil nil nil )))) (setq p (cdr type) boundary nil) (while p @@ -803,7 +733,7 @@ (vm-marker (point)) (vm-marker (point-max)) (nreverse multipart-list) - nil ))))))) + nil nil ))))))) (defun vm-mime-parse-entity-safe (&optional m c-t c-t-e) (or c-t (setq c-t '("text/plain" "charset=us-ascii"))) @@ -834,7 +764,8 @@ '("attachment") '("attachment") header text - text-end))))) + text-end + nil nil nil))))) (defun vm-mime-get-xxx-parameter (layout name param-list) (let ((match-end (1+ (length name))) @@ -900,9 +831,9 @@ (defvar scroll-in-place) (make-local-variable 'scroll-in-place) (setq scroll-in-place nil) - (and (vm-xemacs-mule-p) - (set-file-coding-system 'binary t)) - (cond ((vm-fsfemacs-19-p) + (and vm-xemacs-mule-p + (set-buffer-file-coding-system 'binary t)) + (cond (vm-fsfemacs-19-p ;; need to do this outside the let because ;; loading disp-table initializes ;; standard-display-table. @@ -911,7 +842,8 @@ (copy-sequence standard-display-table))) (standard-display-european t) (setq buffer-display-table standard-display-table)))) - (if (and vm-frame-per-folder (vm-multiple-frames-possible-p)) + (if (and vm-mutable-frames vm-frame-per-folder + (vm-multiple-frames-possible-p)) (vm-set-hooks-for-frame-deletion)) (use-local-map vm-mode-map) (and (vm-toolbar-support-possible-p) vm-use-toolbar @@ -935,6 +867,8 @@ (set-buffer b) (widen) (let ((buffer-read-only nil) + ;; disable read-only text properties + (inhibit-read-only t) (modified (buffer-modified-p))) (unwind-protect (progn @@ -966,7 +900,7 @@ (fset 'vm-presentation-mode 'vm-mode) (put 'vm-presentation-mode 'mode-class 'special) -(defvar file-coding-system) +(defvar buffer-file-coding-system) (defun vm-determine-proper-charset (beg end) (save-excursion @@ -974,14 +908,15 @@ (narrow-to-region beg end) (catch 'done (goto-char (point-min)) - (if (vm-xemacs-mule-p) + (if vm-xemacs-mule-p (let ((charsets (delq 'ascii (charsets-in-region beg end)))) (cond ((null charsets) "us-ascii") ((cdr charsets) (or (car (cdr - (assoc (coding-system-name file-coding-system) - vm-mime-mule-coding-to-charset-alist))) + (assq (coding-system-name + buffer-file-coding-system) + vm-mime-mule-coding-to-charset-alist))) "iso-2022-jp")) (t (or (car (cdr @@ -1037,23 +972,23 @@ (defun vm-mime-can-display-internal (layout) (let ((type (car (vm-mm-layout-type layout)))) (cond ((vm-mime-types-match "image/jpeg" type) - (and (vm-xemacs-p) + (and vm-xemacs-p (featurep 'jpeg) (eq (device-type) 'x))) ((vm-mime-types-match "image/gif" type) - (and (vm-xemacs-p) + (and vm-xemacs-p (featurep 'gif) (eq (device-type) 'x))) ((vm-mime-types-match "image/png" type) - (and (vm-xemacs-p) + (and vm-xemacs-p (featurep 'png) (eq (device-type) 'x))) ((vm-mime-types-match "image/tiff" type) - (and (vm-xemacs-p) + (and vm-xemacs-p (featurep 'tiff) (eq (device-type) 'x))) ((vm-mime-types-match "audio/basic" type) - (and (vm-xemacs-p) + (and vm-xemacs-p (or (featurep 'native-sound) (featurep 'nas-sound)) (or (device-sound-enabled-p) @@ -1068,13 +1003,11 @@ (let ((charset (or (vm-mime-get-parameter layout "charset") "us-ascii"))) (vm-mime-charset-internally-displayable-p charset))) -;; commented out until w3-region behavior gets worked out -;; -;; ((vm-mime-types-match "text/html" type) -;; (condition-case () -;; (progn (require 'w3) -;; (fboundp 'w3-region)) -;; (error nil))) + ((vm-mime-types-match "text/html" type) + (condition-case () + (progn (require 'w3) + (fboundp 'w3-region)) + (error nil))) (t nil)))) (defun vm-mime-can-convert (type) @@ -1126,7 +1059,8 @@ (vm-marker (point)) (vm-marker (point-max)) nil - nil )))) + nil + nil)))) (defun vm-mime-should-display-button (layout dont-honor-content-disposition) (if (and vm-honor-mime-content-disposition @@ -1327,7 +1261,9 @@ ;; text/plain. (vm-mime-display-internal-text/plain layout))) (t (and extent (vm-mime-rewrite-failed-button - extent (vm-mm-layout-cache layout))) + extent + (or (vm-mm-layout-display-error layout) + "no external viewer defined for type"))) (vm-mime-display-internal-application/octet-stream (or extent layout)))) (and extent (vm-mime-delete-button-maybe extent))) @@ -1337,28 +1273,29 @@ (defun vm-mime-display-button-text (layout) (vm-mime-display-button-xxxx layout t)) -;; commented out until w3-region behavior is worked out -;; -;;(defun vm-mime-display-internal-text/html (layout) -;; (let ((buffer-read-only nil) -;; (work-buffer nil)) -;; (message "Inlining text/html, be patient...") -;; ;; w3-region is not as tame as we would like. -;; ;; make sure the yoke is firmly attached. -;; (unwind-protect -;; (progn -;; (save-excursion -;; (set-buffer (setq work-buffer -;; (generate-new-buffer " *workbuf*"))) -;; (vm-mime-insert-mime-body layout) -;; (vm-mime-transfer-decode-region layout (point-min) (point-max)) -;; (save-excursion -;; (save-window-excursion -;; (w3-region (point-min) (point-max))))) -;; (insert-buffer-substring work-buffer)) -;; (and work-buffer (kill-buffer work-buffer))) -;; (message "Inlining text/html... done") -;; t )) +(defun vm-mime-display-internal-text/html (layout) + (if (fboundp 'w3-region) + (let ((buffer-read-only nil) + (work-buffer nil)) + (message "Inlining text/html, be patient...") + ;; w3-region is not as tame as we would like. + ;; make sure the yoke is firmly attached. + (unwind-protect + (progn + (save-excursion + (set-buffer (setq work-buffer + (generate-new-buffer " *workbuf*"))) + (vm-mime-insert-mime-body layout) + (vm-mime-transfer-decode-region layout (point-min) (point-max)) + (save-excursion + (save-window-excursion + (w3-region (point-min) (point-max))))) + (insert-buffer-substring work-buffer)) + (and work-buffer (kill-buffer work-buffer))) + (message "Inlining text/html... done") + t ) + (vm-set-mm-layout-display-error layout "Need W3 to inline HTML") + nil )) (defun vm-mime-display-internal-text/plain (layout &optional no-highlighting) (let ((start (point)) end old-size @@ -1366,7 +1303,7 @@ (charset (or (vm-mime-get-parameter layout "charset") "us-ascii"))) (if (not (vm-mime-charset-internally-displayable-p charset)) (progn - (vm-set-mm-layout-cache + (vm-set-mm-layout-display-error layout (concat "Undisplayable charset: " charset)) nil) (vm-mime-insert-mime-body layout) @@ -1403,11 +1340,13 @@ (defun vm-mime-display-external-generic (layout) (let ((program-list (vm-mime-find-external-viewer (car (vm-mm-layout-type layout)))) - (process (nth 0 (vm-mm-layout-cache layout))) - (tempfile (nth 1 (vm-mm-layout-cache layout))) (buffer-read-only nil) (start (point)) - end) + process tempfile cache end) + (setq cache (cdr (assq 'vm-mime-display-external-generic + (vm-mm-layout-cache layout))) + process (nth 0 cache) + tempfile (nth 1 cache)) (if (and (processp process) (eq (process-status process) 'run)) t (cond ((or (null tempfile) (null (file-exists-p tempfile))) @@ -1416,15 +1355,20 @@ (vm-mime-transfer-decode-region layout start end) (setq tempfile (vm-make-tempfile-name)) (let ((buffer-file-type buffer-file-type) - file-coding-system) + buffer-file-coding-system) ;; Tell DOS/Windows NT whether the file is binary (setq buffer-file-type (not (vm-mime-text-type-p layout))) ;; Tell XEmacs/MULE not to mess with the bits unless ;; this is a text type. - (if (vm-xemacs-mule-p) + (if vm-xemacs-mule-p (if (vm-mime-text-type-p layout) - (set-file-coding-system 'no-conversion nil) - (set-file-coding-system 'binary t))) + (set-buffer-file-coding-system 'no-conversion nil) + (set-buffer-file-coding-system 'binary t))) + ;; Write an empty tempfile out to disk and set its + ;; permissions to 0600, then write the actual buffer + ;; contents to tempfile. + (write-region start start tempfile nil 0) + (set-file-modes tempfile 384) (write-region start end tempfile nil 0)) (delete-region start end) (save-excursion @@ -1446,7 +1390,11 @@ (setq vm-message-garbage-alist (cons (cons process 'delete-process) vm-message-garbage-alist))) - (vm-set-mm-layout-cache layout (list process tempfile)))) + (vm-set-mm-layout-cache + layout + (nconc (vm-mm-layout-cache layout) + (list (cons 'vm-mime-display-external-generic + (list process tempfile))))))) t ) (defun vm-mime-display-internal-application/octet-stream (layout) @@ -1456,7 +1404,7 @@ (vm-mime-insert-button (format "%-35.35s [%s to save to a file]" (vm-mime-layout-description layout) - (if (vm-mouse-support-possible-p) + (if (vm-mouse-support-possible-here-p) "Click mouse-2" "Press RETURN")) (function @@ -1475,9 +1423,12 @@ (vm-mime-get-parameter layout "name")))) (vm-mime-send-body-to-file layout default-filename))) t ) -(fset 'vm-mime-display-button-application +(fset 'vm-mime-display-button-application/octet-stream 'vm-mime-display-internal-application/octet-stream) +(defun vm-mime-display-button-application (layout) + (vm-mime-display-button-xxxx layout nil)) + (defun vm-mime-display-button-image (layout) (vm-mime-display-button-xxxx layout t)) @@ -1540,7 +1491,7 @@ (vm-mime-insert-button (format "%-35.35s [%s to display in parallel]" (vm-mime-layout-description layout) - (if (vm-mouse-support-possible-p) + (if (vm-mouse-support-possible-here-p) "Click mouse-2" "Press RETURN")) (function @@ -1559,7 +1510,7 @@ (vm-mime-insert-button (format "%-35.35s [%s to display]" (vm-mime-layout-description layout) - (if (vm-mouse-support-possible-p) + (if (vm-mouse-support-possible-here-p) "Click mouse-2" "Press RETURN")) (function @@ -1586,20 +1537,36 @@ (fset 'vm-mime-display-button-multipart/digest 'vm-mime-display-internal-multipart/digest) +(defun vm-mime-display-button-message/rfc822 (layout) + (let ((buffer-read-only nil)) + (vm-mime-insert-button + (format "%-35.35s [%s to display]" + (vm-mime-layout-description layout) + (if (vm-mouse-support-possible-here-p) + "Click mouse-2" + "Press RETURN")) + (function + (lambda (layout) + (save-excursion + (vm-mime-display-internal-message/rfc822 layout)))) + layout nil))) +(fset 'vm-mime-display-button-message/news + 'vm-mime-display-button-message/rfc822) + (defun vm-mime-display-internal-message/rfc822 (layout) (if (vectorp layout) - (let ((buffer-read-only nil)) - (vm-mime-insert-button - (format "%-35.35s [%s to display]" - (vm-mime-layout-description layout) - (if (vm-mouse-support-possible-p) - "Click mouse-2" - "Press RETURN")) - (function - (lambda (layout) - (save-excursion - (vm-mime-display-internal-message/rfc822 layout)))) - layout nil)) + (let ((start (point)) + (buffer-read-only nil)) + (vm-mime-insert-mime-headers (car (vm-mm-layout-parts layout))) + (insert ?\n) + (save-excursion + (goto-char start) + (vm-reorder-message-headers nil vm-visible-headers + vm-invisible-header-regexp)) + (save-restriction + (narrow-to-region start (point)) + (vm-decode-mime-encoded-words)) + (vm-mime-display-internal-multipart/mixed layout)) (goto-char (vm-extent-start-position layout)) (setq layout (vm-extent-property layout 'vm-mime-layout)) (set-buffer (generate-new-buffer @@ -1618,8 +1585,6 @@ (vm-display (or vm-presentation-buffer (current-buffer)) t (list this-command) '(vm-mode startup))) t ) -(fset 'vm-mime-display-button-message/rfc822 - 'vm-mime-display-internal-message/rfc822) (fset 'vm-mime-display-internal-message/news 'vm-mime-display-internal-message/rfc822) @@ -1633,7 +1598,7 @@ (concat (vm-mime-layout-description layout) (and number (concat ", part " number)) (and number total (concat " of " total))) - (if (vm-mouse-support-possible-p) + (if (vm-mouse-support-possible-here-p) "Click mouse-2" "Press RETURN")) (function @@ -1758,28 +1723,45 @@ 'vm-mime-display-internal-message/partial) (defun vm-mime-display-internal-image-xxxx (layout feature name) - (if (and (vm-xemacs-p) + (if (and vm-xemacs-p (featurep feature) (eq (device-type) 'x)) (let ((start (point)) end tempfile g e (buffer-read-only nil)) - (if (vm-mm-layout-cache layout) - (setq g (vm-mm-layout-cache layout)) + (if (setq g (cdr (assq 'vm-mime-display-internal-image-xxxx + (vm-mm-layout-cache layout)))) + nil (vm-mime-insert-mime-body layout) (setq end (point-marker)) (vm-mime-transfer-decode-region layout start end) (setq tempfile (vm-make-tempfile-name)) - ;; coding system for presentation buffer is binary + ;; Write an empty tempfile out to disk and set its + ;; permissions to 0600, then write the actual buffer + ;; contents to tempfile. + (write-region start start tempfile nil 0) + (set-file-modes tempfile 384) + ;; coding system for presentation buffer is binary so + ;; we don't need to set it here. (write-region start end tempfile nil 0) (message "Creating %s glyph..." name) (setq g (make-glyph - (list (vector feature ':file tempfile) - (vector 'string - ':data - (format "[Unknown %s image encoding]\n" - name))))) + (list + (cons (list 'win) + (vector feature ':file tempfile)) + (cons (list 'win) + (vector 'string + ':data + (format "[Unknown/Bad %s image encoding]\n" + name))) + (cons nil + (vector 'string + ':data + (format "[%s image]\n" name)))))) (message "") - (vm-set-mm-layout-cache layout g) + (vm-set-mm-layout-cache + layout + (nconc (vm-mm-layout-cache layout) + (list (cons 'vm-mime-display-internal-image-xxxx g)))) (save-excursion (vm-select-folder-buffer) (setq vm-folder-garbage-alist @@ -1806,7 +1788,7 @@ (vm-mime-display-internal-image-xxxx layout 'tiff "TIFF")) (defun vm-mime-display-internal-audio/basic (layout) - (if (and (vm-xemacs-p) + (if (and vm-xemacs-p (or (featurep 'native-sound) (featurep 'nas-sound)) (or (device-sound-enabled-p) @@ -1815,15 +1797,26 @@ (eq (device-type) 'x)))) (let ((start (point)) end tempfile (buffer-read-only nil)) - (if (vm-mm-layout-cache layout) - (setq tempfile (vm-mm-layout-cache layout)) + (if (setq tempfile (cdr (assq 'vm-mime-display-internal-audio/basic + (vm-mm-layout-cache layout)))) + nil (vm-mime-insert-mime-body layout) (setq end (point-marker)) (vm-mime-transfer-decode-region layout start end) (setq tempfile (vm-make-tempfile-name)) - ;; coding system for presentation buffer is binary + ;; Write an empty tempfile out to disk and set its + ;; permissions to 0600, then write the actual buffer + ;; contents to tempfile. + (write-region start start tempfile nil 0) + (set-file-modes tempfile 384) + ;; coding system for presentation buffer is binary, so + ;; we don't need to set it here. (write-region start end tempfile nil 0) - (vm-set-mm-layout-cache layout tempfile) + (vm-set-mm-layout-cache + layout + (nconc (vm-mm-layout-cache layout) + (list (cons 'vm-mime-display-internal-audio/basic + tempfile)))) (save-excursion (vm-select-folder-buffer) (setq vm-folder-garbage-alist @@ -1839,9 +1832,11 @@ (defun vm-mime-display-button-xxxx (layout disposable) (let ((description (vm-mime-layout-description layout))) (vm-mime-insert-button - (format "%-35.35s [%s to display]" + (format "%-35.35s [%s to attempt display]" description - (if (vm-mouse-support-possible-p) "Click mouse-2" "Press RETURN")) + (if (vm-mouse-support-possible-here-p) + "Click mouse-2" + "Press RETURN")) (function (lambda (layout) (save-excursion @@ -1856,7 +1851,7 @@ ;; drag window point along, to a place arbitrarily far from ;; where it was when the user triggered the button. (save-excursion - (cond ((vm-fsfemacs-19-p) + (cond (vm-fsfemacs-19-p (let (o-list o (found nil)) (setq o-list (overlays-at (point))) (while (and o-list (not found)) @@ -1866,7 +1861,7 @@ 'vm-mime-function)) (car o-list)))) (setq o-list (cdr o-list))))) - ((vm-xemacs-p) + (vm-xemacs-p (let ((e (extent-at (point) nil 'vm-mime-layout))) (funcall (or function (extent-property e 'vm-mime-function)) e)))))) @@ -1874,42 +1869,40 @@ ;; for the karking compiler (defvar vm-menu-mime-dispose-menu) -(defun vm-mime-set-extent-glyph-for-layout (e layout) - (if (and (vm-xemacs-p) (fboundp 'make-glyph) - (eq (device-type) 'x) (> (device-bitplanes) 15)) - (let ((type (car (vm-mm-layout-type layout))) - (dir vm-image-directory) - glyph) - (setq glyph - (cond ((vm-mime-types-match "text" type) - (make-glyph (vector - 'xpm ':file - (expand-file-name "document.xpm" dir)))) - ((vm-mime-types-match "image" type) - (make-glyph (vector - 'gif ':file - (expand-file-name "mona_stamp.gif" dir)))) - ((vm-mime-types-match "audio" type) - (make-glyph (vector - 'xpm ':file - (expand-file-name "audio_stamp.xpm" dir)))) - ((vm-mime-types-match "video" type) - (make-glyph (vector - 'xpm ':file - (expand-file-name "film.xpm" dir)))) - ((vm-mime-types-match "message" type) - (make-glyph (vector - 'xpm ':file - (expand-file-name "message.xpm" dir)))) - ((vm-mime-types-match "application" type) - (make-glyph (vector - 'xpm ':file - (expand-file-name "gear.xpm" dir)))) - ((vm-mime-types-match "multipart" type) - (make-glyph (vector - 'xpm ':file - (expand-file-name "stuffed_box.xpm" dir)))) - (t nil))) +(defun vm-mime-set-extent-glyph-for-type (e type) + (if (and vm-xemacs-p + (featurep 'xpm) + (eq (device-type) 'x) + (> (device-bitplanes) 7)) + (let ((dir vm-image-directory) + (colorful (> (device-bitplanes) 15)) + (tuples + '(("text" "document-simple.xpm" "document-colorful.xpm") + ("image" "mona_stamp-simple.xpm" "mona_stamp-colorful.xpm") + ("audio" "audio_stamp-simple.xpm" "audio_stamp-colorful.xpm") + ("video" "film-simple.xpm" "film-colorful.xpm") + ("message" "message-simple.xpm" "message-colorful.xpm") + ("application" "gear-simple.xpm" "gear-colorful.xpm") + ("multipart" "stuffed_box-simple.xpm" + "stuffed_box-colorful.xpm"))) + glyph file sym p) + (setq file (catch 'done + (while tuples + (if (vm-mime-types-match (car (car tuples)) type) + (throw 'done (car tuples)) + (setq tuples (cdr tuples)))) + nil) + file (and file (if colorful (nth 2 file) (nth 1 file))) + sym (and file (intern file vm-image-obarray)) + glyph (and sym (boundp sym) (symbol-value sym)) + glyph (or glyph + (and file + (make-glyph + (list + (vector 'xpm ':file + (expand-file-name file dir)) + [nothing]))))) + (and sym (not (boundp sym)) (set sym glyph)) (and glyph (set-extent-begin-glyph e glyph))))) (defun vm-mime-insert-button (caption action layout disposable) @@ -1926,16 +1919,18 @@ (if (not (bolp)) (insert "\n")) (insert caption "\n") - ;; we MUST have the five arg make-overlay. overlays must - ;; advance when text is inserted at their start position or - ;; inline text and graphics will seep into the button - ;; overlay and then be removed when the button is removed. - (if (fboundp 'make-overlay) + ;; we must use the same interface that the vm-extent functions + ;; use. if they use overlays, then we call make-overlay. + (if (eq (symbol-function 'vm-make-extent) 'make-overlay) + ;; we MUST have the five arg make-overlay. overlays must + ;; advance when text is inserted at their start position or + ;; inline text and graphics will seep into the button + ;; overlay and then be removed when the button is removed. (setq e (make-overlay start (point) nil t nil)) (setq e (make-extent start (point))) (set-extent-property e 'start-open t) (set-extent-property e 'end-open t)) - (vm-mime-set-extent-glyph-for-layout e layout) + (vm-mime-set-extent-glyph-for-type e (car (vm-mm-layout-type layout))) ;; for emacs (vm-set-extent-property e 'mouse-face 'highlight) (vm-set-extent-property e 'local-map keymap) @@ -1953,7 +1948,7 @@ (let* ((buffer-read-only nil) (start (point))) (goto-char (vm-extent-start-position button)) - (insert (format "DISPLAY FAILED -- %s" error-string)) + (insert (format "DISPLAY FAILED -- %s\n" error-string)) (vm-set-extent-endpoints button start (vm-extent-end-position button)) (delete-region (point) (vm-extent-end-position button)))) @@ -2000,10 +1995,10 @@ (setq buffer-file-type (not (vm-mime-text-type-p layout))) ;; Tell XEmacs/MULE not to mess with the bits unless ;; this is a text type. - (if (vm-xemacs-mule-p) + (if vm-xemacs-mule-p (if (vm-mime-text-type-p layout) - (set-file-coding-system 'no-conversion nil) - (set-file-coding-system 'binary t))) + (set-buffer-file-coding-system 'no-conversion nil) + (set-buffer-file-coding-system 'binary t))) (vm-mime-insert-mime-body layout) (vm-mime-transfer-decode-region layout (point-min) (point-max)) (or (not (file-exists-p file)) @@ -2144,6 +2139,24 @@ (setq done t) (setq p (cdr p)))) result ))) + +;; breadth first traversal +(defun vm-mime-find-digests-in-layout (layout) + (let ((layout-list (list layout)) + layout-type + (result nil)) + (while layout-list + (setq layout-type (car (vm-mm-layout-type (car layout-list)))) + (cond ((string-match "^multipart/digest\\|message/\\(rfc822\\|news\\)" + layout-type) + (setq result (nconc result (list (car layout-list))))) + ((vm-mime-composite-type-p layout-type) + (setq layout-list (nconc layout-list + (copy-sequence + (vm-mm-layout-parts + (car layout-list))))))) + (setq layout-list (cdr layout-list))) + result )) (defun vm-mime-plain-message-p (m) (save-match-data @@ -2164,7 +2177,7 @@ (vm-mime-types-match "message" (car (vm-mm-layout-type layout))))) (defun vm-mime-charset-internally-displayable-p (name) - (cond ((and (vm-xemacs-mule-p) (eq (device-type) 'x)) + (cond ((and vm-xemacs-mule-p (eq (device-type) 'x)) (vm-string-assoc name vm-mime-mule-charset-to-coding-alist)) ((vm-multiple-fonts-possible-p) (or (vm-string-member name vm-mime-default-face-charsets) @@ -2199,7 +2212,7 @@ (car mp))) (defun vm-mime-make-multipart-boundary () - (let ((boundary (make-string 40 ?a)) + (let ((boundary (make-string 10 ?a)) (i 0)) (random t) (while (< i (length boundary)) @@ -2330,7 +2343,7 @@ (file-name-nondirectory object) "\""))))) (setq disposition (list "unspecified"))) - (cond ((vm-fsfemacs-19-p) + (cond (vm-fsfemacs-19-p (put-text-property start end 'front-sticky nil) (put-text-property start end 'rear-nonsticky t) ;; can't be intangible because menu clicking at a position needs @@ -2345,38 +2358,39 @@ (put-text-property start end 'vm-mime-disposition disposition) (put-text-property start end 'vm-mime-encoded mimed) (put-text-property start end 'vm-mime-object object)) - ((fboundp 'make-extent) + (vm-xemacs-p (setq e (make-extent start end)) + (vm-mime-set-extent-glyph-for-type e (or type "text/plain")) (set-extent-property e 'start-open t) (set-extent-property e 'face vm-mime-button-face) - (vm-set-extent-property e 'duplicable t) + (set-extent-property e 'duplicable t) (let ((keymap (make-sparse-keymap))) (if vm-popup-menu-on-mouse-3 (define-key keymap 'button3 'vm-menu-popup-content-disposition-menu)) - (vm-set-extent-property e 'keymap keymap) + (set-extent-property e 'keymap keymap) (set-extent-property e 'balloon-help 'vm-mouse-3-help)) - (vm-set-extent-property e 'vm-mime-type type) - (vm-set-extent-property e 'vm-mime-object object) - (vm-set-extent-property e 'vm-mime-parameters params) - (vm-set-extent-property e 'vm-mime-description description) - (vm-set-extent-property e 'vm-mime-disposition disposition) - (vm-set-extent-property e 'vm-mime-encoded mimed))))) + (set-extent-property e 'vm-mime-type type) + (set-extent-property e 'vm-mime-object object) + (set-extent-property e 'vm-mime-parameters params) + (set-extent-property e 'vm-mime-description description) + (set-extent-property e 'vm-mime-disposition disposition) + (set-extent-property e 'vm-mime-encoded mimed))))) (defun vm-mime-attachment-disposition-at-point () - (cond ((vm-fsfemacs-19-p) + (cond (vm-fsfemacs-19-p (let ((disp (get-text-property (point) 'vm-mime-disposition))) (intern (car disp)))) - ((vm-xemacs-p) + (vm-xemacs-p (let* ((e (extent-at (point) nil 'vm-mime-disposition)) (disp (extent-property e 'vm-mime-disposition))) (intern (car disp)))))) (defun vm-mime-set-attachment-disposition-at-point (sym) - (cond ((vm-fsfemacs-19-p) + (cond (vm-fsfemacs-19-p (let ((disp (get-text-property (point) 'vm-mime-disposition))) (setcar disp (symbol-name sym)))) - ((vm-xemacs-p) + (vm-xemacs-p (let* ((e (extent-at (point) nil 'vm-mime-disposition)) (disp (extent-property e 'vm-mime-disposition))) (setcar disp (symbol-name sym)))))) @@ -2447,11 +2461,16 @@ (let ((case-fold-search nil)) (save-excursion (goto-char beg) - (re-search-forward "^From " nil t)))))) + (re-search-forward "^From " nil t))))) + (armor-dot (let ((case-fold-search nil)) + (save-excursion + (goto-char beg) + (re-search-forward "^\\.\\n" nil t))))) (cond ((string-match "^binary$" encoding) (vm-mime-base64-encode-region beg end crlf) (setq encoding "base64")) - ((and (not armor-from) (string-match "^7bit$" encoding)) t) + ((and (not armor-from) (not armor-dot) + (string-match "^7bit$" encoding)) t) ((string-match "^base64$" encoding) t) ((string-match "^quoted-printable$" encoding) t) ((eq vm-mime-8bit-text-transfer-encoding 'quoted-printable) @@ -2465,21 +2484,72 @@ encoding )) (defun vm-mime-transfer-encode-layout (layout) - (if (vm-mime-text-type-p layout) - (vm-mime-transfer-encode-region (vm-mm-layout-encoding layout) - (vm-mm-layout-body-start layout) - (vm-mm-layout-body-end layout) - t) - (vm-mime-transfer-encode-region (vm-mm-layout-encoding layout) - (vm-mm-layout-body-start layout) - (vm-mm-layout-body-end layout) - nil))) + (let ((list (vm-mm-layout-parts layout)) + (type (car (vm-mm-layout-type layout))) + (encoding "7bit") + (vm-mime-8bit-text-transfer-encoding + vm-mime-8bit-text-transfer-encoding)) + (cond ((vm-mime-composite-type-p type) + ;; MIME messages of type "message" and + ;; "multipart" are required to have a non-opaque + ;; content transfer encoding. This means that + ;; if the user only wants to send out 7bit data, + ;; then any subpart that contains 8bit data must + ;; have an opaque (qp or base64) 8->7bit + ;; conversion performed on it so that the + ;; enclosing entity can use a non-opaque + ;; encoding. + ;; + ;; message/partial requires a "7bit" encoding so + ;; force 8->7 conversion in that case. + (cond ((memq vm-mime-8bit-text-transfer-encoding + '(quoted-printable base64)) + t) + ((vm-mime-types-match "message/partial" type) + (setq vm-mime-8bit-text-transfer-encoding + 'quoted-printable))) + (while list + (if (equal (vm-mime-transfer-encode-layout (car list)) "8bit") + (setq encoding "8bit")) + (setq list (cdr list)))) + (t + (if (and (vm-mime-types-match "message/partial" type) + (not (memq vm-mime-8bit-text-transfer-encoding + '(quoted-printable base64)))) + (setq vm-mime-8bit-text-transfer-encoding + 'quoted-printable)) + (setq encoding + (vm-mime-transfer-encode-region (vm-mm-layout-encoding layout) + (vm-mm-layout-body-start layout) + (vm-mm-layout-body-end layout) + (vm-mime-text-type-p layout))))) + (save-excursion + (save-restriction + (goto-char (vm-mm-layout-header-start layout)) + (narrow-to-region (point) (vm-mm-layout-body-start layout)) + (vm-reorder-message-headers nil nil "Content-Transfer-Encoding:") + (if (not (equal encoding "7bit")) + (insert "CONTENT-TRANSFER-ENCODING: " encoding "\n")) + encoding )))) (defun vm-mime-encode-composition () - "MIME encode the current buffer. + "MIME encode the current mail composition buffer. Attachment tags added to the buffer with vm-mime-attach-file are expanded and the approriate content-type and boundary markup information is added." (interactive) + (cond (vm-xemacs-mule-p + (vm-mime-xemacs-encode-composition)) + (vm-xemacs-p + (vm-mime-xemacs-encode-composition)) + (vm-fsfemacs-19-p + (vm-mime-fsfemacs-encode-composition)) + (t + (error "don't know how to MIME encode composition for %s" + (emacs-version))))) + +(defvar enriched-mode) + +(defun vm-mime-xemacs-encode-composition () (save-restriction (widen) (if (not (eq major-mode 'mail-mode)) @@ -2489,21 +2559,20 @@ (let ((8bit nil) (just-one nil) (boundary-positions nil) + (enriched (and (boundp 'enriched-mode) enriched-mode)) already-mimed layout e e-list boundary type encoding charset params description disposition object opoint-min) (mail-text) - (setq e-list (if (fboundp 'extent-list) - (extent-list nil (point) (point-max)) - (vm-mime-fake-attachment-overlays (point) (point-max))) + (setq e-list (extent-list nil (point) (point-max)) e-list (vm-delete (function (lambda (e) - (vm-extent-property e 'vm-mime-object))) + (extent-property e 'vm-mime-object))) e-list t) e-list (sort e-list (function (lambda (e1 e2) - (< (vm-extent-end-position e1) - (vm-extent-end-position e2)))))) + (< (extent-end-position e1) + (extent-end-position e2)))))) ;; If there's just one attachment and no other readable ;; text in the buffer then make the message type just be ;; the attachment type rather than sending a multipart @@ -2511,18 +2580,22 @@ (setq just-one (and (= (length e-list) 1) (looking-at "[ \t\n]*") (= (match-end 0) - (vm-extent-start-position (car e-list))) + (extent-start-position (car e-list))) (save-excursion - (goto-char (vm-extent-end-position (car e-list))) + (goto-char (extent-end-position (car e-list))) (looking-at "[ \t\n]*\\'")))) (if (null e-list) (progn (narrow-to-region (point) (point-max)) + ;; support enriched-mode for text/enriched composition + (if enriched + (let ((enriched-initial-annotation "")) + (enriched-encode (point-min) (point-max)))) (setq charset (vm-determine-proper-charset (point-min) (point-max))) - (if (vm-xemacs-mule-p) + (if vm-xemacs-mule-p (encode-coding-region (point-min) (point-max) - file-coding-system)) + buffer-file-coding-system)) (setq encoding (vm-determine-proper-content-transfer-encoding (point-min) (point-max)) @@ -2536,16 +2609,24 @@ (vm-reorder-message-headers nil nil "\\(Content-Type:\\|Content-Transfer-Encoding\\|MIME-Version:\\)") (insert "MIME-Version: 1.0\n") - (insert "Content-Type: text/plain; charset=" charset "\n") + (if enriched + (insert "Content-Type: text/enriched; charset=" charset "\n") + (insert "Content-Type: text/plain; charset=" charset "\n")) (insert "Content-Transfer-Encoding: " encoding "\n") (vm-add-mail-mode-header-separator)) (while e-list (setq e (car e-list)) - (if (or just-one (= (point) (vm-extent-start-position e))) + (if (or just-one (= (point) (extent-start-position e))) nil - (narrow-to-region (point) (vm-extent-start-position e)) + (narrow-to-region (point) (extent-start-position e)) + (if enriched + (let ((enriched-initial-annotation "")) + (enriched-encode (point-min) (point-max)))) (setq charset (vm-determine-proper-charset (point-min) (point-max))) + (if vm-xemacs-mule-p + (encode-coding-region (point-min) (point-max) + buffer-file-coding-system)) (setq encoding (vm-determine-proper-content-transfer-encoding (point-min) (point-max)) @@ -2554,61 +2635,49 @@ (point-max) t)) (setq boundary-positions (cons (point-marker) boundary-positions)) - (insert "Content-Type: text/plain; charset=" charset "\n") + (if enriched + (insert "Content-Type: text/enriched; charset=" charset "\n") + (insert "Content-Type: text/plain; charset=" charset "\n")) (insert "Content-Transfer-Encoding: " encoding "\n\n") (widen)) - (goto-char (vm-extent-start-position e)) + (goto-char (extent-start-position e)) (narrow-to-region (point) (point)) - (setq object (vm-extent-property e 'vm-mime-object)) + (setq object (extent-property e 'vm-mime-object)) ;; insert the object (cond ((bufferp object) - (if (vm-xemacs-p) - (insert-buffer-substring object) - ;; as of FSF Emacs 19.34, even with the hooks - ;; we've attached to the attachment overlays, - ;; text STILL can be inserted into them when - ;; font-lock is enabled. Explaining why is - ;; beyond the scope of this comment and I - ;; don't know the answer anyway. This works - ;; to prevent it. - (insert-before-markers " ") - (forward-char -1) - (insert-buffer-substring object) - (delete-char 1))) + (insert-buffer-substring object)) ((stringp object) - (let ((overridding-file-coding-system 'no-conversion)) - (if (vm-xemacs-p) - (insert-file-contents-literally object) - (insert-before-markers " ") - (forward-char -1) - (insert-file-contents-literally object) - (goto-char (point-max)) - (delete-char -1))))) + (let ((coding-system-for-read 'no-conversion) + ;; don't let buffer-file-coding-system be changed + ;; by insert-file-contents-literally. The + ;; value we bind to it to here isn't important. + (buffer-file-coding-system 'no-conversion)) + (insert-file-contents-literally object)))) ;; gather information about the object from the extent. - (if (setq already-mimed (vm-extent-property e 'vm-mime-encoded)) + (if (setq already-mimed (extent-property e 'vm-mime-encoded)) (setq layout (vm-mime-parse-entity nil (list "text/plain" "charset=us-ascii") "7bit") - type (or (vm-extent-property e 'vm-mime-type) + type (or (extent-property e 'vm-mime-type) (car (vm-mm-layout-type layout))) - params (or (vm-extent-property e 'vm-mime-parameters) + params (or (extent-property e 'vm-mime-parameters) (cdr (vm-mm-layout-qtype layout))) - description (vm-extent-property e 'vm-mime-description) + description (extent-property e 'vm-mime-description) disposition (if (not (equal - (car (vm-extent-property e 'vm-mime-disposition)) + (car (extent-property e 'vm-mime-disposition)) "unspecified")) - (vm-extent-property e 'vm-mime-disposition) + (extent-property e 'vm-mime-disposition) (vm-mm-layout-qdisposition layout))) - (setq type (vm-extent-property e 'vm-mime-type) - params (vm-extent-property e 'vm-mime-parameters) - description (vm-extent-property e 'vm-mime-description) + (setq type (extent-property e 'vm-mime-type) + params (extent-property e 'vm-mime-parameters) + description (extent-property e 'vm-mime-description) disposition (if (not (equal - (car (vm-extent-property e 'vm-mime-disposition)) + (car (extent-property e 'vm-mime-disposition)) "unspecified")) - (vm-extent-property e 'vm-mime-disposition) + (extent-property e 'vm-mime-disposition) nil))) (cond ((vm-mime-types-match "text" type) (setq encoding @@ -2625,41 +2694,13 @@ (point-max) t)) (setq 8bit (or 8bit (equal encoding "8bit")))) - ((or (vm-mime-types-match "message/rfc822" type) - (vm-mime-types-match "message/news" type) - (vm-mime-types-match "multipart" type)) + ((vm-mime-composite-type-p type) (setq opoint-min (point-min)) (if (not already-mimed) (setq layout (vm-mime-parse-entity nil (list "text/plain" "charset=us-ascii") "7bit"))) - ;; MIME messages of type "message" and - ;; "multipart" are required to have a non-opaque - ;; content transfer encoding. This means that - ;; if the user only wants to send out 7bit data, - ;; then any subpart that contains 8bit data must - ;; have an opaque (qp or base64) 8->7bit - ;; conversion performed on it so that the - ;; enclosing entity can use an non-opqaue - ;; encoding. - ;; - ;; message/partial requires a "7bit" encoding so - ;; force 8->7 conversion in that case. - (let ((vm-mime-8bit-text-transfer-encoding - (if (vm-mime-types-match "message/partial" type) - 'quoted-printable - vm-mime-8bit-text-transfer-encoding))) - (vm-mime-map-atomic-layouts 'vm-mime-transfer-encode-layout - (vm-mm-layout-parts layout))) - ;; now figure out a proper content trasnfer - ;; encoding value for the enclosing entity. - (re-search-forward "^\n" nil t) - (save-restriction - (narrow-to-region (point) (point-max)) - (setq encoding - (vm-determine-proper-content-transfer-encoding - (point-min) - (point-max)))) + (setq encoding (vm-mime-transfer-encode-layout layout)) (setq 8bit (or 8bit (equal encoding "8bit"))) (goto-char (point-max)) (widen) @@ -2708,11 +2749,11 @@ (goto-char (point-max)) (widen) (save-excursion - (goto-char (vm-extent-start-position e)) + (goto-char (extent-start-position e)) (vm-assert (looking-at "\\[ATTACHMENT"))) - (delete-region (vm-extent-start-position e) - (vm-extent-end-position e)) - (vm-detach-extent e) + (delete-region (extent-start-position e) + (extent-end-position e)) + (detach-extent e) (if (looking-at "\n") (delete-char 1)) (setq e-list (cdr e-list))) @@ -2720,11 +2761,14 @@ ;; extent, if any. (if (or just-one (= (point) (point-max))) nil + (if enriched + (let ((enriched-initial-annotation "")) + (enriched-encode (point) (point-max)))) (setq charset (vm-determine-proper-charset (point) (point-max))) - (if (vm-xemacs-mule-p) - (encode-coding-region (point-min) (point-max) - file-coding-system)) + (if vm-xemacs-mule-p + (encode-coding-region (point) (point-max) + buffer-file-coding-system)) (setq encoding (vm-determine-proper-content-transfer-encoding (point) (point-max)) @@ -2734,7 +2778,9 @@ t)) (setq 8bit (or 8bit (equal encoding "8bit"))) (setq boundary-positions (cons (point-marker) boundary-positions)) - (insert "Content-Type: text/plain; charset=" charset "\n") + (if enriched + (insert "Content-Type: text/enriched; charset=" charset "\n") + (insert "Content-Type: text/plain; charset=" charset "\n")) (insert "Content-Transfer-Encoding: " encoding "\n\n") (goto-char (point-max))) (setq boundary (vm-mime-make-multipart-boundary)) @@ -2782,8 +2828,8 @@ (if params (if vm-mime-avoid-folding-content-type (insert "; " (mapconcat 'identity params "; ") "\n") - (insert ";\n\t" (mapconcat 'identity params ";\n\t")))) - (insert "\n")) + (insert ";\n\t" (mapconcat 'identity params ";\n\t") "\n")) + (insert "\n"))) (if just-one (and description (insert "Content-Description: " description "\n"))) @@ -2791,10 +2837,325 @@ (progn (insert "Content-Disposition: " (car disposition)) (if (cdr disposition) - (insert ";\n\t" (mapconcat 'identity - (cdr disposition) - ";\n\t"))) - (insert "\n"))) + (if vm-mime-avoid-folding-content-type + (insert "; " (mapconcat 'identity (cdr disposition) "; ") + "\n") + (insert ";\n\t" (mapconcat 'identity (cdr disposition) + ";\n\t"))) + (insert "\n")))) + (if just-one + (insert "Content-Transfer-Encoding: " encoding "\n") + (if 8bit + (insert "Content-Transfer-Encoding: 8bit\n") + (insert "Content-Transfer-Encoding: 7bit\n"))))))) + +(defun vm-mime-fsfemacs-encode-composition () + (save-restriction + (widen) + (if (not (eq major-mode 'mail-mode)) + (error "Command must be used in a VM Mail mode buffer.")) + (or (null (vm-mail-mode-get-header-contents "MIME-Version:")) + (error "Message is already MIME encoded.")) + (let ((8bit nil) + (just-one nil) + (boundary-positions nil) + (enriched (and (boundp 'enriched-mode) enriched-mode)) + already-mimed layout o o-list boundary + type encoding charset params description disposition object + opoint-min) + (mail-text) + (setq o-list (vm-mime-fake-attachment-overlays (point) (point-max)) + o-list (vm-delete (function + (lambda (o) + (overlay-get o 'vm-mime-object))) + o-list t) + o-list (sort o-list (function + (lambda (e1 e2) + (< (overlay-end e1) + (overlay-end e2)))))) + ;; If there's just one attachment and no other readable + ;; text in the buffer then make the message type just be + ;; the attachment type rather than sending a multipart + ;; message with one attachment + (setq just-one (and (= (length o-list) 1) + (looking-at "[ \t\n]*") + (= (match-end 0) + (overlay-start (car o-list))) + (save-excursion + (goto-char (overlay-end (car o-list))) + (looking-at "[ \t\n]*\\'")))) + (if (null o-list) + (progn + (narrow-to-region (point) (point-max)) + ;; support enriched-mode for text/enriched composition + (if enriched + (let ((enriched-initial-annotation "")) + (enriched-encode (point-min) (point-max)))) + (setq charset (vm-determine-proper-charset (point-min) + (point-max))) + (setq encoding (vm-determine-proper-content-transfer-encoding + (point-min) + (point-max)) + encoding (vm-mime-transfer-encode-region encoding + (point-min) + (point-max) + t)) + (widen) + (vm-remove-mail-mode-header-separator) + (goto-char (point-min)) + (vm-reorder-message-headers + nil nil "\\(Content-Type:\\|Content-Transfer-Encoding\\|MIME-Version:\\)") + (insert "MIME-Version: 1.0\n") + (if enriched + (insert "Content-Type: text/enriched; charset=" charset "\n") + (insert "Content-Type: text/plain; charset=" charset "\n")) + (insert "Content-Transfer-Encoding: " encoding "\n") + (vm-add-mail-mode-header-separator)) + (while o-list + (setq o (car o-list)) + (if (or just-one (= (point) (overlay-start o))) + nil + (narrow-to-region (point) (overlay-start o)) + ;; support enriched-mode for text/enriched composition + (if enriched + (let ((enriched-initial-annotation "")) + (save-excursion + ;; insert/delete trick needed to avoid + ;; enriched-mode tags from seeping into the + ;; attachment overlays. I really wish + ;; front-advance / rear-advance overlay + ;; endpoint properties actually worked. + (goto-char (point-max)) + (insert-before-markers "\n") + (enriched-encode (point-min) (1- (point))) + (goto-char (point-max)) + (delete-char -1) + '(goto-char (point-min))))) + (setq charset (vm-determine-proper-charset (point-min) + (point-max))) + (setq encoding (vm-determine-proper-content-transfer-encoding + (point-min) + (point-max)) + encoding (vm-mime-transfer-encode-region encoding + (point-min) + (point-max) + t)) + (setq boundary-positions (cons (point-marker) boundary-positions)) + (if enriched + (insert "Content-Type: text/enriched; charset=" charset "\n") + (insert "Content-Type: text/plain; charset=" charset "\n")) + (insert "Content-Transfer-Encoding: " encoding "\n\n") + (widen)) + (goto-char (overlay-start o)) + (narrow-to-region (point) (point)) + (setq object (overlay-get o 'vm-mime-object)) + ;; insert the object + (cond ((bufferp object) + ;; as of FSF Emacs 19.34, even with the hooks + ;; we've attached to the attachment overlays, + ;; text STILL can be inserted into them when + ;; font-lock is enabled. Explaining why is + ;; beyond the scope of this comment and I + ;; don't know the answer anyway. This works + ;; to prevent it. + (insert-before-markers " ") + (forward-char -1) + (insert-buffer-substring object) + (delete-char 1)) + ((stringp object) + (insert-before-markers " ") + (forward-char -1) + (insert-file-contents object) + (goto-char (point-max)) + (delete-char -1))) + ;; gather information about the object from the extent. + (if (setq already-mimed (overlay-get o 'vm-mime-encoded)) + (setq layout (vm-mime-parse-entity + nil (list "text/plain" "charset=us-ascii") + "7bit") + type (or (overlay-get o 'vm-mime-type) + (car (vm-mm-layout-type layout))) + params (or (overlay-get o 'vm-mime-parameters) + (cdr (vm-mm-layout-qtype layout))) + description (overlay-get o 'vm-mime-description) + disposition + (if (not + (equal + (car (overlay-get o 'vm-mime-disposition)) + "unspecified")) + (overlay-get o 'vm-mime-disposition) + (vm-mm-layout-qdisposition layout))) + (setq type (overlay-get o 'vm-mime-type) + params (overlay-get o 'vm-mime-parameters) + description (overlay-get o 'vm-mime-description) + disposition + (if (not (equal + (car (overlay-get o 'vm-mime-disposition)) + "unspecified")) + (overlay-get o 'vm-mime-disposition) + nil))) + (cond ((vm-mime-types-match "text" type) + (setq encoding + (vm-determine-proper-content-transfer-encoding + (if already-mimed + (vm-mm-layout-body-start layout) + (point-min)) + (point-max)) + encoding (vm-mime-transfer-encode-region + encoding + (if already-mimed + (vm-mm-layout-body-start layout) + (point-min)) + (point-max) + t)) + (setq 8bit (or 8bit (equal encoding "8bit")))) + ((vm-mime-composite-type-p type) + (setq opoint-min (point-min)) + (if (not already-mimed) + (setq layout (vm-mime-parse-entity + nil (list "text/plain" "charset=us-ascii") + "7bit"))) + (setq encoding (vm-mime-transfer-encode-layout layout)) + (setq 8bit (or 8bit (equal encoding "8bit"))) + (goto-char (point-max)) + (widen) + (narrow-to-region opoint-min (point))) + (t + (vm-mime-base64-encode-region + (if already-mimed + (vm-mm-layout-body-start layout) + (point-min)) + (point-max)) + (setq encoding "base64"))) + (if just-one + nil + (goto-char (point-min)) + (setq boundary-positions (cons (point-marker) boundary-positions)) + (if (not already-mimed) + nil + ;; trim headers + (vm-reorder-message-headers + nil (nconc (list "Content-Disposition:" "Content-ID:") + (if description + (list "Content-Description:") + nil)) + nil) + ;; remove header/text separator + (goto-char (1- (vm-mm-layout-body-start layout))) + (if (looking-at "\n") + (delete-char 1))) + (insert "Content-Type: " type) + (if params + (if vm-mime-avoid-folding-content-type + (insert "; " (mapconcat 'identity params "; ") "\n") + (insert ";\n\t" (mapconcat 'identity params ";\n\t") "\n")) + (insert "\n")) + (and description + (insert "Content-Description: " description "\n")) + (if disposition + (progn + (insert "Content-Disposition: " (car disposition)) + (if (cdr disposition) + (insert ";\n\t" (mapconcat 'identity + (cdr disposition) + ";\n\t"))) + (insert "\n"))) + (insert "Content-Transfer-Encoding: " encoding "\n\n")) + (goto-char (point-max)) + (widen) + (save-excursion + (goto-char (overlay-start o)) + (vm-assert (looking-at "\\[ATTACHMENT"))) + (delete-region (overlay-start o) + (overlay-end o)) + (delete-overlay o) + (if (looking-at "\n") + (delete-char 1)) + (setq o-list (cdr o-list))) + ;; handle the remaining chunk of text after the last + ;; extent, if any. + (if (or just-one (= (point) (point-max))) + nil + ;; support enriched-mode for text/enriched composition + (if enriched + (let ((enriched-initial-annotation "")) + (enriched-encode (point) (point-max)))) + (setq charset (vm-determine-proper-charset (point) + (point-max))) + (setq encoding (vm-determine-proper-content-transfer-encoding + (point) + (point-max)) + encoding (vm-mime-transfer-encode-region encoding + (point) + (point-max) + t)) + (setq 8bit (or 8bit (equal encoding "8bit"))) + (setq boundary-positions (cons (point-marker) boundary-positions)) + (if enriched + (insert "Content-Type: text/enriched; charset=" charset "\n") + (insert "Content-Type: text/plain; charset=" charset "\n")) + (insert "Content-Transfer-Encoding: " encoding "\n\n") + (goto-char (point-max))) + (setq boundary (vm-mime-make-multipart-boundary)) + (mail-text) + (while (re-search-forward (concat "^--" + (regexp-quote boundary) + "\\(--\\)?$") + nil t) + (setq boundary (vm-mime-make-multipart-boundary)) + (mail-text)) + (goto-char (point-max)) + (or just-one (insert "\n--" boundary "--\n")) + (while boundary-positions + (goto-char (car boundary-positions)) + (insert "\n--" boundary "\n") + (setq boundary-positions (cdr boundary-positions))) + (if (and just-one already-mimed) + (progn + (goto-char (vm-mm-layout-header-start layout)) + ;; trim headers + (vm-reorder-message-headers + nil '("Content-Description:" "Content-ID:") nil) + ;; remove header/text separator + (goto-char (1- (vm-mm-layout-body-start layout))) + (if (looking-at "\n") + (delete-char 1)) + ;; copy remainder to enclosing entity's header section + (insert-buffer-substring (current-buffer) + (vm-mm-layout-header-start layout) + (vm-mm-layout-body-start layout)) + (delete-region (vm-mm-layout-header-start layout) + (vm-mm-layout-body-start layout)))) + (goto-char (point-min)) + (vm-remove-mail-mode-header-separator) + (vm-reorder-message-headers + nil nil "\\(Content-Type:\\|MIME-Version:\\|Content-Transfer-Encoding\\)") + (vm-add-mail-mode-header-separator) + (insert "MIME-Version: 1.0\n") + (if (not just-one) + (insert (if vm-mime-avoid-folding-content-type + "Content-Type: multipart/mixed; boundary=\"" + "Content-Type: multipart/mixed;\n\tboundary=\"") + boundary "\"\n") + (insert "Content-Type: " type) + (if params + (if vm-mime-avoid-folding-content-type + (insert "; " (mapconcat 'identity params "; ") "\n") + (insert ";\n\t" (mapconcat 'identity params ";\n\t") "\n")) + (insert "\n"))) + (if just-one + (and description + (insert "Content-Description: " description "\n"))) + (if (and just-one disposition) + (progn + (insert "Content-Disposition: " (car disposition)) + (if (cdr disposition) + (if vm-mime-avoid-folding-content-type + (insert "; " (mapconcat 'identity (cdr disposition) "; ") + "\n") + (insert ";\n\t" (mapconcat 'identity (cdr disposition) + ";\n\t"))) + (insert "\n")))) (if just-one (insert "Content-Transfer-Encoding: " encoding "\n") (if 8bit @@ -2812,16 +3173,15 @@ b header-start header-end master-buffer start end) (vm-remove-mail-mode-header-separator) ;; message/partial must have "7bit" content transfer - ;; encoding, so verify that everything has been encoded for + ;; encoding, so force everything to be encoded for ;; 7bit transmission. (let ((vm-mime-8bit-text-transfer-encoding - (if (eq vm-mime-8bit-text-transfer-encoding 'send) + (if (eq vm-mime-8bit-text-transfer-encoding '8bit) 'quoted-printable vm-mime-8bit-text-transfer-encoding))) - (vm-mime-map-atomic-layouts - 'vm-mime-transfer-encode-layout - (list (vm-mime-parse-entity nil (list "text/plain" "charset=us-ascii") - "7bit")))) + (vm-mime-transfer-encode-layout + (vm-mime-parse-entity nil (list "text/plain" "charset=us-ascii") + "7bit"))) (goto-char (point-min)) (setq header-start (point)) (search-forward "\n\n") @@ -2864,6 +3224,7 @@ (vm-increment n) (set-buffer master-buffer) (setq start (point))) + (vm-add-mail-mode-header-separator) (message "Fragmenting message... done") (nreverse buffers)))) @@ -2878,13 +3239,15 @@ (error "Command must be used in a VM Mail mode buffer.")) (let ((temp-buffer nil) (mail-buffer (current-buffer)) + (enriched (and (boundp 'enriched-mode) enriched-mode)) e-list) (unwind-protect (progn (setq temp-buffer (generate-new-buffer "composition preview")) (set-buffer temp-buffer) - ;; so vm-mime-encode-composition won't complain + ;; so vm-mime-xxxx-encode-composition won't complain (setq major-mode 'mail-mode) + (set (make-local-variable 'enriched-mode) enriched) (vm-insert-region-from-buffer mail-buffer) (goto-char (point-min)) (or (vm-mail-mode-get-header-contents "From") @@ -2899,6 +3262,7 @@ (and vm-send-using-mime (null (vm-mail-mode-get-header-contents "MIME-Version:")) (vm-mime-encode-composition)) + (vm-remove-mail-mode-header-separator) (goto-char (point-min)) (insert (vm-leading-message-separator 'From_)) (goto-char (point-max)) @@ -2921,12 +3285,16 @@ (and temp-buffer (kill-buffer temp-buffer))))) (defun vm-mime-composite-type-p (type) - (or (vm-mime-types-match "message" type) + (or (and (vm-mime-types-match "message" type) + (not (vm-mime-types-match "message/partial" type)) + (not (vm-mime-types-match "message/external-body" type))) (vm-mime-types-match "multipart" type))) -(defun vm-mime-map-atomic-layouts (function list) - (while list - (if (vm-mime-composite-type-p (car (vm-mm-layout-type (car list)))) - (vm-mime-map-atomic-layouts function (vm-mm-layout-parts (car list))) - (funcall function (car list))) - (setq list (cdr list)))) +;; Unused currrently. +;; +;;(defun vm-mime-map-atomic-layouts (function list) +;; (while list +;; (if (vm-mime-composite-type-p (car (vm-mm-layout-type (car list)))) +;; (vm-mime-map-atomic-layouts function (vm-mm-layout-parts (car list))) +;; (funcall function (car list))) +;; (setq list (cdr list))))