mm-view.el 22 KB

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