75d210fe0c5ddc35acb575fb2c543467c28817f8
[elisp/epg.git] / epg.el
1 ;;; epg.el --- the EasyPG Library
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   "The EasyPG Library")
30
31 (defcustom epg-gpg-program "gpg"
32   "The `gpg' executable."
33   :group 'epg
34   :type 'string)
35
36 (defconst epg-version-number "0.0.0")
37
38 (defvar epg-user-id nil
39   "GnuPG ID of your default identity.")
40
41 (defvar epg-user-id-alist nil
42   "An alist mapping from key ID to user ID.")
43
44 (defvar epg-read-point nil)
45 (defvar epg-pending-status-list nil)
46 (defvar epg-key-id nil)
47 (defvar epg-context nil)
48 (defvar epg-debug nil)
49
50 ;; from gnupg/include/cipher.h
51 (defconst epg-cipher-algorithm-alist
52   '((0 . "NONE")
53     (1 . "IDEA")
54     (2 . "3DES")
55     (3 . "CAST5")
56     (4 . "BLOWFISH")
57     (7 . "AES")
58     (8 . "AES192")
59     (9 . "AES256")
60     (10 . "TWOFISH")
61     (110 . "DUMMY")))
62
63 ;; from gnupg/include/cipher.h
64 (defconst epg-pubkey-algorithm-alist
65   '((1 . "RSA")
66     (2 . "RSA_E")
67     (3 . "RSA_S")
68     (16 . "ELGAMAL_E")
69     (17 . "DSA")
70     (20 . "ELGAMAL")))
71
72 ;; from gnupg/include/cipher.h
73 (defconst epg-digest-algorithm-alist
74   '((1 . "MD5")
75     (2 . "SHA1")
76     (3 . "RMD160")
77     (8 . "SHA256")
78     (9 . "SHA384")
79     (10 . "SHA512")))
80
81 ;; from gnupg/include/cipher.h
82 (defconst epg-compress-algorithm-alist
83   '((0 . "NONE")
84     (1 . "ZIP")
85     (2 . "ZLIB")
86     (3 . "BZIP2")))
87
88 (defconst epg-invalid-recipients-alist
89   '((0 . "No specific reason given")
90     (1 . "Not Found")
91     (2 . "Ambigious specification")
92     (3 . "Wrong key usage")
93     (4 . "Key revoked")
94     (5 . "Key expired")
95     (6 . "No CRL known")
96     (7 . "CRL too old")
97     (8 . "Policy mismatch")
98     (9 . "Not a secret key")
99     (10 . "Key not trusted")))
100
101 (defconst epg-delete-problem-alist
102   '((1 . "No such key")
103     (2 . "Must delete secret key first")
104     (3 . "Ambigious specification")))
105
106 (defvar epg-key-validity-alist
107   '((?o . unknown)
108     (?i . invalid)
109     (?d . disabled)
110     (?r . revoked)
111     (?e . expired)
112     (?- . none)
113     (?q . undefined)
114     (?n . never)
115     (?m . marginal)
116     (?f . full)
117     (?u . ultimate)))
118
119 (defvar epg-key-capablity-alist
120   '((?e . encrypt)
121     (?s . sign)
122     (?c . certify)
123     (?a . authentication)))
124
125 (defvar epg-prompt-alist nil)
126
127 (defun epg-make-data-from-file (file)
128   "Make a data object from FILE."
129   (vector file nil))
130
131 (defun epg-make-data-from-string (string)
132   "Make a data object from STRING."
133   (vector nil string))
134
135 (defun epg-data-file (data)
136   "Return the file of DATA."
137   (aref data 0))
138
139 (defun epg-data-string (data)
140   "Return the string of DATA."
141   (aref data 1))
142
143 (defun epg-make-context (&optional protocol armor textmode include-certs
144                                    cipher-algorithm digest-algorithm
145                                    compress-algorithm)
146   "Return a context object."
147   (vector protocol armor textmode include-certs
148           cipher-algorithm digest-algorithm compress-algorithm
149           #'epg-passphrase-callback-function
150           #'epg-progress-callback-function
151           nil nil nil nil))
152
153 (defun epg-context-protocol (context)
154   "Return the protocol used within CONTEXT."
155   (aref context 0))
156
157 (defun epg-context-armor (context)
158   "Return t if the output shouled be ASCII armored in CONTEXT."
159   (aref context 1))
160
161 (defun epg-context-textmode (context)
162   "Return t if canonical text mode should be used in CONTEXT."
163   (aref context 2))
164
165 (defun epg-context-include-certs (context)
166   "Return how many certificates should be included in an S/MIME signed
167 message."
168   (aref context 3))
169
170 (defun epg-context-cipher-algorithm (context)
171   "Return the cipher algorithm in CONTEXT."
172   (aref context 4))
173
174 (defun epg-context-digest-algorithm (context)
175   "Return the digest algorithm in CONTEXT."
176   (aref context 5))
177
178 (defun epg-context-compress-algorithm (context)
179   "Return the compress algorithm in CONTEXT."
180   (aref context 6))
181
182 (defun epg-context-passphrase-callback (context)
183   "Return the function used to query passphrase."
184   (aref context 7))
185
186 (defun epg-context-progress-callback (context)
187   "Return the function which handles progress update."
188   (aref context 8))
189
190 (defun epg-context-signers (context)
191   "Return the list of key-id for singning."
192   (aref context 9))
193
194 (defun epg-context-process (context)
195   "Return the process object of `epg-gpg-program'.
196 This function is for internal use only."
197   (aref context 10))
198
199 (defun epg-context-output-file (context)
200   "Return the output file of `epg-gpg-program'.
201 This function is for internal use only."
202   (aref context 11))
203
204 (defun epg-context-result (context)
205   "Return the result of the previous cryptographic operation."
206   (aref context 12))
207
208 (defun epg-context-set-protocol (context protocol)
209   "Set the protocol used within CONTEXT."
210   (aset context 0 protocol))
211
212 (defun epg-context-set-armor (context armor)
213   "Specify if the output shouled be ASCII armored in CONTEXT."
214   (aset context 1 armor))
215
216 (defun epg-context-set-textmode (context textmode)
217   "Specify if canonical text mode should be used in CONTEXT."
218   (aset context 2 textmode))
219
220 (defun epg-context-set-include-certs (context include-certs)
221  "Set how many certificates should be included in an S/MIME signed message."
222   (aset context 3 include-certs))
223
224 (defun epg-context-set-cipher-algorithm (context cipher-algorithm)
225  "Set the cipher algorithm in CONTEXT."
226   (aset context 4 cipher-algorithm))
227
228 (defun epg-context-set-digest-algorithm (context digest-algorithm)
229  "Set the digest algorithm in CONTEXT."
230   (aset context 5 digest-algorithm))
231
232 (defun epg-context-set-compress-algorithm (context compress-algorithm)
233  "Set the compress algorithm in CONTEXT."
234   (aset context 6 compress-algorithm))
235
236 (defun epg-context-set-passphrase-callback (context
237                                                  passphrase-callback)
238   "Set the function used to query passphrase."
239   (aset context 7 passphrase-callback))
240
241 (defun epg-context-set-progress-callback (context progress-callback)
242   "Set the function which handles progress update."
243   (aset context 8 progress-callback))
244
245 (defun epg-context-set-signers (context signers)
246  "Set the list of key-id for singning."
247   (aset context 9 signers))
248
249 (defun epg-context-set-process (context process)
250   "Set the process object of `epg-gpg-program'.
251 This function is for internal use only."
252   (aset context 10 process))
253
254 (defun epg-context-set-output-file (context output-file)
255   "Set the output file of `epg-gpg-program'.
256 This function is for internal use only."
257   (aset context 11 output-file))
258
259 (defun epg-context-set-result (context result)
260   "Set the result of the previous cryptographic operation."
261   (aset context 12 result))
262
263 (defun epg-make-signature (status key-id user-id)
264   "Return a signature object."
265   (vector status key-id user-id nil nil))
266
267 (defun epg-signature-status (signature)
268   "Return the status code of SIGNATURE."
269   (aref signature 0))
270
271 (defun epg-signature-key-id (signature)
272   "Return the key-id of SIGNATURE."
273   (aref signature 1))
274
275 (defun epg-signature-user-id (signature)
276   "Return the user-id of SIGNATURE."
277   (aref signature 2))
278   
279 (defun epg-signature-validity (signature)
280   "Return the validity of SIGNATURE."
281   (aref signature 3))
282
283 (defun epg-signature-fingerprint (signature)
284   "Return the fingerprint of SIGNATURE."
285   (aref signature 4))
286
287 (defun epg-signature-set-status (signature status)
288  "Set the status code of SIGNATURE."
289   (aset signature 0 status))
290
291 (defun epg-signature-set-key-id (signature key-id)
292  "Set the key-id of SIGNATURE."
293   (aset signature 1 key-id))
294
295 (defun epg-signature-set-user-id (signature user-id)
296  "Set the user-id of SIGNATURE."
297   (aset signature 2 user-id))
298   
299 (defun epg-signature-set-validity (signature validity)
300  "Set the validity of SIGNATURE."
301   (aset signature 3 validity))
302
303 (defun epg-signature-set-fingerprint (signature fingerprint)
304  "Set the fingerprint of SIGNATURE."
305   (aset signature 4 fingerprint))
306
307 (defun epg-make-key (owner-trust)
308   "Return a key object."
309   (vector owner-trust nil nil))
310
311 (defun epg-key-owner-trust (key)
312   "Return the owner trust of KEY."
313   (aref key 0))
314
315 (defun epg-key-sub-key-list (key)
316   "Return the sub key list of KEY."
317   (aref key 1))
318
319 (defun epg-key-user-id-list (key)
320   "Return the user ID list of KEY."
321   (aref key 2))
322
323 (defun epg-key-set-sub-key-list (key sub-key-list)
324   "Set the sub key list of KEY."
325   (aset key 1 sub-key-list))
326
327 (defun epg-key-set-user-id-list (key user-id-list)
328   "Set the user ID list of KEY."
329   (aset key 2 user-id-list))
330
331 (defun epg-make-sub-key (validity capability secret algorithm length id
332                                   creation-time expiration-time)
333   "Return a sub key object."
334   (vector validity capability secret algorithm length id creation-time
335           expiration-time nil))
336
337 (defun epg-sub-key-validity (sub-key)
338   "Return the validity of SUB-KEY."
339   (aref sub-key 0))
340
341 (defun epg-sub-key-capability (sub-key)
342   "Return the capability of SUB-KEY."
343   (aref sub-key 1))
344
345 (defun epg-sub-key-secret (sub-key)
346   "Return non-nil if SUB-KEY is a secret key."
347   (aref sub-key 2))
348
349 (defun epg-sub-key-algorithm (sub-key)
350   "Return the algorithm of SUB-KEY."
351   (aref sub-key 3))
352
353 (defun epg-sub-key-length (sub-key)
354   "Return the length of SUB-KEY."
355   (aref sub-key 4))
356
357 (defun epg-sub-key-id (sub-key)
358   "Return the ID of SUB-KEY."
359   (aref sub-key 5))
360
361 (defun epg-sub-key-creation-time (sub-key)
362   "Return the creation time of SUB-KEY."
363   (aref sub-key 6))
364
365 (defun epg-sub-key-expiration-time (sub-key)
366   "Return the expiration time of SUB-KEY."
367   (aref sub-key 7))
368
369 (defun epg-sub-key-fingerprint (sub-key)
370   "Return the fingerprint of SUB-KEY."
371   (aref sub-key 8))
372
373 (defun epg-sub-key-set-fingerprint (sub-key fingerprint)
374   "Set the fingerprint of SUB-KEY.
375 This function is for internal use only."
376   (aset sub-key 8 fingerprint))
377
378 (defun epg-make-user-id (validity name)
379   "Return a user ID object."
380   (vector validity name nil))
381
382 (defun epg-user-id-validity (user-id)
383   "Return the validity of USER-ID."
384   (aref user-id 0))
385
386 (defun epg-user-id-name (user-id)
387   "Return the name of USER-ID."
388   (aref user-id 1))
389
390 (defun epg-user-id-signature-list (user-id)
391   "Return the signature list of USER-ID."
392   (aref user-id 2))
393
394 (defun epg-user-id-set-signature-list (user-id signature-list)
395   "Set the signature list of USER-ID."
396   (aset user-id 2 signature-list))
397
398 (defun epg-context-result-for (context name)
399   (cdr (assq name (epg-context-result context))))
400
401 (defun epg-context-set-result-for (context name value)
402   (let* ((result (epg-context-result context))
403          (entry (assq name result)))
404     (if entry
405         (setcdr entry value)
406       (epg-context-set-result context (cons (cons name value) result)))))
407
408 (defun epg-start (context args)
409   "Start `epg-gpg-program' in a subprocess with given ARGS."
410   (let* ((args (append (list "--no-tty"
411                              "--status-fd" "1"
412                              "--command-fd" "0"
413                              "--yes")
414                        (if (epg-context-armor context) '("--armor"))
415                        (if (epg-context-textmode context) '("--textmode"))
416                        (if (epg-context-output-file context)
417                            (list "--output" (epg-context-output-file context)))
418                        args))
419          (coding-system-for-write 'binary)
420          process-connection-type
421          (orig-mode (default-file-modes))
422          (buffer (generate-new-buffer " *epg*"))
423          process)
424     (if epg-debug
425         (save-excursion
426           (set-buffer (get-buffer-create  " *epg-debug*"))
427           (goto-char (point-max))
428           (insert (format "%s %s\n" epg-gpg-program
429                           (mapconcat #'identity args " ")))))
430     (with-current-buffer buffer
431       (make-local-variable 'epg-read-point)
432       (setq epg-read-point (point-min))
433       (make-local-variable 'epg-pending-status-list)
434       (setq epg-pending-status-list nil)
435       (make-local-variable 'epg-key-id)
436       (setq epg-key-id nil)
437       (make-local-variable 'epg-context)
438       (setq epg-context context))
439     (unwind-protect
440         (progn
441           (set-default-file-modes 448)
442           (setq process
443                 (apply #'start-process "epg" buffer epg-gpg-program args)))
444       (set-default-file-modes orig-mode))
445     (set-process-filter process #'epg-process-filter)
446     (epg-context-set-process context process)))
447
448 (defun epg-process-filter (process input)
449   (if epg-debug
450       (save-excursion
451         (set-buffer (get-buffer-create  " *epg-debug*"))
452         (goto-char (point-max))
453         (insert input)))
454   (if (buffer-live-p (process-buffer process))
455       (save-excursion
456         (set-buffer (process-buffer process))
457         (goto-char (point-max))
458         (insert input)
459         (goto-char epg-read-point)
460         (beginning-of-line)
461         (while (looking-at ".*\n")      ;the input line finished
462           (save-excursion
463             (if (looking-at "\\[GNUPG:] \\([A-Z_]+\\) ?\\(.*\\)")
464                 (let* ((status (match-string 1))
465                        (string (match-string 2))
466                        (symbol (intern-soft (concat "epg-status-" status))))
467                   (if (member status epg-pending-status-list)
468                       (setq epg-pending-status-list nil))
469                   (if (and symbol
470                            (fboundp symbol))
471                       (funcall symbol process string))
472                   (condition-case nil
473                       (run-hook-with-args-until-success
474                        (intern (concat "epg-after-status-" status "-function"))
475                        string)
476                     (error)))))
477           (forward-line))
478         (setq epg-read-point (point)))))
479
480 (defun epg-read-output (context)
481   (with-temp-buffer
482     (if (fboundp 'set-buffer-multibyte)
483         (set-buffer-multibyte nil))
484     (if (file-exists-p (epg-context-output-file context))
485         (let ((coding-system-for-read (if (epg-context-textmode context)
486                                           'raw-text
487                                         'binary)))
488           (insert-file-contents (epg-context-output-file context))
489           (buffer-string)))))
490
491 (defun epg-wait-for-status (context status-list)
492   (with-current-buffer (process-buffer (epg-context-process context))
493     (setq epg-pending-status-list status-list)
494     (while (and (eq (process-status (epg-context-process context)) 'run)
495                 epg-pending-status-list)
496       (accept-process-output (epg-context-process context) 1))))
497
498 (defun epg-wait-for-completion (context &optional no-eof)
499   (if (and (not no-eof)
500            (eq (process-status (epg-context-process context)) 'run))
501       (process-send-eof (epg-context-process context)))
502   (while (eq (process-status (epg-context-process context)) 'run)
503     ;; We can't use accept-process-output instead of sit-for here
504     ;; because it may cause an interrupt during the sentinel execution.
505     (sit-for 0.1)))
506
507 (defun epg-reset (context)
508   (if (and (epg-context-process context)
509            (buffer-live-p (process-buffer (epg-context-process context))))
510       (kill-buffer (process-buffer (epg-context-process context))))
511   (epg-context-set-process context nil))
512
513 (defun epg-delete-output-file (context)
514   (if (and (epg-context-output-file context)
515            (file-exists-p (epg-context-output-file context)))
516       (delete-file (epg-context-output-file context))))
517
518 (defun epg-status-USERID_HINT (process string)
519   (if (string-match "\\`\\([^ ]+\\) \\(.*\\)" string)
520       (let* ((key-id (match-string 1 string))
521              (user-id (match-string 2 string))
522              (entry (assoc key-id epg-user-id-alist)))
523         (if entry
524             (setcdr entry user-id)
525           (setq epg-user-id-alist (cons (cons key-id user-id)
526                                         epg-user-id-alist))))))
527
528 (defun epg-status-NEED_PASSPHRASE (process string)
529   (if (string-match "\\`\\([^ ]+\\)" string)
530       (setq epg-key-id (match-string 1 string))))
531
532 (defun epg-status-NEED_PASSPHRASE_SYM (process string)
533   (setq epg-key-id 'SYM))
534
535 (defun epg-status-NEED_PASSPHRASE_PIN (process string)
536   (setq epg-key-id 'PIN))
537
538 (defun epg-status-GET_HIDDEN (process string)
539   (let ((passphrase
540          (funcall (if (consp (epg-context-passphrase-callback epg-context))
541                       (car (epg-context-passphrase-callback epg-context))
542                     (epg-context-passphrase-callback epg-context))
543                   (if (consp (epg-context-passphrase-callback epg-context))
544                       (cdr (epg-context-passphrase-callback epg-context)))))
545         string)
546     (if passphrase
547         (unwind-protect
548             (progn
549               (setq string (concat passphrase "\n"))
550               (fillarray passphrase 0)
551               (setq passphrase nil)
552               (process-send-string process string))
553           (if string
554               (fillarray string 0))))))
555
556 (defun epg-status-GET_BOOL (process string)
557   (let ((entry (assoc string epg-prompt-alist)))
558     (if (y-or-n-p (if entry (cdr entry) (concat string "? ")))
559         (process-send-string process "y\n")
560       (process-send-string process "n\n"))))
561
562 (defun epg-status-GET_LINE (process string)
563   (let* ((entry (assoc string epg-prompt-alist))
564          (string (read-string (if entry (cdr entry) (concat string ": ")))))
565     (process-send-string process (concat string "\n"))))
566
567 (defun epg-status-GOODSIG (process string)
568   (if (string-match "\\`\\([^ ]+\\) \\(.*\\)" string)
569       (epg-context-set-result-for
570        epg-context
571        'verify
572        (cons (epg-make-signature 'good
573                                  (match-string 1 string)
574                                  (match-string 2 string))
575              (epg-context-result-for epg-context 'verify)))))
576
577 (defun epg-status-EXPSIG (process string)
578   (if (string-match "\\`\\([^ ]+\\) \\(.*\\)" string)
579       (epg-context-set-result-for
580        epg-context
581        'verify
582        (cons (epg-make-signature 'expired
583                                  (match-string 1 string)
584                                  (match-string 2 string))
585              (epg-context-result-for epg-context 'verify)))))
586
587 (defun epg-status-EXPKEYSIG (process string)
588   (if (string-match "\\`\\([^ ]+\\) \\(.*\\)" string)
589       (epg-context-set-result-for
590        epg-context
591        'verify
592        (cons (epg-make-signature 'expired-key
593                                  (match-string 1 string)
594                                  (match-string 2 string))
595              (epg-context-result-for epg-context 'verify)))))
596
597 (defun epg-status-REVKEYSIG (process string)
598   (if (string-match "\\`\\([^ ]+\\) \\(.*\\)" string)
599       (epg-context-set-result-for
600        epg-context
601        'verify
602        (cons (epg-make-signature 'revoked-key
603                                  (match-string 1 string)
604                                  (match-string 2 string))
605              (epg-context-result-for epg-context 'verify)))))
606
607 (defun epg-status-BADSIG (process string)
608   (if (string-match "\\`\\([^ ]+\\) \\(.*\\)" string)
609       (epg-context-set-result-for
610        epg-context
611        'verify
612        (cons (epg-make-signature 'bad
613                                  (match-string 1 string)
614                                  (match-string 2 string))
615              (epg-context-result-for epg-context 'verify)))))
616
617 (defun epg-status-VALIDSIG (process string)
618   (let ((signature (car (epg-context-result-for epg-context 'verify))))
619     (if (and signature
620              (eq (epg-signature-status signature) 'good)
621              (string-match "\\`\\([^ ]+\\) " string))
622         (epg-signature-set-fingerprint signature (match-string 1 string)))))
623
624 (defun epg-status-TRUST_UNDEFINED (process string)
625   (let ((signature (car (epg-context-result-for epg-context 'verify))))
626     (if (and signature
627              (eq (epg-signature-status signature) 'good))
628         (epg-signature-set-validity signature 'undefined))))
629
630 (defun epg-status-TRUST_NEVER (process string)
631   (let ((signature (car (epg-context-result-for epg-context 'verify))))
632     (if (and signature
633              (eq (epg-signature-status signature) 'good))
634         (epg-signature-set-validity signature 'never))))
635
636 (defun epg-status-TRUST_MARGINAL (process string)
637   (let ((signature (car (epg-context-result-for epg-context 'verify))))
638     (if (and signature
639              (eq (epg-signature-status signature) 'marginal))
640         (epg-signature-set-validity signature 'marginal))))
641
642 (defun epg-status-TRUST_FULLY (process string)
643   (let ((signature (car (epg-context-result-for epg-context 'verify))))
644     (if (and signature
645              (eq (epg-signature-status signature) 'good))
646         (epg-signature-set-validity signature 'full))))
647
648 (defun epg-status-TRUST_ULTIMATE (process string)
649   (let ((signature (car (epg-context-result-for epg-context 'verify))))
650     (if (and signature
651              (eq (epg-signature-status signature) 'good))
652         (epg-signature-set-validity signature 'ultimate))))
653
654 (defun epg-status-PROGRESS (process string)
655   (if (string-match "\\`\\([^ ]+\\) \\([^ ]\\) \\([0-9]+\\) \\([0-9]+\\)"
656                     string)
657       (funcall (if (consp (epg-context-progress-callback epg-context))
658                    (car (epg-context-progress-callback epg-context))
659                  (epg-context-progress-callback epg-context))
660                (match-string 1 string)
661                (match-string 2 string)
662                (string-to-number (match-string 3 string))
663                (string-to-number (match-string 4 string))
664                (if (consp (epg-context-progress-callback epg-context))
665                    (cdr (epg-context-progress-callback epg-context))))))
666
667 (defun epg-status-DECRYPTION_FAILED (process string)
668   (epg-context-set-result-for
669    epg-context 'error
670    (cons 'decryption-failed
671          (epg-context-result-for epg-context 'error))))
672
673 (defun epg-status-NODATA (process string)
674   (epg-context-set-result-for
675    epg-context 'error
676    (cons (cons 'no-data (string-to-number string))
677          (epg-context-result-for epg-context 'error))))
678
679 (defun epg-status-UNEXPECTED (process string)
680   (epg-context-set-result-for
681    epg-context 'error
682    (cons (cons 'unexpected (string-to-number string))
683          (epg-context-result-for epg-context 'error))))
684
685 (defun epg-status-KEYEXPIRED (process string)
686   (epg-context-set-result-for
687    epg-context 'error
688    (cons (cons 'key-expired string)
689          (epg-context-result-for epg-context 'error))))
690
691 (defun epg-status-KEYREVOKED (process string)
692   (epg-context-set-result-for
693    epg-context 'error
694    (cons 'key-revoked
695          (epg-context-result-for epg-context 'error))))
696
697 (defun epg-status-BADARMOR (process string)
698   (epg-context-set-result-for
699    epg-context 'error
700    (cons 'bad-armor
701          (epg-context-result-for epg-context 'error))))
702
703 (defun epg-status-INV_RECP (process string)
704   (if (string-match "\\`\\([0-9]+\\) \\(.*\\)" string)
705       (epg-context-set-result-for
706        epg-context 'error
707        (cons (list 'invalid-recipient
708                    (string-to-number (match-string 1 string))
709                    (match-string 2 string))
710              (epg-context-result-for epg-context 'error)))))
711
712 (defun epg-status-NO_RECP (process string)
713   (epg-context-set-result-for
714    epg-context 'error
715    (cons 'no-recipients
716          (epg-context-result-for epg-context 'error))))
717
718 (defun epg-status-DELETE_PROBLEM (process string)
719   (if (string-match "\\`\\([0-9]+\\)" string)
720       (epg-context-set-result-for
721        epg-context 'error
722        (cons (cons 'delete-problem (string-to-number (match-string 1 string)))
723              (epg-context-result-for epg-context 'error)))))
724
725 (defun epg-passphrase-callback-function (handback)
726   (read-passwd
727    (if (eq epg-key-id 'SYM)
728        "Passphrase for symmetric encryption: "
729      (if (eq epg-key-id 'PIN)
730          "Passphrase for PIN: "
731        (let ((entry (assoc epg-key-id epg-user-id-alist)))
732          (if entry
733              (format "Passphrase for %s %s: " epg-key-id (cdr entry))
734            (format "Passphrase for %s: " epg-key-id)))))))
735
736 (defun epg-progress-callback-function (what char current total handback)
737   (message "%s: %d%%/%d%%" what current total))
738
739 (defun epg-configuration ()
740   "Return a list of internal configuration parameters of `epg-gpg-program'."
741   (let (config type)
742     (with-temp-buffer
743       (apply #'call-process epg-gpg-program nil (list t nil) nil
744              '("--with-colons" "--list-config"))
745       (goto-char (point-min))
746       (while (re-search-forward "^cfg:\\([^:]+\\):\\(.*\\)" nil t)
747         (setq type (intern (match-string 1))
748               config (cons (cons type
749                                  (if (memq type
750                                            '(pubkey cipher digest compress))
751                                      (mapcar #'string-to-number
752                                              (delete "" (split-string
753                                                          (match-string 2)
754                                                          ";")))
755                                    (match-string 2)))
756                            config))))
757     config))
758
759 (defun epg-list-keys-1 (name mode)
760   (let ((args (append (list "--with-colons" "--no-greeting" "--batch"
761                             "--fixed-list-mode" "--with-fingerprint"
762                             "--with-fingerprint"
763                             (if mode "--list-secret-keys" "--list-keys"))
764                       (if name (list name))))
765         keys string field index)
766     (with-temp-buffer
767       (apply #'call-process epg-gpg-program nil (list t nil) nil args)
768       (goto-char (point-min))
769       (while (re-search-forward "^[a-z][a-z][a-z]:.*" nil t)
770         (setq keys (cons (make-vector 15 nil) keys)
771               string (match-string 0)
772               index 0
773               field 0)
774         (while (eq index
775                    (string-match "\\([^:]+\\)?:" string index))
776           (setq index (match-end 0))
777           (aset (car keys) field (match-string 1 string))
778           (setq field (1+ field))))
779       (nreverse keys))))
780
781 (defun epg-make-sub-key-1 (line)
782   (epg-make-sub-key
783    (if (aref line 1)
784        (cdr (assq (string-to-char (aref line 1)) epg-key-validity-alist)))
785    (delq nil
786          (mapcar (lambda (char) (cdr (assq char epg-key-capablity-alist)))
787                  (aref line 11)))
788    (member (aref line 0) '("sec" "ssb"))
789    (string-to-number (aref line 3))
790    (string-to-number (aref line 2))
791    (aref line 4)
792    (aref line 5)
793    (aref line 6)))
794
795 (defun epg-list-keys (&optional name mode)
796   (let ((lines (epg-list-keys-1 name mode))
797         keys)
798     (while lines
799       (cond
800        ((member (aref (car lines) 0) '("pub" "sec"))
801         (when (car keys)
802           (epg-key-set-sub-key-list
803            (car keys)
804            (nreverse (epg-key-sub-key-list (car keys))))
805           (epg-key-set-user-id-list
806            (car keys)
807            (nreverse (epg-key-user-id-list (car keys)))))
808         (setq keys (cons (epg-make-key
809                           (if (aref (car lines) 8)
810                               (cdr (assq (string-to-char (aref (car lines) 8))
811                                          epg-key-validity-alist))))
812                          keys))
813         (epg-key-set-sub-key-list
814          (car keys)
815          (cons (epg-make-sub-key-1 (car lines))
816                (epg-key-sub-key-list (car keys)))))
817        ((member (aref (car lines) 0) '("sub" "ssb"))
818         (epg-key-set-sub-key-list
819          (car keys)
820          (cons (epg-make-sub-key-1 (car lines))
821                (epg-key-sub-key-list (car keys)))))
822        ((equal (aref (car lines) 0) "uid")
823         (epg-key-set-user-id-list
824          (car keys)
825          (cons (epg-make-user-id
826                 (if (aref (car lines) 1)
827                     (cdr (assq (string-to-char (aref (car lines) 1))
828                                epg-key-validity-alist)))
829                 (aref (car lines) 9))
830                (epg-key-user-id-list (car keys)))))
831        ((equal (aref (car lines) 0) "fpr")
832         (epg-sub-key-set-fingerprint (car (epg-key-sub-key-list (car keys)))
833                                      (aref (car lines) 9))))
834       (setq lines (cdr lines)))
835     (nreverse keys)))
836
837 (if (fboundp 'make-temp-file)
838     (defalias 'epg-make-temp-file 'make-temp-file)
839   ;; stolen from poe.el.
840   (defun epg-make-temp-file (prefix)
841     "Create a temporary file.
842 The returned file name (created by appending some random characters at the end
843 of PREFIX, and expanding against `temporary-file-directory' if necessary),
844 is guaranteed to point to a newly created empty file.
845 You can then use `write-region' to write new data into the file."
846     (let (tempdir tempfile)
847       (unwind-protect
848           (let (file)
849             ;; First, create a temporary directory.
850             (while (condition-case ()
851                        (progn
852                          (setq tempdir (make-temp-name
853                                         (concat
854                                          (file-name-directory prefix)
855                                          "DIR")))
856                          ;; return nil or signal an error.
857                          (make-directory tempdir))
858                      ;; let's try again.
859                      (file-already-exists t)))
860             (set-file-modes tempdir 448)
861             ;; Second, create a temporary file in the tempdir.
862             ;; There *is* a race condition between `make-temp-name'
863             ;; and `write-region', but we don't care it since we are
864             ;; in a private directory now.
865             (setq tempfile (make-temp-name (concat tempdir "/EMU")))
866             (write-region "" nil tempfile nil 'silent)
867             (set-file-modes tempfile 384)
868             ;; Finally, make a hard-link from the tempfile.
869             (while (condition-case ()
870                        (progn
871                          (setq file (make-temp-name prefix))
872                          ;; return nil or signal an error.
873                          (add-name-to-file tempfile file))
874                      ;; let's try again.
875                      (file-already-exists t)))
876             file)
877         ;; Cleanup the tempfile.
878         (and tempfile
879              (file-exists-p tempfile)
880              (delete-file tempfile))
881         ;; Cleanup the tempdir.
882         (and tempdir
883              (file-directory-p tempdir)
884              (delete-directory tempdir))))))
885
886 ;;;###autoload
887 (defun epg-start-decrypt (context cipher)
888   "Initiate a decrypt operation on CIPHER.
889 CIPHER is a data object.
890
891 If you use this function, you will need to wait for the completion of
892 `epg-gpg-program' by using `epg-wait-for-completion' and call
893 `epg-reset' to clear a temporaly output file.
894 If you are unsure, use synchronous version of this function
895 `epg-decrypt-file' or `epg-decrypt-string' instead."
896   (unless (epg-data-file cipher)
897     (error "Not a file"))
898   (epg-context-set-result context nil)
899   (epg-start context (list "--decrypt" (epg-data-file cipher)))
900   (epg-wait-for-status context '("BEGIN_DECRYPTION")))
901
902 ;;;###autoload
903 (defun epg-decrypt-file (context cipher plain)
904   "Decrypt a file CIPHER and store the result to a file PLAIN.
905 If PLAIN is nil, it returns the result as a string."
906   (unwind-protect
907       (progn
908         (if plain
909             (epg-context-set-output-file context plain)
910           (epg-context-set-output-file context
911                                        (epg-make-temp-file "epg-output")))
912         (epg-start-decrypt context (epg-make-data-from-file cipher))
913         (epg-wait-for-completion context t)
914         (if (epg-context-result-for context 'error)
915             (error "Decrypt failed: %S"
916                    (epg-context-result-for context 'error)))
917         (unless plain
918           (epg-read-output context)))
919     (unless plain
920       (epg-delete-output-file context))
921     (epg-reset context)))
922
923 ;;;###autoload
924 (defun epg-decrypt-string (context cipher)
925   "Decrypt a string CIPHER and return the plain text."
926   (let ((input-file (epg-make-temp-file "epg-input"))
927         (coding-system-for-write 'binary))
928     (unwind-protect
929         (progn
930           (write-region cipher nil input-file)
931           (epg-context-set-output-file context
932                                        (epg-make-temp-file "epg-output"))
933           (epg-start-decrypt context (epg-make-data-from-file input-file))
934           (epg-wait-for-completion context)
935           (if (epg-context-result-for context 'error)
936               (error "Decrypt failed: %S"
937                      (epg-context-result-for context 'error)))
938           (epg-read-output context))
939       (epg-delete-output-file context)
940       (if (file-exists-p input-file)
941           (delete-file input-file))
942       (epg-reset context))))
943
944 ;;;###autoload
945 (defun epg-start-verify (context signature &optional signed-text)
946   "Initiate a verify operation on SIGNATURE.
947 SIGNATURE and SIGNED-TEXT are a data object if they are specified.
948
949 For a detached signature, both SIGNATURE and SIGNED-TEXT should be set.
950 For a normal or a clear text signature, SIGNED-TEXT should be nil.
951
952 If you use this function, you will need to wait for the completion of
953 `epg-gpg-program' by using `epg-wait-for-completion' and call
954 `epg-reset' to clear a temporaly output file.
955 If you are unsure, use synchronous version of this function
956 `epg-verify-file' or `epg-verify-string' instead."
957   (epg-context-set-result context nil)
958   (if signed-text
959       ;; Detached signature.
960       (if (epg-data-file signed-text)
961           (epg-start context (list "--verify" (epg-data-file signature)
962                                    (epg-data-file signed-text)))
963         (epg-start context (list "--verify" (epg-data-file signature) "-"))
964         (if (eq (process-status (epg-context-process context)) 'run)
965             (process-send-string (epg-context-process context)
966                                  (epg-data-string signed-text))))
967     ;; Normal (or cleartext) signature.
968     (if (epg-data-file signature)
969         (epg-start context (list "--verify" (epg-data-file signature)))
970       (epg-start context (list "--verify"))
971       (if (eq (process-status (epg-context-process context)) 'run)
972           (process-send-string (epg-context-process context)
973                                (epg-data-string signature))))))
974
975 ;;;###autoload
976 (defun epg-verify-file (context signature &optional signed-text plain)
977   "Verify a file SIGNATURE.
978 SIGNED-TEXT and PLAIN are also a file if they are specified.
979
980 For a detached signature, both SIGNATURE and SIGNED-TEXT should be string.
981 For a normal or a clear text signature, SIGNED-TEXT should be nil."
982   (unwind-protect
983       (progn
984         (if plain
985             (epg-context-set-output-file context plain)
986           (epg-context-set-output-file context
987                                        (epg-make-temp-file "epg-output")))
988         (if signed-text
989             (epg-start-verify context
990                               (epg-make-data-from-file signature)
991                               (epg-make-data-from-file signed-text))
992           (epg-start-verify context
993                             (epg-make-data-from-file signature)))
994         (epg-wait-for-completion context t)
995         (unless plain
996           (epg-read-output context)))
997     (unless plain
998       (epg-delete-output-file context))
999     (epg-reset context)))
1000
1001 ;;;###autoload
1002 (defun epg-verify-string (context signature &optional signed-text)
1003   "Verify a string SIGNATURE.
1004 SIGNED-TEXT is a string if it is specified.
1005
1006 For a detached signature, both SIGNATURE and SIGNED-TEXT should be string.
1007 For a normal or a clear text signature, SIGNED-TEXT should be nil."
1008   (let ((coding-system-for-write 'binary)
1009         input-file)
1010     (unwind-protect
1011         (progn
1012           (epg-context-set-output-file context
1013                                        (epg-make-temp-file "epg-output"))
1014           (if signed-text
1015               (progn
1016                 (setq input-file (epg-make-temp-file "epg-signature"))
1017                 (write-region signature nil input-file)
1018                 (epg-start-verify context
1019                                   (epg-make-data-from-file input-file)
1020                                   (epg-make-data-from-string signed-text)))
1021             (epg-start-verify context (epg-make-data-from-string signature)))
1022           (epg-wait-for-completion context)
1023           (epg-read-output context))
1024       (epg-delete-output-file context)
1025       (if (and input-file
1026                (file-exists-p input-file))
1027           (delete-file input-file))
1028       (epg-reset context))))
1029
1030 ;;;###autoload
1031 (defun epg-start-sign (context plain &optional mode)
1032   "Initiate a sign operation on PLAIN.
1033 PLAIN is a data object.
1034
1035 If optional 3rd argument MODE is 'clearsign, it makes a clear text signature.
1036 If MODE is t or 'detached, it makes a detached signature.
1037 Otherwise, it makes a normal signature.
1038
1039 If you use this function, you will need to wait for the completion of
1040 `epg-gpg-program' by using `epg-wait-for-completion' and call
1041 `epg-reset' to clear a temporaly output file.
1042 If you are unsure, use synchronous version of this function
1043 `epg-sign-file' or `epg-sign-string' instead."
1044   (epg-context-set-result context nil)
1045   (epg-start context
1046              (append (list (if (eq mode 'clearsign)
1047                                "--clearsign"
1048                              (if (or (eq mode t) (eq mode 'detached))
1049                                  "--detach-sign"
1050                                "--sign")))
1051                      (apply #'nconc
1052                             (mapcar (lambda (signer)
1053                                       (list "-u" signer))
1054                                     (epg-context-signers context)))
1055                      (if (epg-data-file plain)
1056                          (list (epg-data-file plain)))))
1057   (epg-wait-for-status context '("BEGIN_SIGNING"))
1058   (if (and (epg-data-string plain)
1059            (eq (process-status (epg-context-process context)) 'run))
1060       (process-send-string (epg-context-process context)
1061                            (epg-data-string plain))))
1062
1063 ;;;###autoload
1064 (defun epg-sign-file (context plain signature &optional mode)
1065   "Sign a file PLAIN and store the result to a file SIGNATURE.
1066 If SIGNATURE is nil, it returns the result as a string.
1067 If optional 3rd argument MODE is 'clearsign, it makes a clear text signature.
1068 If MODE is t or 'detached, it makes a detached signature.
1069 Otherwise, it makes a normal signature."
1070   (unwind-protect
1071       (progn
1072         (if signature
1073             (epg-context-set-output-file context signature)
1074           (epg-context-set-output-file context
1075                                        (epg-make-temp-file "epg-output")))
1076         (epg-start-sign context (epg-make-data-from-file plain) mode)
1077         (epg-wait-for-completion context t)
1078         (if (epg-context-result-for context 'error)
1079             (error "Sign failed: %S"
1080                    (epg-context-result-for context 'error)))
1081         (unless signature
1082           (epg-read-output context)))
1083     (unless signature
1084       (epg-delete-output-file context))
1085     (epg-reset context)))
1086
1087 ;;;###autoload
1088 (defun epg-sign-string (context plain &optional mode)
1089   "Sign a string PLAIN and return the output as string.
1090 If optional 3rd argument MODE is 'clearsign, it makes a clear text signature.
1091 If MODE is t or 'detached, it makes a detached signature.
1092 Otherwise, it makes a normal signature."
1093   (unwind-protect
1094       (progn
1095         (epg-context-set-output-file context
1096                                      (epg-make-temp-file "epg-output"))
1097         (epg-start-sign context (epg-make-data-from-string plain) mode)
1098         (epg-wait-for-completion context)
1099         (if (epg-context-result-for context 'error)
1100             (error "Sign failed: %S"
1101                    (epg-context-result-for context 'error)))
1102         (epg-read-output context))
1103     (epg-delete-output-file context)
1104     (epg-reset context)))
1105
1106 ;;;###autoload
1107 (defun epg-start-encrypt (context plain recipients
1108                                   &optional sign always-trust)
1109   "Initiate an encrypt operation on PLAIN.
1110 PLAIN is a data object.
1111 If RECIPIENTS is nil, it performs symmetric encryption.
1112
1113 If you use this function, you will need to wait for the completion of
1114 `epg-gpg-program' by using `epg-wait-for-completion' and call
1115 `epg-reset' to clear a temporaly output file.
1116 If you are unsure, use synchronous version of this function
1117 `epg-encrypt-file' or `epg-encrypt-string' instead."
1118   (epg-context-set-result context nil)
1119   (epg-start context
1120              (append (if always-trust '("--always-trust"))
1121                      (if recipients '("--encrypt") '("--symmetric"))
1122                      (if sign
1123                          (cons "--sign"
1124                                (apply #'nconc
1125                                       (mapcar (lambda (signer)
1126                                                 (list "-u" signer))
1127                                               (epg-context-signers context)))))
1128                      (apply #'nconc
1129                             (mapcar (lambda (recipient)
1130                                       (list "-r" recipient))
1131                                     recipients))
1132                      (if (epg-data-file plain)
1133                          (list (epg-data-file plain)))))
1134   (if sign
1135       (epg-wait-for-status context '("BEGIN_SIGNING")))
1136   (epg-wait-for-status context '("BEGIN_ENCRYPTION"))
1137   (if (and (epg-data-string plain)
1138            (eq (process-status (epg-context-process context)) 'run))
1139       (process-send-string (epg-context-process context)
1140                            (epg-data-string plain))))
1141
1142 ;;;###autoload
1143 (defun epg-encrypt-file (context plain recipients
1144                                  cipher &optional sign always-trust)
1145   "Encrypt a file PLAIN and store the result to a file CIPHER.
1146 If CIPHER is nil, it returns the result as a string.
1147 If RECIPIENTS is nil, it performs symmetric encryption."
1148   (unwind-protect
1149       (progn
1150         (if cipher
1151             (epg-context-set-output-file context cipher)
1152           (epg-context-set-output-file context
1153                                        (epg-make-temp-file "epg-output")))
1154         (epg-start-encrypt context (epg-make-data-from-file plain)
1155                            recipients sign always-trust)
1156         (epg-wait-for-completion context t)
1157         (if (epg-context-result-for context 'error)
1158             (error "Encrypt failed: %S"
1159                    (epg-context-result-for context 'error)))
1160         (unless cipher
1161           (epg-read-output context)))
1162     (unless cipher
1163       (epg-delete-output-file context))
1164     (epg-reset context)))
1165
1166 ;;;###autoload
1167 (defun epg-encrypt-string (context plain recipients
1168                                    &optional sign always-trust)
1169   "Encrypt a string PLAIN.
1170 If RECIPIENTS is nil, it performs symmetric encryption."
1171   (unwind-protect
1172       (progn
1173         (epg-context-set-output-file context
1174                                      (epg-make-temp-file "epg-output"))
1175         (epg-start-encrypt context (epg-make-data-from-string plain)
1176                            recipients sign always-trust)
1177         (epg-wait-for-completion context)
1178         (if (epg-context-result-for context 'error)
1179             (error "Encrypt failed: %S"
1180                    (epg-context-result-for context 'error)))
1181         (epg-read-output context))
1182     (epg-delete-output-file context)
1183     (epg-reset context)))
1184
1185 ;;;###autoload
1186 (defun epg-start-export-keys (context keys)
1187   "Initiate an export keys operation.
1188
1189 If you use this function, you will need to wait for the completion of
1190 `epg-gpg-program' by using `epg-wait-for-completion' and call
1191 `epg-reset' to clear a temporaly output file.
1192 If you are unsure, use synchronous version of this function
1193 `epg-export-keys-to-file' or `epg-export-keys-to-string' instead."
1194   (epg-context-set-result context nil)
1195   (epg-start context (cons "--export"
1196                            (mapcar
1197                             (lambda (key)
1198                               (epg-sub-key-id
1199                                (car (epg-key-sub-key-list key))))
1200                             keys))))
1201
1202 ;;;###autoload
1203 (defun epg-export-keys-to-file (context keys file)
1204   "Extract public KEYS."
1205   (unwind-protect
1206       (progn
1207         (if keys
1208             (epg-context-set-output-file context file)
1209           (epg-context-set-output-file context
1210                                        (epg-make-temp-file "epg-output")))
1211         (epg-start-export-keys context keys)
1212         (epg-wait-for-completion context)
1213         (if (epg-context-result-for context 'error)
1214             (error "Export keys failed"))
1215         (unless file
1216           (epg-read-output context)))
1217     (unless file
1218       (epg-delete-output-file context))
1219     (epg-reset context)))
1220
1221 ;;;###autoload
1222 (defun epg-export-keys-to-string (context keys)
1223   "Extract public KEYS and return them as a string."
1224   (epg-export-keys-to-file context keys nil))
1225
1226 ;;;###autoload
1227 (defun epg-start-import-keys (context keys)
1228   "Initiate an import keys operation.
1229 KEYS is a data object.
1230
1231 If you use this function, you will need to wait for the completion of
1232 `epg-gpg-program' by using `epg-wait-for-completion' and call
1233 `epg-reset' to clear a temporaly output file.
1234 If you are unsure, use synchronous version of this function
1235 `epg-import-keys-from-file' or `epg-import-keys-from-string' instead."
1236   (epg-context-set-result context nil)
1237   (epg-context-set-output-file context (epg-make-temp-file "epg-output"))
1238   (epg-start context (list "--import" (epg-data-file keys)))
1239   (if (and (epg-data-string keys)
1240            (eq (process-status (epg-context-process context)) 'run))
1241       (process-send-string (epg-context-process context)
1242                            (epg-data-string keys))))
1243   
1244 (defun epg-import-keys-1 (context keys)
1245   (unwind-protect
1246       (progn
1247         (epg-start-import-keys context keys)
1248         (epg-wait-for-completion context (epg-data-file keys))
1249         (if (epg-context-result-for context 'error)
1250             (error "Import keys failed"))
1251         (epg-read-output context))
1252     (epg-reset context)))
1253
1254 ;;;###autoload
1255 (defun epg-import-keys-from-file (context keys)
1256   "Add keys from a file KEYS."
1257   (epg-import-keys-1 context (epg-make-data-from-file keys)))
1258
1259 ;;;###autoload
1260 (defun epg-import-keys-from-string (context keys)
1261   "Add keys from a string KEYS."
1262   (epg-import-keys-1 context (epg-make-data-from-string keys)))
1263
1264 ;;;###autoload
1265 (defun epg-start-delete-keys (context keys &optional allow-secret)
1266   "Initiate an delete keys operation.
1267
1268 If you use this function, you will need to wait for the completion of
1269 `epg-gpg-program' by using `epg-wait-for-completion' and call
1270 `epg-reset' to clear a temporaly output file.
1271 If you are unsure, use synchronous version of this function
1272 `epg-delete-keys' instead."
1273   (epg-context-set-result context nil)
1274   (epg-start context (cons (if allow-secret
1275                                "--delete-secret-key"
1276                              "--delete-key")
1277                            (mapcar
1278                             (lambda (key)
1279                               (epg-sub-key-id
1280                                (car (epg-key-sub-key-list key))))
1281                             keys))))
1282
1283 ;;;###autoload
1284 (defun epg-delete-keys (context keys &optional allow-secret)
1285   "Delete KEYS from the key ring."
1286   (unwind-protect
1287       (progn
1288         (epg-start-delete-keys context keys)
1289         (epg-wait-for-completion context t)
1290         (if (epg-context-result-for context 'error)
1291             (error "Delete key failed")))
1292     (epg-reset context)))
1293
1294 (provide 'epg)
1295
1296 ;;; epg.el ends here