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