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