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