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