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