Fixed.
[elisp/epg.git] / epg.el
1 ;;; epg.el --- EasyPG, yet another GnuPG interface.
2 ;; Copyright (C) 1999, 2000, 2002, 2003, 2004,
3 ;;   2005, 2006 Free Software Foundation, Inc.
4 ;; Copyright (C) 2006 Daiki Ueno
5
6 ;; Author: Daiki Ueno <ueno@unixuser.org>
7 ;; Keywords: PGP, GnuPG
8
9 ;; This file is part of EasyPG.
10
11 ;; This program is free software; you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation; either version 2, or (at your option)
14 ;; any later version.
15
16 ;; This program is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 ;; GNU General Public License for more details.
20
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., 51 Franklin Street, Fifth Floor,
24 ;; Boston, MA 02110-1301, USA.
25
26 ;;; Code:
27
28 (defgroup epg ()
29   "EasyPG, yet another GnuPG interface.")
30
31 (defcustom epg-gpg-program "gpg"
32   "The `gpg' executable."
33   :group 'epg
34   :type 'string)
35
36 (defvar epg-user-id nil
37   "GnuPG ID of your default identity.")
38
39 (defvar epg-user-id-alist nil
40   "An alist mapping from key ID to user ID.")
41
42 (defvar epg-read-point nil)
43 (defvar epg-pending-status-list nil)
44 (defvar epg-key-id nil)
45 (defvar epg-context nil)
46 (defvar epg-debug nil)
47
48 (defvar epg-colons-pub-spec
49   '((trust "[^:]")
50     (length "[0-9]+" 0 string-to-number)
51     (algorithm "[0-9]+" 0 string-to-number)
52     (key-id "[^:]+")
53     (creation-date "[0-9]+")
54     (expiration-date "[0-9]+")
55     nil
56     (ownertrust "[^:]")
57     nil
58     nil
59     (capability "[escaESCA]*"))
60   "The schema of keylisting output whose type is \"pub\".
61 This is used by `epg-list-keys'.")
62
63 (defvar epg-colons-sec-spec
64   '((trust "[^:]")
65     (length "[0-9]+" 0 string-to-number)
66     (algorithm "[0-9]+" 0 string-to-number)
67     (key-id "[^:]+")
68     (creation-date "[0-9]+")
69     (expiration-date "[0-9]+")
70     nil
71     (ownertrust "[^:]"))
72 "The schema of keylisting output whose type is \"sec\".
73 This is used by `epg-list-keys'.")
74
75 (defvar epg-colons-uid-spec
76   '((trust "[^:]")
77     nil
78     nil
79     nil
80     (creation-date "[0-9]+")
81     (expiration-date "[0-9]+")
82     (hash "[^:]+")
83     nil
84     (user-id "[^:]+"))
85   "The schema of keylisting output whose type is \"uid\".
86 This is used by `epg-list-keys'.")
87
88 (defvar epg-prompt-alist nil)
89     
90 (defun epg-make-context (&optional protocol armor textmode include-certs)
91   "Return a context object."
92   (vector protocol armor textmode include-certs
93           (cons #'epg-passphrase-callback-function nil)
94           (cons #'epg-progress-callback-function nil)
95           nil nil nil nil))
96
97 (defun epg-context-protocol (context)
98   "Return the protocol used within the context."
99   (aref context 0))
100
101 (defun epg-context-armor (context)
102   "Return t if the output shouled be ASCII armored in the CONTEXT context."
103   (aref context 1))
104
105 (defun epg-context-textmode (context)
106   "Return t if canonical text mode should be used in the CONTEXT context."
107   (aref context 2))
108
109 (defun epg-context-include-certs (context)
110   "Return how many certificates should be included in an S/MIME signed
111 message."
112   (aref context 3))
113
114 (defun epg-context-passphrase-callback-info (context)
115   "Return the function used to query passphrase."
116   (aref context 4))
117
118 (defun epg-context-progress-callback-info (context)
119   "Return the function which handles progress update."
120   (aref context 5))
121
122 (defun epg-context-signers (context)
123   "Return the list of key-id for singning."
124   (aref context 6))
125
126 (defun epg-context-process (context)
127   "Return the process object of `epg-gpg-program'.
128 This function is for internal use only."
129   (aref context 7))
130
131 (defun epg-context-output-file (context)
132   "Return the output file of `epg-gpg-program'.
133 This function is for internal use only."
134   (aref context 8))
135
136 (defun epg-context-result (context)
137   "Return the result of the previous cryptographic operation."
138   (aref context 9))
139
140 (defun epg-context-set-protocol (context protocol)
141   "Set the protocol used within the context."
142   (aset context 0 protocol))
143
144 (defun epg-context-set-armor (context armor)
145   "Specify if the output shouled be ASCII armored in the CONTEXT context."
146   (aset context 1 armor))
147
148 (defun epg-context-set-textmode (context textmode)
149   "Specify if canonical text mode should be used in the CONTEXT context."
150   (aset context 2 textmode))
151
152 (defun epg-context-set-include-certs (context include-certs)
153  "Set how many certificates should be included in an S/MIME signed message."
154   (aset context 3 include-certs))
155
156 (defun epg-context-set-passphrase-callback-info (context
157                                                  passphrase-callback-info)
158   "Set the function used to query passphrase."
159   (aset context 4 passphrase-callback-info))
160
161 (defun epg-context-set-progress-callback-info (context progress-callback-info)
162   "Set the function which handles progress update."
163   (aset context 5 progress-callback-info))
164
165 (defun epg-context-set-signers (context signers)
166  "Set the list of key-id for singning."
167   (aset context 6 signers))
168
169 (defun epg-context-set-process (context process)
170   "Set the process object of `epg-gpg-program'.
171 This function is for internal use only."
172   (aset context 7 process))
173
174 (defun epg-context-set-output-file (context output-file)
175   "Set the output file of `epg-gpg-program'.
176 This function is for internal use only."
177   (aset context 8 output-file))
178
179 (defun epg-context-set-result (context result)
180   "Set the result of the previous cryptographic operation."
181   (aset context 9 result))
182
183 (defun epg-make-signature (status key-id user-id)
184   "Return a signature object."
185   (vector status key-id user-id nil nil))
186
187 (defun epg-signature-status (signature)
188   "Return the status code of SIGNATURE."
189   (aref signature 0))
190
191 (defun epg-signature-key-id (signature)
192   "Return the key-id of SIGNATURE."
193   (aref signature 1))
194
195 (defun epg-signature-user-id (signature)
196   "Return the user-id of SIGNATURE."
197   (aref signature 2))
198   
199 (defun epg-signature-validity (signature)
200   "Return the validity of SIGNATURE."
201   (aref signature 3))
202
203 (defun epg-signature-fingerprint (signature)
204   "Return the fingerprint of SIGNATURE."
205   (aref signature 4))
206
207 (defun epg-signature-set-status (signature status)
208  "Set the status code of SIGNATURE."
209   (aset signature 0 status))
210
211 (defun epg-signature-set-key-id (signature key-id)
212  "Set the key-id of SIGNATURE."
213   (aset signature 1 key-id))
214
215 (defun epg-signature-set-user-id (signature user-id)
216  "Set the user-id of SIGNATURE."
217   (aset signature 2 user-id))
218   
219 (defun epg-signature-set-validity (signature validity)
220  "Set the validity of SIGNATURE."
221   (aset signature 3 validity))
222
223 (defun epg-signature-set-fingerprint (signature fingerprint)
224  "Set the fingerprint of SIGNATURE."
225   (aset signature 4 fingerprint))
226
227 (defun epg-context-result-for (context name)
228   (cdr (assq name (epg-context-result context))))
229
230 (defun epg-context-set-result-for (context name value)
231   (let* ((result (epg-context-result context))
232          (entry (assq name result)))
233     (if entry
234         (setcdr entry value)
235       (epg-context-set-result context (cons (cons name value) result)))))
236
237 (defun epg-start (context args)
238   "Start `epg-gpg-program' in a subprocess with given ARGS."
239   (let* ((args (append (list "--no-tty"
240                              "--status-fd" "1"
241                              "--command-fd" "0"
242                              "--yes") ; overwrite
243                        (if (epg-context-armor context) '("--armor"))
244                        (if (epg-context-textmode context) '("--textmode"))
245                        (if (epg-context-output-file context)
246                            (list "--output" (epg-context-output-file context)))
247                        args))
248          (coding-system-for-write 'binary)
249          process-connection-type
250          (orig-mode (default-file-modes))
251          (buffer (generate-new-buffer " *epg*"))
252          process)
253     (with-current-buffer buffer
254       (make-local-variable 'epg-read-point)
255       (setq epg-read-point (point-min))
256       (make-local-variable 'epg-pending-status-list)
257       (setq epg-pending-status-list nil)
258       (make-local-variable 'epg-key-id)
259       (setq epg-key-id nil)
260       (make-local-variable 'epg-context)
261       (setq epg-context context))
262     (unwind-protect
263         (progn
264           (set-default-file-modes 448)
265           (setq process
266                 (apply #'start-process "epg" buffer epg-gpg-program args)))
267       (set-default-file-modes orig-mode))
268     (set-process-filter process #'epg-process-filter)
269     (epg-context-set-process context process)))
270
271 (defun epg-process-filter (process input)
272   (if epg-debug
273       (save-excursion
274         (set-buffer (get-buffer-create  " *epg-debug*"))
275         (goto-char (point-max))
276         (insert input)))
277   (if (buffer-live-p (process-buffer process))
278       (save-excursion
279         (set-buffer (process-buffer process))
280         (goto-char (point-max))
281         (insert input)
282         (goto-char epg-read-point)
283         (beginning-of-line)
284         (while (looking-at ".*\n")      ;the input line is finished
285           (save-excursion
286             (if (looking-at "\\[GNUPG:] \\([A-Z_]+\\) ?\\(.*\\)")
287                 (let* ((status (match-string 1))
288                        (string (match-string 2))
289                        (symbol (intern-soft (concat "epg-status-" status))))
290                   (if (member status epg-pending-status-list)
291                       (setq epg-pending-status-list nil))
292                   (if (and symbol
293                            (fboundp symbol))
294                       (funcall symbol process string)))))
295           (forward-line))
296         (setq epg-read-point (point)))))
297
298 (defun epg-read-output (context)
299   (with-temp-buffer
300     (if (fboundp 'set-buffer-multibyte)
301         (set-buffer-multibyte nil))
302     (if (file-exists-p (epg-context-output-file context))
303         (let ((coding-system-for-read (if (epg-context-textmode context)
304                                           'raw-text
305                                         'binary)))
306           (insert-file-contents (epg-context-output-file context))
307           (buffer-string)))))
308
309 (defun epg-wait-for-status (context status-list)
310   (with-current-buffer (process-buffer (epg-context-process context))
311     (setq epg-pending-status-list status-list)
312     (while (and (eq (process-status (epg-context-process context)) 'run)
313                 epg-pending-status-list)
314       (accept-process-output (epg-context-process context) 1))))
315
316 (defun epg-wait-for-completion (context)
317   (if (eq (process-status (epg-context-process context)) 'run)
318       (process-send-eof (epg-context-process context)))
319   (while (eq (process-status (epg-context-process context)) 'run)
320     ;; We can't use accept-process-output instead of sit-for here
321     ;; because it may cause an interrupt during the sentinel execution.
322     (sit-for 0.1)))
323
324 (defun epg-reset (context)
325   (if (and (epg-context-process context)
326            (buffer-live-p (process-buffer (epg-context-process context))))
327       (kill-buffer (process-buffer (epg-context-process context))))
328   (epg-context-set-process context nil)
329   (if (file-exists-p (epg-context-output-file context))
330       (delete-file (epg-context-output-file context))))
331
332 (defun epg-status-USERID_HINT (process string)
333   (if (string-match "\\`\\([^ ]+\\) \\(.*\\)" string)
334       (let* ((key-id (match-string 1 string))
335              (user-id (match-string 2 string))
336              (entry (assoc key-id epg-user-id-alist)))
337         (if entry
338             (setcdr entry user-id)
339           (setq epg-user-id-alist (cons (cons key-id user-id)
340                                         epg-user-id-alist))))))
341
342 (defun epg-status-NEED_PASSPHRASE (process string)
343   (if (string-match "\\`\\([^ ]+\\)" string)
344       (setq epg-key-id (match-string 1 string))))
345
346 (defun epg-status-NEED_PASSPHRASE_SYM (process string)
347   (setq epg-key-id 'SYM))
348
349 (defun epg-status-NEED_PASSPHRASE_PIN (process string)
350   (setq epg-key-id 'PIN))
351
352 (defun epg-status-GET_HIDDEN (process string)
353   (let ((passphrase
354          (funcall (car (epg-context-passphrase-callback-info epg-context))
355                   epg-key-id
356                   (cdr (epg-context-passphrase-callback-info epg-context))))
357         string)
358     (if passphrase
359         (unwind-protect
360             (progn
361               (setq string (concat passphrase "\n"))
362               (fillarray passphrase 0)
363               (setq passphrase nil)
364               (process-send-string process string))
365           (if string
366               (fillarray string 0))))))
367
368 (defun epg-status-GET_BOOL (process string)
369   (let ((entry (assoc string epg-prompt-alist)))
370     (if (y-or-n-p (if entry (cdr entry) (concat string "? ")))
371         (process-send-string process "y\n")
372       (process-send-string process "n\n"))))
373
374 (defun epg-status-GET_LINE (process string)
375   (let* ((entry (assoc string epg-prompt-alist))
376          (string (read-string (if entry (cdr entry) (concat string ": ")))))
377     (process-send-string process (concat string "\n"))))
378
379 (defun epg-status-GOODSIG (process string)
380   (if (string-match "\\`\\([^ ]+\\) \\(.*\\)" string)
381       (epg-context-set-result-for
382        epg-context
383        'verify
384        (cons (epg-make-signature 'good
385                                  (match-string 1 string)
386                                  (match-string 2 string))
387              (epg-context-result-for epg-context 'verify)))))
388
389 (defun epg-status-EXPSIG (process string)
390   (if (string-match "\\`\\([^ ]+\\) \\(.*\\)" string)
391       (epg-context-set-result-for
392        epg-context
393        'verify
394        (cons (epg-make-signature 'expired
395                                  (match-string 1 string)
396                                  (match-string 2 string))
397              (epg-context-result-for epg-context 'verify)))))
398
399 (defun epg-status-EXPKEYSIG (process string)
400   (if (string-match "\\`\\([^ ]+\\) \\(.*\\)" string)
401       (epg-context-set-result-for
402        epg-context
403        'verify
404        (cons (epg-make-signature 'expired-key
405                                  (match-string 1 string)
406                                  (match-string 2 string))
407              (epg-context-result-for epg-context 'verify)))))
408
409 (defun epg-status-REVKEYSIG (process string)
410   (if (string-match "\\`\\([^ ]+\\) \\(.*\\)" string)
411       (epg-context-set-result-for
412        epg-context
413        'verify
414        (cons (epg-make-signature 'revoked-key
415                                  (match-string 1 string)
416                                  (match-string 2 string))
417              (epg-context-result-for epg-context 'verify)))))
418
419 (defun epg-status-BADSIG (process string)
420   (if (string-match "\\`\\([^ ]+\\) \\(.*\\)" string)
421       (epg-context-set-result-for
422        epg-context
423        'verify
424        (cons (epg-make-signature 'bad
425                                  (match-string 1 string)
426                                  (match-string 2 string))
427              (epg-context-result-for epg-context 'verify)))))
428
429 (defun epg-status-VALIDSIG (process string)
430   (let ((signature (car (epg-context-result-for epg-context 'verify))))
431     (if (and signature
432              (eq (epg-signature-status signature) 'good)
433              (string-match "\\`\\([^ ]+\\) " string))
434         (epg-signature-set-fingerprint signature (match-string 1 string)))))
435
436 (defun epg-status-TRUST_UNDEFINED (process string)
437   (let ((signature (car (epg-context-result-for epg-context 'verify))))
438     (if (and signature
439              (eq (epg-signature-status signature) 'good))
440         (epg-signature-set-validity signature 'undefined))))
441
442 (defun epg-status-TRUST_NEVER (process string)
443   (let ((signature (car (epg-context-result-for epg-context 'verify))))
444     (if (and signature
445              (eq (epg-signature-status signature) 'good))
446         (epg-signature-set-validity signature 'never))))
447
448 (defun epg-status-TRUST_MARGINAL (process string)
449   (let ((signature (car (epg-context-result-for epg-context 'verify))))
450     (if (and signature
451              (eq (epg-signature-status signature) 'marginal))
452         (epg-signature-set-validity signature 'marginal))))
453
454 (defun epg-status-TRUST_FULLY (process string)
455   (let ((signature (car (epg-context-result-for epg-context 'verify))))
456     (if (and signature
457              (eq (epg-signature-status signature) 'good))
458         (epg-signature-set-validity signature 'fully))))
459
460 (defun epg-status-TRUST_ULTIMATE (process string)
461   (let ((signature (car (epg-context-result-for epg-context 'verify))))
462     (if (and signature
463              (eq (epg-signature-status signature) 'good))
464         (epg-signature-set-validity signature 'ultimate))))
465
466 (defun epg-status-PROGRESS (process string)
467   (if (string-match "\\`\\([^ ]+\\) \\([^ ]\\) \\([0-9]+\\) \\([0-9]+\\)"
468                     string)
469       (funcall (car (epg-context-progress-callback-info epg-context))
470                (match-string 1 string)
471                (match-string 2 string)
472                (string-to-number (match-string 3 string))
473                (string-to-number (match-string 4 string))
474                (cdr (epg-context-progress-callback-info epg-context)))))
475
476 (defun epg-status-DECRYPTION_FAILED (process string)
477   (epg-context-set-result-for
478    epg-context 'error
479    (cons 'decryption-failed
480          (epg-context-result-for epg-context 'error))))
481
482 (defun epg-status-NODATA (process string)
483   (epg-context-set-result-for
484    epg-context 'error
485    (cons (cons 'no-data (string-to-number string))
486          (epg-context-result-for epg-context 'error))))
487
488 (defun epg-status-UNEXPECTED (process string)
489   (epg-context-set-result-for
490    epg-context 'error
491    (cons (cons 'unexpected (string-to-number string))
492          (epg-context-result-for epg-context 'error))))
493
494 (defun epg-status-KEYEXPIRED (process string)
495   (epg-context-set-result-for
496    epg-context 'error
497    (cons (cons 'key-expired string)
498          (epg-context-result-for epg-context 'error))))
499
500 (defun epg-status-KEYREVOKED (process string)
501   (epg-context-set-result-for
502    epg-context 'error
503    (cons 'key-revoked
504          (epg-context-result-for epg-context 'error))))
505
506 (defun epg-status-BADARMOR (process string)
507   (epg-context-set-result-for
508    epg-context 'error
509    (cons 'bad-armor
510          (epg-context-result-for epg-context 'error))))
511
512 (defun epg-passphrase-callback-function (key-id handback)
513   (read-passwd
514    (if (eq key-id 'SYM)
515        "Passphrase for symmetric encryption: "
516      (if (eq key-id 'PIN)
517          "Passphrase for PIN: "
518        (let ((entry (assoc key-id epg-user-id-alist)))
519          (if entry
520              (format "Passphrase for %s %s: " key-id (cdr entry))
521            (format "Passphrase for %s: " key-id)))))))
522
523 (defun epg-progress-callback-function (what char current total handback)
524   (message "%s: %d%%/%d%%" what current total))
525
526 (defun epg-list-keys (name &optional secret)
527   "List keys associated with STRING."
528   (let ((args (list "--with-colons" "--no-greeting" "--batch"
529                     "--fixed-list-mode"
530                     (if secret "--list-secret-keys" "--list-keys")
531                     name))
532         keys type symbol pointer)
533     (with-temp-buffer
534       (apply #'call-process epg-gpg-program nil (list t nil) nil args)
535       (goto-char (point-min))
536       (while (looking-at "\\([a-z][a-z][a-z]\\):\\(.*\\)")
537         (setq type (match-string 1)
538               symbol (intern-soft (format "epg-colons-%s-spec" type)))
539         (if (member type '("pub" "sec"))
540             (setq keys (cons nil keys)))
541         (if (and symbol
542                  (boundp symbol))
543             (setcar keys (cons (cons (intern type)
544                                      (epg-parse-colons
545                                       (symbol-value symbol)
546                                       (match-string 2)))
547                                (car keys))))
548         (forward-line)))
549     (setq pointer keys)
550     (while pointer
551       (setcar pointer (nreverse (car pointer)))
552       (setq pointer (cdr pointer)))
553     (nreverse keys)))
554
555 (defun epg-parse-colons (alist string)
556   (let ((index 0)
557         result)
558     (while (and alist
559                 (or (null (car alist))
560                     (eq index
561                         (string-match
562                          (concat "\\(" (nth 1 (car alist)) "\\)?:")
563                          string index))))
564       (if (car alist)
565           (progn
566             (setq index (match-end 0))
567             (if (match-beginning 1)
568                 (setq result
569                       (cons (cons (car (car alist))
570                                   (funcall (or (nth 3 (car alist)) #'identity)
571                                            (match-string
572                                             (1+ (or (nth 2 (car alist)) 0))
573                                             string)))
574                             result))))
575         (setq index (1+ index)))
576       (setq alist (cdr alist)))
577     (nreverse result)))
578
579 (if (fboundp 'make-temp-file)
580     (defalias 'epg-make-temp-file 'make-temp-file)
581   ;; stolen from poe.el.
582   (defun epg-make-temp-file (prefix)
583     "Create a temporary file.
584 The returned file name (created by appending some random characters at the end
585 of PREFIX, and expanding against `temporary-file-directory' if necessary),
586 is guaranteed to point to a newly created empty file.
587 You can then use `write-region' to write new data into the file."
588     (let (tempdir tempfile)
589       (unwind-protect
590           (let (file)
591             ;; First, create a temporary directory.
592             (while (condition-case ()
593                        (progn
594                          (setq tempdir (make-temp-name
595                                         (concat
596                                          (file-name-directory prefix)
597                                          "DIR")))
598                          ;; return nil or signal an error.
599                          (make-directory tempdir))
600                      ;; let's try again.
601                      (file-already-exists t)))
602             (set-file-modes tempdir 448)
603             ;; Second, create a temporary file in the tempdir.
604             ;; There *is* a race condition between `make-temp-name'
605             ;; and `write-region', but we don't care it since we are
606             ;; in a private directory now.
607             (setq tempfile (make-temp-name (concat tempdir "/EMU")))
608             (write-region "" nil tempfile nil 'silent)
609             (set-file-modes tempfile 384)
610             ;; Finally, make a hard-link from the tempfile.
611             (while (condition-case ()
612                        (progn
613                          (setq file (make-temp-name prefix))
614                          ;; return nil or signal an error.
615                          (add-name-to-file tempfile file))
616                      ;; let's try again.
617                      (file-already-exists t)))
618             file)
619         ;; Cleanup the tempfile.
620         (and tempfile
621              (file-exists-p tempfile)
622              (delete-file tempfile))
623         ;; Cleanup the tempdir.
624         (and tempdir
625              (file-directory-p tempdir)
626              (delete-directory tempdir))))))
627
628 ;;;###autoload
629 (defun epg-start-decrypt (context input-file)
630   "Initiate a decrypt operation on INPUT-FILE.
631
632 If you use this function, you will need to wait for the completion of
633 `epg-gpg-program' by using `epg-wait-for-completion' and call
634 `epg-reset' to clear a temporaly output file.
635 If you are unsure, use synchronous version of this function
636 `epg-decrypt-string' instead."
637   (epg-context-set-result context nil)
638   (epg-context-set-output-file context (epg-make-temp-file "epg-output"))
639   (epg-start context
640              (list "--decrypt" input-file))
641   (epg-wait-for-status context '("BEGIN_DECRYPTION")))
642
643 ;;;###autoload
644 (defun epg-decrypt-file (context input-file)
645   "Decrypt INPUT-FILE and return the plain text."
646   (unwind-protect
647       (progn
648         (epg-start-decrypt context input-file)
649         (epg-wait-for-completion context)
650         (if (epg-context-result-for context 'error)
651             (error "Decryption failed"))
652         (epg-read-output context))
653     (epg-reset context)))
654
655 ;;;###autoload
656 (defun epg-decrypt-string (context string)
657   "Decrypt STRING and return the plain text."
658   (let ((input-file (epg-make-temp-file "epg-input"))
659         (coding-system-for-write 'binary))
660     (unwind-protect
661         (progn
662           (write-region string nil input-file)
663           (epg-decrypt-file context input-file))
664       (if (file-exists-p input-file)
665           (delete-file input-file)))))
666
667 ;;;###autoload
668 (defun epg-start-verify (context signature &optional string)
669   "Initiate a verify operation on SIGNATURE.
670
671 For a detached signature, both SIGNATURE and STRING should be string.
672 For a normal or a clear text signature, STRING should be nil.
673
674 If you use this function, you will need to wait for the completion of
675 `epg-gpg-program' by using `epg-wait-for-completion' and call
676 `epg-reset' to clear a temporaly output file.
677 If you are unsure, use synchronous version of this function
678 `epg-verify-string' instead."
679   (epg-context-set-result context nil)
680   (epg-context-set-output-file context (epg-make-temp-file "epg-output"))
681   (if string
682       ;; Detached signature.
683       (progn
684         (epg-start context
685                    (append (list "--verify")
686                            (list signature "-")))
687         (if (eq (process-status (epg-context-process context)) 'run)
688             (process-send-string (epg-context-process context) string)))
689     ;; Normal (or cleartext) signature.
690     (epg-start context (list "--verify"))
691     (if (eq (process-status (epg-context-process context)) 'run)
692         (process-send-string (epg-context-process context) signature))))
693
694 ;;;###autoload
695 (defun epg-verify-file (context input-file &optional string)
696   "Verify INPUT-FILE.
697
698 For a detached signature, both INPUT-FILE and STRING should be string.
699 For a normal or a clear text signature, STRING should be nil."
700   (unwind-protect
701       (progn
702         (epg-start-verify context input-file string)
703         (epg-wait-for-completion context)
704         (epg-context-result-for context 'verify))
705     (epg-reset context)))
706
707 ;;;###autoload
708 (defun epg-verify-string (context signature &optional string)
709   "Verify SIGNATURE.
710
711 For a detached signature, both SIGNATURE and STRING should be string.
712 For a normal or a clear text signature, STRING should be nil."
713   (let ((input-file (epg-make-temp-file "epg-input"))
714         (coding-system-for-write 'binary))
715     (unwind-protect
716         (progn
717           (if string
718               (write-region signature nil input-file))
719           (epg-verify-file context input-file string))
720       (if (file-exists-p input-file)
721           (delete-file input-file)))))
722
723 ;;;###autoload
724 (defun epg-start-sign (context string &optional mode)
725   "Initiate a sign operation on STRING.
726
727 If optional 3rd argument MODE is 'clearsign, it makes a clear text signature.
728 If MODE is t or 'detached, it makes a detached signature.
729 Otherwise, it makes a normal signature.
730
731 If you use this function, you will need to wait for the completion of
732 `epg-gpg-program' by using `epg-wait-for-completion' and call
733 `epg-reset' to clear a temporaly output file.
734 If you are unsure, use synchronous version of this function
735 `epg-sign-string' instead."
736   (epg-context-set-result context nil)
737   (epg-context-set-output-file context (epg-make-temp-file "epg-output"))
738   (epg-start context
739              (append (list (if (eq mode 'clearsign)
740                                "--clearsign"
741                              (if (or (eq mode t) (eq mode 'detached))
742                                  "--detach-sign"
743                                "--sign")))
744                      (apply #'nconc
745                             (mapcar (lambda (signer)
746                                       (list "-u" signer))
747                                     (epg-context-signers context)))))
748   (epg-wait-for-status context '("BEGIN_SIGNING"))
749   (if (eq (process-status (epg-context-process context)) 'run)
750       (process-send-string (epg-context-process context) string)))
751
752 ;;;###autoload
753 (defun epg-sign-string (context string &optional mode)
754   "Sign STRING and return the output as string.
755 If optional 3rd argument MODE is 'clearsign, it makes a clear text signature.
756 If MODE is t or 'detached, it makes a detached signature.
757 Otherwise, it makes a normal signature."
758   (unwind-protect
759       (progn
760         (epg-start-sign context string mode)
761         (epg-wait-for-completion context)
762         (if (epg-context-result-for context 'error)
763             (error "Sign failed"))
764         (epg-read-output context))
765     (epg-reset context)))
766
767 ;;;###autoload
768 (defun epg-start-encrypt (context string recipients
769                                   &optional sign always-trust)
770   "Initiate an encrypt operation on STRING.
771 If RECIPIENTS is nil, it performs symmetric encryption.
772
773 If you use this function, you will need to wait for the completion of
774 `epg-gpg-program' by using `epg-wait-for-completion' and call
775 `epg-reset' to clear a temporaly output file.
776 If you are unsure, use synchronous version of this function
777 `epg-encrypt-string' instead."
778   (epg-context-set-result context nil)
779   (epg-context-set-output-file context (epg-make-temp-file "epg-output"))
780   (epg-start context
781              (append (if always-trust '("--always-trust"))
782                      (if recipients '("--encrypt") '("--symmetric"))
783                      (if sign
784                          (cons "--sign"
785                                (apply #'nconc
786                                       (mapcar (lambda (signer)
787                                                 (list "-u" signer))
788                                               (epg-context-signers context)))))
789                      (apply #'nconc
790                             (mapcar (lambda (recipient)
791                                       (list "-r" recipient))
792                                     recipients))))
793   (if sign
794       (epg-wait-for-status context '("BEGIN_SIGNING"))
795     (if (null recipients)
796         (epg-wait-for-status context '("BEGIN_ENCRYPTION"))))
797   (if (eq (process-status (epg-context-process context)) 'run)
798       (process-send-string (epg-context-process context) string)))
799
800 ;;;###autoload
801 (defun epg-encrypt-string (context string recipients
802                                    &optional sign always-trust)
803   "Encrypt STRING.
804 If RECIPIENTS is nil, it performs symmetric encryption."
805   (unwind-protect
806       (progn
807         (epg-start-encrypt context string recipients sign always-trust)
808         (epg-wait-for-completion context)
809         (if (epg-context-result-for context 'error)
810             (error "Encrypt failed"))
811         (epg-read-output context))
812     (epg-reset context)))
813
814 ;;;###autoload
815 (defun epg-start-export-keys (context pattern)
816   "Initiate an export keys operation.
817
818 If you use this function, you will need to wait for the completion of
819 `epg-gpg-program' by using `epg-wait-for-completion' and call
820 `epg-reset' to clear a temporaly output file.
821 If you are unsure, use synchronous version of this function
822 `epg-export-keys' instead."
823   (epg-context-set-result context nil)
824   (epg-context-set-output-file context (epg-make-temp-file "epg-output"))
825   (epg-start context (list "--export" pattern)))
826
827 ;;;###autoload
828 (defun epg-export-keys (context pattern)
829   "Extract public keys matched with PATTERN and return them."
830   (unwind-protect
831       (progn
832         (epg-start-export-keys context pattern)
833         (epg-wait-for-completion context)
834         (if (epg-context-result-for context 'error)
835             (error "Export keys failed"))
836         (epg-read-output context))
837     (epg-reset context)))
838
839 ;;;###autoload
840 (defun epg-start-import-keys (context keys)
841   "Initiate an import key operation.
842
843 If you use this function, you will need to wait for the completion of
844 `epg-gpg-program' by using `epg-wait-for-completion' and call
845 `epg-reset' to clear a temporaly output file.
846 If you are unsure, use synchronous version of this function
847 `epg-import-keys' instead."
848   (epg-context-set-result context nil)
849   (epg-context-set-output-file context (epg-make-temp-file "epg-output"))
850   (epg-start context (list "--import"))
851   (if (eq (process-status (epg-context-process context)) 'run)
852       (process-send-string (epg-context-process context) keys)))
853
854 ;;;###autoload
855 (defun epg-import-keys (context keys)
856   "Add KEYS."
857   (unwind-protect
858       (progn
859         (epg-start-import-keys context keys)
860         (epg-wait-for-completion context)
861         (if (epg-context-result-for context 'error)
862             (error "Import keys failed"))
863         (epg-read-output context))
864     (epg-reset context)))
865
866 (provide 'epg)
867
868 ;;; epg.el ends here