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