1 ;;; mime-mc.el --- Mailcrypt interface for SEMI -*- coding: iso-8859-4; -*-
3 ;; Copyright (C) 1996,1997,1998,1999 MORIOKA Tomohiko
5 ;; Author: MORIOKA Tomohiko <morioka@jaist.ac.jp>
6 ;; Katsumi Yamaoka <yamaoka@jpl.org>
7 ;; Keywords: PGP, GnuPG, security, MIME, multimedia, mail, news
9 ;; This file is part of SEMI (Secure Emacs MIME Interface).
11 ;; This program is free software; you can redistribute it and/or
12 ;; modify it under the terms of the GNU General Public License as
13 ;; published by the Free Software Foundation; either version 2, or (at
14 ;; your option) any later version.
16 ;; This program is distributed in the hope that it will be useful, but
17 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 ;; General Public License for more details.
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs; see the file COPYING. If not, write to the
23 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24 ;; Boston, MA 02111-1307, USA.
40 (function (lambda (elem) (apply 'autoload elem)))
42 (mc-gpg-debug-print "mc-gpg")
44 (mc-gpg-encrypt-region "mc-gpg")
45 (mc-gpg-fetch-key "mc-gpg")
46 (mc-gpg-lookup-key "mc-gpg")
47 (mc-gpg-sign-region "mc-gpg")
49 (mc-pgp50-encrypt-region "mc-pgp5")
50 (mc-pgp50-fetch-key "mc-pgp5")
51 (mc-pgp50-lookup-key "mc-pgp5")
52 (mc-pgp50-sign-region "mc-pgp5")
54 (mc-pgp-encrypt-region "mc-pgp")
55 (mc-pgp-fetch-key "mc-pgp")
56 (mc-pgp-lookup-key "mc-pgp")
57 (mc-pgp-sign-region "mc-pgp")
59 (mc-snarf-keys "mc-toplev")
63 "Mailcrypt interface for SEMI."
67 (defcustom mime-mc-shell-file-name "/bin/sh"
68 "File name to load inferior shells from. Bourne shell or its equivalent
69 \(not tcsh) is needed for \"2>\"."
73 (defcustom mime-mc-shell-command-switch "-c"
74 "Switch used to have the shell execute its command line argument."
78 (defcustom mime-mc-omit-micalg nil
79 "Non-nil value means to omit the micalg parameter for multipart/signed.
80 See draft-yamamoto-openpgp-mime-00.txt (OpenPGP/MIME) for more information."
84 (defcustom mime-mc-comment-alist
85 (let ((product-name (mime-product-name mime-user-interface-product))
87 (function number-to-string)
88 (mime-product-version mime-user-interface-product)
90 (codename (mime-product-code-name mime-user-interface-product))
92 (while (string-match "ò" codename)
93 (setq codename (replace-match "o" t nil codename)))
94 (while (string-match "þ" codename)
95 (setq codename (replace-match "u" t nil codename)))
96 (setq string (format "Processed by Mailcrypt %s under %s %s%s"
97 mc-version product-name version
98 (if (string-match "^[ -~]+$" codename)
99 (concat " - \"" codename "\"")
101 (list (cons 'gpg string)
104 "Alist of the schemes and strings of the comment field to appear in ASCII
107 :type '(repeat (cons :format "%v"
108 (choice (choice-item :tag "GnuPG" gpg)
109 (choice-item :tag "PGP 5.0i" pgp50)
110 (choice-item :tag "PGP 2.6" pgp))
111 (string :tag "Comment"))))
113 (defvar mime-mc-symbol-format-alist
114 '((comment . "mc-%s-comment")
115 (fetch-key . "mc-%s-fetch-key")
116 (insert-key . "mc-%s-insert-public-key")
117 (mime-encrypt . "mime-mc-%s-encrypt-region")
118 (mime-sign . "mime-mc-%s-sign-region")
119 (scheme . "mc-scheme-%s")
120 (traditional-sign . "mc-%s-sign-region")
122 "Alist of service names and corresponding format strings.")
124 (defmacro mime-mc-symbol (service)
126 (format (cdr (assq (, service) mime-mc-symbol-format-alist))
129 (defmacro mime-mc-comment ()
130 "Return a string of the comment field."
131 '(or (cdr (assq pgp-version mime-mc-comment-alist))
132 (symbol-value (mime-mc-symbol 'comment))
136 ;;; @ Internal variable
139 (defvar mime-mc-micalg-alist nil
140 "Alist of KeyID and the value of message integrity check algorithm.")
143 ;;; @ External variables (for avoid byte compile warnings)
146 (defvar mc-gpg-extra-args)
148 (defvar mc-gpg-user-id)
149 (defvar mc-pgp50-pgps-path)
150 (defvar mc-pgp50-user-id)
152 (defvar mc-pgp-user-id)
155 ;;; @ Generic functions
158 (defun mime-mc-setversion (&optional version)
159 "Select `pgp-version' and `mc-default-scheme' if possible.
160 VERSION should be a string or a symbol."
162 (let ((oldversion pgp-version)
163 (table '(("GnuPG" . gpg) ("PGP 5.0i" . pgp50) ("PGP 2.6" . pgp)
164 ("gnupg" . gpg) ("gpg" . gpg) ("pgp5" . pgp50)
165 ("pgp50" . pgp50) ("pgp2" . pgp) ("pgp" . pgp)
166 ("5.0" . pgp50) ("2.6" . pgp))))
168 (setq version (completing-read
169 (format "Select PGP version (currently %s): "
170 (car (rassoc oldversion table)))
172 pgp-version (or (cdr (assoc version table))
174 (if (stringp version)
175 (setq pgp-version (or (cdr (assoc version table)) oldversion))
176 (if (memq version '(gpg pgp50 pgp))
177 (setq pgp-version version)
181 (cdr (assq pgp-version
182 '((gpg . "gpg") (pgp50 . "5.0") (pgp . "2.6"))))
185 (message "PGP version set to %s." (car (rassq pgp-version table)))
188 (defun mime-mc-replace-comment-field (comment &optional start end)
189 (let ((regexp (if (eq 'pgp pgp-version)
190 "-----BEGIN PGP.*-----\nVersion:"
191 "^-----BEGIN PGP.*\n")))
194 (narrow-to-region (or start (point-min)) (or end (point-max)))
195 (goto-char (point-min))
196 (while (re-search-forward regexp nil t)
199 (narrow-to-region (point)
200 (if (search-forward "\n\n" nil t)
203 (goto-char (point-min))
204 (if (re-search-forward "^Comment:.*$" nil t)
205 (replace-match (concat "Comment: " comment))
209 (defun mime-mc-verify ()
210 "Verify a message in the current buffer. Exact behavior depends on
212 (let ((mc-default-scheme (mime-mc-symbol 'scheme)))
216 (defun mime-mc-decrypt ()
217 "Decrypt a message in the current buffer. Exact behavior depends on
219 (let ((mc-default-scheme (mime-mc-symbol 'scheme)))
220 (if (eq 'mc-scheme-gpg mc-default-scheme)
224 (let ((ofunc (symbol-function 'mc-gpg-decrypt-region)))
225 (message "\"mc-gpg.el\" may be broken. Trying to fix it...")
227 (defun mc-gpg-decrypt-region (start end &optional id)
228 (funcall ofunc start end (or id mc-gpg-user-id)))
231 (fset 'mc-gpg-decrypt-region ofunc)))))
235 (defun mime-mc-fetch-key (&optional id)
236 "Attempt to fetch a key for addition to PGP or GnuPG keyring.
237 Interactively, prompt for string matching key to fetch.
239 Non-interactively, ID must be a pair. The CAR must be a bare Email
240 address and the CDR a keyID (with \"0x\" prefix). Either, but not
243 Return t if we think we were successful; nil otherwise. Note that nil
244 is not necessarily an error, since we may have merely fired off an Email
245 request for the key."
246 (funcall (mime-mc-symbol 'fetch-key) id)
249 (defun mime-mc-snarf-keys ()
250 "Add all public keys in the buffer to your keyring."
251 (let ((mc-default-scheme (mime-mc-symbol 'scheme)))
255 (defun mime-mc-sign-region (start end &optional id unclear boundary)
256 (funcall (mime-mc-symbol 'mime-sign) start end id unclear boundary)
259 (defun mime-mc-traditional-sign-region (start end &optional id unclear)
260 (funcall (mime-mc-symbol 'traditional-sign) start end id unclear)
263 (defun mime-mc-encrypt-region (recipients start end &optional id sign)
264 (funcall (mime-mc-symbol 'mime-encrypt) recipients start end id sign)
267 (defun mime-mc-insert-public-key (&optional userid)
268 "Insert your public key at point."
269 (or (fboundp (mime-mc-symbol 'insert-key))
270 (load (concat "mc-" (cdr (assq pgp-version '((gpg . "gpg")
273 (let ((mc-comment (mime-mc-symbol 'comment))
274 (comment (mime-mc-comment))
275 (scheme (mime-mc-symbol 'scheme)))
276 (eval (` (let (((, mc-comment) (if (, comment) "DUMMY")))
277 (mc-insert-public-key (, userid) (quote (, scheme)))
280 (mime-mc-replace-comment-field comment)
284 ;;; @ GnuPG functions
287 (defun mime-mc-gpg-process-region
288 (beg end passwd program args parser bufferdummy &optional boundary comment)
289 "Similar to `mc-gpg-process-region', however enclose an processed data
290 with BOUNDARY if it is specified and replace the comment field with the
291 optional argument COMMENT if it is specified."
292 (let ((obuf (current-buffer))
293 (process-connection-type nil)
294 (shell-file-name mime-mc-shell-file-name)
295 (shell-command-switch mime-mc-shell-command-switch)
298 stderr-tempfilename stderr-buf
299 status-tempfilename status-buf
300 proc rc status parser-result
302 (mc-gpg-debug-print (format
303 "(mime-mc-gpg-process-region beg=%s end=%s passwd=%s program=%s args=%s parser=%s bufferdummy=%s boundary=%s comment=%s)"
304 beg end passwd program args parser bufferdummy boundary comment))
305 (setq stderr-tempfilename
306 (make-temp-name (expand-file-name "mailcrypt-gpg-stderr-"
308 (setq status-tempfilename
309 (make-temp-name (expand-file-name "mailcrypt-gpg-status-"
312 (catch ;; Returns non-nil if success, otherwise nil with error message.
313 'mime-mc-gpg-process-region-done
315 ;; get output places ready
316 (setq mybuf (get-buffer-create " *mailcrypt stdout temp"))
320 (buffer-disable-undo mybuf)
323 (setq args (append '("--passphrase-fd" "0") args)))
324 (setq args (append (list (concat "2>" stderr-tempfilename)) args))
325 (setq args (append (list (concat "3>" status-tempfilename)) args))
326 (setq args (append '("--status-fd" "3") args))
329 (setq args (append '("--comment" "DUMMY") args))
332 (if mc-gpg-extra-args
333 (setq args (append mc-gpg-extra-args args)))
335 (mc-gpg-debug-print (format "prog is %s, args are %s"
337 (mapconcat '(lambda (x)
342 (apply 'start-process-shell-command "*GPG*" mybuf
344 ;; send in passwd if necessary
347 (process-send-string proc (concat passwd "\n"))
348 (or mc-passwd-timeout (mc-deactivate-passwd t))))
349 ;; send in the region
350 (process-send-region proc beg end)
352 (process-send-eof proc)
353 ;; wait for it to finish
354 (while (eq 'run (process-status proc))
355 (accept-process-output proc 5))
356 ;; remember result codes
357 (setq status (process-status proc))
358 (setq rc (process-exit-status proc))
359 (mc-gpg-debug-print (format "prog finished, rc=%s" rc))
361 ;; Hack to force a status_notify() in Emacs 19.29
362 (delete-process proc)
364 ;; remove the annoying "yes your process has finished" message
366 (goto-char (point-max))
367 (if (re-search-backward "\nProcess \\*GPG.*\n\\'" nil t)
368 (delete-region (match-beginning 0) (match-end 0)))
369 (goto-char (point-min))
371 (while (search-forward "\r\n" nil t)
372 (replace-match "\n"))
374 ;; ponder process death: signal, not just rc!=0
375 (if (or (eq 'stop status) (eq 'signal status))
379 "%s exited abnormally: '%s'" program rc) ;; is rc a string?
380 (throw 'mime-mc-gpg-process-region-done nil)
386 "%s could not be found" program) ;; at least on my system
387 (throw 'mime-mc-gpg-process-region-done nil)
391 (setq stderr-buf (get-buffer-create " *mailcrypt stderr temp"))
392 (buffer-disable-undo stderr-buf)
393 (set-buffer stderr-buf)
395 (insert-file-contents stderr-tempfilename)
398 (setq status-buf (get-buffer-create " *mailcrypt status temp"))
399 (buffer-disable-undo status-buf)
400 (set-buffer status-buf)
402 (insert-file-contents status-tempfilename)
404 ;; replace comment string
407 (mime-mc-replace-comment-field comment)
413 (funcall parser mybuf stderr-buf status-buf rc)
417 (throw 'mime-mc-gpg-process-region-done nil)
419 (mc-gpg-debug-print (format " parser returned %s" parser-result))
421 ;; what did the parser tell us?
422 (if (car parser-result)
423 ;; yes, replace region
428 (narrow-to-region beg end)
430 (insert (format "--%s\n" boundary))
431 (goto-char (point-max))
432 (insert (format "\n--%s
433 Content-Type: application/pgp-signature
434 Content-Transfer-Encoding: 7bit
437 (insert-buffer-substring mybuf)
438 (goto-char (point-max))
439 (insert (format "\n--%s--\n" boundary))
441 (delete-region beg end)
443 (insert-buffer-substring mybuf)
450 (if (and proc (eq 'run (process-status proc)))
451 ;; it is still running. kill it.
452 (interrupt-process proc))
454 (delete-file stderr-tempfilename)
455 (delete-file status-tempfilename)
456 ;; kill off temporary buffers (which would be useful for debugging)
457 (if t ;; nil for easier debugging
459 (if (get-buffer " *mailcrypt stdout temp")
460 (kill-buffer " *mailcrypt stdout temp"))
461 (if (get-buffer " *mailcrypt stderr temp")
462 (kill-buffer " *mailcrypt stderr temp"))
463 (if (get-buffer " *mailcrypt status temp")
464 (kill-buffer " *mailcrypt status temp"))
468 (defun mime-mc-gpg-sign-region (start end &optional id unclear boundary)
469 (if (not (fboundp 'mc-gpg-insert-parser))
472 (let ((buffer (get-buffer-create mc-buffer-name))
474 (parser (function mc-gpg-insert-parser))
475 (pgp-path mc-gpg-path)
477 (comment (mime-mc-comment))
479 (setq key (mc-gpg-lookup-key (or id mc-gpg-user-id) 'sign))
483 (format "GPG passphrase for %s (%s): " (car key) (cdr key))))
491 (list "--armor" "--batch" "--verbose"
492 "--local-user" (cdr key))
496 (if (string-match "^pgp-" boundary)
498 (concat "gpg-" (substring boundary (match-end 0))))
500 (if (not (or mime-mc-omit-micalg
502 (cdr (assoc (cdr key) mime-mc-micalg-alist)))
505 (message "Detecting the value of `micalg'...")
507 (if (let ((mc-passwd-timeout 60)) ;; Don't deactivate passwd.
508 (mime-mc-gpg-process-region
510 (list "--clearsign" "--armor" "--batch"
511 "--verbose" "--local-user" (cdr key))
515 (std11-narrow-to-header)
517 (downcase (or (std11-fetch-field "Hash") "md5"))
519 (set-alist 'mime-mc-micalg-alist (cdr key) micalg)
521 (or mc-passwd-timeout (mc-deactivate-passwd t))
524 (if (or mime-mc-omit-micalg micalg)
525 (let ((cur (current-buffer))
527 (message "Signing as %s ..." (car key))
528 (if (with-temp-buffer
529 (insert-buffer-substring cur start end)
530 (goto-char (point-min))
537 (mime-mc-gpg-process-region (point-min) (point-max)
538 passwd pgp-path args parser
539 buffer boundary comment)
540 (goto-char (point-min))
541 (while (search-forward "\r\n" nil t)
544 (setq result (buffer-string))))
546 (delete-region (goto-char start) end)
550 (goto-char (point-min))
553 --[[multipart/signed; protocol=\"application/pgp-signature\";
554 boundary=\"%s\"%s][7bit]]\n"
556 (if mime-mc-omit-micalg
558 (concat "; micalg=pgp-" micalg)
561 (message "Signing as %s ... Done." (car key))
567 (defun mime-mc-gpg-encrypt-region (recipients start end &optional id sign)
568 (if (not (fboundp 'mc-gpg-encrypt-region))
571 (let* ((mc-pgp-always-sign (if (eq sign 'maybe)
574 (comment (mime-mc-comment))
575 (mc-gpg-comment (if comment "DUMMY")))
577 (mc-gpg-encrypt-region
578 (mc-split "\\([ \t\n]*,[ \t\n]*\\)+" recipients)
581 (mime-mc-replace-comment-field comment)
585 ;;; @ PGP 5.0i functions
588 (defun mime-mc-pgp50-process-region
589 (beg end passwd program args parser &optional buffer boundary comment)
590 "Similar to `mc-pgp50-process-region', however enclose an processed data
591 with BOUNDARY if it is specified and replace the comment field with the
592 optional argument COMMENT if it is specified."
593 (let ((obuf (current-buffer))
594 (process-connection-type nil)
595 (shell-file-name mime-mc-shell-file-name)
596 (shell-command-switch mime-mc-shell-command-switch)
597 mybuf result rgn proc results)
599 (setq args (cons "+comment=DUMMY" args))
602 (catch ;; Returns non-nil if success, otherwise nil with error message.
603 'mime-mc-pgp50-process-region-done
605 (setq mybuf (or buffer (generate-new-buffer " *mailcrypt temp")))
609 (buffer-disable-undo mybuf)
611 (apply 'start-process-shell-command "*PGP*" mybuf program
614 ;; Now hand the process to the parser, which returns the exit
615 ;; status of the dead process and the limits of the region
616 ;; containing the PGP results.
618 (setq results (funcall parser proc obuf beg end mybuf passwd))
621 (throw 'mime-mc-pgp50-process-region-done nil)
623 (setq result (car results))
624 (setq rgn (cadr results))
626 ;; Hack to force a status_notify() in Emacs 19.29
629 ;; replace comment string
630 (if (and comment (consp rgn))
631 (setcdr rgn (mime-mc-replace-comment-field
632 comment (car rgn) (cdr rgn)))
635 ;; Hurm. FIXME; must get better result codes.
639 ;; If the parser found something, migrate it to the old
640 ;; buffer. In particular, the parser's job is to return
641 ;; a cons of the form ( beg . end ) delimited the result
642 ;; of PGP in the new buffer.
648 (narrow-to-region beg end)
650 (insert (format "--%s\n" boundary))
651 (goto-char (point-max))
652 (insert (format "\n--%s
653 Content-Type: application/pgp-signature
654 Content-Transfer-Encoding: 7bit
657 (insert-buffer-substring mybuf (car rgn) (cdr rgn))
658 (goto-char (point-max))
659 (insert (format "\n--%s--\n" boundary))
661 (delete-region beg end)
663 (insert-buffer-substring mybuf (car rgn) (cdr rgn))
666 (delete-region (car rgn) (cdr rgn))))
668 ;; Return nil on failure and exit code on success
671 ;; Cleanup even on nonlocal exit
672 (if (and proc (eq 'run (process-status proc)))
673 (interrupt-process proc))
675 (or buffer (null mybuf) (kill-buffer mybuf))
678 (defun mime-mc-pgp50-sign-parser (proc oldbuf start end newbuf passwd)
679 ;; This function is a copy of `mc-pgp50-sign-parser', however it is
680 ;; modified for parsing a detached sign.
681 (let (result results rgn)
682 ;; (setenv "PGPPASSFD" "0")
684 (goto-char (point-max))
688 (message "Sending passphrase...")
689 (expect-send (concat passwd "\n"))
690 (or mc-passwd-timeout (mc-deactivate-passwd t))
691 (expect "No files specified. Using stdin."
692 (message "Passphrase sent. Signing...")
694 (process-send-region proc start end)
696 (process-send-eof proc)
698 ;; Test output of the program, looking for
702 ;; OPTION 1: Great! The data is now signed!
703 ("-----END PGP SIGNATURE-----"
705 ;; Catch the exit status.
706 (setq result (process-exit-status proc))
707 (delete-process proc)
708 (message "Signing complete.")
710 ;; Delete everything preceding the signed data.
711 (goto-char (point-max))
713 ;; "-----BEGIN PGP SIGNED MESSAGE-----" nil t)
714 "-----BEGIN PGP SIGNATURE-----" nil t)
715 (delete-region (point-min) (match-beginning 0))
716 (setq rgn (point-min))
718 ;; Convert out CR/NL -> NL
719 (goto-char (point-min))
720 (while (search-forward "\r\n" nil t)
721 (replace-match "\n"))
723 ;; Delete everything after the signature.
724 (goto-char (point-min))
726 "-----END PGP SIGNATURE-----\n" nil t)
727 (delete-region (match-end 0) (point-max))
729 ;; Return the exit status, with the region
731 (setq rgn (cons rgn (point-max)))
732 (setq results (list result rgn)))
735 ;; OPTION 1.a: The data is now signed, but is 8bit data.
736 ("-----END PGP MESSAGE-----"
738 ;; Catch the exit status.
739 (setq result (process-exit-status proc))
740 (delete-process proc)
741 (message "Signing complete.")
743 ;; Delete everything preceding the signed data.
744 (goto-char (point-max))
746 "-----BEGIN PGP MESSAGE-----" nil t)
747 (delete-region (point-min) (match-beginning 0))
748 (setq rgn (point-min))
750 ;; Convert out CR/NL -> NL
751 (goto-char (point-min))
752 (while (search-forward "\r\n" nil t)
753 (replace-match "\n"))
755 ;; Delete everything after the signature.
756 (goto-char (point-min))
758 "-----END PGP MESSAGE-----\n" nil t)
759 (delete-region (match-end 0) (point-max))
761 ;; Return the exit status, with the region
763 (setq rgn (cons rgn (point-max)))
764 (setq results (list result rgn)))
767 ;; OPTION 2: Awww...bad passphrase!
768 ("Enter pass phrase:"
769 (mc-deactivate-passwd t)
770 (interrupt-process proc)
771 (delete-process proc)
773 ;; Return the bad news.
774 (setq results '("Incorrect passphrase" nil)))
776 ;; OPTION 3: The program exits.
779 (process-exit-status proc) nil)))))))
782 (defun mime-mc-pgp50-sign-region (start end &optional id unclear boundary)
783 (if (not (fboundp 'mc-pgp50-sign-parser))
786 (let ((process-environment process-environment)
787 (buffer (get-buffer-create mc-buffer-name))
790 (function mime-mc-pgp50-sign-parser)
791 (function mc-pgp50-sign-parser)))
792 (pgp-path mc-pgp50-pgps-path)
794 (comment (mime-mc-comment))
796 (setq key (mc-pgp50-lookup-key (or id mc-pgp50-user-id)))
800 (format "PGP passphrase for %s (%s): " (car key) (cdr key))))
801 (setenv "PGPPASSFD" "0")
802 (setq args (if boundary
803 (list "-fbat" "+verbose=1" "+language=us" "+batchmode"
805 (list "-fat" "+verbose=1" "+language=us"
806 (format "+clearsig=%s" (if unclear "off" "on"))
807 "+batchmode" "-u" (cdr key))
810 (not (or mime-mc-omit-micalg
812 (cdr (assoc (cdr key) mime-mc-micalg-alist)))
815 (message "Detecting the value of `micalg'...")
817 (if (let ((mc-passwd-timeout 60)) ;; Don't deactivate passwd.
818 (mime-mc-pgp50-process-region
820 (list "-fat" "+verbose=1" "+language=us" "+clearsig=on"
821 "+batchmode" "-u" (cdr key))
822 (function mc-pgp50-sign-parser) buffer nil)
825 (std11-narrow-to-header)
826 (setq micalg (downcase (or (std11-fetch-field "Hash") "md5")))
827 (set-alist 'mime-mc-micalg-alist (cdr key) micalg)
829 (or mc-passwd-timeout (mc-deactivate-passwd t))
832 (if (or mime-mc-omit-micalg micalg)
834 (message "Signing as %s ..." (car key))
835 (if (mime-mc-pgp50-process-region
836 start end passwd pgp-path args parser buffer boundary comment)
840 (goto-char (point-min))
843 --[[multipart/signed; protocol=\"application/pgp-signature\";
844 boundary=\"%s\"%s][7bit]]\n"
846 (if mime-mc-omit-micalg
848 (concat "; micalg=pgp-" micalg)
851 (message "Signing as %s ... Done." (car key))
857 (defun mime-mc-pgp50-encrypt-region (recipients start end &optional id sign)
858 (if (not (fboundp 'mc-pgp50-encrypt-region))
861 (let ((mc-pgp-always-sign (if (eq sign 'maybe)
864 (comment (mime-mc-comment))
865 (mc-pgp50-comment "DUMMY"))
867 (mc-pgp50-encrypt-region
868 (mc-split "\\([ \t\n]*,[ \t\n]*\\)+" recipients)
871 (mime-mc-replace-comment-field comment)
875 ;;; @ PGP 2.6 functions
878 (defun mime-mc-process-region
879 (beg end passwd program args parser &optional buffer boundary comment)
880 "Similar to `mc-pgp-process-region', however enclose an processed data
881 with BOUNDARY if it is specified and replace the comment field with the
882 optional argument COMMENT if it is specified."
883 (let ((obuf (current-buffer))
884 (process-connection-type nil)
885 mybuf result rgn proc)
887 (setq args (cons "+comment=DUMMY" args))
891 (setq mybuf (or buffer (generate-new-buffer " *mailcrypt temp")))
895 (buffer-disable-undo mybuf)
897 (apply 'start-process "*PGP*" mybuf program args))
900 (process-send-string proc (concat passwd "\n"))
901 (or mc-passwd-timeout (mc-deactivate-passwd t))))
902 (process-send-region proc beg end)
903 (process-send-eof proc)
904 (while (eq 'run (process-status proc))
905 (accept-process-output proc 5))
906 (setq result (process-exit-status proc))
907 ;; Hack to force a status_notify() in Emacs 19.29
908 (delete-process proc)
910 (goto-char (point-max))
911 (if (re-search-backward "\nProcess \\*PGP.*\n\\'" nil t)
912 (delete-region (match-beginning 0) (match-end 0)))
913 (goto-char (point-min))
915 (while (search-forward "\r\n" nil t)
916 (replace-match "\n"))
917 ;; Hurm. FIXME; must get better result codes.
919 (error "%s exited abnormally: '%s'" program result)
920 ;; replace comment string
922 (mime-mc-replace-comment-field comment)
924 (setq rgn (funcall parser result))
925 ;; If the parser found something, migrate it
931 (narrow-to-region beg end)
933 (insert (format "--%s\n" boundary))
934 (goto-char (point-max))
935 (insert (format "\n--%s
936 Content-Type: application/pgp-signature
937 Content-Transfer-Encoding: 7bit
940 (insert-buffer-substring mybuf (car rgn) (cdr rgn))
941 (goto-char (point-max))
942 (insert (format "\n--%s--\n" boundary))
944 (delete-region beg end)
946 (insert-buffer-substring mybuf (car rgn) (cdr rgn))
949 (delete-region (car rgn) (cdr rgn)))))
950 ;; Return nil on failure and exit code on success
952 ;; Cleanup even on nonlocal exit
953 (if (and proc (eq 'run (process-status proc)))
954 (interrupt-process proc))
956 (or buffer (null mybuf) (kill-buffer mybuf)))))
958 (defun mime-mc-pgp-sign-region (start end &optional id unclear boundary)
959 (if (not (fboundp 'mc-pgp-generic-parser))
962 (let ((process-environment process-environment)
963 (buffer (get-buffer-create mc-buffer-name))
965 (parser (function mc-pgp-generic-parser))
966 (pgp-path mc-pgp-path)
967 (comment (mime-mc-comment))
969 (setq key (mc-pgp-lookup-key (or id mc-pgp-user-id)))
973 (format "PGP passphrase for %s (%s): " (car key) (cdr key))))
974 (setenv "PGPPASSFD" "0")
980 (list "+verbose=1" "+language=en"
981 (format "+clearsig=%s" (if unclear "off" "on"))
982 "+batchmode" "-u" (cdr key))))
983 (message "Signing as %s ..." (car key))
984 (if (mime-mc-process-region
985 start end passwd pgp-path args parser buffer boundary comment)
989 (goto-char (point-min))
992 --[[multipart/signed; protocol=\"application/pgp-signature\";
993 boundary=\"%s\"%s][7bit]]\n"
995 (if mime-mc-omit-micalg
1000 (message "Signing as %s ... Done." (car key))
1004 (defun mime-mc-pgp-encrypt-region (recipients start end &optional id sign)
1005 (if (not (fboundp 'mc-pgp-encrypt-region))
1008 (let ((mc-pgp-always-sign (if (eq sign 'maybe)
1011 (comment (mime-mc-comment))
1012 (mc-pgp-comment "DUMMY"))
1014 (mc-pgp-encrypt-region
1015 (mc-split "\\([ \t\n]*,[ \t\n]*\\)+" recipients)
1018 (mime-mc-replace-comment-field comment)
1027 ;;; mime-mc.el ends here