662ffe90ed89fde4e816b759be700a239bba2ba8
[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
295 (defun epg-status-USERID_HINT (process string)
296   (if (string-match "\\`\\([^ ]+\\) \\(.*\\)" string)
297       (let* ((key-id (match-string 1 string))
298              (user-id (match-string 2 string))
299              (entry (assoc key-id epg-user-id-alist)))
300         (if entry
301             (setcdr entry user-id)
302           (setq epg-user-id-alist (cons (cons key-id user-id)
303                                         epg-user-id-alist))))))
304
305 (defun epg-status-NEED_PASSPHRASE (process string)
306   (if (string-match "\\`\\([^ ]+\\)" string)
307       (setq epg-key-id (match-string 1 string))))
308
309 (defun epg-status-NEED_PASSPHRASE_SYM (process string)
310   (setq epg-key-id 'SYM))
311
312 (defun epg-status-NEED_PASSPHRASE_PIN (process string)
313   (setq epg-key-id 'PIN))
314
315 (defun epg-status-GET_HIDDEN (process string)
316   (let ((passphrase
317          (funcall (car (epg-context-passphrase-callback-info epg-context))
318                   epg-key-id
319                   (cdr (epg-context-passphrase-callback-info epg-context))))
320         string)
321     (if passphrase
322         (unwind-protect
323             (progn
324               (setq string (concat passphrase "\n"))
325               (fillarray passphrase 0)
326               (setq passphrase nil)
327               (process-send-string process string))
328           (if string
329               (fillarray string 0))))))
330
331 (defun epg-status-GOODSIG (process string)
332   (if (string-match "\\`\\([^ ]+\\) \\(.*\\)" string)
333       (epg-context-set-result-for
334        epg-context
335        'verify
336        (cons (epg-make-signature 'good
337                                  (match-string 1 string)
338                                  (match-string 2 string))
339              (epg-context-result-for epg-context 'verify)))))
340
341 (defun epg-status-EXPSIG (process string)
342   (if (string-match "\\`\\([^ ]+\\) \\(.*\\)" string)
343       (epg-context-set-result-for
344        epg-context
345        'verify
346        (cons (epg-make-signature 'expired
347                                  (match-string 1 string)
348                                  (match-string 2 string))
349              (epg-context-result-for epg-context 'verify)))))
350
351 (defun epg-status-EXPKEYSIG (process string)
352   (if (string-match "\\`\\([^ ]+\\) \\(.*\\)" string)
353       (epg-context-set-result-for
354        epg-context
355        'verify
356        (cons (epg-make-signature 'expired-key
357                                  (match-string 1 string)
358                                  (match-string 2 string))
359              (epg-context-result-for epg-context 'verify)))))
360
361 (defun epg-status-REVKEYSIG (process string)
362   (if (string-match "\\`\\([^ ]+\\) \\(.*\\)" string)
363       (epg-context-set-result-for
364        epg-context
365        'verify
366        (cons (epg-make-signature 'revoked-key
367                                  (match-string 1 string)
368                                  (match-string 2 string))
369              (epg-context-result-for epg-context 'verify)))))
370
371 (defun epg-status-BADSIG (process string)
372   (if (string-match "\\`\\([^ ]+\\) \\(.*\\)" string)
373       (epg-context-set-result-for
374        epg-context
375        'verify
376        (cons (epg-make-signature 'bad
377                                  (match-string 1 string)
378                                  (match-string 2 string))
379              (epg-context-result-for epg-context 'verify)))))
380
381 (defun epg-status-TRUST_UNDEFINED (process string)
382   (let ((signature (car (epg-context-result-for epg-context 'verify))))
383     (if (and signature
384              (eq (epg-signature-status signature) 'good))
385         (epg-signature-set-validity signature 'unknown))))
386
387 (defun epg-status-TRUST_NEVER (process string)
388   (let ((signature (car (epg-context-result-for epg-context 'verify))))
389     (if (and signature
390              (eq (epg-signature-status signature) 'good))
391         (epg-signature-set-validity signature 'never))))
392
393 (defun epg-status-TRUST_MARGINAL (process string)
394   (let ((signature (car (epg-context-result-for epg-context 'verify))))
395     (if (and signature
396              (eq (epg-signature-status signature) 'marginal))
397         (epg-signature-set-validity signature 'marginal))))
398
399 (defun epg-status-TRUST_FULLY (process string)
400   (let ((signature (car (epg-context-result-for epg-context 'verify))))
401     (if (and signature
402              (eq (epg-signature-status signature) 'good))
403         (epg-signature-set-validity signature 'full))))
404
405 (defun epg-status-TRUST_ULTIMATE (process string)
406   (let ((signature (car (epg-context-result-for epg-context 'verify))))
407     (if (and signature
408              (eq (epg-signature-status signature) 'good))
409         (epg-signature-set-validity signature 'full))))
410
411 (defun epg-status-PROGRESS (process string)
412   (if (string-match "\\`\\([^ ]+\\) \\([^ ]\\) \\([0-9]+\\) \\([0-9]+\\)"
413                     string)
414       (funcall (car (epg-context-progress-callback-info epg-context))
415                (match-string 1 string)
416                (match-string 2 string)
417                (string-to-number (match-string 3 string))
418                (string-to-number (match-string 4 string))
419                (cdr (epg-context-progress-callback-info epg-context)))))
420
421 (defun epg-status-DECRYPTION_FAILED (process string)
422   (epg-context-set-result-for
423    epg-context 'error
424    (cons 'decryption-failed
425          (epg-context-result-for epg-context 'error))))
426
427 (defun epg-status-NODATA (process string)
428   (epg-context-set-result-for
429    epg-context 'error
430    (cons (cons 'no-data (string-to-number string))
431          (epg-context-result-for epg-context 'error))))
432
433 (defun epg-status-UNEXPECTED (process string)
434   (epg-context-set-result-for
435    epg-context 'error
436    (cons (cons 'unexpected (string-to-number string))
437          (epg-context-result-for epg-context 'error))))
438
439 (defun epg-status-KEYEXPIRED (process string)
440   (epg-context-set-result-for
441    epg-context 'error
442    (cons (cons 'key-expired string)
443          (epg-context-result-for epg-context 'error))))
444
445 (defun epg-status-KEYREVOKED (process string)
446   (epg-context-set-result-for
447    epg-context 'error
448    (cons 'key-revoked
449          (epg-context-result-for epg-context 'error))))
450
451 (defun epg-status-BADARMOR (process string)
452   (epg-context-set-result-for
453    epg-context 'error
454    (cons 'bad-armor
455          (epg-context-result-for epg-context 'error))))
456
457 (defun epg-passphrase-callback-function (key-id handback)
458   (read-passwd
459    (if (eq key-id 'SYM)
460        "Passphrase for symmetric encryption: "
461      (if (eq key-id 'PIN)
462          "Passphrase for PIN: "
463        (let ((entry (assoc key-id epg-user-id-alist)))
464          (if entry
465              (format "Passphrase for %s %s: " key-id (cdr entry))
466            (format "Passphrase for %s: " key-id)))))))
467
468 (defun epg-progress-callback-function (what char current total handback)
469   (message "%s: %d%%/%d%%" what current total))
470
471 (defun epg-list-keys (name &optional secret)
472   "List keys associated with STRING."
473   (let ((args (list "--with-colons" "--no-greeting" "--batch"
474                     "--fixed-list-mode"
475                     (if secret "--list-secret-keys" "--list-keys")
476                     name))
477         keys type symbol pointer)
478     (with-temp-buffer
479       (apply #'call-process epg-gpg-program nil (list t nil) nil args)
480       (goto-char (point-min))
481       (while (looking-at "\\([a-z][a-z][a-z]\\):\\(.*\\)")
482         (setq type (match-string 1)
483               symbol (intern-soft (format "epg-colons-%s-spec" type)))
484         (if (member type '("pub" "sec"))
485             (setq keys (cons nil keys)))
486         (if (and symbol
487                  (boundp symbol))
488             (setcar keys (cons (cons (intern type)
489                                      (epg-parse-colons
490                                       (symbol-value symbol)
491                                       (match-string 2)))
492                                (car keys))))
493         (forward-line)))
494     (setq pointer keys)
495     (while pointer
496       (setcar pointer (nreverse (car pointer)))
497       (setq pointer (cdr pointer)))
498     (nreverse keys)))
499
500 (defun epg-parse-colons (alist string)
501   (let ((index 0)
502         result)
503     (while (and alist
504                 (or (null (car alist))
505                     (eq index
506                         (string-match
507                          (concat "\\(" (nth 1 (car alist)) "\\)?:")
508                          string index))))
509       (if (car alist)
510           (progn
511             (setq index (match-end 0))
512             (if (match-beginning 1)
513                 (setq result
514                       (cons (cons (car (car alist))
515                                   (funcall (or (nth 3 (car alist)) #'identity)
516                                            (match-string
517                                             (1+ (or (nth 2 (car alist)) 0))
518                                             string)))
519                             result))))
520         (setq index (1+ index)))
521       (setq alist (cdr alist)))
522     (nreverse result)))
523
524 (if (fboundp 'make-temp-file)
525     (defalias 'epg-make-temp-file 'make-temp-file)
526   ;; stolen from poe.el.
527   (defun epg-make-temp-file (prefix)
528     "Create a temporary file.
529 The returned file name (created by appending some random characters at the end
530 of PREFIX, and expanding against `temporary-file-directory' if necessary),
531 is guaranteed to point to a newly created empty file.
532 You can then use `write-region' to write new data into the file."
533     (let (tempdir tempfile)
534       (unwind-protect
535           (let (file)
536             ;; First, create a temporary directory.
537             (while (condition-case ()
538                        (progn
539                          (setq tempdir (make-temp-name
540                                         (concat
541                                          (file-name-directory prefix)
542                                          "DIR")))
543                          ;; return nil or signal an error.
544                          (make-directory tempdir))
545                      ;; let's try again.
546                      (file-already-exists t)))
547             (set-file-modes tempdir 448)
548             ;; Second, create a temporary file in the tempdir.
549             ;; There *is* a race condition between `make-temp-name'
550             ;; and `write-region', but we don't care it since we are
551             ;; in a private directory now.
552             (setq tempfile (make-temp-name (concat tempdir "/EMU")))
553             (write-region "" nil tempfile nil 'silent)
554             (set-file-modes tempfile 384)
555             ;; Finally, make a hard-link from the tempfile.
556             (while (condition-case ()
557                        (progn
558                          (setq file (make-temp-name prefix))
559                          ;; return nil or signal an error.
560                          (add-name-to-file tempfile file))
561                      ;; let's try again.
562                      (file-already-exists t)))
563             file)
564         ;; Cleanup the tempfile.
565         (and tempfile
566              (file-exists-p tempfile)
567              (delete-file tempfile))
568         ;; Cleanup the tempdir.
569         (and tempdir
570              (file-directory-p tempdir)
571              (delete-directory tempdir))))))
572
573 ;;;###autoload
574 (defun epg-start-decrypt (context input-file)
575   "Initiate a decrypt operation on INPUT-FILE.
576
577 If you use this function, you will need to wait for the completion of
578 `epg-gpg-program' by using `epg-wait-for-completion' and call
579 `epg-reset' to clear a temporaly output file.
580 If you are unsure, use synchronous version of this function
581 `epg-decrypt-string' instead."
582   (epg-context-set-result context nil)
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-result context nil)
625   (epg-context-set-output-file context (epg-make-temp-file "epg-output"))
626   (if string
627       ;; Detached signature.
628       (progn
629         (epg-start context
630                    (append (list "--verify")
631                            (list signature "-")))
632         (if (eq (process-status (epg-context-process context)) 'run)
633             (process-send-string (epg-context-process context) string)))
634     ;; Normal (or cleartext) signature.
635     (epg-start context (list "--verify"))
636     (if (eq (process-status (epg-context-process context)) 'run)
637         (process-send-string (epg-context-process context) signature))))
638
639 ;;;###autoload
640 (defun epg-verify-file (context input-file &optional string)
641   "Verify INPUT-FILE.
642
643 For a detached signature, both INPUT-FILE and STRING should be string.
644 For a normal or a clear text signature, STRING should be nil."
645   (unwind-protect
646       (progn
647         (epg-start-verify context input-file string)
648         (epg-wait-for-completion context)
649         (epg-context-result-for context 'verify))
650     (epg-reset context)))
651
652 ;;;###autoload
653 (defun epg-verify-string (context signature &optional string)
654   "Verify SIGNATURE.
655
656 For a detached signature, both SIGNATURE and STRING should be string.
657 For a normal or a clear text signature, STRING should be nil."
658   (let ((input-file (epg-make-temp-file "epg-input"))
659         (coding-system-for-write 'binary))
660     (unwind-protect
661         (progn
662           (if string
663               (write-region signature nil input-file))
664           (epg-verify-file context input-file string))
665       (if (file-exists-p input-file)
666           (delete-file input-file)))))
667
668 ;;;###autoload
669 (defun epg-start-sign (context string &optional mode)
670   "Initiate a sign operation on STRING.
671
672 If optional 3rd argument MODE is 'clearsign, it makes a clear text signature.
673 If MODE is t or 'detached, it makes a detached signature.
674 Otherwise, it makes a normal signature.
675
676 If you use this function, you will need to wait for the completion of
677 `epg-gpg-program' by using `epg-wait-for-completion' and call
678 `epg-reset' to clear a temporaly output file.
679 If you are unsure, use synchronous version of this function
680 `epg-sign-string' instead."
681   (epg-context-set-result context nil)
682   (epg-context-set-output-file context (epg-make-temp-file "epg-output"))
683   (epg-start context
684              (append (list (if (eq mode 'clearsign)
685                                "--clearsign"
686                              (if (or (eq mode t) (eq mode 'detached))
687                                  "--detach-sign"
688                                "--sign")))
689                      (apply #'nconc
690                             (mapcar (lambda (signer)
691                                       (list "-u" signer))
692                                     (epg-context-signers context)))))
693   (epg-wait-for-status context '("BEGIN_SIGNING"))
694   (if (eq (process-status (epg-context-process context)) 'run)
695       (process-send-string (epg-context-process context) string)))
696
697 ;;;###autoload
698 (defun epg-sign-string (context string &optional mode)
699   "Sign STRING and return the output as string.
700 If optional 3rd argument MODE is 'clearsign, it makes a clear text signature.
701 If MODE is t or 'detached, it makes a detached signature.
702 Otherwise, it makes a normal signature."
703   (unwind-protect
704       (progn
705         (epg-start-sign context string mode)
706         (epg-wait-for-completion context)
707         (if (epg-context-result-for context 'error)
708             (error "Sign failed"))
709         (epg-read-output context))
710     (epg-reset context)))
711
712 ;;;###autoload
713 (defun epg-start-encrypt (context string recipients
714                                   &optional sign always-trust)
715   "Initiate an encrypt operation on STRING.
716 If RECIPIENTS is nil, it performs symmetric encryption.
717
718 If you use this function, you will need to wait for the completion of
719 `epg-gpg-program' by using `epg-wait-for-completion' and call
720 `epg-reset' to clear a temporaly output file.
721 If you are unsure, use synchronous version of this function
722 `epg-encrypt-string' instead."
723   (epg-context-set-result context nil)
724   (epg-context-set-output-file context (epg-make-temp-file "epg-output"))
725   (epg-start context
726              (append (if always-trust '("--always-trust"))
727                      (if recipients '("--encrypt") '("--symmetric"))
728                      (if sign
729                          (cons "--sign"
730                                (apply #'nconc
731                                       (mapcar (lambda (signer)
732                                                 (list "-u" signer))
733                                               (epg-context-signers context)))))
734                      (apply #'nconc
735                             (mapcar (lambda (recipient)
736                                       (list "-r" recipient))
737                                     recipients))))
738   (if sign
739       (epg-wait-for-status context '("BEGIN_SIGNING"))
740     (if (null recipients)
741         (epg-wait-for-status context '("BEGIN_ENCRYPTION"))))
742   (if (eq (process-status (epg-context-process context)) 'run)
743       (process-send-string (epg-context-process context) string)))
744
745 ;;;###autoload
746 (defun epg-encrypt-string (context string recipients
747                                    &optional sign always-trust)
748   "Encrypt STRING.
749 If RECIPIENTS is nil, it performs symmetric encryption."
750   (unwind-protect
751       (progn
752         (epg-start-encrypt context string recipients sign always-trust)
753         (epg-wait-for-completion context)
754         (if (epg-context-result-for context 'error)
755             (error "Encrypt failed"))
756         (epg-read-output context))
757     (epg-reset context)))
758
759 ;;;###autoload
760 (defun epg-start-export-keys (context pattern)
761   "Initiate an export keys operation.
762
763 If you use this function, you will need to wait for the completion of
764 `epg-gpg-program' by using `epg-wait-for-completion' and call
765 `epg-reset' to clear a temporaly output file.
766 If you are unsure, use synchronous version of this function
767 `epg-export-keys' instead."
768   (epg-context-set-result context nil)
769   (epg-context-set-output-file context (epg-make-temp-file "epg-output"))
770   (epg-start context (list "--export" pattern)))
771
772 ;;;###autoload
773 (defun epg-export-keys (context pattern)
774   "Extract public keys matched with PATTERN and return them."
775   (unwind-protect
776       (progn
777         (epg-start-export-keys context pattern)
778         (epg-wait-for-completion context)
779         (if (epg-context-result-for context 'error)
780             (error "Export keys failed"))
781         (epg-read-output context))
782     (epg-reset context)))
783
784 ;;;###autoload
785 (defun epg-start-import-keys (context keys)
786   "Initiate an import key operation.
787
788 If you use this function, you will need to wait for the completion of
789 `epg-gpg-program' by using `epg-wait-for-completion' and call
790 `epg-reset' to clear a temporaly output file.
791 If you are unsure, use synchronous version of this function
792 `epg-import-keys' instead."
793   (epg-context-set-result context nil)
794   (epg-context-set-output-file context (epg-make-temp-file "epg-output"))
795   (epg-start context (list "--import"))
796   (if (eq (process-status (epg-context-process context)) 'run)
797       (process-send-string (epg-context-process context) keys)))
798
799 ;;;###autoload
800 (defun epg-import-keys (context keys)
801   "Add KEYS."
802   (unwind-protect
803       (progn
804         (epg-start-import-keys context keys)
805         (epg-wait-for-completion context)
806         (if (epg-context-result-for context 'error)
807             (error "Import keys failed"))
808         (epg-read-output context))
809     (epg-reset context)))
810
811 (provide 'epg)
812
813 ;;; epg.el ends here