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