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