* New branch for developing PGP 5.0i and GnuPG support. semi-pgpgpg_00
authoryamaoka <yamaoka>
Wed, 24 Mar 1999 11:03:10 +0000 (11:03 +0000)
committeryamaoka <yamaoka>
Wed, 24 Mar 1999 11:03:10 +0000 (11:03 +0000)
ChangeLog
NEWS
README.en
mime-edit.el
mime-mc.el
mime-pgp.el
mime-ui-en.sgml
mime-ui-ja.sgml
semi-def.el
semi-setup.el

index 1da428f..17b5ba8 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,61 @@
+1999-03-24  Katsumi Yamaoka   <yamaoka@jpl.org>
+
+       * NEWS, README.en, mime-ui-en.sgml, mime-ui-ja.sgml: Update for
+       PGP 5.0i and GnuPG support.
+
+       * semi-def.el (TopLevel): Autoload "mc-pgp5" and "mc-gpg".
+       (pgp-function): Modify for extended `pgp-function-alist'.
+       (pgp-function-alist): Extend for supporting PGP 5.0i and GnuPG.
+       (pgp-version): New user option.
+
+       * mime-pgp.el (mime-pgp-good-signature-post-function-pgp50-us): New
+       function.
+
+       (mime-verify-application/pgp-signature): Support PGP 5.0i and
+       GnuPG.
+       (mime-pgp-check-signature): Likewise.
+
+       (mime-pgp-key-expected-regexp,
+       mime-pgp-good-signature-post-function,
+       mime-pgp-good-signature-regexp, mime-pgp-default-language,
+       mime-pgp-command): New macros.
+
+       (mime-pgp-key-expected-regexp-alist): Use `defcustom'; extend for
+       supporting PGP 5.0i and GnuPG.
+       (mime-pgp-good-signature-regexp-alist): Likewise.
+
+       (mime-pgp-default-language-alist, mime-pgp-command-alist): New
+       user options.
+       (mime-pgp-default-language): Abolish variable. Move to
+       `mime-pgp-default-language-alist'.
+       (mime-pgp-command): Abolish variable. Move to
+       `mime-pgp-command-alist'
+
+       (TopLevel): Require `semi-def' explicitly for referring to the
+       value of `pgp-version'.
+
+       * mime-mc.el (mime-mc-pgp-encrypt-region): Load "mc-pgp" if the
+       function `mc-pgp-encrypt-region' does not exist.
+       (mime-mc-pgp-sign-region): Load "mc-pgp" if the function
+       `mc-pgp-generic-parser' does not exist.
+
+       (mime-mc-pgp50-encrypt-region, mime-mc-pgp50-sign-region,
+       mime-mc-pgp50-process-region, mime-mc-gpg-encrypt-region,
+       mime-mc-gpg-sign-region, mime-mc-gpg-process-region,
+       mime-mc-snarf-keys, mime-mc-decrypt, mime-mc-verify,
+       mime-mc-insert-public-key): New functions.
+
+       (mime-mc-pgp-generic-parser): Abolish function.
+       (TopLevel): Autoload or load some modules if they are needed
+       instead of to load "mc-pgp" first; define some variables for
+       avoiding byte-compile warnings; require `semi-def' explicitly for
+       referring to the value of `pgp-version'.
+
+       * mime-edit.el (mime-edit-encrypt-pgp-mime): Use "gpg" for the
+       prefix string of boundary if GnuPG is used.
+       (TopLevel): Require `semi-def' explicitly for referring to the
+       value of `pgp-version'.
+
 1999-03-11  MORIOKA Tomohiko  <morioka@jaist.ac.jp>
 
        * mime-edit.el (mime-charset-type-list): Add `tis-620'.
diff --git a/NEWS b/NEWS
index ad678eb..28c5a0e 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,14 @@ Copyright (C) 1998,1999 Free Software Foundation, Inc.
 
 * Changes in SEMI 1.13
 
+** PGP 5.0i and GnuPG are now supported for PGP/MIME
+
+You can select the various PGP or GnuPG commands by the new user
+option `pgp-version'.  Note that Mailcrypt 3.5.3 or later is needed
+for PGP 5.0i or GnuPG.  A user interface for editing or viewing has
+never changed.
+
+
 ** Function `mime-play-entity'
 
 Function `mime-play-entity' was renamed from `mime-raw-play-entity'
index 363cc58..66733ef 100644 (file)
--- a/README.en
+++ b/README.en
@@ -50,7 +50,15 @@ Required environment
 
        ftp://ftp.jaist.ac.jp/pub/GNU/elisp/flim/
 
-  PGP/MIME and application/pgp require mailcrypt or tiny-pgp package.
+  PGP/MIME and application/pgp require Mailcrypt or tiny-pgp package.
+  In addition, if you want to use PGP 5.0i or GnuPG for PGP/MIME, it
+  is needed that the version of Mailcrypt package is 3.5.3 or later.
+  If Mailcrypt is not installed on your system, obtain the latest
+  version from the Mailcrypt home page at:
+
+       http://www.pobox.com/~lbudney/linux/software/mailcrypt.html
+
+  and follow the instructions in the file `INSTALL'.
 
 
 Installation
index 0c04b97..ab98d43 100644 (file)
 (require 'sendmail)
 (require 'mail-utils)
 (require 'mel)
+(require 'semi-def)
 (require 'mime-view)
 (require 'signature)
 (require 'alist)
@@ -1797,7 +1798,10 @@ Parameter must be '(PROMPT CHOICE1 (CHOISE2 ...))."
                (mime-edit-translate-region beg end boundary))
               (ctype    (car ret))
               (encoding (nth 1 ret))
-              (pgp-boundary (concat "pgp-" boundary)))
+              (pgp-boundary (concat (if (eq 'gpg pgp-version)
+                                        "pgp-"
+                                      "gpg-")
+                                    boundary)))
          (goto-char beg)
          (insert header)
          (insert (format "Content-Type: %s\n" ctype))
index 7e5cb26..7312e48 100644 (file)
@@ -1,9 +1,10 @@
 ;;; mime-mc.el --- Mailcrypt interface for SEMI
 
-;; Copyright (C) 1996,1997,1998 MORIOKA Tomohiko
+;; Copyright (C) 1996,1997,1998,1999 MORIOKA Tomohiko
 
 ;; Author: MORIOKA Tomohiko <morioka@jaist.ac.jp>
-;; Keywords: PGP, security, MIME, multimedia, mail, news
+;;         Katsumi Yamaoka  <yamaoka@jpl.org>
+;; Keywords: PGP, GnuPG, security, MIME, multimedia, mail, news
 
 ;; This file is part of SEMI (Secure Emacs MIME Interface).
 
 
 ;;; Code:
 
+(require 'semi-def)
 (require 'mailcrypt)
-(eval-and-compile (load "mc-pgp"))
 
-(defun mime-mc-pgp-generic-parser (result)
-  (let ((ret (mc-pgp-generic-parser result)))
-    (if (consp ret)
-       (vector (car ret)(cdr ret))
+(eval-and-compile
+  (mapcar
+   (function (lambda (elem) (apply 'autoload elem)))
+   '(
+     (mc-gpg-debug-print       "mc-gpg")
+     (mc-gpg-encrypt-region    "mc-gpg")
+     (mc-gpg-lookup-key                "mc-gpg")
+     (mc-pgp50-encrypt-region  "mc-pgp5")
+     (mc-pgp50-lookup-key      "mc-pgp5")
+     (mc-pgp-encrypt-region    "mc-pgp")
+     (mc-pgp-lookup-key                "mc-pgp")
+     (mc-snarf-keys            "mc-toplev")
+     )))
+
+(defvar mc-gpg-comment)
+(defvar mc-gpg-extra-args)
+(defvar mc-gpg-path)
+(defvar mc-gpg-user-id)
+(defvar mc-pgp50-comment)
+(defvar mc-pgp50-pgps-path)
+(defvar mc-pgp50-user-id)
+(defvar mc-pgp-comment)
+(defvar mc-pgp-path)
+(defvar mc-pgp-user-id)
+
+
+;;; @ Generic functions
+;;;
+
+(defun mime-mc-insert-public-key (&optional userid scheme)
+  (mc-insert-public-key
+   userid
+   (or scheme (intern (format "mc-scheme-%s" pgp-version)))
+   ))
+
+(defun mime-mc-verify ()
+  (let ((mc-default-scheme (intern (format "mc-scheme-%s" pgp-version))))
+    (mc-verify)
+    ))
+
+(defun mime-mc-decrypt ()
+  (let ((mc-default-scheme (intern (format "mc-scheme-%s" pgp-version))))
+    (mc-decrypt)
+    ))
+
+(defun mime-mc-snarf-keys ()
+  (let ((mc-default-scheme (intern (format "mc-scheme-%s" pgp-version))))
+    (mc-snarf-keys)
+    ))
+
+
+;;; @ GnuPG functions
+;;;
+
+(defun mime-mc-gpg-process-region
+  (beg end passwd program args parser bufferdummy boundary)
+  (let ((obuf (current-buffer))
+       (process-connection-type nil)
+       (shell-file-name "/bin/sh") ;; ??? force? need sh (not tcsh) for "2>"
+       ; other local vars
+       mybuf
+       stderr-tempfilename stderr-buf
+       status-tempfilename status-buf
+       proc rc status parser-result
+       )
+    (mc-gpg-debug-print (format
+                        "(mc-gpg-process-region beg=%s end=%s passwd=%s program=%s args=%s parser=%s bufferdummy=%s)"
+                        beg end passwd program args parser bufferdummy))
+    (setq stderr-tempfilename
+         (make-temp-name (expand-file-name "mailcrypt-gpg-stderr-"
+                                           mc-temp-directory)))
+    (setq status-tempfilename
+         (make-temp-name (expand-file-name "mailcrypt-gpg-status-"
+                                           mc-temp-directory)))
+    (unwind-protect
+       (progn
+         ;; get output places ready
+         (setq mybuf (get-buffer-create " *mailcrypt stdout temp"))
+         (set-buffer mybuf)
+         (erase-buffer)
+         (set-buffer obuf)
+         (buffer-disable-undo mybuf)
+         (if passwd
+             (setq args (append '("--passphrase-fd" "0") args)))
+         (setq args (append (list (concat "2>" stderr-tempfilename)) args))
+         (setq args (append (list (concat "3>" status-tempfilename)) args))
+         (setq args (append '("--status-fd" "3") args))
+         (if mc-gpg-extra-args
+             (setq args (append mc-gpg-extra-args args)))
+         (mc-gpg-debug-print (format "prog is %s, args are %s"
+                                     program
+                                     (mapconcat '(lambda (x)
+                                                   (format "'%s'" x))
+                                                args " ")))
+         (setq proc
+               (apply 'start-process-shell-command "*GPG*" mybuf
+                      program args))
+         ;; send in passwd if necessary
+         (if passwd
+             (progn
+               (process-send-string proc (concat passwd "\n"))
+               (or mc-passwd-timeout (mc-deactivate-passwd t))))
+         ;; send in the region
+         (process-send-region proc beg end)
+         ;; finish it off
+         (process-send-eof proc)
+         ;; wait for it to finish
+         (while (eq 'run (process-status proc))
+           (accept-process-output proc 5))
+         ;; remember result codes
+         (setq status (process-status proc))
+         (setq rc (process-exit-status proc))
+         (mc-gpg-debug-print (format "prog finished, rc=%s" rc))
+         ;; Hack to force a status_notify() in Emacs 19.29
+         (delete-process proc)
+         ;; remove the annoying "yes your process has finished" message
+         (set-buffer mybuf)
+         (goto-char (point-max))
+         (if (re-search-backward "\nProcess \\*GPG.*\n\\'" nil t)
+             (delete-region (match-beginning 0) (match-end 0)))
+         (goto-char (point-min))
+         ;; CRNL -> NL
+         (while (search-forward "\r\n" nil t)
+           (replace-match "\n"))
+         ;; ponder process death: signal, not just rc!=0
+         (if (or (eq 'stop status) (eq 'signal status))
+             ;; process died
+             (error "%s exited abnormally: '%s'" program rc) ;;is rc a string?
+           )
+         (if (= 127 rc)
+             (error "%s could not be found" program) ;; at least on my system
+           )
+         ;; fill stderr buf
+         (setq stderr-buf (get-buffer-create " *mailcrypt stderr temp"))
+         (buffer-disable-undo stderr-buf)
+         (set-buffer stderr-buf)
+         (erase-buffer)
+         (insert-file-contents stderr-tempfilename)
+         ;; fill status buf
+         (setq status-buf (get-buffer-create " *mailcrypt status temp"))
+         (buffer-disable-undo status-buf)
+         (set-buffer status-buf)
+         (erase-buffer)
+         (insert-file-contents status-tempfilename)
+         ;; feed the parser
+         (set-buffer mybuf)
+         (setq parser-result (funcall parser mybuf stderr-buf status-buf rc))
+         (mc-gpg-debug-print (format " parser returned %s" parser-result))
+         ;; what did the parser tell us?
+         (if (car parser-result)
+             ;; yes, replace region
+             (progn
+               (set-buffer obuf)
+               (if boundary
+                   (save-restriction
+                     (narrow-to-region beg end)
+                     (goto-char beg)
+                     (insert (format "--%s\n" boundary))
+                     (goto-char (point-max))
+                     (insert (format "\n--%s
+Content-Type: application/pgp-signature
+Content-Transfer-Encoding: 7bit
+
+" boundary))
+                     (insert-buffer-substring mybuf)
+                     (goto-char (point-max))
+                     (insert (format "\n--%s--\n" boundary))
+                     )
+                 (delete-region beg end)
+                 (goto-char beg)
+                 (insert-buffer-substring mybuf)
+                 )))
+         ;; return result
+         (cdr parser-result)
+         )
+      ;; cleanup forms
+      (if (and proc (eq 'run (process-status proc)))
+         ;; it is still running. kill it.
+         (interrupt-process proc))
+      (set-buffer obuf)
+      (delete-file stderr-tempfilename)
+      (delete-file status-tempfilename)
+      ;; kill off temporary buffers (which would be useful for debugging)
+      (if t ;; nil for easier debugging
+         (progn
+           (if (get-buffer " *mailcrypt stdout temp")
+               (kill-buffer " *mailcrypt stdout temp"))
+           (if (get-buffer " *mailcrypt stderr temp")
+               (kill-buffer " *mailcrypt stderr temp"))
+           (if (get-buffer " *mailcrypt status temp")
+               (kill-buffer " *mailcrypt status temp"))
+           ))
       )))
 
+(defun mime-mc-gpg-sign-region (start end &optional id unclear boundary)
+  (if (not (fboundp 'mc-gpg-insert-parser))
+      (load "mc-gpg")
+    )
+  (let ((buffer (get-buffer-create mc-buffer-name))
+       passwd args key
+       (parser (function mc-gpg-insert-parser))
+       (pgp-path mc-gpg-path)
+       )
+    (setq key (mc-gpg-lookup-key (or id mc-gpg-user-id)))
+    (setq passwd
+         (mc-activate-passwd
+          (cdr key)
+          (format "GnuPG passphrase for %s (%s): " (car key) (cdr key))))
+    (setq args
+         (cons
+          (if boundary
+              "--detach-sign"
+            (if unclear
+                "--sign"
+              "--clearsign"))
+          (list "--passphrase-fd" "0"
+                "--armor" "--batch" "--textmode" "--verbose"
+                "--local-user" (cdr key))))
+    (if mc-gpg-comment
+       (setq args (nconc args
+                         (list "--comment"
+                               (format "\"%s\"" mc-gpg-comment))))
+      )
+    (if (and boundary
+            (string-match "^pgp-" boundary))
+       (setq boundary
+             (concat "gpg-" (substring boundary (match-end 0))))
+      )
+    (message "Signing as %s ..." (car key))
+    (if (mime-mc-gpg-process-region
+        start end passwd pgp-path args parser buffer boundary)
+       (progn
+         (if boundary
+             (progn
+               (goto-char (point-min))
+               (insert
+                (format "\
+--[[multipart/signed; protocol=\"application/pgp-signature\";
+ boundary=\"%s\"; micalg=pgp-sha1][7bit]]\n" boundary))
+               ))
+         (message "Signing as %s ... Done." (car key))
+         t)
+      nil)))
+
+(defun mime-mc-gpg-encrypt-region (recipients start end &optional id sign)
+  (if (not (fboundp 'mc-gpg-encrypt-region))
+      (load "mc-gpg")
+    )
+  (let ((mc-pgp-always-sign (if (eq sign 'maybe)
+                               mc-pgp-always-sign
+                             'never)))
+    (mc-gpg-encrypt-region
+     (mc-split "\\([ \t\n]*,[ \t\n]*\\)+" recipients)
+     start end id nil)
+    ))
+
+
+;;; @ PGP 5.0i functions
+;;;
+
+(defun mime-mc-pgp50-process-region
+  (beg end passwd program args parser &optional buffer boundary)
+  (let ((obuf (current-buffer))
+       (process-connection-type nil)
+       (shell-file-name "/bin/sh")
+       mybuf result rgn proc results)
+    (unwind-protect
+       (progn
+         (setq mybuf (or buffer (generate-new-buffer " *mailcrypt temp")))
+         (set-buffer mybuf)
+         (erase-buffer)
+         (set-buffer obuf)
+         (buffer-disable-undo mybuf)
+         (setq proc
+               (apply 'start-process-shell-command "*PGP*" mybuf program
+                      "2>&1" args))
+         ;; Now hand the process to the parser, which returns the exit
+         ;; status of the dead process and the limits of the region
+         ;; containing the PGP results.
+         (setq results (funcall parser proc obuf beg end mybuf passwd))
+         (setq result  (car results))
+         (setq rgn     (cadr results))
+         ;; Hack to force a status_notify() in Emacs 19.29
+         (set-buffer mybuf)
+         ;; Hurm.  FIXME; must get better result codes.
+         (if (stringp result)
+             (mc-message result))
+         ;; If the parser found something, migrate it to the old
+         ;; buffer.  In particular, the parser's job is to return
+         ;; a cons of the form ( beg . end ) delimited the result
+         ;; of PGP in the new buffer.
+         (if (consp rgn)
+             (progn
+               (set-buffer obuf)
+               (if boundary
+                   (save-restriction
+                     (narrow-to-region beg end)
+                     (goto-char beg)
+                     (insert (format "--%s\n" boundary))
+                     (goto-char (point-max))
+                     (insert (format "\n--%s
+Content-Type: application/pgp-signature
+Content-Transfer-Encoding: 7bit
+
+" boundary))
+                     (insert-buffer-substring mybuf (car rgn) (cdr rgn))
+                     (goto-char (point-max))
+                     (insert (format "\n--%s--\n" boundary))
+                     )
+                 (delete-region beg end)
+                 (goto-char beg)
+                 (insert-buffer-substring mybuf (car rgn) (cdr rgn))
+                 )
+               (set-buffer mybuf)
+               (delete-region (car rgn) (cdr rgn))))
+         ;; Return nil on failure and exit code on success
+         (if rgn result nil))
+      ;; Cleanup even on nonlocal exit
+      (if (and proc (eq 'run (process-status proc)))
+         (interrupt-process proc))
+      (set-buffer obuf)
+      (or buffer (null mybuf) (kill-buffer mybuf))
+      rgn)))
+
+(defun mime-mc-pgp50-sign-region (start end &optional id unclear boundary)
+  (if (not (fboundp 'mc-pgp50-sign-parser))
+      (load "mc-pgp5")
+    )
+  (let ((process-environment process-environment)
+       (buffer (get-buffer-create mc-buffer-name))
+       passwd args key
+       (parser (function mc-pgp50-sign-parser))
+       (pgp-path mc-pgp50-pgps-path)
+       )
+    (setq key (mc-pgp50-lookup-key (or id mc-pgp50-user-id)))
+    (setq passwd
+         (mc-activate-passwd
+          (cdr key)
+          (format "PGP passphrase for %s (%s): " (car key) (cdr key))))
+    (setenv "PGPPASSFD" "0")
+    (setq args
+         (cons
+          (if boundary
+              "-fbat"
+            "-fat")
+          (list "+verbose=1" "+language=us"
+                (format "+clearsig=%s" (if unclear "off" "on"))
+                "+batchmode" "-u" (cdr key))))
+    (if mc-pgp50-comment
+       (setq args (cons (format "+comment=\"%s\"" mc-pgp50-comment) args))
+      )
+    (message "Signing as %s ..." (car key))
+    (if (mime-mc-pgp50-process-region
+        start end passwd pgp-path args parser buffer boundary)
+       (progn
+         (if boundary
+             (progn
+               (goto-char (point-min))
+               (insert
+                (format "\
+--[[multipart/signed; protocol=\"application/pgp-signature\";
+ boundary=\"%s\"; micalg=pgp-md5][7bit]]\n" boundary))
+               ))
+         (message "Signing as %s ... Done." (car key))
+         t)
+      nil)))
+
+(defun mime-mc-pgp50-encrypt-region (recipients start end &optional id sign)
+  (if (not (fboundp 'mc-pgp50-encrypt-region))
+      (load "mc-pgp5")
+    )
+  (let ((mc-pgp-always-sign (if (eq sign 'maybe)
+                               mc-pgp-always-sign
+                             'never)))
+    (mc-pgp50-encrypt-region
+     (mc-split "\\([ \t\n]*,[ \t\n]*\\)+" recipients)
+     start end id nil)
+    ))
+
+
+;;; @ PGP 2.6 functions
+;;;
+
 (defun mime-mc-process-region
   (beg end passwd program args parser &optional buffer boundary)
   (let ((obuf (current-buffer))
@@ -104,9 +482,9 @@ Content-Transfer-Encoding: 7bit
       (or buffer (null mybuf) (kill-buffer mybuf)))))
 
 (defun mime-mc-pgp-sign-region (start end &optional id unclear boundary)
-  ;; (if (not (boundp 'mc-pgp-user-id))
-  ;;     (load "mc-pgp")
-  ;;   )
+  (if (not (fboundp 'mc-pgp-generic-parser))
+      (load "mc-pgp")
+    )
   (let ((process-environment process-environment)
        (buffer (get-buffer-create mc-buffer-name))
        passwd args key
@@ -147,6 +525,9 @@ Content-Transfer-Encoding: 7bit
       nil)))
 
 (defun mime-mc-pgp-encrypt-region (recipients start end &optional id sign)
+  (if (not (fboundp 'mc-pgp-encrypt-region))
+      (load "mc-pgp")
+    )
   (let ((mc-pgp-always-sign (if (eq sign 'maybe)
                                mc-pgp-always-sign
                              'never)))
@@ -155,7 +536,7 @@ Content-Transfer-Encoding: 7bit
      start end id nil)
     ))
 
-               
+
 ;;; @ end
 ;;;
 
index fd0203a..88ffcb3 100644 (file)
@@ -1,11 +1,12 @@
-;;; mime-pgp.el --- mime-view internal methods for PGP.
+;;; mime-pgp.el --- mime-view internal methods for either PGP or GnuPG.
 
 ;; Copyright (C) 1995,1996,1997,1998,1999 MORIOKA Tomohiko
 
 ;; Author: MORIOKA Tomohiko <morioka@jaist.ac.jp>
+;;         Katsumi Yamaoka  <yamaoka@jpl.org>
 ;; Created: 1995/12/7
 ;;     Renamed: 1997/2/27 from tm-pgp.el
-;; Keywords: PGP, security, MIME, multimedia, mail, news
+;; Keywords: PGP, GnuPG, security, MIME, multimedia, mail, news
 
 ;; This file is part of SEMI (Secure Emacs MIME Interface).
 
@@ -30,9 +31,9 @@
 
 ;;     [security-multipart] RFC 1847: "Security Multiparts for MIME:
 ;;         Multipart/Signed and Multipart/Encrypted" by
-;;          Jim Galvin <galvin@tis.com>, Sandy Murphy <sandy@tis.com>,
+;;         Jim Galvin <galvin@tis.com>, Sandy Murphy <sandy@tis.com>,
 ;;         Steve Crocker <crocker@cybercash.com> and
-;;          Ned Freed <ned@innosoft.com> (1995/10)
+;;         Ned Freed <ned@innosoft.com> (1995/10)
 
 ;;     [PGP/MIME] RFC 2015: "MIME Security with Pretty Good Privacy
 ;;         (PGP)" by Michael Elkins <elkins@aero.org> (1996/6)
@@ -43,6 +44,7 @@
 
 ;;; Code:
 
+(require 'semi-def)
 (require 'mime-play)
 
 
 ;;;
 ;;; It is based on RFC 2015 (PGP/MIME).
 
-(defvar mime-pgp-command "pgp"
-  "*Name of the PGP command.")
-
-(defvar mime-pgp-default-language 'en
-  "*Symbol of language for pgp.
-It should be ISO 639 2 letter language code such as en, ja, ...")
-
-(defvar mime-pgp-good-signature-regexp-alist
-  '((en . "Good signature from user.*$"))
-  "Alist of language vs regexp to detect ``Good signature''.")
-
-(defvar mime-pgp-key-expected-regexp-alist
-  '((en . "Key matching expected Key ID \\(\\S +\\) not found"))
-  "Alist of language vs regexp to detect ``Key expected''.")
+(defcustom mime-pgp-command-alist '((gpg   . "gpg")
+                                   (pgp50 . "pgp")
+                                   (pgp   . "pgp"))
+  "Alist of the schemes and the name of the commands.  Valid SCHEMEs are:
+
+   gpg   - GnuPG.
+   pgp50 - PGP version 5.0i.
+   pgp   - PGP version 2.6.
+
+COMMAND for `pgp50' must *NOT* have a suffix, like neither \"pgpe\", \"pgpk\",
+\"pgps\" nor \"pgpv\"."
+  :group 'mime
+  :type '(repeat (cons :format "%v"
+                      (choice (choice-item :tag "GnuPG" gpg)
+                              (choice-item :tag "PGP 5.0i" pgp50)
+                              (choice-item :tag "PGP 2.6" pgp))
+                      (string :tag "Command"))))
+
+(defcustom mime-pgp-default-language-alist '((gpg   . nil)
+                                            (pgp50 . us)
+                                            (pgp   . en))
+  "Alist of the schemes and the symbol of languages.  It should be ISO 639
+2 letter language code such as en, ja, ...  Each element looks like
+\(SCHEME . SYMBOL).  See also `mime-pgp-command-alist' for valid SCHEMEs."
+  :group 'mime
+  :type '(repeat (cons :format "%v"
+                      (choice (choice-item :tag "GnuPG" gpg)
+                              (choice-item :tag "PGP 5.0i" pgp50)
+                              (choice-item :tag "PGP 2.6" pgp))
+                      (symbol :tag "Language"))))
+
+(defcustom mime-pgp-good-signature-regexp-alist
+  '((gpg
+     (nil "Good signature from.*$" nil)
+     )
+    (pgp50
+     (us "Good signature made .* by key:$"
+        mime-pgp-good-signature-post-function-pgp50-us)
+     )
+    (pgp
+     (en "Good signature from user.*$" nil)
+     ))
+  "Alist of the schemes and alist of the languages and the regexps for
+detecting ``Good signature''.  The optional symbol of the post processing
+function for arranging the output message can be specified in each element.
+It will be called just after re-search is done successfully, and it is
+expected that the function returns a string for messaging."
+  :group 'mime
+  :type '(repeat (cons :format "%v"
+                      (choice (choice-item :tag "GnuPG" gpg)
+                              (choice-item :tag "PGP 5.0i" pgp50)
+                              (choice-item :tag "PGP 2.6" pgp))
+                      (repeat (list :format "%v"
+                                    (symbol :tag "Language")
+                                    (regexp :tag "Regexp")
+                                    (function :tag "Post Function"))))))
+
+(defcustom mime-pgp-key-expected-regexp-alist
+  '((gpg
+     (nil
+      .
+      "key ID \\(\\S +\\)\ngpg: Can't check signature: public key not found")
+     )
+    (pgp50
+     (us . "Signature by unknown keyid: 0x\\(\\S +\\)")
+     )
+    (pgp
+     (en . "Key matching expected Key ID \\(\\S +\\) not found")
+     ))
+  "Alist of the schemes and alist of the languages and regexps for detecting
+``Key expected''."
+  :group 'mime
+  :type '(repeat (cons :format "%v"
+                      (choice (choice-item :tag "GnuPG" gpg)
+                              (choice-item :tag "PGP 5.0i" pgp50)
+                              (choice-item :tag "PGP 2.6" pgp))
+                      (repeat (cons :format "%v"
+                                    (symbol :tag "Language")
+                                    (regexp :tag "Regexp"))))))
+
+(defmacro mime-pgp-command (&optional suffix)
+  "Return a suitable command.  SUFFIX should be either \"e\", \"k\", \"s\"
+or \"v\" for choosing a command of PGP 5.0i."
+  (` (let ((command (cdr (assq pgp-version mime-pgp-command-alist))))
+       (if (and command
+               (progn
+                 (if (eq 'pgp50 pgp-version)
+                     (setq command (format "%s%s" command (, suffix))))
+                 (exec-installed-p command)))
+          command
+        (error "Please specify the valid command name for `%s'."
+               (or pgp-version 'pgp-version))))))
+
+(defmacro mime-pgp-default-language ()
+  "Return a symbol of language."
+  '(cond ((eq 'gpg pgp-version)
+         nil)
+        ((eq 'pgp50 pgp-version)
+         (or (cdr (assq pgp-version mime-pgp-default-language-alist)) 'us)
+         )
+        (t
+         (or (cdr (assq pgp-version mime-pgp-default-language-alist)) 'en)
+         )))
+
+(defmacro mime-pgp-good-signature-regexp ()
+  "Return a regexp to detect ``Good signature''."
+  '(nth 1
+       (assq
+        (mime-pgp-default-language)
+        (cdr (assq pgp-version mime-pgp-good-signature-regexp-alist))
+        )))
+
+(defmacro mime-pgp-good-signature-post-function ()
+  "Return a post processing function for arranging the message for
+``Good signature''."
+  '(nth 2
+       (assq
+        (mime-pgp-default-language)
+        (cdr (assq pgp-version mime-pgp-good-signature-regexp-alist))
+        )))
+
+(defmacro mime-pgp-key-expected-regexp ()
+  "Return a regexp to detect ``Key expected''."
+  '(cdr (assq (mime-pgp-default-language)
+             (cdr (assq pgp-version mime-pgp-key-expected-regexp-alist))
+             )))
 
 (defun mime-pgp-check-signature (output-buffer orig-file)
   (save-excursion
     (set-buffer output-buffer)
-    (erase-buffer))
-  (let* ((lang (or mime-pgp-default-language 'en))
-        (status (call-process-region (point-min)(point-max)
-                                     mime-pgp-command
-                                     nil output-buffer nil
-                                     orig-file (format "+language=%s" lang)))
-        (regexp (cdr (assq lang mime-pgp-good-signature-regexp-alist))))
-    (if (= status 0)
+    (erase-buffer)
+    (setq truncate-lines t))
+  (let* ((lang (mime-pgp-default-language))
+        (command (mime-pgp-command 'v))
+        (args (cond ((eq 'gpg pgp-version)
+                     (list "--batch" "--verify"
+                           (concat orig-file ".sig"))
+                     )
+                    ((eq 'pgp50 pgp-version)
+                     (list "+batchmode=1"
+                           (format "+language=%s" lang)
+                           (concat orig-file ".sig"))
+                     )
+                    ((eq 'pgp pgp-version)
+                     (list (format "+language=%s" lang) orig-file))
+                    ))
+        (regexp (mime-pgp-good-signature-regexp))
+        (post-function (mime-pgp-good-signature-post-function))
+        pgp-id)
+    (if (zerop (apply 'call-process-region
+                     (point-min) (point-max) command nil output-buffer nil
+                     args))
        (save-excursion
          (set-buffer output-buffer)
          (goto-char (point-min))
-         (message
-          (cond ((not (stringp regexp))
-                 "Please specify right regexp for specified language")
-                ((re-search-forward regexp nil t)
-                 (buffer-substring (match-beginning 0) (match-end 0)))
-                (t "Bad signature")))
-         ))))
+         (cond
+          ((not (stringp regexp))
+           (message "Please specify right regexp for specified language")
+           )
+          ((re-search-forward regexp nil t)
+           (message (if post-function
+                        (funcall post-function)
+                      (buffer-substring (match-beginning 0) (match-end 0))))
+           (goto-char (point-min))
+           )
+          ;; PGP 5.0i always returns 0, so we should attempt to fetch.
+          ((eq 'pgp50 pgp-version)
+           (if (not (stringp (setq regexp (mime-pgp-key-expected-regexp))))
+               (message "Please specify right regexp for specified language")
+             (if (re-search-forward regexp nil t)
+                 (progn
+                   (setq pgp-id
+                         (concat "0x" (buffer-substring-no-properties
+                                       (match-beginning 1)
+                                       (match-end 1))))
+                   (if (and
+                        pgp-id
+                        (y-or-n-p
+                         (format "Key %s not found; attempt to fetch? "
+                                 pgp-id)
+                         ))
+                       (progn
+                         (funcall (pgp-function 'fetch-key) (cons nil pgp-id))
+                         (mime-pgp-check-signature mime-echo-buffer-name
+                                                   orig-file)
+                         )
+                     (message "Bad signature")
+                     ))
+               (message "Bad signature")
+               ))
+           )
+          (t
+           (message "Bad signature")
+           ))
+         )
+      (message "Bad signature")
+      nil)))
 
 (defun mime-verify-application/pgp-signature (entity situation)
   "Internal method to check PGP/MIME signature."
@@ -168,39 +331,60 @@ It should be ISO 639 2 letter language code such as en, ja, ...")
     (mime-write-entity orig-entity orig-file)
     (save-excursion (mime-show-echo-buffer))
     (mime-write-entity-content entity sig-file)
-    (or (mime-pgp-check-signature mime-echo-buffer-name orig-file)
-       (let (pgp-id)
+    (if (mime-pgp-check-signature mime-echo-buffer-name orig-file)
+       (let ((other-window-scroll-buffer mime-echo-buffer-name))
+         (scroll-other-window
+          (cdr (assq pgp-version '((gpg . 0) (pgp50 . 1) (pgp . 10))))
+          ))
+      (if (eq 'pgp pgp-version)
          (save-excursion
            (set-buffer mime-echo-buffer-name)
            (goto-char (point-min))
-           (let ((regexp (cdr (assq (or mime-pgp-default-language 'en)
-                                    mime-pgp-key-expected-regexp-alist))))
-             (cond ((not (stringp regexp))
-                    (message
-                     "Please specify right regexp for specified language")
-                    )
-                   ((re-search-forward regexp nil t)
-                    (setq pgp-id
-                          (concat "0x" (buffer-substring-no-properties
+           (if (search-forward "\C-g" nil t)
+               (goto-char (match-beginning 0))
+             (forward-line 7))
+           (set-window-start
+            (get-buffer-window mime-echo-buffer-name)
+            (point))
+           )
+       (let ((other-window-scroll-buffer mime-echo-buffer-name))
+         (scroll-other-window
+          (cdr (assq pgp-version '((gpg . 0) (pgp50 . 1))))
+          )))
+      (let (pgp-id)
+       (save-excursion
+         (set-buffer mime-echo-buffer-name)
+         (goto-char (point-min))
+         (let ((regexp (mime-pgp-key-expected-regexp)))
+           (cond
+            ((not (stringp regexp))
+             (message "Please specify right regexp for specified language")
+             )
+            ((re-search-forward regexp nil t)
+             (setq pgp-id (concat "0x" (buffer-substring-no-properties
                                         (match-beginning 1)
                                         (match-end 1))))
-                    ))))
-         (if (and pgp-id
-                  (y-or-n-p
-                   (format "Key %s not found; attempt to fetch? " pgp-id))
-                  )
-             (progn
-               (funcall (pgp-function 'fetch-key) (cons nil pgp-id))
-               (mime-pgp-check-signature mime-echo-buffer-name orig-file)
-               ))
-         ))
-    (let ((other-window-scroll-buffer mime-echo-buffer-name))
-      (scroll-other-window 8)
-      )
+             ))))
+       (if (and pgp-id
+                (prog1
+                    (y-or-n-p
+                     (format "Key %s not found; attempt to fetch? " pgp-id))
+                  (message ""))
+                )
+           (progn
+             (funcall (pgp-function 'fetch-key) (cons nil pgp-id))
+             (mime-pgp-check-signature mime-echo-buffer-name orig-file)
+             )
+         )))
     (delete-file orig-file)
     (delete-file sig-file)
     ))
 
+(defun mime-pgp-good-signature-post-function-pgp50-us ()
+  (forward-line 2)
+  (looking-at "\\s +\\(.+\\)$")
+  (format "Good signature from %s" (match-string 1)))
+
 
 ;;; @ Internal method for application/pgp-encrypted
 ;;;
@@ -243,7 +427,7 @@ It should be ISO 639 2 letter language code such as en, ja, ...")
     (kill-buffer (current-buffer))
     ))
 
-        
+
 ;;; @ end
 ;;;
 
index 6f1b876..49f60ca 100644 (file)
@@ -608,23 +608,35 @@ sending.
 mime-edit provides PGP encryption, signature and inserting public-key
 features based on <concept>PGP/MIME</concept> (RFC 2015) or
 <concept>PGP-kazu</concept> (draft-kazu-pgp-mime-00.txt).
+In current version, PGP 5.0i and GnuPG are supported as well.
 <p>
-This feature requires pgp command and pgp interface package, such as
-<a file="mailcrypt">Mailcrypt package</a>.
+This feature requires PGP or GnuPG commands and its interface package,
+such as <a file="mailcrypt">Mailcrypt package</a>.
+
+<defvar name="pgp-version">
+<p>
+Version of PGP or GnuPG command to be used for encryption or sign.
+The value should be a symbol.  Allowed versions are <code>gpg</code>,
+<code>pgp50</code> or <code>pgp</code>.
+</defvar>
 
 <defvar name="pgp-function-alist">
 <p>
 Alist of service names vs. corresponding functions and its filenames.
-Each element looks like <code>(SERVICE FUNCTION FILE)</code>.
+Each element looks like
+<code>(SERVICE FUNCTION FILE [PGP5_FUNCTION PGP5_FILE [GPG_FUNCTION GPG_FILE]])</code>.
 <p>
-SERVICE is a symbol of PGP processing.  It allows `verify', `decrypt',
-`fetch-key', `snarf-keys', `mime-sign', `traditional-sign', `encrypt'
-or `insert-key'.
+SERVICE is a symbol of PGP2, PGP5 or GnuPG processing.  It allows
+`verify', `decrypt', `fetch-key', `snarf-keys', `mime-sign',
+`traditional-sign', `encrypt' or `insert-key'.
 <p>
 Function is a symbol of function to do specified SERVICE.
 <p>
 FILE is string of filename which has definition of corresponding
 FUNCTION.
+<p>
+PGP5_FUNCTION, PGP5_FILE, GPG_FUNCTION and GPG_FILE are similar to
+FUNCTION and FILE, but they will be used for PGP 5.0i or GnuPG.
 </defvar>
 
 <defun name="pgp-function">
index 2e1094a..bda633d 100644 (file)
@@ -623,23 +623,35 @@ sending.
 mime-edit \e$B$G$O\e(B <concept>PGP/MIME</concept> (RFC 2015) \e$B$*$h$S\e(B
 <concept>PGP-kazu</concept> (draft-kazu-pgp-mime-00.txt) \e$B$K$h$k0E9f2=!&\e(B
 \e$BEE;R=pL>!&8x3+80$NA^F~5!G=$rMxMQ$9$k$3$H$,$G$-$^$9!#\e(B
+\e$B8=:_$NHG$G$O\e(B PGP 5.0i \e$B$H\e(B GnuPG \e$B$b%5%]!<%H$5$l$F$$$^$9!#\e(B
 <p>
 \e$BC"$7!"$3$N5!G=$rMxMQ$9$k$K$O\e(B <a file="mailcrypt">Mailcrypt package</a> 
 \e$B$H\e(B pgp command \e$B$,I,MW$G$9!#\e(B
 
+<defvar name="pgp-version">
+<p>
+Version of PGP or GnuPG command to be used for encryption or sign.
+The value should be a symbol.  Allowed versions are <code>gpg</code>,
+<code>pgp50</code> or <code>pgp</code>.
+</defvar>
+
 <defvar name="pgp-function-alist">
 <p>
 Alist of service names vs. corresponding functions and its filenames.
-Each element looks like <code>(SERVICE FUNCTION FILE)</code>.
+Each element looks like
+<code>(SERVICE FUNCTION FILE [PGP5_FUNCTION PGP5_FILE [GPG_FUNCTION GPG_FILE]])</code>.
 <p>
-SERVICE is a symbol of PGP processing.  It allows `verify', `decrypt',
-`fetch-key', `snarf-keys', `mime-sign', `traditional-sign', `encrypt'
-or `insert-key'.
+SERVICE is a symbol of PGP2, PGP5 or GnuPG processing.  It allows
+`verify', `decrypt', `fetch-key', `snarf-keys', `mime-sign',
+`traditional-sign', `encrypt' or `insert-key'.
 <p>
 Function is a symbol of function to do specified SERVICE.
 <p>
 FILE is string of filename which has definition of corresponding
 FUNCTION.
+<p>
+PGP5_FUNCTION, PGP5_FILE, GPG_FUNCTION and GPG_FILE are similar to
+FUNCTION and FILE, but they will be used for PGP 5.0i or GnuPG.
 </defvar>
 
 <defun name="pgp-function">
index d5e28a7..2f432ce 100644 (file)
 ;;; @ PGP
 ;;;
 
+(defcustom pgp-version 'pgp
+  "Version of PGP or GnuPG command to be used for encryption or sign.
+The value should be a symbol.  Allowed versions are:
+
+  gpg   - GnuPG.
+  pgp50 - PGP version 5.0i.
+  pgp   - PGP version 2.6."
+  :group 'mime
+  :type '(radio (choice-item :tag "GnuPG" gpg)
+               (choice-item :tag "PGP 5.0i" pgp50)
+               (choice-item :tag "PGP 2.6" pgp)))
+
 (defvar pgp-function-alist
   '(
     ;; for mime-pgp
-    (verify            mc-verify                       "mc-toplev")
-    (decrypt           mc-decrypt                      "mc-toplev")
-    (fetch-key         mc-pgp-fetch-key                "mc-pgp")
-    (snarf-keys                mc-snarf-keys                   "mc-toplev")
+    (verify            mime-mc-verify                  "mime-mc")
+    (decrypt           mime-mc-decrypt                 "mime-mc")
+    (fetch-key         mc-pgp-fetch-key                "mc-pgp"
+                       mc-pgp50-fetch-key              "mc-pgp5"
+                       mc-gpg-fetch-key                "mc-gpg")
+    (snarf-keys                mime-mc-snarf-keys              "mime-mc")
     ;; for mime-edit
-    (mime-sign         mime-mc-pgp-sign-region         "mime-mc")
-    (traditional-sign  mc-pgp-sign-region              "mc-pgp")
-    (encrypt           mime-mc-pgp-encrypt-region      "mime-mc")
-    (insert-key                mc-insert-public-key            "mc-toplev")
+    (mime-sign         mime-mc-pgp-sign-region         "mime-mc"
+                       mime-mc-pgp50-sign-region       "mime-mc"
+                       mime-mc-gpg-sign-region         "mime-mc")
+    (traditional-sign  mc-pgp-sign-region              "mc-pgp"
+                       mc-pgp50-sign-region            "mc-pgp5"
+                       mc-gpg-sign-region              "mc-gpg")
+    (encrypt           mime-mc-pgp-encrypt-region      "mime-mc"
+                       mime-mc-pgp50-encrypt-region    "mime-mc"
+                       mime-mc-gpg-encrypt-region      "mime-mc")
+    (insert-key                mime-mc-insert-public-key       "mime-mc")
     )
   "Alist of service names vs. corresponding functions and its filenames.
-Each element looks like (SERVICE FUNCTION FILE).
+Each element looks like:
 
-SERVICE is a symbol of PGP processing.  It allows `verify', `decrypt',
-`fetch-key', `snarf-keys', `mime-sign', `traditional-sign', `encrypt'
-or `insert-key'.
+\(SERVICE FUNCTION FILE [PGP5_FUNCTION PGP5_FILE [GPG_FUNCTION GPG_FILE]]).
 
-Function is a symbol of function to do specified SERVICE.
+SERVICE is a symbol of PGP2, PGP5 or GnuPG processing.  It allows `verify',
+`decrypt', `fetch-key', `snarf-keys', `mime-sign', `traditional-sign',
+`encrypt' or `insert-key'.
+
+FUNCTION is a symbol of function to do specified SERVICE.
 
 FILE is string of filename which has definition of corresponding
-FUNCTION.")
+FUNCTION.
+
+PGP5_FUNCTION, PGP5_FILE, GPG_FUNCTION and GPG_FILE are similar to
+FUNCTION and FILE, but they will be used for PGP 5.0i or GnuPG.")
 
 (defmacro pgp-function (method)
   "Return function to do service METHOD."
-  `(cadr (assq ,method (symbol-value 'pgp-function-alist))))
+  `(let ((elem (assq ,method (symbol-value 'pgp-function-alist))))
+     (cond ((eq 'gpg pgp-version)
+           (if (> (length elem) 3)
+               (nth 5 elem)
+             (nth 1 elem))
+           )
+          ((eq 'pgp50 pgp-version)
+           (if (> (length elem) 3)
+               (nth 3 elem)
+             (nth 1 elem))
+           )
+          (t
+           (nth 1 elem)
+           ))))
 
 (mapcar (function
-        (lambda (method)
-          (autoload (cadr method)(nth 2 method))
-          ))
+        (lambda (elem)
+          (setq elem (cdr elem))
+          (while elem
+            (autoload (car elem) (nth 1 elem))
+            (setq elem (nthcdr 2 elem)))))
        pgp-function-alist)
 
 
index 9928d1e..b1493a6 100644 (file)
@@ -1,6 +1,6 @@
 ;;; semi-setup.el --- setup file for MIME-View.
 
-;; Copyright (C) 1994,1995,1996,1997,1998 Free Software Foundation, Inc.
+;; Copyright (C) 1994,1995,1996,1997,1998,1999 Free Software Foundation, Inc.
 
 ;; Author: MORIOKA Tomohiko <morioka@jaist.ac.jp>
 ;; Keywords: mail, news, MIME, multimedia, multilingual, encoded-word
@@ -85,7 +85,7 @@ it is used as hook to set."
 ;; for PGP
 (defvar mime-setup-enable-pgp
   (module-installed-p 'mailcrypt)
-  "*If it is non-nil, semi-setup sets uf to use mime-pgp.")
+  "*If it is non-nil, semi-setup sets up to use mime-pgp.")
 
 (if mime-setup-enable-pgp
     (eval-after-load "mime-view"