f02fffa728af262783fcc5aa315969e8233d4425
[platform/upstream/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_WITH_SECRET)
1865     modes[idx++] = "with_secret";
1866   if (mode & GPGME_KEYLIST_MODE_EPHEMERAL)
1867     modes[idx++] = "ephemeral";
1868   if (mode & GPGME_KEYLIST_MODE_VALIDATE)
1869     modes[idx++] = "validate";
1870   modes[idx++] = NULL;
1871
1872   gt_write_status (gt, STATUS_KEYLIST_MODE, modes[0], modes[1], modes[2],
1873                    modes[3], modes[4], modes[5], modes[6], NULL);
1874
1875   return 0;
1876 }
1877
1878
1879 gpg_error_t
1880 gt_set_include_certs (gpgme_tool_t gt, int include_certs)
1881 {
1882   gpgme_set_include_certs (gt->ctx, include_certs);
1883   return 0;
1884 }
1885
1886
1887 gpg_error_t
1888 gt_get_include_certs (gpgme_tool_t gt)
1889 {
1890   int include_certs = gpgme_get_include_certs (gt->ctx);
1891   char buf[100];
1892
1893   if (include_certs == GPGME_INCLUDE_CERTS_DEFAULT)
1894     strcpy (buf, "default");
1895   else
1896     snprintf (buf, sizeof (buf), "%i", include_certs);
1897
1898   gt_write_status (gt, STATUS_INCLUDE_CERTS, buf, NULL);
1899
1900   return 0;
1901 }
1902
1903
1904 gpg_error_t
1905 gt_decrypt_verify (gpgme_tool_t gt, gpgme_data_t cipher, gpgme_data_t plain,
1906                    int verify)
1907 {
1908   if (verify)
1909     return gpgme_op_decrypt_verify (gt->ctx, cipher, plain);
1910   else
1911     return gpgme_op_decrypt (gt->ctx, cipher, plain);
1912 }
1913
1914
1915 gpg_error_t
1916 gt_sign_encrypt (gpgme_tool_t gt, gpgme_encrypt_flags_t flags,
1917                  gpgme_data_t plain, gpgme_data_t cipher, int sign)
1918 {
1919   gpg_error_t err;
1920   gpgme_key_t *recp;
1921
1922   recp = gt->recipients_nr? gt->recipients : NULL;
1923
1924   if (sign)
1925     err = gpgme_op_encrypt_sign (gt->ctx, recp, flags, plain, cipher);
1926   else
1927     err = gpgme_op_encrypt (gt->ctx, recp, flags, plain, cipher);
1928
1929   gt_recipients_clear (gt);
1930
1931   return err;
1932 }
1933
1934
1935 gpg_error_t
1936 gt_sign (gpgme_tool_t gt, gpgme_data_t plain, gpgme_data_t sig,
1937          gpgme_sig_mode_t mode)
1938 {
1939   return gpgme_op_sign (gt->ctx, plain, sig, mode);
1940 }
1941
1942
1943 gpg_error_t
1944 gt_verify (gpgme_tool_t gt, gpgme_data_t sig, gpgme_data_t sig_text,
1945            gpgme_data_t plain)
1946 {
1947   return gpgme_op_verify (gt->ctx, sig, sig_text, plain);
1948 }
1949
1950
1951 gpg_error_t
1952 gt_import (gpgme_tool_t gt, gpgme_data_t data)
1953 {
1954   return gpgme_op_import (gt->ctx, data);
1955 }
1956
1957
1958 gpg_error_t
1959 gt_export (gpgme_tool_t gt, const char *pattern[], gpgme_export_mode_t mode,
1960            gpgme_data_t data)
1961 {
1962   return gpgme_op_export_ext (gt->ctx, pattern, mode, data);
1963 }
1964
1965
1966 gpg_error_t
1967 gt_genkey (gpgme_tool_t gt, const char *parms, gpgme_data_t public,
1968            gpgme_data_t secret)
1969 {
1970   return gpgme_op_genkey (gt->ctx, parms, public, secret);
1971 }
1972
1973
1974 gpg_error_t
1975 gt_import_keys (gpgme_tool_t gt, char *fpr[])
1976 {
1977   gpg_error_t err = 0;
1978   int cnt;
1979   int idx;
1980   gpgme_key_t *keys;
1981
1982   cnt = 0;
1983   while (fpr[cnt])
1984     cnt++;
1985
1986   if (! cnt)
1987     return gpg_error (GPG_ERR_INV_VALUE);
1988
1989   keys = malloc ((cnt + 1) * sizeof (gpgme_key_t));
1990   if (! keys)
1991     return gpg_error_from_syserror ();
1992
1993   for (idx = 0; idx < cnt; idx++)
1994     {
1995       err = gpgme_get_key (gt->ctx, fpr[idx], &keys[idx], 0);
1996       if (err)
1997         break;
1998     }
1999   if (! err)
2000     {
2001       keys[cnt] = NULL;
2002       err = gpgme_op_import_keys (gt->ctx, keys);
2003     }
2004
2005   /* Rollback.  */
2006   while (--idx >= 0)
2007     gpgme_key_unref (keys[idx]);
2008   free (keys);
2009
2010   return err;
2011 }
2012
2013
2014 gpg_error_t
2015 gt_delete (gpgme_tool_t gt, char *fpr, int allow_secret)
2016 {
2017   gpg_error_t err;
2018   gpgme_key_t key;
2019
2020   err = gpgme_get_key (gt->ctx, fpr, &key, 0);
2021   if (err)
2022     return err;
2023
2024   err = gpgme_op_delete (gt->ctx, key, allow_secret);
2025   gpgme_key_unref (key);
2026   return err;
2027 }
2028
2029
2030 gpg_error_t
2031 gt_keylist_start (gpgme_tool_t gt, const char *pattern[], int secret_only)
2032 {
2033   return gpgme_op_keylist_ext_start (gt->ctx, pattern, secret_only, 0);
2034 }
2035
2036
2037 gpg_error_t
2038 gt_keylist_next (gpgme_tool_t gt, gpgme_key_t *key)
2039 {
2040   return gpgme_op_keylist_next (gt->ctx, key);
2041 }
2042
2043
2044 gpg_error_t
2045 gt_getauditlog (gpgme_tool_t gt, gpgme_data_t output, unsigned int flags)
2046 {
2047   return gpgme_op_getauditlog (gt->ctx, output, flags);
2048 }
2049
2050
2051 gpg_error_t
2052 gt_vfs_mount (gpgme_tool_t gt, const char *container_file,
2053               const char *mount_dir, int flags)
2054 {
2055   gpg_error_t err;
2056   gpg_error_t op_err;
2057   err = gpgme_op_vfs_mount (gt->ctx, container_file, mount_dir, flags, &op_err);
2058   return err ? err : op_err;
2059 }
2060
2061
2062 gpg_error_t
2063 gt_vfs_create (gpgme_tool_t gt, const char *container_file, int flags)
2064 {
2065   gpg_error_t err;
2066   gpg_error_t op_err;
2067   err = gpgme_op_vfs_create (gt->ctx, gt->recipients, container_file,
2068                              flags, &op_err);
2069   gt_recipients_clear (gt);
2070   return err ? err : op_err;
2071 }
2072
2073
2074 gpg_error_t
2075 gt_passwd (gpgme_tool_t gt, char *fpr)
2076 {
2077   gpg_error_t err;
2078   gpgme_key_t key;
2079
2080   err = gpgme_get_key (gt->ctx, fpr, &key, 0);
2081   if (err)
2082     return gpg_err_code (err) == GPG_ERR_EOF? gpg_error (GPG_ERR_NO_PUBKEY):err;
2083
2084   err = gpgme_op_passwd (gt->ctx, key, 0);
2085   gpgme_key_unref (key);
2086   return err;
2087 }
2088
2089
2090 gpg_error_t
2091 gt_identify (gpgme_tool_t gt, gpgme_data_t data)
2092 {
2093   const char *s = "?";
2094
2095   switch (gpgme_data_identify (data, 0))
2096     {
2097     case GPGME_DATA_TYPE_INVALID: return gpg_error (GPG_ERR_GENERAL);
2098     case GPGME_DATA_TYPE_UNKNOWN      : s = "unknown"; break;
2099     case GPGME_DATA_TYPE_PGP_SIGNED   : s = "PGP-signed"; break;
2100     case GPGME_DATA_TYPE_PGP_OTHER    : s = "PGP"; break;
2101     case GPGME_DATA_TYPE_PGP_KEY      : s = "PGP-key"; break;
2102     case GPGME_DATA_TYPE_CMS_SIGNED   : s = "CMS-signed"; break;
2103     case GPGME_DATA_TYPE_CMS_ENCRYPTED: s = "CMS-encrypted"; break;
2104     case GPGME_DATA_TYPE_CMS_OTHER    : s = "CMS"; break;
2105     case GPGME_DATA_TYPE_X509_CERT    : s = "X.509"; break;
2106     case GPGME_DATA_TYPE_PKCS12       : s = "PKCS12"; break;
2107     }
2108   gt_write_status (gt, STATUS_IDENTIFY_RESULT, s, NULL);
2109   return 0;
2110 }
2111
2112
2113 gpg_error_t
2114 gt_spawn (gpgme_tool_t gt, const char *pgm,
2115           gpgme_data_t inp, gpgme_data_t outp)
2116 {
2117   gpg_error_t err;
2118
2119   err = gpgme_op_spawn (gt->ctx, pgm, NULL, inp, outp, outp, 0);
2120
2121   return err;
2122 }
2123
2124
2125 #define GT_RESULT_ENCRYPT 0x1
2126 #define GT_RESULT_DECRYPT 0x2
2127 #define GT_RESULT_SIGN 0x4
2128 #define GT_RESULT_VERIFY 0x8
2129 #define GT_RESULT_IMPORT 0x10
2130 #define GT_RESULT_GENKEY 0x20
2131 #define GT_RESULT_KEYLIST 0x40
2132 #define GT_RESULT_VFS_MOUNT 0x80
2133 #define GT_RESULT_ALL (~0U)
2134
2135 gpg_error_t
2136 gt_result (gpgme_tool_t gt, unsigned int flags)
2137 {
2138   int indent = 2;
2139
2140   gt_write_data (gt, xml_preamble1, sizeof (xml_preamble1));
2141   gt_write_data (gt, NULL, 0);
2142   gt_write_data (gt, xml_preamble2, sizeof (xml_preamble2));
2143   gt_write_data (gt, NULL, 0);
2144   if (flags & GT_RESULT_ENCRYPT)
2145     result_encrypt_to_xml (gt->ctx, indent,
2146                            (result_xml_write_cb_t) gt_write_data, gt);
2147   if (flags & GT_RESULT_DECRYPT)
2148     result_decrypt_to_xml (gt->ctx, indent,
2149                            (result_xml_write_cb_t) gt_write_data, gt);
2150   if (flags & GT_RESULT_SIGN)
2151     result_sign_to_xml (gt->ctx, indent,
2152                         (result_xml_write_cb_t) gt_write_data, gt);
2153   if (flags & GT_RESULT_VERIFY)
2154     result_verify_to_xml (gt->ctx, indent,
2155                           (result_xml_write_cb_t) gt_write_data, gt);
2156   if (flags & GT_RESULT_IMPORT)
2157     result_import_to_xml (gt->ctx, indent,
2158                           (result_xml_write_cb_t) gt_write_data, gt);
2159   if (flags & GT_RESULT_GENKEY)
2160     result_genkey_to_xml (gt->ctx, indent,
2161                           (result_xml_write_cb_t) gt_write_data, gt);
2162   if (flags & GT_RESULT_KEYLIST)
2163     result_keylist_to_xml (gt->ctx, indent,
2164                            (result_xml_write_cb_t) gt_write_data, gt);
2165   if (flags & GT_RESULT_VFS_MOUNT)
2166     result_vfs_mount_to_xml (gt->ctx, indent,
2167                              (result_xml_write_cb_t) gt_write_data, gt);
2168   gt_write_data (gt, xml_end, sizeof (xml_end));
2169
2170   return 0;
2171 }
2172
2173 \f
2174 /* GPGME SERVER.  */
2175
2176 #include <assuan.h>
2177
2178 struct server
2179 {
2180   gpgme_tool_t gt;
2181   assuan_context_t assuan_ctx;
2182
2183   gpgme_data_encoding_t input_enc;
2184   gpgme_data_encoding_t output_enc;
2185   assuan_fd_t input_fd;
2186   char *input_filename;
2187   FILE *input_stream;
2188   assuan_fd_t output_fd;
2189   char *output_filename;
2190   FILE *output_stream;
2191   assuan_fd_t message_fd;
2192   char *message_filename;
2193   FILE *message_stream;
2194   gpgme_data_encoding_t message_enc;
2195 };
2196
2197
2198 gpg_error_t
2199 server_write_status (void *hook, const char *status, const char *msg)
2200 {
2201   struct server *server = hook;
2202   return assuan_write_status (server->assuan_ctx, status, msg);
2203 }
2204
2205
2206 gpg_error_t
2207 server_write_data (void *hook, const void *buf, size_t len)
2208 {
2209   struct server *server = hook;
2210   return assuan_send_data (server->assuan_ctx, buf, len);
2211 }
2212
2213
2214 static gpg_error_t
2215 server_passphrase_cb (void *opaque, const char *uid_hint, const char *info,
2216                       int was_bad, int fd)
2217 {
2218   struct server *server = opaque;
2219   gpg_error_t err;
2220   unsigned char *buf = NULL;
2221   size_t buflen = 0;
2222
2223   if (server && server->assuan_ctx)
2224     {
2225       if (uid_hint)
2226         assuan_write_status (server->assuan_ctx, "USERID_HINT", uid_hint);
2227       if (info)
2228         assuan_write_status (server->assuan_ctx, "NEED_PASSPHRASE", info);
2229
2230       err = assuan_inquire (server->assuan_ctx, "PASSPHRASE",
2231                             &buf, &buflen, 100);
2232     }
2233   else
2234     err = gpg_error (GPG_ERR_NO_PASSPHRASE);
2235
2236   if (!err)
2237     {
2238       /* We take care to always send a LF.  */
2239       if (gpgme_io_writen (fd, buf, buflen))
2240         err = gpg_error_from_syserror ();
2241       else if (!memchr (buf, '\n', buflen) && gpgme_io_writen (fd, "\n", 1))
2242         err = gpg_error_from_syserror ();
2243     }
2244   free (buf);
2245   return err;
2246 }
2247
2248
2249 /* Wrapper around assuan_command_parse_fd to also handle a
2250    "file=FILENAME" argument.  On success either a filename is returned
2251    at FILENAME or a file descriptor at RFD; the other one is set to
2252    NULL respective ASSUAN_INVALID_FD.  */
2253 static gpg_error_t
2254 server_parse_fd (assuan_context_t ctx, char *line, assuan_fd_t *rfd,
2255                  char **filename)
2256 {
2257   *rfd = ASSUAN_INVALID_FD;
2258   *filename = NULL;
2259
2260   if (! strncasecmp (line, "file=", 5))
2261     {
2262       char *term;
2263       *filename = strdup (line + 5);
2264       if (!*filename)
2265         return gpg_error_from_syserror();
2266       term = strchr (*filename, ' ');
2267       if (term)
2268         *term = '\0';
2269       return 0;
2270     }
2271   else
2272     return assuan_command_parse_fd (ctx, line, rfd);
2273 }
2274
2275
2276 static gpgme_data_encoding_t
2277 server_data_encoding (const char *line)
2278 {
2279   if (strstr (line, "--binary"))
2280     return GPGME_DATA_ENCODING_BINARY;
2281   if (strstr (line, "--base64"))
2282     return GPGME_DATA_ENCODING_BASE64;
2283   if (strstr (line, "--armor"))
2284     return GPGME_DATA_ENCODING_ARMOR;
2285   if (strstr (line, "--url"))
2286     return GPGME_DATA_ENCODING_URL;
2287   if (strstr (line, "--urlesc"))
2288     return GPGME_DATA_ENCODING_URLESC;
2289   if (strstr (line, "--url0"))
2290     return GPGME_DATA_ENCODING_URL0;
2291   return GPGME_DATA_ENCODING_NONE;
2292 }
2293
2294
2295 static gpgme_error_t
2296 server_data_obj (assuan_fd_t fd, char *fn, int out,
2297                  gpgme_data_encoding_t encoding,
2298                  gpgme_data_t *data, FILE **fs)
2299 {
2300   gpgme_error_t err;
2301
2302   *fs = NULL;
2303   if (fn)
2304     {
2305       *fs = fopen (fn, out ? "wb" : "rb");
2306       if (!*fs)
2307         return gpg_error_from_syserror ();
2308
2309       err = gpgme_data_new_from_stream (data, *fs);
2310     }
2311   else
2312     err = gpgme_data_new_from_fd (data, (int) fd);
2313
2314   if (err)
2315     return err;
2316   return gpgme_data_set_encoding (*data, encoding);
2317 }
2318
2319
2320 void
2321 server_reset_fds (struct server *server)
2322 {
2323   /* assuan closes the input and output FDs for us when doing a RESET,
2324      but we use this same function after commands, so repeat it
2325      here.  */
2326   if (server->input_fd != ASSUAN_INVALID_FD)
2327     {
2328 #if HAVE_W32_SYSTEM
2329       CloseHandle (server->input_fd);
2330 #else
2331       close (server->input_fd);
2332 #endif
2333       server->input_fd = ASSUAN_INVALID_FD;
2334     }
2335   if (server->output_fd != ASSUAN_INVALID_FD)
2336     {
2337 #if HAVE_W32_SYSTEM
2338       CloseHandle (server->output_fd);
2339 #else
2340       close (server->output_fd);
2341 #endif
2342       server->output_fd = ASSUAN_INVALID_FD;
2343     }
2344   if (server->message_fd != ASSUAN_INVALID_FD)
2345     {
2346       /* FIXME: Assuan should provide a close function.  */
2347 #if HAVE_W32_SYSTEM
2348       CloseHandle (server->message_fd);
2349 #else
2350       close (server->message_fd);
2351 #endif
2352       server->message_fd = ASSUAN_INVALID_FD;
2353     }
2354   if (server->input_filename)
2355     {
2356       free (server->input_filename);
2357       server->input_filename = NULL;
2358     }
2359   if (server->output_filename)
2360     {
2361       free (server->output_filename);
2362       server->output_filename = NULL;
2363     }
2364   if (server->message_filename)
2365     {
2366       free (server->message_filename);
2367       server->message_filename = NULL;
2368     }
2369   if (server->input_stream)
2370     {
2371       fclose (server->input_stream);
2372       server->input_stream = NULL;
2373     }
2374   if (server->output_stream)
2375     {
2376       fclose (server->output_stream);
2377       server->output_stream = NULL;
2378     }
2379   if (server->message_stream)
2380     {
2381       fclose (server->message_stream);
2382       server->message_stream = NULL;
2383     }
2384
2385   server->input_enc = GPGME_DATA_ENCODING_NONE;
2386   server->output_enc = GPGME_DATA_ENCODING_NONE;
2387   server->message_enc = GPGME_DATA_ENCODING_NONE;
2388 }
2389
2390
2391 static gpg_error_t
2392 reset_notify (assuan_context_t ctx, char *line)
2393 {
2394   struct server *server = assuan_get_pointer (ctx);
2395   server_reset_fds (server);
2396   gt_reset (server->gt);
2397   return 0;
2398 }
2399
2400
2401 static const char hlp_version[] =
2402   "VERSION [<string>]\n"
2403   "\n"
2404   "Call the function gpgme_check_version.";
2405 static gpg_error_t
2406 cmd_version (assuan_context_t ctx, char *line)
2407 {
2408   if (line && *line)
2409     {
2410       const char *version = gpgme_check_version (line);
2411       return version ? 0 : gpg_error (GPG_ERR_SELFTEST_FAILED);
2412     }
2413   else
2414     {
2415       const char *version = gpgme_check_version (NULL);
2416       return assuan_send_data (ctx, version, strlen (version));
2417     }
2418 }
2419
2420
2421 static const char hlp_engine[] =
2422   "ENGINE [<string>]\n"
2423   "\n"
2424   "Get information about a GPGME engine (a.k.a. protocol).";
2425 static gpg_error_t
2426 cmd_engine (assuan_context_t ctx, char *line)
2427 {
2428   struct server *server = assuan_get_pointer (ctx);
2429   return gt_get_engine_info (server->gt, gt_protocol_from_name (line));
2430 }
2431
2432
2433 static const char hlp_protocol[] =
2434   "PROTOCOL [<name>]\n"
2435   "\n"
2436   "With NAME, set the protocol.  Without, return the current\n"
2437   "protocol.";
2438 static gpg_error_t
2439 cmd_protocol (assuan_context_t ctx, char *line)
2440 {
2441   struct server *server = assuan_get_pointer (ctx);
2442   if (line && *line)
2443     return gt_set_protocol (server->gt, gt_protocol_from_name (line));
2444   else
2445     return gt_get_protocol (server->gt);
2446 }
2447
2448
2449 static const char hlp_sub_protocol[] =
2450   "SUB_PROTOCOL [<name>]\n"
2451   "\n"
2452   "With NAME, set the sub-protocol.  Without, return the\n"
2453   "current sub-protocol.";
2454 static gpg_error_t
2455 cmd_sub_protocol (assuan_context_t ctx, char *line)
2456 {
2457   struct server *server = assuan_get_pointer (ctx);
2458   if (line && *line)
2459     return gt_set_sub_protocol (server->gt, gt_protocol_from_name (line));
2460   else
2461     return gt_get_sub_protocol (server->gt);
2462 }
2463
2464
2465 static const char hlp_pinentry_mode[] =
2466   "PINENTRY_MODE <name>\n"
2467   "\n"
2468   "Set the pinentry mode to NAME.   Allowedvalues for NAME are:\n"
2469   "  default  - reset to the default of the engine,\n"
2470   "  ask      - force the use of the pinentry,\n"
2471   "  cancel   - emulate use of pinentry's cancel button,\n"
2472   "  error    - return a pinentry error,\n"
2473   "  loopback - redirect pinentry queries to the caller.\n"
2474   "Note that only recent versions of GPG support changing the pinentry mode.";
2475 static gpg_error_t
2476 cmd_pinentry_mode (assuan_context_t ctx, char *line)
2477 {
2478   struct server *server = assuan_get_pointer (ctx);
2479   gpgme_pinentry_mode_t mode;
2480
2481   if (!line || !*line || !strcmp (line, "default"))
2482     mode = GPGME_PINENTRY_MODE_DEFAULT;
2483   else if (!strcmp (line, "ask"))
2484     mode = GPGME_PINENTRY_MODE_ASK;
2485   else if (!strcmp (line, "cancel"))
2486     mode = GPGME_PINENTRY_MODE_CANCEL;
2487   else if (!strcmp (line, "error"))
2488     mode = GPGME_PINENTRY_MODE_ERROR;
2489   else if (!strcmp (line, "loopback"))
2490     mode = GPGME_PINENTRY_MODE_LOOPBACK;
2491   else
2492     return gpg_error (GPG_ERR_INV_VALUE);
2493
2494   return gt_set_pinentry_mode (server->gt, mode, server);
2495 }
2496
2497
2498 static const char hlp_armor[] =
2499   "ARMOR [true|false]\n"
2500   "\n"
2501   "With 'true' or 'false', turn output ASCII armoring on or\n"
2502   "off.  Without, return the current armoring status.";
2503 static gpg_error_t
2504 cmd_armor (assuan_context_t ctx, char *line)
2505 {
2506   struct server *server = assuan_get_pointer (ctx);
2507   if (line && *line)
2508     {
2509       int flag = 0;
2510
2511       if (! strcasecmp (line, "true") || ! strcasecmp (line, "yes")
2512           || line[0] == '1')
2513         flag = 1;
2514
2515       return gt_set_armor (server->gt, flag);
2516     }
2517   else
2518     return gt_get_armor (server->gt);
2519 }
2520
2521
2522 static const char hlp_textmode[] =
2523   "TEXTMODE [true|false]\n"
2524   "\n"
2525   "With 'true' or 'false', turn text mode on or off.\n"
2526   "Without, return the current text mode status.";
2527 static gpg_error_t
2528 cmd_textmode (assuan_context_t ctx, char *line)
2529 {
2530   struct server *server = assuan_get_pointer (ctx);
2531   if (line && *line)
2532     {
2533       int flag = 0;
2534
2535       if (! strcasecmp (line, "true") || ! strcasecmp (line, "yes")
2536           || line[0] == '1')
2537         flag = 1;
2538
2539       return gt_set_textmode (server->gt, flag);
2540     }
2541   else
2542     return gt_get_textmode (server->gt);
2543 }
2544
2545
2546 static const char hlp_include_certs[] =
2547   "INCLUDE_CERTS [default|<n>]\n"
2548   "\n"
2549   "With DEFAULT or N, set how many certificates should be\n"
2550   "included in the next S/MIME signed message.  See the\n"
2551   "GPGME documentation for details on the meaning of"
2552   "various N.  Without either, return the current setting.";
2553 static gpg_error_t
2554 cmd_include_certs (assuan_context_t ctx, char *line)
2555 {
2556   struct server *server = assuan_get_pointer (ctx);
2557
2558   if (line && *line)
2559     {
2560       int include_certs = 0;
2561
2562       if (! strcasecmp (line, "default"))
2563         include_certs = GPGME_INCLUDE_CERTS_DEFAULT;
2564       else
2565         include_certs = atoi (line);
2566
2567       return gt_set_include_certs (server->gt, include_certs);
2568     }
2569   else
2570     return gt_get_include_certs (server->gt);
2571 }
2572
2573
2574 static const char hlp_keylist_mode[] =
2575   "KEYLIST_MODE [local] [extern] [sigs] [sig_notations]\n"
2576   "  [ephemeral] [validate]\n"
2577   "\n"
2578   "Set the mode for the next KEYLIST command.";
2579 static gpg_error_t
2580 cmd_keylist_mode (assuan_context_t ctx, char *line)
2581 {
2582   struct server *server = assuan_get_pointer (ctx);
2583
2584   if (line && *line)
2585     {
2586       gpgme_keylist_mode_t mode = 0;
2587
2588       if (strstr (line, "local"))
2589         mode |= GPGME_KEYLIST_MODE_LOCAL;
2590       if (strstr (line, "extern"))
2591         mode |= GPGME_KEYLIST_MODE_EXTERN;
2592       if (strstr (line, "sigs"))
2593         mode |= GPGME_KEYLIST_MODE_SIGS;
2594       if (strstr (line, "sig_notations"))
2595         mode |= GPGME_KEYLIST_MODE_SIG_NOTATIONS;
2596       if (strstr (line, "with_secret"))
2597         mode |= GPGME_KEYLIST_MODE_WITH_SECRET;
2598       if (strstr (line, "ephemeral"))
2599         mode |= GPGME_KEYLIST_MODE_EPHEMERAL;
2600       if (strstr (line, "validate"))
2601         mode |= GPGME_KEYLIST_MODE_VALIDATE;
2602
2603       return gt_set_keylist_mode (server->gt, mode);
2604     }
2605   else
2606     return gt_get_keylist_mode (server->gt);
2607 }
2608
2609
2610 static const char hlp_input[] =
2611   "INPUT [<fd>|FILE=<path>]\n"
2612   "\n"
2613   "Set the input for the next command.  Use either the\n"
2614   "Assuan file descriptor FD or a filesystem PATH.";
2615 static gpg_error_t
2616 cmd_input (assuan_context_t ctx, char *line)
2617 {
2618   struct server *server = assuan_get_pointer (ctx);
2619   gpg_error_t err;
2620   assuan_fd_t sysfd;
2621   char *filename;
2622
2623   err = server_parse_fd (ctx, line, &sysfd, &filename);
2624   if (err)
2625     return err;
2626   server->input_fd = sysfd;
2627   server->input_filename = filename;
2628   server->input_enc = server_data_encoding (line);
2629   return 0;
2630 }
2631
2632
2633 static const char hlp_output[] =
2634   "OUTPUT [<fd>|FILE=<path>]\n"
2635   "\n"
2636   "Set the output for the next command.  Use either the\n"
2637   "Assuan file descriptor FD or a filesystem PATH.";
2638 static gpg_error_t
2639 cmd_output (assuan_context_t ctx, char *line)
2640 {
2641   struct server *server = assuan_get_pointer (ctx);
2642   gpg_error_t err;
2643   assuan_fd_t sysfd;
2644   char *filename;
2645
2646   err = server_parse_fd (ctx, line, &sysfd, &filename);
2647   if (err)
2648     return err;
2649   server->output_fd = sysfd;
2650   server->output_filename = filename;
2651   server->output_enc = server_data_encoding (line);
2652   return 0;
2653 }
2654
2655
2656 static const char hlp_message[] =
2657   "MESSAGE [<fd>|FILE=<path>]\n"
2658   "\n"
2659   "Set the plaintext message for the next VERIFY command\n"
2660   "with a detached signature.  Use either the Assuan file\n"
2661   "descriptor FD or a filesystem PATH.";
2662 static gpg_error_t
2663 cmd_message (assuan_context_t ctx, char *line)
2664 {
2665   struct server *server = assuan_get_pointer (ctx);
2666   gpg_error_t err;
2667   assuan_fd_t sysfd;
2668   char *filename;
2669
2670   err = server_parse_fd (ctx, line, &sysfd, &filename);
2671   if (err)
2672     return err;
2673   server->message_fd = sysfd;
2674   server->message_filename = filename;
2675   server->message_enc = server_data_encoding (line);
2676   return 0;
2677 }
2678
2679
2680 static const char hlp_recipient[] =
2681   "RECIPIENT <pattern>\n"
2682   "\n"
2683   "Add the key matching PATTERN to the list of recipients\n"
2684   "for the next encryption command.";
2685 static gpg_error_t
2686 cmd_recipient (assuan_context_t ctx, char *line)
2687 {
2688   struct server *server = assuan_get_pointer (ctx);
2689
2690   return gt_recipients_add (server->gt, line);
2691 }
2692
2693
2694 static const char hlp_signer[] =
2695   "SIGNER <fingerprint>\n"
2696   "\n"
2697   "Add the key with FINGERPRINT to the list of signers to\n"
2698   "be used for the next signing command.";
2699 static gpg_error_t
2700 cmd_signer (assuan_context_t ctx, char *line)
2701 {
2702   struct server *server = assuan_get_pointer (ctx);
2703
2704   return gt_signers_add (server->gt, line);
2705 }
2706
2707
2708 static const char hlp_signers_clear[] =
2709   "SIGNERS_CLEAR\n"
2710   "\n"
2711   "Clear the list of signers specified by previous SIGNER\n"
2712   "commands.";
2713 static gpg_error_t
2714 cmd_signers_clear (assuan_context_t ctx, char *line)
2715 {
2716   struct server *server = assuan_get_pointer (ctx);
2717
2718   return gt_signers_clear (server->gt);
2719 }
2720
2721
2722 static gpg_error_t
2723 _cmd_decrypt_verify (assuan_context_t ctx, char *line, int verify)
2724 {
2725   struct server *server = assuan_get_pointer (ctx);
2726   gpg_error_t err;
2727   assuan_fd_t inp_fd;
2728   char *inp_fn;
2729   assuan_fd_t out_fd;
2730   char *out_fn;
2731   gpgme_data_t inp_data;
2732   gpgme_data_t out_data;
2733
2734   inp_fd = server->input_fd;
2735   inp_fn = server->input_filename;
2736   if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
2737     return GPG_ERR_ASS_NO_INPUT;
2738   out_fd = server->output_fd;
2739   out_fn = server->output_filename;
2740   if (out_fd == ASSUAN_INVALID_FD && !out_fn)
2741     return GPG_ERR_ASS_NO_OUTPUT;
2742
2743   err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2744                          &server->input_stream);
2745   if (err)
2746     return err;
2747   err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2748                          &server->output_stream);
2749   if (err)
2750     {
2751       gpgme_data_release (inp_data);
2752       return err;
2753     }
2754
2755   err = gt_decrypt_verify (server->gt, inp_data, out_data, verify);
2756
2757   gpgme_data_release (inp_data);
2758   gpgme_data_release (out_data);
2759
2760   server_reset_fds (server);
2761
2762   return err;
2763 }
2764
2765
2766 static const char hlp_decrypt[] =
2767   "DECRYPT\n"
2768   "\n"
2769   "Decrypt the object set by the last INPUT command and\n"
2770   "write the decrypted message to the object set by the\n"
2771   "last OUTPUT command.";
2772 static gpg_error_t
2773 cmd_decrypt (assuan_context_t ctx, char *line)
2774 {
2775   return _cmd_decrypt_verify (ctx, line, 0);
2776 }
2777
2778
2779 static const char hlp_decrypt_verify[] =
2780   "DECRYPT_VERIFY\n"
2781   "\n"
2782   "Decrypt the object set by the last INPUT command and\n"
2783   "verify any embedded signatures.  Write the decrypted\n"
2784   "message to the object set by the last OUTPUT command.";
2785 static gpg_error_t
2786 cmd_decrypt_verify (assuan_context_t ctx, char *line)
2787 {
2788   return _cmd_decrypt_verify (ctx, line, 1);
2789 }
2790
2791
2792 static gpg_error_t
2793 _cmd_sign_encrypt (assuan_context_t ctx, char *line, int sign)
2794 {
2795   struct server *server = assuan_get_pointer (ctx);
2796   gpg_error_t err;
2797   assuan_fd_t inp_fd;
2798   char *inp_fn;
2799   assuan_fd_t out_fd;
2800   char *out_fn;
2801   gpgme_data_t inp_data = NULL;
2802   gpgme_data_t out_data = NULL;
2803   gpgme_encrypt_flags_t flags = 0;
2804
2805   if (strstr (line, "--always-trust"))
2806     flags |= GPGME_ENCRYPT_ALWAYS_TRUST;
2807   if (strstr (line, "--no-encrypt-to"))
2808     flags |= GPGME_ENCRYPT_NO_ENCRYPT_TO;
2809   if (strstr (line, "--prepare"))
2810     flags |= GPGME_ENCRYPT_PREPARE;
2811   if (strstr (line, "--expect-sign"))
2812     flags |= GPGME_ENCRYPT_EXPECT_SIGN;
2813   if (strstr (line, "--no-compress"))
2814     flags |= GPGME_ENCRYPT_NO_COMPRESS;
2815
2816   inp_fd = server->input_fd;
2817   inp_fn = server->input_filename;
2818   out_fd = server->output_fd;
2819   out_fn = server->output_filename;
2820   if (inp_fd != ASSUAN_INVALID_FD || inp_fn)
2821     {
2822       err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2823                              &server->input_stream);
2824       if (err)
2825         return err;
2826     }
2827   if (out_fd != ASSUAN_INVALID_FD || out_fn)
2828     {
2829       err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2830                              &server->output_stream);
2831       if (err)
2832         {
2833           gpgme_data_release (inp_data);
2834           return err;
2835         }
2836     }
2837
2838   err = gt_sign_encrypt (server->gt, flags, inp_data, out_data, sign);
2839
2840   gpgme_data_release (inp_data);
2841   gpgme_data_release (out_data);
2842
2843   server_reset_fds (server);
2844
2845   return err;
2846 }
2847
2848
2849 static const char hlp_encrypt[] =
2850   "ENCRYPT [--always-trust] [--no-encrypt-to]\n"
2851   "  [--no-compress] [--prepare] [--expect-sign]\n"
2852   "\n"
2853   "Encrypt the object set by the last INPUT command to\n"
2854   "the keys specified by previous RECIPIENT commands.  \n"
2855   "Write the signed and encrypted message to the object\n"
2856   "set by the last OUTPUT command.";
2857 static gpg_error_t
2858 cmd_encrypt (assuan_context_t ctx, char *line)
2859 {
2860   return _cmd_sign_encrypt (ctx, line, 0);
2861 }
2862
2863
2864 static const char hlp_sign_encrypt[] =
2865   "SIGN_ENCRYPT [--always-trust] [--no-encrypt-to]\n"
2866   "  [--no-compress] [--prepare] [--expect-sign]\n"
2867   "\n"
2868   "Sign the object set by the last INPUT command with the\n"
2869   "keys specified by previous SIGNER commands and encrypt\n"
2870   "it to the keys specified by previous RECIPIENT\n"
2871   "commands.  Write the signed and encrypted message to\n"
2872   "the object set by the last OUTPUT command.";
2873 static gpg_error_t
2874 cmd_sign_encrypt (assuan_context_t ctx, char *line)
2875 {
2876   return _cmd_sign_encrypt (ctx, line, 1);
2877 }
2878
2879
2880 static const char hlp_sign[] =
2881   "SIGN [--clear|--detach]\n"
2882   "\n"
2883   "Sign the object set by the last INPUT command with the\n"
2884   "keys specified by previous SIGNER commands.  Write the\n"
2885   "signed message to the object set by the last OUTPUT\n"
2886   "command.  With `--clear`, generate a clear text\n"
2887   "signature.  With `--detach`, generate a detached\n"
2888   "signature.";
2889 static gpg_error_t
2890 cmd_sign (assuan_context_t ctx, char *line)
2891 {
2892   struct server *server = assuan_get_pointer (ctx);
2893   gpg_error_t err;
2894   assuan_fd_t inp_fd;
2895   char *inp_fn;
2896   assuan_fd_t out_fd;
2897   char *out_fn;
2898   gpgme_data_t inp_data;
2899   gpgme_data_t out_data;
2900   gpgme_sig_mode_t mode = GPGME_SIG_MODE_NORMAL;
2901
2902   if (strstr (line, "--clear"))
2903     mode = GPGME_SIG_MODE_CLEAR;
2904   if (strstr (line, "--detach"))
2905     mode = GPGME_SIG_MODE_DETACH;
2906
2907   inp_fd = server->input_fd;
2908   inp_fn = server->input_filename;
2909   if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
2910     return GPG_ERR_ASS_NO_INPUT;
2911   out_fd = server->output_fd;
2912   out_fn = server->output_filename;
2913   if (out_fd == ASSUAN_INVALID_FD && !out_fn)
2914     return GPG_ERR_ASS_NO_OUTPUT;
2915
2916   err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2917                          &server->input_stream);
2918   if (err)
2919     return err;
2920   err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2921                          &server->output_stream);
2922   if (err)
2923     {
2924       gpgme_data_release (inp_data);
2925       return err;
2926     }
2927
2928   err = gt_sign (server->gt, inp_data, out_data, mode);
2929
2930   gpgme_data_release (inp_data);
2931   gpgme_data_release (out_data);
2932   server_reset_fds (server);
2933
2934   return err;
2935 }
2936
2937
2938 static const char hlp_verify[] =
2939   "VERIFY\n"
2940   "\n"
2941   "Verify signatures on the object set by the last INPUT\n"
2942   "and MESSAGE commands.  If the message was encrypted,\n"
2943   "write the plaintext to the object set by the last\n"
2944   "OUTPUT command.";
2945 static gpg_error_t
2946 cmd_verify (assuan_context_t ctx, char *line)
2947 {
2948   struct server *server = assuan_get_pointer (ctx);
2949   gpg_error_t err;
2950   assuan_fd_t inp_fd;
2951   assuan_fd_t msg_fd;
2952   assuan_fd_t out_fd;
2953   char *inp_fn;
2954   char *msg_fn;
2955   char *out_fn;
2956   gpgme_data_t inp_data;
2957   gpgme_data_t msg_data = NULL;
2958   gpgme_data_t out_data = NULL;
2959
2960   inp_fd = server->input_fd;
2961   inp_fn = server->input_filename;
2962   if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
2963     return GPG_ERR_ASS_NO_INPUT;
2964   msg_fd = server->message_fd;
2965   msg_fn = server->message_filename;
2966   out_fd = server->output_fd;
2967   out_fn = server->output_filename;
2968
2969   err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2970                          &server->input_stream);
2971   if (err)
2972     return err;
2973   if (msg_fd != ASSUAN_INVALID_FD || msg_fn)
2974     {
2975       err = server_data_obj (msg_fd, msg_fn, 0, server->message_enc, &msg_data,
2976                              &server->message_stream);
2977       if (err)
2978         {
2979           gpgme_data_release (inp_data);
2980           return err;
2981         }
2982     }
2983   if (out_fd != ASSUAN_INVALID_FD || out_fn)
2984     {
2985       err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2986                              &server->output_stream);
2987       if (err)
2988         {
2989           gpgme_data_release (inp_data);
2990           gpgme_data_release (msg_data);
2991           return err;
2992         }
2993     }
2994
2995   err = gt_verify (server->gt, inp_data, msg_data, out_data);
2996
2997   gpgme_data_release (inp_data);
2998   if (msg_data)
2999     gpgme_data_release (msg_data);
3000   if (out_data)
3001     gpgme_data_release (out_data);
3002
3003   server_reset_fds (server);
3004
3005   return err;
3006 }
3007
3008
3009 static const char hlp_import[] =
3010   "IMPORT [<pattern>]\n"
3011   "\n"
3012   "With PATTERN, import the keys described by PATTERN.\n"
3013   "Without, read a key (or keys) from the object set by the\n"
3014   "last INPUT command.";
3015 static gpg_error_t
3016 cmd_import (assuan_context_t ctx, char *line)
3017 {
3018   struct server *server = assuan_get_pointer (ctx);
3019
3020   if (line && *line)
3021     {
3022       char *fprs[2] = { line, NULL };
3023
3024       return gt_import_keys (server->gt, fprs);
3025     }
3026   else
3027     {
3028       gpg_error_t err;
3029       assuan_fd_t inp_fd;
3030       char *inp_fn;
3031       gpgme_data_t inp_data;
3032
3033       inp_fd = server->input_fd;
3034       inp_fn = server->input_filename;
3035       if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
3036         return GPG_ERR_ASS_NO_INPUT;
3037
3038       err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
3039                              &server->input_stream);
3040       if (err)
3041         return err;
3042
3043       err = gt_import (server->gt, inp_data);
3044
3045       gpgme_data_release (inp_data);
3046       server_reset_fds (server);
3047
3048       return err;
3049     }
3050 }
3051
3052
3053 static const char hlp_export[] =
3054   "EXPORT [--extern] [--minimal] [<pattern>]\n"
3055   "\n"
3056   "Export the keys described by PATTERN.  Write the\n"
3057   "the output to the object set by the last OUTPUT command.";
3058 static gpg_error_t
3059 cmd_export (assuan_context_t ctx, char *line)
3060 {
3061   struct server *server = assuan_get_pointer (ctx);
3062   gpg_error_t err;
3063   assuan_fd_t out_fd;
3064   char *out_fn;
3065   gpgme_data_t out_data;
3066   gpgme_export_mode_t mode = 0;
3067   const char *pattern[2];
3068
3069   out_fd = server->output_fd;
3070   out_fn = server->output_filename;
3071   if (out_fd == ASSUAN_INVALID_FD && !out_fn)
3072     return GPG_ERR_ASS_NO_OUTPUT;
3073   err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
3074                          &server->output_stream);
3075   if (err)
3076     return err;
3077
3078   if (has_option (line, "--extern"))
3079     mode |= GPGME_EXPORT_MODE_EXTERN;
3080   if (has_option (line, "--minimal"))
3081     mode |= GPGME_EXPORT_MODE_MINIMAL;
3082
3083   line = skip_options (line);
3084
3085   pattern[0] = line;
3086   pattern[1] = NULL;
3087
3088   err = gt_export (server->gt, pattern, mode, out_data);
3089
3090   gpgme_data_release (out_data);
3091   server_reset_fds (server);
3092
3093   return err;
3094 }
3095
3096
3097 static gpg_error_t
3098 _cmd_genkey_write (gpgme_data_t data, const void *buf, size_t size)
3099 {
3100   while (size > 0)
3101     {
3102       gpgme_ssize_t writen = gpgme_data_write (data, buf, size);
3103       if (writen < 0 && errno != EAGAIN)
3104         return gpg_error_from_syserror ();
3105       else if (writen > 0)
3106         {
3107           buf = (void *) (((char *) buf) + writen);
3108           size -= writen;
3109         }
3110     }
3111   return 0;
3112 }
3113
3114
3115 static gpg_error_t
3116 cmd_genkey (assuan_context_t ctx, char *line)
3117 {
3118   struct server *server = assuan_get_pointer (ctx);
3119   gpg_error_t err;
3120   assuan_fd_t inp_fd;
3121   char *inp_fn;
3122   assuan_fd_t out_fd;
3123   char *out_fn;
3124   gpgme_data_t inp_data;
3125   gpgme_data_t out_data = NULL;
3126   gpgme_data_t parms_data = NULL;
3127   const char *parms;
3128
3129   inp_fd = server->input_fd;
3130   inp_fn = server->input_filename;
3131   if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
3132     return GPG_ERR_ASS_NO_INPUT;
3133   out_fd = server->output_fd;
3134   out_fn = server->output_filename;
3135
3136   err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
3137                          &server->input_stream);
3138   if (err)
3139     return err;
3140   if (out_fd != ASSUAN_INVALID_FD || out_fn)
3141     {
3142       err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
3143                              &server->output_stream);
3144       if (err)
3145         {
3146           gpgme_data_release (inp_data);
3147           return err;
3148         }
3149     }
3150
3151   /* Convert input data.  */
3152   err = gpgme_data_new (&parms_data);
3153   if (err)
3154     goto out;
3155   do
3156     {
3157       char buf[512];
3158       gpgme_ssize_t readn = gpgme_data_read (inp_data, buf, sizeof (buf));
3159       if (readn < 0)
3160         {
3161           err = gpg_error_from_syserror ();
3162           goto out;
3163         }
3164       else if (readn == 0)
3165         break;
3166
3167       err = _cmd_genkey_write (parms_data, buf, readn);
3168       if (err)
3169         goto out;
3170     }
3171   while (1);
3172   err = _cmd_genkey_write (parms_data, "", 1);
3173   if (err)
3174     goto out;
3175   parms = gpgme_data_release_and_get_mem (parms_data, NULL);
3176   parms_data = NULL;
3177   if (! parms)
3178     {
3179       err = gpg_error (GPG_ERR_GENERAL);
3180       goto out;
3181     }
3182
3183   err = gt_genkey (server->gt, parms, out_data, NULL);
3184
3185   server_reset_fds (server);
3186
3187  out:
3188   gpgme_data_release (inp_data);
3189   if (out_data)
3190     gpgme_data_release (out_data);
3191   if (parms_data)
3192     gpgme_data_release (parms_data);
3193
3194   return err;
3195 }
3196
3197
3198 static gpg_error_t
3199 cmd_delete (assuan_context_t ctx, char *line)
3200 {
3201   struct server *server = assuan_get_pointer (ctx);
3202   int allow_secret = 0;
3203   const char optstr[] = "--allow-secret";
3204
3205   if (!strncasecmp (line, optstr, strlen (optstr)))
3206     {
3207       allow_secret = 1;
3208       line += strlen (optstr);
3209       while (*line && !spacep (line))
3210         line++;
3211     }
3212   return gt_delete (server->gt, line, allow_secret);
3213 }
3214
3215
3216 static const char hlp_keylist[] =
3217   "KEYLIST [--secret-only] [<patterns>]\n"
3218   "\n"
3219   "List all certificates or only those specified by PATTERNS.  Each\n"
3220   "pattern shall be a percent-plus escaped certificate specification.";
3221 static gpg_error_t
3222 cmd_keylist (assuan_context_t ctx, char *line)
3223 {
3224 #define MAX_CMD_KEYLIST_PATTERN 20
3225   struct server *server = assuan_get_pointer (ctx);
3226   gpgme_tool_t gt = server->gt;
3227   struct result_xml_state state;
3228   gpg_error_t err;
3229   int secret_only = 0;
3230   int idx, indent=2;
3231   const char *pattern[MAX_CMD_KEYLIST_PATTERN+1];
3232   const char optstr[] = "--secret-only";
3233   char *p;
3234
3235   if (!strncasecmp (line, optstr, strlen (optstr)))
3236     {
3237       secret_only = 1;
3238       line += strlen (optstr);
3239       while (*line && !spacep (line))
3240         line++;
3241     }
3242
3243   idx = 0;
3244   for (p=line; *p; line = p)
3245     {
3246       while (*p && *p != ' ')
3247         p++;
3248       if (*p)
3249         *p++ = 0;
3250       if (*line)
3251         {
3252           if (idx+1 == DIM (pattern))
3253             return gpg_error (GPG_ERR_TOO_MANY);
3254           strcpy_escaped_plus (line, line);
3255           pattern[idx++] = line;
3256         }
3257     }
3258   pattern[idx] = NULL;
3259
3260   gt_write_data (gt, xml_preamble1, sizeof (xml_preamble1));
3261   gt_write_data (gt, NULL, 0);
3262   gt_write_data (gt, xml_preamble2, sizeof (xml_preamble2));
3263   gt_write_data (gt, NULL, 0);
3264   result_init (&state, indent, (result_xml_write_cb_t) gt_write_data, gt);
3265   result_xml_tag_start (&state, "keylist", NULL);
3266
3267   err = gt_keylist_start (server->gt, pattern, secret_only);
3268   while (! err)
3269     {
3270       gpgme_key_t key;
3271       gpgme_subkey_t subkey;
3272       gpgme_user_id_t uid;
3273
3274       err = gt_keylist_next (server->gt, &key);
3275       if (gpg_err_code (err) == GPG_ERR_EOF)
3276         {
3277           err = 0;
3278           break;
3279         }
3280       else if (! err)
3281         {
3282           result_xml_tag_start (&state, "key", NULL);
3283           result_add_value (&state, "revoked", key->revoked);
3284           result_add_value (&state, "expired", key->expired);
3285           result_add_value (&state, "disabled", key->disabled);
3286           result_add_value (&state, "invalid", key->invalid);
3287           result_add_value (&state, "can-encrypt", key->can_encrypt);
3288           result_add_value (&state, "can-sign", key->can_sign);
3289           result_add_value (&state, "can-certify", key->can_certify);
3290           result_add_value (&state, "can-authenticate", key->can_authenticate);
3291           result_add_value (&state, "is-qualified", key->is_qualified);
3292           result_add_value (&state, "secret", key->secret);
3293           result_add_protocol (&state, "protocol", key->protocol);
3294           result_xml_tag_start (&state, "issuer", NULL);
3295           result_add_string (&state, "serial", key->issuer_serial);
3296           result_add_string (&state, "name", key->issuer_name);
3297           result_xml_tag_end (&state);  /* issuer */
3298           result_add_string (&state, "chain-id", key->chain_id);
3299           result_add_validity (&state, "owner-trust", key->owner_trust);
3300           result_xml_tag_start (&state, "subkeys", NULL);
3301           subkey = key->subkeys;
3302           while (subkey) {
3303             result_xml_tag_start (&state, "subkey", NULL);
3304             /* FIXME: more data */
3305             result_add_fpr (&state, "fpr", subkey->fpr);
3306             result_add_value (&state, "secret", subkey->secret);
3307             result_add_value (&state, "is_cardkey", subkey->is_cardkey);
3308             if (subkey->card_number)
3309               result_add_string (&state, "card_number", subkey->card_number);
3310             if (subkey->curve)
3311               result_add_string (&state, "curve", subkey->curve);
3312             result_xml_tag_end (&state);  /* subkey */
3313             subkey = subkey->next;
3314           }
3315           result_xml_tag_end (&state);  /* subkeys */
3316           result_xml_tag_start (&state, "uids", NULL);
3317           uid = key->uids;
3318           while (uid) {
3319             result_xml_tag_start (&state, "uid", NULL);
3320             /* FIXME: more data */
3321             result_add_string (&state, "uid", uid->uid);
3322             result_add_string (&state, "name", uid->name);
3323             result_add_string (&state, "email", uid->email);
3324             result_add_string (&state, "comment", uid->comment);
3325             result_xml_tag_end (&state);  /* uid */
3326             uid = uid->next;
3327           }
3328           result_xml_tag_end (&state);  /* uids */
3329           result_xml_tag_end (&state);  /* key */
3330           gpgme_key_unref (key);
3331         }
3332     }
3333
3334   result_xml_tag_end (&state);  /* keylist */
3335   gt_write_data (gt, xml_end, sizeof (xml_end));
3336
3337   server_reset_fds (server);
3338
3339   return err;
3340 }
3341
3342
3343 static const char hlp_getauditlog[] =
3344   "GETAUDITLOG [--html] [--with-help]\n"
3345   "\n"
3346   "Call the function gpgme_op_getauditlog with the given flags.  Write\n"
3347   "the output to the object set by the last OUTPUT command.";
3348 static gpg_error_t
3349 cmd_getauditlog (assuan_context_t ctx, char *line)
3350 {
3351   struct server *server = assuan_get_pointer (ctx);
3352   gpg_error_t err;
3353   assuan_fd_t out_fd;
3354   char *out_fn;
3355   gpgme_data_t out_data;
3356   unsigned int flags = 0;
3357
3358   out_fd = server->output_fd;
3359   out_fn = server->output_filename;
3360   if (out_fd == ASSUAN_INVALID_FD && !out_fn)
3361     return GPG_ERR_ASS_NO_OUTPUT;
3362   err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
3363                          &server->output_stream);
3364   if (err)
3365     return err;
3366
3367   if (strstr (line, "--html"))
3368     flags |= GPGME_AUDITLOG_HTML;
3369   if (strstr (line, "--with-help"))
3370     flags |= GPGME_AUDITLOG_WITH_HELP;
3371
3372   err = gt_getauditlog (server->gt, out_data, flags);
3373
3374   gpgme_data_release (out_data);
3375   server_reset_fds (server);
3376
3377   return err;
3378 }
3379
3380
3381 static gpg_error_t
3382 cmd_vfs_mount (assuan_context_t ctx, char *line)
3383 {
3384   struct server *server = assuan_get_pointer (ctx);
3385   char *mount_dir;
3386   gpg_error_t err;
3387
3388   mount_dir = strchr (line, ' ');
3389   if (mount_dir)
3390     {
3391       *(mount_dir++) = '\0';
3392       while (*mount_dir == ' ')
3393         mount_dir++;
3394     }
3395
3396   err = gt_vfs_mount (server->gt, line, mount_dir, 0);
3397
3398   return err;
3399 }
3400
3401
3402 static gpg_error_t
3403 cmd_vfs_create (assuan_context_t ctx, char *line)
3404 {
3405   struct server *server = assuan_get_pointer (ctx);
3406   gpg_error_t err;
3407   char *end;
3408
3409   end = strchr (line, ' ');
3410   if (end)
3411     {
3412       *(end++) = '\0';
3413       while (*end == ' ')
3414         end++;
3415     }
3416
3417   err = gt_vfs_create (server->gt, line, 0);
3418
3419   return err;
3420 }
3421
3422
3423 static const char hlp_passwd[] =
3424   "PASSWD <user-id>\n"
3425   "\n"
3426   "Ask the backend to change the passphrase for the key\n"
3427   "specified by USER-ID.";
3428 static gpg_error_t
3429 cmd_passwd (assuan_context_t ctx, char *line)
3430 {
3431   struct server *server = assuan_get_pointer (ctx);
3432
3433   return gt_passwd (server->gt, line);
3434 }
3435
3436
3437
3438 static gpg_error_t
3439 cmd_result (assuan_context_t ctx, char *line)
3440 {
3441   struct server *server = assuan_get_pointer (ctx);
3442   return gt_result (server->gt, GT_RESULT_ALL);
3443 }
3444
3445
3446 /* STRERROR <err>  */
3447 static gpg_error_t
3448 cmd_strerror (assuan_context_t ctx, char *line)
3449 {
3450   gpg_error_t err;
3451   char buf[100];
3452
3453   err = atoi (line);
3454   snprintf (buf, sizeof (buf), "%s <%s>", gpgme_strerror (err),
3455             gpgme_strsource (err));
3456   return assuan_send_data (ctx, buf, strlen (buf));
3457 }
3458
3459
3460 static gpg_error_t
3461 cmd_pubkey_algo_name (assuan_context_t ctx, char *line)
3462 {
3463   gpgme_pubkey_algo_t algo;
3464   char buf[100];
3465
3466   algo = atoi (line);
3467   snprintf (buf, sizeof (buf), "%s", gpgme_pubkey_algo_name (algo));
3468   return assuan_send_data (ctx, buf, strlen (buf));
3469 }
3470
3471
3472 static gpg_error_t
3473 cmd_hash_algo_name (assuan_context_t ctx, char *line)
3474 {
3475   gpgme_hash_algo_t algo;
3476   char buf[100];
3477
3478   algo = atoi (line);
3479   snprintf (buf, sizeof (buf), "%s", gpgme_hash_algo_name (algo));
3480   return assuan_send_data (ctx, buf, strlen (buf));
3481 }
3482
3483
3484 static const char hlp_identify[] =
3485   "IDENTIY\n"
3486   "\n"
3487   "Identify the type of data set with the INPUT command.";
3488 static gpg_error_t
3489 cmd_identify (assuan_context_t ctx, char *line)
3490 {
3491   struct server *server = assuan_get_pointer (ctx);
3492   gpg_error_t err;
3493   assuan_fd_t inp_fd;
3494   char *inp_fn;
3495   gpgme_data_t inp_data;
3496
3497   inp_fd = server->input_fd;
3498   inp_fn = server->input_filename;
3499   if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
3500     return GPG_ERR_ASS_NO_INPUT;
3501
3502   err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
3503                          &server->input_stream);
3504   if (err)
3505     return err;
3506
3507   err = gt_identify (server->gt, inp_data);
3508
3509   gpgme_data_release (inp_data);
3510   server_reset_fds (server);
3511
3512   return err;
3513 }
3514
3515
3516 static const char hlp_spawn[] =
3517   "SPAWN PGM [args]\n"
3518   "\n"
3519   "Run program PGM with stdin connected to the INPUT source;\n"
3520   "stdout and stderr to the OUTPUT source.";
3521 static gpg_error_t
3522 cmd_spawn (assuan_context_t ctx, char *line)
3523 {
3524   struct server *server = assuan_get_pointer (ctx);
3525   gpg_error_t err;
3526   assuan_fd_t inp_fd;
3527   char *inp_fn;
3528   assuan_fd_t out_fd;
3529   char *out_fn;
3530   gpgme_data_t inp_data = NULL;
3531   gpgme_data_t out_data = NULL;
3532
3533   inp_fd = server->input_fd;
3534   inp_fn = server->input_filename;
3535   out_fd = server->output_fd;
3536   out_fn = server->output_filename;
3537   if (inp_fd != ASSUAN_INVALID_FD || inp_fn)
3538     {
3539       err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
3540                              &server->input_stream);
3541       if (err)
3542         return err;
3543     }
3544   if (out_fd != ASSUAN_INVALID_FD || out_fn)
3545     {
3546       err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
3547                              &server->output_stream);
3548       if (err)
3549         {
3550           gpgme_data_release (inp_data);
3551           return err;
3552         }
3553     }
3554
3555   err = gt_spawn (server->gt, line, inp_data, out_data);
3556
3557   gpgme_data_release (inp_data);
3558   gpgme_data_release (out_data);
3559
3560   server_reset_fds (server);
3561
3562   return err;
3563 }
3564
3565
3566 /* Tell the assuan library about our commands.  */
3567 static gpg_error_t
3568 register_commands (assuan_context_t ctx)
3569 {
3570   gpg_error_t err;
3571   static struct {
3572     const char *name;
3573     assuan_handler_t handler;
3574     const char * const help;
3575   } table[] = {
3576     /* RESET, BYE are implicit.  */
3577     { "VERSION", cmd_version, hlp_version },
3578     /* TODO: Set engine info.  */
3579     { "ENGINE", cmd_engine, hlp_engine },
3580     { "PROTOCOL", cmd_protocol, hlp_protocol },
3581     { "SUB_PROTOCOL", cmd_sub_protocol, hlp_sub_protocol },
3582     { "PINENTRY_MODE", cmd_pinentry_mode, hlp_pinentry_mode },
3583     { "ARMOR", cmd_armor, hlp_armor },
3584     { "TEXTMODE", cmd_textmode, hlp_textmode },
3585     { "INCLUDE_CERTS", cmd_include_certs, hlp_include_certs },
3586     { "KEYLIST_MODE", cmd_keylist_mode, hlp_keylist_mode },
3587     { "INPUT", cmd_input, hlp_input },
3588     { "OUTPUT", cmd_output, hlp_output },
3589     { "MESSAGE", cmd_message, hlp_message },
3590     { "RECIPIENT", cmd_recipient, hlp_recipient },
3591     { "SIGNER", cmd_signer, hlp_signer },
3592     { "SIGNERS_CLEAR", cmd_signers_clear, hlp_signers_clear },
3593      /* TODO: SIGNOTATION missing. */
3594      /* TODO: Could add wait interface if we allow more than one context */
3595      /* and add _START variants. */
3596      /* TODO: Could add data interfaces if we allow multiple data objects. */
3597     { "DECRYPT", cmd_decrypt, hlp_decrypt },
3598     { "DECRYPT_VERIFY", cmd_decrypt_verify, hlp_decrypt_verify },
3599     { "ENCRYPT", cmd_encrypt, hlp_encrypt },
3600     { "ENCRYPT_SIGN", cmd_sign_encrypt, hlp_sign_encrypt },
3601     { "SIGN_ENCRYPT", cmd_sign_encrypt, hlp_sign_encrypt },
3602     { "SIGN", cmd_sign, hlp_sign },
3603     { "VERIFY", cmd_verify, hlp_verify },
3604     { "IMPORT", cmd_import, hlp_import },
3605     { "EXPORT", cmd_export, hlp_export },
3606     { "GENKEY", cmd_genkey },
3607     { "DELETE", cmd_delete },
3608     /* TODO: EDIT, CARD_EDIT (with INQUIRE) */
3609     { "KEYLIST", cmd_keylist, hlp_keylist },
3610     { "LISTKEYS", cmd_keylist, hlp_keylist },
3611     /* TODO: TRUSTLIST, TRUSTLIST_EXT */
3612     { "GETAUDITLOG", cmd_getauditlog, hlp_getauditlog },
3613     /* TODO: ASSUAN */
3614     { "VFS_MOUNT", cmd_vfs_mount },
3615     { "MOUNT", cmd_vfs_mount },
3616     { "VFS_CREATE", cmd_vfs_create },
3617     { "CREATE", cmd_vfs_create },
3618     /* TODO: GPGCONF  */
3619     { "RESULT", cmd_result },
3620     { "STRERROR", cmd_strerror },
3621     { "PUBKEY_ALGO_NAME", cmd_pubkey_algo_name },
3622     { "HASH_ALGO_NAME", cmd_hash_algo_name },
3623     { "PASSWD", cmd_passwd, hlp_passwd },
3624     { "IDENTIFY", cmd_identify, hlp_identify },
3625     { "SPAWN", cmd_spawn, hlp_spawn },
3626     { NULL }
3627   };
3628   int idx;
3629
3630   for (idx = 0; table[idx].name; idx++)
3631     {
3632       err = assuan_register_command (ctx, table[idx].name, table[idx].handler,
3633                                      table[idx].help);
3634       if (err)
3635         return err;
3636     }
3637   return 0;
3638 }
3639
3640
3641 void
3642 gpgme_server (gpgme_tool_t gt)
3643 {
3644   gpg_error_t err;
3645   assuan_fd_t filedes[2];
3646   struct server server;
3647   static const char hello[] = ("GPGME-Tool " VERSION " ready");
3648
3649   memset (&server, 0, sizeof (server));
3650   server.input_fd = ASSUAN_INVALID_FD;
3651   server.output_fd = ASSUAN_INVALID_FD;
3652   server.message_fd = ASSUAN_INVALID_FD;
3653   server.input_enc = GPGME_DATA_ENCODING_NONE;
3654   server.output_enc = GPGME_DATA_ENCODING_NONE;
3655   server.message_enc = GPGME_DATA_ENCODING_NONE;
3656
3657   server.gt = gt;
3658   gt->write_status = server_write_status;
3659   gt->write_status_hook = &server;
3660   gt->write_data = server_write_data;
3661   gt->write_data_hook = &server;
3662
3663   /* We use a pipe based server so that we can work from scripts.
3664      assuan_init_pipe_server will automagically detect when we are
3665      called with a socketpair and ignore FIELDES in this case. */
3666 #ifdef HAVE_W32CE_SYSTEM
3667   filedes[0] = ASSUAN_STDIN;
3668   filedes[1] = ASSUAN_STDOUT;
3669 #else
3670   filedes[0] = assuan_fdopen (0);
3671   filedes[1] = assuan_fdopen (1);
3672 #endif
3673   err = assuan_new (&server.assuan_ctx);
3674   if (err)
3675     log_error (1, err, "can't create assuan context");
3676
3677   assuan_set_pointer (server.assuan_ctx, &server);
3678
3679   err = assuan_init_pipe_server (server.assuan_ctx, filedes);
3680   if (err)
3681     log_error (1, err, "can't initialize assuan server");
3682   err = register_commands (server.assuan_ctx);
3683   if (err)
3684     log_error (1, err, "can't register assuan commands");
3685   assuan_set_hello_line (server.assuan_ctx, hello);
3686
3687   assuan_register_reset_notify (server.assuan_ctx, reset_notify);
3688
3689 #define DBG_ASSUAN 0
3690   if (DBG_ASSUAN)
3691     assuan_set_log_stream (server.assuan_ctx, log_stream);
3692
3693   for (;;)
3694     {
3695       err = assuan_accept (server.assuan_ctx);
3696       if (err == -1)
3697         break;
3698       else if (err)
3699         {
3700           log_error (0, err, "assuan accept problem");
3701           break;
3702         }
3703
3704       err = assuan_process (server.assuan_ctx);
3705       if (err)
3706         log_error (0, err, "assuan processing failed");
3707     }
3708
3709   assuan_release (server.assuan_ctx);
3710 }
3711
3712
3713 \f
3714 /* MAIN PROGRAM STARTS HERE.  */
3715
3716 const char *argp_program_version = VERSION;
3717 const char *argp_program_bug_address = "bug-gpgme@gnupg.org";
3718 error_t argp_err_exit_status = 1;
3719
3720 static char doc[] = "GPGME Tool -- Assuan server exposing GPGME operations";
3721 static char args_doc[] = "COMMAND [OPTIONS...]";
3722
3723 static struct argp_option options[] = {
3724   { "server", 's', 0, 0, "Server mode" },
3725   { "gpg-binary", 501, "FILE", 0, "Use FILE for the GPG backend" },
3726   { 0 }
3727 };
3728
3729 static error_t parse_options (int key, char *arg, struct argp_state *state);
3730 static struct argp argp = { options, parse_options, args_doc, doc };
3731
3732 struct args
3733 {
3734   enum { CMD_DEFAULT, CMD_SERVER } cmd;
3735   const char *gpg_binary;
3736 };
3737
3738 void
3739 args_init (struct args *args)
3740 {
3741   memset (args, '\0', sizeof (*args));
3742   args->cmd = CMD_DEFAULT;
3743 }
3744
3745
3746 static error_t
3747 parse_options (int key, char *arg, struct argp_state *state)
3748 {
3749   struct args *args = state->input;
3750
3751   switch (key)
3752     {
3753     case 's':
3754       args->cmd = CMD_SERVER;
3755       break;
3756
3757     case 501:
3758       args->gpg_binary = arg;
3759       break;
3760 #if 0
3761     case ARGP_KEY_ARG:
3762       if (state->arg_num >= 2)
3763         argp_usage (state);
3764       printf ("Arg[%i] = %s\n", state->arg_num, arg);
3765       break;
3766     case ARGP_KEY_END:
3767       if (state->arg_num < 2)
3768         argp_usage (state);
3769       break;
3770 #endif
3771
3772     default:
3773       return ARGP_ERR_UNKNOWN;
3774     }
3775   return 0;
3776 }
3777
3778 \f
3779 int
3780 main (int argc, char *argv[])
3781 {
3782   struct args args;
3783   struct gpgme_tool gt;
3784   gpg_error_t err;
3785
3786 #ifdef HAVE_SETLOCALE
3787   setlocale (LC_ALL, "");
3788 #endif
3789   gpgme_check_version (NULL);
3790 #ifdef LC_CTYPE
3791   gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
3792 #endif
3793 #ifdef LC_MESSAGES
3794   gpgme_set_locale (NULL, LC_MESSAGES, setlocale (LC_MESSAGES, NULL));
3795 #endif
3796
3797   args_init (&args);
3798
3799   argp_parse (&argp, argc, argv, 0, 0, &args);
3800   log_init ();
3801
3802   if (args.gpg_binary)
3803     {
3804       if (access (args.gpg_binary, X_OK))
3805         err = gpg_error_from_syserror ();
3806       else
3807         err = gpgme_set_engine_info (GPGME_PROTOCOL_OpenPGP,
3808                                      args.gpg_binary, NULL);
3809       if (err)
3810         log_error (1, err, "error witching OpenPGP engine to '%s'",
3811                    args.gpg_binary);
3812     }
3813
3814   gt_init (&gt);
3815
3816   switch (args.cmd)
3817     {
3818     case CMD_DEFAULT:
3819     case CMD_SERVER:
3820       gpgme_server (&gt);
3821       break;
3822     }
3823
3824   gpgme_release (gt.ctx);
3825
3826 #ifdef HAVE_W32CE_SYSTEM
3827   /* Give the buggy ssh server time to flush the output buffers.  */
3828   Sleep (300);
3829 #endif
3830
3831   return 0;
3832 }
3833