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