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