Indent.
[gnus] / contrib / gpg.el
index f885330..233f859 100644 (file)
@@ -7,7 +7,7 @@
 ;; Keywords: crypto
 ;; Created: 2000-04-15
 
-;; $Id: gpg.el,v 1.2 2000/11/18 20:57:13 jas Exp $
+;; $Id: gpg.el,v 1.17 2001/12/26 15:23:03 fw Exp $
 
 ;; This file is NOT (yet?) part of GNU Emacs.
 
@@ -41,8 +41,8 @@
 ;; * Customization for all flavors of PGP is possible.
 ;; * The main operations (verify, decrypt, sign, encrypt, sign &
 ;;   encrypt) are implemented.
-;; * Gero Treuner's gpg-2comp script is supported, and data which is is
-;;   compatible with PGP 2.6.3 is generated.
+;; * Optionally, Gero Treuner's gpg-2comp script is supported, 
+;;   to generate data which is compatible with PGP 2.6.3.
 
 ;; Customizing external programs 
 ;; =============================
 ;; function (bound to `C-h l' by default).
 
 \f
-;;;; Code:
+;;; Code:
 
 (require 'timer)
-(eval-when-compile 
-  (require 'cl))
+(eval-when-compile (require 'cl))
 
-
-(if (featurep 'xemacs)
-         (defalias 'line-end-position 'point-at-eol))
+(eval-and-compile 
+  (defalias 'gpg-point-at-eol
+    (if (fboundp 'point-at-eol)
+       'point-at-eol
+      'line-end-position)))
 
 ;;;; Customization:
 
 
 ;;; Customization: Widgets:
 
-(define-widget 'gpg-command-alist 'alist
-  "An association list for GnuPG command names."
-  :key-type '(symbol :tag   "Abbreviation")
-  :value-type '(string :tag "Program name")
-  :convert-widget 'widget-alist-convert-widget
-  :tag "Alist")
+(if (get 'alist 'widget-type)
+    (define-widget 'gpg-command-alist 'alist
+      "An association list for GnuPG command names."
+      :key-type '(symbol :tag   "Abbreviation")
+      :value-type '(string :tag "Program name")
+      :convert-widget 'widget-alist-convert-widget
+      :tag "Alist")
+    (define-widget 'gpg-command-alist 'repeat
+      "An association list for GnuPG command names."
+      :args '((cons :format "%v"
+                   (symbol :tag   "Abbreviation")
+                   (string :tag "Program name")))
+      :tag "Alist"))
 
 (define-widget 'gpg-command-program 'choice
   "Widget for entering the name of a program (mostly the GnuPG binary)."
@@ -219,16 +227,22 @@ If you are running Emacs 20, this directory must have mode 0700."
 
 (defcustom gpg-command-default-alist 
   '((gpg . "gpg")
-    (gpg-2comp . "gpg-2comp"))
+    (gpg-2comp . "gpg"))
   "Default paths for some GnuPG-related programs.
 Modify this variable if you have to change the paths to the
-executables required by the GnuPG interface.  You can enter \"gpg\"
-for `gpg-2comp' if you don't have this script, but you'll lose PGP
-2.6.x compatibility."
+executables required by the GnuPG interface.  You can enter \"gpg-2comp\"
+for `gpg-2comp' if you have obtained this script, in order to gain
+PGP 2.6.x compatibility."
   :tag "GnuPG programs"
   :type 'gpg-command-alist
   :group 'gpg-options)
 
+(defcustom gpg-command-all-arglist
+  nil
+  "List of arguments to add to all GPG commands."
+  :tag "All command args"
+  :group 'gpg-options)
+
 (defcustom gpg-command-flag-textmode "--textmode"
   "The flag to indicate canonical text mode to GnuPG."
   :tag "Text mode flag"
@@ -288,7 +302,7 @@ indicate that it should read the passphrase from standard input."
 ;;; Customization: Variables: GnuPG Commands:
 
 (defcustom gpg-command-verify
-  '(gpg . ("--batch" "--verbose" "--verify" signature-file message-file))
+  '(gpg . ("--status-fd" "1" "--batch" "--verbose" "--verify" signature-file message-file))
   "Command to verify a detached signature.
 The invoked program has to read the signed message and the signature
 from the given files.  It should write human-readable information to
@@ -309,7 +323,7 @@ charsets or line endings; the input data shall be treated as binary."
   :group 'gpg-commands)
 
 (defcustom gpg-command-verify-cleartext
-  '(gpg . ("--batch" "--verbose" "--verify" message-file))
+  '(gpg . ("--status-fd" "1" "--batch" "--verbose" "--verify" message-file))
   "Command to verify a message.
 The invoked program has to read the signed message from the given
 file.  It should write human-readable information to standard output
@@ -328,7 +342,7 @@ endings; the input data shall be treated as binary."
   :group 'gpg-commands)
 
 (defcustom gpg-command-decrypt
-  '(gpg . ("--decrypt" "--batch" "--passphrase-fd=0"))
+  '(gpg . ("--status-fd" "2" "--decrypt" "--batch" "--passphrase-fd=0"))
   "Command to decrypt a message.
 The invoked program has to read the passphrase from standard
 input, followed by the encrypted message.  It writes the decrypted
@@ -350,7 +364,7 @@ standard error."
   '(gpg-2comp . ("--batch" "--passphrase-fd=0" "--output=-"
                 armor textmode  "--clearsign"
                 sign-with-key))
-  "Command to create a create a \"clearsign\" text file.  
+  "Command to create a \"clearsign\" text file.  
 The invoked program has to read the passphrase from standard input,
 followed by the message to sign.  It should write the ASCII-amored
 signed text message to standard output, and diagnostic messages to
@@ -363,7 +377,7 @@ standard error."
   '(gpg-2comp . ("--batch" "--passphrase-fd=0" "--output=-"
                 armor textmode "--detach-sign" 
                 sign-with-key))
-  "Command to create a create a detached signature. 
+  "Command to create a detached signature. 
 The invoked program has to read the passphrase from standard input,
 followed by the message to sign.  It should write the ASCII-amored
 detached signature to standard output, and diagnostic messages to
@@ -535,7 +549,7 @@ it are replaced by SUBSTITUTIONS.
 SUBSTITIONS is a list of (SYMBOL . SEXP) pairs, where SEXP is either a
 string (which is inserted literally), a list of strings (which are
 inserted as well), or nil, which means to insert nothing."
-  (let (arglist)
+  (let ((arglist (copy-sequence gpg-command-all-arglist)))
     (while template
       (let* ((templ (pop template))
             (repl (assoc templ substitutions))
@@ -600,20 +614,24 @@ adjust according to `gpg-command-passphrase-env'."
         (when gpg-command-passphrase-env
           ;; This will clear the variable if it wasn't set before.
           (setenv (car gpg-command-passphrase-env) ,env-value))))))
+(put 'gpg-with-passphrase-env 'lisp-indent-function 0)
+(put 'gpg-with-passphrase-env 'edebug-form-spec '(body))
 
 ;;; Temporary files:
 
 (defun gpg-make-temp-file ()
   "Create a temporary file in a safe way"
-  (let ((name (concat gpg-temp-directory "/gnupg")))
+  (let ((name  ;; User may use "~/"
+        (expand-file-name "gnupg" gpg-temp-directory)))
     (if (fboundp 'make-temp-file)
        ;; If we've got make-temp-file, we are on the save side.
        (make-temp-file name)
       ;; make-temp-name doesn't create the file, and an ordinary
       ;; write-file operation is prone to nasty symlink attacks if the
       ;; temporary file resides in a world-writable directory.
-      (unless (eq (file-modes gpg-temp-directory) 448) ; mode 0700
-       (error "Directory for temporary files must have mode 0700."))
+      (unless (or (memq system-type '(windows-nt cygwin32 win32 w32 mswindows))
+                 (eq (file-modes gpg-temp-directory) 448)) ; mode 0700
+       (error "Directory for temporary files (%s) must have mode 0700" gpg-temp-directory))
       (setq name (make-temp-name name))
       (let ((mode (default-file-modes)))
        (unwind-protect
@@ -653,6 +671,8 @@ arguments."
            (gpg-with-temp-files-create ,count)
            ,@body)
        (gpg-with-temp-files-delete))))
+(put 'gpg-with-temp-files 'lisp-indent-function 1)
+(put 'gpg-with-temp-files 'edebug-form-spec '(body))
 
 ;;;  Making subprocesses:
 
@@ -707,7 +727,7 @@ to this file."
                 (apply 'call-process-region (point-min) (point-max) cpr-args)
                 ;; Wipe out passphrase.
                 (goto-char (point-min))
-                (translate-region (point) (line-end-position)
+                (translate-region (point) (gpg-point-at-eol)
                                   (make-string 256 ? )))
             (if (listp stdin)
                 (with-current-buffer (car stdin)
@@ -743,7 +763,7 @@ Never set this variable directly, use `gpg-show-result' instead.")
       (save-window-excursion
        (display-buffer (current-buffer))
        (unless (y-or-n-p "Continue? ")
-         (error "GnuPG operation aborted."))))))
+         (error "GnuPG operation aborted"))))))
 
 (defmacro gpg-show-result (always-show &rest body)
   "Show GnuPG result to user for confirmation.
@@ -755,6 +775,8 @@ evaluates BODY, like `progn'.  If BODY evaluates to `nil' (or
      (unwind-protect
         (gpg-show-result-buffer ,always-show (progn ,@body))
        (kill-buffer gpg-result-buffer))))
+(put 'gpg-show-result 'lisp-indent-function 1)
+(put 'gpg-show-result 'edebug-form-spec '(body))
 
 ;;; Passphrase handling:
 
@@ -779,6 +801,7 @@ evaluates BODY, like `progn'.  If BODY evaluates to `nil' (or
   "Forget stored passphrase."
   (interactive)
   (cancel-timer gpg-passphrase-timer)
+  (setq gpg-passphrase-timer nil)
   (gpg-passphrase-clear-string gpg-passphrase)
   (setq gpg-passphrase nil))
 
@@ -786,14 +809,18 @@ evaluates BODY, like `progn'.  If BODY evaluates to `nil' (or
   "Store PASSPHRASE in cache.
 Updates the timeout for clearing the cache to `gpg-passphrase-timeout'."
   (unless (equal gpg-passphrase-timeout 0)
+    (if (null gpg-passphrase-timer)
+       (setq gpg-passphrase-timer (timer-create)))
     (timer-set-time gpg-passphrase-timer 
                    (timer-relative-time (current-time) 
                                         gpg-passphrase-timeout))
     (timer-set-function gpg-passphrase-timer 'gpg-passphrase-forget)
-    (timer-activate gpg-passphrase-timer)
+    (unless (and (fboundp 'itimer-live-p)
+                (itimer-live-p gpg-passphrase-timer))
+      (timer-activate gpg-passphrase-timer))
     (setq gpg-passphrase passphrase))
   passphrase)
-  
+
 (defun gpg-passphrase-read ()
   "Read a passphrase and remember it for some time."
   (interactive)
@@ -1108,7 +1135,7 @@ documentation for details)."
 
 (defun gpg-key-list-keys-parse-line ()
   "Parse the line in the current buffer and return a vector of fields."
-  (let* ((eol (line-end-position))
+  (let* ((eol (gpg-point-at-eol))
         (v (if (eolp)
                nil
              (vector
@@ -1151,6 +1178,14 @@ documentation for details)."
     (?u . trust-ultimate))
   "Alist mapping GnuPG trust value short forms to long symbols.")
 
+(defconst gpg-unabbrev-trust-alist
+  '(("TRUST_UNDEFINED" . trust-undefined)
+    ("TRUST_NEVER"     . trust-none)
+    ("TRUST_MARGINAL"  . trust-marginal)
+    ("TRUST_FULLY"     . trust-full)
+    ("TRUST_ULTIMATE"  . trust-ultimate))
+  "Alist mapping capitalized GnuPG trust values to long symbols.")
+
 (defmacro gpg-key-list-keys-in-buffer-store ()
   '(when primary-user-id
      (sort user-id 'string-lessp)