75b7c9e1a31d91828297221bd11915c6c0410ed5
[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
1904 static gpg_error_t
1905 server_parse_fd (assuan_context_t ctx, char *line, assuan_fd_t *rfd,
1906                  char **filename)
1907 {
1908   *rfd = ASSUAN_INVALID_FD;
1909   *filename = NULL;
1910
1911   if (! strncasecmp (line, "file=", 5))
1912     {
1913       char *term;
1914       *filename = strdup (line + 5);
1915       if (!*filename)
1916         return gpg_error_from_syserror();
1917       term = strchr (*filename, ' ');
1918       if (term)
1919         *term = '\0';
1920       return 0;
1921     }
1922   else
1923     return assuan_command_parse_fd (ctx, line, rfd);
1924 }
1925
1926
1927 static gpgme_data_encoding_t
1928 server_data_encoding (const char *line)
1929 {
1930   if (strstr (line, "--binary"))
1931     return GPGME_DATA_ENCODING_BINARY;
1932   if (strstr (line, "--base64"))
1933     return GPGME_DATA_ENCODING_BASE64;
1934   if (strstr (line, "--armor"))
1935     return GPGME_DATA_ENCODING_ARMOR;
1936   if (strstr (line, "--url"))
1937     return GPGME_DATA_ENCODING_URL;
1938   if (strstr (line, "--urlesc"))
1939     return GPGME_DATA_ENCODING_URLESC;
1940   if (strstr (line, "--url0"))
1941     return GPGME_DATA_ENCODING_URL0;
1942   return GPGME_DATA_ENCODING_NONE;
1943 }
1944
1945
1946 static gpgme_error_t
1947 server_data_obj (assuan_fd_t fd, char *fn, int out,
1948                  gpgme_data_encoding_t encoding,
1949                  gpgme_data_t *data, FILE **fs)
1950 {
1951   gpgme_error_t err;
1952
1953   *fs = NULL;
1954   if (fn)
1955     {
1956       *fs = fopen (fn, out ? "wb" : "rb");
1957       if (!*fs)
1958         return gpg_error_from_syserror ();
1959
1960       err = gpgme_data_new_from_stream (data, *fs);
1961     }
1962   else
1963     err = gpgme_data_new_from_fd (data, (int) fd);
1964
1965   if (err)
1966     return err;
1967   return gpgme_data_set_encoding (*data, encoding);
1968 }
1969
1970
1971 void
1972 server_reset_fds (struct server *server)
1973 {
1974   /* assuan closes the input and output FDs for us when doing a RESET,
1975      but we use this same function after commands, so repeat it
1976      here.  */
1977   assuan_close_input_fd (server->assuan_ctx);
1978   assuan_close_output_fd (server->assuan_ctx);
1979   if (server->message_fd != ASSUAN_INVALID_FD)
1980     {
1981       /* FIXME: Assuan should provide a close function.  */
1982 #if HAVE_W32_SYSTEM
1983       CloseHandle (server->message_fd);
1984 #else
1985       close (server->message_fd);
1986 #endif
1987       server->message_fd = ASSUAN_INVALID_FD;
1988     }
1989   if (server->input_filename)
1990     {
1991       free (server->input_filename);
1992       server->input_filename = NULL;
1993     }
1994   if (server->output_filename)
1995     {
1996       free (server->output_filename);
1997       server->output_filename = NULL;
1998     }
1999   if (server->message_filename)
2000     {
2001       free (server->message_filename);
2002       server->message_filename = NULL;
2003     }
2004   if (server->input_stream)
2005     {
2006       fclose (server->input_stream);
2007       server->input_stream = NULL;
2008     }
2009   if (server->output_stream)
2010     {
2011       fclose (server->output_stream);
2012       server->output_stream = NULL;
2013     }
2014   if (server->message_stream)
2015     {
2016       fclose (server->message_stream);
2017       server->message_stream = NULL;
2018     }
2019
2020   server->input_enc = GPGME_DATA_ENCODING_NONE;
2021   server->output_enc = GPGME_DATA_ENCODING_NONE;
2022   server->message_enc = GPGME_DATA_ENCODING_NONE;
2023 }
2024
2025
2026 static gpg_error_t
2027 reset_notify (assuan_context_t ctx, char *line)
2028 {
2029   struct server *server = assuan_get_pointer (ctx);
2030   server_reset_fds (server);
2031   gt_reset (server->gt);
2032   return 0;
2033 }
2034
2035
2036 static const char hlp_version[] =
2037   "VERSION [<string>]\n"
2038   "\n"
2039   "Call the function gpgme_check_version.";
2040 static gpg_error_t
2041 cmd_version (assuan_context_t ctx, char *line)
2042 {
2043   if (line && *line)
2044     {
2045       const char *version = gpgme_check_version (line);
2046       return version ? 0 : gpg_error (GPG_ERR_SELFTEST_FAILED);
2047     }
2048   else
2049     {
2050       const char *version = gpgme_check_version (NULL);
2051       return assuan_send_data (ctx, version, strlen (version));
2052     }
2053 }
2054
2055
2056 static const char hlp_engine[] =
2057   "ENGINE [<string>]\n"
2058   "\n"
2059   "Get information about a GPGME engine (a.k.a. protocol).";
2060 static gpg_error_t
2061 cmd_engine (assuan_context_t ctx, char *line)
2062 {
2063   struct server *server = assuan_get_pointer (ctx);
2064   return gt_get_engine_info (server->gt, gt_protocol_from_name (line));
2065 }
2066
2067
2068 static const char hlp_protocol[] =
2069   "PROTOCOL [<name>]\n"
2070   "\n"
2071   "With NAME, set the protocol.  Without, return the current\n"
2072   "protocol.";
2073 static gpg_error_t
2074 cmd_protocol (assuan_context_t ctx, char *line)
2075 {
2076   struct server *server = assuan_get_pointer (ctx);
2077   if (line && *line)
2078     return gt_set_protocol (server->gt, gt_protocol_from_name (line));
2079   else
2080     return gt_get_protocol (server->gt);
2081 }
2082
2083
2084 static const char hlp_sub_protocol[] =
2085   "SUB_PROTOCOL [<name>]\n"
2086   "\n"
2087   "With NAME, set the sub-protocol.  Without, return the\n"
2088   "current sub-protocol.";
2089 static gpg_error_t
2090 cmd_sub_protocol (assuan_context_t ctx, char *line)
2091 {
2092   struct server *server = assuan_get_pointer (ctx);
2093   if (line && *line)
2094     return gt_set_sub_protocol (server->gt, gt_protocol_from_name (line));
2095   else
2096     return gt_get_sub_protocol (server->gt);
2097 }
2098
2099
2100 static const char hlp_armor[] =
2101   "ARMOR [true|false]\n"
2102   "\n"
2103   "With 'true' or 'false', turn output ASCII armoring on or\n"
2104   "off.  Without, return the current armoring status.";
2105 static gpg_error_t
2106 cmd_armor (assuan_context_t ctx, char *line)
2107 {
2108   struct server *server = assuan_get_pointer (ctx);
2109   if (line && *line)
2110     {
2111       int flag = 0;
2112
2113       if (! strcasecmp (line, "true") || ! strcasecmp (line, "yes")
2114           || line[0] == '1')
2115         flag = 1;
2116
2117       return gt_set_armor (server->gt, flag);
2118     }
2119   else
2120     return gt_get_armor (server->gt);
2121 }
2122
2123
2124 static const char hlp_textmode[] =
2125   "TEXTMODE [true|false]\n"
2126   "\n"
2127   "With 'true' or 'false', turn text mode on or off.\n"
2128   "Without, return the current text mode status.";
2129 static gpg_error_t
2130 cmd_textmode (assuan_context_t ctx, char *line)
2131 {
2132   struct server *server = assuan_get_pointer (ctx);
2133   if (line && *line)
2134     {
2135       int flag = 0;
2136
2137       if (! strcasecmp (line, "true") || ! strcasecmp (line, "yes")
2138           || line[0] == '1')
2139         flag = 1;
2140
2141       return gt_set_textmode (server->gt, flag);
2142     }
2143   else
2144     return gt_get_textmode (server->gt);
2145 }
2146
2147
2148 static const char hlp_include_certs[] =
2149   "INCLUDE_CERTS [default|<n>]\n"
2150   "\n"
2151   "With DEFAULT or N, set how many certificates should be\n"
2152   "included in the next S/MIME signed message.  See the\n"
2153   "GPGME documentation for details on the meaning of"
2154   "various N.  Without either, return the current setting.";
2155 static gpg_error_t
2156 cmd_include_certs (assuan_context_t ctx, char *line)
2157 {
2158   struct server *server = assuan_get_pointer (ctx);
2159
2160   if (line && *line)
2161     {
2162       int include_certs = 0;
2163
2164       if (! strcasecmp (line, "default"))
2165         include_certs = GPGME_INCLUDE_CERTS_DEFAULT;
2166       else
2167         include_certs = atoi (line);
2168
2169       return gt_set_include_certs (server->gt, include_certs);
2170     }
2171   else
2172     return gt_get_include_certs (server->gt);
2173 }
2174
2175
2176 static const char hlp_keylist_mode[] =
2177   "KEYLIST_MODE [local] [extern] [sigs] [sig_notations]\n"
2178   "  [ephemeral] [validate]\n"
2179   "\n"
2180   "Set the mode for the next KEYLIST command.";
2181 static gpg_error_t
2182 cmd_keylist_mode (assuan_context_t ctx, char *line)
2183 {
2184   struct server *server = assuan_get_pointer (ctx);
2185
2186   if (line && *line)
2187     {
2188       gpgme_keylist_mode_t mode = 0;
2189
2190       if (strstr (line, "local"))
2191         mode |= GPGME_KEYLIST_MODE_LOCAL;
2192       if (strstr (line, "extern"))
2193         mode |= GPGME_KEYLIST_MODE_EXTERN;
2194       if (strstr (line, "sigs"))
2195         mode |= GPGME_KEYLIST_MODE_SIGS;
2196       if (strstr (line, "sig_notations"))
2197         mode |= GPGME_KEYLIST_MODE_SIG_NOTATIONS;
2198       if (strstr (line, "ephemeral"))
2199         mode |= GPGME_KEYLIST_MODE_EPHEMERAL;
2200       if (strstr (line, "validate"))
2201         mode |= GPGME_KEYLIST_MODE_VALIDATE;
2202
2203       return gt_set_keylist_mode (server->gt, mode);
2204     }
2205   else
2206     return gt_get_keylist_mode (server->gt);
2207 }
2208
2209
2210 static const char hlp_input[] =
2211   "INPUT [<fd>|FILE=<path>]\n"
2212   "\n"
2213   "Set the input for the next command.  Use either the\n"
2214   "Assuan file descriptor FD or a filesystem PATH.";
2215 static gpg_error_t
2216 cmd_input (assuan_context_t ctx, char *line)
2217 {
2218   struct server *server = assuan_get_pointer (ctx);
2219   gpg_error_t err;
2220   assuan_fd_t sysfd;
2221   char *filename;
2222
2223   err = server_parse_fd (ctx, line, &sysfd, &filename);
2224   if (err)
2225     return err;
2226   server->input_fd = sysfd;
2227   server->input_filename = filename;
2228   server->input_enc = server_data_encoding (line);
2229   return 0;
2230 }
2231
2232
2233 static const char hlp_output[] =
2234   "OUTPUT [<fd>|FILE=<path>]\n"
2235   "\n"
2236   "Set the output for the next command.  Use either the\n"
2237   "Assuan file descriptor FD or a filesystem PATH.";
2238 static gpg_error_t
2239 cmd_output (assuan_context_t ctx, char *line)
2240 {
2241   struct server *server = assuan_get_pointer (ctx);
2242   gpg_error_t err;
2243   assuan_fd_t sysfd;
2244   char *filename;
2245
2246   err = server_parse_fd (ctx, line, &sysfd, &filename);
2247   if (err)
2248     return err;
2249   server->output_fd = sysfd;
2250   server->output_filename = filename;
2251   server->output_enc = server_data_encoding (line);
2252   return 0;
2253 }
2254
2255
2256 static const char hlp_message[] =
2257   "MESSAGE [<fd>|FILE=<path>]\n"
2258   "\n"
2259   "Set the plaintext message for the next VERIFY command\n"
2260   "with a detached signature.  Use either the Assuan file\n"
2261   "descriptor FD or a filesystem PATH.";
2262 static gpg_error_t
2263 cmd_message (assuan_context_t ctx, char *line)
2264 {
2265   struct server *server = assuan_get_pointer (ctx);
2266   gpg_error_t err;
2267   assuan_fd_t sysfd;
2268   char *filename;
2269
2270   err = server_parse_fd (ctx, line, &sysfd, &filename);
2271   if (err)
2272     return err;
2273   server->message_fd = sysfd;
2274   server->message_filename = filename;
2275   server->message_enc = server_data_encoding (line);
2276   return 0;
2277 }
2278
2279
2280 static const char hlp_recipient[] =
2281   "RECIPIENT <pattern>\n"
2282   "\n"
2283   "Add the key matching PATTERN to the list of recipients\n"
2284   "for the next encryption command.";
2285 static gpg_error_t
2286 cmd_recipient (assuan_context_t ctx, char *line)
2287 {
2288   struct server *server = assuan_get_pointer (ctx);
2289
2290   return gt_recipients_add (server->gt, line);
2291 }
2292
2293
2294 static const char hlp_signer[] =
2295   "SIGNER <fingerprint>\n"
2296   "\n"
2297   "Add the key with FINGERPRINT to the list of signers to\n"
2298   "be used for the next signing command.";
2299 static gpg_error_t
2300 cmd_signer (assuan_context_t ctx, char *line)
2301 {
2302   struct server *server = assuan_get_pointer (ctx);
2303
2304   return gt_signers_add (server->gt, line);
2305 }
2306
2307
2308 static const char hlp_signers_clear[] =
2309   "SIGNERS_CLEAR\n"
2310   "\n"
2311   "Clear the list of signers specified by previous SIGNER\n"
2312   "commands.";
2313 static gpg_error_t
2314 cmd_signers_clear (assuan_context_t ctx, char *line)
2315 {
2316   struct server *server = assuan_get_pointer (ctx);
2317
2318   return gt_signers_clear (server->gt);
2319 }
2320
2321
2322 static gpg_error_t
2323 _cmd_decrypt_verify (assuan_context_t ctx, char *line, int verify)
2324 {
2325   struct server *server = assuan_get_pointer (ctx);
2326   gpg_error_t err;
2327   assuan_fd_t inp_fd;
2328   char *inp_fn;
2329   assuan_fd_t out_fd;
2330   char *out_fn;
2331   gpgme_data_t inp_data;
2332   gpgme_data_t out_data;
2333
2334   inp_fd = assuan_get_input_fd (ctx);
2335   inp_fn = server->input_filename;
2336   if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
2337     return GPG_ERR_ASS_NO_INPUT;
2338   out_fd = assuan_get_output_fd (ctx);
2339   out_fn = server->output_filename;
2340   if (out_fd == ASSUAN_INVALID_FD && !out_fn)
2341     return GPG_ERR_ASS_NO_OUTPUT;
2342
2343   err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2344                          &server->input_stream);
2345   if (err)
2346     return err;
2347   err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2348                          &server->output_stream);
2349   if (err)
2350     {
2351       gpgme_data_release (inp_data);
2352       return err;
2353     }
2354
2355   err = gt_decrypt_verify (server->gt, inp_data, out_data, verify);
2356
2357   gpgme_data_release (inp_data);
2358   gpgme_data_release (out_data);
2359
2360   server_reset_fds (server);
2361
2362   return err;
2363 }
2364
2365
2366 static const char hlp_decrypt[] =
2367   "DECRYPT\n"
2368   "\n"
2369   "Decrypt the object set by the last INPUT command and\n"
2370   "write the decrypted message to the object set by the\n"
2371   "last OUTPUT command.";
2372 static gpg_error_t
2373 cmd_decrypt (assuan_context_t ctx, char *line)
2374 {
2375   return _cmd_decrypt_verify (ctx, line, 0);
2376 }
2377
2378
2379 static const char hlp_decrypt_verify[] =
2380   "DECRYPT_VERIFY\n"
2381   "\n"
2382   "Decrypt the object set by the last INPUT command and\n"
2383   "verify any embedded signatures.  Write the decrypted\n"
2384   "message to the object set by the last OUTPUT command.";
2385 static gpg_error_t
2386 cmd_decrypt_verify (assuan_context_t ctx, char *line)
2387 {
2388   return _cmd_decrypt_verify (ctx, line, 1);
2389 }
2390
2391
2392 static gpg_error_t
2393 _cmd_sign_encrypt (assuan_context_t ctx, char *line, int sign)
2394 {
2395   struct server *server = assuan_get_pointer (ctx);
2396   gpg_error_t err;
2397   assuan_fd_t inp_fd;
2398   char *inp_fn;
2399   assuan_fd_t out_fd;
2400   char *out_fn;
2401   gpgme_data_t inp_data = NULL;
2402   gpgme_data_t out_data = NULL;
2403   gpgme_encrypt_flags_t flags = 0;
2404
2405   if (strstr (line, "--always-trust"))
2406     flags |= GPGME_ENCRYPT_ALWAYS_TRUST;
2407   if (strstr (line, "--no-encrypt-to"))
2408     flags |= GPGME_ENCRYPT_NO_ENCRYPT_TO;
2409   if (strstr (line, "--prepare"))
2410     flags |= GPGME_ENCRYPT_PREPARE;
2411   if (strstr (line, "--expect-sign"))
2412     flags |= GPGME_ENCRYPT_EXPECT_SIGN;
2413
2414   inp_fd = assuan_get_input_fd (ctx);
2415   inp_fn = server->input_filename;
2416   out_fd = assuan_get_output_fd (ctx);
2417   out_fn = server->output_filename;
2418   if (inp_fd != ASSUAN_INVALID_FD || inp_fn)
2419     {
2420       err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2421                              &server->input_stream);
2422       if (err)
2423         return err;
2424     }
2425   if (out_fd != ASSUAN_INVALID_FD || out_fn)
2426     {
2427       err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2428                              &server->output_stream);
2429       if (err)
2430         {
2431           gpgme_data_release (inp_data);
2432           return err;
2433         }
2434     }
2435
2436   err = gt_sign_encrypt (server->gt, flags, inp_data, out_data, sign);
2437
2438   gpgme_data_release (inp_data);
2439   gpgme_data_release (out_data);
2440
2441   server_reset_fds (server);
2442
2443   return err;
2444 }
2445
2446
2447 static const char hlp_encrypt[] =
2448   "ENCRYPT [--always-trust] [--no-encrypt-to]\n"
2449   "  [--prepare] [--expect-sign]\n"
2450   "\n"
2451   "Encrypt the object set by the last INPUT command to\n"
2452   "the keys specified by previous RECIPIENT commands.  \n"
2453   "Write the signed and encrypted message to the object\n"
2454   "set by the last OUTPUT command.";
2455 static gpg_error_t
2456 cmd_encrypt (assuan_context_t ctx, char *line)
2457 {
2458   return _cmd_sign_encrypt (ctx, line, 0);
2459 }
2460
2461
2462 static const char hlp_sign_encrypt[] =
2463   "SIGN_ENCRYPT [--always-trust] [--no-encrypt-to]\n"
2464   "  [--prepare] [--expect-sign]\n"
2465   "\n"
2466   "Sign the object set by the last INPUT command with the\n"
2467   "keys specified by previous SIGNER commands and encrypt\n"
2468   "it to the keys specified by previous RECIPIENT\n"
2469   "commands.  Write the signed and encrypted message to\n"
2470   "the object set by the last OUTPUT command.";
2471 static gpg_error_t
2472 cmd_sign_encrypt (assuan_context_t ctx, char *line)
2473 {
2474   return _cmd_sign_encrypt (ctx, line, 1);
2475 }
2476
2477
2478 static const char hlp_sign[] =
2479   "SIGN [--clear|--detach]\n"
2480   "\n"
2481   "Sign the object set by the last INPUT command with the\n"
2482   "keys specified by previous SIGNER commands.  Write the\n"
2483   "signed message to the object set by the last OUTPUT\n"
2484   "command.  With `--clear`, generate a clear text\n"
2485   "signature.  With `--detach`, generate a detached\n"
2486   "signature.";
2487 static gpg_error_t
2488 cmd_sign (assuan_context_t ctx, char *line)
2489 {
2490   struct server *server = assuan_get_pointer (ctx);
2491   gpg_error_t err;
2492   assuan_fd_t inp_fd;
2493   char *inp_fn;
2494   assuan_fd_t out_fd;
2495   char *out_fn;
2496   gpgme_data_t inp_data;
2497   gpgme_data_t out_data;
2498   gpgme_sig_mode_t mode = GPGME_SIG_MODE_NORMAL;
2499
2500   if (strstr (line, "--clear"))
2501     mode = GPGME_SIG_MODE_CLEAR;
2502   if (strstr (line, "--detach"))
2503     mode = GPGME_SIG_MODE_DETACH;
2504
2505   inp_fd = assuan_get_input_fd (ctx);
2506   inp_fn = server->input_filename;
2507   if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
2508     return GPG_ERR_ASS_NO_INPUT;
2509   out_fd = assuan_get_output_fd (ctx);
2510   out_fn = server->output_filename;
2511   if (out_fd == ASSUAN_INVALID_FD && !out_fn)
2512     return GPG_ERR_ASS_NO_OUTPUT;
2513
2514   err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2515                          &server->input_stream);
2516   if (err)
2517     return err;
2518   err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2519                          &server->output_stream);
2520   if (err)
2521     {
2522       gpgme_data_release (inp_data);
2523       return err;
2524     }
2525
2526   err = gt_sign (server->gt, inp_data, out_data, mode);
2527
2528   gpgme_data_release (inp_data);
2529   gpgme_data_release (out_data);
2530   server_reset_fds (server);
2531
2532   return err;
2533 }
2534
2535
2536 static const char hlp_verify[] =
2537   "VERIFY\n"
2538   "\n"
2539   "Verify signatures on the object set by the last INPUT\n"
2540   "and MESSAGE commands.  If the message was encrypted,\n"
2541   "write the plaintext to the object set by the last\n"
2542   "OUTPUT command.";
2543 static gpg_error_t
2544 cmd_verify (assuan_context_t ctx, char *line)
2545 {
2546   struct server *server = assuan_get_pointer (ctx);
2547   gpg_error_t err;
2548   assuan_fd_t inp_fd;
2549   assuan_fd_t msg_fd;
2550   assuan_fd_t out_fd;
2551   char *inp_fn;
2552   char *msg_fn;
2553   char *out_fn;
2554   gpgme_data_t inp_data;
2555   gpgme_data_t msg_data = NULL;
2556   gpgme_data_t out_data = NULL;
2557
2558   inp_fd = assuan_get_input_fd (ctx);
2559   inp_fn = server->input_filename;
2560   if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
2561     return GPG_ERR_ASS_NO_INPUT;
2562   msg_fd = server->message_fd;
2563   msg_fn = server->message_filename;
2564   out_fd = assuan_get_output_fd (ctx);
2565   out_fn = server->output_filename;
2566
2567   err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2568                          &server->input_stream);
2569   if (err)
2570     return err;
2571   if (msg_fd != ASSUAN_INVALID_FD || msg_fn)
2572     {
2573       err = server_data_obj (msg_fd, msg_fn, 0, server->message_enc, &msg_data,
2574                              &server->message_stream);
2575       if (err)
2576         {
2577           gpgme_data_release (inp_data);
2578           return err;
2579         }
2580     }
2581   if (out_fd != ASSUAN_INVALID_FD || out_fn)
2582     {
2583       err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2584                              &server->output_stream);
2585       if (err)
2586         {
2587           gpgme_data_release (inp_data);
2588           gpgme_data_release (msg_data);
2589           return err;
2590         }
2591     }
2592
2593   err = gt_verify (server->gt, inp_data, msg_data, out_data);
2594
2595   gpgme_data_release (inp_data);
2596   if (msg_data)
2597     gpgme_data_release (msg_data);
2598   if (out_data)
2599     gpgme_data_release (out_data);
2600
2601   server_reset_fds (server);
2602
2603   return err;
2604 }
2605
2606
2607 static const char hlp_import[] =
2608   "IMPORT [<pattern>]\n"
2609   "\n"
2610   "With PATTERN, import the keys described by PATTERN.\n"
2611   "Without, read a key (or keys) from the object set by the\n"
2612   "last INPUT command.";
2613 static gpg_error_t
2614 cmd_import (assuan_context_t ctx, char *line)
2615 {
2616   struct server *server = assuan_get_pointer (ctx);
2617
2618   if (line && *line)
2619     {
2620       char *fprs[2] = { line, NULL };
2621
2622       return gt_import_keys (server->gt, fprs);
2623     }
2624   else
2625     {
2626       gpg_error_t err;
2627       assuan_fd_t inp_fd;
2628       char *inp_fn;
2629       gpgme_data_t inp_data;
2630
2631       inp_fd = assuan_get_input_fd (ctx);
2632       inp_fn = server->input_filename;
2633       if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
2634         return GPG_ERR_ASS_NO_INPUT;
2635
2636       err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2637                              &server->input_stream);
2638       if (err)
2639         return err;
2640
2641       err = gt_import (server->gt, inp_data);
2642
2643       gpgme_data_release (inp_data);
2644       server_reset_fds (server);
2645
2646       return err;
2647     }
2648 }
2649
2650
2651 static const char hlp_export[] =
2652   "EXPORT [--extern] [--minimal] [<pattern>]\n"
2653   "\n"
2654   "Export the keys described by PATTERN.  Write the\n"
2655   "the output to the object set by the last OUTPUT command.";
2656 static gpg_error_t
2657 cmd_export (assuan_context_t ctx, char *line)
2658 {
2659   struct server *server = assuan_get_pointer (ctx);
2660   gpg_error_t err;
2661   assuan_fd_t out_fd;
2662   char *out_fn;
2663   gpgme_data_t out_data;
2664   gpgme_export_mode_t mode = 0;
2665   const char *pattern[2];
2666
2667   out_fd = assuan_get_output_fd (ctx);
2668   out_fn = server->output_filename;
2669   if (out_fd == ASSUAN_INVALID_FD && !out_fn)
2670     return GPG_ERR_ASS_NO_OUTPUT;
2671   err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2672                          &server->output_stream);
2673   if (err)
2674     return err;
2675
2676   if (has_option (line, "--extern"))
2677     mode |= GPGME_EXPORT_MODE_EXTERN;
2678   if (has_option (line, "--minimal"))
2679     mode |= GPGME_EXPORT_MODE_MINIMAL;
2680
2681   line = skip_options (line);
2682
2683   pattern[0] = line;
2684   pattern[1] = NULL;
2685
2686   err = gt_export (server->gt, pattern, mode, out_data);
2687
2688   gpgme_data_release (out_data);
2689   server_reset_fds (server);
2690
2691   return err;
2692 }
2693
2694
2695 static gpg_error_t
2696 _cmd_genkey_write (gpgme_data_t data, const void *buf, size_t size)
2697 {
2698   while (size > 0)
2699     {
2700       ssize_t writen = gpgme_data_write (data, buf, size);
2701       if (writen < 0 && errno != EAGAIN)
2702         return gpg_error_from_syserror ();
2703       else if (writen > 0)
2704         {
2705           buf = (void *) (((char *) buf) + writen);
2706           size -= writen;
2707         }
2708     }
2709   return 0;
2710 }
2711
2712
2713 static gpg_error_t
2714 cmd_genkey (assuan_context_t ctx, char *line)
2715 {
2716   struct server *server = assuan_get_pointer (ctx);
2717   gpg_error_t err;
2718   assuan_fd_t inp_fd;
2719   char *inp_fn;
2720   assuan_fd_t out_fd;
2721   char *out_fn;
2722   gpgme_data_t inp_data;
2723   gpgme_data_t out_data = NULL;
2724   gpgme_data_t parms_data = NULL;
2725   const char *parms;
2726
2727   inp_fd = assuan_get_input_fd (ctx);
2728   inp_fn = server->input_filename;
2729   if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
2730     return GPG_ERR_ASS_NO_INPUT;
2731   out_fd = assuan_get_output_fd (ctx);
2732   out_fn = server->output_filename;
2733
2734   err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2735                          &server->input_stream);
2736   if (err)
2737     return err;
2738   if (out_fd != ASSUAN_INVALID_FD || out_fn)
2739     {
2740       err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2741                              &server->output_stream);
2742       if (err)
2743         {
2744           gpgme_data_release (inp_data);
2745           return err;
2746         }
2747     }
2748
2749   /* Convert input data.  */
2750   err = gpgme_data_new (&parms_data);
2751   if (err)
2752     goto out;
2753   do
2754     {
2755       char buf[512];
2756       ssize_t readn = gpgme_data_read (inp_data, buf, sizeof (buf));
2757       if (readn < 0)
2758         {
2759           err = gpg_error_from_syserror ();
2760           goto out;
2761         }
2762       else if (readn == 0)
2763         break;
2764
2765       err = _cmd_genkey_write (parms_data, buf, readn);
2766       if (err)
2767         goto out;
2768     }
2769   while (1);
2770   err = _cmd_genkey_write (parms_data, "", 1);
2771   if (err)
2772     goto out;
2773   parms = gpgme_data_release_and_get_mem (parms_data, NULL);
2774   parms_data = NULL;
2775   if (! parms)
2776     {
2777       err = gpg_error (GPG_ERR_GENERAL);
2778       goto out;
2779     }
2780
2781   err = gt_genkey (server->gt, parms, out_data, NULL);
2782
2783   server_reset_fds (server);
2784
2785  out:
2786   gpgme_data_release (inp_data);
2787   if (out_data)
2788     gpgme_data_release (out_data);
2789   if (parms_data)
2790     gpgme_data_release (parms_data);
2791
2792   return err;
2793 }
2794
2795
2796 static gpg_error_t
2797 cmd_delete (assuan_context_t ctx, char *line)
2798 {
2799   struct server *server = assuan_get_pointer (ctx);
2800   int allow_secret = 0;
2801   const char optstr[] = "--allow-secret";
2802
2803   if (!strncasecmp (line, optstr, strlen (optstr)))
2804     {
2805       allow_secret = 1;
2806       line += strlen (optstr);
2807       while (*line && !spacep (line))
2808         line++;
2809     }
2810   return gt_delete (server->gt, line, allow_secret);
2811 }
2812
2813
2814 static const char hlp_keylist[] =
2815   "KEYLIST [--secret-only] [<patterns>]\n"
2816   "\n"
2817   "List all certificates or only those specified by PATTERNS.  Each\n"
2818   "pattern shall be a percent-plus escaped certificate specification.";
2819 static gpg_error_t
2820 cmd_keylist (assuan_context_t ctx, char *line)
2821 {
2822 #define MAX_CMD_KEYLIST_PATTERN 20
2823   struct server *server = assuan_get_pointer (ctx);
2824   gpg_error_t err;
2825   int secret_only = 0;
2826   int idx;
2827   const char *pattern[MAX_CMD_KEYLIST_PATTERN+1];
2828   const char optstr[] = "--secret-only";
2829   char *p;
2830
2831   if (!strncasecmp (line, optstr, strlen (optstr)))
2832     {
2833       secret_only = 1;
2834       line += strlen (optstr);
2835       while (*line && !spacep (line))
2836         line++;
2837     }
2838
2839   idx = 0;
2840   for (p=line; *p; line = p)
2841     {
2842       while (*p && *p != ' ')
2843         p++;
2844       if (*p)
2845         *p++ = 0;
2846       if (*line)
2847         {
2848           if (idx+1 == DIM (pattern))
2849             return gpg_error (GPG_ERR_TOO_MANY);
2850           strcpy_escaped_plus (line, line);
2851           pattern[idx++] = line;
2852         }
2853     }
2854   pattern[idx] = NULL;
2855
2856   err = gt_keylist_start (server->gt, pattern, secret_only);
2857   while (! err)
2858     {
2859       gpgme_key_t key;
2860
2861       err = gt_keylist_next (server->gt, &key);
2862       if (gpg_err_code (err) == GPG_ERR_EOF)
2863         {
2864           err = 0;
2865           break;
2866         }
2867       else if (! err)
2868         {
2869           char buf[100];
2870           /* FIXME: More data.  */
2871           snprintf (buf, sizeof (buf), "key:%s\n", key->subkeys->fpr);
2872           /* Write data and flush so that we see one D line for each
2873              key.  This does not change the semantics but is easier to
2874              read by organic eyes.  */
2875           if (!assuan_send_data (ctx, buf, strlen (buf)))
2876             assuan_send_data (ctx, NULL, 0);
2877           gpgme_key_unref (key);
2878         }
2879     }
2880
2881   server_reset_fds (server);
2882
2883   return err;
2884 }
2885
2886
2887 static const char hlp_getauditlog[] =
2888   "GETAUDITLOG [--html] [--with-help]\n"
2889   "\n"
2890   "Call the function gpgme_op_getauditlog with the given flags.  Write\n"
2891   "the output to the object set by the last OUTPUT command.";
2892 static gpg_error_t
2893 cmd_getauditlog (assuan_context_t ctx, char *line)
2894 {
2895   struct server *server = assuan_get_pointer (ctx);
2896   gpg_error_t err;
2897   assuan_fd_t out_fd;
2898   char *out_fn;
2899   gpgme_data_t out_data;
2900   unsigned int flags = 0;
2901
2902   out_fd = assuan_get_output_fd (ctx);
2903   out_fn = server->output_filename;
2904   if (out_fd == ASSUAN_INVALID_FD && !out_fn)
2905     return GPG_ERR_ASS_NO_OUTPUT;
2906   err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2907                          &server->output_stream);
2908   if (err)
2909     return err;
2910
2911   if (strstr (line, "--html"))
2912     flags |= GPGME_AUDITLOG_HTML;
2913   if (strstr (line, "--with-help"))
2914     flags |= GPGME_AUDITLOG_WITH_HELP;
2915
2916   err = gt_getauditlog (server->gt, out_data, flags);
2917
2918   gpgme_data_release (out_data);
2919   server_reset_fds (server);
2920
2921   return err;
2922 }
2923
2924
2925 static gpg_error_t
2926 cmd_vfs_mount (assuan_context_t ctx, char *line)
2927 {
2928   struct server *server = assuan_get_pointer (ctx);
2929   char *mount_dir;
2930   gpg_error_t err;
2931
2932   mount_dir = strchr (line, ' ');
2933   if (mount_dir)
2934     {
2935       *(mount_dir++) = '\0';
2936       while (*mount_dir == ' ')
2937         mount_dir++;
2938     }
2939
2940   err = gt_vfs_mount (server->gt, line, mount_dir, 0);
2941
2942   return err;
2943 }
2944
2945
2946 static gpg_error_t
2947 cmd_vfs_create (assuan_context_t ctx, char *line)
2948 {
2949   struct server *server = assuan_get_pointer (ctx);
2950   gpg_error_t err;
2951   char *end;
2952
2953   end = strchr (line, ' ');
2954   if (end)
2955     {
2956       *(end++) = '\0';
2957       while (*end == ' ')
2958         end++;
2959     }
2960
2961   err = gt_vfs_create (server->gt, line, 0);
2962
2963   return err;
2964 }
2965
2966
2967 static gpg_error_t
2968 cmd_passwd (assuan_context_t ctx, char *line)
2969 {
2970   struct server *server = assuan_get_pointer (ctx);
2971
2972   return gt_passwd (server->gt, line);
2973 }
2974
2975
2976
2977 static gpg_error_t
2978 cmd_result (assuan_context_t ctx, char *line)
2979 {
2980   struct server *server = assuan_get_pointer (ctx);
2981   return gt_result (server->gt, GT_RESULT_ALL);
2982 }
2983
2984
2985 /* STRERROR <err>  */
2986 static gpg_error_t
2987 cmd_strerror (assuan_context_t ctx, char *line)
2988 {
2989   gpg_error_t err;
2990   char buf[100];
2991
2992   err = atoi (line);
2993   snprintf (buf, sizeof (buf), "%s <%s>", gpgme_strerror (err),
2994             gpgme_strsource (err));
2995   return assuan_send_data (ctx, buf, strlen (buf));
2996 }
2997
2998
2999 static gpg_error_t
3000 cmd_pubkey_algo_name (assuan_context_t ctx, char *line)
3001 {
3002   gpgme_pubkey_algo_t algo;
3003   char buf[100];
3004
3005   algo = atoi (line);
3006   snprintf (buf, sizeof (buf), "%s", gpgme_pubkey_algo_name (algo));
3007   return assuan_send_data (ctx, buf, strlen (buf));
3008 }
3009
3010
3011 static gpg_error_t
3012 cmd_hash_algo_name (assuan_context_t ctx, char *line)
3013 {
3014   gpgme_hash_algo_t algo;
3015   char buf[100];
3016
3017   algo = atoi (line);
3018   snprintf (buf, sizeof (buf), "%s", gpgme_hash_algo_name (algo));
3019   return assuan_send_data (ctx, buf, strlen (buf));
3020 }
3021
3022
3023 /* Tell the assuan library about our commands.  */
3024 static gpg_error_t
3025 register_commands (assuan_context_t ctx)
3026 {
3027   gpg_error_t err;
3028   static struct {
3029     const char *name;
3030     assuan_handler_t handler;
3031     const char * const help;
3032   } table[] = {
3033     /* RESET, BYE are implicit.  */
3034     { "VERSION", cmd_version, hlp_version },
3035     /* TODO: Set engine info.  */
3036     { "ENGINE", cmd_engine, hlp_engine },
3037     { "PROTOCOL", cmd_protocol, hlp_protocol },
3038     { "SUB_PROTOCOL", cmd_sub_protocol, hlp_sub_protocol },
3039     { "ARMOR", cmd_armor, hlp_armor },
3040     { "TEXTMODE", cmd_textmode, hlp_textmode },
3041     { "INCLUDE_CERTS", cmd_include_certs, hlp_include_certs },
3042     { "KEYLIST_MODE", cmd_keylist_mode, hlp_keylist_mode },
3043     { "INPUT", cmd_input, hlp_input },
3044     { "OUTPUT", cmd_output, hlp_output },
3045     { "MESSAGE", cmd_message, hlp_message },
3046     { "RECIPIENT", cmd_recipient, hlp_recipient },
3047     { "SIGNER", cmd_signer, hlp_signer },
3048     { "SIGNERS_CLEAR", cmd_signers_clear, hlp_signers_clear },
3049      /* TODO: SIGNOTATION missing. */
3050      /* TODO: Could add wait interface if we allow more than one context */
3051      /* and add _START variants. */
3052      /* TODO: Could add data interfaces if we allow multiple data objects. */
3053     { "DECRYPT", cmd_decrypt, hlp_decrypt },
3054     { "DECRYPT_VERIFY", cmd_decrypt_verify, hlp_decrypt_verify },
3055     { "ENCRYPT", cmd_encrypt, hlp_encrypt },
3056     { "ENCRYPT_SIGN", cmd_sign_encrypt, hlp_sign_encrypt },
3057     { "SIGN_ENCRYPT", cmd_sign_encrypt, hlp_sign_encrypt },
3058     { "SIGN", cmd_sign, hlp_sign },
3059     { "VERIFY", cmd_verify, hlp_verify },
3060     { "IMPORT", cmd_import, hlp_import },
3061     { "EXPORT", cmd_export, hlp_export },
3062     { "GENKEY", cmd_genkey },
3063     { "DELETE", cmd_delete },
3064     /* TODO: EDIT, CARD_EDIT (with INQUIRE) */
3065     { "KEYLIST", cmd_keylist, hlp_keylist },
3066     { "LISTKEYS", cmd_keylist, hlp_keylist },
3067     /* TODO: TRUSTLIST, TRUSTLIST_EXT */
3068     { "GETAUDITLOG", cmd_getauditlog, hlp_getauditlog },
3069     /* TODO: ASSUAN */
3070     { "VFS_MOUNT", cmd_vfs_mount },
3071     { "MOUNT", cmd_vfs_mount },
3072     { "VFS_CREATE", cmd_vfs_create },
3073     { "CREATE", cmd_vfs_create },
3074     /* TODO: GPGCONF  */
3075     { "RESULT", cmd_result },
3076     { "STRERROR", cmd_strerror },
3077     { "PUBKEY_ALGO_NAME", cmd_pubkey_algo_name },
3078     { "HASH_ALGO_NAME", cmd_hash_algo_name },
3079     { "PASSWD", cmd_passwd, hlp_passwd },
3080     { NULL }
3081   };
3082   int idx;
3083
3084   for (idx = 0; table[idx].name; idx++)
3085     {
3086       err = assuan_register_command (ctx, table[idx].name, table[idx].handler,
3087                                      table[idx].help);
3088       if (err)
3089         return err;
3090     }
3091   return 0;
3092 }
3093
3094
3095 /* TODO: password callback can do INQUIRE.  */
3096 void
3097 gpgme_server (gpgme_tool_t gt)
3098 {
3099   gpg_error_t err;
3100   assuan_fd_t filedes[2];
3101   struct server server;
3102   static const char hello[] = ("GPGME-Tool " VERSION " ready");
3103
3104   memset (&server, 0, sizeof (server));
3105   server.message_fd = ASSUAN_INVALID_FD;
3106   server.input_enc = GPGME_DATA_ENCODING_NONE;
3107   server.output_enc = GPGME_DATA_ENCODING_NONE;
3108   server.message_enc = GPGME_DATA_ENCODING_NONE;
3109
3110   server.gt = gt;
3111   gt->write_status = server_write_status;
3112   gt->write_status_hook = &server;
3113   gt->write_data = server_write_data;
3114   gt->write_data_hook = &server;
3115
3116   /* We use a pipe based server so that we can work from scripts.
3117      assuan_init_pipe_server will automagically detect when we are
3118      called with a socketpair and ignore FIELDES in this case. */
3119 #ifdef HAVE_W32CE_SYSTEM
3120   filedes[0] = ASSUAN_STDIN;
3121   filedes[1] = ASSUAN_STDOUT;
3122 #else
3123   filedes[0] = assuan_fdopen (0);
3124   filedes[1] = assuan_fdopen (1);
3125 #endif
3126   err = assuan_new (&server.assuan_ctx);
3127   if (err)
3128     log_error (1, err, "can't create assuan context");
3129
3130   assuan_set_pointer (server.assuan_ctx, &server);
3131
3132   err = assuan_init_pipe_server (server.assuan_ctx, filedes);
3133   if (err)
3134     log_error (1, err, "can't initialize assuan server");
3135   err = register_commands (server.assuan_ctx);
3136   if (err)
3137     log_error (1, err, "can't register assuan commands");
3138   assuan_set_hello_line (server.assuan_ctx, hello);
3139
3140   assuan_register_reset_notify (server.assuan_ctx, reset_notify);
3141
3142 #define DBG_ASSUAN 0
3143   if (DBG_ASSUAN)
3144     assuan_set_log_stream (server.assuan_ctx, log_stream);
3145
3146   for (;;)
3147     {
3148       err = assuan_accept (server.assuan_ctx);
3149       if (err == -1)
3150         break;
3151       else if (err)
3152         {
3153           log_error (0, err, "assuan accept problem");
3154           break;
3155         }
3156
3157       err = assuan_process (server.assuan_ctx);
3158       if (err)
3159         log_error (0, err, "assuan processing failed");
3160     }
3161
3162   assuan_release (server.assuan_ctx);
3163 }
3164
3165
3166 \f
3167 /* MAIN PROGRAM STARTS HERE.  */
3168
3169 const char *argp_program_version = VERSION;
3170 const char *argp_program_bug_address = "bug-gpgme@gnupg.org";
3171 error_t argp_err_exit_status = 1;
3172
3173 static char doc[] = "GPGME Tool -- Assuan server exposing GPGME operations";
3174 static char args_doc[] = "COMMAND [OPTIONS...]";
3175
3176 static struct argp_option options[] = {
3177   { "server", 's', 0, 0, "Server mode" },
3178   { 0 }
3179 };
3180
3181 static error_t parse_options (int key, char *arg, struct argp_state *state);
3182 static struct argp argp = { options, parse_options, args_doc, doc };
3183
3184 struct args
3185 {
3186   enum { CMD_DEFAULT, CMD_SERVER } cmd;
3187 };
3188
3189 void
3190 args_init (struct args *args)
3191 {
3192   memset (args, '\0', sizeof (*args));
3193   args->cmd = CMD_DEFAULT;
3194 }
3195
3196
3197 static error_t
3198 parse_options (int key, char *arg, struct argp_state *state)
3199 {
3200   struct args *args = state->input;
3201
3202   switch (key)
3203     {
3204     case 's':
3205       args->cmd = CMD_SERVER;
3206       break;
3207 #if 0
3208     case ARGP_KEY_ARG:
3209       if (state->arg_num >= 2)
3210         argp_usage (state);
3211       printf ("Arg[%i] = %s\n", state->arg_num, arg);
3212       break;
3213     case ARGP_KEY_END:
3214       if (state->arg_num < 2)
3215         argp_usage (state);
3216       break;
3217 #endif
3218
3219     default:
3220       return ARGP_ERR_UNKNOWN;
3221     }
3222   return 0;
3223 }
3224
3225 \f
3226 int
3227 main (int argc, char *argv[])
3228 {
3229   struct args args;
3230   struct gpgme_tool gt;
3231
3232 #ifdef HAVE_SETLOCALE
3233   setlocale (LC_ALL, "");
3234 #endif
3235   gpgme_check_version (NULL);
3236 #ifdef LC_CTYPE
3237   gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
3238 #endif
3239 #ifdef LC_MESSAGES
3240   gpgme_set_locale (NULL, LC_MESSAGES, setlocale (LC_MESSAGES, NULL));
3241 #endif
3242
3243   args_init (&args);
3244
3245   argp_parse (&argp, argc, argv, 0, 0, &args);
3246   log_init ();
3247
3248   gt_init (&gt);
3249
3250   switch (args.cmd)
3251     {
3252     case CMD_DEFAULT:
3253     case CMD_SERVER:
3254       gpgme_server (&gt);
3255       break;
3256     }
3257
3258   gpgme_release (gt.ctx);
3259
3260 #ifdef HAVE_W32CE_SYSTEM
3261   /* Give the buggy ssh server time to flush the output buffers.  */
3262   Sleep (300);
3263 #endif
3264
3265   return 0;
3266 }
3267