2010-05-06 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 #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   err = gpgme_data_new_from_fd (data, fd);
1883   if (err)
1884     return err;
1885   return gpgme_data_set_encoding (*data, encoding);
1886 }
1887
1888
1889 void
1890 server_reset_fds (struct server *server)
1891 {
1892   /* assuan closes the input and output FDs for us when doing a RESET,
1893      but we use this same function after commands, so repeat it
1894      here.  */
1895   assuan_close_input_fd (server->assuan_ctx);
1896   assuan_close_output_fd (server->assuan_ctx);
1897   if (server->message_fd != -1)
1898     {
1899       /* FIXME: Assuan should provide a close function.  */
1900       close (server->message_fd);
1901       server->message_fd = -1;
1902     }
1903   server->input_enc = GPGME_DATA_ENCODING_NONE;
1904   server->output_enc = GPGME_DATA_ENCODING_NONE;
1905   server->message_enc = GPGME_DATA_ENCODING_NONE;
1906 }
1907
1908
1909 static gpg_error_t
1910 reset_notify (assuan_context_t ctx, char *line)
1911 {
1912   struct server *server = assuan_get_pointer (ctx);
1913   server_reset_fds (server);
1914   gt_reset (server->gt);
1915   return 0;
1916 }
1917
1918 static const char hlp_version[] = 
1919   "VERSION [<string>]\n"
1920   "\n"
1921   "Call the function gpgme_check_version.";
1922 static gpg_error_t
1923 cmd_version (assuan_context_t ctx, char *line)
1924 {
1925   if (line && *line)
1926     {
1927       const char *version = gpgme_check_version (line);
1928       return version ? 0 : gpg_error (GPG_ERR_SELFTEST_FAILED);
1929     }
1930   else
1931     {
1932       const char *version = gpgme_check_version (NULL);
1933       return assuan_send_data (ctx, version, strlen (version));
1934     }
1935 }
1936
1937
1938 static gpg_error_t
1939 cmd_engine (assuan_context_t ctx, char *line)
1940 {
1941   struct server *server = assuan_get_pointer (ctx);
1942   return gt_get_engine_info (server->gt, gt_protocol_from_name (line));
1943 }
1944
1945
1946 static const char hlp_protocol[] = 
1947   "PROTOCOL [<name>]\n"
1948   "\n"
1949   "With NAME, set the protocol.  Without return the current protocol.";
1950 static gpg_error_t
1951 cmd_protocol (assuan_context_t ctx, char *line)
1952 {
1953   struct server *server = assuan_get_pointer (ctx);
1954   if (line && *line)
1955     return gt_set_protocol (server->gt, gt_protocol_from_name (line));
1956   else
1957     return gt_get_protocol (server->gt);
1958 }
1959
1960
1961 static gpg_error_t
1962 cmd_sub_protocol (assuan_context_t ctx, char *line)
1963 {
1964   struct server *server = assuan_get_pointer (ctx);
1965   if (line && *line)
1966     return gt_set_sub_protocol (server->gt, gt_protocol_from_name (line));
1967   else
1968     return gt_get_sub_protocol (server->gt);
1969 }
1970
1971
1972 static gpg_error_t
1973 cmd_armor (assuan_context_t ctx, char *line)
1974 {
1975   struct server *server = assuan_get_pointer (ctx);
1976   if (line && *line)
1977     {
1978       int flag = 0;
1979       
1980       if (! strcasecmp (line, "true") || ! strcasecmp (line, "yes")
1981           || line[0] == '1')
1982         flag = 1;
1983       
1984       return gt_set_armor (server->gt, flag);
1985     }
1986   else
1987     return gt_get_armor (server->gt);
1988 }
1989
1990
1991 static gpg_error_t
1992 cmd_textmode (assuan_context_t ctx, char *line)
1993 {
1994   struct server *server = assuan_get_pointer (ctx);
1995   if (line && *line)
1996     {
1997       int flag = 0;
1998
1999       if (! strcasecmp (line, "true") || ! strcasecmp (line, "yes")
2000           || line[0] == '1')
2001         flag = 1;
2002       
2003       return gt_set_textmode (server->gt, flag);
2004     }
2005   else
2006     return gt_get_textmode (server->gt);
2007 }
2008
2009
2010 static gpg_error_t
2011 cmd_include_certs (assuan_context_t ctx, char *line)
2012 {
2013   struct server *server = assuan_get_pointer (ctx);
2014
2015   if (line && *line)
2016     {
2017       int include_certs = 0;
2018       
2019       if (! strcasecmp (line, "default"))
2020         include_certs = GPGME_INCLUDE_CERTS_DEFAULT;
2021       else
2022         include_certs = atoi (line);
2023       
2024       return gt_set_include_certs (server->gt, include_certs);
2025     }
2026   else
2027     return gt_get_include_certs (server->gt);
2028 }
2029
2030
2031 static gpg_error_t
2032 cmd_keylist_mode (assuan_context_t ctx, char *line)
2033 {
2034   struct server *server = assuan_get_pointer (ctx);
2035
2036   if (line && *line)
2037     {
2038       gpgme_keylist_mode_t mode = 0;
2039       
2040       if (strstr (line, "local"))
2041         mode |= GPGME_KEYLIST_MODE_LOCAL;
2042       if (strstr (line, "extern"))
2043         mode |= GPGME_KEYLIST_MODE_EXTERN;
2044       if (strstr (line, "sigs"))
2045         mode |= GPGME_KEYLIST_MODE_SIGS;
2046       if (strstr (line, "sig_notations"))
2047         mode |= GPGME_KEYLIST_MODE_SIG_NOTATIONS;
2048       if (strstr (line, "ephemeral"))
2049         mode |= GPGME_KEYLIST_MODE_EPHEMERAL;
2050       if (strstr (line, "validate"))
2051         mode |= GPGME_KEYLIST_MODE_VALIDATE;
2052       
2053       return gt_set_keylist_mode (server->gt, mode);
2054     }
2055   else
2056     return gt_get_keylist_mode (server->gt);
2057 }
2058
2059
2060 static gpg_error_t
2061 input_notify (assuan_context_t ctx, char *line)
2062 {
2063   struct server *server = assuan_get_pointer (ctx);
2064   server->input_enc = server_data_encoding (line);
2065   return 0;
2066 }
2067
2068
2069 static gpg_error_t
2070 output_notify (assuan_context_t ctx, char *line)
2071 {
2072   struct server *server = assuan_get_pointer (ctx);
2073   server->output_enc = server_data_encoding (line);
2074   return 0;
2075 }
2076
2077
2078 static gpg_error_t
2079 cmd_message (assuan_context_t ctx, char *line)
2080 {
2081   struct server *server = assuan_get_pointer (ctx);
2082   gpg_error_t err;
2083   assuan_fd_t sysfd;
2084
2085   err = assuan_command_parse_fd (ctx, line, &sysfd);
2086   if (err)
2087     return err;
2088   server->message_fd = sysfd;
2089   server->message_enc = server_data_encoding (line);
2090   return 0;
2091 }
2092
2093
2094 static gpg_error_t
2095 cmd_recipient (assuan_context_t ctx, char *line)
2096 {
2097   struct server *server = assuan_get_pointer (ctx);
2098
2099   return gt_recipients_add (server->gt, line);
2100 }
2101
2102
2103 static gpg_error_t
2104 cmd_signer (assuan_context_t ctx, char *line)
2105 {
2106   struct server *server = assuan_get_pointer (ctx);
2107
2108   return gt_signers_add (server->gt, line);
2109 }
2110
2111
2112 static gpg_error_t
2113 cmd_signers_clear (assuan_context_t ctx, char *line)
2114 {
2115   struct server *server = assuan_get_pointer (ctx);
2116
2117   return gt_signers_clear (server->gt);
2118 }
2119
2120
2121 static gpg_error_t
2122 _cmd_decrypt_verify (assuan_context_t ctx, char *line, int verify)
2123 {
2124   struct server *server = assuan_get_pointer (ctx);
2125   gpg_error_t err;
2126   assuan_fd_t inp_fd;
2127   assuan_fd_t out_fd;
2128   gpgme_data_t inp_data;
2129   gpgme_data_t out_data;
2130
2131   inp_fd = assuan_get_input_fd (ctx);
2132   if (inp_fd == ASSUAN_INVALID_FD)
2133     return GPG_ERR_ASS_NO_INPUT;
2134   out_fd = assuan_get_output_fd (ctx);
2135   if (out_fd == ASSUAN_INVALID_FD)
2136     return GPG_ERR_ASS_NO_OUTPUT;
2137   
2138   err = server_data_obj (inp_fd, server->input_enc, &inp_data);
2139   if (err)
2140     return err;
2141   err = server_data_obj (out_fd, server->output_enc, &out_data);
2142   if (err)
2143     {
2144       gpgme_data_release (inp_data);
2145       return err;
2146     }
2147
2148   err = gt_decrypt_verify (server->gt, inp_data, out_data, verify); 
2149
2150   gpgme_data_release (inp_data);
2151   gpgme_data_release (out_data);
2152
2153   server_reset_fds (server);
2154
2155   return err;
2156 }
2157
2158
2159 static gpg_error_t
2160 cmd_decrypt (assuan_context_t ctx, char *line)
2161 {
2162   return _cmd_decrypt_verify (ctx, line, 0);
2163 }
2164
2165
2166 static gpg_error_t
2167 cmd_decrypt_verify (assuan_context_t ctx, char *line)
2168 {
2169   return _cmd_decrypt_verify (ctx, line, 1);
2170 }
2171
2172
2173 static gpg_error_t
2174 _cmd_sign_encrypt (assuan_context_t ctx, char *line, int sign)
2175 {
2176   struct server *server = assuan_get_pointer (ctx);
2177   gpg_error_t err;
2178   assuan_fd_t inp_fd;
2179   assuan_fd_t out_fd;
2180   gpgme_data_t inp_data = NULL;
2181   gpgme_data_t out_data = NULL;
2182   gpgme_encrypt_flags_t flags = 0;
2183
2184   if (strstr (line, "--always-trust"))
2185     flags |= GPGME_ENCRYPT_ALWAYS_TRUST;
2186   if (strstr (line, "--no-encrypt-to"))
2187     flags |= GPGME_ENCRYPT_NO_ENCRYPT_TO;
2188   if (strstr (line, "--prepare"))
2189     flags |= GPGME_ENCRYPT_PREPARE;
2190   if (strstr (line, "--expect-sign"))
2191     flags |= GPGME_ENCRYPT_EXPECT_SIGN;
2192   
2193   inp_fd = assuan_get_input_fd (ctx);
2194   out_fd = assuan_get_output_fd (ctx);
2195   if (inp_fd != ASSUAN_INVALID_FD)
2196     {
2197       err = server_data_obj (inp_fd, server->input_enc, &inp_data);
2198       if (err)
2199         return err;
2200     }
2201   if (out_fd != ASSUAN_INVALID_FD)
2202     {
2203       err = server_data_obj (out_fd, server->output_enc, &out_data);
2204       if (err)
2205         {
2206           gpgme_data_release (inp_data);
2207           return err;
2208         }
2209     }
2210
2211   err = gt_sign_encrypt (server->gt, flags, inp_data, out_data, sign); 
2212
2213   gpgme_data_release (inp_data);
2214   gpgme_data_release (out_data);
2215
2216   server_reset_fds (server);
2217
2218   return err;
2219 }
2220
2221
2222 static gpg_error_t
2223 cmd_encrypt (assuan_context_t ctx, char *line)
2224 {
2225   return _cmd_sign_encrypt (ctx, line, 0);
2226 }
2227
2228
2229 static gpg_error_t
2230 cmd_sign_encrypt (assuan_context_t ctx, char *line)
2231 {
2232   return _cmd_sign_encrypt (ctx, line, 1);
2233 }
2234
2235
2236 static gpg_error_t
2237 cmd_sign (assuan_context_t ctx, char *line)
2238 {
2239   struct server *server = assuan_get_pointer (ctx);
2240   gpg_error_t err;
2241   assuan_fd_t inp_fd;
2242   assuan_fd_t out_fd;
2243   gpgme_data_t inp_data;
2244   gpgme_data_t out_data;
2245   gpgme_sig_mode_t mode = GPGME_SIG_MODE_NORMAL;
2246
2247   if (strstr (line, "--clear"))
2248     mode = GPGME_SIG_MODE_CLEAR;
2249   if (strstr (line, "--detach"))
2250     mode = GPGME_SIG_MODE_DETACH;
2251
2252   inp_fd = assuan_get_input_fd (ctx);
2253   if (inp_fd == ASSUAN_INVALID_FD)
2254     return GPG_ERR_ASS_NO_INPUT;
2255   out_fd = assuan_get_output_fd (ctx);
2256   if (out_fd == ASSUAN_INVALID_FD)
2257     return GPG_ERR_ASS_NO_OUTPUT;
2258   
2259   err = server_data_obj (inp_fd, server->input_enc, &inp_data);
2260   if (err)
2261     return err;
2262   err = server_data_obj (out_fd, server->output_enc, &out_data);
2263   if (err)
2264     {
2265       gpgme_data_release (inp_data);
2266       return err;
2267     }
2268
2269   err = gt_sign (server->gt, inp_data, out_data, mode);
2270
2271   gpgme_data_release (inp_data);
2272   gpgme_data_release (out_data);
2273   server_reset_fds (server);
2274
2275   return err;
2276 }
2277
2278
2279 static gpg_error_t
2280 cmd_verify (assuan_context_t ctx, char *line)
2281 {
2282   struct server *server = assuan_get_pointer (ctx);
2283   gpg_error_t err;
2284   assuan_fd_t inp_fd;
2285   assuan_fd_t msg_fd;
2286   assuan_fd_t out_fd;
2287   gpgme_data_t inp_data;
2288   gpgme_data_t msg_data = NULL;
2289   gpgme_data_t out_data = NULL;
2290
2291   inp_fd = assuan_get_input_fd (ctx);
2292   if (inp_fd == ASSUAN_INVALID_FD)
2293     return GPG_ERR_ASS_NO_INPUT;
2294   msg_fd = server->message_fd;
2295   out_fd = assuan_get_output_fd (ctx);
2296   
2297   err = server_data_obj (inp_fd, server->input_enc, &inp_data);
2298   if (err)
2299     return err;
2300   if (msg_fd != ASSUAN_INVALID_FD)
2301     {
2302       err = server_data_obj (msg_fd, server->message_enc, &msg_data);
2303       if (err)
2304         {
2305           gpgme_data_release (inp_data);
2306           return err;
2307         }
2308     }
2309   if (out_fd != ASSUAN_INVALID_FD)
2310     {
2311       err = server_data_obj (out_fd, server->output_enc, &out_data);
2312       if (err)
2313         {
2314           gpgme_data_release (inp_data);
2315           gpgme_data_release (msg_data);
2316           return err;
2317         }
2318     }
2319
2320   err = gt_verify (server->gt, inp_data, msg_data, out_data);
2321
2322   gpgme_data_release (inp_data);
2323   if (msg_data)
2324     gpgme_data_release (msg_data);
2325   if (out_data)
2326     gpgme_data_release (out_data);
2327
2328   server_reset_fds (server);
2329
2330   return err;
2331 }
2332
2333
2334 static gpg_error_t
2335 cmd_import (assuan_context_t ctx, char *line)
2336 {
2337   struct server *server = assuan_get_pointer (ctx);
2338   
2339   if (line && *line)
2340     {
2341       char *fprs[2] = { line, NULL };
2342
2343       return gt_import_keys (server->gt, fprs);
2344     }
2345   else
2346     {
2347       gpg_error_t err;
2348       assuan_fd_t inp_fd;
2349       gpgme_data_t inp_data;
2350       
2351       inp_fd = assuan_get_input_fd (ctx);
2352       if (inp_fd == ASSUAN_INVALID_FD)
2353         return GPG_ERR_ASS_NO_INPUT;
2354
2355       err = server_data_obj (inp_fd, server->input_enc, &inp_data);
2356       if (err)
2357         return err;
2358       
2359       err = gt_import (server->gt, inp_data); 
2360       
2361       gpgme_data_release (inp_data);
2362       server_reset_fds (server);
2363
2364       return err;
2365     }
2366 }
2367
2368
2369 static const char hlp_export[] = 
2370   "EXPORT [--extern] [--minimal] [<pattern>]\n"
2371   "\n"
2372   "Export the keys described by PATTERN.  Write the\n"
2373   "the output to the object set by the last OUTPUT command.";
2374 static gpg_error_t
2375 cmd_export (assuan_context_t ctx, char *line)
2376 {
2377   struct server *server = assuan_get_pointer (ctx);
2378   gpg_error_t err;
2379   assuan_fd_t out_fd;
2380   gpgme_data_t out_data;
2381   gpgme_export_mode_t mode = 0;
2382   const char *pattern[2];
2383
2384   out_fd = assuan_get_output_fd (ctx);
2385   if (out_fd == ASSUAN_INVALID_FD)
2386     return GPG_ERR_ASS_NO_OUTPUT;
2387   err = server_data_obj (out_fd, server->output_enc, &out_data);
2388   if (err)
2389     return err;
2390
2391   if (has_option (line, "--extern"))
2392     mode |= GPGME_EXPORT_MODE_EXTERN;
2393   if (has_option (line, "--minimal"))
2394     mode |= GPGME_EXPORT_MODE_MINIMAL;
2395
2396   line = skip_options (line);
2397
2398   pattern[0] = line;
2399   pattern[1] = NULL;
2400
2401   err = gt_export (server->gt, pattern, mode, out_data);
2402
2403   gpgme_data_release (out_data);
2404   server_reset_fds (server);
2405
2406   return err;
2407 }
2408
2409
2410 static gpg_error_t
2411 _cmd_genkey_write (gpgme_data_t data, const void *buf, size_t size)
2412 {
2413   while (size > 0)
2414     {
2415       ssize_t writen = gpgme_data_write (data, buf, size);
2416       if (writen < 0 && errno != EAGAIN)
2417         return gpg_error_from_syserror ();
2418       else if (writen > 0)
2419         {
2420           buf = (void *) (((char *) buf) + writen);
2421           size -= writen;
2422         }
2423     }
2424   return 0;
2425 }
2426
2427
2428 static gpg_error_t
2429 cmd_genkey (assuan_context_t ctx, char *line)
2430 {
2431   struct server *server = assuan_get_pointer (ctx);
2432   gpg_error_t err;
2433   assuan_fd_t inp_fd;
2434   assuan_fd_t out_fd;
2435   gpgme_data_t inp_data;
2436   gpgme_data_t out_data = NULL;
2437   gpgme_data_t parms_data = NULL;
2438   const char *parms;
2439
2440   inp_fd = assuan_get_input_fd (ctx);
2441   if (inp_fd == ASSUAN_INVALID_FD)
2442     return GPG_ERR_ASS_NO_INPUT;
2443   out_fd = assuan_get_output_fd (ctx);
2444   
2445   err = server_data_obj (inp_fd, server->input_enc, &inp_data);
2446   if (err)
2447     return err;
2448   if (out_fd != ASSUAN_INVALID_FD)
2449     {
2450       err = server_data_obj (out_fd, server->output_enc, &out_data);
2451       if (err)
2452         {
2453           gpgme_data_release (inp_data);
2454           return err;
2455         }
2456     }
2457
2458   /* Convert input data.  */
2459   err = gpgme_data_new (&parms_data);
2460   if (err)
2461     goto out;
2462   do
2463     {
2464       char buf[512];
2465       ssize_t readn = gpgme_data_read (inp_data, buf, sizeof (buf));
2466       if (readn < 0)
2467         {
2468           err = gpg_error_from_syserror ();
2469           goto out;
2470         }
2471       else if (readn == 0)
2472         break;
2473
2474       err = _cmd_genkey_write (parms_data, buf, readn);
2475       if (err)
2476         goto out;
2477     }
2478   while (1);
2479   err = _cmd_genkey_write (parms_data, "", 1);
2480   if (err)
2481     goto out;
2482   parms = gpgme_data_release_and_get_mem (parms_data, NULL);
2483   parms_data = NULL;
2484   if (! parms)
2485     {
2486       err = gpg_error (GPG_ERR_GENERAL);
2487       goto out;
2488     }
2489
2490   err = gt_genkey (server->gt, parms, out_data, NULL);
2491
2492   server_reset_fds (server);
2493
2494  out:
2495   gpgme_data_release (inp_data);
2496   if (out_data)
2497     gpgme_data_release (out_data);
2498   if (parms_data)
2499     gpgme_data_release (parms_data);
2500
2501   return err; 
2502 }
2503
2504
2505 static gpg_error_t
2506 cmd_delete (assuan_context_t ctx, char *line)
2507 {
2508   struct server *server = assuan_get_pointer (ctx);
2509   int allow_secret = 0;
2510   const char optstr[] = "--allow-secret ";
2511
2512   if (strncasecmp (line, optstr, strlen (optstr)))
2513     {
2514       allow_secret = 1;
2515       line += strlen (optstr);
2516     }
2517   return gt_delete (server->gt, line, allow_secret);
2518 }
2519
2520
2521 static gpg_error_t
2522 cmd_keylist (assuan_context_t ctx, char *line)
2523 {
2524   struct server *server = assuan_get_pointer (ctx);
2525   gpg_error_t err;
2526   int secret_only = 0;
2527   const char *pattern[2];
2528   const char optstr[] = "--secret-only ";
2529
2530   if (strncasecmp (line, optstr, strlen (optstr)))
2531     {
2532       secret_only = 1;
2533       line += strlen (optstr);
2534     }
2535   pattern[0] = line;
2536   pattern[1] = NULL;
2537
2538   err = gt_keylist_start (server->gt, pattern, secret_only);
2539   while (! err)
2540     {
2541       gpgme_key_t key;
2542
2543       err = gt_keylist_next (server->gt, &key);
2544       if (gpg_err_code (err) == GPG_ERR_EOF)
2545         {
2546           err = 0;
2547           break;
2548         }
2549       else if (! err)
2550         {
2551           char buf[100];
2552           /* FIXME: More data.  */
2553           snprintf (buf, sizeof (buf), "key:%s\n", key->subkeys->fpr);
2554           assuan_send_data (ctx, buf, strlen (buf));
2555           gpgme_key_unref (key);
2556         }
2557     }
2558   
2559   server_reset_fds (server);
2560
2561   return err;
2562 }
2563
2564
2565 static const char hlp_getauditlog[] = 
2566   "GETAUDITLOG [--html] [--with-help]\n"
2567   "\n"
2568   "Call the function gpgme_op_getauditlog with the given flags.  Write\n"
2569   "the output to the object set by the last OUTPUT command.";
2570 static gpg_error_t
2571 cmd_getauditlog (assuan_context_t ctx, char *line)
2572 {
2573   struct server *server = assuan_get_pointer (ctx);
2574   gpg_error_t err;
2575   assuan_fd_t out_fd;
2576   gpgme_data_t out_data;
2577   unsigned int flags = 0;
2578
2579   out_fd = assuan_get_output_fd (ctx);
2580   if (out_fd == ASSUAN_INVALID_FD)
2581     return GPG_ERR_ASS_NO_OUTPUT;
2582   err = server_data_obj (out_fd, server->output_enc, &out_data);
2583   if (err)
2584     return err;
2585
2586   if (strstr (line, "--html"))
2587     flags |= GPGME_AUDITLOG_HTML;
2588   if (strstr (line, "--with-help"))
2589     flags |= GPGME_AUDITLOG_WITH_HELP;
2590
2591   err = gt_getauditlog (server->gt, out_data, flags);
2592
2593   gpgme_data_release (out_data);
2594   server_reset_fds (server);
2595
2596   return err;
2597 }
2598
2599
2600 static gpg_error_t
2601 cmd_vfs_mount (assuan_context_t ctx, char *line)
2602 {
2603   struct server *server = assuan_get_pointer (ctx);
2604   char *mount_dir;
2605   gpg_error_t err;
2606
2607   mount_dir = strchr (line, ' ');
2608   if (mount_dir)
2609     {
2610       *(mount_dir++) = '\0';
2611       while (*mount_dir == ' ')
2612         mount_dir++;
2613     }
2614
2615   err = gt_vfs_mount (server->gt, line, mount_dir, 0);
2616
2617   return err;
2618 }
2619
2620
2621 static gpg_error_t
2622 cmd_vfs_create (assuan_context_t ctx, char *line)
2623 {
2624   struct server *server = assuan_get_pointer (ctx);
2625   gpg_error_t err;
2626   char *end;
2627
2628   end = strchr (line, ' ');
2629   if (end)
2630     {
2631       *(end++) = '\0';
2632       while (*end == ' ')
2633         end++;
2634     }
2635
2636   err = gt_vfs_create (server->gt, line, 0);
2637
2638   return err;
2639 }
2640
2641
2642 static gpg_error_t
2643 cmd_passwd (assuan_context_t ctx, char *line)
2644 {
2645   struct server *server = assuan_get_pointer (ctx);
2646
2647   return gt_passwd (server->gt, line);
2648 }
2649
2650
2651
2652 static gpg_error_t
2653 cmd_result (assuan_context_t ctx, char *line)
2654 {
2655   struct server *server = assuan_get_pointer (ctx);
2656   return gt_result (server->gt, GT_RESULT_ALL);
2657 }
2658
2659
2660 /* STRERROR <err>  */
2661 static gpg_error_t
2662 cmd_strerror (assuan_context_t ctx, char *line)
2663 {
2664   gpg_error_t err;
2665   char buf[100];
2666
2667   err = atoi (line);
2668   snprintf (buf, sizeof (buf), "%s <%s>", gpgme_strerror (err),
2669             gpgme_strsource (err));
2670   return assuan_send_data (ctx, buf, strlen (buf));
2671 }
2672
2673
2674 static gpg_error_t
2675 cmd_pubkey_algo_name (assuan_context_t ctx, char *line)
2676 {
2677   gpgme_pubkey_algo_t algo;
2678   char buf[100];
2679
2680   algo = atoi (line);
2681   snprintf (buf, sizeof (buf), "%s", gpgme_pubkey_algo_name (algo));
2682   return assuan_send_data (ctx, buf, strlen (buf));
2683 }
2684
2685
2686 static gpg_error_t
2687 cmd_hash_algo_name (assuan_context_t ctx, char *line)
2688 {
2689   gpgme_hash_algo_t algo;
2690   char buf[100];
2691
2692   algo = atoi (line);
2693   snprintf (buf, sizeof (buf), "%s", gpgme_hash_algo_name (algo));
2694   return assuan_send_data (ctx, buf, strlen (buf));
2695 }
2696
2697
2698 /* Tell the assuan library about our commands.  */
2699 static gpg_error_t
2700 register_commands (assuan_context_t ctx)
2701 {
2702   gpg_error_t err;
2703   static struct {
2704     const char *name;
2705     assuan_handler_t handler;
2706     const char * const help;
2707   } table[] = {
2708     /* RESET, BYE are implicit.  */
2709     { "VERSION", cmd_version, hlp_version },
2710     /* TODO: Set engine info.  */
2711     { "ENGINE", cmd_engine },
2712     { "PROTOCOL", cmd_protocol, hlp_protocol },
2713     { "SUB_PROTOCOL", cmd_sub_protocol },
2714     { "ARMOR", cmd_armor },
2715     { "TEXTMODE", cmd_textmode },
2716     { "INCLUDE_CERTS", cmd_include_certs },
2717     { "KEYLIST_MODE", cmd_keylist_mode },
2718     { "INPUT", NULL }, 
2719     { "OUTPUT", NULL }, 
2720     { "MESSAGE", cmd_message },
2721     { "RECIPIENT", cmd_recipient },
2722     { "SIGNER", cmd_signer },
2723     { "SIGNERS_CLEAR", cmd_signers_clear },
2724      /* TODO: SIGNOTATION missing. */
2725      /* TODO: Could add wait interface if we allow more than one context */
2726      /* and add _START variants. */
2727      /* TODO: Could add data interfaces if we allow multiple data objects. */
2728     { "DECRYPT", cmd_decrypt },
2729     { "DECRYPT_VERIFY", cmd_decrypt_verify },
2730     { "ENCRYPT", cmd_encrypt },
2731     { "ENCRYPT_SIGN", cmd_sign_encrypt },
2732     { "SIGN_ENCRYPT", cmd_sign_encrypt },
2733     { "SIGN", cmd_sign },
2734     { "VERIFY", cmd_verify },
2735     { "IMPORT", cmd_import },
2736     { "EXPORT", cmd_export, hlp_export },
2737     { "GENKEY", cmd_genkey },
2738     { "DELETE", cmd_delete },
2739     /* TODO: EDIT, CARD_EDIT (with INQUIRE) */
2740     { "KEYLIST", cmd_keylist },
2741     { "LISTKEYS", cmd_keylist },
2742     /* TODO: TRUSTLIST, TRUSTLIST_EXT */
2743     { "GETAUDITLOG", cmd_getauditlog, hlp_getauditlog },
2744     /* TODO: ASSUAN */
2745     { "VFS_MOUNT", cmd_vfs_mount },
2746     { "MOUNT", cmd_vfs_mount },
2747     { "VFS_CREATE", cmd_vfs_create },
2748     { "CREATE", cmd_vfs_create },
2749     /* TODO: GPGCONF  */
2750     { "RESULT", cmd_result },
2751     { "STRERROR", cmd_strerror },
2752     { "PUBKEY_ALGO_NAME", cmd_pubkey_algo_name },
2753     { "HASH_ALGO_NAME", cmd_hash_algo_name },
2754     { "PASSWD", cmd_passwd, hlp_passwd },
2755     { NULL }
2756   };
2757   int idx;
2758
2759   for (idx = 0; table[idx].name; idx++)
2760     {
2761       err = assuan_register_command (ctx, table[idx].name, table[idx].handler,
2762                                      table[idx].help);
2763       if (err)
2764         return err;
2765     } 
2766   return 0;
2767 }
2768
2769
2770 /* TODO: password callback can do INQUIRE.  */
2771 void
2772 gpgme_server (gpgme_tool_t gt)
2773 {
2774   gpg_error_t err;
2775   assuan_fd_t filedes[2];
2776   struct server server;
2777   static const char hello[] = ("GPGME-Tool " VERSION " ready");
2778
2779   memset (&server, 0, sizeof (server));
2780   server.message_fd = -1;
2781   server.input_enc = GPGME_DATA_ENCODING_NONE;
2782   server.output_enc = GPGME_DATA_ENCODING_NONE;
2783   server.message_enc = GPGME_DATA_ENCODING_NONE;
2784
2785   server.gt = gt;
2786   gt->write_status = server_write_status;
2787   gt->write_status_hook = &server;
2788   gt->write_data = server_write_data;
2789   gt->write_data_hook = &server;
2790
2791   /* We use a pipe based server so that we can work from scripts.
2792      assuan_init_pipe_server will automagically detect when we are
2793      called with a socketpair and ignore FIELDES in this case. */
2794   filedes[0] = assuan_fdopen (0);
2795   filedes[1] = assuan_fdopen (1);
2796   err = assuan_new (&server.assuan_ctx);
2797   if (err)
2798     log_error (1, err, "can't create assuan context");
2799
2800   assuan_set_pointer (server.assuan_ctx, &server);
2801
2802   err = assuan_init_pipe_server (server.assuan_ctx, filedes);
2803   if (err)
2804     log_error (1, err, "can't initialize assuan server");
2805   err = register_commands (server.assuan_ctx);
2806   if (err)
2807     log_error (1, err, "can't register assuan commands");
2808   assuan_set_hello_line (server.assuan_ctx, hello);
2809
2810   assuan_register_reset_notify (server.assuan_ctx, reset_notify);
2811   assuan_register_input_notify (server.assuan_ctx, input_notify);
2812   assuan_register_output_notify (server.assuan_ctx, output_notify);
2813
2814 #define DBG_ASSUAN 0
2815   if (DBG_ASSUAN)
2816     assuan_set_log_stream (server.assuan_ctx, log_stream);
2817
2818   for (;;)
2819     {
2820       err = assuan_accept (server.assuan_ctx);
2821       if (err == -1)
2822         break;
2823       else if (err)
2824         {
2825           log_error (0, err, "assuan accept problem");
2826           break;
2827         }
2828       
2829       err = assuan_process (server.assuan_ctx);
2830       if (err)
2831         log_error (0, err, "assuan processing failed");
2832     }
2833
2834   assuan_release (server.assuan_ctx);
2835 }
2836
2837
2838 \f
2839 /* MAIN PROGRAM STARTS HERE.  */
2840
2841 const char *argp_program_version = VERSION;
2842 const char *argp_program_bug_address = "bug-gpgme@gnupg.org";
2843 error_t argp_err_exit_status = 1;
2844
2845 static char doc[] = "GPGME Tool -- invoke GPGME operations";
2846 static char args_doc[] = "COMMAND [OPTIONS...]";
2847
2848 static struct argp_option options[] = {
2849   { "server", 's', 0, 0, "Server mode" },
2850   { 0 }
2851 };
2852
2853 static error_t parse_options (int key, char *arg, struct argp_state *state);
2854 static struct argp argp = { options, parse_options, args_doc, doc };
2855
2856 struct args
2857 {
2858   enum { CMD_DEFAULT, CMD_SERVER } cmd;
2859 };
2860
2861 void
2862 args_init (struct args *args)
2863 {
2864   memset (args, '\0', sizeof (*args));
2865   args->cmd = CMD_DEFAULT;
2866 }
2867
2868
2869 static error_t
2870 parse_options (int key, char *arg, struct argp_state *state)
2871 {
2872   struct args *args = state->input;
2873
2874   switch (key)
2875     {
2876     case 's':
2877       args->cmd = CMD_SERVER;
2878       break;
2879 #if 0
2880     case ARGP_KEY_ARG:
2881       if (state->arg_num >= 2)
2882         argp_usage (state);
2883       printf ("Arg[%i] = %s\n", state->arg_num, arg);
2884       break;
2885     case ARGP_KEY_END:
2886       if (state->arg_num < 2)
2887         argp_usage (state);
2888       break;
2889 #endif
2890
2891     default:
2892       return ARGP_ERR_UNKNOWN;
2893     }
2894   return 0;
2895 }
2896
2897 \f
2898 int
2899 main (int argc, char *argv[])
2900 {
2901   struct args args;
2902   struct gpgme_tool gt;
2903
2904   setlocale (LC_ALL, "");
2905   gpgme_check_version (NULL);
2906   gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
2907 #ifdef LC_MESSAGES
2908   gpgme_set_locale (NULL, LC_MESSAGES, setlocale (LC_MESSAGES, NULL));
2909 #endif
2910   args_init (&args);
2911
2912   argp_parse (&argp, argc, argv, 0, 0, &args);
2913   log_init ();
2914
2915   gt_init (&gt);
2916
2917   switch (args.cmd)
2918     {
2919     case CMD_DEFAULT:
2920     case CMD_SERVER:
2921       gpgme_server (&gt);
2922       break;
2923     }
2924
2925   gpgme_release (gt.ctx);
2926
2927   return 0;
2928 }
2929