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