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