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