1 ;;; mime-mc.el --- Mailcrypt interface for SEMI
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")
43 (mc-gpg-encrypt-region "mc-gpg")
44 (mc-gpg-lookup-key "mc-gpg")
45 (mc-pgp50-encrypt-region "mc-pgp5")
46 (mc-pgp50-lookup-key "mc-pgp5")
47 (mc-pgp-encrypt-region "mc-pgp")
48 (mc-pgp-lookup-key "mc-pgp")
49 (mc-snarf-keys "mc-toplev")
52 (defcustom mime-mc-shell-file-name "/bin/sh"
53 "File name to load inferior shells from. Bourne shell or its equivalent
54 \(not tcsh) is needed for \"2>\"."
58 (defcustom mime-mc-omit-micalg nil
59 "Non-nil value means to omit the micalg parameter for multipart/signed.
60 See draft-yamamoto-openpgp-mime-00.txt (OpenPGP/MIME) for more information."
64 (defcustom mime-mc-comment-alist
65 (let ((product-name (mime-product-name mime-user-interface-product))
67 (function number-to-string)
68 (mime-product-version mime-user-interface-product)
70 (codename (mime-product-code-name mime-user-interface-product))
72 (setq string (format "Processed by Mailcrypt %s under %s %s%s"
73 mc-version product-name version
74 (if (string-match "^[ -~]+$" codename)
75 (concat " - \"" codename "\"")
77 (list (cons 'gpg string)
80 "Alist of the schemes and strings of the comment field to appear in ASCII
83 :type '(repeat (cons :format "%v"
84 (choice (choice-item :tag "GnuPG" gpg)
85 (choice-item :tag "PGP 5.0i" pgp50)
86 (choice-item :tag "PGP 2.6" pgp))
87 (string :tag "Comment"))))
89 (defmacro mime-mc-comment ()
90 "Return a string of the comment field."
91 '(or (cdr (assq pgp-version mime-mc-comment-alist))
92 (symbol-value (intern (format "mc-%s-comment" pgp-version)))))
95 ;;; @ Internal variable
98 (defvar mime-mc-micalg-alist nil
99 "Alist of KeyID and the value of message integrity check algorithm.")
102 ;;; @ External variables (for avoid byte compile warnings)
105 (defvar mc-gpg-extra-args)
107 (defvar mc-gpg-user-id)
108 (defvar mc-pgp50-pgps-path)
109 (defvar mc-pgp50-user-id)
111 (defvar mc-pgp-user-id)
114 ;;; @ Generic functions
117 (defun mime-mc-setversion (&optional version)
118 "Select `pgp-version' and `mc-default-scheme' if possible.
119 VERSION should be a string or a symbol."
121 (let ((oldversion pgp-version)
122 (table '(("GnuPG" . gpg) ("PGP 5.0i" . pgp50) ("PGP 2.6" . pgp)
123 ("gnupg" . gpg) ("gpg" . gpg) ("pgp5" . pgp50)
124 ("pgp50" . pgp50) ("pgp2" . pgp) ("pgp" . pgp)
125 ("5.0" . pgp50) ("2.6" . pgp))))
127 (setq version (completing-read
128 (format "Select PGP version (currently %s): "
129 (car (rassoc oldversion table)))
131 pgp-version (or (cdr (assoc version table))
133 (if (stringp version)
134 (setq pgp-version (or (cdr (assoc version table)) oldversion))
135 (if (memq version '(gpg pgp50 pgp))
136 (setq pgp-version version)
140 (cdr (assq pgp-version
141 '((gpg . "gpg") (pgp50 . "5.0") (pgp . "2.6"))))
144 (message "PGP version set to %s." (car (rassq pgp-version table)))
147 (defun mime-mc-replace-comment-field (comment &optional start end)
148 (let ((regexp (if (eq 'pgp pgp-version)
149 "-----BEGIN PGP.*-----\nVersion:"
150 "^-----BEGIN PGP.*\n")))
153 (narrow-to-region (or start (point-min)) (or end (point-max)))
154 (goto-char (point-min))
155 (while (re-search-forward regexp nil t)
158 (narrow-to-region (point)
159 (if (search-forward "\n\n" nil t)
162 (goto-char (point-min))
163 (if (re-search-forward "^Comment:.*$" nil t)
164 (replace-match (concat "Comment: " comment))
168 (defun mime-mc-insert-public-key (&optional userid)
169 (let ((not-loaded (not (fboundp (intern (format "mc-%s-insert-public-key"
171 (comment (mime-mc-comment))
172 (scheme (intern (format "mc-scheme-%s" pgp-version))))
173 (cond ((eq 'gpg pgp-version)
177 (let ((mc-gpg-comment (if comment "DUMMY")))
178 (mc-insert-public-key userid scheme))
180 ((eq 'pgp50 pgp-version)
184 (let ((mc-pgp50-comment (if comment "DUMMY")))
185 (mc-insert-public-key userid scheme))
191 (let ((mc-pgp-comment (if comment "DUMMY")))
192 (mc-insert-public-key userid scheme))
195 (mime-mc-replace-comment-field comment)
198 (defun mime-mc-verify ()
199 (let ((mc-default-scheme (intern (format "mc-scheme-%s" pgp-version))))
203 (defun mime-mc-decrypt ()
204 (let ((mc-default-scheme (intern (format "mc-scheme-%s" pgp-version))))
208 (defun mime-mc-snarf-keys ()
209 (let ((mc-default-scheme (intern (format "mc-scheme-%s" pgp-version))))
214 ;;; @ GnuPG functions
217 (defun mime-mc-gpg-process-region
218 (beg end passwd program args parser bufferdummy &optional boundary comment)
219 "Similar to `mc-gpg-process-region', however enclose an processed data
220 with BOUNDARY if it is specified and replace the comment field with the
221 optional argument COMMENT if it is specified."
222 (let ((obuf (current-buffer))
223 (process-connection-type nil)
224 (shell-file-name mime-mc-shell-file-name)
227 stderr-tempfilename stderr-buf
228 status-tempfilename status-buf
229 proc rc status parser-result
231 (mc-gpg-debug-print (format
232 "(mc-gpg-process-region beg=%s end=%s passwd=%s program=%s args=%s parser=%s bufferdummy=%s boundary=%s comment=%s)"
233 beg end passwd program args parser bufferdummy
235 (setq stderr-tempfilename
236 (make-temp-name (expand-file-name "mailcrypt-gpg-stderr-"
238 (setq status-tempfilename
239 (make-temp-name (expand-file-name "mailcrypt-gpg-status-"
243 ;; get output places ready
244 (setq mybuf (get-buffer-create " *mailcrypt stdout temp"))
248 (buffer-disable-undo mybuf)
251 (setq args (append '("--passphrase-fd" "0") args)))
252 (setq args (append (list (concat "2>" stderr-tempfilename)) args))
253 (setq args (append (list (concat "3>" status-tempfilename)) args))
254 (setq args (append '("--status-fd" "3") args))
257 (setq args (append '("--comment" "DUMMY") args))
260 (if mc-gpg-extra-args
261 (setq args (append mc-gpg-extra-args args)))
263 (mc-gpg-debug-print (format "prog is %s, args are %s"
265 (mapconcat '(lambda (x)
270 (apply 'start-process-shell-command "*GPG*" mybuf
272 ;; send in passwd if necessary
275 (process-send-string proc (concat passwd "\n"))
276 (or mc-passwd-timeout (mc-deactivate-passwd t))))
277 ;; send in the region
278 (process-send-region proc beg end)
280 (process-send-eof proc)
281 ;; wait for it to finish
282 (while (eq 'run (process-status proc))
283 (accept-process-output proc 5))
284 ;; remember result codes
285 (setq status (process-status proc))
286 (setq rc (process-exit-status proc))
287 (mc-gpg-debug-print (format "prog finished, rc=%s" rc))
289 ;; Hack to force a status_notify() in Emacs 19.29
290 (delete-process proc)
292 ;; remove the annoying "yes your process has finished" message
294 (goto-char (point-max))
295 (if (re-search-backward "\nProcess \\*GPG.*\n\\'" nil t)
296 (delete-region (match-beginning 0) (match-end 0)))
297 (goto-char (point-min))
299 (while (search-forward "\r\n" nil t)
300 (replace-match "\n"))
302 ;; ponder process death: signal, not just rc!=0
303 (if (or (eq 'stop status) (eq 'signal status))
305 (error "%s exited abnormally: '%s'" program rc) ;;is rc a string?
309 (error "%s could not be found" program) ;; at least on my system
313 (setq stderr-buf (get-buffer-create " *mailcrypt stderr temp"))
314 (buffer-disable-undo stderr-buf)
315 (set-buffer stderr-buf)
317 (insert-file-contents stderr-tempfilename)
320 (setq status-buf (get-buffer-create " *mailcrypt status temp"))
321 (buffer-disable-undo status-buf)
322 (set-buffer status-buf)
324 (insert-file-contents status-tempfilename)
326 ;; replace comment string
329 (mime-mc-replace-comment-field comment)
333 (setq parser-result (funcall parser mybuf stderr-buf status-buf rc))
334 (mc-gpg-debug-print (format " parser returned %s" parser-result))
336 ;; what did the parser tell us?
337 (if (car parser-result)
338 ;; yes, replace region
343 (narrow-to-region beg end)
345 (insert (format "--%s\n" boundary))
346 (goto-char (point-max))
347 (insert (format "\n--%s
348 Content-Type: application/pgp-signature
349 Content-Transfer-Encoding: 7bit
352 (insert-buffer-substring mybuf)
353 (goto-char (point-max))
354 (insert (format "\n--%s--\n" boundary))
356 (delete-region beg end)
358 (insert-buffer-substring mybuf)
365 (if (and proc (eq 'run (process-status proc)))
366 ;; it is still running. kill it.
367 (interrupt-process proc))
369 (delete-file stderr-tempfilename)
370 (delete-file status-tempfilename)
371 ;; kill off temporary buffers (which would be useful for debugging)
372 (if t ;; nil for easier debugging
374 (if (get-buffer " *mailcrypt stdout temp")
375 (kill-buffer " *mailcrypt stdout temp"))
376 (if (get-buffer " *mailcrypt stderr temp")
377 (kill-buffer " *mailcrypt stderr temp"))
378 (if (get-buffer " *mailcrypt status temp")
379 (kill-buffer " *mailcrypt status temp"))
383 (defun mime-mc-gpg-sign-region (start end &optional id unclear boundary)
384 (if (not (fboundp 'mc-gpg-insert-parser))
387 (let ((buffer (get-buffer-create mc-buffer-name))
389 (parser (function mc-gpg-insert-parser))
390 (pgp-path mc-gpg-path)
392 (comment (mime-mc-comment))
394 (setq key (mc-gpg-lookup-key (or id mc-gpg-user-id)))
398 (format "GnuPG passphrase for %s (%s): " (car key) (cdr key))))
406 (list "--armor" "--batch" "--textmode" "--verbose"
407 "--local-user" (cdr key))
411 (if (string-match "^pgp-" boundary)
413 (concat "gpg-" (substring boundary (match-end 0))))
415 (if (not (or mime-mc-omit-micalg
417 (cdr (assoc (cdr key) mime-mc-micalg-alist)))
420 (message "Detecting the value of `micalg'...")
422 (mime-mc-gpg-process-region
424 (list "--clearsign" "--armor" "--batch" "--textmode"
425 "--verbose" "--local-user" (cdr key))
428 (std11-narrow-to-header)
430 (downcase (or (std11-fetch-field "Hash") "md5"))
432 (set-alist 'mime-mc-micalg-alist (cdr key) micalg)
435 (message "Signing as %s ..." (car key))
436 (if (mime-mc-gpg-process-region
437 start end passwd pgp-path args parser buffer boundary comment)
441 (goto-char (point-min))
444 --[[multipart/signed; protocol=\"application/pgp-signature\";
445 boundary=\"%s\"%s][7bit]]\n"
447 (if mime-mc-omit-micalg
449 (concat "; micalg=pgp-" micalg)
452 (message "Signing as %s ... Done." (car key))
456 (defun mime-mc-gpg-encrypt-region (recipients start end &optional id sign)
457 (if (not (fboundp 'mc-gpg-encrypt-region))
460 (let ((mc-pgp-always-sign (if (eq sign 'maybe)
463 (comment (mime-mc-comment)))
465 (mc-gpg-encrypt-region
466 (mc-split "\\([ \t\n]*,[ \t\n]*\\)+" recipients)
469 (mime-mc-replace-comment-field comment)
473 ;;; @ PGP 5.0i functions
476 (defun mime-mc-pgp50-process-region
477 (beg end passwd program args parser &optional buffer boundary comment)
478 "Similar to `mc-pgp50-process-region', however enclose an processed data
479 with BOUNDARY if it is specified and replace the comment field with the
480 optional argument COMMENT if it is specified."
481 (let ((obuf (current-buffer))
482 (process-connection-type nil)
483 (shell-file-name mime-mc-shell-file-name)
484 mybuf result rgn proc results)
486 (setq args (cons "+comment=DUMMY" args))
490 (setq mybuf (or buffer (generate-new-buffer " *mailcrypt temp")))
494 (buffer-disable-undo mybuf)
496 (apply 'start-process-shell-command "*PGP*" mybuf program
499 ;; Now hand the process to the parser, which returns the exit
500 ;; status of the dead process and the limits of the region
501 ;; containing the PGP results.
502 (setq results (funcall parser proc obuf beg end mybuf passwd))
503 (setq result (car results))
504 (setq rgn (cadr results))
506 ;; Hack to force a status_notify() in Emacs 19.29
509 ;; replace comment string
511 (setcdr rgn (mime-mc-replace-comment-field
512 comment (car rgn) (cdr rgn)))
515 ;; Hurm. FIXME; must get better result codes.
519 ;; If the parser found something, migrate it to the old
520 ;; buffer. In particular, the parser's job is to return
521 ;; a cons of the form ( beg . end ) delimited the result
522 ;; of PGP in the new buffer.
528 (narrow-to-region beg end)
530 (insert (format "--%s\n" boundary))
531 (goto-char (point-max))
532 (insert (format "\n--%s
533 Content-Type: application/pgp-signature
534 Content-Transfer-Encoding: 7bit
537 (insert-buffer-substring mybuf (car rgn) (cdr rgn))
538 (goto-char (point-max))
539 (insert (format "\n--%s--\n" boundary))
541 (delete-region beg end)
543 (insert-buffer-substring mybuf (car rgn) (cdr rgn))
546 (delete-region (car rgn) (cdr rgn))))
548 ;; Return nil on failure and exit code on success
551 ;; Cleanup even on nonlocal exit
552 (if (and proc (eq 'run (process-status proc)))
553 (interrupt-process proc))
555 (or buffer (null mybuf) (kill-buffer mybuf))
558 (defun mime-mc-pgp50-sign-parser (proc oldbuf start end newbuf passwd)
559 ;; This function is a copy of `mc-pgp50-sign-parser', however it is
560 ;; modified for parsing a detached sign.
561 (let (result results rgn)
562 ;; (setenv "PGPPASSFD" "0")
564 (goto-char (point-max))
568 (message "Sending passphrase...")
569 (expect-send (concat passwd "\n"))
570 (or mc-passwd-timeout (mc-deactivate-passwd t))
571 (expect "No files specified. Using stdin."
572 (message "Passphrase sent. Signing...")
574 (process-send-region proc start end)
576 (process-send-eof proc)
578 ;; Test output of the program, looking for
582 ;; OPTION 1: Great! The data is now signed!
583 ("-----END PGP SIGNATURE-----"
585 ;; Catch the exit status.
586 (setq result (process-exit-status proc))
587 (delete-process proc)
588 (message "Signing complete.")
590 ;; Delete everything preceding the signed data.
591 (goto-char (point-max))
593 ;; "-----BEGIN PGP SIGNED MESSAGE-----" nil t)
594 "-----BEGIN PGP SIGNATURE-----" nil t)
595 (delete-region (point-min) (match-beginning 0))
596 (setq rgn (point-min))
598 ;; Convert out CR/NL -> NL
599 (goto-char (point-min))
600 (while (search-forward "\r\n" nil t)
601 (replace-match "\n"))
603 ;; Delete everything after the signature.
604 (goto-char (point-min))
606 "-----END PGP SIGNATURE-----\n" nil t)
607 (delete-region (match-end 0) (point-max))
609 ;; Return the exit status, with the region
611 (setq rgn (cons rgn (point-max)))
612 (setq results (list result rgn)))
615 ;; OPTION 1.a: The data is now signed, but is 8bit data.
616 ("-----END PGP MESSAGE-----"
618 ;; Catch the exit status.
619 (setq result (process-exit-status proc))
620 (delete-process proc)
621 (message "Signing complete.")
623 ;; Delete everything preceding the signed data.
624 (goto-char (point-max))
626 "-----BEGIN PGP MESSAGE-----" nil t)
627 (delete-region (point-min) (match-beginning 0))
628 (setq rgn (point-min))
630 ;; Convert out CR/NL -> NL
631 (goto-char (point-min))
632 (while (search-forward "\r\n" nil t)
633 (replace-match "\n"))
635 ;; Delete everything after the signature.
636 (goto-char (point-min))
638 "-----END PGP MESSAGE-----\n" nil t)
639 (delete-region (match-end 0) (point-max))
641 ;; Return the exit status, with the region
643 (setq rgn (cons rgn (point-max)))
644 (setq results (list result rgn)))
647 ;; OPTION 2: Awww...bad passphrase!
648 ("Enter pass phrase:"
649 (mc-deactivate-passwd t)
650 (interrupt-process proc)
651 (delete-process proc)
653 ;; Return the bad news.
654 (setq results '("Incorrect passphrase" nil)))
656 ;; OPTION 3: The program exits.
659 (process-exit-status proc) nil)))))))
662 (defun mime-mc-pgp50-sign-region (start end &optional id unclear boundary)
663 (if (not (fboundp 'mc-pgp50-sign-parser))
666 (let ((process-environment process-environment)
667 (buffer (get-buffer-create mc-buffer-name))
670 (function mime-mc-pgp50-sign-parser)
671 (function mc-pgp50-sign-parser)))
672 (pgp-path mc-pgp50-pgps-path)
674 (comment (mime-mc-comment))
676 (setq key (mc-pgp50-lookup-key (or id mc-pgp50-user-id)))
680 (format "PGP passphrase for %s (%s): " (car key) (cdr key))))
681 (setenv "PGPPASSFD" "0")
682 (setq args (if boundary
683 (list "-fbat" "+verbose=1" "+language=us" "+batchmode"
685 (list "-fat" "+verbose=1" "+language=us"
686 (format "+clearsig=%s" (if unclear "off" "on"))
687 "+batchmode" "-u" (cdr key))
690 (not (or mime-mc-omit-micalg
692 (cdr (assoc (cdr key) mime-mc-micalg-alist)))
695 (message "Detecting the value of `micalg'...")
697 (mime-mc-pgp50-process-region
699 (list "-fat" "+verbose=1" "+language=us" "+clearsig=on"
700 "+batchmode" "-u" (cdr key))
701 (function mc-pgp50-sign-parser) buffer nil)
702 (std11-narrow-to-header)
703 (setq micalg (downcase (or (std11-fetch-field "Hash") "md5")))
704 (set-alist 'mime-mc-micalg-alist (cdr key) micalg)
706 (message "Signing as %s ..." (car key))
707 (if (mime-mc-pgp50-process-region
708 start end passwd pgp-path args parser buffer boundary comment)
712 (goto-char (point-min))
715 --[[multipart/signed; protocol=\"application/pgp-signature\";
716 boundary=\"%s\"%s][7bit]]\n"
718 (if mime-mc-omit-micalg
720 (concat "; micalg=pgp-" micalg)
723 (message "Signing as %s ... Done." (car key))
727 (defun mime-mc-pgp50-encrypt-region (recipients start end &optional id sign)
728 (if (not (fboundp 'mc-pgp50-encrypt-region))
731 (let ((mc-pgp-always-sign (if (eq sign 'maybe)
734 (comment (mime-mc-comment))
735 (mc-pgp50-comment "DUMMY"))
737 (mc-pgp50-encrypt-region
738 (mc-split "\\([ \t\n]*,[ \t\n]*\\)+" recipients)
741 (mime-mc-replace-comment-field comment)
745 ;;; @ PGP 2.6 functions
748 (defun mime-mc-process-region
749 (beg end passwd program args parser &optional buffer boundary comment)
750 "Similar to `mc-pgp-process-region', however enclose an processed data
751 with BOUNDARY if it is specified and replace the comment field with the
752 optional argument COMMENT if it is specified."
753 (let ((obuf (current-buffer))
754 (process-connection-type nil)
755 mybuf result rgn proc)
757 (setq args (cons "+comment=DUMMY" args))
761 (setq mybuf (or buffer (generate-new-buffer " *mailcrypt temp")))
765 (buffer-disable-undo mybuf)
767 (apply 'start-process "*PGP*" mybuf program args))
770 (process-send-string proc (concat passwd "\n"))
771 (or mc-passwd-timeout (mc-deactivate-passwd t))))
772 (process-send-region proc beg end)
773 (process-send-eof proc)
774 (while (eq 'run (process-status proc))
775 (accept-process-output proc 5))
776 (setq result (process-exit-status proc))
777 ;; Hack to force a status_notify() in Emacs 19.29
778 (delete-process proc)
780 (goto-char (point-max))
781 (if (re-search-backward "\nProcess \\*PGP.*\n\\'" nil t)
782 (delete-region (match-beginning 0) (match-end 0)))
783 (goto-char (point-min))
785 (while (search-forward "\r\n" nil t)
786 (replace-match "\n"))
787 ;; Hurm. FIXME; must get better result codes.
789 (error "%s exited abnormally: '%s'" program result)
790 ;; replace comment string
792 (mime-mc-replace-comment-field comment)
794 (setq rgn (funcall parser result))
795 ;; If the parser found something, migrate it
801 (narrow-to-region beg end)
803 (insert (format "--%s\n" boundary))
804 (goto-char (point-max))
805 (insert (format "\n--%s
806 Content-Type: application/pgp-signature
807 Content-Transfer-Encoding: 7bit
810 (insert-buffer-substring mybuf (car rgn) (cdr rgn))
811 (goto-char (point-max))
812 (insert (format "\n--%s--\n" boundary))
814 (delete-region beg end)
816 (insert-buffer-substring mybuf (car rgn) (cdr rgn))
819 (delete-region (car rgn) (cdr rgn)))))
820 ;; Return nil on failure and exit code on success
822 ;; Cleanup even on nonlocal exit
823 (if (and proc (eq 'run (process-status proc)))
824 (interrupt-process proc))
826 (or buffer (null mybuf) (kill-buffer mybuf)))))
828 (defun mime-mc-pgp-sign-region (start end &optional id unclear boundary)
829 (if (not (fboundp 'mc-pgp-generic-parser))
832 (let ((process-environment process-environment)
833 (buffer (get-buffer-create mc-buffer-name))
835 (parser (function mc-pgp-generic-parser))
836 (pgp-path mc-pgp-path)
837 (comment (mime-mc-comment))
839 (setq key (mc-pgp-lookup-key (or id mc-pgp-user-id)))
843 (format "PGP passphrase for %s (%s): " (car key) (cdr key))))
844 (setenv "PGPPASSFD" "0")
850 (list "+verbose=1" "+language=en"
851 (format "+clearsig=%s" (if unclear "off" "on"))
852 "+batchmode" "-u" (cdr key))))
853 (message "Signing as %s ..." (car key))
854 (if (mime-mc-process-region
855 start end passwd pgp-path args parser buffer boundary comment)
859 (goto-char (point-min))
862 --[[multipart/signed; protocol=\"application/pgp-signature\";
863 boundary=\"%s\"%s][7bit]]\n"
865 (if mime-mc-omit-micalg
870 (message "Signing as %s ... Done." (car key))
874 (defun mime-mc-pgp-encrypt-region (recipients start end &optional id sign)
875 (if (not (fboundp 'mc-pgp-encrypt-region))
878 (let ((mc-pgp-always-sign (if (eq sign 'maybe)
881 (comment (mime-mc-comment))
882 (mc-pgp-comment "DUMMY"))
884 (mc-pgp-encrypt-region
885 (mc-split "\\([ \t\n]*,[ \t\n]*\\)+" recipients)
888 (mime-mc-replace-comment-field comment)
897 ;;; mime-mc.el ends here