Merge changes made in Gnus trunk.
[bpt/emacs.git] / lisp / gnus / mm-view.el
CommitLineData
715a2ca2 1;;; mm-view.el --- functions for viewing MIME objects
e84b4b86 2
8abf1b22 3;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
114f9c96 4;; 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
c113de23
GM
5
6;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
7;; This file is part of GNU Emacs.
8
5e809f55 9;; GNU Emacs is free software: you can redistribute it and/or modify
c113de23 10;; it under the terms of the GNU General Public License as published by
5e809f55
GM
11;; the Free Software Foundation, either version 3 of the License, or
12;; (at your option) any later version.
c113de23
GM
13
14;; GNU Emacs is distributed in the hope that it will be useful,
15;; but WITHOUT ANY WARRANTY; without even the implied warranty of
5e809f55 16;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
c113de23
GM
17;; GNU General Public License for more details.
18
19;; You should have received a copy of the GNU General Public License
5e809f55 20;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
c113de23
GM
21
22;;; Commentary:
23
24;;; Code:
49ad38a1
GM
25(eval-and-compile
26 (unless (fboundp 'declare-function) (defmacro declare-function (&rest r))))
c113de23
GM
27(eval-when-compile (require 'cl))
28(require 'mail-parse)
29(require 'mailcap)
30(require 'mm-bodies)
31(require 'mm-decode)
01c52d31 32(require 'smime)
c113de23 33
229b59da 34(autoload 'gnus-completing-read "gnus-util")
a41c2e6d 35(autoload 'gnus-window-inside-pixel-edges "gnus-ems")
8abf1b22
GM
36(autoload 'gnus-article-prepare-display "gnus-art")
37(autoload 'vcard-parse-string "vcard")
38(autoload 'vcard-format-string "vcard")
39(autoload 'fill-flowed "flow-fill")
40(autoload 'html2text "html2text" nil t)
c113de23 41
dd3eac76
JB
42(defvar gnus-article-mime-handles)
43(defvar gnus-newsgroup-charset)
44(defvar smime-keys)
45(defvar w3m-cid-retrieve-function-alist)
46(defvar w3m-current-buffer)
47(defvar w3m-display-inline-images)
48(defvar w3m-minor-mode-map)
49
23f87bed
MB
50(defvar mm-text-html-renderer-alist
51 '((w3 . mm-inline-text-html-render-with-w3)
52 (w3m . mm-inline-text-html-render-with-w3m)
73043f7d 53 (w3m-standalone . mm-inline-text-html-render-with-w3m-standalone)
23f87bed
MB
54 (links mm-inline-render-with-file
55 mm-links-remove-leading-blank
56 "links" "-dump" file)
57 (lynx mm-inline-render-with-stdin nil
58 "lynx" "-dump" "-force_html" "-stdin" "-nolist")
59 (html2text mm-inline-render-with-function html2text))
60 "The attributes of renderer types for text/html.")
61
62(defvar mm-text-html-washer-alist
63 '((w3 . gnus-article-wash-html-with-w3)
64 (w3m . gnus-article-wash-html-with-w3m)
73043f7d 65 (w3m-standalone . gnus-article-wash-html-with-w3m-standalone)
23f87bed
MB
66 (links mm-inline-wash-with-file
67 mm-links-remove-leading-blank
68 "links" "-dump" file)
69 (lynx mm-inline-wash-with-stdin nil
70 "lynx" "-dump" "-force_html" "-stdin" "-nolist")
71 (html2text html2text))
72 "The attributes of washer types for text/html.")
73
5f4264e5 74(defcustom mm-fill-flowed t
01c52d31 75 "If non-nil a format=flowed article will be displayed flowed."
5f4264e5
MB
76 :type 'boolean
77 :version "22.1"
78 :group 'mime-display)
79
a41c2e6d
G
80(defcustom mm-inline-large-images-proportion 0.9
81 "Maximum proportion of large image resized when
82`mm-inline-large-images' is set to resize."
83 :type 'float
84 :version "24.1"
85 :group 'mime-display)
86
23f87bed
MB
87;;; Internal variables.
88
c113de23
GM
89;;;
90;;; Functions for displaying various formats inline
91;;;
23f87bed 92
c113de23
GM
93(defun mm-inline-image-emacs (handle)
94 (let ((b (point-marker))
3d2440b4 95 (inhibit-read-only t))
a41c2e6d
G
96 (put-image
97 (let ((image (mm-get-image handle)))
98 (if (eq mm-inline-large-images 'resize)
99 (gnus-rescale-image image
100 (let ((edges (gnus-window-inside-pixel-edges
101 (get-buffer-window (current-buffer)))))
102 (cons (truncate (* mm-inline-large-images-proportion
103 (- (nth 2 edges) (nth 0 edges))))
104 (truncate (* mm-inline-large-images-proportion
105 (- (nth 3 edges) (nth 1 edges)))))))
106 image))
107 b)
23f87bed 108 (insert "\n\n")
c113de23
GM
109 (mm-handle-set-undisplayer
110 handle
23f87bed
MB
111 `(lambda ()
112 (let ((b ,b)
3d2440b4 113 (inhibit-read-only t))
23f87bed
MB
114 (remove-images b b)
115 (delete-region b (+ b 2)))))))
c113de23
GM
116
117(defun mm-inline-image-xemacs (handle)
9efa445f
DN
118 (when (featurep 'xemacs)
119 (insert "\n\n")
120 (forward-char -2)
121 (let ((annot (make-annotation (mm-get-image handle) nil 'text))
3d2440b4 122 (inhibit-read-only t))
9efa445f
DN
123 (mm-handle-set-undisplayer
124 handle
125 `(lambda ()
126 (let ((b ,(point-marker))
3d2440b4 127 (inhibit-read-only t))
9efa445f
DN
128 (delete-annotation ,annot)
129 (delete-region (- b 2) b))))
130 (set-extent-property annot 'mm t)
131 (set-extent-property annot 'duplicable t))))
c113de23
GM
132
133(eval-and-compile
722a8409 134 (if (featurep 'xemacs)
c113de23
GM
135 (defalias 'mm-inline-image 'mm-inline-image-xemacs)
136 (defalias 'mm-inline-image 'mm-inline-image-emacs)))
137
49ad38a1
GM
138;; External.
139(declare-function w3-do-setup "ext:w3" ())
140(declare-function w3-region "ext:w3-display" (st nd))
141(declare-function w3-prepare-buffer "ext:w3-display" (&rest args))
142
c113de23
GM
143(defvar mm-w3-setup nil)
144(defun mm-setup-w3 ()
145 (unless mm-w3-setup
146 (require 'w3)
147 (w3-do-setup)
148 (require 'url)
149 (require 'w3-vars)
150 (require 'url-vars)
151 (setq mm-w3-setup t)))
152
23f87bed
MB
153(defun mm-inline-text-html-render-with-w3 (handle)
154 (mm-setup-w3)
155 (let ((text (mm-get-part handle))
156 (b (point))
157 (url-standalone-mode t)
158 (url-gateway-unplugged t)
159 (w3-honor-stylesheets nil)
160 (url-current-object
161 (url-generic-parse-url (format "cid:%s" (mm-handle-id handle))))
162 (width (window-width))
163 (charset (mail-content-type-get
164 (mm-handle-type handle) 'charset)))
165 (save-excursion
01c52d31 166 (insert (if charset (mm-decode-string text charset) text))
23f87bed
MB
167 (save-restriction
168 (narrow-to-region b (point))
01c52d31
MB
169 (unless charset
170 (goto-char (point-min))
171 (when (or (and (boundp 'w3-meta-content-type-charset-regexp)
172 (re-search-forward
173 w3-meta-content-type-charset-regexp nil t))
174 (and (boundp 'w3-meta-charset-content-type-regexp)
175 (re-search-forward
176 w3-meta-charset-content-type-regexp nil t)))
23f87bed 177 (setq charset
01c52d31
MB
178 (let ((bsubstr (buffer-substring-no-properties
179 (match-beginning 2)
180 (match-end 2))))
181 (if (fboundp 'w3-coding-system-for-mime-charset)
182 (w3-coding-system-for-mime-charset bsubstr)
183 (mm-charset-to-coding-system bsubstr))))
184 (delete-region (point-min) (point-max))
185 (insert (mm-decode-string text charset))))
23f87bed 186 (save-window-excursion
c113de23 187 (save-restriction
23f87bed
MB
188 (let ((w3-strict-width width)
189 ;; Don't let w3 set the global version of
190 ;; this variable.
191 (fill-column fill-column))
192 (if (or debug-on-error debug-on-quit)
193 (w3-region (point-min) (point-max))
194 (condition-case ()
195 (w3-region (point-min) (point-max))
196 (error
197 (delete-region (point-min) (point-max))
198 (let ((b (point))
199 (charset (mail-content-type-get
200 (mm-handle-type handle) 'charset)))
201 (if (or (eq charset 'gnus-decoded)
202 (eq mail-parse-charset 'gnus-decoded))
203 (save-restriction
204 (narrow-to-region (point) (point))
205 (mm-insert-part handle)
206 (goto-char (point-max)))
207 (insert (mm-decode-string (mm-get-part handle)
208 charset))))
209 (message
210 "Error while rendering html; showing as text/plain")))))))
211 (mm-handle-set-undisplayer
212 handle
213 `(lambda ()
3d2440b4 214 (let ((inhibit-read-only t))
01c52d31 215 ,@(if (functionp 'remove-specifier)
3d2440b4
SM
216 '((dolist (prop '(background background-pixmap foreground))
217 (remove-specifier
218 (face-property 'default prop)
219 (current-buffer)))))
23f87bed
MB
220 (delete-region ,(point-min-marker)
221 ,(point-max-marker)))))))))
222
223(defvar mm-w3m-setup nil
224 "Whether gnus-article-mode has been setup to use emacs-w3m.")
225
49ad38a1
GM
226;; External.
227(declare-function w3m-detect-meta-charset "ext:w3m" ())
228(declare-function w3m-region "ext:w3m" (start end &optional url charset))
229
23f87bed
MB
230(defun mm-setup-w3m ()
231 "Setup gnus-article-mode to use emacs-w3m."
232 (unless mm-w3m-setup
233 (require 'w3m)
234 (unless (assq 'gnus-article-mode w3m-cid-retrieve-function-alist)
235 (push (cons 'gnus-article-mode 'mm-w3m-cid-retrieve)
236 w3m-cid-retrieve-function-alist))
237 (setq mm-w3m-setup t))
238 (setq w3m-display-inline-images mm-inline-text-html-with-images))
239
240(defun mm-w3m-cid-retrieve-1 (url handle)
54506618 241 (dolist (elem handle)
fe62aacc
MB
242 (when (consp elem)
243 (when (equal url (mm-handle-id elem))
244 (mm-insert-part elem)
245 (throw 'found-handle (mm-handle-media-type elem)))
246 (when (and (stringp (car elem))
247 (equal "multipart" (mm-handle-media-supertype elem)))
248 (mm-w3m-cid-retrieve-1 url elem)))))
23f87bed
MB
249
250(defun mm-w3m-cid-retrieve (url &rest args)
251 "Insert a content pointed by URL if it has the cid: scheme."
252 (when (string-match "\\`cid:" url)
fe62aacc
MB
253 (or (catch 'found-handle
254 (mm-w3m-cid-retrieve-1
255 (setq url (concat "<" (substring url (match-end 0)) ">"))
256 (with-current-buffer w3m-current-buffer
257 gnus-article-mime-handles)))
258 (prog1
259 nil
260 (message "Failed to find \"Content-ID: %s\"" url)))))
23f87bed
MB
261
262(defun mm-inline-text-html-render-with-w3m (handle)
263 "Render a text/html part using emacs-w3m."
264 (mm-setup-w3m)
265 (let ((text (mm-get-part handle))
266 (b (point))
6b554e88
MB
267 (charset (or (mail-content-type-get (mm-handle-type handle) 'charset)
268 mail-parse-charset)))
23f87bed
MB
269 (save-excursion
270 (insert (if charset (mm-decode-string text charset) text))
271 (save-restriction
272 (narrow-to-region b (point))
273 (unless charset
274 (goto-char (point-min))
275 (when (setq charset (w3m-detect-meta-charset))
c113de23 276 (delete-region (point-min) (point-max))
23f87bed
MB
277 (insert (mm-decode-string text charset))))
278 (let ((w3m-safe-url-regexp mm-w3m-safe-url-regexp)
279 w3m-force-redisplay)
280 (w3m-region (point-min) (point-max) nil charset))
1250af7b
KY
281 ;; Put the mark meaning this part was rendered by emacs-w3m.
282 (put-text-property (point-min) (point-max)
283 'mm-inline-text-html-with-w3m t)
23f87bed
MB
284 (when (and mm-inline-text-html-with-w3m-keymap
285 (boundp 'w3m-minor-mode-map)
286 w3m-minor-mode-map)
886367d8
KY
287 (if (and (boundp 'w3m-link-map)
288 w3m-link-map)
1250af7b
KY
289 (let* ((start (point-min))
290 (end (point-max))
291 (on (get-text-property start 'w3m-href-anchor))
292 (map (copy-keymap w3m-link-map))
293 next)
886367d8 294 (set-keymap-parent map w3m-minor-mode-map)
1250af7b
KY
295 (while (< start end)
296 (if on
297 (progn
298 (setq next (or (text-property-any start end
299 'w3m-href-anchor nil)
300 end))
301 (put-text-property start next 'keymap map))
302 (setq next (or (text-property-not-all start end
303 'w3m-href-anchor nil)
304 end))
305 (put-text-property start next 'keymap w3m-minor-mode-map))
306 (setq start next
307 on (not on))))
308 (put-text-property (point-min) (point-max)
309 'keymap w3m-minor-mode-map)))
58090a8d
MB
310 (mm-handle-set-undisplayer
311 handle
312 `(lambda ()
01c52d31 313 (let ((inhibit-read-only t))
58090a8d
MB
314 (delete-region ,(point-min-marker)
315 ,(point-max-marker)))))))))
23f87bed 316
7347faa8
MB
317(defvar mm-w3m-standalone-supports-m17n-p (if (featurep 'mule) 'undecided)
318 "*T means the w3m command supports the m17n feature.")
319
320(defun mm-w3m-standalone-supports-m17n-p ()
321 "Say whether the w3m command supports the m17n feature."
322 (cond ((eq mm-w3m-standalone-supports-m17n-p t) t)
323 ((eq mm-w3m-standalone-supports-m17n-p nil) nil)
324 ((not (featurep 'mule)) (setq mm-w3m-standalone-supports-m17n-p nil))
325 ((condition-case nil
326 (let ((coding-system-for-write 'iso-2022-jp)
327 (coding-system-for-read 'iso-2022-jp)
328 (str (mm-decode-coding-string "\
8f7abae3 329\e$B#D#o#e#s!!#w#3#m!!#s#u#p#p#o#r#t!!#m#1#7#n!)\e(B" 'iso-2022-jp)))
7347faa8
MB
330 (mm-with-multibyte-buffer
331 (insert str)
332 (call-process-region
333 (point-min) (point-max) "w3m" t t nil "-dump"
334 "-T" "text/html" "-I" "iso-2022-jp" "-O" "iso-2022-jp")
335 (goto-char (point-min))
336 (search-forward str nil t)))
337 (error nil))
338 (setq mm-w3m-standalone-supports-m17n-p t))
339 (t
340 ;;(message "You had better upgrade your w3m command")
341 (setq mm-w3m-standalone-supports-m17n-p nil))))
342
73043f7d
MB
343(defun mm-inline-text-html-render-with-w3m-standalone (handle)
344 "Render a text/html part using w3m."
7347faa8
MB
345 (if (mm-w3m-standalone-supports-m17n-p)
346 (let ((source (mm-get-part handle))
6b554e88
MB
347 (charset (or (mail-content-type-get (mm-handle-type handle)
348 'charset)
349 (symbol-name mail-parse-charset)))
7347faa8
MB
350 cs)
351 (unless (and charset
352 (setq cs (mm-charset-to-coding-system charset))
353 (not (eq cs 'ascii)))
354 ;; The default.
355 (setq charset "iso-8859-1"
356 cs 'iso-8859-1))
357 (mm-insert-inline
358 handle
359 (mm-with-unibyte-buffer
360 (insert source)
361 (mm-enable-multibyte)
362 (let ((coding-system-for-write 'binary)
363 (coding-system-for-read cs))
364 (call-process-region
365 (point-min) (point-max)
366 "w3m" t t nil "-dump" "-T" "text/html"
367 "-I" charset "-O" charset))
368 (buffer-string))))
369 (mm-inline-render-with-stdin handle nil "w3m" "-dump" "-T" "text/html")))
73043f7d 370
23f87bed
MB
371(defun mm-links-remove-leading-blank ()
372 ;; Delete the annoying three spaces preceding each line of links
373 ;; output.
374 (goto-char (point-min))
375 (while (re-search-forward "^ " nil t)
376 (delete-region (match-beginning 0) (match-end 0))))
377
378(defun mm-inline-wash-with-file (post-func cmd &rest args)
379 (let ((file (mm-make-temp-file
380 (expand-file-name "mm" mm-tmp-directory))))
381 (let ((coding-system-for-write 'binary))
382 (write-region (point-min) (point-max) file nil 'silent))
383 (delete-region (point-min) (point-max))
384 (unwind-protect
385 (apply 'call-process cmd nil t nil (mapcar 'eval args))
386 (delete-file file))
387 (and post-func (funcall post-func))))
388
389(defun mm-inline-wash-with-stdin (post-func cmd &rest args)
390 (let ((coding-system-for-write 'binary))
391 (apply 'call-process-region (point-min) (point-max)
392 cmd t t nil args))
393 (and post-func (funcall post-func)))
394
395(defun mm-inline-render-with-file (handle post-func cmd &rest args)
396 (let ((source (mm-get-part handle)))
397 (mm-insert-inline
398 handle
399 (mm-with-unibyte-buffer
400 (insert source)
401 (apply 'mm-inline-wash-with-file post-func cmd args)
402 (buffer-string)))))
403
404(defun mm-inline-render-with-stdin (handle post-func cmd &rest args)
405 (let ((source (mm-get-part handle)))
406 (mm-insert-inline
407 handle
408 (mm-with-unibyte-buffer
409 (insert source)
410 (apply 'mm-inline-wash-with-stdin post-func cmd args)
411 (buffer-string)))))
412
413(defun mm-inline-render-with-function (handle func &rest args)
414 (let ((source (mm-get-part handle))
6b554e88
MB
415 (charset (or (mail-content-type-get (mm-handle-type handle) 'charset)
416 mail-parse-charset)))
23f87bed
MB
417 (mm-insert-inline
418 handle
419 (mm-with-multibyte-buffer
420 (insert (if charset
421 (mm-decode-string source charset)
422 source))
423 (apply func args)
424 (buffer-string)))))
425
426(defun mm-inline-text-html (handle)
427 (let* ((func (or mm-inline-text-html-renderer mm-text-html-renderer))
428 (entry (assq func mm-text-html-renderer-alist))
3d2440b4 429 (inhibit-read-only t))
23f87bed
MB
430 (if entry
431 (setq func (cdr entry)))
432 (cond
433 ((functionp func)
434 (funcall func handle))
c113de23 435 (t
23f87bed
MB
436 (apply (car func) handle (cdr func))))))
437
438(defun mm-inline-text-vcard (handle)
3d2440b4 439 (let ((inhibit-read-only t))
23f87bed
MB
440 (mm-insert-inline
441 handle
442 (concat "\n-- \n"
443 (ignore-errors
444 (if (fboundp 'vcard-pretty-print)
445 (vcard-pretty-print (mm-get-part handle))
446 (vcard-format-string
447 (vcard-parse-string (mm-get-part handle)
448 'vcard-standard-filter))))))))
449
450(defun mm-inline-text (handle)
451 (let ((b (point))
452 (type (mm-handle-media-subtype handle))
453 (charset (mail-content-type-get
454 (mm-handle-type handle) 'charset))
3d2440b4 455 (inhibit-read-only t))
23f87bed
MB
456 (if (or (eq charset 'gnus-decoded)
457 ;; This is probably not entirely correct, but
458 ;; makes rfc822 parts with embedded multiparts work.
459 (eq mail-parse-charset 'gnus-decoded))
c113de23 460 (save-restriction
23f87bed
MB
461 (narrow-to-region (point) (point))
462 (mm-insert-part handle)
463 (goto-char (point-max)))
464 (insert (mm-decode-string (mm-get-part handle) charset)))
5f4264e5
MB
465 (when (and mm-fill-flowed
466 (equal type "plain")
23f87bed
MB
467 (equal (cdr (assoc 'format (mm-handle-type handle)))
468 "flowed"))
469 (save-restriction
470 (narrow-to-region b (point))
471 (goto-char b)
01c52d31
MB
472 (fill-flowed nil (equal (cdr (assoc 'delsp (mm-handle-type handle)))
473 "yes"))
23f87bed
MB
474 (goto-char (point-max))))
475 (save-restriction
476 (narrow-to-region b (point))
3d2440b4
SM
477 (when (member type '("enriched" "richtext"))
478 (set-text-properties (point-min) (point-max) nil)
23f87bed
MB
479 (ignore-errors
480 (enriched-decode (point-min) (point-max))))
481 (mm-handle-set-undisplayer
482 handle
483 `(lambda ()
3d2440b4 484 (let ((inhibit-read-only t))
23f87bed
MB
485 (delete-region ,(point-min-marker)
486 ,(point-max-marker))))))))
c113de23
GM
487
488(defun mm-insert-inline (handle text)
489 "Insert TEXT inline from HANDLE."
23f87bed 490 (let ((b (point)))
c113de23 491 (insert text)
01c52d31
MB
492 (unless (bolp)
493 (insert "\n"))
c113de23
GM
494 (mm-handle-set-undisplayer
495 handle
496 `(lambda ()
3d2440b4
SM
497 (let ((inhibit-read-only t))
498 (delete-region ,(copy-marker b)
499 ,(copy-marker (point))))))))
c113de23
GM
500
501(defun mm-inline-audio (handle)
502 (message "Not implemented"))
503
504(defun mm-view-sound-file ()
505 (message "Not implemented"))
506
507(defun mm-w3-prepare-buffer ()
508 (require 'w3)
6833e8ba 509 (let ((url-standalone-mode t)
23f87bed
MB
510 (url-gateway-unplugged t)
511 (w3-honor-stylesheets nil))
c113de23
GM
512 (w3-prepare-buffer)))
513
514(defun mm-view-message ()
515 (mm-enable-multibyte)
516 (let (handles)
517 (let (gnus-article-mime-handles)
518 ;; Double decode problem may happen. See mm-inline-message.
519 (run-hooks 'gnus-article-decode-hook)
520 (gnus-article-prepare-display)
521 (setq handles gnus-article-mime-handles))
522 (when handles
523 (setq gnus-article-mime-handles
23f87bed 524 (mm-merge-handles gnus-article-mime-handles handles))))
c113de23
GM
525 (fundamental-mode)
526 (goto-char (point-min)))
527
528(defun mm-inline-message (handle)
529 (let ((b (point))
4e728580 530 (bolp (bolp))
c113de23
GM
531 (charset (mail-content-type-get
532 (mm-handle-type handle) 'charset))
533 gnus-displaying-mime handles)
534 (when (and charset
535 (stringp charset))
536 (setq charset (intern (downcase charset)))
537 (when (eq charset 'us-ascii)
538 (setq charset nil)))
539 (save-excursion
540 (save-restriction
541 (narrow-to-region b b)
542 (mm-insert-part handle)
543 (let (gnus-article-mime-handles
4e728580
SZ
544 ;; disable prepare hook
545 gnus-article-prepare-hook
c113de23 546 (gnus-newsgroup-charset
34128042
MB
547 (unless (eq charset 'gnus-decoded) ;; mm-uu might set it.
548 (or charset gnus-newsgroup-charset))))
23f87bed
MB
549 (let ((gnus-original-article-buffer (mm-handle-buffer handle)))
550 (run-hooks 'gnus-article-decode-hook))
c113de23
GM
551 (gnus-article-prepare-display)
552 (setq handles gnus-article-mime-handles))
4e728580
SZ
553 (goto-char (point-min))
554 (unless bolp
555 (insert "\n"))
c113de23
GM
556 (goto-char (point-max))
557 (unless (bolp)
558 (insert "\n"))
559 (insert "----------\n\n")
560 (when handles
561 (setq gnus-article-mime-handles
23f87bed 562 (mm-merge-handles gnus-article-mime-handles handles)))
c113de23
GM
563 (mm-handle-set-undisplayer
564 handle
565 `(lambda ()
3d2440b4 566 (let ((inhibit-read-only t))
722a8409 567 (if (fboundp 'remove-specifier)
c113de23 568 ;; This is only valid on XEmacs.
3d2440b4
SM
569 (dolist (prop '(background background-pixmap foreground))
570 (remove-specifier
571 (face-property 'default prop) (current-buffer))))
c113de23
GM
572 (delete-region ,(point-min-marker) ,(point-max-marker)))))))))
573
ce9401f3 574(defun mm-display-inline-fontify (handle mode)
01c52d31
MB
575 (let ((charset (mail-content-type-get (mm-handle-type handle) 'charset))
576 text coding-system)
577 (unless (eq charset 'gnus-decoded)
578 (mm-with-unibyte-buffer
579 (mm-insert-part handle)
580 (mm-decompress-buffer
581 (or (mail-content-type-get (mm-handle-disposition handle) 'name)
582 (mail-content-type-get (mm-handle-disposition handle) 'filename))
583 t t)
584 (unless charset
585 (setq coding-system (mm-find-buffer-file-coding-system)))
586 (setq text (buffer-string))))
23f87bed
MB
587 ;; XEmacs @#$@ version of font-lock refuses to fully turn itself
588 ;; on for buffers whose name begins with " ". That's why we use
01c52d31
MB
589 ;; `with-current-buffer'/`generate-new-buffer' rather than
590 ;; `with-temp-buffer'.
591 (with-current-buffer (generate-new-buffer "*fontification*")
592 (buffer-disable-undo)
593 (mm-enable-multibyte)
594 (insert (cond ((eq charset 'gnus-decoded)
595 (with-current-buffer (mm-handle-buffer handle)
596 (buffer-string)))
597 (coding-system
598 (mm-decode-coding-string text coding-system))
599 (charset
600 (mm-decode-string text charset))
601 (t
602 text)))
603 (require 'font-lock)
604 (let ((font-lock-maximum-size nil)
605 ;; Disable support modes, e.g., jit-lock, lazy-lock, etc.
606 (font-lock-mode-hook nil)
607 (font-lock-support-mode nil)
608 ;; I find font-lock a bit too verbose.
609 (font-lock-verbose nil))
610 (funcall mode)
611 ;; The mode function might have already turned on font-lock.
612 (unless (symbol-value 'font-lock-mode)
613 (font-lock-fontify-buffer)))
614 ;; By default, XEmacs font-lock uses non-duplicable text
615 ;; properties. This code forces all the text properties
616 ;; to be copied along with the text.
9efa445f 617 (when (featurep 'xemacs)
01c52d31
MB
618 (map-extents (lambda (ext ignored)
619 (set-extent-property ext 'duplicable t)
620 nil)
621 nil nil nil nil nil 'text-prop))
622 (setq text (buffer-string))
623 (kill-buffer (current-buffer)))
c113de23
GM
624 (mm-insert-inline handle text)))
625
23f87bed
MB
626;; Shouldn't these functions check whether the user even wants to use
627;; font-lock? At least under XEmacs, this fontification is pretty
628;; much unconditional. Also, it would be nice to change for the size
629;; of the fontified region.
630
ce9401f3
DL
631(defun mm-display-patch-inline (handle)
632 (mm-display-inline-fontify handle 'diff-mode))
633
634(defun mm-display-elisp-inline (handle)
635 (mm-display-inline-fontify handle 'emacs-lisp-mode))
636
01c52d31
MB
637(defun mm-display-dns-inline (handle)
638 (mm-display-inline-fontify handle 'dns-mode))
639
23f87bed
MB
640;; id-signedData OBJECT IDENTIFIER ::= { iso(1) member-body(2)
641;; us(840) rsadsi(113549) pkcs(1) pkcs7(7) 2 }
642(defvar mm-pkcs7-signed-magic
e52cac88
MB
643 "\x30\x5c\x28\x80\x5c\x7c\x81\x2e\x5c\x7c\x82\x2e\x2e\x5c\x7c\x83\x2e\x2e\
644\x2e\x5c\x29\x06\x09\x5c\x2a\x86\x48\x86\xf7\x0d\x01\x07\x02")
23f87bed
MB
645
646;; id-envelopedData OBJECT IDENTIFIER ::= { iso(1) member-body(2)
647;; us(840) rsadsi(113549) pkcs(1) pkcs7(7) 3 }
648(defvar mm-pkcs7-enveloped-magic
e52cac88
MB
649 "\x30\x5c\x28\x80\x5c\x7c\x81\x2e\x5c\x7c\x82\x2e\x2e\x5c\x7c\x83\x2e\x2e\
650\x2e\x5c\x29\x06\x09\x5c\x2a\x86\x48\x86\xf7\x0d\x01\x07\x03")
23f87bed
MB
651
652(defun mm-view-pkcs7-get-type (handle)
653 (mm-with-unibyte-buffer
654 (mm-insert-part handle)
655 (cond ((looking-at mm-pkcs7-enveloped-magic)
656 'enveloped)
657 ((looking-at mm-pkcs7-signed-magic)
658 'signed)
659 (t
660 (error "Could not identify PKCS#7 type")))))
661
662(defun mm-view-pkcs7 (handle)
663 (case (mm-view-pkcs7-get-type handle)
664 (enveloped (mm-view-pkcs7-decrypt handle))
665 (signed (mm-view-pkcs7-verify handle))
666 (otherwise (error "Unknown or unimplemented PKCS#7 type"))))
667
668(defun mm-view-pkcs7-verify (handle)
01c52d31
MB
669 (let ((verified nil))
670 (with-temp-buffer
671 (insert "MIME-Version: 1.0\n")
672 (mm-insert-headers "application/pkcs7-mime" "base64" "smime.p7m")
673 (insert-buffer-substring (mm-handle-buffer handle))
674 (setq verified (smime-verify-region (point-min) (point-max))))
675 (goto-char (point-min))
676 (mm-insert-part handle)
677 (if (search-forward "Content-Type: " nil t)
678 (delete-region (point-min) (match-beginning 0)))
679 (goto-char (point-max))
680 (if (re-search-backward "--\r?\n?" nil t)
681 (delete-region (match-end 0) (point-max)))
682 (unless verified
683 (insert-buffer-substring smime-details-buffer)))
23f87bed
MB
684 (goto-char (point-min))
685 (while (search-forward "\r\n" nil t)
686 (replace-match "\n"))
23f87bed
MB
687 t)
688
23f87bed
MB
689(defun mm-view-pkcs7-decrypt (handle)
690 (insert-buffer-substring (mm-handle-buffer handle))
691 (goto-char (point-min))
692 (insert "MIME-Version: 1.0\n")
693 (mm-insert-headers "application/pkcs7-mime" "base64" "smime.p7m")
694 (smime-decrypt-region
695 (point-min) (point-max)
696 (if (= (length smime-keys) 1)
697 (cadar smime-keys)
698 (smime-get-key-by-email
229b59da
G
699 (gnus-completing-read
700 "Decipher using key"
701 smime-keys nil nil nil (car-safe (car-safe smime-keys))))))
23f87bed
MB
702 (goto-char (point-min))
703 (while (search-forward "\r\n" nil t)
704 (replace-match "\n"))
705 (goto-char (point-min)))
706
c113de23
GM
707(provide 'mm-view)
708
715a2ca2 709;;; mm-view.el ends here