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