Fix including nil bytes in keylist output.
[gpgme.git] / src / gpgme-tool.c
1 /* gpgme-tool.c - Assuan server exposing GnuPG Made Easy operations.
2    Copyright (C) 2009, 2010, 2012, 2013 g10 Code GmbH
3    Copyright (C) 2001, 2003, 2009, 2011 Free Software Foundation, Inc.
4
5    This file is part of GPGME.
6
7    GPGME is free software; you can redistribute it and/or modify it
8    under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    GPGME is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    Lesser General Public License for more details.
16
17    You should have received a copy of the GNU Lesser General Public
18    License along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #if HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <getopt.h>
30 #include <ctype.h>
31 #include <stdarg.h>
32 #ifdef HAVE_LOCALE_H
33 #include <locale.h>
34 #endif
35
36 #include <assuan.h>
37
38 #include "argparse.h"
39 #include "gpgme.h"
40
41 /* GCC attributes.  */
42 #if __GNUC__ >= 4
43 # define GT_GCC_A_SENTINEL(a) __attribute__ ((sentinel(a)))
44 #else
45 # define GT_GCC_A_SENTINEL(a)
46 #endif
47
48 #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )
49 # define GT_GCC_A_PRINTF(f, a)  __attribute__ ((format (printf,f,a)))
50 #else
51 # define GT_GCC_A_PRINTF(f, a)
52 #endif
53
54 #define DIM(v) (sizeof(v)/sizeof((v)[0]))
55 #define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
56                      *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
57 #define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
58
59
60 \f
61 /* MEMBUF */
62
63 /* A simple implementation of a dynamic buffer.  Use init_membuf() to
64    create a buffer, put_membuf to append bytes and get_membuf to
65    release and return the buffer.  Allocation errors are detected but
66    only returned at the final get_membuf(), this helps not to clutter
67    the code with out-of-core checks.  */
68
69 /* The definition of the structure is private, we only need it here,
70    so it can be allocated on the stack. */
71 struct private_membuf_s
72 {
73   size_t len;
74   size_t size;
75   char *buf;
76   int out_of_core;
77 };
78
79 typedef struct private_membuf_s membuf_t;
80
81 /* Return the current length of the membuf.  */
82 #define get_membuf_len(a)  ((a)->len)
83 #define is_membuf_ready(a) ((a)->buf || (a)->out_of_core)
84 #define MEMBUF_ZERO        { 0, 0, NULL, 0}
85
86
87 static void
88 init_membuf (membuf_t *mb, int initiallen)
89 {
90   mb->len = 0;
91   mb->size = initiallen;
92   mb->out_of_core = 0;
93   mb->buf = malloc (initiallen);
94   if (!mb->buf)
95     mb->out_of_core = errno;
96 }
97
98
99 /* Shift the the content of the membuf MB by AMOUNT bytes.  The next
100    operation will then behave as if AMOUNT bytes had not been put into
101    the buffer.  If AMOUNT is greater than the actual accumulated
102    bytes, the membuf is basically reset to its initial state.  */
103 #if 0 /* Not yet used.  */
104 static void
105 clear_membuf (membuf_t *mb, size_t amount)
106 {
107   /* No need to clear if we are already out of core.  */
108   if (mb->out_of_core)
109     return;
110   if (amount >= mb->len)
111     mb->len = 0;
112   else
113     {
114       mb->len -= amount;
115       memmove (mb->buf, mb->buf+amount, mb->len);
116     }
117 }
118 #endif /* unused */
119
120 static void
121 put_membuf (membuf_t *mb, const void *buf, size_t len)
122 {
123   if (mb->out_of_core || !len)
124     return;
125
126   if (mb->len + len >= mb->size)
127     {
128       char *p;
129
130       mb->size += len + 1024;
131       p = realloc (mb->buf, mb->size);
132       if (!p)
133         {
134           mb->out_of_core = errno ? errno : ENOMEM;
135           return;
136         }
137       mb->buf = p;
138     }
139   memcpy (mb->buf + mb->len, buf, len);
140   mb->len += len;
141 }
142
143
144 #if 0 /* Not yet used.  */
145 static void
146 put_membuf_str (membuf_t *mb, const char *string)
147 {
148   put_membuf (mb, string, strlen (string));
149 }
150 #endif /* unused */
151
152
153 static void *
154 get_membuf (membuf_t *mb, size_t *len)
155 {
156   char *p;
157
158   if (mb->out_of_core)
159     {
160       if (mb->buf)
161         {
162           free (mb->buf);
163           mb->buf = NULL;
164         }
165       gpg_err_set_errno (mb->out_of_core);
166       return NULL;
167     }
168
169   p = mb->buf;
170   if (len)
171     *len = mb->len;
172   mb->buf = NULL;
173   mb->out_of_core = ENOMEM; /* hack to make sure it won't get reused. */
174   return p;
175 }
176
177
178 /* Peek at the membuf MB.  On success a pointer to the buffer is
179    returned which is valid until the next operation on MB.  If LEN is
180    not NULL the current LEN of the buffer is stored there.  On error
181    NULL is returned and ERRNO is set.  */
182 #if 0 /* Not yet used.  */
183 static const void *
184 peek_membuf (membuf_t *mb, size_t *len)
185 {
186   const char *p;
187
188   if (mb->out_of_core)
189     {
190       gpg_err_set_errno (mb->out_of_core);
191       return NULL;
192     }
193
194   p = mb->buf;
195   if (len)
196     *len = mb->len;
197   return p;
198 }
199 #endif /* unused */
200
201
202 \f
203 /* SUPPORT.  */
204 FILE *log_stream;
205 char *program_name = "gpgme-tool";
206
207 #define spacep(p)   (*(p) == ' ' || *(p) == '\t')
208
209
210 void log_error (int status, gpg_error_t errnum,
211                 const char *fmt, ...) GT_GCC_A_PRINTF(3,4);
212
213
214 void
215 log_init (void)
216 {
217   log_stream = stderr;
218 }
219
220
221 void
222 log_error (int status, gpg_error_t errnum, const char *fmt, ...)
223 {
224   va_list ap;
225
226   fprintf (log_stream, "%s: ", program_name);
227   va_start (ap, fmt);
228   vfprintf (log_stream, fmt, ap);
229   va_end (ap);
230   if (errnum)
231     {
232       fprintf (log_stream, ": %s", gpg_strerror (errnum));
233       if (gpg_err_source (errnum) != GPG_ERR_SOURCE_GPGME)
234         fprintf (log_stream, " <%s>", gpg_strsource (errnum));
235     }
236   fprintf (log_stream, "\n");
237   if (status)
238     exit (status);
239 }
240
241
242 /* Note that it is sufficient to allocate the target string D as long
243    as the source string S, i.e.: strlen(s)+1;.  D == S is allowed.  */
244 static void
245 strcpy_escaped_plus (char *d, const char *s)
246 {
247   while (*s)
248     {
249       if (*s == '%' && s[1] && s[2])
250         {
251           s++;
252           *d++ = xtoi_2 (s);
253           s += 2;
254         }
255       else if (*s == '+')
256         *d++ = ' ', s++;
257       else
258         *d++ = *s++;
259     }
260   *d = 0;
261 }
262
263
264 /* Check whether the option NAME appears in LINE.  */
265 static int
266 has_option (const char *line, const char *name)
267 {
268   const char *s;
269   int n = strlen (name);
270
271   s = strstr (line, name);
272   return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
273 }
274
275 /* Skip over options.  It is assumed that leading spaces have been
276    removed (this is the case for lines passed to a handler from
277    assuan).  Blanks after the options are also removed.  */
278 static char *
279 skip_options (char *line)
280 {
281   while ( *line == '-' && line[1] == '-' )
282     {
283       while (*line && !spacep (line))
284         line++;
285       while (spacep (line))
286         line++;
287     }
288   return line;
289 }
290
291
292
293 \f
294 typedef gpg_error_t (*result_xml_write_cb_t) (void *hook, const void *buf,
295                                               size_t len);
296
297 static char xml_preamble1[] = "<?xml version=\"1.0\" "
298   "encoding=\"UTF-8\" standalone=\"yes\"?>\n";
299 static const char xml_preamble2[] = "<gpgme>\n";
300 static const char xml_end[] = "</gpgme>\n";
301
302
303 struct result_xml_state
304 {
305   int indent;
306   result_xml_write_cb_t cb;
307   void *hook;
308
309 #define MAX_TAGS 20
310   int next_tag;
311   char *tag[MAX_TAGS];
312   int had_data[MAX_TAGS];
313 };
314
315
316 void
317 result_init (struct result_xml_state *state, int indent,
318              result_xml_write_cb_t cb, void *hook)
319 {
320   memset (state, '\0', sizeof (*state));
321   state->indent = indent;
322   state->cb = cb;
323   state->hook = hook;
324 }
325
326
327 gpg_error_t
328 result_xml_indent (struct result_xml_state *state)
329 {
330   char spaces[state->indent + 1];
331   int i;
332   for (i = 0; i < state->indent; i++)
333     spaces[i] = ' ';
334   spaces[i] = '\0';
335   return (*state->cb) (state->hook, spaces, i);
336 }
337
338
339 gpg_error_t
340 result_xml_tag_start (struct result_xml_state *state, char *name, ...)
341 {
342   result_xml_write_cb_t cb = state->cb;
343   void *hook = state->hook;
344   va_list ap;
345   char *attr;
346   char *attr_val;
347
348   va_start (ap, name);
349
350   if (state->next_tag > 0)
351     {
352       if (! state->had_data[state->next_tag - 1])
353         {
354           (*cb) (hook, ">\n", 2);
355           (*cb) (hook, NULL, 0);
356         }
357       state->had_data[state->next_tag - 1] = 1;
358     }
359
360   result_xml_indent (state);
361   (*cb) (hook, "<", 1);
362   (*cb) (hook, name, strlen (name));
363
364   state->tag[state->next_tag] = name;
365   state->had_data[state->next_tag] = 0;
366   state->indent += 2;
367   state->next_tag++;
368
369   while (1)
370     {
371       attr = va_arg (ap, char *);
372       if (attr == NULL)
373         break;
374
375       attr_val = va_arg (ap, char *);
376       if (attr_val == NULL)
377         attr_val = "(null)";
378
379       (*cb) (hook, " ", 1);
380       (*cb) (hook, attr, strlen (attr));
381       (*cb) (hook, "=\"", 2);
382       (*cb) (hook, attr_val, strlen (attr_val));
383       (*cb) (hook, "\"", 1);
384     }
385   va_end (ap);
386   return 0;
387 }
388
389 /* Return a constant string with an XML entity for C.  */
390 static const char *
391 result_xml_escape_replacement(char c)
392 {
393   switch (c)
394     {
395     case '<':
396       return "&lt;";
397     case '>':
398       return "&gt;";
399     case '&':
400       return "&amp;";
401     default:
402       return NULL;
403     }
404 }
405
406 /* Escape DATA by replacing certain characters with their XML
407    entities.  The result is stored in a newly allocated buffer which
408    address will be stored at BUF.   Returns 0 on success. */
409 static gpg_error_t
410 result_xml_escape (const char *data, char **buf)
411 {
412   int data_len, i;
413   const char *r;
414   membuf_t mb;
415
416   init_membuf (&mb, 128);
417   if (data)
418     {
419       data_len = strlen (data);
420       for (i = 0; i < data_len; i++)
421         {
422           r = result_xml_escape_replacement (data[i]);
423           if (r)
424             put_membuf (&mb, r, strlen (r));
425           else
426             put_membuf (&mb, data+i, 1);
427         }
428     }
429   put_membuf (&mb, "", 1);
430   *buf = get_membuf (&mb, NULL);
431   return *buf? 0 : gpg_error_from_syserror ();
432 }
433
434
435 gpg_error_t
436 result_xml_tag_data (struct result_xml_state *state, const char *data)
437 {
438   gpg_error_t err;
439   result_xml_write_cb_t cb = state->cb;
440   void *hook = state->hook;
441   char *buf = NULL;
442
443   if (state->had_data[state->next_tag - 1])
444     {
445       (*cb) (hook, "\n", 2);
446       (*cb) (hook, NULL, 0);
447       result_xml_indent (state);
448     }
449   else
450     (*cb) (hook, ">", 1);
451   state->had_data[state->next_tag - 1] = 2;
452
453   err = result_xml_escape (data, &buf);
454   if (err)
455     return err;
456
457   (*cb) (hook, buf, strlen (buf));
458
459   free (buf);
460
461   return 0;
462 }
463
464
465 gpg_error_t
466 result_xml_tag_end (struct result_xml_state *state)
467 {
468   result_xml_write_cb_t cb = state->cb;
469   void *hook = state->hook;
470
471   state->next_tag--;
472   state->indent -= 2;
473
474   if (state->had_data[state->next_tag])
475     {
476       if (state->had_data[state->next_tag] == 1)
477         result_xml_indent (state);
478       (*cb) (hook, "</", 2);
479       (*cb) (hook, state->tag[state->next_tag],
480              strlen (state->tag[state->next_tag]));
481       (*cb) (hook, ">\n", 2);
482       (*cb) (hook, NULL, 0);
483     }
484   else
485     {
486       (*cb) (hook, " />\n", 4);
487       (*cb) (hook, NULL, 0);
488     }
489   return 0;
490 }
491
492
493 gpg_error_t
494 result_add_error (struct result_xml_state *state, char *name, gpg_error_t err)
495 {
496   char code[20];
497   char msg[1024];
498   snprintf (code, sizeof (code) - 1, "0x%x", err);
499   snprintf (msg, sizeof (msg) - 1, "%s <%s>",
500             gpg_strerror (err), gpg_strsource (err));
501   result_xml_tag_start (state, name, "value", code, NULL);
502   result_xml_tag_data (state, msg);
503   result_xml_tag_end (state);
504   return 0;
505 }
506
507
508 gpg_error_t
509 result_add_pubkey_algo (struct result_xml_state *state,
510                         char *name, gpgme_pubkey_algo_t algo)
511 {
512   char code[20];
513   char msg[80];
514   snprintf (code, sizeof (code) - 1, "0x%x", algo);
515   snprintf (msg, sizeof (msg) - 1, "%s",
516             gpgme_pubkey_algo_name (algo));
517   result_xml_tag_start (state, name, "value", code, NULL);
518   result_xml_tag_data (state, msg);
519   result_xml_tag_end (state);
520   return 0;
521 }
522
523
524 gpg_error_t
525 result_add_hash_algo (struct result_xml_state *state,
526                          char *name, gpgme_hash_algo_t algo)
527 {
528   char code[20];
529   char msg[80];
530   snprintf (code, sizeof (code) - 1, "0x%x", algo);
531   snprintf (msg, sizeof (msg) - 1, "%s",
532             gpgme_hash_algo_name (algo));
533   result_xml_tag_start (state, name, "value", code, NULL);
534   result_xml_tag_data (state, msg);
535   result_xml_tag_end (state);
536   return 0;
537 }
538
539
540 gpg_error_t
541 result_add_keyid (struct result_xml_state *state, char *name, char *keyid)
542 {
543   result_xml_tag_start (state, name, NULL);
544   result_xml_tag_data (state, keyid);
545   result_xml_tag_end (state);
546   return 0;
547 }
548
549
550 gpg_error_t
551 result_add_fpr (struct result_xml_state *state, char *name, char *fpr)
552 {
553   result_xml_tag_start (state, name, NULL);
554   result_xml_tag_data (state, fpr);
555   result_xml_tag_end (state);
556   return 0;
557 }
558
559
560 gpg_error_t
561 result_add_timestamp (struct result_xml_state *state, char *name,
562                       unsigned int timestamp)
563 {
564   char code[20];
565
566   snprintf (code, sizeof (code) - 1, "%ui", timestamp);
567   result_xml_tag_start (state, name, "unix", code, NULL);
568   result_xml_tag_end (state);
569   return 0;
570 }
571
572
573 gpg_error_t
574 result_add_sig_mode (struct result_xml_state *state, char *name,
575                      gpgme_sig_mode_t sig_mode)
576 {
577   char *mode;
578   char code[20];
579
580   snprintf (code, sizeof (code) - 1, "%i", sig_mode);
581   switch (sig_mode)
582     {
583     case GPGME_SIG_MODE_NORMAL:
584       mode = "normal";
585       break;
586     case GPGME_SIG_MODE_DETACH:
587       mode = "detach";
588       break;
589     case GPGME_SIG_MODE_CLEAR:
590       mode = "clear";
591       break;
592     default:
593       mode = "unknown";
594     }
595
596   result_xml_tag_start (state, name, "type", mode, "value", code, NULL);
597   result_xml_tag_data (state, mode);
598   result_xml_tag_end (state);
599   return 0;
600 }
601
602
603 gpg_error_t
604 result_add_protocol (struct result_xml_state *state, char *name,
605                      gpgme_protocol_t protocol)
606 {
607   const char *str;
608   char code[20];
609
610   snprintf (code, sizeof (code) - 1, "%i", protocol);
611   str = gpgme_get_protocol_name(protocol);
612   if (!str)
613     str = "invalid";
614   result_xml_tag_start (state, name, "value", code, NULL);
615   result_xml_tag_data (state, str);
616   result_xml_tag_end (state);
617   return 0;
618 }
619
620
621 gpg_error_t
622 result_add_validity (struct result_xml_state *state, char *name,
623                      gpgme_validity_t validity)
624 {
625   const char *str;
626   char code[20];
627
628   snprintf (code, sizeof (code) - 1, "%i", validity);
629   switch (validity)
630     {
631     case GPGME_VALIDITY_UNDEFINED:
632       str ="undefined";
633       break;
634     case GPGME_VALIDITY_NEVER:
635       str ="never";
636       break;
637     case GPGME_VALIDITY_MARGINAL:
638       str ="marginal";
639       break;
640     case GPGME_VALIDITY_FULL:
641       str ="full";
642       break;
643     case GPGME_VALIDITY_ULTIMATE:
644       str ="ultimate";
645       break;
646     default:
647       str ="unknown";
648     }
649
650   result_xml_tag_start (state, name, "value", code, NULL);
651   result_xml_tag_data (state, str);
652   result_xml_tag_end (state);
653   return 0;
654 }
655
656
657 gpg_error_t
658 result_add_value (struct result_xml_state *state,
659                   char *name, unsigned int val)
660 {
661   char code[20];
662
663   snprintf (code, sizeof (code) - 1, "0x%x", val);
664   result_xml_tag_start (state, name, "value", code, NULL);
665   result_xml_tag_end (state);
666   return 0;
667 }
668
669
670 gpg_error_t
671 result_add_string (struct result_xml_state *state,
672                    char *name, char *str)
673 {
674   if (!str)
675     str = "";
676   result_xml_tag_start (state, name, NULL);
677   result_xml_tag_data (state, str);
678   result_xml_tag_end (state);
679   return 0;
680 }
681
682
683 gpg_error_t
684 result_encrypt_to_xml (gpgme_ctx_t ctx, int indent,
685                        result_xml_write_cb_t cb, void *hook)
686 {
687   struct result_xml_state state;
688   gpgme_encrypt_result_t res = gpgme_op_encrypt_result (ctx);
689   gpgme_invalid_key_t inv_recp;
690
691   if (! res)
692     return 0;
693
694   result_init (&state, indent, cb, hook);
695   result_xml_tag_start (&state, "encrypt-result", NULL);
696
697   inv_recp = res->invalid_recipients;
698   if (inv_recp)
699     {
700       result_xml_tag_start (&state, "invalid-recipients", NULL);
701
702       while (inv_recp)
703         {
704           result_xml_tag_start (&state, "invalid-key", NULL);
705           if (inv_recp->fpr)
706             result_add_fpr (&state, "fpr", inv_recp->fpr);
707           result_add_error (&state, "reason", inv_recp->reason);
708           result_xml_tag_end (&state);
709           inv_recp = inv_recp->next;
710         }
711       result_xml_tag_end (&state);
712     }
713   result_xml_tag_end (&state);
714
715   return 0;
716 }
717
718
719 gpg_error_t
720 result_decrypt_to_xml (gpgme_ctx_t ctx, int indent,
721                        result_xml_write_cb_t cb, void *hook)
722 {
723   struct result_xml_state state;
724   gpgme_decrypt_result_t res = gpgme_op_decrypt_result (ctx);
725   gpgme_recipient_t recp;
726
727   if (! res)
728     return 0;
729
730   result_init (&state, indent, cb, hook);
731   result_xml_tag_start (&state, "decrypt-result", NULL);
732
733   if (res->file_name)
734     {
735       result_xml_tag_start (&state, "file-name", NULL);
736       result_xml_tag_data (&state, res->file_name);
737       result_xml_tag_end (&state);
738     }
739   if (res->unsupported_algorithm)
740     {
741       result_xml_tag_start (&state, "unsupported-alogorithm", NULL);
742       result_xml_tag_data (&state, res->unsupported_algorithm);
743       result_xml_tag_end (&state);
744     }
745   if (res->wrong_key_usage)
746     {
747       result_xml_tag_start (&state, "wrong-key-usage", NULL);
748       result_xml_tag_end (&state);
749     }
750
751   recp = res->recipients;
752   if (recp)
753     {
754       result_xml_tag_start (&state, "recipients", NULL);
755       while (recp)
756         {
757           result_xml_tag_start (&state, "recipient", NULL);
758           result_add_keyid (&state, "keyid", recp->keyid);
759           result_add_pubkey_algo (&state, "pubkey-algo", recp->pubkey_algo);
760           result_add_error (&state, "status", recp->status);
761           result_xml_tag_end (&state);
762           recp = recp->next;
763         }
764       result_xml_tag_end (&state);
765     }
766   result_xml_tag_end (&state);
767
768   return 0;
769 }
770
771
772 gpg_error_t
773 result_sign_to_xml (gpgme_ctx_t ctx, int indent,
774                     result_xml_write_cb_t cb, void *hook)
775 {
776   struct result_xml_state state;
777   gpgme_sign_result_t res = gpgme_op_sign_result (ctx);
778   gpgme_invalid_key_t inv_key;
779   gpgme_new_signature_t new_sig;
780
781   if (! res)
782     return 0;
783
784   result_init (&state, indent, cb, hook);
785   result_xml_tag_start (&state, "sign-result", NULL);
786
787   inv_key = res->invalid_signers;
788   if (inv_key)
789     {
790       result_xml_tag_start (&state, "invalid-signers", NULL);
791
792       while (inv_key)
793         {
794           result_xml_tag_start (&state, "invalid-key", NULL);
795           if (inv_key->fpr)
796             result_add_fpr (&state, "fpr", inv_key->fpr);
797           result_add_error (&state, "reason", inv_key->reason);
798           result_xml_tag_end (&state);
799           inv_key = inv_key->next;
800         }
801       result_xml_tag_end (&state);
802     }
803
804   new_sig = res->signatures;
805   if (new_sig)
806     {
807       result_xml_tag_start (&state, "signatures", NULL);
808
809       while (new_sig)
810         {
811           result_xml_tag_start (&state, "new-signature", NULL);
812           result_add_sig_mode (&state, "type", new_sig->type);
813           result_add_pubkey_algo (&state, "pubkey-algo", new_sig->pubkey_algo);
814           result_add_hash_algo (&state, "hash-algo", new_sig->hash_algo);
815           result_add_timestamp (&state, "timestamp", new_sig->timestamp);
816           if (new_sig->fpr)
817             result_add_fpr (&state, "fpr", new_sig->fpr);
818           result_add_value (&state, "sig-class", new_sig->sig_class);
819
820           result_xml_tag_end (&state);
821           new_sig = new_sig->next;
822         }
823       result_xml_tag_end (&state);
824     }
825
826   result_xml_tag_end (&state);
827
828   return 0;
829 }
830
831
832 gpg_error_t
833 result_verify_to_xml (gpgme_ctx_t ctx, int indent,
834                       result_xml_write_cb_t cb, void *hook)
835 {
836   struct result_xml_state state;
837   gpgme_verify_result_t res = gpgme_op_verify_result (ctx);
838   gpgme_signature_t sig;
839
840   if (! res)
841     return 0;
842
843   result_init (&state, indent, cb, hook);
844   result_xml_tag_start (&state, "verify-result", NULL);
845
846   if (res->file_name)
847     {
848       result_xml_tag_start (&state, "file-name", NULL);
849       result_xml_tag_data (&state, res->file_name);
850       result_xml_tag_end (&state);
851     }
852
853   sig = res->signatures;
854   if (sig)
855     {
856       result_xml_tag_start (&state, "signatures", NULL);
857
858       while (sig)
859         {
860           result_xml_tag_start (&state, "signature", NULL);
861
862           /* FIXME: Could be done better. */
863           result_add_value (&state, "summary", sig->summary);
864           if (sig->fpr)
865             result_add_fpr (&state, "fpr", sig->fpr);
866           result_add_error (&state, "status", sig->status);
867           /* FIXME: notations */
868           result_add_timestamp (&state, "timestamp", sig->timestamp);
869           result_add_timestamp (&state, "exp-timestamp", sig->exp_timestamp);
870           result_add_value (&state, "wrong-key-usage", sig->wrong_key_usage);
871           result_add_value (&state, "pka-trust", sig->pka_trust);
872           result_add_value (&state, "chain-model", sig->chain_model);
873           result_add_value (&state, "validity", sig->validity);
874           result_add_error (&state, "validity-reason", sig->validity_reason);
875           result_add_pubkey_algo (&state, "pubkey-algo", sig->pubkey_algo);
876           result_add_hash_algo (&state, "hash-algo", sig->hash_algo);
877           if (sig->pka_address)
878             result_add_string (&state, "pka_address", sig->pka_address);
879
880           result_xml_tag_end (&state);
881           sig = sig->next;
882         }
883       result_xml_tag_end (&state);
884     }
885
886   result_xml_tag_end (&state);
887
888   return 0;
889 }
890
891
892 gpg_error_t
893 result_import_to_xml (gpgme_ctx_t ctx, int indent,
894                       result_xml_write_cb_t cb, void *hook)
895 {
896   struct result_xml_state state;
897   gpgme_import_result_t res = gpgme_op_import_result (ctx);
898   gpgme_import_status_t stat;
899
900   if (! res)
901     return 0;
902
903   result_init (&state, indent, cb, hook);
904   result_xml_tag_start (&state, "import-result", NULL);
905
906   result_add_value (&state, "considered", res->considered);
907   result_add_value (&state, "no-user-id", res->no_user_id);
908   result_add_value (&state, "imported", res->imported);
909   result_add_value (&state, "imported-rsa", res->imported_rsa);
910   result_add_value (&state, "unchanged", res->unchanged);
911   result_add_value (&state, "new-user-ids", res->new_user_ids);
912   result_add_value (&state, "new-sub-keys", res->new_sub_keys);
913   result_add_value (&state, "new-signatures", res->new_signatures);
914   result_add_value (&state, "new-revocations", res->new_revocations);
915   result_add_value (&state, "secret-read", res->secret_read);
916   result_add_value (&state, "secret-imported", res->secret_imported);
917   result_add_value (&state, "secret-unchanged", res->secret_unchanged);
918   result_add_value (&state, "skipped-new-keys", res->skipped_new_keys);
919   result_add_value (&state, "not-imported", res->not_imported);
920
921   stat = res->imports;
922   if (stat)
923     {
924       result_xml_tag_start (&state, "imports", NULL);
925
926       while (stat)
927         {
928           result_xml_tag_start (&state, "import-status", NULL);
929
930           if (stat->fpr)
931             result_add_fpr (&state, "fpr", stat->fpr);
932           result_add_error (&state, "result", stat->result);
933           /* FIXME: Could be done better. */
934           result_add_value (&state, "status", stat->status);
935
936           result_xml_tag_end (&state);
937           stat = stat->next;
938         }
939       result_xml_tag_end (&state);
940     }
941
942   result_xml_tag_end (&state);
943
944   return 0;
945 }
946
947
948 gpg_error_t
949 result_genkey_to_xml (gpgme_ctx_t ctx, int indent,
950                       result_xml_write_cb_t cb, void *hook)
951 {
952   struct result_xml_state state;
953   gpgme_genkey_result_t res = gpgme_op_genkey_result (ctx);
954
955   if (! res)
956     return 0;
957
958   result_init (&state, indent, cb, hook);
959   result_xml_tag_start (&state, "genkey-result", NULL);
960
961   result_add_value (&state, "primary", res->primary);
962   result_add_value (&state, "sub", res->sub);
963   if (res->fpr)
964     result_add_fpr (&state, "fpr", res->fpr);
965
966   result_xml_tag_end (&state);
967
968   return 0;
969 }
970
971
972 gpg_error_t
973 result_keylist_to_xml (gpgme_ctx_t ctx, int indent,
974                       result_xml_write_cb_t cb, void *hook)
975 {
976   struct result_xml_state state;
977   gpgme_keylist_result_t res = gpgme_op_keylist_result (ctx);
978
979   if (! res)
980     return 0;
981
982   result_init (&state, indent, cb, hook);
983   result_xml_tag_start (&state, "keylist-result", NULL);
984
985   result_add_value (&state, "truncated", res->truncated);
986
987   result_xml_tag_end (&state);
988
989   return 0;
990 }
991
992
993 gpg_error_t
994 result_vfs_mount_to_xml (gpgme_ctx_t ctx, int indent,
995                          result_xml_write_cb_t cb, void *hook)
996 {
997   struct result_xml_state state;
998   gpgme_vfs_mount_result_t res = gpgme_op_vfs_mount_result (ctx);
999
1000   if (! res)
1001     return 0;
1002
1003   result_init (&state, indent, cb, hook);
1004   result_xml_tag_start (&state, "vfs-mount-result", NULL);
1005
1006   result_add_string (&state, "mount-dir", res->mount_dir);
1007
1008   result_xml_tag_end (&state);
1009
1010   return 0;
1011 }
1012
1013 \f
1014 typedef enum status
1015   {
1016     STATUS_PROTOCOL,
1017     STATUS_PROGRESS,
1018     STATUS_ENGINE,
1019     STATUS_ARMOR,
1020     STATUS_TEXTMODE,
1021     STATUS_INCLUDE_CERTS,
1022     STATUS_KEYLIST_MODE,
1023     STATUS_RECIPIENT,
1024     STATUS_ENCRYPT_RESULT,
1025     STATUS_IDENTIFY_RESULT
1026   } status_t;
1027
1028 const char *status_string[] =
1029   {
1030     "PROTOCOL",
1031     "PROGRESS",
1032     "ENGINE",
1033     "ARMOR",
1034     "TEXTMODE",
1035     "INCLUDE_CERTS",
1036     "KEYLIST_MODE",
1037     "RECIPIENT",
1038     "ENCRYPT_RESULT",
1039     "IDENTIFY_RESULT"
1040   };
1041
1042 struct gpgme_tool
1043 {
1044   gpgme_ctx_t ctx;
1045 #define MAX_RECIPIENTS 10
1046   gpgme_key_t recipients[MAX_RECIPIENTS + 1];
1047   int recipients_nr;
1048
1049   gpg_error_t (*write_status) (void *hook, const char *status, const char *msg);
1050   void *write_status_hook;
1051   gpg_error_t (*write_data) (void *hook, const void *buf, size_t len);
1052   void *write_data_hook;
1053 };
1054 typedef struct gpgme_tool *gpgme_tool_t;
1055
1056
1057 /* Forward declaration.  */
1058 void gt_write_status (gpgme_tool_t gt,
1059                       status_t status, ...) GT_GCC_A_SENTINEL(0);
1060 static gpg_error_t
1061 server_passphrase_cb (void *opaque, const char *uid_hint, const char *info,
1062                       int was_bad, int fd);
1063
1064
1065 void
1066 _gt_progress_cb (void *opaque, const char *what,
1067                  int type, int current, int total)
1068 {
1069   gpgme_tool_t gt = opaque;
1070   char buf[100];
1071
1072   snprintf (buf, sizeof (buf), "0x%02x %i %i", type, current, total);
1073   gt_write_status (gt, STATUS_PROGRESS, what, buf, NULL);
1074 }
1075
1076
1077 gpg_error_t
1078 _gt_gpgme_new (gpgme_tool_t gt, gpgme_ctx_t *ctx)
1079 {
1080   gpg_error_t err;
1081
1082   err = gpgme_new (ctx);
1083   if (err)
1084     return err;
1085   gpgme_set_progress_cb (*ctx, _gt_progress_cb, gt);
1086   return 0;
1087 }
1088
1089
1090 void
1091 gt_init (gpgme_tool_t gt)
1092 {
1093   gpg_error_t err;
1094
1095   memset (gt, '\0', sizeof (*gt));
1096
1097   err = _gt_gpgme_new (gt, &gt->ctx);
1098   if (err)
1099     log_error (1, err, "can't create gpgme context");
1100 }
1101
1102
1103 gpg_error_t
1104 gt_signers_add (gpgme_tool_t gt, const char *fpr)
1105 {
1106   gpg_error_t err;
1107   gpgme_key_t key;
1108
1109   err = gpgme_get_key (gt->ctx, fpr, &key, 0);
1110   if (err)
1111     return err;
1112
1113   return gpgme_signers_add (gt->ctx, key);
1114 }
1115
1116
1117 gpg_error_t
1118 gt_signers_clear (gpgme_tool_t gt)
1119 {
1120   gpgme_signers_clear (gt->ctx);
1121   return 0;
1122 }
1123
1124
1125 gpg_error_t
1126 gt_get_key (gpgme_tool_t gt, const char *pattern, gpgme_key_t *r_key)
1127 {
1128   gpgme_ctx_t ctx;
1129   gpgme_ctx_t listctx;
1130   gpgme_error_t err;
1131   gpgme_key_t key;
1132
1133   if (!gt || !r_key || !pattern)
1134     return gpg_error (GPG_ERR_INV_VALUE);
1135
1136   ctx = gt->ctx;
1137
1138   err = gpgme_new (&listctx);
1139   if (err)
1140     return err;
1141
1142   {
1143     gpgme_protocol_t proto;
1144     gpgme_engine_info_t info;
1145
1146     /* Clone the relevant state.  */
1147     proto = gpgme_get_protocol (ctx);
1148     /* The g13 protocol does not allow keylisting, we need to choose
1149        something else.  */
1150     if (proto == GPGME_PROTOCOL_G13)
1151       proto = GPGME_PROTOCOL_OpenPGP;
1152
1153     gpgme_set_protocol (listctx, proto);
1154     gpgme_set_keylist_mode (listctx, gpgme_get_keylist_mode (ctx));
1155     info = gpgme_ctx_get_engine_info (ctx);
1156     while (info && info->protocol != proto)
1157       info = info->next;
1158     if (info)
1159       gpgme_ctx_set_engine_info (listctx, proto,
1160                                  info->file_name, info->home_dir);
1161   }
1162
1163   err = gpgme_op_keylist_start (listctx, pattern, 0);
1164   if (!err)
1165     err = gpgme_op_keylist_next (listctx, r_key);
1166   if (!err)
1167     {
1168     try_next_key:
1169       err = gpgme_op_keylist_next (listctx, &key);
1170       if (gpgme_err_code (err) == GPG_ERR_EOF)
1171         err = 0;
1172       else
1173         {
1174           if (!err
1175               && *r_key && (*r_key)->subkeys && (*r_key)->subkeys->fpr
1176               && key && key->subkeys && key->subkeys->fpr
1177               && !strcmp ((*r_key)->subkeys->fpr, key->subkeys->fpr))
1178             {
1179               /* The fingerprint is identical.  We assume that this is
1180                  the same key and don't mark it as an ambiguous.  This
1181                  problem may occur with corrupted keyrings and has
1182                  been noticed often with gpgsm.  In fact gpgsm uses a
1183                  similar hack to sort out such duplicates but it can't
1184                  do that while listing keys.  */
1185               gpgme_key_unref (key);
1186               goto try_next_key;
1187             }
1188           if (!err)
1189             {
1190               gpgme_key_unref (key);
1191               err = gpg_error (GPG_ERR_AMBIGUOUS_NAME);
1192             }
1193           gpgme_key_unref (*r_key);
1194         }
1195     }
1196   gpgme_release (listctx);
1197
1198   if (! err)
1199     gt_write_status (gt, STATUS_RECIPIENT,
1200                      ((*r_key)->subkeys && (*r_key)->subkeys->fpr) ?
1201                      (*r_key)->subkeys->fpr : "invalid", NULL);
1202   return err;
1203 }
1204
1205
1206 gpg_error_t
1207 gt_recipients_add (gpgme_tool_t gt, const char *pattern)
1208 {
1209   gpg_error_t err;
1210   gpgme_key_t key;
1211
1212   if (gt->recipients_nr >= MAX_RECIPIENTS)
1213     return gpg_error (GPG_ERR_ENOMEM);
1214
1215   if (gpgme_get_protocol (gt->ctx) == GPGME_PROTOCOL_UISERVER)
1216     err = gpgme_key_from_uid (&key, pattern);
1217   else
1218     err = gt_get_key (gt, pattern, &key);
1219   if (err)
1220     return err;
1221
1222   gt->recipients[gt->recipients_nr++] = key;
1223   return 0;
1224 }
1225
1226
1227 void
1228 gt_recipients_clear (gpgme_tool_t gt)
1229 {
1230   int idx;
1231
1232   for (idx = 0; idx < gt->recipients_nr; idx++)
1233     gpgme_key_unref (gt->recipients[idx]);
1234   memset (gt->recipients, '\0', gt->recipients_nr * sizeof (gpgme_key_t));
1235   gt->recipients_nr = 0;
1236 }
1237
1238
1239 gpg_error_t
1240 gt_reset (gpgme_tool_t gt)
1241 {
1242   gpg_error_t err;
1243   gpgme_ctx_t ctx;
1244
1245   err = _gt_gpgme_new (gt, &ctx);
1246   if (err)
1247     return err;
1248
1249   gpgme_release (gt->ctx);
1250   gt->ctx = ctx;
1251   gt_recipients_clear (gt);
1252   return 0;
1253 }
1254
1255
1256 void
1257 gt_write_status (gpgme_tool_t gt, status_t status, ...)
1258 {
1259   va_list ap;
1260   const char *text;
1261   char buf[950];
1262   char *p;
1263   size_t n;
1264   gpg_error_t err;
1265
1266   va_start (ap, status);
1267   p = buf;
1268   n = 0;
1269   while ((text = va_arg (ap, const char *)))
1270     {
1271       if (n)
1272         {
1273           *p++ = ' ';
1274           n++;
1275         }
1276       while (*text && n < sizeof (buf) - 2)
1277         {
1278           *p++ = *text++;
1279           n++;
1280         }
1281     }
1282   *p = 0;
1283   va_end (ap);
1284
1285   err = gt->write_status (gt->write_status_hook, status_string[status], buf);
1286   if (err)
1287     log_error (1, err, "can't write status line");
1288 }
1289
1290
1291 gpg_error_t
1292 gt_write_data (gpgme_tool_t gt, const void *buf, size_t len)
1293 {
1294   return gt->write_data (gt->write_data_hook, buf, len);
1295 }
1296
1297
1298 gpg_error_t
1299 gt_get_engine_info (gpgme_tool_t gt, gpgme_protocol_t proto)
1300 {
1301   gpgme_engine_info_t info;
1302   info = gpgme_ctx_get_engine_info (gt->ctx);
1303   while (info)
1304     {
1305       if (proto == GPGME_PROTOCOL_UNKNOWN || proto == info->protocol)
1306         gt_write_status (gt, STATUS_ENGINE,
1307                          gpgme_get_protocol_name (info->protocol),
1308                          info->file_name, info->version,
1309                          info->req_version, info->home_dir, NULL);
1310       info = info->next;
1311     }
1312   return 0;
1313 }
1314
1315
1316 gpgme_protocol_t
1317 gt_protocol_from_name (const char *name)
1318 {
1319   if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_OpenPGP)))
1320     return GPGME_PROTOCOL_OpenPGP;
1321   if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_CMS)))
1322     return GPGME_PROTOCOL_CMS;
1323   if (! strcasecmp (name,gpgme_get_protocol_name (GPGME_PROTOCOL_GPGCONF)))
1324     return GPGME_PROTOCOL_GPGCONF;
1325   if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_ASSUAN)))
1326     return GPGME_PROTOCOL_ASSUAN;
1327   if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_G13)))
1328     return GPGME_PROTOCOL_G13;
1329   if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_UISERVER)))
1330     return GPGME_PROTOCOL_UISERVER;
1331   if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_SPAWN)))
1332     return GPGME_PROTOCOL_SPAWN;
1333   if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_DEFAULT)))
1334     return GPGME_PROTOCOL_DEFAULT;
1335   return GPGME_PROTOCOL_UNKNOWN;
1336 }
1337
1338
1339 gpg_error_t
1340 gt_set_protocol (gpgme_tool_t gt, gpgme_protocol_t proto)
1341 {
1342   return gpgme_set_protocol (gt->ctx, proto);
1343 }
1344
1345
1346 gpg_error_t
1347 gt_get_protocol (gpgme_tool_t gt)
1348 {
1349   gpgme_protocol_t proto = gpgme_get_protocol (gt->ctx);
1350
1351   gt_write_status (gt, STATUS_PROTOCOL, gpgme_get_protocol_name (proto),
1352                    NULL);
1353
1354   return 0;
1355 }
1356
1357
1358 gpg_error_t
1359 gt_set_sub_protocol (gpgme_tool_t gt, gpgme_protocol_t proto)
1360 {
1361   return gpgme_set_sub_protocol (gt->ctx, proto);
1362 }
1363
1364
1365 gpg_error_t
1366 gt_get_sub_protocol (gpgme_tool_t gt)
1367 {
1368   gpgme_protocol_t proto = gpgme_get_sub_protocol (gt->ctx);
1369
1370   gt_write_status (gt, STATUS_PROTOCOL, gpgme_get_protocol_name (proto),
1371                    NULL);
1372
1373   return 0;
1374 }
1375
1376
1377 gpg_error_t
1378 gt_set_pinentry_mode (gpgme_tool_t gt, gpgme_pinentry_mode_t mode, void *opaque)
1379 {
1380   gpg_error_t err;
1381
1382   gpgme_set_passphrase_cb (gt->ctx, NULL, NULL);
1383   err = gpgme_set_pinentry_mode (gt->ctx, mode);
1384   if (!err && mode == GPGME_PINENTRY_MODE_LOOPBACK)
1385     gpgme_set_passphrase_cb (gt->ctx, server_passphrase_cb, opaque);
1386   return err;
1387 }
1388
1389
1390 gpg_error_t
1391 gt_set_armor (gpgme_tool_t gt, int armor)
1392 {
1393   gpgme_set_armor (gt->ctx, armor);
1394   return 0;
1395 }
1396
1397
1398 gpg_error_t
1399 gt_get_armor (gpgme_tool_t gt)
1400 {
1401   gt_write_status (gt, STATUS_ARMOR,
1402                    gpgme_get_armor (gt->ctx) ? "true" : "false", NULL);
1403
1404   return 0;
1405 }
1406
1407
1408 gpg_error_t
1409 gt_set_textmode (gpgme_tool_t gt, int textmode)
1410 {
1411   gpgme_set_textmode (gt->ctx, textmode);
1412   return 0;
1413 }
1414
1415
1416 gpg_error_t
1417 gt_get_textmode (gpgme_tool_t gt)
1418 {
1419   gt_write_status (gt, STATUS_TEXTMODE,
1420                    gpgme_get_textmode (gt->ctx) ? "true" : "false", NULL);
1421
1422   return 0;
1423 }
1424
1425
1426 gpg_error_t
1427 gt_set_keylist_mode (gpgme_tool_t gt, gpgme_keylist_mode_t keylist_mode)
1428 {
1429   gpgme_set_keylist_mode (gt->ctx, keylist_mode);
1430   return 0;
1431 }
1432
1433
1434 gpg_error_t
1435 gt_get_keylist_mode (gpgme_tool_t gt)
1436 {
1437 #define NR_KEYLIST_MODES 6
1438   const char *modes[NR_KEYLIST_MODES + 1];
1439   int idx = 0;
1440   gpgme_keylist_mode_t mode = gpgme_get_keylist_mode (gt->ctx);
1441
1442   if (mode & GPGME_KEYLIST_MODE_LOCAL)
1443     modes[idx++] = "local";
1444   if (mode & GPGME_KEYLIST_MODE_EXTERN)
1445     modes[idx++] = "extern";
1446   if (mode & GPGME_KEYLIST_MODE_SIGS)
1447     modes[idx++] = "sigs";
1448   if (mode & GPGME_KEYLIST_MODE_SIG_NOTATIONS)
1449     modes[idx++] = "sig_notations";
1450   if (mode & GPGME_KEYLIST_MODE_WITH_SECRET)
1451     modes[idx++] = "with_secret";
1452   if (mode & GPGME_KEYLIST_MODE_EPHEMERAL)
1453     modes[idx++] = "ephemeral";
1454   if (mode & GPGME_KEYLIST_MODE_VALIDATE)
1455     modes[idx++] = "validate";
1456   modes[idx++] = NULL;
1457
1458   gt_write_status (gt, STATUS_KEYLIST_MODE, modes[0], modes[1], modes[2],
1459                    modes[3], modes[4], modes[5], modes[6], NULL);
1460
1461   return 0;
1462 }
1463
1464
1465 gpg_error_t
1466 gt_set_include_certs (gpgme_tool_t gt, int include_certs)
1467 {
1468   gpgme_set_include_certs (gt->ctx, include_certs);
1469   return 0;
1470 }
1471
1472
1473 gpg_error_t
1474 gt_get_include_certs (gpgme_tool_t gt)
1475 {
1476   int include_certs = gpgme_get_include_certs (gt->ctx);
1477   char buf[100];
1478
1479   if (include_certs == GPGME_INCLUDE_CERTS_DEFAULT)
1480     strcpy (buf, "default");
1481   else
1482     snprintf (buf, sizeof (buf), "%i", include_certs);
1483
1484   gt_write_status (gt, STATUS_INCLUDE_CERTS, buf, NULL);
1485
1486   return 0;
1487 }
1488
1489
1490 gpg_error_t
1491 gt_decrypt_verify (gpgme_tool_t gt, gpgme_data_t cipher, gpgme_data_t plain,
1492                    int verify)
1493 {
1494   if (verify)
1495     return gpgme_op_decrypt_verify (gt->ctx, cipher, plain);
1496   else
1497     return gpgme_op_decrypt (gt->ctx, cipher, plain);
1498 }
1499
1500
1501 gpg_error_t
1502 gt_sign_encrypt (gpgme_tool_t gt, gpgme_encrypt_flags_t flags,
1503                  gpgme_data_t plain, gpgme_data_t cipher, int sign)
1504 {
1505   gpg_error_t err;
1506   gpgme_key_t *recp;
1507
1508   recp = gt->recipients_nr? gt->recipients : NULL;
1509
1510   if (sign)
1511     err = gpgme_op_encrypt_sign (gt->ctx, recp, flags, plain, cipher);
1512   else
1513     err = gpgme_op_encrypt (gt->ctx, recp, flags, plain, cipher);
1514
1515   gt_recipients_clear (gt);
1516
1517   return err;
1518 }
1519
1520
1521 gpg_error_t
1522 gt_sign (gpgme_tool_t gt, gpgme_data_t plain, gpgme_data_t sig,
1523          gpgme_sig_mode_t mode)
1524 {
1525   return gpgme_op_sign (gt->ctx, plain, sig, mode);
1526 }
1527
1528
1529 gpg_error_t
1530 gt_verify (gpgme_tool_t gt, gpgme_data_t sig, gpgme_data_t sig_text,
1531            gpgme_data_t plain)
1532 {
1533   return gpgme_op_verify (gt->ctx, sig, sig_text, plain);
1534 }
1535
1536
1537 gpg_error_t
1538 gt_import (gpgme_tool_t gt, gpgme_data_t data)
1539 {
1540   return gpgme_op_import (gt->ctx, data);
1541 }
1542
1543
1544 gpg_error_t
1545 gt_export (gpgme_tool_t gt, const char *pattern[], gpgme_export_mode_t mode,
1546            gpgme_data_t data)
1547 {
1548   return gpgme_op_export_ext (gt->ctx, pattern, mode, data);
1549 }
1550
1551
1552 gpg_error_t
1553 gt_genkey (gpgme_tool_t gt, const char *parms, gpgme_data_t public,
1554            gpgme_data_t secret)
1555 {
1556   return gpgme_op_genkey (gt->ctx, parms, public, secret);
1557 }
1558
1559
1560 gpg_error_t
1561 gt_import_keys (gpgme_tool_t gt, char *fpr[])
1562 {
1563   gpg_error_t err = 0;
1564   int cnt;
1565   int idx;
1566   gpgme_key_t *keys;
1567
1568   cnt = 0;
1569   while (fpr[cnt])
1570     cnt++;
1571
1572   if (! cnt)
1573     return gpg_error (GPG_ERR_INV_VALUE);
1574
1575   keys = malloc ((cnt + 1) * sizeof (gpgme_key_t));
1576   if (! keys)
1577     return gpg_error_from_syserror ();
1578
1579   for (idx = 0; idx < cnt; idx++)
1580     {
1581       err = gpgme_get_key (gt->ctx, fpr[idx], &keys[idx], 0);
1582       if (err)
1583         break;
1584     }
1585   if (! err)
1586     {
1587       keys[cnt] = NULL;
1588       err = gpgme_op_import_keys (gt->ctx, keys);
1589     }
1590
1591   /* Rollback.  */
1592   while (--idx >= 0)
1593     gpgme_key_unref (keys[idx]);
1594   free (keys);
1595
1596   return err;
1597 }
1598
1599
1600 gpg_error_t
1601 gt_delete (gpgme_tool_t gt, char *fpr, int allow_secret)
1602 {
1603   gpg_error_t err;
1604   gpgme_key_t key;
1605
1606   err = gpgme_get_key (gt->ctx, fpr, &key, 0);
1607   if (err)
1608     return err;
1609
1610   err = gpgme_op_delete (gt->ctx, key, allow_secret);
1611   gpgme_key_unref (key);
1612   return err;
1613 }
1614
1615
1616 gpg_error_t
1617 gt_keylist_start (gpgme_tool_t gt, const char *pattern[], int secret_only)
1618 {
1619   return gpgme_op_keylist_ext_start (gt->ctx, pattern, secret_only, 0);
1620 }
1621
1622
1623 gpg_error_t
1624 gt_keylist_next (gpgme_tool_t gt, gpgme_key_t *key)
1625 {
1626   return gpgme_op_keylist_next (gt->ctx, key);
1627 }
1628
1629
1630 gpg_error_t
1631 gt_getauditlog (gpgme_tool_t gt, gpgme_data_t output, unsigned int flags)
1632 {
1633   return gpgme_op_getauditlog (gt->ctx, output, flags);
1634 }
1635
1636
1637 gpg_error_t
1638 gt_vfs_mount (gpgme_tool_t gt, const char *container_file,
1639               const char *mount_dir, int flags)
1640 {
1641   gpg_error_t err;
1642   gpg_error_t op_err;
1643   err = gpgme_op_vfs_mount (gt->ctx, container_file, mount_dir, flags, &op_err);
1644   return err ? err : op_err;
1645 }
1646
1647
1648 gpg_error_t
1649 gt_vfs_create (gpgme_tool_t gt, const char *container_file, int flags)
1650 {
1651   gpg_error_t err;
1652   gpg_error_t op_err;
1653   err = gpgme_op_vfs_create (gt->ctx, gt->recipients, container_file,
1654                              flags, &op_err);
1655   gt_recipients_clear (gt);
1656   return err ? err : op_err;
1657 }
1658
1659
1660 gpg_error_t
1661 gt_passwd (gpgme_tool_t gt, char *fpr)
1662 {
1663   gpg_error_t err;
1664   gpgme_key_t key;
1665
1666   err = gpgme_get_key (gt->ctx, fpr, &key, 0);
1667   if (err)
1668     return gpg_err_code (err) == GPG_ERR_EOF? gpg_error (GPG_ERR_NO_PUBKEY):err;
1669
1670   err = gpgme_op_passwd (gt->ctx, key, 0);
1671   gpgme_key_unref (key);
1672   return err;
1673 }
1674
1675
1676 gpg_error_t
1677 gt_identify (gpgme_tool_t gt, gpgme_data_t data)
1678 {
1679   const char *s = "?";
1680
1681   switch (gpgme_data_identify (data, 0))
1682     {
1683     case GPGME_DATA_TYPE_INVALID: return gpg_error (GPG_ERR_GENERAL);
1684     case GPGME_DATA_TYPE_UNKNOWN      : s = "unknown"; break;
1685     case GPGME_DATA_TYPE_PGP_SIGNED   : s = "PGP-signed"; break;
1686     case GPGME_DATA_TYPE_PGP_SIGNATURE: s = "PGP-signature"; break;
1687     case GPGME_DATA_TYPE_PGP_ENCRYPTED: s = "PGP-encrypted"; break;
1688     case GPGME_DATA_TYPE_PGP_OTHER    : s = "PGP"; break;
1689     case GPGME_DATA_TYPE_PGP_KEY      : s = "PGP-key"; break;
1690     case GPGME_DATA_TYPE_CMS_SIGNED   : s = "CMS-signed"; break;
1691     case GPGME_DATA_TYPE_CMS_ENCRYPTED: s = "CMS-encrypted"; break;
1692     case GPGME_DATA_TYPE_CMS_OTHER    : s = "CMS"; break;
1693     case GPGME_DATA_TYPE_X509_CERT    : s = "X.509"; break;
1694     case GPGME_DATA_TYPE_PKCS12       : s = "PKCS12"; break;
1695     }
1696   gt_write_status (gt, STATUS_IDENTIFY_RESULT, s, NULL);
1697   return 0;
1698 }
1699
1700
1701 gpg_error_t
1702 gt_spawn (gpgme_tool_t gt, const char *pgm,
1703           gpgme_data_t inp, gpgme_data_t outp)
1704 {
1705   gpg_error_t err;
1706
1707   err = gpgme_op_spawn (gt->ctx, pgm, NULL, inp, outp, outp, 0);
1708
1709   return err;
1710 }
1711
1712
1713 #define GT_RESULT_ENCRYPT 0x1
1714 #define GT_RESULT_DECRYPT 0x2
1715 #define GT_RESULT_SIGN 0x4
1716 #define GT_RESULT_VERIFY 0x8
1717 #define GT_RESULT_IMPORT 0x10
1718 #define GT_RESULT_GENKEY 0x20
1719 #define GT_RESULT_KEYLIST 0x40
1720 #define GT_RESULT_VFS_MOUNT 0x80
1721 #define GT_RESULT_ALL (~0U)
1722
1723 gpg_error_t
1724 gt_result (gpgme_tool_t gt, unsigned int flags)
1725 {
1726   int indent = 2;
1727
1728   gt_write_data (gt, xml_preamble1, strlen (xml_preamble1));
1729   gt_write_data (gt, NULL, 0);
1730   gt_write_data (gt, xml_preamble2, strlen (xml_preamble2));
1731   gt_write_data (gt, NULL, 0);
1732   if (flags & GT_RESULT_ENCRYPT)
1733     result_encrypt_to_xml (gt->ctx, indent,
1734                            (result_xml_write_cb_t) gt_write_data, gt);
1735   if (flags & GT_RESULT_DECRYPT)
1736     result_decrypt_to_xml (gt->ctx, indent,
1737                            (result_xml_write_cb_t) gt_write_data, gt);
1738   if (flags & GT_RESULT_SIGN)
1739     result_sign_to_xml (gt->ctx, indent,
1740                         (result_xml_write_cb_t) gt_write_data, gt);
1741   if (flags & GT_RESULT_VERIFY)
1742     result_verify_to_xml (gt->ctx, indent,
1743                           (result_xml_write_cb_t) gt_write_data, gt);
1744   if (flags & GT_RESULT_IMPORT)
1745     result_import_to_xml (gt->ctx, indent,
1746                           (result_xml_write_cb_t) gt_write_data, gt);
1747   if (flags & GT_RESULT_GENKEY)
1748     result_genkey_to_xml (gt->ctx, indent,
1749                           (result_xml_write_cb_t) gt_write_data, gt);
1750   if (flags & GT_RESULT_KEYLIST)
1751     result_keylist_to_xml (gt->ctx, indent,
1752                            (result_xml_write_cb_t) gt_write_data, gt);
1753   if (flags & GT_RESULT_VFS_MOUNT)
1754     result_vfs_mount_to_xml (gt->ctx, indent,
1755                              (result_xml_write_cb_t) gt_write_data, gt);
1756   gt_write_data (gt, xml_end, strlen (xml_end));
1757
1758   return 0;
1759 }
1760
1761 \f
1762 /* GPGME SERVER.  */
1763
1764 #include <assuan.h>
1765
1766 struct server
1767 {
1768   gpgme_tool_t gt;
1769   assuan_context_t assuan_ctx;
1770
1771   gpgme_data_encoding_t input_enc;
1772   gpgme_data_encoding_t output_enc;
1773   assuan_fd_t input_fd;
1774   char *input_filename;
1775   FILE *input_stream;
1776   assuan_fd_t output_fd;
1777   char *output_filename;
1778   FILE *output_stream;
1779   assuan_fd_t message_fd;
1780   char *message_filename;
1781   FILE *message_stream;
1782   gpgme_data_encoding_t message_enc;
1783 };
1784
1785
1786 gpg_error_t
1787 server_write_status (void *hook, const char *status, const char *msg)
1788 {
1789   struct server *server = hook;
1790   return assuan_write_status (server->assuan_ctx, status, msg);
1791 }
1792
1793
1794 gpg_error_t
1795 server_write_data (void *hook, const void *buf, size_t len)
1796 {
1797   struct server *server = hook;
1798   return assuan_send_data (server->assuan_ctx, buf, len);
1799 }
1800
1801
1802 static gpg_error_t
1803 server_passphrase_cb (void *opaque, const char *uid_hint, const char *info,
1804                       int was_bad, int fd)
1805 {
1806   struct server *server = opaque;
1807   gpg_error_t err;
1808   unsigned char *buf = NULL;
1809   size_t buflen = 0;
1810
1811   if (server && server->assuan_ctx)
1812     {
1813       if (uid_hint)
1814         assuan_write_status (server->assuan_ctx, "USERID_HINT", uid_hint);
1815       if (info)
1816         assuan_write_status (server->assuan_ctx, "NEED_PASSPHRASE", info);
1817
1818       err = assuan_inquire (server->assuan_ctx, "PASSPHRASE",
1819                             &buf, &buflen, 100);
1820     }
1821   else
1822     err = gpg_error (GPG_ERR_NO_PASSPHRASE);
1823
1824   if (!err)
1825     {
1826       /* We take care to always send a LF.  */
1827       if (gpgme_io_writen (fd, buf, buflen))
1828         err = gpg_error_from_syserror ();
1829       else if (!memchr (buf, '\n', buflen) && gpgme_io_writen (fd, "\n", 1))
1830         err = gpg_error_from_syserror ();
1831     }
1832   free (buf);
1833   return err;
1834 }
1835
1836
1837 /* Wrapper around assuan_command_parse_fd to also handle a
1838    "file=FILENAME" argument.  On success either a filename is returned
1839    at FILENAME or a file descriptor at RFD; the other one is set to
1840    NULL respective ASSUAN_INVALID_FD.  */
1841 static gpg_error_t
1842 server_parse_fd (assuan_context_t ctx, char *line, assuan_fd_t *rfd,
1843                  char **filename)
1844 {
1845   *rfd = ASSUAN_INVALID_FD;
1846   *filename = NULL;
1847
1848   if (! strncasecmp (line, "file=", 5))
1849     {
1850       char *term;
1851       *filename = strdup (line + 5);
1852       if (!*filename)
1853         return gpg_error_from_syserror();
1854       term = strchr (*filename, ' ');
1855       if (term)
1856         *term = '\0';
1857       return 0;
1858     }
1859   else
1860     return assuan_command_parse_fd (ctx, line, rfd);
1861 }
1862
1863
1864 static gpgme_data_encoding_t
1865 server_data_encoding (const char *line)
1866 {
1867   if (strstr (line, "--binary"))
1868     return GPGME_DATA_ENCODING_BINARY;
1869   if (strstr (line, "--base64"))
1870     return GPGME_DATA_ENCODING_BASE64;
1871   if (strstr (line, "--armor"))
1872     return GPGME_DATA_ENCODING_ARMOR;
1873   if (strstr (line, "--url"))
1874     return GPGME_DATA_ENCODING_URL;
1875   if (strstr (line, "--urlesc"))
1876     return GPGME_DATA_ENCODING_URLESC;
1877   if (strstr (line, "--url0"))
1878     return GPGME_DATA_ENCODING_URL0;
1879   if (strstr (line, "--mime"))
1880     return GPGME_DATA_ENCODING_MIME;
1881   return GPGME_DATA_ENCODING_NONE;
1882 }
1883
1884
1885 static gpgme_error_t
1886 server_data_obj (assuan_fd_t fd, char *fn, int out,
1887                  gpgme_data_encoding_t encoding,
1888                  gpgme_data_t *data, FILE **fs)
1889 {
1890   gpgme_error_t err;
1891
1892   *fs = NULL;
1893   if (fn)
1894     {
1895       *fs = fopen (fn, out ? "wb" : "rb");
1896       if (!*fs)
1897         return gpg_error_from_syserror ();
1898
1899       err = gpgme_data_new_from_stream (data, *fs);
1900     }
1901   else
1902     err = gpgme_data_new_from_fd (data, (int) fd);
1903
1904   if (err)
1905     return err;
1906   return gpgme_data_set_encoding (*data, encoding);
1907 }
1908
1909
1910 void
1911 server_reset_fds (struct server *server)
1912 {
1913   /* assuan closes the input and output FDs for us when doing a RESET,
1914      but we use this same function after commands, so repeat it
1915      here.  */
1916   if (server->input_fd != ASSUAN_INVALID_FD)
1917     {
1918 #if HAVE_W32_SYSTEM
1919       CloseHandle (server->input_fd);
1920 #else
1921       close (server->input_fd);
1922 #endif
1923       server->input_fd = ASSUAN_INVALID_FD;
1924     }
1925   if (server->output_fd != ASSUAN_INVALID_FD)
1926     {
1927 #if HAVE_W32_SYSTEM
1928       CloseHandle (server->output_fd);
1929 #else
1930       close (server->output_fd);
1931 #endif
1932       server->output_fd = ASSUAN_INVALID_FD;
1933     }
1934   if (server->message_fd != ASSUAN_INVALID_FD)
1935     {
1936       /* FIXME: Assuan should provide a close function.  */
1937 #if HAVE_W32_SYSTEM
1938       CloseHandle (server->message_fd);
1939 #else
1940       close (server->message_fd);
1941 #endif
1942       server->message_fd = ASSUAN_INVALID_FD;
1943     }
1944   if (server->input_filename)
1945     {
1946       free (server->input_filename);
1947       server->input_filename = NULL;
1948     }
1949   if (server->output_filename)
1950     {
1951       free (server->output_filename);
1952       server->output_filename = NULL;
1953     }
1954   if (server->message_filename)
1955     {
1956       free (server->message_filename);
1957       server->message_filename = NULL;
1958     }
1959   if (server->input_stream)
1960     {
1961       fclose (server->input_stream);
1962       server->input_stream = NULL;
1963     }
1964   if (server->output_stream)
1965     {
1966       fclose (server->output_stream);
1967       server->output_stream = NULL;
1968     }
1969   if (server->message_stream)
1970     {
1971       fclose (server->message_stream);
1972       server->message_stream = NULL;
1973     }
1974
1975   server->input_enc = GPGME_DATA_ENCODING_NONE;
1976   server->output_enc = GPGME_DATA_ENCODING_NONE;
1977   server->message_enc = GPGME_DATA_ENCODING_NONE;
1978 }
1979
1980
1981 static gpg_error_t
1982 reset_notify (assuan_context_t ctx, char *line)
1983 {
1984   struct server *server = assuan_get_pointer (ctx);
1985   server_reset_fds (server);
1986   gt_reset (server->gt);
1987   return 0;
1988 }
1989
1990
1991 static const char hlp_version[] =
1992   "VERSION [<string>]\n"
1993   "\n"
1994   "Call the function gpgme_check_version.";
1995 static gpg_error_t
1996 cmd_version (assuan_context_t ctx, char *line)
1997 {
1998   if (line && *line)
1999     {
2000       const char *version = gpgme_check_version (line);
2001       return version ? 0 : gpg_error (GPG_ERR_SELFTEST_FAILED);
2002     }
2003   else
2004     {
2005       const char *version = gpgme_check_version (NULL);
2006       return assuan_send_data (ctx, version, strlen (version));
2007     }
2008 }
2009
2010
2011 static const char hlp_engine[] =
2012   "ENGINE [<string>]\n"
2013   "\n"
2014   "Get information about a GPGME engine (a.k.a. protocol).";
2015 static gpg_error_t
2016 cmd_engine (assuan_context_t ctx, char *line)
2017 {
2018   struct server *server = assuan_get_pointer (ctx);
2019   return gt_get_engine_info (server->gt, gt_protocol_from_name (line));
2020 }
2021
2022
2023 static const char hlp_protocol[] =
2024   "PROTOCOL [<name>]\n"
2025   "\n"
2026   "With NAME, set the protocol.  Without, return the current\n"
2027   "protocol.";
2028 static gpg_error_t
2029 cmd_protocol (assuan_context_t ctx, char *line)
2030 {
2031   struct server *server = assuan_get_pointer (ctx);
2032   if (line && *line)
2033     return gt_set_protocol (server->gt, gt_protocol_from_name (line));
2034   else
2035     return gt_get_protocol (server->gt);
2036 }
2037
2038
2039 static const char hlp_sub_protocol[] =
2040   "SUB_PROTOCOL [<name>]\n"
2041   "\n"
2042   "With NAME, set the sub-protocol.  Without, return the\n"
2043   "current sub-protocol.";
2044 static gpg_error_t
2045 cmd_sub_protocol (assuan_context_t ctx, char *line)
2046 {
2047   struct server *server = assuan_get_pointer (ctx);
2048   if (line && *line)
2049     return gt_set_sub_protocol (server->gt, gt_protocol_from_name (line));
2050   else
2051     return gt_get_sub_protocol (server->gt);
2052 }
2053
2054
2055 static const char hlp_pinentry_mode[] =
2056   "PINENTRY_MODE <name>\n"
2057   "\n"
2058   "Set the pinentry mode to NAME.   Allowedvalues for NAME are:\n"
2059   "  default  - reset to the default of the engine,\n"
2060   "  ask      - force the use of the pinentry,\n"
2061   "  cancel   - emulate use of pinentry's cancel button,\n"
2062   "  error    - return a pinentry error,\n"
2063   "  loopback - redirect pinentry queries to the caller.\n"
2064   "Note that only recent versions of GPG support changing the pinentry mode.";
2065 static gpg_error_t
2066 cmd_pinentry_mode (assuan_context_t ctx, char *line)
2067 {
2068   struct server *server = assuan_get_pointer (ctx);
2069   gpgme_pinentry_mode_t mode;
2070
2071   if (!line || !*line || !strcmp (line, "default"))
2072     mode = GPGME_PINENTRY_MODE_DEFAULT;
2073   else if (!strcmp (line, "ask"))
2074     mode = GPGME_PINENTRY_MODE_ASK;
2075   else if (!strcmp (line, "cancel"))
2076     mode = GPGME_PINENTRY_MODE_CANCEL;
2077   else if (!strcmp (line, "error"))
2078     mode = GPGME_PINENTRY_MODE_ERROR;
2079   else if (!strcmp (line, "loopback"))
2080     mode = GPGME_PINENTRY_MODE_LOOPBACK;
2081   else
2082     return gpg_error (GPG_ERR_INV_VALUE);
2083
2084   return gt_set_pinentry_mode (server->gt, mode, server);
2085 }
2086
2087
2088 static const char hlp_armor[] =
2089   "ARMOR [true|false]\n"
2090   "\n"
2091   "With 'true' or 'false', turn output ASCII armoring on or\n"
2092   "off.  Without, return the current armoring status.";
2093 static gpg_error_t
2094 cmd_armor (assuan_context_t ctx, char *line)
2095 {
2096   struct server *server = assuan_get_pointer (ctx);
2097   if (line && *line)
2098     {
2099       int flag = 0;
2100
2101       if (! strcasecmp (line, "true") || ! strcasecmp (line, "yes")
2102           || line[0] == '1')
2103         flag = 1;
2104
2105       return gt_set_armor (server->gt, flag);
2106     }
2107   else
2108     return gt_get_armor (server->gt);
2109 }
2110
2111
2112 static const char hlp_textmode[] =
2113   "TEXTMODE [true|false]\n"
2114   "\n"
2115   "With 'true' or 'false', turn text mode on or off.\n"
2116   "Without, return the current text mode status.";
2117 static gpg_error_t
2118 cmd_textmode (assuan_context_t ctx, char *line)
2119 {
2120   struct server *server = assuan_get_pointer (ctx);
2121   if (line && *line)
2122     {
2123       int flag = 0;
2124
2125       if (! strcasecmp (line, "true") || ! strcasecmp (line, "yes")
2126           || line[0] == '1')
2127         flag = 1;
2128
2129       return gt_set_textmode (server->gt, flag);
2130     }
2131   else
2132     return gt_get_textmode (server->gt);
2133 }
2134
2135
2136 static const char hlp_include_certs[] =
2137   "INCLUDE_CERTS [default|<n>]\n"
2138   "\n"
2139   "With DEFAULT or N, set how many certificates should be\n"
2140   "included in the next S/MIME signed message.  See the\n"
2141   "GPGME documentation for details on the meaning of"
2142   "various N.  Without either, return the current setting.";
2143 static gpg_error_t
2144 cmd_include_certs (assuan_context_t ctx, char *line)
2145 {
2146   struct server *server = assuan_get_pointer (ctx);
2147
2148   if (line && *line)
2149     {
2150       int include_certs = 0;
2151
2152       if (! strcasecmp (line, "default"))
2153         include_certs = GPGME_INCLUDE_CERTS_DEFAULT;
2154       else
2155         include_certs = atoi (line);
2156
2157       return gt_set_include_certs (server->gt, include_certs);
2158     }
2159   else
2160     return gt_get_include_certs (server->gt);
2161 }
2162
2163
2164 static const char hlp_keylist_mode[] =
2165   "KEYLIST_MODE [local] [extern] [sigs] [sig_notations]\n"
2166   "  [ephemeral] [validate]\n"
2167   "\n"
2168   "Set the mode for the next KEYLIST command.";
2169 static gpg_error_t
2170 cmd_keylist_mode (assuan_context_t ctx, char *line)
2171 {
2172   struct server *server = assuan_get_pointer (ctx);
2173
2174   if (line && *line)
2175     {
2176       gpgme_keylist_mode_t mode = 0;
2177
2178       if (strstr (line, "local"))
2179         mode |= GPGME_KEYLIST_MODE_LOCAL;
2180       if (strstr (line, "extern"))
2181         mode |= GPGME_KEYLIST_MODE_EXTERN;
2182       if (strstr (line, "sigs"))
2183         mode |= GPGME_KEYLIST_MODE_SIGS;
2184       if (strstr (line, "sig_notations"))
2185         mode |= GPGME_KEYLIST_MODE_SIG_NOTATIONS;
2186       if (strstr (line, "with_secret"))
2187         mode |= GPGME_KEYLIST_MODE_WITH_SECRET;
2188       if (strstr (line, "ephemeral"))
2189         mode |= GPGME_KEYLIST_MODE_EPHEMERAL;
2190       if (strstr (line, "validate"))
2191         mode |= GPGME_KEYLIST_MODE_VALIDATE;
2192
2193       return gt_set_keylist_mode (server->gt, mode);
2194     }
2195   else
2196     return gt_get_keylist_mode (server->gt);
2197 }
2198
2199
2200 static const char hlp_input[] =
2201   "INPUT [<fd>|FILE=<path>]\n"
2202   "\n"
2203   "Set the input for the next command.  Use either the\n"
2204   "Assuan file descriptor FD or a filesystem PATH.";
2205 static gpg_error_t
2206 cmd_input (assuan_context_t ctx, char *line)
2207 {
2208   struct server *server = assuan_get_pointer (ctx);
2209   gpg_error_t err;
2210   assuan_fd_t sysfd;
2211   char *filename;
2212
2213   err = server_parse_fd (ctx, line, &sysfd, &filename);
2214   if (err)
2215     return err;
2216   server->input_fd = sysfd;
2217   server->input_filename = filename;
2218   server->input_enc = server_data_encoding (line);
2219   return 0;
2220 }
2221
2222
2223 static const char hlp_output[] =
2224   "OUTPUT [<fd>|FILE=<path>]\n"
2225   "\n"
2226   "Set the output for the next command.  Use either the\n"
2227   "Assuan file descriptor FD or a filesystem PATH.";
2228 static gpg_error_t
2229 cmd_output (assuan_context_t ctx, char *line)
2230 {
2231   struct server *server = assuan_get_pointer (ctx);
2232   gpg_error_t err;
2233   assuan_fd_t sysfd;
2234   char *filename;
2235
2236   err = server_parse_fd (ctx, line, &sysfd, &filename);
2237   if (err)
2238     return err;
2239   server->output_fd = sysfd;
2240   server->output_filename = filename;
2241   server->output_enc = server_data_encoding (line);
2242   return 0;
2243 }
2244
2245
2246 static const char hlp_message[] =
2247   "MESSAGE [<fd>|FILE=<path>]\n"
2248   "\n"
2249   "Set the plaintext message for the next VERIFY command\n"
2250   "with a detached signature.  Use either the Assuan file\n"
2251   "descriptor FD or a filesystem PATH.";
2252 static gpg_error_t
2253 cmd_message (assuan_context_t ctx, char *line)
2254 {
2255   struct server *server = assuan_get_pointer (ctx);
2256   gpg_error_t err;
2257   assuan_fd_t sysfd;
2258   char *filename;
2259
2260   err = server_parse_fd (ctx, line, &sysfd, &filename);
2261   if (err)
2262     return err;
2263   server->message_fd = sysfd;
2264   server->message_filename = filename;
2265   server->message_enc = server_data_encoding (line);
2266   return 0;
2267 }
2268
2269
2270 static const char hlp_recipient[] =
2271   "RECIPIENT <pattern>\n"
2272   "\n"
2273   "Add the key matching PATTERN to the list of recipients\n"
2274   "for the next encryption command.";
2275 static gpg_error_t
2276 cmd_recipient (assuan_context_t ctx, char *line)
2277 {
2278   struct server *server = assuan_get_pointer (ctx);
2279
2280   return gt_recipients_add (server->gt, line);
2281 }
2282
2283
2284 static const char hlp_signer[] =
2285   "SIGNER <fingerprint>\n"
2286   "\n"
2287   "Add the key with FINGERPRINT to the list of signers to\n"
2288   "be used for the next signing command.";
2289 static gpg_error_t
2290 cmd_signer (assuan_context_t ctx, char *line)
2291 {
2292   struct server *server = assuan_get_pointer (ctx);
2293
2294   return gt_signers_add (server->gt, line);
2295 }
2296
2297
2298 static const char hlp_signers_clear[] =
2299   "SIGNERS_CLEAR\n"
2300   "\n"
2301   "Clear the list of signers specified by previous SIGNER\n"
2302   "commands.";
2303 static gpg_error_t
2304 cmd_signers_clear (assuan_context_t ctx, char *line)
2305 {
2306   struct server *server = assuan_get_pointer (ctx);
2307
2308   return gt_signers_clear (server->gt);
2309 }
2310
2311
2312 static gpg_error_t
2313 _cmd_decrypt_verify (assuan_context_t ctx, char *line, int verify)
2314 {
2315   struct server *server = assuan_get_pointer (ctx);
2316   gpg_error_t err;
2317   assuan_fd_t inp_fd;
2318   char *inp_fn;
2319   assuan_fd_t out_fd;
2320   char *out_fn;
2321   gpgme_data_t inp_data;
2322   gpgme_data_t out_data;
2323
2324   inp_fd = server->input_fd;
2325   inp_fn = server->input_filename;
2326   if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
2327     return GPG_ERR_ASS_NO_INPUT;
2328   out_fd = server->output_fd;
2329   out_fn = server->output_filename;
2330   if (out_fd == ASSUAN_INVALID_FD && !out_fn)
2331     return GPG_ERR_ASS_NO_OUTPUT;
2332
2333   err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2334                          &server->input_stream);
2335   if (err)
2336     return err;
2337   err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2338                          &server->output_stream);
2339   if (err)
2340     {
2341       gpgme_data_release (inp_data);
2342       return err;
2343     }
2344
2345   err = gt_decrypt_verify (server->gt, inp_data, out_data, verify);
2346
2347   gpgme_data_release (inp_data);
2348   gpgme_data_release (out_data);
2349
2350   server_reset_fds (server);
2351
2352   return err;
2353 }
2354
2355
2356 static const char hlp_decrypt[] =
2357   "DECRYPT\n"
2358   "\n"
2359   "Decrypt the object set by the last INPUT command and\n"
2360   "write the decrypted message to the object set by the\n"
2361   "last OUTPUT command.";
2362 static gpg_error_t
2363 cmd_decrypt (assuan_context_t ctx, char *line)
2364 {
2365   return _cmd_decrypt_verify (ctx, line, 0);
2366 }
2367
2368
2369 static const char hlp_decrypt_verify[] =
2370   "DECRYPT_VERIFY\n"
2371   "\n"
2372   "Decrypt the object set by the last INPUT command and\n"
2373   "verify any embedded signatures.  Write the decrypted\n"
2374   "message to the object set by the last OUTPUT command.";
2375 static gpg_error_t
2376 cmd_decrypt_verify (assuan_context_t ctx, char *line)
2377 {
2378   return _cmd_decrypt_verify (ctx, line, 1);
2379 }
2380
2381
2382 static gpg_error_t
2383 _cmd_sign_encrypt (assuan_context_t ctx, char *line, int sign)
2384 {
2385   struct server *server = assuan_get_pointer (ctx);
2386   gpg_error_t err;
2387   assuan_fd_t inp_fd;
2388   char *inp_fn;
2389   assuan_fd_t out_fd;
2390   char *out_fn;
2391   gpgme_data_t inp_data = NULL;
2392   gpgme_data_t out_data = NULL;
2393   gpgme_encrypt_flags_t flags = 0;
2394
2395   if (strstr (line, "--always-trust"))
2396     flags |= GPGME_ENCRYPT_ALWAYS_TRUST;
2397   if (strstr (line, "--no-encrypt-to"))
2398     flags |= GPGME_ENCRYPT_NO_ENCRYPT_TO;
2399   if (strstr (line, "--prepare"))
2400     flags |= GPGME_ENCRYPT_PREPARE;
2401   if (strstr (line, "--expect-sign"))
2402     flags |= GPGME_ENCRYPT_EXPECT_SIGN;
2403   if (strstr (line, "--no-compress"))
2404     flags |= GPGME_ENCRYPT_NO_COMPRESS;
2405
2406   inp_fd = server->input_fd;
2407   inp_fn = server->input_filename;
2408   out_fd = server->output_fd;
2409   out_fn = server->output_filename;
2410   if (inp_fd != ASSUAN_INVALID_FD || inp_fn)
2411     {
2412       err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2413                              &server->input_stream);
2414       if (err)
2415         return err;
2416     }
2417   if (out_fd != ASSUAN_INVALID_FD || out_fn)
2418     {
2419       err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2420                              &server->output_stream);
2421       if (err)
2422         {
2423           gpgme_data_release (inp_data);
2424           return err;
2425         }
2426     }
2427
2428   err = gt_sign_encrypt (server->gt, flags, inp_data, out_data, sign);
2429
2430   gpgme_data_release (inp_data);
2431   gpgme_data_release (out_data);
2432
2433   server_reset_fds (server);
2434
2435   return err;
2436 }
2437
2438
2439 static const char hlp_encrypt[] =
2440   "ENCRYPT [--always-trust] [--no-encrypt-to]\n"
2441   "  [--no-compress] [--prepare] [--expect-sign]\n"
2442   "\n"
2443   "Encrypt the object set by the last INPUT command to\n"
2444   "the keys specified by previous RECIPIENT commands.  \n"
2445   "Write the signed and encrypted message to the object\n"
2446   "set by the last OUTPUT command.";
2447 static gpg_error_t
2448 cmd_encrypt (assuan_context_t ctx, char *line)
2449 {
2450   return _cmd_sign_encrypt (ctx, line, 0);
2451 }
2452
2453
2454 static const char hlp_sign_encrypt[] =
2455   "SIGN_ENCRYPT [--always-trust] [--no-encrypt-to]\n"
2456   "  [--no-compress] [--prepare] [--expect-sign]\n"
2457   "\n"
2458   "Sign the object set by the last INPUT command with the\n"
2459   "keys specified by previous SIGNER commands and encrypt\n"
2460   "it to the keys specified by previous RECIPIENT\n"
2461   "commands.  Write the signed and encrypted message to\n"
2462   "the object set by the last OUTPUT command.";
2463 static gpg_error_t
2464 cmd_sign_encrypt (assuan_context_t ctx, char *line)
2465 {
2466   return _cmd_sign_encrypt (ctx, line, 1);
2467 }
2468
2469
2470 static const char hlp_sign[] =
2471   "SIGN [--clear|--detach]\n"
2472   "\n"
2473   "Sign the object set by the last INPUT command with the\n"
2474   "keys specified by previous SIGNER commands.  Write the\n"
2475   "signed message to the object set by the last OUTPUT\n"
2476   "command.  With `--clear`, generate a clear text\n"
2477   "signature.  With `--detach`, generate a detached\n"
2478   "signature.";
2479 static gpg_error_t
2480 cmd_sign (assuan_context_t ctx, char *line)
2481 {
2482   struct server *server = assuan_get_pointer (ctx);
2483   gpg_error_t err;
2484   assuan_fd_t inp_fd;
2485   char *inp_fn;
2486   assuan_fd_t out_fd;
2487   char *out_fn;
2488   gpgme_data_t inp_data;
2489   gpgme_data_t out_data;
2490   gpgme_sig_mode_t mode = GPGME_SIG_MODE_NORMAL;
2491
2492   if (strstr (line, "--clear"))
2493     mode = GPGME_SIG_MODE_CLEAR;
2494   if (strstr (line, "--detach"))
2495     mode = GPGME_SIG_MODE_DETACH;
2496
2497   inp_fd = server->input_fd;
2498   inp_fn = server->input_filename;
2499   if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
2500     return GPG_ERR_ASS_NO_INPUT;
2501   out_fd = server->output_fd;
2502   out_fn = server->output_filename;
2503   if (out_fd == ASSUAN_INVALID_FD && !out_fn)
2504     return GPG_ERR_ASS_NO_OUTPUT;
2505
2506   err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2507                          &server->input_stream);
2508   if (err)
2509     return err;
2510   err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2511                          &server->output_stream);
2512   if (err)
2513     {
2514       gpgme_data_release (inp_data);
2515       return err;
2516     }
2517
2518   err = gt_sign (server->gt, inp_data, out_data, mode);
2519
2520   gpgme_data_release (inp_data);
2521   gpgme_data_release (out_data);
2522   server_reset_fds (server);
2523
2524   return err;
2525 }
2526
2527
2528 static const char hlp_verify[] =
2529   "VERIFY\n"
2530   "\n"
2531   "Verify signatures on the object set by the last INPUT\n"
2532   "and MESSAGE commands.  If the message was encrypted,\n"
2533   "write the plaintext to the object set by the last\n"
2534   "OUTPUT command.";
2535 static gpg_error_t
2536 cmd_verify (assuan_context_t ctx, char *line)
2537 {
2538   struct server *server = assuan_get_pointer (ctx);
2539   gpg_error_t err;
2540   assuan_fd_t inp_fd;
2541   assuan_fd_t msg_fd;
2542   assuan_fd_t out_fd;
2543   char *inp_fn;
2544   char *msg_fn;
2545   char *out_fn;
2546   gpgme_data_t inp_data;
2547   gpgme_data_t msg_data = NULL;
2548   gpgme_data_t out_data = NULL;
2549
2550   inp_fd = server->input_fd;
2551   inp_fn = server->input_filename;
2552   if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
2553     return GPG_ERR_ASS_NO_INPUT;
2554   msg_fd = server->message_fd;
2555   msg_fn = server->message_filename;
2556   out_fd = server->output_fd;
2557   out_fn = server->output_filename;
2558
2559   err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2560                          &server->input_stream);
2561   if (err)
2562     return err;
2563   if (msg_fd != ASSUAN_INVALID_FD || msg_fn)
2564     {
2565       err = server_data_obj (msg_fd, msg_fn, 0, server->message_enc, &msg_data,
2566                              &server->message_stream);
2567       if (err)
2568         {
2569           gpgme_data_release (inp_data);
2570           return err;
2571         }
2572     }
2573   if (out_fd != ASSUAN_INVALID_FD || out_fn)
2574     {
2575       err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2576                              &server->output_stream);
2577       if (err)
2578         {
2579           gpgme_data_release (inp_data);
2580           gpgme_data_release (msg_data);
2581           return err;
2582         }
2583     }
2584
2585   err = gt_verify (server->gt, inp_data, msg_data, out_data);
2586
2587   gpgme_data_release (inp_data);
2588   if (msg_data)
2589     gpgme_data_release (msg_data);
2590   if (out_data)
2591     gpgme_data_release (out_data);
2592
2593   server_reset_fds (server);
2594
2595   return err;
2596 }
2597
2598
2599 static const char hlp_import[] =
2600   "IMPORT [<pattern>]\n"
2601   "\n"
2602   "With PATTERN, import the keys described by PATTERN.\n"
2603   "Without, read a key (or keys) from the object set by the\n"
2604   "last INPUT command.";
2605 static gpg_error_t
2606 cmd_import (assuan_context_t ctx, char *line)
2607 {
2608   struct server *server = assuan_get_pointer (ctx);
2609
2610   if (line && *line)
2611     {
2612       char *fprs[2] = { line, NULL };
2613
2614       return gt_import_keys (server->gt, fprs);
2615     }
2616   else
2617     {
2618       gpg_error_t err;
2619       assuan_fd_t inp_fd;
2620       char *inp_fn;
2621       gpgme_data_t inp_data;
2622
2623       inp_fd = server->input_fd;
2624       inp_fn = server->input_filename;
2625       if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
2626         return GPG_ERR_ASS_NO_INPUT;
2627
2628       err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2629                              &server->input_stream);
2630       if (err)
2631         return err;
2632
2633       err = gt_import (server->gt, inp_data);
2634
2635       gpgme_data_release (inp_data);
2636       server_reset_fds (server);
2637
2638       return err;
2639     }
2640 }
2641
2642
2643 static const char hlp_export[] =
2644   "EXPORT [--extern] [--minimal] [--secret [--pkcs12] [--raw]] [<pattern>]\n"
2645   "\n"
2646   "Export the keys described by PATTERN.  Write the\n"
2647   "the output to the object set by the last OUTPUT command.";
2648 static gpg_error_t
2649 cmd_export (assuan_context_t ctx, char *line)
2650 {
2651   struct server *server = assuan_get_pointer (ctx);
2652   gpg_error_t err;
2653   assuan_fd_t out_fd;
2654   char *out_fn;
2655   gpgme_data_t out_data;
2656   gpgme_export_mode_t mode = 0;
2657   const char *pattern[2];
2658
2659   out_fd = server->output_fd;
2660   out_fn = server->output_filename;
2661   if (out_fd == ASSUAN_INVALID_FD && !out_fn)
2662     return GPG_ERR_ASS_NO_OUTPUT;
2663   err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2664                          &server->output_stream);
2665   if (err)
2666     return err;
2667
2668   if (has_option (line, "--extern"))
2669     mode |= GPGME_EXPORT_MODE_EXTERN;
2670   if (has_option (line, "--minimal"))
2671     mode |= GPGME_EXPORT_MODE_MINIMAL;
2672   if (has_option (line, "--secret"))
2673     mode |= GPGME_EXPORT_MODE_SECRET;
2674   if (has_option (line, "--raw"))
2675     mode |= GPGME_EXPORT_MODE_RAW;
2676   if (has_option (line, "--pkcs12"))
2677     mode |= GPGME_EXPORT_MODE_PKCS12;
2678
2679   line = skip_options (line);
2680
2681   pattern[0] = line;
2682   pattern[1] = NULL;
2683
2684   err = gt_export (server->gt, pattern, mode, out_data);
2685
2686   gpgme_data_release (out_data);
2687   server_reset_fds (server);
2688
2689   return err;
2690 }
2691
2692
2693 static gpg_error_t
2694 _cmd_genkey_write (gpgme_data_t data, const void *buf, size_t size)
2695 {
2696   while (size > 0)
2697     {
2698       gpgme_ssize_t writen = gpgme_data_write (data, buf, size);
2699       if (writen < 0 && errno != EAGAIN)
2700         return gpg_error_from_syserror ();
2701       else if (writen > 0)
2702         {
2703           buf = (void *) (((char *) buf) + writen);
2704           size -= writen;
2705         }
2706     }
2707   return 0;
2708 }
2709
2710
2711 static gpg_error_t
2712 cmd_genkey (assuan_context_t ctx, char *line)
2713 {
2714   struct server *server = assuan_get_pointer (ctx);
2715   gpg_error_t err;
2716   assuan_fd_t inp_fd;
2717   char *inp_fn;
2718   assuan_fd_t out_fd;
2719   char *out_fn;
2720   gpgme_data_t inp_data;
2721   gpgme_data_t out_data = NULL;
2722   gpgme_data_t parms_data = NULL;
2723   const char *parms;
2724
2725   inp_fd = server->input_fd;
2726   inp_fn = server->input_filename;
2727   if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
2728     return GPG_ERR_ASS_NO_INPUT;
2729   out_fd = server->output_fd;
2730   out_fn = server->output_filename;
2731
2732   err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2733                          &server->input_stream);
2734   if (err)
2735     return err;
2736   if (out_fd != ASSUAN_INVALID_FD || out_fn)
2737     {
2738       err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2739                              &server->output_stream);
2740       if (err)
2741         {
2742           gpgme_data_release (inp_data);
2743           return err;
2744         }
2745     }
2746
2747   /* Convert input data.  */
2748   err = gpgme_data_new (&parms_data);
2749   if (err)
2750     goto out;
2751   do
2752     {
2753       char buf[512];
2754       gpgme_ssize_t readn = gpgme_data_read (inp_data, buf, sizeof (buf));
2755       if (readn < 0)
2756         {
2757           err = gpg_error_from_syserror ();
2758           goto out;
2759         }
2760       else if (readn == 0)
2761         break;
2762
2763       err = _cmd_genkey_write (parms_data, buf, readn);
2764       if (err)
2765         goto out;
2766     }
2767   while (1);
2768   err = _cmd_genkey_write (parms_data, "", 1);
2769   if (err)
2770     goto out;
2771   parms = gpgme_data_release_and_get_mem (parms_data, NULL);
2772   parms_data = NULL;
2773   if (! parms)
2774     {
2775       err = gpg_error (GPG_ERR_GENERAL);
2776       goto out;
2777     }
2778
2779   err = gt_genkey (server->gt, parms, out_data, NULL);
2780
2781   server_reset_fds (server);
2782
2783  out:
2784   gpgme_data_release (inp_data);
2785   if (out_data)
2786     gpgme_data_release (out_data);
2787   if (parms_data)
2788     gpgme_data_release (parms_data);
2789
2790   return err;
2791 }
2792
2793
2794 static gpg_error_t
2795 cmd_delete (assuan_context_t ctx, char *line)
2796 {
2797   struct server *server = assuan_get_pointer (ctx);
2798   int allow_secret = 0;
2799   const char optstr[] = "--allow-secret";
2800
2801   if (!strncasecmp (line, optstr, strlen (optstr)))
2802     {
2803       allow_secret = 1;
2804       line += strlen (optstr);
2805       while (*line && !spacep (line))
2806         line++;
2807     }
2808   return gt_delete (server->gt, line, allow_secret);
2809 }
2810
2811
2812 static const char hlp_keylist[] =
2813   "KEYLIST [--secret-only] [<patterns>]\n"
2814   "\n"
2815   "List all certificates or only those specified by PATTERNS.  Each\n"
2816   "pattern shall be a percent-plus escaped certificate specification.";
2817 static gpg_error_t
2818 cmd_keylist (assuan_context_t ctx, char *line)
2819 {
2820 #define MAX_CMD_KEYLIST_PATTERN 20
2821   struct server *server = assuan_get_pointer (ctx);
2822   gpgme_tool_t gt = server->gt;
2823   struct result_xml_state state;
2824   gpg_error_t err;
2825   int secret_only = 0;
2826   int idx, indent=2;
2827   const char *pattern[MAX_CMD_KEYLIST_PATTERN+1];
2828   const char optstr[] = "--secret-only";
2829   char *p;
2830
2831   if (!strncasecmp (line, optstr, strlen (optstr)))
2832     {
2833       secret_only = 1;
2834       line += strlen (optstr);
2835       while (*line && !spacep (line))
2836         line++;
2837     }
2838
2839   idx = 0;
2840   for (p=line; *p; line = p)
2841     {
2842       while (*p && *p != ' ')
2843         p++;
2844       if (*p)
2845         *p++ = 0;
2846       if (*line)
2847         {
2848           if (idx+1 == DIM (pattern))
2849             return gpg_error (GPG_ERR_TOO_MANY);
2850           strcpy_escaped_plus (line, line);
2851           pattern[idx++] = line;
2852         }
2853     }
2854   pattern[idx] = NULL;
2855
2856   gt_write_data (gt, xml_preamble1, strlen (xml_preamble1));
2857   gt_write_data (gt, NULL, 0);
2858   gt_write_data (gt, xml_preamble2, strlen (xml_preamble2));
2859   gt_write_data (gt, NULL, 0);
2860   result_init (&state, indent, (result_xml_write_cb_t) gt_write_data, gt);
2861   result_xml_tag_start (&state, "keylist", NULL);
2862
2863   err = gt_keylist_start (server->gt, pattern, secret_only);
2864   while (! err)
2865     {
2866       gpgme_key_t key;
2867       gpgme_subkey_t subkey;
2868       gpgme_user_id_t uid;
2869
2870       err = gt_keylist_next (server->gt, &key);
2871       if (gpg_err_code (err) == GPG_ERR_EOF)
2872         {
2873           err = 0;
2874           break;
2875         }
2876       else if (! err)
2877         {
2878           result_xml_tag_start (&state, "key", NULL);
2879           result_add_value (&state, "revoked", key->revoked);
2880           result_add_value (&state, "expired", key->expired);
2881           result_add_value (&state, "disabled", key->disabled);
2882           result_add_value (&state, "invalid", key->invalid);
2883           result_add_value (&state, "can-encrypt", key->can_encrypt);
2884           result_add_value (&state, "can-sign", key->can_sign);
2885           result_add_value (&state, "can-certify", key->can_certify);
2886           result_add_value (&state, "can-authenticate", key->can_authenticate);
2887           result_add_value (&state, "is-qualified", key->is_qualified);
2888           result_add_value (&state, "secret", key->secret);
2889           result_add_protocol (&state, "protocol", key->protocol);
2890           result_xml_tag_start (&state, "issuer", NULL);
2891           result_add_string (&state, "serial", key->issuer_serial);
2892           result_add_string (&state, "name", key->issuer_name);
2893           result_xml_tag_end (&state);  /* issuer */
2894           result_add_string (&state, "chain-id", key->chain_id);
2895           result_add_validity (&state, "owner-trust", key->owner_trust);
2896           result_xml_tag_start (&state, "subkeys", NULL);
2897           subkey = key->subkeys;
2898           while (subkey) {
2899             result_xml_tag_start (&state, "subkey", NULL);
2900             /* FIXME: more data */
2901             result_add_keyid (&state, "keyid", subkey->keyid);
2902             if (subkey->fpr)
2903               result_add_fpr (&state, "fpr", subkey->fpr);
2904             result_add_value (&state, "secret", subkey->secret);
2905             result_add_value (&state, "is_cardkey", subkey->is_cardkey);
2906             if (subkey->card_number)
2907               result_add_string (&state, "card_number", subkey->card_number);
2908             if (subkey->curve)
2909               result_add_string (&state, "curve", subkey->curve);
2910             result_xml_tag_end (&state);  /* subkey */
2911             subkey = subkey->next;
2912           }
2913           result_xml_tag_end (&state);  /* subkeys */
2914           result_xml_tag_start (&state, "uids", NULL);
2915           uid = key->uids;
2916           while (uid) {
2917             result_xml_tag_start (&state, "uid", NULL);
2918             /* FIXME: more data */
2919             result_add_string (&state, "uid", uid->uid);
2920             result_add_string (&state, "name", uid->name);
2921             result_add_string (&state, "email", uid->email);
2922             result_add_string (&state, "comment", uid->comment);
2923             result_xml_tag_end (&state);  /* uid */
2924             uid = uid->next;
2925           }
2926           result_xml_tag_end (&state);  /* uids */
2927           result_xml_tag_end (&state);  /* key */
2928           gpgme_key_unref (key);
2929         }
2930     }
2931
2932   result_xml_tag_end (&state);  /* keylist */
2933   gt_write_data (gt, xml_end, strlen (xml_end));
2934
2935   server_reset_fds (server);
2936
2937   return err;
2938 }
2939
2940
2941 static const char hlp_getauditlog[] =
2942   "GETAUDITLOG [--html] [--with-help]\n"
2943   "\n"
2944   "Call the function gpgme_op_getauditlog with the given flags.  Write\n"
2945   "the output to the object set by the last OUTPUT command.";
2946 static gpg_error_t
2947 cmd_getauditlog (assuan_context_t ctx, char *line)
2948 {
2949   struct server *server = assuan_get_pointer (ctx);
2950   gpg_error_t err;
2951   assuan_fd_t out_fd;
2952   char *out_fn;
2953   gpgme_data_t out_data;
2954   unsigned int flags = 0;
2955
2956   out_fd = server->output_fd;
2957   out_fn = server->output_filename;
2958   if (out_fd == ASSUAN_INVALID_FD && !out_fn)
2959     return GPG_ERR_ASS_NO_OUTPUT;
2960   err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2961                          &server->output_stream);
2962   if (err)
2963     return err;
2964
2965   if (strstr (line, "--html"))
2966     flags |= GPGME_AUDITLOG_HTML;
2967   if (strstr (line, "--with-help"))
2968     flags |= GPGME_AUDITLOG_WITH_HELP;
2969
2970   err = gt_getauditlog (server->gt, out_data, flags);
2971
2972   gpgme_data_release (out_data);
2973   server_reset_fds (server);
2974
2975   return err;
2976 }
2977
2978
2979 static gpg_error_t
2980 cmd_vfs_mount (assuan_context_t ctx, char *line)
2981 {
2982   struct server *server = assuan_get_pointer (ctx);
2983   char *mount_dir;
2984   gpg_error_t err;
2985
2986   mount_dir = strchr (line, ' ');
2987   if (mount_dir)
2988     {
2989       *(mount_dir++) = '\0';
2990       while (*mount_dir == ' ')
2991         mount_dir++;
2992     }
2993
2994   err = gt_vfs_mount (server->gt, line, mount_dir, 0);
2995
2996   return err;
2997 }
2998
2999
3000 static gpg_error_t
3001 cmd_vfs_create (assuan_context_t ctx, char *line)
3002 {
3003   struct server *server = assuan_get_pointer (ctx);
3004   gpg_error_t err;
3005   char *end;
3006
3007   end = strchr (line, ' ');
3008   if (end)
3009     {
3010       *(end++) = '\0';
3011       while (*end == ' ')
3012         end++;
3013     }
3014
3015   err = gt_vfs_create (server->gt, line, 0);
3016
3017   return err;
3018 }
3019
3020
3021 static const char hlp_passwd[] =
3022   "PASSWD <user-id>\n"
3023   "\n"
3024   "Ask the backend to change the passphrase for the key\n"
3025   "specified by USER-ID.";
3026 static gpg_error_t
3027 cmd_passwd (assuan_context_t ctx, char *line)
3028 {
3029   struct server *server = assuan_get_pointer (ctx);
3030
3031   return gt_passwd (server->gt, line);
3032 }
3033
3034
3035
3036 static gpg_error_t
3037 cmd_result (assuan_context_t ctx, char *line)
3038 {
3039   struct server *server = assuan_get_pointer (ctx);
3040   return gt_result (server->gt, GT_RESULT_ALL);
3041 }
3042
3043
3044 /* STRERROR <err>  */
3045 static gpg_error_t
3046 cmd_strerror (assuan_context_t ctx, char *line)
3047 {
3048   gpg_error_t err;
3049   char buf[100];
3050
3051   err = atoi (line);
3052   snprintf (buf, sizeof (buf), "%s <%s>", gpgme_strerror (err),
3053             gpgme_strsource (err));
3054   return assuan_send_data (ctx, buf, strlen (buf));
3055 }
3056
3057
3058 static gpg_error_t
3059 cmd_pubkey_algo_name (assuan_context_t ctx, char *line)
3060 {
3061   gpgme_pubkey_algo_t algo;
3062   char buf[100];
3063
3064   algo = atoi (line);
3065   snprintf (buf, sizeof (buf), "%s", gpgme_pubkey_algo_name (algo));
3066   return assuan_send_data (ctx, buf, strlen (buf));
3067 }
3068
3069
3070 static gpg_error_t
3071 cmd_hash_algo_name (assuan_context_t ctx, char *line)
3072 {
3073   gpgme_hash_algo_t algo;
3074   char buf[100];
3075
3076   algo = atoi (line);
3077   snprintf (buf, sizeof (buf), "%s", gpgme_hash_algo_name (algo));
3078   return assuan_send_data (ctx, buf, strlen (buf));
3079 }
3080
3081
3082 static const char hlp_identify[] =
3083   "IDENTIY\n"
3084   "\n"
3085   "Identify the type of data set with the INPUT command.";
3086 static gpg_error_t
3087 cmd_identify (assuan_context_t ctx, char *line)
3088 {
3089   struct server *server = assuan_get_pointer (ctx);
3090   gpg_error_t err;
3091   assuan_fd_t inp_fd;
3092   char *inp_fn;
3093   gpgme_data_t inp_data;
3094
3095   inp_fd = server->input_fd;
3096   inp_fn = server->input_filename;
3097   if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
3098     return GPG_ERR_ASS_NO_INPUT;
3099
3100   err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
3101                          &server->input_stream);
3102   if (err)
3103     return err;
3104
3105   err = gt_identify (server->gt, inp_data);
3106
3107   gpgme_data_release (inp_data);
3108   server_reset_fds (server);
3109
3110   return err;
3111 }
3112
3113
3114 static const char hlp_spawn[] =
3115   "SPAWN PGM [args]\n"
3116   "\n"
3117   "Run program PGM with stdin connected to the INPUT source;\n"
3118   "stdout and stderr to the OUTPUT source.";
3119 static gpg_error_t
3120 cmd_spawn (assuan_context_t ctx, char *line)
3121 {
3122   struct server *server = assuan_get_pointer (ctx);
3123   gpg_error_t err;
3124   assuan_fd_t inp_fd;
3125   char *inp_fn;
3126   assuan_fd_t out_fd;
3127   char *out_fn;
3128   gpgme_data_t inp_data = NULL;
3129   gpgme_data_t out_data = NULL;
3130
3131   inp_fd = server->input_fd;
3132   inp_fn = server->input_filename;
3133   out_fd = server->output_fd;
3134   out_fn = server->output_filename;
3135   if (inp_fd != ASSUAN_INVALID_FD || inp_fn)
3136     {
3137       err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
3138                              &server->input_stream);
3139       if (err)
3140         return err;
3141     }
3142   if (out_fd != ASSUAN_INVALID_FD || out_fn)
3143     {
3144       err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
3145                              &server->output_stream);
3146       if (err)
3147         {
3148           gpgme_data_release (inp_data);
3149           return err;
3150         }
3151     }
3152
3153   err = gt_spawn (server->gt, line, inp_data, out_data);
3154
3155   gpgme_data_release (inp_data);
3156   gpgme_data_release (out_data);
3157
3158   server_reset_fds (server);
3159
3160   return err;
3161 }
3162
3163
3164 /* Tell the assuan library about our commands.  */
3165 static gpg_error_t
3166 register_commands (assuan_context_t ctx)
3167 {
3168   gpg_error_t err;
3169   static struct {
3170     const char *name;
3171     assuan_handler_t handler;
3172     const char * const help;
3173   } table[] = {
3174     /* RESET, BYE are implicit.  */
3175     { "VERSION", cmd_version, hlp_version },
3176     /* TODO: Set engine info.  */
3177     { "ENGINE", cmd_engine, hlp_engine },
3178     { "PROTOCOL", cmd_protocol, hlp_protocol },
3179     { "SUB_PROTOCOL", cmd_sub_protocol, hlp_sub_protocol },
3180     { "PINENTRY_MODE", cmd_pinentry_mode, hlp_pinentry_mode },
3181     { "ARMOR", cmd_armor, hlp_armor },
3182     { "TEXTMODE", cmd_textmode, hlp_textmode },
3183     { "INCLUDE_CERTS", cmd_include_certs, hlp_include_certs },
3184     { "KEYLIST_MODE", cmd_keylist_mode, hlp_keylist_mode },
3185     { "INPUT", cmd_input, hlp_input },
3186     { "OUTPUT", cmd_output, hlp_output },
3187     { "MESSAGE", cmd_message, hlp_message },
3188     { "RECIPIENT", cmd_recipient, hlp_recipient },
3189     { "SIGNER", cmd_signer, hlp_signer },
3190     { "SIGNERS_CLEAR", cmd_signers_clear, hlp_signers_clear },
3191      /* TODO: SIGNOTATION missing. */
3192      /* TODO: Could add wait interface if we allow more than one context */
3193      /* and add _START variants. */
3194      /* TODO: Could add data interfaces if we allow multiple data objects. */
3195     { "DECRYPT", cmd_decrypt, hlp_decrypt },
3196     { "DECRYPT_VERIFY", cmd_decrypt_verify, hlp_decrypt_verify },
3197     { "ENCRYPT", cmd_encrypt, hlp_encrypt },
3198     { "ENCRYPT_SIGN", cmd_sign_encrypt, hlp_sign_encrypt },
3199     { "SIGN_ENCRYPT", cmd_sign_encrypt, hlp_sign_encrypt },
3200     { "SIGN", cmd_sign, hlp_sign },
3201     { "VERIFY", cmd_verify, hlp_verify },
3202     { "IMPORT", cmd_import, hlp_import },
3203     { "EXPORT", cmd_export, hlp_export },
3204     { "GENKEY", cmd_genkey },
3205     { "DELETE", cmd_delete },
3206     /* TODO: EDIT, CARD_EDIT (with INQUIRE) */
3207     { "KEYLIST", cmd_keylist, hlp_keylist },
3208     { "LISTKEYS", cmd_keylist, hlp_keylist },
3209     /* TODO: TRUSTLIST, TRUSTLIST_EXT */
3210     { "GETAUDITLOG", cmd_getauditlog, hlp_getauditlog },
3211     /* TODO: ASSUAN */
3212     { "VFS_MOUNT", cmd_vfs_mount },
3213     { "MOUNT", cmd_vfs_mount },
3214     { "VFS_CREATE", cmd_vfs_create },
3215     { "CREATE", cmd_vfs_create },
3216     /* TODO: GPGCONF  */
3217     { "RESULT", cmd_result },
3218     { "STRERROR", cmd_strerror },
3219     { "PUBKEY_ALGO_NAME", cmd_pubkey_algo_name },
3220     { "HASH_ALGO_NAME", cmd_hash_algo_name },
3221     { "PASSWD", cmd_passwd, hlp_passwd },
3222     { "IDENTIFY", cmd_identify, hlp_identify },
3223     { "SPAWN", cmd_spawn, hlp_spawn },
3224     { NULL }
3225   };
3226   int idx;
3227
3228   for (idx = 0; table[idx].name; idx++)
3229     {
3230       err = assuan_register_command (ctx, table[idx].name, table[idx].handler,
3231                                      table[idx].help);
3232       if (err)
3233         return err;
3234     }
3235   return 0;
3236 }
3237
3238
3239 void
3240 gpgme_server (gpgme_tool_t gt)
3241 {
3242   gpg_error_t err;
3243   assuan_fd_t filedes[2];
3244   struct server server;
3245   static const char hello[] = ("GPGME-Tool " VERSION " ready");
3246
3247   memset (&server, 0, sizeof (server));
3248   server.input_fd = ASSUAN_INVALID_FD;
3249   server.output_fd = ASSUAN_INVALID_FD;
3250   server.message_fd = ASSUAN_INVALID_FD;
3251   server.input_enc = GPGME_DATA_ENCODING_NONE;
3252   server.output_enc = GPGME_DATA_ENCODING_NONE;
3253   server.message_enc = GPGME_DATA_ENCODING_NONE;
3254
3255   server.gt = gt;
3256   gt->write_status = server_write_status;
3257   gt->write_status_hook = &server;
3258   gt->write_data = server_write_data;
3259   gt->write_data_hook = &server;
3260
3261   /* We use a pipe based server so that we can work from scripts.
3262      assuan_init_pipe_server will automagically detect when we are
3263      called with a socketpair and ignore FIELDES in this case. */
3264 #ifdef HAVE_W32CE_SYSTEM
3265   filedes[0] = ASSUAN_STDIN;
3266   filedes[1] = ASSUAN_STDOUT;
3267 #else
3268   filedes[0] = assuan_fdopen (0);
3269   filedes[1] = assuan_fdopen (1);
3270 #endif
3271   err = assuan_new (&server.assuan_ctx);
3272   if (err)
3273     log_error (1, err, "can't create assuan context");
3274
3275   assuan_set_pointer (server.assuan_ctx, &server);
3276
3277   err = assuan_init_pipe_server (server.assuan_ctx, filedes);
3278   if (err)
3279     log_error (1, err, "can't initialize assuan server");
3280   err = register_commands (server.assuan_ctx);
3281   if (err)
3282     log_error (1, err, "can't register assuan commands");
3283   assuan_set_hello_line (server.assuan_ctx, hello);
3284
3285   assuan_register_reset_notify (server.assuan_ctx, reset_notify);
3286
3287 #define DBG_ASSUAN 0
3288   if (DBG_ASSUAN)
3289     assuan_set_log_stream (server.assuan_ctx, log_stream);
3290
3291   for (;;)
3292     {
3293       err = assuan_accept (server.assuan_ctx);
3294       if (err == -1)
3295         break;
3296       else if (err)
3297         {
3298           log_error (0, err, "assuan accept problem");
3299           break;
3300         }
3301
3302       err = assuan_process (server.assuan_ctx);
3303       if (err)
3304         log_error (0, err, "assuan processing failed");
3305     }
3306
3307   assuan_release (server.assuan_ctx);
3308 }
3309
3310
3311 \f
3312 static const char *
3313 my_strusage( int level )
3314 {
3315   const char *p;
3316
3317   switch (level)
3318     {
3319     case 11: p = "gpgme-tool"; break;
3320     case 13: p = PACKAGE_VERSION; break;
3321     case 14: p = "Copyright (C) 2015 g10 Code GmbH"; break;
3322     case 19: p = "Please report bugs to <" PACKAGE_BUGREPORT ">.\n"; break;
3323     case 1:
3324     case 40:
3325       p = "Usage: gpgme-tool [OPTIONS] [COMMANDS]";
3326       break;
3327     case 41:
3328       p = "GPGME Tool -- Assuan server exposing GPGME operations\n";
3329       break;
3330     case 42:
3331       p = "1"; /* Flag print 40 as part of 41. */
3332       break;
3333     default: p = NULL; break;
3334     }
3335   return p;
3336 }
3337
3338
3339 int
3340 main (int argc, char *argv[])
3341 {
3342   static ARGPARSE_OPTS opts[] = {
3343     ARGPARSE_c  ('s', "server",      "Server mode"),
3344     ARGPARSE_s_s(501, "gpg-binary",  "|FILE|Use FILE for the GPG backend"),
3345     ARGPARSE_c  (502, "lib-version", "Show library version"),
3346     ARGPARSE_end()
3347   };
3348   ARGPARSE_ARGS pargs = { &argc, &argv, 0 };
3349   enum { CMD_DEFAULT, CMD_SERVER, CMD_LIBVERSION } cmd = CMD_DEFAULT;
3350   const char *gpg_binary = NULL;
3351   struct gpgme_tool gt;
3352   gpg_error_t err;
3353   int needgt = 1;
3354
3355   set_strusage (my_strusage);
3356
3357 #ifdef HAVE_SETLOCALE
3358   setlocale (LC_ALL, "");
3359 #endif
3360   gpgme_check_version (NULL);
3361 #ifdef LC_CTYPE
3362   gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
3363 #endif
3364 #ifdef LC_MESSAGES
3365   gpgme_set_locale (NULL, LC_MESSAGES, setlocale (LC_MESSAGES, NULL));
3366 #endif
3367
3368   log_init ();
3369
3370   while (arg_parse  (&pargs, opts))
3371     {
3372       switch (pargs.r_opt)
3373         {
3374         case 's': cmd = CMD_SERVER; break;
3375         case 501: gpg_binary = pargs.r.ret_str; break;
3376         case 502: cmd = CMD_LIBVERSION; break;
3377         default:
3378           pargs.err = ARGPARSE_PRINT_WARNING;
3379           break;
3380         }
3381     }
3382
3383   if (cmd == CMD_LIBVERSION)
3384     needgt = 0;
3385
3386   if (needgt && gpg_binary)
3387     {
3388       if (access (gpg_binary, X_OK))
3389         err = gpg_error_from_syserror ();
3390       else
3391         err = gpgme_set_engine_info (GPGME_PROTOCOL_OpenPGP,
3392                                      gpg_binary, NULL);
3393       if (err)
3394         log_error (1, err, "error witching OpenPGP engine to '%s'",
3395                    gpg_binary);
3396     }
3397
3398   if (needgt)
3399     gt_init (&gt);
3400
3401   switch (cmd)
3402     {
3403     case CMD_DEFAULT:
3404     case CMD_SERVER:
3405       gpgme_server (&gt);
3406       break;
3407
3408     case CMD_LIBVERSION:
3409       printf ("Version from header: %s (0x%06x)\n",
3410               GPGME_VERSION, GPGME_VERSION_NUMBER);
3411       printf ("Version from binary: %s\n", gpgme_check_version (NULL));
3412       printf ("Copyright blurb ...:%s\n", gpgme_check_version ("\x01\x01"));
3413       break;
3414     }
3415
3416   if (needgt)
3417     gpgme_release (gt.ctx);
3418
3419 #ifdef HAVE_W32CE_SYSTEM
3420   /* Give the buggy ssh server time to flush the output buffers.  */
3421   Sleep (300);
3422 #endif
3423
3424   return 0;
3425 }