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