1 ;;; mime-pgp.el --- mime-view internal methods for either PGP or GnuPG.
3 ;; Copyright (C) 1995,1996,1997,1998,1999 MORIOKA Tomohiko
5 ;; Author: MORIOKA Tomohiko <morioka@jaist.ac.jp>
6 ;; Katsumi Yamaoka <yamaoka@jpl.org>
8 ;; Renamed: 1997/2/27 from tm-pgp.el
9 ;; Keywords: PGP, GnuPG, security, MIME, multimedia, mail, news
11 ;; This file is part of SEMI (Secure Emacs MIME Interface).
13 ;; This program is free software; you can redistribute it and/or
14 ;; modify it under the terms of the GNU General Public License as
15 ;; published by the Free Software Foundation; either version 2, or (at
16 ;; your option) any later version.
18 ;; This program is distributed in the hope that it will be useful, but
19 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 ;; General Public License for more details.
23 ;; You should have received a copy of the GNU General Public License
24 ;; along with GNU Emacs; see the file COPYING. If not, write to the
25 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26 ;; Boston, MA 02111-1307, USA.
30 ;; This module is based on
32 ;; [security-multipart] RFC 1847: "Security Multiparts for MIME:
33 ;; Multipart/Signed and Multipart/Encrypted" by
34 ;; Jim Galvin <galvin@tis.com>, Sandy Murphy <sandy@tis.com>,
35 ;; Steve Crocker <crocker@cybercash.com> and
36 ;; Ned Freed <ned@innosoft.com> (1995/10)
38 ;; [PGP/MIME] RFC 2015: "MIME Security with Pretty Good Privacy
39 ;; (PGP)" by Michael Elkins <elkins@aero.org> (1996/6)
41 ;; [PGP-kazu] draft-kazu-pgp-mime-00.txt: "PGP MIME Integration"
42 ;; by Kazuhiko Yamamoto <kazu@is.aist-nara.ac.jp> (1995/10;
45 ;; [OpenPGP/MIME] draft-yamamoto-openpgp-mime-00.txt: "MIME
46 ;; Security with OpenPGP (OpenPGP/MIME)" by Kazuhiko YAMAMOTO
47 ;; <kazu@iijlab.net> (1998/1)
55 (defgroup mime-pgp nil
56 "Internal methods for either PGP or GnuPG."
60 ;;; @ Internal method for multipart/signed
62 ;;; It is based on RFC 1847 (security-multipart).
64 (defun mime-verify-multipart/signed (entity situation)
65 "Internal method to verify multipart/signed."
67 (nth 1 (mime-entity-children entity)) ; entity-info of signature
68 (list (assq 'mode situation)) ; play-mode
72 ;;; @ internal method for application/pgp
74 ;;; It is based on draft-kazu-pgp-mime-00.txt (PGP-kazu).
76 (defun mime-view-application/pgp (entity situation)
77 (let* ((p-win (or (get-buffer-window (current-buffer))
78 (get-largest-window)))
80 (format "%s-%s" (buffer-name) (mime-entity-number entity)))
81 (mother (current-buffer))
82 (preview-buffer (concat "*Preview-" (buffer-name) "*"))
84 (set-buffer (get-buffer-create new-name))
86 (mime-insert-entity entity)
88 (goto-char (point-min))
89 (re-search-forward "^-+BEGIN PGP SIGNED MESSAGE-+$" nil t))
90 (funcall (pgp-function 'verify))
91 (goto-char (point-min))
95 (re-search-forward "^-+BEGIN PGP SIGNED MESSAGE-+\n\n")
98 (and (re-search-forward "^-+BEGIN PGP SIGNATURE-+")
101 (goto-char (point-min))
102 (while (re-search-forward "^- -" nil t)
105 (setq representation-type (if (mime-entity-cooked-p entity)
109 (goto-char (point-min))
110 (re-search-forward "^-+BEGIN PGP MESSAGE-+$" nil t))
111 (as-binary-process (funcall (pgp-function 'decrypt)))
112 (goto-char (point-min))
113 (delete-region (point-min)
115 (search-forward "\n\n")
117 (setq representation-type 'binary)
119 (setq major-mode 'mime-show-message-mode)
120 (save-window-excursion (mime-view-buffer nil preview-buffer mother
121 nil representation-type))
122 (set-window-buffer p-win preview-buffer)
126 ;;; @ Internal method for application/pgp-signature
128 ;;; It is based on RFC 2015 (PGP/MIME) and
129 ;;; draft-yamamoto-openpgp-mime-00.txt (OpenPGP/MIME).
131 (defcustom mime-pgp-command-alist '((gpg . "gpg")
134 "Alist of the schemes and the name of the commands. Valid SCHEMEs are:
137 pgp50 - PGP version 5.0i.
138 pgp - PGP version 2.6.
140 COMMAND for `pgp50' must *NOT* have a suffix, like neither \"pgpe\", \"pgpk\",
141 \"pgps\" nor \"pgpv\"."
143 :type '(repeat (cons :format "%v"
144 (choice (choice-item :tag "GnuPG" gpg)
145 (choice-item :tag "PGP 5.0i" pgp50)
146 (choice-item :tag "PGP 2.6" pgp))
147 (string :tag "Command"))))
149 (defcustom mime-pgp-default-language-alist '((gpg . nil)
152 "Alist of the schemes and the symbol of languages. It should be ISO 639
153 2 letter language code such as en, ja, ... Each element looks like
154 \(SCHEME . SYMBOL). See also `mime-pgp-command-alist' for valid SCHEMEs."
156 :type '(repeat (cons :format "%v"
157 (choice (choice-item :tag "GnuPG" gpg)
158 (choice-item :tag "PGP 5.0i" pgp50)
159 (choice-item :tag "PGP 2.6" pgp))
160 (symbol :tag "Language"))))
162 (defcustom mime-pgp-good-signature-regexp-alist
164 (nil "Good signature from.*$" nil)
167 (us "Good signature made .* by key:$"
168 mime-pgp-good-signature-post-function-pgp50-us)
171 (en "Good signature from user.*$" nil)
173 "Alist of the schemes and alist of the languages and the regexps for
174 detecting ``Good signature''. The optional symbol of the post processing
175 function for arranging the output message can be specified in each element.
176 It will be called just after re-search is done successfully, and it is
177 expected that the function returns a string for messaging."
179 :type '(repeat (cons :format "%v"
180 (choice (choice-item :tag "GnuPG" gpg)
181 (choice-item :tag "PGP 5.0i" pgp50)
182 (choice-item :tag "PGP 2.6" pgp))
183 (repeat (list :format "%v"
184 (symbol :tag "Language")
185 (regexp :tag "Regexp")
186 (function :tag "Post Function"))))))
188 (defcustom mime-pgp-bad-signature-regexp-alist
190 (nil "BAD signature from.*$" nil)
193 (us "BAD signature made .* by key:$"
194 mime-pgp-bad-signature-post-function-pgp50-us)
197 (en "Bad signature from user.*$" nil)
199 "Alist of the schemes and alist of the languages and the regexps for
200 detecting ``BAD signature''. The optional symbol of the post processing
201 function for arranging the output message can be specified in each element.
202 It will be called just after re-search is done successfully, and it is
203 expected that the function returns a string for messaging."
205 :type '(repeat (cons :format "%v"
206 (choice (choice-item :tag "GnuPG" gpg)
207 (choice-item :tag "PGP 5.0i" pgp50)
208 (choice-item :tag "PGP 2.6" pgp))
209 (repeat (list :format "%v"
210 (symbol :tag "Language")
211 (regexp :tag "Regexp")
212 (function :tag "Post Function"))))))
214 (defcustom mime-pgp-key-expected-regexp-alist
218 "key ID \\(\\S +\\)\ngpg: Can't check signature: public key not found")
221 (us . "Signature by unknown keyid: 0x\\(\\S +\\)")
224 (en . "Key matching expected Key ID \\(\\S +\\) not found")
226 "Alist of the schemes and alist of the languages and regexps for detecting
229 :type '(repeat (cons :format "%v"
230 (choice (choice-item :tag "GnuPG" gpg)
231 (choice-item :tag "PGP 5.0i" pgp50)
232 (choice-item :tag "PGP 2.6" pgp))
233 (repeat (cons :format "%v"
234 (symbol :tag "Language")
235 (regexp :tag "Regexp"))))))
237 (defmacro mime-pgp-command (&optional suffix)
238 "Return a suitable command. SUFFIX should be either \"e\", \"k\", \"s\"
239 or \"v\" for choosing a command of PGP 5.0i."
240 (` (let ((command (cdr (assq pgp-version mime-pgp-command-alist))))
243 (if (eq 'pgp50 pgp-version)
244 (setq command (format "%s%s" command (, suffix))))
245 (exec-installed-p command)))
247 (error "Please specify the valid command name for `%s'."
248 (or pgp-version 'pgp-version))))))
250 (defmacro mime-pgp-default-language ()
251 "Return a symbol of language."
252 '(cond ((eq 'gpg pgp-version)
254 ((eq 'pgp50 pgp-version)
255 (or (cdr (assq pgp-version mime-pgp-default-language-alist)) 'us)
258 (or (cdr (assq pgp-version mime-pgp-default-language-alist)) 'en)
261 (defmacro mime-pgp-good-signature-regexp ()
262 "Return a regexp to detect ``Good signature''."
265 (mime-pgp-default-language)
266 (cdr (assq pgp-version mime-pgp-good-signature-regexp-alist))
269 (defmacro mime-pgp-good-signature-post-function ()
270 "Return a post processing function for arranging the message for
274 (mime-pgp-default-language)
275 (cdr (assq pgp-version mime-pgp-good-signature-regexp-alist))
278 (defmacro mime-pgp-bad-signature-regexp ()
279 "Return a regexp to detect ``BAD signature''."
282 (mime-pgp-default-language)
283 (cdr (assq pgp-version mime-pgp-bad-signature-regexp-alist))
286 (defmacro mime-pgp-bad-signature-post-function ()
287 "Return a post processing function for arranging the message for
291 (mime-pgp-default-language)
292 (cdr (assq pgp-version mime-pgp-bad-signature-regexp-alist))
295 (defmacro mime-pgp-key-expected-regexp ()
296 "Return a regexp to detect ``Key expected''."
297 '(cdr (assq (mime-pgp-default-language)
298 (cdr (assq pgp-version mime-pgp-key-expected-regexp-alist))
301 (defun mime-pgp-detect-version ()
302 "Detect PGP version in the buffer. The buffer is expected to be narrowed
303 to just an ascii armor. However, a few leading garbage lines are allowed."
304 (let ((version (save-restriction
305 (goto-char (point-min))
306 (if (re-search-forward "^-+BEGIN PGP " nil t)
309 (narrow-to-region (point) (point-max))
310 (std11-narrow-to-header)
311 (std11-fetch-field "Version")
315 ((string-match "GnuPG" version)
317 ((string-match "5\\.0i" version)
319 ((string-match "2\\.6" version)
324 (defun mime-entity-detect-pgp-version (entity)
325 "Detect PGP version from entity content."
327 (mime-insert-entity-content entity)
328 (mime-pgp-detect-version)
331 (defun mime-pgp-check-signature (output-buffer sig-file orig-file
332 &optional hide-lines)
333 (with-current-buffer output-buffer
335 (setq truncate-lines t))
336 (let* ((lang (mime-pgp-default-language))
337 (command (mime-pgp-command 'v))
338 (args (cond ((eq 'gpg pgp-version)
339 (list "--batch" "--verify" sig-file)
341 ((eq 'pgp50 pgp-version)
343 (format "+language=%s" lang)
346 ((eq 'pgp pgp-version)
347 (list (format "+language=%s" lang)
350 (good-regexp (mime-pgp-good-signature-regexp))
351 (good-post-function (mime-pgp-good-signature-post-function))
352 (bad-regexp (mime-pgp-bad-signature-regexp))
353 (bad-post-function (mime-pgp-bad-signature-post-function))
356 (setq status (apply 'call-process-region (point-min) (point-max)
357 command nil output-buffer nil args)
359 (with-current-buffer output-buffer
360 (goto-char (point-min))
361 (forward-line (or hide-lines 0))
363 lines (count-lines start (point-max)))
364 (cond ((not (stringp good-regexp))
365 (message "Please specify right regexp for specified language")
370 (goto-char (point-min))
371 (re-search-forward good-regexp nil t)
373 (message (if good-post-function
374 (funcall good-post-function)
375 (buffer-substring (match-beginning 0)
379 ((not (stringp bad-regexp))
380 (message "Please specify right regexp for specified language")
384 (goto-char (point-min))
385 (re-search-forward bad-regexp nil t)
387 (message (if bad-post-function
388 (funcall bad-post-function)
389 (buffer-substring (match-beginning 0)
394 ;; Returns nil in order for attempt to fetch key.
398 (defmacro mime-pgp-parse-verify-error (output-buffer &rest forms)
399 (` (let ((regexp (mime-pgp-key-expected-regexp))
401 (with-current-buffer (, output-buffer)
402 (goto-char (point-min))
404 (if (re-search-forward regexp nil t)
408 (buffer-substring-no-properties
409 (match-beginning 1) (match-end 1))))
410 (goto-char (point-min))
412 (message "Please specify right regexp for specified language")
415 (list keyid (point) (count-lines (point) (point-max)))
418 (defun mime-pgp-parse-verify-error-for-gpg (output-buffer)
419 "Subroutine used for parsing verify error with GnuPG. Returns the
420 list of expected key-ID, start position and lines to be shown a result."
421 (mime-pgp-parse-verify-error output-buffer)
424 (defun mime-pgp-parse-verify-error-for-pgp50 (output-buffer)
425 "Subroutine used for parsing verify error with PGP 5.0i. Returns the
426 list of expected key-ID, start position and lines to be shown a result."
427 (mime-pgp-parse-verify-error output-buffer (forward-line 1))
430 (defun mime-pgp-parse-verify-error-for-pgp (output-buffer)
431 "Subroutine used for parsing verify error with PGP 2.6. Returns the
432 list of expected key-ID, start position and lines to be shown a result."
433 (mime-pgp-parse-verify-error
435 (if (search-forward "\C-g" nil t)
436 (goto-char (match-beginning 0))
440 (defmacro mime-pgp-show-echo-buffer (start lines)
441 (` (let ((mime-echo-window-height
443 (max window-min-height
444 (- (window-height) window-min-height)
447 (car (save-current-buffer (mime-show-echo-buffer)))
451 (defun mime-verify-application/pgp-signature (entity situation)
452 "Internal method to check PGP/MIME signature."
453 (let* ((entity-node-id (mime-entity-node-id entity))
454 (mother (mime-entity-parent entity))
455 (knum (car entity-node-id))
459 (orig-entity (nth onum (mime-entity-children mother)))
460 (basename (expand-file-name "tm" temporary-file-directory))
461 (orig-file (make-temp-name basename))
462 (sig-file (concat orig-file ".sig"))
463 (pgp-version (mime-entity-detect-pgp-version entity))
464 (output-buffer (get-buffer-create mime-echo-buffer-name))
465 (hide-lines (cdr (assq pgp-version
466 '((gpg . nil) (pgp50 . 1) (pgp . 10)))))
467 (parser (intern (format "mime-pgp-parse-verify-error-for-%s"
470 (mime-write-entity orig-entity orig-file)
471 (mime-write-entity-content entity sig-file)
472 (message "Checking signature...")
475 (if (setq return (mime-pgp-check-signature
476 output-buffer sig-file orig-file hide-lines))
478 (mime-pgp-show-echo-buffer (car return) (cdr return))
484 (setq return (funcall parser output-buffer))
485 (mime-pgp-show-echo-buffer (nth 1 return)
487 (setq pgp-id (car return))
489 (y-or-n-p (format "Key %s not found; attempt to fetch? "
492 (funcall (pgp-function 'fetch-key) (cons nil pgp-id))
493 (setq return (funcall parser output-buffer))
494 (mime-pgp-show-echo-buffer (nth 1 return) (nth 2 return))
496 (message "Can't check signature")
498 (delete-file orig-file)
499 (delete-file sig-file)
502 (defun mime-pgp-good-signature-post-function-pgp50-us ()
504 (looking-at "\\s +\\(.+\\)$")
505 (format "Good signature from %s" (match-string 1)))
507 (defun mime-pgp-bad-signature-post-function-pgp50-us ()
509 (looking-at "\\s +\\(.+\\)$")
510 (format "BAD signature from %s" (match-string 1)))
513 ;;; @ Internal method for application/pgp-encrypted
515 ;;; It is based on RFC 2015 (PGP/MIME) and
516 ;;; draft-yamamoto-openpgp-mime-00.txt (OpenPGP/MIME).
518 (defun mime-decrypt-application/pgp-encrypted (entity situation)
519 (let* ((entity-node-id (mime-entity-node-id entity))
520 (mother (mime-entity-parent entity))
521 (knum (car entity-node-id))
525 (orig-entity (nth onum (mime-entity-children mother)))
526 (pgp-version (mime-entity-detect-pgp-version orig-entity))
528 (mime-view-application/pgp orig-entity situation)
531 (defun mime-edit-decrypt-application/pgp-encrypted ()
532 "Decrypt the encrypted part for the function `mime-edit-again'."
533 (let ((pgp-version (mime-pgp-detect-version)))
534 ;; The following process should returns a pair (SUCCEEDED . VERIFIED)
535 ;; where SUCCEEDED is t if the decryption succeeded and VERIFIED is t
536 ;; if there was a valid signature.
537 (as-binary-process (funcall (pgp-function 'decrypt)))
541 ;;; @ Internal method for application/pgp-keys
543 ;;; It is based on RFC 2015 (PGP/MIME) and
544 ;;; draft-yamamoto-openpgp-mime-00.txt (OpenPGP/MIME).
546 (defun mime-add-application/pgp-keys (entity situation)
548 (mime-insert-entity-content entity)
549 (mime-decode-region (point-min) (point-max)
550 (cdr (assq 'encoding situation)))
551 (let ((pgp-version (mime-pgp-detect-version)))
552 (funcall (pgp-function 'snarf-keys))
556 ;;; @ Internal method for fetching a public key
559 (defcustom mime-pgp-keyserver-url-template "/pks/lookup?op=get&search=%s"
560 "The URL to pass to the keyserver."
564 (defcustom mime-pgp-keyserver-address "pgp.nic.ad.jp"
565 "Host name of keyserver."
569 (defcustom mime-pgp-keyserver-port 11371
570 "Port on which the keyserver's HKP daemon lives."
574 (defcustom mime-pgp-http-proxy-url-template
575 "/cgi-bin/pgpsearchkey.pl?op=get&search=%s"
576 "The URL to pass to the keyserver via HTTP proxy."
580 (defcustom mime-pgp-http-proxy-server-address nil
581 "Host name of HTTP proxy server. If you are behind firewalls, set the
582 values of this variable and `mime-pgp-http-proxy-server-port' appropriately."
586 (defcustom mime-pgp-http-proxy-server-port 8080
587 "Port on which the proxy server's HTTP daemon lives."
591 (defcustom mime-pgp-fetch-timeout 20
592 "Timeout, in seconds, for any particular key fetch operation."
596 (defmacro mime-pgp-show-fetched-key (key scroll &rest args)
597 (` (let ((current-window (selected-window))
598 keys start hide return window)
603 (point-min) (point-max) (mime-pgp-command 'v) t t (,@ args))
605 (goto-char (point-min))
606 (forward-line (, scroll))
607 (setq keys (buffer-string)
609 hide (count-lines (point) (point-max)))
611 (setq return (mime-show-echo-buffer "%s" keys)
613 start (1- (+ start (car (cdr return))))
614 hide (- (window-height window) hide 2))
615 (if (>= (+ (window-height current-window) hide) window-min-height)
617 (select-window window)
619 (select-window current-window)
621 (set-window-start window start)
624 (defun mime-pgp-show-fetched-key-for-gpg (key)
625 "Extract KEY and show."
626 (mime-pgp-show-fetched-key key 0)
629 (defun mime-pgp-show-fetched-key-for-pgp50 (key)
630 "Extract KEY and show."
631 (let ((current-window (selected-window))
632 (process-environment process-environment)
633 process-connection-type process keys start hide return window)
634 (setenv "PGPPASSFD" nil)
637 (start-process "*show fetched keys*"
638 (current-buffer) (mime-pgp-command 'v)
639 "-f" "+batchmode=0" "+language=us")
641 (set-process-coding-system process 'binary 'binary)
642 (process-send-string process key)
643 (process-send-eof process)
646 (accept-process-output process 1)
647 (goto-char (point-min))
650 "^Add these keys to your keyring\\? \\[Y/n\\] "
653 (setq start (match-beginning 0))
654 (delete-process process)
655 (delete-region start (point-max))
656 (goto-char (point-min))
658 (setq keys (buffer-string)
660 hide (count-lines (point) start))
662 (setq return (mime-show-echo-buffer "%s" keys)
664 start (1- (+ start (car (cdr return))))
665 hide (- (window-height window) hide 2))
666 (if (>= (+ (window-height current-window) hide) window-min-height)
668 (select-window window)
670 (select-window current-window)
672 (set-window-start window start)
675 (defun mime-pgp-show-fetched-key-for-pgp (key)
676 "Extract KEY and show."
677 (mime-pgp-show-fetched-key key 7 "-f" "+language=en")
680 (defun mime-pgp-fetch-key (&optional id)
681 "Attempt to fetch a key for addition to PGP or GnuPG keyring.
682 Interactively, prompt for string matching key to fetch.
684 Non-interactively, ID must be a pair. The CAR must be a bare Email
685 address and the CDR a keyID (with \"0x\" prefix). Either, but not
688 Return t if we think we were successful; nil otherwise. Note that nil
689 is not necessarily an error, since we may have merely fired off an Email
692 If you want to use this function for verifying a message of PGP/MIME,
693 for example, please put the following lines in your startup file:
695 (eval-after-load \"semi-def\"
696 '(progn (require 'alist)
697 (set-alist 'pgp-function-alist 'fetch-key
698 '(mime-pgp-fetch-key \"mime-pgp\"))
699 (autoload 'mime-pgp-fetch-key \"mime-pgp\" nil t)
702 In addition, if you are behind firewalls, please set the values of
703 `mime-pgp-http-proxy-server-address' and `mime-pgp-http-proxy-server-port'
706 (let ((server (or mime-pgp-http-proxy-server-address
707 mime-pgp-keyserver-address))
708 (port (or mime-pgp-http-proxy-server-port
709 mime-pgp-keyserver-port))
711 (if mime-pgp-http-proxy-server-address
713 mime-pgp-keyserver-address
714 mime-pgp-http-proxy-url-template
716 mime-pgp-keyserver-url-template))
717 (show-function (intern (format "mime-pgp-show-fetched-key-for-%s"
719 (snarf-function (pgp-function 'snarf-keys))
720 armor case-fold-search process-connection-type process start)
721 (if (cond ((interactive-p)
722 (setq id (read-string "Fetch key for: "))
723 (cond ((string-equal "" id)
726 ((string-match "^0[Xx]" id)
727 (setq id (cons nil id)))
729 (setq id (cons id nil)))))
731 (not (or (stringp (car id)) (stringp (cdr id)))))
737 (catch 'mime-pgp-fetch-key-done
738 (message "Fetching %s via HTTP to %s..."
739 (or (cdr id) (car id))
740 mime-pgp-keyserver-address)
742 (setq process (open-network-stream-as-binary
743 "*key fetch*" (current-buffer) server port))
746 (throw 'mime-pgp-fetch-key-done nil)
750 (message "Can't connect to %s%s."
751 mime-pgp-keyserver-address
752 (if mime-pgp-http-proxy-server-address
754 mime-pgp-http-proxy-server-address)
756 (throw 'mime-pgp-fetch-key-done nil)
760 (concat "GET " (format url-template
761 (or (cdr id) (car id))) "\r\n")
763 (while (and (eq 'open (process-status process))
764 (accept-process-output process
765 mime-pgp-fetch-timeout)
767 (delete-process process)
768 (goto-char (point-min))
769 (if (and (re-search-forward
770 "^-----BEGIN PGP PUBLIC KEY BLOCK-----\r?$" nil t)
771 (setq start (match-beginning 0))
773 "^-----END PGP PUBLIC KEY BLOCK-----\r?$" nil t)
775 (setq armor (buffer-substring start (1+ (point))))
778 (save-window-excursion
779 (funcall show-function armor)
780 (if (y-or-n-p "Add this key to keyring? ")
785 ;; The function should return a number of
786 ;; keys found as a string.
787 (format "%s" (funcall snarf-function))))
789 (message "Key not found or discarded.")
794 (message "Key not found.")
803 (run-hooks 'mime-pgp-load-hook)
805 ;;; mime-pgp.el ends here