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