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