* epg.el (epg-sign-file): Signal an error only when a signature is not
[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     (set-process-sentinel process #'epg-process-sentinel)
489     (epg-context-set-process context process)))
490
491 (defun epg-process-filter (process input)
492   (if epg-debug
493       (save-excursion
494         (unless epg-debug-buffer
495           (setq epg-debug-buffer (generate-new-buffer " *epg-debug*")))
496         (set-buffer epg-debug-buffer)
497         (goto-char (point-max))
498         (insert input)))
499   (if (buffer-live-p (process-buffer process))
500       (save-excursion
501         (set-buffer (process-buffer process))
502         (goto-char (point-max))
503         (insert input)
504         (goto-char epg-read-point)
505         (beginning-of-line)
506         (while (looking-at ".*\n")      ;the input line finished
507           (save-excursion
508             (if (looking-at "\\[GNUPG:] \\([A-Z_]+\\) ?\\(.*\\)")
509                 (let* ((status (match-string 1))
510                        (string (match-string 2))
511                        (symbol (intern-soft (concat "epg-status-" status))))
512                   (if (member status epg-pending-status-list)
513                       (setq epg-pending-status-list nil))
514                   (if (and symbol
515                            (fboundp symbol))
516                       (funcall symbol process string)))))
517           (forward-line))
518         (setq epg-read-point (point)))))
519
520 (defun epg-process-sentinel (process status)
521   (if (and (buffer-live-p (process-buffer process))
522            (not (equal status "finished\n")))
523       (save-excursion
524         (set-buffer (process-buffer process))
525         ;; gpg process exited abnormally, but we have not received an
526         ;; error response from it.  Set it here.
527         (unless (epg-context-result-for epg-context 'error)
528           (if (string-match "\\`exited abnormally with code \\(.*\\)\n" status)
529               (epg-context-set-result-for
530                epg-context 'error
531                (list (cons 'exit (string-to-number (match-string 1 status)))))
532             (epg-context-set-result-for epg-context 'error
533                                     (list (cons 'signal status))))))))
534
535 (defun epg-read-output (context)
536   (with-temp-buffer
537     (if (fboundp 'set-buffer-multibyte)
538         (set-buffer-multibyte nil))
539     (if (file-exists-p (epg-context-output-file context))
540         (let ((coding-system-for-read (if (epg-context-textmode context)
541                                           'raw-text
542                                         'binary)))
543           (insert-file-contents (epg-context-output-file context))
544           (buffer-string)))))
545
546 (defun epg-wait-for-status (context status-list)
547   (with-current-buffer (process-buffer (epg-context-process context))
548     (setq epg-pending-status-list status-list)
549     (while (and (eq (process-status (epg-context-process context)) 'run)
550                 epg-pending-status-list)
551       (accept-process-output (epg-context-process context) 1))))
552
553 (defun epg-wait-for-completion (context)
554   (while (eq (process-status (epg-context-process context)) 'run)
555     ;; We can't use accept-process-output instead of sit-for here
556     ;; because it may cause an interrupt during the sentinel execution.
557     (sit-for 0.1)))
558
559 (defun epg-flush (context)
560   (if (eq (process-status (epg-context-process context)) 'run)
561       (process-send-eof (epg-context-process context))))
562
563 (defun epg-reset (context)
564   (if (and (epg-context-process context)
565            (buffer-live-p (process-buffer (epg-context-process context))))
566       (kill-buffer (process-buffer (epg-context-process context))))
567   (epg-context-set-process context nil))
568
569 (defun epg-delete-output-file (context)
570   (if (and (epg-context-output-file context)
571            (file-exists-p (epg-context-output-file context)))
572       (delete-file (epg-context-output-file context))))
573
574 (defun epg-status-USERID_HINT (process string)
575   (if (string-match "\\`\\([^ ]+\\) \\(.*\\)" string)
576       (let* ((key-id (match-string 1 string))
577              (user-id (match-string 2 string))
578              (entry (assoc key-id epg-user-id-alist)))
579         (if entry
580             (setcdr entry user-id)
581           (setq epg-user-id-alist (cons (cons key-id user-id)
582                                         epg-user-id-alist))))))
583
584 (defun epg-status-NEED_PASSPHRASE (process string)
585   (if (string-match "\\`\\([^ ]+\\)" string)
586       (setq epg-key-id (match-string 1 string))))
587
588 (defun epg-status-NEED_PASSPHRASE_SYM (process string)
589   (setq epg-key-id 'SYM))
590
591 (defun epg-status-NEED_PASSPHRASE_PIN (process string)
592   (setq epg-key-id 'PIN))
593
594 (defun epg-status-GET_HIDDEN (process string)
595   (if (and epg-key-id
596            (string-match "\\`passphrase\\." string))
597       (let (inhibit-quit
598             passphrase
599             passphrase-with-new-line)
600         (unwind-protect
601             (condition-case nil
602                 (progn
603                   (setq passphrase
604                         (funcall
605                          (if (consp (epg-context-passphrase-callback
606                                      epg-context))
607                              (car (epg-context-passphrase-callback
608                                    epg-context))
609                            (epg-context-passphrase-callback epg-context))
610                          epg-key-id
611                          (if (consp (epg-context-passphrase-callback
612                                      epg-context))
613                              (cdr (epg-context-passphrase-callback
614                                    epg-context)))))
615                   (when passphrase
616                     (setq passphrase-with-new-line (concat passphrase "\n"))
617                     (fillarray passphrase 0)
618                     (setq passphrase nil)
619                     (process-send-string process passphrase-with-new-line)))
620               (quit
621                (epg-context-set-result-for
622                 epg-context 'error
623                 (cons 'quit
624                       (epg-context-result-for epg-context 'error)))
625                (delete-process process)))
626           (if passphrase
627               (fillarray passphrase 0))
628           (if passphrase-with-new-line
629               (fillarray passphrase-with-new-line 0))))))
630
631 (defun epg-status-GET_BOOL (process string)
632   (let ((entry (assoc string epg-prompt-alist))
633         inhibit-quit)
634     (condition-case nil
635       (if (y-or-n-p (if entry (cdr entry) (concat string "? ")))
636           (process-send-string process "y\n")
637         (process-send-string process "n\n"))
638       (quit
639        (epg-context-set-result-for
640         epg-context 'error
641         (cons 'quit
642               (epg-context-result-for epg-context 'error)))
643        (delete-process process)))))
644
645 (defun epg-status-GET_LINE (process string)
646   (let ((entry (assoc string epg-prompt-alist))
647         inhibit-quit)
648     (condition-case nil
649         (process-send-string
650          process
651          (concat (read-string (if entry (cdr entry) (concat string ": ")))
652                  "\n"))
653       (quit
654        (epg-context-set-result-for
655         epg-context 'error
656         (cons 'quit
657               (epg-context-result-for epg-context 'error)))
658        (delete-process process)))))
659
660 (defun epg-status-GOODSIG (process string)
661   (if (string-match "\\`\\([^ ]+\\) \\(.*\\)" string)
662       (epg-context-set-result-for
663        epg-context
664        'verify
665        (cons (epg-make-signature
666               'good
667               (match-string 1 string)
668               (if (eq (epg-context-protocol epg-context) 'CMS)
669                   (condition-case nil
670                       (epg-dn-from-string (match-string 2 string))
671                     (error (match-string 2 string)))
672                 (match-string 2 string)))
673              (epg-context-result-for epg-context 'verify)))))
674
675 (defun epg-status-EXPSIG (process string)
676   (if (string-match "\\`\\([^ ]+\\) \\(.*\\)" string)
677       (epg-context-set-result-for
678        epg-context
679        'verify
680        (cons (epg-make-signature
681               'expired
682               (match-string 1 string)
683               (if (eq (epg-context-protocol epg-context) 'CMS)
684                   (condition-case nil
685                       (epg-dn-from-string (match-string 2 string))
686                     (error (match-string 2 string)))
687                 (match-string 2 string)))
688              (epg-context-result-for epg-context 'verify)))))
689
690 (defun epg-status-EXPKEYSIG (process string)
691   (if (string-match "\\`\\([^ ]+\\) \\(.*\\)" string)
692       (epg-context-set-result-for
693        epg-context
694        'verify
695        (cons (epg-make-signature
696               'expired-key
697               (match-string 1 string)
698               (if (eq (epg-context-protocol epg-context) 'CMS)
699                   (condition-case nil
700                       (epg-dn-from-string (match-string 2 string))
701                     (error (match-string 2 string)))
702                 (match-string 2 string)))
703              (epg-context-result-for epg-context 'verify)))))
704
705 (defun epg-status-REVKEYSIG (process string)
706   (if (string-match "\\`\\([^ ]+\\) \\(.*\\)" string)
707       (epg-context-set-result-for
708        epg-context
709        'verify
710        (cons (epg-make-signature
711               'revoked-key
712               (match-string 1 string)
713               (if (eq (epg-context-protocol epg-context) 'CMS)
714                   (condition-case nil
715                       (epg-dn-from-string (match-string 2 string))
716                     (error (match-string 2 string)))
717                 (match-string 2 string)))
718              (epg-context-result-for epg-context 'verify)))))
719
720 (defun epg-status-BADSIG (process string)
721   (if (string-match "\\`\\([^ ]+\\) \\(.*\\)" string)
722       (epg-context-set-result-for
723        epg-context
724        'verify
725        (cons (epg-make-signature
726               'bad
727               (match-string 1 string)
728               (if (eq (epg-context-protocol epg-context) 'CMS)
729                   (condition-case nil
730                       (epg-dn-from-string (match-string 2 string))
731                     (error (match-string 2 string)))
732                 (match-string 2 string)))
733              (epg-context-result-for epg-context 'verify)))))
734
735 (defun epg-status-VALIDSIG (process string)
736   (let ((signature (car (epg-context-result-for epg-context 'verify))))
737     (if (and signature
738              (eq (epg-signature-status signature) 'good)
739              (string-match "\\`\\([^ ]+\\) " string))
740         (epg-signature-set-fingerprint signature (match-string 1 string)))))
741
742 (defun epg-status-TRUST_UNDEFINED (process string)
743   (let ((signature (car (epg-context-result-for epg-context 'verify))))
744     (if (and signature
745              (eq (epg-signature-status signature) 'good))
746         (epg-signature-set-validity signature 'undefined))))
747
748 (defun epg-status-TRUST_NEVER (process string)
749   (let ((signature (car (epg-context-result-for epg-context 'verify))))
750     (if (and signature
751              (eq (epg-signature-status signature) 'good))
752         (epg-signature-set-validity signature 'never))))
753
754 (defun epg-status-TRUST_MARGINAL (process string)
755   (let ((signature (car (epg-context-result-for epg-context 'verify))))
756     (if (and signature
757              (eq (epg-signature-status signature) 'marginal))
758         (epg-signature-set-validity signature 'marginal))))
759
760 (defun epg-status-TRUST_FULLY (process string)
761   (let ((signature (car (epg-context-result-for epg-context 'verify))))
762     (if (and signature
763              (eq (epg-signature-status signature) 'good))
764         (epg-signature-set-validity signature 'full))))
765
766 (defun epg-status-TRUST_ULTIMATE (process string)
767   (let ((signature (car (epg-context-result-for epg-context 'verify))))
768     (if (and signature
769              (eq (epg-signature-status signature) 'good))
770         (epg-signature-set-validity signature 'ultimate))))
771
772 (defun epg-status-PROGRESS (process string)
773   (if (string-match "\\`\\([^ ]+\\) \\([^ ]\\) \\([0-9]+\\) \\([0-9]+\\)"
774                     string)
775       (funcall (if (consp (epg-context-progress-callback epg-context))
776                    (car (epg-context-progress-callback epg-context))
777                  (epg-context-progress-callback epg-context))
778                (match-string 1 string)
779                (match-string 2 string)
780                (string-to-number (match-string 3 string))
781                (string-to-number (match-string 4 string))
782                (if (consp (epg-context-progress-callback epg-context))
783                    (cdr (epg-context-progress-callback epg-context))))))
784
785 (defun epg-status-DECRYPTION_FAILED (process string)
786   (epg-context-set-result-for
787    epg-context 'error
788    (cons 'decryption-failed
789          (epg-context-result-for epg-context 'error))))
790
791 (defun epg-status-NODATA (process string)
792   (epg-context-set-result-for
793    epg-context 'error
794    (cons (cons 'no-data (string-to-number string))
795          (epg-context-result-for epg-context 'error))))
796
797 (defun epg-status-UNEXPECTED (process string)
798   (epg-context-set-result-for
799    epg-context 'error
800    (cons (cons 'unexpected (string-to-number string))
801          (epg-context-result-for epg-context 'error))))
802
803 (defun epg-status-KEYEXPIRED (process string)
804   (epg-context-set-result-for
805    epg-context 'error
806    (cons (cons 'key-expired string)
807          (epg-context-result-for epg-context 'error))))
808
809 (defun epg-status-KEYREVOKED (process string)
810   (epg-context-set-result-for
811    epg-context 'error
812    (cons 'key-revoked
813          (epg-context-result-for epg-context 'error))))
814
815 (defun epg-status-BADARMOR (process string)
816   (epg-context-set-result-for
817    epg-context 'error
818    (cons 'bad-armor
819          (epg-context-result-for epg-context 'error))))
820
821 (defun epg-status-INV_RECP (process string)
822   (if (string-match "\\`\\([0-9]+\\) \\(.*\\)" string)
823       (epg-context-set-result-for
824        epg-context 'error
825        (cons (list 'invalid-recipient
826                    (string-to-number (match-string 1 string))
827                    (match-string 2 string))
828              (epg-context-result-for epg-context 'error)))))
829
830 (defun epg-status-NO_RECP (process string)
831   (epg-context-set-result-for
832    epg-context 'error
833    (cons 'no-recipients
834          (epg-context-result-for epg-context 'error))))
835
836 (defun epg-status-DELETE_PROBLEM (process string)
837   (if (string-match "\\`\\([0-9]+\\)" string)
838       (epg-context-set-result-for
839        epg-context 'error
840        (cons (cons 'delete-problem (string-to-number (match-string 1 string)))
841              (epg-context-result-for epg-context 'error)))))
842
843 (defun epg-status-SIG_CREATED (process string)
844   (if (string-match "\\`\\([DCS]\\) \\([0-9]+\\) \\([0-9]+\\) \
845 \\([0-9A-Fa-F][0-9A-Fa-F]\\) \\(.*\\) " string)
846       (epg-context-set-result-for
847        epg-context 'sign
848        (cons (list (cons 'type (string-to-char (match-string 1 string)))
849                    (cons 'pubkey-algorithm
850                          (string-to-number (match-string 2 string)))
851                    (cons 'digest-algorithm
852                          (string-to-number (match-string 3 string)))
853                    (cons 'class (string-to-number (match-string 4 string) 16))
854                    (cons 'creation-time (match-string 5 string))
855                    (cons 'fingerprint (substring string (match-end 0))))
856              (epg-context-result-for epg-context 'sign)))))
857
858 (defun epg-passphrase-callback-function (key-id handback)
859   (read-passwd
860    (if (eq key-id 'SYM)
861        "Passphrase for symmetric encryption: "
862      (if (eq key-id 'PIN)
863          "Passphrase for PIN: "
864        (let ((entry (assoc key-id epg-user-id-alist)))
865          (if entry
866              (format "Passphrase for %s %s: " key-id (cdr entry))
867            (format "Passphrase for %s: " key-id)))))))
868
869 (defun epg-progress-callback-function (what char current total handback)
870   (message "%s: %d%%/%d%%" what current total))
871
872 (defun epg-configuration ()
873   "Return a list of internal configuration parameters of `epg-gpg-program'."
874   (let (config type)
875     (with-temp-buffer
876       (apply #'call-process epg-gpg-program nil (list t nil) nil
877              '("--with-colons" "--list-config"))
878       (goto-char (point-min))
879       (while (re-search-forward "^cfg:\\([^:]+\\):\\(.*\\)" nil t)
880         (setq type (intern (match-string 1))
881               config (cons (cons type
882                                  (if (memq type
883                                            '(pubkey cipher digest compress))
884                                      (mapcar #'string-to-number
885                                              (delete "" (split-string
886                                                          (match-string 2)
887                                                          ";")))
888                                    (match-string 2)))
889                            config))))
890     config))
891
892 (defun epg-list-keys-1 (context name mode)
893   (let ((args (append (list "--with-colons" "--no-greeting" "--batch"
894                             "--with-fingerprint"
895                             "--with-fingerprint"
896                             (if mode "--list-secret-keys" "--list-keys"))
897                       (unless (eq (epg-context-protocol context) 'CMS)
898                         '("--fixed-list-mode"))
899                       (if name (list name))))
900         keys string field index)
901     (with-temp-buffer
902       (apply #'call-process
903              (if (eq (epg-context-protocol context) 'CMS)
904                  epg-gpgsm-program
905                epg-gpg-program)
906              nil (list t nil) nil args)
907       (goto-char (point-min))
908       (while (re-search-forward "^[a-z][a-z][a-z]:.*" nil t)
909         (setq keys (cons (make-vector 15 nil) keys)
910               string (match-string 0)
911               index 0
912               field 0)
913         (while (eq index
914                    (string-match "\\([^:]+\\)?:" string index))
915           (setq index (match-end 0))
916           (aset (car keys) field (match-string 1 string))
917           (setq field (1+ field))))
918       (nreverse keys))))
919
920 (defun epg-make-sub-key-1 (line)
921   (epg-make-sub-key
922    (if (aref line 1)
923        (cdr (assq (string-to-char (aref line 1)) epg-key-validity-alist)))
924    (delq nil
925          (mapcar (lambda (char) (cdr (assq char epg-key-capablity-alist)))
926                  (aref line 11)))
927    (member (aref line 0) '("sec" "ssb"))
928    (string-to-number (aref line 3))
929    (string-to-number (aref line 2))
930    (aref line 4)
931    (aref line 5)
932    (aref line 6)))
933
934 (defun epg-list-keys (context &optional name mode)
935   (let ((lines (epg-list-keys-1 context name mode))
936         keys cert)
937     (while lines
938       (cond
939        ((member (aref (car lines) 0) '("pub" "sec" "crt" "crs"))
940         (when (car keys)
941           (epg-key-set-sub-key-list
942            (car keys)
943            (nreverse (epg-key-sub-key-list (car keys))))
944           (epg-key-set-user-id-list
945            (car keys)
946            (nreverse (epg-key-user-id-list (car keys)))))
947         (setq cert (member (aref (car lines) 0) '("crt" "crs"))
948               keys (cons (epg-make-key
949                           (if (aref (car lines) 8)
950                               (cdr (assq (string-to-char (aref (car lines) 8))
951                                          epg-key-validity-alist))))
952                          keys))
953         (epg-key-set-sub-key-list
954          (car keys)
955          (cons (epg-make-sub-key-1 (car lines))
956                (epg-key-sub-key-list (car keys)))))
957        ((member (aref (car lines) 0) '("sub" "ssb"))
958         (epg-key-set-sub-key-list
959          (car keys)
960          (cons (epg-make-sub-key-1 (car lines))
961                (epg-key-sub-key-list (car keys)))))
962        ((equal (aref (car lines) 0) "uid")
963         (epg-key-set-user-id-list
964          (car keys)
965          (cons (epg-make-user-id
966                 (if (aref (car lines) 1)
967                     (cdr (assq (string-to-char (aref (car lines) 1))
968                                epg-key-validity-alist)))
969                 (if cert
970                     (condition-case nil
971                         (epg-dn-from-string (aref (car lines) 9))
972                       (error (aref (car lines) 9)))
973                   (aref (car lines) 9)))
974                (epg-key-user-id-list (car keys)))))
975        ((equal (aref (car lines) 0) "fpr")
976         (epg-sub-key-set-fingerprint (car (epg-key-sub-key-list (car keys)))
977                                      (aref (car lines) 9))))
978       (setq lines (cdr lines)))
979     (when (car keys)
980       (epg-key-set-sub-key-list
981        (car keys)
982        (nreverse (epg-key-sub-key-list (car keys))))
983       (epg-key-set-user-id-list
984        (car keys)
985        (nreverse (epg-key-user-id-list (car keys)))))
986     (nreverse keys)))
987
988 (if (fboundp 'make-temp-file)
989     (defalias 'epg-make-temp-file 'make-temp-file)
990   ;; stolen from poe.el.
991   (defun epg-make-temp-file (prefix)
992     "Create a temporary file.
993 The returned file name (created by appending some random characters at the end
994 of PREFIX, and expanding against `temporary-file-directory' if necessary),
995 is guaranteed to point to a newly created empty file.
996 You can then use `write-region' to write new data into the file."
997     (let (tempdir tempfile)
998       (unwind-protect
999           (let (file)
1000             ;; First, create a temporary directory.
1001             (while (condition-case ()
1002                        (progn
1003                          (setq tempdir (make-temp-name
1004                                         (concat
1005                                          (file-name-directory prefix)
1006                                          "DIR")))
1007                          ;; return nil or signal an error.
1008                          (make-directory tempdir))
1009                      ;; let's try again.
1010                      (file-already-exists t)))
1011             (set-file-modes tempdir 448)
1012             ;; Second, create a temporary file in the tempdir.
1013             ;; There *is* a race condition between `make-temp-name'
1014             ;; and `write-region', but we don't care it since we are
1015             ;; in a private directory now.
1016             (setq tempfile (make-temp-name (concat tempdir "/EMU")))
1017             (write-region "" nil tempfile nil 'silent)
1018             (set-file-modes tempfile 384)
1019             ;; Finally, make a hard-link from the tempfile.
1020             (while (condition-case ()
1021                        (progn
1022                          (setq file (make-temp-name prefix))
1023                          ;; return nil or signal an error.
1024                          (add-name-to-file tempfile file))
1025                      ;; let's try again.
1026                      (file-already-exists t)))
1027             file)
1028         ;; Cleanup the tempfile.
1029         (and tempfile
1030              (file-exists-p tempfile)
1031              (delete-file tempfile))
1032         ;; Cleanup the tempdir.
1033         (and tempdir
1034              (file-directory-p tempdir)
1035              (delete-directory tempdir))))))
1036
1037 ;;;###autoload
1038 (defun epg-start-decrypt (context cipher)
1039   "Initiate a decrypt operation on CIPHER.
1040 CIPHER is a data object.
1041
1042 If you use this function, you will need to wait for the completion of
1043 `epg-gpg-program' by using `epg-wait-for-completion' and call
1044 `epg-reset' to clear a temporaly output file.
1045 If you are unsure, use synchronous version of this function
1046 `epg-decrypt-file' or `epg-decrypt-string' instead."
1047   (unless (epg-data-file cipher)
1048     (error "Not a file"))
1049   (epg-context-set-result context nil)
1050   (epg-start context (list "--decrypt" (epg-data-file cipher)))
1051   ;; `gpgsm' does not read passphrase from stdin, so waiting is not needed.
1052   (unless (eq (epg-context-protocol context) 'CMS)
1053     (epg-wait-for-status context '("BEGIN_DECRYPTION"))))
1054
1055 ;;;###autoload
1056 (defun epg-decrypt-file (context cipher plain)
1057   "Decrypt a file CIPHER and store the result to a file PLAIN.
1058 If PLAIN is nil, it returns the result as a string."
1059   (unwind-protect
1060       (progn
1061         (if plain
1062             (epg-context-set-output-file context plain)
1063           (epg-context-set-output-file context
1064                                        (epg-make-temp-file "epg-output")))
1065         (epg-start-decrypt context (epg-make-data-from-file cipher))
1066         (epg-wait-for-completion context)
1067         (if (epg-context-result-for context 'error)
1068             (error "Decrypt failed: %S"
1069                    (epg-context-result-for context 'error)))
1070         (unless plain
1071           (epg-read-output context)))
1072     (unless plain
1073       (epg-delete-output-file context))
1074     (epg-reset context)))
1075
1076 ;;;###autoload
1077 (defun epg-decrypt-string (context cipher)
1078   "Decrypt a string CIPHER and return the plain text."
1079   (let ((input-file (epg-make-temp-file "epg-input"))
1080         (coding-system-for-write 'binary))
1081     (unwind-protect
1082         (progn
1083           (write-region cipher nil input-file nil 'quiet)
1084           (epg-context-set-output-file context
1085                                        (epg-make-temp-file "epg-output"))
1086           (epg-start-decrypt context (epg-make-data-from-file input-file))
1087           (epg-flush context)
1088           (epg-wait-for-completion context)
1089           (if (epg-context-result-for context 'error)
1090               (error "Decrypt failed: %S"
1091                      (epg-context-result-for context 'error)))
1092           (epg-read-output context))
1093       (epg-delete-output-file context)
1094       (if (file-exists-p input-file)
1095           (delete-file input-file))
1096       (epg-reset context))))
1097
1098 ;;;###autoload
1099 (defun epg-start-verify (context signature &optional signed-text)
1100   "Initiate a verify operation on SIGNATURE.
1101 SIGNATURE and SIGNED-TEXT are a data object if they are specified.
1102
1103 For a detached signature, both SIGNATURE and SIGNED-TEXT should be set.
1104 For a normal or a clear text signature, SIGNED-TEXT should be nil.
1105
1106 If you use this function, you will need to wait for the completion of
1107 `epg-gpg-program' by using `epg-wait-for-completion' and call
1108 `epg-reset' to clear a temporaly output file.
1109 If you are unsure, use synchronous version of this function
1110 `epg-verify-file' or `epg-verify-string' instead."
1111   (epg-context-set-result context nil)
1112   (if signed-text
1113       ;; Detached signature.
1114       (if (epg-data-file signed-text)
1115           (epg-start context (list "--verify" (epg-data-file signature)
1116                                    (epg-data-file signed-text)))
1117         (epg-start context (list "--verify" (epg-data-file signature) "-"))
1118         (if (eq (process-status (epg-context-process context)) 'run)
1119             (process-send-string (epg-context-process context)
1120                                  (epg-data-string signed-text))))
1121     ;; Normal (or cleartext) signature.
1122     (if (epg-data-file signature)
1123         (epg-start context (list "--verify" (epg-data-file signature)))
1124       (epg-start context (list "--verify"))
1125       (if (eq (process-status (epg-context-process context)) 'run)
1126           (process-send-string (epg-context-process context)
1127                                (epg-data-string signature))))))
1128
1129 ;;;###autoload
1130 (defun epg-verify-file (context signature &optional signed-text plain)
1131   "Verify a file SIGNATURE.
1132 SIGNED-TEXT and PLAIN are also a file if they are specified.
1133
1134 For a detached signature, both SIGNATURE and SIGNED-TEXT should be string.
1135 For a normal or a clear text signature, SIGNED-TEXT should be nil."
1136   (unwind-protect
1137       (progn
1138         (if plain
1139             (epg-context-set-output-file context plain)
1140           (epg-context-set-output-file context
1141                                        (epg-make-temp-file "epg-output")))
1142         (if signed-text
1143             (epg-start-verify context
1144                               (epg-make-data-from-file signature)
1145                               (epg-make-data-from-file signed-text))
1146           (epg-start-verify context
1147                             (epg-make-data-from-file signature)))
1148         (epg-wait-for-completion context)
1149         (unless plain
1150           (epg-read-output context)))
1151     (unless plain
1152       (epg-delete-output-file context))
1153     (epg-reset context)))
1154
1155 ;;;###autoload
1156 (defun epg-verify-string (context signature &optional signed-text)
1157   "Verify a string SIGNATURE.
1158 SIGNED-TEXT is a string if it is specified.
1159
1160 For a detached signature, both SIGNATURE and SIGNED-TEXT should be string.
1161 For a normal or a clear text signature, SIGNED-TEXT should be nil."
1162   (let ((coding-system-for-write 'binary)
1163         input-file)
1164     (unwind-protect
1165         (progn
1166           (epg-context-set-output-file context
1167                                        (epg-make-temp-file "epg-output"))
1168           (if signed-text
1169               (progn
1170                 (setq input-file (epg-make-temp-file "epg-signature"))
1171                 (write-region signature nil input-file nil 'quiet)
1172                 (epg-start-verify context
1173                                   (epg-make-data-from-file input-file)
1174                                   (epg-make-data-from-string signed-text)))
1175             (epg-start-verify context (epg-make-data-from-string signature)))
1176           (epg-flush context)
1177           (epg-wait-for-completion context)
1178           (epg-read-output context))
1179       (epg-delete-output-file context)
1180       (if (and input-file
1181                (file-exists-p input-file))
1182           (delete-file input-file))
1183       (epg-reset context))))
1184
1185 ;;;###autoload
1186 (defun epg-start-sign (context plain &optional mode)
1187   "Initiate a sign operation on PLAIN.
1188 PLAIN is a data object.
1189
1190 If optional 3rd argument MODE is 'clearsign, it makes a clear text signature.
1191 If MODE is t or 'detached, it makes a detached signature.
1192 Otherwise, it makes a normal signature.
1193
1194 If you use this function, you will need to wait for the completion of
1195 `epg-gpg-program' by using `epg-wait-for-completion' and call
1196 `epg-reset' to clear a temporaly output file.
1197 If you are unsure, use synchronous version of this function
1198 `epg-sign-file' or `epg-sign-string' instead."
1199   (epg-context-set-result context nil)
1200   (epg-start context
1201              (append (list (if (eq mode 'clearsign)
1202                                "--clearsign"
1203                              (if (or (eq mode t) (eq mode 'detached))
1204                                  "--detach-sign"
1205                                "--sign")))
1206                      (apply #'nconc
1207                             (mapcar
1208                              (lambda (signer)
1209                                (list "-u"
1210                                      (epg-sub-key-id
1211                                       (car (epg-key-sub-key-list signer)))))
1212                              (epg-context-signers context)))
1213                      (if (epg-data-file plain)
1214                          (list (epg-data-file plain)))))
1215   ;; `gpgsm' does not read passphrase from stdin, so waiting is not needed.
1216   (unless (eq (epg-context-protocol context) 'CMS)
1217     (epg-wait-for-status context '("BEGIN_SIGNING")))
1218   (if (and (epg-data-string plain)
1219            (eq (process-status (epg-context-process context)) 'run))
1220       (process-send-string (epg-context-process context)
1221                            (epg-data-string plain))))
1222
1223 ;;;###autoload
1224 (defun epg-sign-file (context plain signature &optional mode)
1225   "Sign a file PLAIN and store the result to a file SIGNATURE.
1226 If SIGNATURE is nil, it returns the result as a string.
1227 If optional 3rd argument MODE is 'clearsign, it makes a clear text signature.
1228 If MODE is t or 'detached, it makes a detached signature.
1229 Otherwise, it makes a normal signature."
1230   (unwind-protect
1231       (progn
1232         (if signature
1233             (epg-context-set-output-file context signature)
1234           (epg-context-set-output-file context
1235                                        (epg-make-temp-file "epg-output")))
1236         (epg-start-sign context (epg-make-data-from-file plain) mode)
1237         (epg-wait-for-completion context)
1238         (unless (epg-context-result-for context 'sign)
1239           (error "Sign failed: %S"
1240                  (epg-context-result-for context 'error)))
1241         (unless signature
1242           (epg-read-output context)))
1243     (unless signature
1244       (epg-delete-output-file context))
1245     (epg-reset context)))
1246
1247 ;;;###autoload
1248 (defun epg-sign-string (context plain &optional mode)
1249   "Sign a string PLAIN and return the output as string.
1250 If optional 3rd argument MODE is 'clearsign, it makes a clear text signature.
1251 If MODE is t or 'detached, it makes a detached signature.
1252 Otherwise, it makes a normal signature."
1253   (unwind-protect
1254       (progn
1255         (epg-context-set-output-file context
1256                                      (epg-make-temp-file "epg-output"))
1257         (epg-start-sign context (epg-make-data-from-string plain) mode)
1258         (epg-flush context)
1259         (epg-wait-for-completion context)
1260         (unless (epg-context-result-for context 'sign)
1261           (error "Sign failed: %S"
1262                  (epg-context-result-for context 'error)))
1263         (epg-read-output context))
1264     (epg-delete-output-file context)
1265     (epg-reset context)))
1266
1267 ;;;###autoload
1268 (defun epg-start-encrypt (context plain recipients
1269                                   &optional sign always-trust)
1270   "Initiate an encrypt operation on PLAIN.
1271 PLAIN is a data object.
1272 If RECIPIENTS is nil, it performs symmetric encryption.
1273
1274 If you use this function, you will need to wait for the completion of
1275 `epg-gpg-program' by using `epg-wait-for-completion' and call
1276 `epg-reset' to clear a temporaly output file.
1277 If you are unsure, use synchronous version of this function
1278 `epg-encrypt-file' or `epg-encrypt-string' instead."
1279   (epg-context-set-result context nil)
1280   (epg-start context
1281              (append (if always-trust '("--always-trust"))
1282                      (if recipients '("--encrypt") '("--symmetric"))
1283                      (if sign
1284                          (cons "--sign"
1285                                (apply #'nconc
1286                                       (mapcar (lambda (signer)
1287                                                 (list "-u" signer))
1288                                               (epg-context-signers context)))))
1289                      (apply #'nconc
1290                             (mapcar
1291                              (lambda (recipient)
1292                                (list "-r"
1293                                      (epg-sub-key-id
1294                                       (car (epg-key-sub-key-list recipient)))))
1295                              recipients))
1296                      (if (epg-data-file plain)
1297                          (list (epg-data-file plain)))))
1298   ;; `gpgsm' does not read passphrase from stdin, so waiting is not needed.
1299   (unless (eq (epg-context-protocol context) 'CMS)
1300     (if sign
1301         (epg-wait-for-status context '("BEGIN_SIGNING"))
1302       (epg-wait-for-status context '("BEGIN_ENCRYPTION"))))
1303   (if (and (epg-data-string plain)
1304            (eq (process-status (epg-context-process context)) 'run))
1305       (process-send-string (epg-context-process context)
1306                            (epg-data-string plain))))
1307
1308 ;;;###autoload
1309 (defun epg-encrypt-file (context plain recipients
1310                                  cipher &optional sign always-trust)
1311   "Encrypt a file PLAIN and store the result to a file CIPHER.
1312 If CIPHER is nil, it returns the result as a string.
1313 If RECIPIENTS is nil, it performs symmetric encryption."
1314   (unwind-protect
1315       (progn
1316         (if cipher
1317             (epg-context-set-output-file context cipher)
1318           (epg-context-set-output-file context
1319                                        (epg-make-temp-file "epg-output")))
1320         (epg-start-encrypt context (epg-make-data-from-file plain)
1321                            recipients sign always-trust)
1322         (epg-wait-for-completion context)
1323         (if (and sign
1324                  (not (epg-context-result-for context 'sign)))
1325             (error "Sign encrypt failed: %S"
1326                    (epg-context-result-for context 'error)))
1327         (if (epg-context-result-for context 'error)
1328             (error "Encrypt failed: %S"
1329                    (epg-context-result-for context 'error)))
1330         (unless cipher
1331           (epg-read-output context)))
1332     (unless cipher
1333       (epg-delete-output-file context))
1334     (epg-reset context)))
1335
1336 ;;;###autoload
1337 (defun epg-encrypt-string (context plain recipients
1338                                    &optional sign always-trust)
1339   "Encrypt a string PLAIN.
1340 If RECIPIENTS is nil, it performs symmetric encryption."
1341   (unwind-protect
1342       (progn
1343         (epg-context-set-output-file context
1344                                      (epg-make-temp-file "epg-output"))
1345         (epg-start-encrypt context (epg-make-data-from-string plain)
1346                            recipients sign always-trust)
1347         (epg-flush context)
1348         (epg-wait-for-completion context)
1349         (if (and sign
1350                  (not (epg-context-result-for context 'sign)))
1351             (error "Sign encrypt failed: %S"
1352                    (epg-context-result-for context 'error)))
1353         (if (epg-context-result-for context 'error)
1354             (error "Encrypt failed: %S"
1355                    (epg-context-result-for context 'error)))
1356         (epg-read-output context))
1357     (epg-delete-output-file context)
1358     (epg-reset context)))
1359
1360 ;;;###autoload
1361 (defun epg-start-export-keys (context keys)
1362   "Initiate an export keys operation.
1363
1364 If you use this function, you will need to wait for the completion of
1365 `epg-gpg-program' by using `epg-wait-for-completion' and call
1366 `epg-reset' to clear a temporaly output file.
1367 If you are unsure, use synchronous version of this function
1368 `epg-export-keys-to-file' or `epg-export-keys-to-string' instead."
1369   (epg-context-set-result context nil)
1370   (epg-start context (cons "--export"
1371                            (mapcar
1372                             (lambda (key)
1373                               (epg-sub-key-id
1374                                (car (epg-key-sub-key-list key))))
1375                             keys))))
1376
1377 ;;;###autoload
1378 (defun epg-export-keys-to-file (context keys file)
1379   "Extract public KEYS."
1380   (unwind-protect
1381       (progn
1382         (if keys
1383             (epg-context-set-output-file context file)
1384           (epg-context-set-output-file context
1385                                        (epg-make-temp-file "epg-output")))
1386         (epg-start-export-keys context keys)
1387         (epg-wait-for-completion context)
1388         (if (epg-context-result-for context 'error)
1389             (error "Export keys failed: %S"
1390                    (epg-context-result-for context 'error)))
1391         (unless file
1392           (epg-read-output context)))
1393     (unless file
1394       (epg-delete-output-file context))
1395     (epg-reset context)))
1396
1397 ;;;###autoload
1398 (defun epg-export-keys-to-string (context keys)
1399   "Extract public KEYS and return them as a string."
1400   (epg-export-keys-to-file context keys nil))
1401
1402 ;;;###autoload
1403 (defun epg-start-import-keys (context keys)
1404   "Initiate an import keys operation.
1405 KEYS is a data object.
1406
1407 If you use this function, you will need to wait for the completion of
1408 `epg-gpg-program' by using `epg-wait-for-completion' and call
1409 `epg-reset' to clear a temporaly output file.
1410 If you are unsure, use synchronous version of this function
1411 `epg-import-keys-from-file' or `epg-import-keys-from-string' instead."
1412   (epg-context-set-result context nil)
1413   (epg-context-set-output-file context (epg-make-temp-file "epg-output"))
1414   (epg-start context (list "--import" (epg-data-file keys)))
1415   (if (and (epg-data-string keys)
1416            (eq (process-status (epg-context-process context)) 'run))
1417       (process-send-string (epg-context-process context)
1418                            (epg-data-string keys))))
1419   
1420 (defun epg-import-keys-1 (context keys)
1421   (unwind-protect
1422       (progn
1423         (epg-start-import-keys context keys)
1424         (if (epg-data-file keys)
1425             (epg-flush context))
1426         (epg-wait-for-completion context)
1427         (if (epg-context-result-for context 'error)
1428             (error "Import keys failed: %S"
1429                    (epg-context-result-for context 'error)))
1430         (epg-read-output context))
1431     (epg-reset context)))
1432
1433 ;;;###autoload
1434 (defun epg-import-keys-from-file (context keys)
1435   "Add keys from a file KEYS."
1436   (epg-import-keys-1 context (epg-make-data-from-file keys)))
1437
1438 ;;;###autoload
1439 (defun epg-import-keys-from-string (context keys)
1440   "Add keys from a string KEYS."
1441   (epg-import-keys-1 context (epg-make-data-from-string keys)))
1442
1443 ;;;###autoload
1444 (defun epg-start-delete-keys (context keys &optional allow-secret)
1445   "Initiate an delete keys operation.
1446
1447 If you use this function, you will need to wait for the completion of
1448 `epg-gpg-program' by using `epg-wait-for-completion' and call
1449 `epg-reset' to clear a temporaly output file.
1450 If you are unsure, use synchronous version of this function
1451 `epg-delete-keys' instead."
1452   (epg-context-set-result context nil)
1453   (epg-start context (cons (if allow-secret
1454                                "--delete-secret-key"
1455                              "--delete-key")
1456                            (mapcar
1457                             (lambda (key)
1458                               (epg-sub-key-id
1459                                (car (epg-key-sub-key-list key))))
1460                             keys))))
1461
1462 ;;;###autoload
1463 (defun epg-delete-keys (context keys &optional allow-secret)
1464   "Delete KEYS from the key ring."
1465   (unwind-protect
1466       (progn
1467         (epg-start-delete-keys context keys allow-secret)
1468         (epg-wait-for-completion context)
1469         (if (epg-context-result-for context 'error)
1470             (error "Delete keys failed: %S"
1471                    (epg-context-result-for context 'error))))
1472     (epg-reset context)))
1473
1474 ;;;###autoload
1475 (defun epg-start-sign-keys (context keys &optional local)
1476   "Initiate an sign keys operation.
1477
1478 If you use this function, you will need to wait for the completion of
1479 `epg-gpg-program' by using `epg-wait-for-completion' and call
1480 `epg-reset' to clear a temporaly output file.
1481 If you are unsure, use synchronous version of this function
1482 `epg-sign-keys' instead."
1483   (epg-context-set-result context nil)
1484   (epg-start context (cons (if local
1485                                "--lsign-key"
1486                              "--sign-key")
1487                            (mapcar
1488                             (lambda (key)
1489                               (epg-sub-key-id
1490                                (car (epg-key-sub-key-list key))))
1491                             keys))))
1492
1493 ;;;###autoload
1494 (defun epg-sign-keys (context keys &optional local)
1495   "Sign KEYS from the key ring."
1496   (unwind-protect
1497       (progn
1498         (epg-start-sign-keys context keys local)
1499         (epg-wait-for-completion context)
1500         (if (epg-context-result-for context 'error)
1501             (error "Sign keys failed: %S"
1502                    (epg-context-result-for context 'error))))
1503     (epg-reset context)))
1504
1505 (defun epg-decode-hexstring (string)
1506   (let ((index 0))
1507     (while (eq index (string-match "[0-9A-Fa-f][0-9A-Fa-f]" string index))
1508       (setq string (replace-match "\\x\\&" t nil string)
1509             index (+ index 4)))
1510     (car (read-from-string (concat "\"" string "\"")))))
1511
1512 (defun epg-decode-quotedstring (string)
1513   (let ((index 0))
1514     (while (string-match "\\\\\\(\\([,=+<>#;\\\"]\\)\\|\
1515 \\([0-9A-Fa-f][0-9A-Fa-f]\\)\\|\\(.\\)\\)"
1516                          string index)
1517       (if (match-beginning 2)
1518           (setq string (replace-match "\\2" t nil string)
1519                 index (1+ index))
1520         (if (match-beginning 3)
1521             (setq string (replace-match "\\x\\3" t nil string)
1522                   index (+ index 4))
1523           (setq string (replace-match "\\\\\\\\\\4" t nil string)
1524                 index (+ index 3)))))
1525     (car (read-from-string (concat "\"" string "\"")))))
1526
1527 (defun epg-dn-from-string (string)
1528   "Parse STRING as LADPv3 Distinguished Names (RFC2253).
1529 The return value is an alist mapping from types to values."
1530   (let ((index 0)
1531         (length (length string))
1532         alist type value group)
1533     (while (< index length)
1534       (if (eq index (string-match "[ \t\n\r]*" string index))
1535           (setq index (match-end 0)))
1536       (if (eq index (string-match
1537                      "\\([0-9]+\\(\\.[0-9]+\\)*\\)\[ \t\n\r]*=[ \t\n\r]*"
1538                      string index))
1539           (setq type (match-string 1 string)
1540                 index (match-end 0))
1541         (if (eq index (string-match "\\([0-9A-Za-z]+\\)[ \t\n\r]*=[ \t\n\r]*"
1542                                     string index))
1543             (setq type (match-string 1 string)
1544                   index (match-end 0))))
1545       (unless type
1546         (error "Invalid type"))
1547       (if (eq index (string-match
1548                      "\\([^,=+<>#;\\\"]\\|\\\\.\\)+"
1549                      string index))
1550           (setq index (match-end 0)
1551                 value (epg-decode-quotedstring (match-string 0 string)))
1552         (if (eq index (string-match "#\\([0-9A-Fa-f]+\\)" string index))
1553             (setq index (match-end 0)
1554                   value (epg-decode-hexstring (match-string 1 string)))
1555           (if (eq index (string-match "\"\\([^\\\"]\\|\\\\.\\)*\""
1556                                       string index))
1557               (setq index (match-end 0)
1558                     value (epg-decode-quotedstring (match-string 0 string))))))
1559       (if group
1560           (if (stringp (car (car alist)))
1561               (setcar alist (list (cons type value) (car alist)))
1562             (setcar alist (cons (cons type value) (car alist))))
1563         (if (consp (car (car alist)))
1564             (setcar alist (nreverse (car alist))))
1565         (setq alist (cons (cons type value) alist)
1566               type nil
1567               value nil))
1568       (if (eq index (string-match "[ \t\n\r]*\\([,;+]\\)" string index))
1569           (setq index (match-end 0)
1570                 group (eq (aref string (match-beginning 1)) ?+))))
1571     (nreverse alist)))
1572
1573 (defun epg-decode-dn (alist)
1574   "Convert ALIST returned by `epg-dn-from-string' to a human readable form.
1575 Type names are resolved using `epg-dn-type-alist'."
1576   (mapconcat
1577    (lambda (rdn)
1578      (if (stringp (car rdn))
1579          (let ((entry (assoc (car rdn) epg-dn-type-alist)))
1580            (if entry
1581                (format "%s=%s" (cdr entry) (cdr rdn))
1582              (format "%s=%s" (car rdn) (cdr rdn))))
1583        (concat "(" (epg-decode-dn rdn) ")")))
1584    alist
1585    ", "))
1586
1587 (provide 'epg)
1588
1589 ;;; epg.el ends here