* mh-e.el (mh-limit-map, mh-help-messages): Change keybinding of
[bpt/emacs.git] / lisp / gnus / mm-view.el
CommitLineData
715a2ca2 1;;; mm-view.el --- functions for viewing MIME objects
e84b4b86
TTN
2
3;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
4;; 2005 Free Software Foundation, Inc.
c113de23
GM
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
3a35cf56
LK
21;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22;; Boston, MA 02110-1301, USA.
c113de23
GM
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")
23f87bed 39 (autoload 'html2text "html2text")
39e72e55
GM
40 (unless (fboundp 'diff-mode)
41 (autoload 'diff-mode "diff-mode" "" t nil)))
c113de23 42
dd3eac76
JB
43(defvar gnus-article-mime-handles)
44(defvar gnus-newsgroup-charset)
45(defvar smime-keys)
46(defvar w3m-cid-retrieve-function-alist)
47(defvar w3m-current-buffer)
48(defvar w3m-display-inline-images)
49(defvar w3m-minor-mode-map)
50
23f87bed
MB
51(defvar mm-text-html-renderer-alist
52 '((w3 . mm-inline-text-html-render-with-w3)
53 (w3m . mm-inline-text-html-render-with-w3m)
54 (w3m-standalone mm-inline-render-with-stdin nil
55 "w3m" "-dump" "-T" "text/html")
56 (links mm-inline-render-with-file
57 mm-links-remove-leading-blank
58 "links" "-dump" file)
59 (lynx mm-inline-render-with-stdin nil
60 "lynx" "-dump" "-force_html" "-stdin" "-nolist")
61 (html2text mm-inline-render-with-function html2text))
62 "The attributes of renderer types for text/html.")
63
64(defvar mm-text-html-washer-alist
65 '((w3 . gnus-article-wash-html-with-w3)
66 (w3m . gnus-article-wash-html-with-w3m)
67 (w3m-standalone mm-inline-wash-with-stdin nil
68 "w3m" "-dump" "-T" "text/html")
69 (links mm-inline-wash-with-file
70 mm-links-remove-leading-blank
71 "links" "-dump" file)
72 (lynx mm-inline-wash-with-stdin nil
73 "lynx" "-dump" "-force_html" "-stdin" "-nolist")
74 (html2text html2text))
75 "The attributes of washer types for text/html.")
76
77;;; Internal variables.
78
c113de23
GM
79;;;
80;;; Functions for displaying various formats inline
81;;;
23f87bed 82
c113de23
GM
83(defun mm-inline-image-emacs (handle)
84 (let ((b (point-marker))
85 buffer-read-only)
c113de23 86 (put-image (mm-get-image handle) b)
23f87bed 87 (insert "\n\n")
c113de23
GM
88 (mm-handle-set-undisplayer
89 handle
23f87bed
MB
90 `(lambda ()
91 (let ((b ,b)
92 buffer-read-only)
93 (remove-images b b)
94 (delete-region b (+ b 2)))))))
c113de23
GM
95
96(defun mm-inline-image-xemacs (handle)
23f87bed
MB
97 (insert "\n\n")
98 (forward-char -2)
99 (let ((annot (make-annotation (mm-get-image handle) nil 'text))
c113de23 100 buffer-read-only)
c113de23
GM
101 (mm-handle-set-undisplayer
102 handle
103 `(lambda ()
23f87bed
MB
104 (let ((b ,(point-marker))
105 buffer-read-only)
c113de23 106 (delete-annotation ,annot)
23f87bed 107 (delete-region (- b 2) b))))
c113de23
GM
108 (set-extent-property annot 'mm t)
109 (set-extent-property annot 'duplicable t)))
110
111(eval-and-compile
722a8409 112 (if (featurep 'xemacs)
c113de23
GM
113 (defalias 'mm-inline-image 'mm-inline-image-xemacs)
114 (defalias 'mm-inline-image 'mm-inline-image-emacs)))
115
116(defvar mm-w3-setup nil)
117(defun mm-setup-w3 ()
118 (unless mm-w3-setup
119 (require 'w3)
120 (w3-do-setup)
121 (require 'url)
122 (require 'w3-vars)
123 (require 'url-vars)
124 (setq mm-w3-setup t)))
125
23f87bed
MB
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 text)
140 (save-restriction
141 (narrow-to-region b (point))
142 (goto-char (point-min))
143 (if (or (and (boundp 'w3-meta-content-type-charset-regexp)
144 (re-search-forward
145 w3-meta-content-type-charset-regexp nil t))
146 (and (boundp 'w3-meta-charset-content-type-regexp)
147 (re-search-forward
148 w3-meta-charset-content-type-regexp nil t)))
149 (setq charset
150 (or (let ((bsubstr (buffer-substring-no-properties
151 (match-beginning 2)
152 (match-end 2))))
153 (if (fboundp 'w3-coding-system-for-mime-charset)
154 (w3-coding-system-for-mime-charset bsubstr)
155 (mm-charset-to-coding-system bsubstr)))
156 charset)))
157 (delete-region (point-min) (point-max))
158 (insert (mm-decode-string text charset))
159 (save-window-excursion
c113de23 160 (save-restriction
23f87bed
MB
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 (buffer-read-only)
188 (if (functionp 'remove-specifier)
189 (mapcar (lambda (prop)
190 (remove-specifier
191 (face-property 'default prop)
192 (current-buffer)))
193 '(background background-pixmap foreground)))
194 (delete-region ,(point-min-marker)
195 ,(point-max-marker)))))))))
196
197(defvar mm-w3m-setup nil
198 "Whether gnus-article-mode has been setup to use emacs-w3m.")
199
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
210(defun mm-w3m-cid-retrieve-1 (url handle)
54506618
MB
211 (dolist (elem handle)
212 (when (listp elem)
213 (if (equal url (mm-handle-id elem))
214 (progn
215 (mm-insert-part elem)
216 (throw 'found-handle (mm-handle-media-type elem))))
217 (if (equal "multipart" (mm-handle-media-supertype elem))
218 (mm-w3m-cid-retrieve-1 url elem)))))
23f87bed
MB
219
220(defun mm-w3m-cid-retrieve (url &rest args)
221 "Insert a content pointed by URL if it has the cid: scheme."
222 (when (string-match "\\`cid:" url)
223 (catch 'found-handle
224 (mm-w3m-cid-retrieve-1 (concat "<" (substring url (match-end 0)) ">")
225 (with-current-buffer w3m-current-buffer
226 gnus-article-mime-handles)))))
227
228(defun mm-inline-text-html-render-with-w3m (handle)
229 "Render a text/html part using emacs-w3m."
230 (mm-setup-w3m)
231 (let ((text (mm-get-part handle))
232 (b (point))
233 (charset (mail-content-type-get (mm-handle-type handle) 'charset)))
234 (save-excursion
235 (insert (if charset (mm-decode-string text charset) text))
236 (save-restriction
237 (narrow-to-region b (point))
238 (unless charset
239 (goto-char (point-min))
240 (when (setq charset (w3m-detect-meta-charset))
c113de23 241 (delete-region (point-min) (point-max))
23f87bed
MB
242 (insert (mm-decode-string text charset))))
243 (let ((w3m-safe-url-regexp mm-w3m-safe-url-regexp)
244 w3m-force-redisplay)
245 (w3m-region (point-min) (point-max) nil charset))
246 (when (and mm-inline-text-html-with-w3m-keymap
247 (boundp 'w3m-minor-mode-map)
248 w3m-minor-mode-map)
249 (add-text-properties
250 (point-min) (point-max)
251 (list 'keymap w3m-minor-mode-map
252 ;; Put the mark meaning this part was rendered by emacs-w3m.
58090a8d
MB
253 'mm-inline-text-html-with-w3m t)))
254 (mm-handle-set-undisplayer
255 handle
256 `(lambda ()
257 (let (buffer-read-only)
258 (if (functionp 'remove-specifier)
259 (mapcar (lambda (prop)
260 (remove-specifier
261 (face-property 'default prop)
262 (current-buffer)))
263 '(background background-pixmap foreground)))
264 (delete-region ,(point-min-marker)
265 ,(point-max-marker)))))))))
23f87bed
MB
266
267(defun mm-links-remove-leading-blank ()
268 ;; Delete the annoying three spaces preceding each line of links
269 ;; output.
270 (goto-char (point-min))
271 (while (re-search-forward "^ " nil t)
272 (delete-region (match-beginning 0) (match-end 0))))
273
274(defun mm-inline-wash-with-file (post-func cmd &rest args)
275 (let ((file (mm-make-temp-file
276 (expand-file-name "mm" mm-tmp-directory))))
277 (let ((coding-system-for-write 'binary))
278 (write-region (point-min) (point-max) file nil 'silent))
279 (delete-region (point-min) (point-max))
280 (unwind-protect
281 (apply 'call-process cmd nil t nil (mapcar 'eval args))
282 (delete-file file))
283 (and post-func (funcall post-func))))
284
285(defun mm-inline-wash-with-stdin (post-func cmd &rest args)
286 (let ((coding-system-for-write 'binary))
287 (apply 'call-process-region (point-min) (point-max)
288 cmd t t nil args))
289 (and post-func (funcall post-func)))
290
291(defun mm-inline-render-with-file (handle post-func cmd &rest args)
292 (let ((source (mm-get-part handle)))
293 (mm-insert-inline
294 handle
295 (mm-with-unibyte-buffer
296 (insert source)
297 (apply 'mm-inline-wash-with-file post-func cmd args)
298 (buffer-string)))))
299
300(defun mm-inline-render-with-stdin (handle post-func cmd &rest args)
301 (let ((source (mm-get-part handle)))
302 (mm-insert-inline
303 handle
304 (mm-with-unibyte-buffer
305 (insert source)
306 (apply 'mm-inline-wash-with-stdin post-func cmd args)
307 (buffer-string)))))
308
309(defun mm-inline-render-with-function (handle func &rest args)
310 (let ((source (mm-get-part handle))
311 (charset (mail-content-type-get (mm-handle-type handle) 'charset)))
312 (mm-insert-inline
313 handle
314 (mm-with-multibyte-buffer
315 (insert (if charset
316 (mm-decode-string source charset)
317 source))
318 (apply func args)
319 (buffer-string)))))
320
321(defun mm-inline-text-html (handle)
322 (let* ((func (or mm-inline-text-html-renderer mm-text-html-renderer))
323 (entry (assq func mm-text-html-renderer-alist))
324 buffer-read-only)
325 (if entry
326 (setq func (cdr entry)))
327 (cond
328 ((functionp func)
329 (funcall func handle))
c113de23 330 (t
23f87bed
MB
331 (apply (car func) handle (cdr func))))))
332
333(defun mm-inline-text-vcard (handle)
334 (let (buffer-read-only)
335 (mm-insert-inline
336 handle
337 (concat "\n-- \n"
338 (ignore-errors
339 (if (fboundp 'vcard-pretty-print)
340 (vcard-pretty-print (mm-get-part handle))
341 (vcard-format-string
342 (vcard-parse-string (mm-get-part handle)
343 'vcard-standard-filter))))))))
344
345(defun mm-inline-text (handle)
346 (let ((b (point))
347 (type (mm-handle-media-subtype handle))
348 (charset (mail-content-type-get
349 (mm-handle-type handle) 'charset))
350 buffer-read-only)
351 (if (or (eq charset 'gnus-decoded)
352 ;; This is probably not entirely correct, but
353 ;; makes rfc822 parts with embedded multiparts work.
354 (eq mail-parse-charset 'gnus-decoded))
c113de23 355 (save-restriction
23f87bed
MB
356 (narrow-to-region (point) (point))
357 (mm-insert-part handle)
358 (goto-char (point-max)))
359 (insert (mm-decode-string (mm-get-part handle) charset)))
360 (when (and (equal type "plain")
361 (equal (cdr (assoc 'format (mm-handle-type handle)))
362 "flowed"))
363 (save-restriction
364 (narrow-to-region b (point))
365 (goto-char b)
366 (fill-flowed)
367 (goto-char (point-max))))
368 (save-restriction
369 (narrow-to-region b (point))
23f87bed
MB
370 (when (or (equal type "enriched")
371 (equal type "richtext"))
53cfefc8 372 (set-text-properties (point-min) (point-max) nil)
23f87bed
MB
373 (ignore-errors
374 (enriched-decode (point-min) (point-max))))
375 (mm-handle-set-undisplayer
376 handle
377 `(lambda ()
378 (let (buffer-read-only)
379 (delete-region ,(point-min-marker)
380 ,(point-max-marker))))))))
c113de23
GM
381
382(defun mm-insert-inline (handle text)
383 "Insert TEXT inline from HANDLE."
23f87bed 384 (let ((b (point)))
c113de23
GM
385 (insert text)
386 (mm-handle-set-undisplayer
387 handle
388 `(lambda ()
389 (let (buffer-read-only)
390 (delete-region ,(set-marker (make-marker) b)
391 ,(set-marker (make-marker) (point))))))))
392
393(defun mm-inline-audio (handle)
394 (message "Not implemented"))
395
396(defun mm-view-sound-file ()
397 (message "Not implemented"))
398
399(defun mm-w3-prepare-buffer ()
400 (require 'w3)
6833e8ba 401 (let ((url-standalone-mode t)
23f87bed
MB
402 (url-gateway-unplugged t)
403 (w3-honor-stylesheets nil))
c113de23
GM
404 (w3-prepare-buffer)))
405
406(defun mm-view-message ()
407 (mm-enable-multibyte)
408 (let (handles)
409 (let (gnus-article-mime-handles)
410 ;; Double decode problem may happen. See mm-inline-message.
411 (run-hooks 'gnus-article-decode-hook)
412 (gnus-article-prepare-display)
413 (setq handles gnus-article-mime-handles))
414 (when handles
415 (setq gnus-article-mime-handles
23f87bed 416 (mm-merge-handles gnus-article-mime-handles handles))))
c113de23
GM
417 (fundamental-mode)
418 (goto-char (point-min)))
419
420(defun mm-inline-message (handle)
421 (let ((b (point))
4e728580 422 (bolp (bolp))
c113de23
GM
423 (charset (mail-content-type-get
424 (mm-handle-type handle) 'charset))
425 gnus-displaying-mime handles)
426 (when (and charset
427 (stringp charset))
428 (setq charset (intern (downcase charset)))
429 (when (eq charset 'us-ascii)
430 (setq charset nil)))
431 (save-excursion
432 (save-restriction
433 (narrow-to-region b b)
434 (mm-insert-part handle)
435 (let (gnus-article-mime-handles
4e728580
SZ
436 ;; disable prepare hook
437 gnus-article-prepare-hook
c113de23
GM
438 (gnus-newsgroup-charset
439 (or charset gnus-newsgroup-charset)))
23f87bed
MB
440 (let ((gnus-original-article-buffer (mm-handle-buffer handle)))
441 (run-hooks 'gnus-article-decode-hook))
c113de23
GM
442 (gnus-article-prepare-display)
443 (setq handles gnus-article-mime-handles))
4e728580
SZ
444 (goto-char (point-min))
445 (unless bolp
446 (insert "\n"))
c113de23
GM
447 (goto-char (point-max))
448 (unless (bolp)
449 (insert "\n"))
450 (insert "----------\n\n")
451 (when handles
452 (setq gnus-article-mime-handles
23f87bed 453 (mm-merge-handles gnus-article-mime-handles handles)))
c113de23
GM
454 (mm-handle-set-undisplayer
455 handle
456 `(lambda ()
457 (let (buffer-read-only)
722a8409 458 (if (fboundp 'remove-specifier)
c113de23
GM
459 ;; This is only valid on XEmacs.
460 (mapcar (lambda (prop)
461 (remove-specifier
462 (face-property 'default prop) (current-buffer)))
722a8409 463 '(background background-pixmap foreground)))
c113de23
GM
464 (delete-region ,(point-min-marker) ,(point-max-marker)))))))))
465
ce9401f3 466(defun mm-display-inline-fontify (handle mode)
c113de23 467 (let (text)
23f87bed
MB
468 ;; XEmacs @#$@ version of font-lock refuses to fully turn itself
469 ;; on for buffers whose name begins with " ". That's why we use
470 ;; save-current-buffer/get-buffer-create rather than
471 ;; with-temp-buffer.
472 (save-current-buffer
473 (set-buffer (generate-new-buffer "*fontification*"))
474 (unwind-protect
475 (progn
476 (buffer-disable-undo)
477 (mm-insert-part handle)
23f87bed 478 (require 'font-lock)
d752cf53
MB
479 (let ((font-lock-maximum-size nil)
480 ;; Disable support modes, e.g., jit-lock, lazy-lock, etc.
481 (font-lock-mode-hook nil)
482 (font-lock-support-mode nil)
483 ;; I find font-lock a bit too verbose.
484 (font-lock-verbose nil))
485 (funcall mode)
486 ;; The mode function might have already turned on font-lock.
487 (unless (symbol-value 'font-lock-mode)
488 (font-lock-fontify-buffer)))
23f87bed
MB
489 ;; By default, XEmacs font-lock uses non-duplicable text
490 ;; properties. This code forces all the text properties
491 ;; to be copied along with the text.
492 (when (fboundp 'extent-list)
493 (map-extents (lambda (ext ignored)
494 (set-extent-property ext 'duplicable t)
495 nil)
496 nil nil nil nil nil 'text-prop))
497 (setq text (buffer-string)))
498 (kill-buffer (current-buffer))))
c113de23
GM
499 (mm-insert-inline handle text)))
500
23f87bed
MB
501;; Shouldn't these functions check whether the user even wants to use
502;; font-lock? At least under XEmacs, this fontification is pretty
503;; much unconditional. Also, it would be nice to change for the size
504;; of the fontified region.
505
ce9401f3
DL
506(defun mm-display-patch-inline (handle)
507 (mm-display-inline-fontify handle 'diff-mode))
508
509(defun mm-display-elisp-inline (handle)
510 (mm-display-inline-fontify handle 'emacs-lisp-mode))
511
23f87bed
MB
512;; id-signedData OBJECT IDENTIFIER ::= { iso(1) member-body(2)
513;; us(840) rsadsi(113549) pkcs(1) pkcs7(7) 2 }
514(defvar mm-pkcs7-signed-magic
515 (mm-string-as-unibyte
516 (apply 'concat
517 (mapcar 'char-to-string
518 (list ?\x30 ?\x5c ?\x28 ?\x80 ?\x5c ?\x7c ?\x81 ?\x2e ?\x5c
519 ?\x7c ?\x82 ?\x2e ?\x2e ?\x5c ?\x7c ?\x83 ?\x2e ?\x2e
520 ?\x2e ?\x5c ?\x29 ?\x06 ?\x09 ?\x5c ?\x2a ?\x86 ?\x48
521 ?\x86 ?\xf7 ?\x0d ?\x01 ?\x07 ?\x02)))))
522
523;; id-envelopedData OBJECT IDENTIFIER ::= { iso(1) member-body(2)
524;; us(840) rsadsi(113549) pkcs(1) pkcs7(7) 3 }
525(defvar mm-pkcs7-enveloped-magic
526 (mm-string-as-unibyte
527 (apply 'concat
528 (mapcar 'char-to-string
529 (list ?\x30 ?\x5c ?\x28 ?\x80 ?\x5c ?\x7c ?\x81 ?\x2e ?\x5c
530 ?\x7c ?\x82 ?\x2e ?\x2e ?\x5c ?\x7c ?\x83 ?\x2e ?\x2e
531 ?\x2e ?\x5c ?\x29 ?\x06 ?\x09 ?\x5c ?\x2a ?\x86 ?\x48
532 ?\x86 ?\xf7 ?\x0d ?\x01 ?\x07 ?\x03)))))
533
534(defun mm-view-pkcs7-get-type (handle)
535 (mm-with-unibyte-buffer
536 (mm-insert-part handle)
537 (cond ((looking-at mm-pkcs7-enveloped-magic)
538 'enveloped)
539 ((looking-at mm-pkcs7-signed-magic)
540 'signed)
541 (t
542 (error "Could not identify PKCS#7 type")))))
543
544(defun mm-view-pkcs7 (handle)
545 (case (mm-view-pkcs7-get-type handle)
546 (enveloped (mm-view-pkcs7-decrypt handle))
547 (signed (mm-view-pkcs7-verify handle))
548 (otherwise (error "Unknown or unimplemented PKCS#7 type"))))
549
550(defun mm-view-pkcs7-verify (handle)
551 ;; A bogus implementation of PKCS#7. FIXME::
552 (mm-insert-part handle)
553 (goto-char (point-min))
554 (if (search-forward "Content-Type: " nil t)
555 (delete-region (point-min) (match-beginning 0)))
556 (goto-char (point-max))
557 (if (re-search-backward "--\r?\n?" nil t)
558 (delete-region (match-end 0) (point-max)))
559 (goto-char (point-min))
560 (while (search-forward "\r\n" nil t)
561 (replace-match "\n"))
562 (message "Verify signed PKCS#7 message is unimplemented.")
563 (sit-for 1)
564 t)
565
566(autoload 'gnus-completing-read-maybe-default "gnus-util" nil nil 'macro)
567
568(defun mm-view-pkcs7-decrypt (handle)
569 (insert-buffer-substring (mm-handle-buffer handle))
570 (goto-char (point-min))
571 (insert "MIME-Version: 1.0\n")
572 (mm-insert-headers "application/pkcs7-mime" "base64" "smime.p7m")
573 (smime-decrypt-region
574 (point-min) (point-max)
575 (if (= (length smime-keys) 1)
576 (cadar smime-keys)
577 (smime-get-key-by-email
578 (gnus-completing-read-maybe-default
81df110a
RF
579 (concat "Decipher using key"
580 (if smime-keys
581 (concat " (default " (caar smime-keys) "): ")
582 ": "))
23f87bed
MB
583 smime-keys nil nil nil nil (car-safe (car-safe smime-keys))))))
584 (goto-char (point-min))
585 (while (search-forward "\r\n" nil t)
586 (replace-match "\n"))
587 (goto-char (point-min)))
588
c113de23
GM
589(provide 'mm-view)
590
ab5796a9 591;;; arch-tag: b60e749a-d05c-47f2-bccd-bdaa59327cb2
715a2ca2 592;;; mm-view.el ends here