mm-view.el 24 KB

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