b1b2ab3e4be638f8c0b6bb85cf3208ab792fce8c
[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   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           if (inv_recp->fpr)
832             result_add_fpr (&state, "fpr", inv_recp->fpr);
833           result_add_error (&state, "reason", inv_recp->reason);
834           result_xml_tag_end (&state);
835           inv_recp = inv_recp->next;
836         }
837       result_xml_tag_end (&state);
838     }
839   result_xml_tag_end (&state);
840   
841   return 0;
842 }
843
844
845 gpg_error_t
846 result_decrypt_to_xml (gpgme_ctx_t ctx, int indent,
847                        result_xml_write_cb_t cb, void *hook)
848 {
849   struct result_xml_state state;
850   gpgme_decrypt_result_t res = gpgme_op_decrypt_result (ctx);
851   gpgme_recipient_t recp;
852
853   if (! res)
854     return 0;
855
856   result_init (&state, indent, cb, hook);
857   result_xml_tag_start (&state, "decrypt-result", NULL);
858
859   if (res->file_name)
860     {
861       result_xml_tag_start (&state, "file-name", NULL);
862       result_xml_tag_data (&state, res->file_name);
863       result_xml_tag_end (&state);
864     }
865   if (res->unsupported_algorithm)
866     {
867       result_xml_tag_start (&state, "unsupported-alogorithm", NULL);
868       result_xml_tag_data (&state, res->unsupported_algorithm);
869       result_xml_tag_end (&state);
870     }
871   if (res->wrong_key_usage)
872     {
873       result_xml_tag_start (&state, "wrong-key-usage", NULL);
874       result_xml_tag_end (&state);
875     }
876
877   recp = res->recipients;
878   if (recp)
879     {
880       result_xml_tag_start (&state, "recipients", NULL);
881       while (recp)
882         {
883           result_xml_tag_start (&state, "recipient", NULL);
884           result_add_keyid (&state, "keyid", recp->keyid);
885           result_add_pubkey_algo (&state, "pubkey-algo", recp->pubkey_algo);
886           result_add_error (&state, "status", recp->status);
887           result_xml_tag_end (&state);
888           recp = recp->next;
889         }
890       result_xml_tag_end (&state);
891     }
892   result_xml_tag_end (&state);
893   
894   return 0;
895 }
896
897
898 gpg_error_t
899 result_sign_to_xml (gpgme_ctx_t ctx, int indent,
900                     result_xml_write_cb_t cb, void *hook)
901 {
902   struct result_xml_state state;
903   gpgme_sign_result_t res = gpgme_op_sign_result (ctx);
904   gpgme_invalid_key_t inv_key;
905   gpgme_new_signature_t new_sig;
906
907   if (! res)
908     return 0;
909
910   result_init (&state, indent, cb, hook);
911   result_xml_tag_start (&state, "sign-result", NULL);
912
913   inv_key = res->invalid_signers;
914   if (inv_key)
915     {
916       result_xml_tag_start (&state, "invalid-signers", NULL);
917       
918       while (inv_key)
919         {
920           result_xml_tag_start (&state, "invalid-key", NULL);
921           if (inv_key->fpr)
922             result_add_fpr (&state, "fpr", inv_key->fpr);
923           result_add_error (&state, "reason", inv_key->reason);
924           result_xml_tag_end (&state);
925           inv_key = inv_key->next;
926         }
927       result_xml_tag_end (&state);
928     }
929
930   new_sig = res->signatures;
931   if (new_sig)
932     {
933       result_xml_tag_start (&state, "signatures", NULL);
934
935       while (new_sig)
936         {
937           result_xml_tag_start (&state, "new-signature", NULL);
938           result_add_sig_mode (&state, "type", new_sig->type);
939           result_add_pubkey_algo (&state, "pubkey-algo", new_sig->pubkey_algo);
940           result_add_hash_algo (&state, "hash-algo", new_sig->hash_algo);
941           result_add_timestamp (&state, "timestamp", new_sig->timestamp);
942           if (new_sig->fpr)
943             result_add_fpr (&state, "fpr", new_sig->fpr);
944           result_add_value (&state, "sig-class", new_sig->sig_class);
945
946           result_xml_tag_end (&state);
947           new_sig = new_sig->next;
948         }
949       result_xml_tag_end (&state);
950     }
951
952   result_xml_tag_end (&state);
953   
954   return 0;
955 }
956
957
958 gpg_error_t
959 result_verify_to_xml (gpgme_ctx_t ctx, int indent,
960                       result_xml_write_cb_t cb, void *hook)
961 {
962   struct result_xml_state state;
963   gpgme_verify_result_t res = gpgme_op_verify_result (ctx);
964   gpgme_signature_t sig;
965
966   if (! res)
967     return 0;
968
969   result_init (&state, indent, cb, hook);
970   result_xml_tag_start (&state, "verify-result", NULL);
971
972   if (res->file_name)
973     {
974       result_xml_tag_start (&state, "file-name", NULL);
975       result_xml_tag_data (&state, res->file_name);
976       result_xml_tag_end (&state);
977     }
978
979   sig = res->signatures;
980   if (sig)
981     {
982       result_xml_tag_start (&state, "signatures", NULL);
983
984       while (sig)
985         {
986           result_xml_tag_start (&state, "signature", NULL);
987           
988           /* FIXME: Could be done better. */
989           result_add_value (&state, "summary", sig->summary);
990           if (sig->fpr)
991             result_add_fpr (&state, "fpr", sig->fpr);
992           result_add_error (&state, "status", sig->status);
993           /* FIXME: notations */
994           result_add_timestamp (&state, "timestamp", sig->timestamp);
995           result_add_timestamp (&state, "exp-timestamp", sig->exp_timestamp);
996           result_add_value (&state, "wrong-key-usage", sig->wrong_key_usage);
997           result_add_value (&state, "pka-trust", sig->pka_trust);
998           result_add_value (&state, "chain-model", sig->chain_model);
999           result_add_value (&state, "validity", sig->validity);
1000           result_add_error (&state, "validity-reason", sig->validity_reason);
1001           result_add_pubkey_algo (&state, "pubkey-algo", sig->pubkey_algo);
1002           result_add_hash_algo (&state, "hash-algo", sig->hash_algo);
1003           if (sig->pka_address)
1004             result_add_string (&state, "pka_address", sig->pka_address);
1005           
1006           result_xml_tag_end (&state);
1007           sig = sig->next;
1008         }
1009       result_xml_tag_end (&state);
1010     }
1011
1012   result_xml_tag_end (&state);
1013   
1014   return 0;
1015 }
1016
1017
1018 gpg_error_t
1019 result_import_to_xml (gpgme_ctx_t ctx, int indent,
1020                       result_xml_write_cb_t cb, void *hook)
1021 {
1022   struct result_xml_state state;
1023   gpgme_import_result_t res = gpgme_op_import_result (ctx);
1024   gpgme_import_status_t stat;
1025
1026   if (! res)
1027     return 0;
1028
1029   result_init (&state, indent, cb, hook);
1030   result_xml_tag_start (&state, "import-result", NULL);
1031
1032   result_add_value (&state, "considered", res->considered);
1033   result_add_value (&state, "no-user-id", res->no_user_id);
1034   result_add_value (&state, "imported", res->imported);
1035   result_add_value (&state, "imported-rsa", res->imported_rsa);
1036   result_add_value (&state, "unchanged", res->unchanged);
1037   result_add_value (&state, "new-user-ids", res->new_user_ids);
1038   result_add_value (&state, "new-sub-keys", res->new_sub_keys);
1039   result_add_value (&state, "new-signatures", res->new_signatures);
1040   result_add_value (&state, "new-revocations", res->new_revocations);
1041   result_add_value (&state, "secret-read", res->secret_read);
1042   result_add_value (&state, "secret-imported", res->secret_imported);
1043   result_add_value (&state, "secret-unchanged", res->secret_unchanged);
1044   result_add_value (&state, "skipped-new-keys", res->skipped_new_keys);
1045   result_add_value (&state, "not-imported", res->not_imported);
1046
1047   stat = res->imports;
1048   if (stat)
1049     {
1050       result_xml_tag_start (&state, "imports", NULL);
1051       
1052       while (stat)
1053         {
1054           result_xml_tag_start (&state, "import-status", NULL);
1055
1056           if (stat->fpr)
1057             result_add_fpr (&state, "fpr", stat->fpr);
1058           result_add_error (&state, "result", stat->result);
1059           /* FIXME: Could be done better. */
1060           result_add_value (&state, "status", stat->status);
1061
1062           result_xml_tag_end (&state);
1063           stat = stat->next;
1064         }
1065       result_xml_tag_end (&state);
1066     }
1067
1068   result_xml_tag_end (&state);
1069   
1070   return 0;
1071 }
1072
1073
1074 gpg_error_t
1075 result_genkey_to_xml (gpgme_ctx_t ctx, int indent,
1076                       result_xml_write_cb_t cb, void *hook)
1077 {
1078   struct result_xml_state state;
1079   gpgme_genkey_result_t res = gpgme_op_genkey_result (ctx);
1080
1081   if (! res)
1082     return 0;
1083
1084   result_init (&state, indent, cb, hook);
1085   result_xml_tag_start (&state, "genkey-result", NULL);
1086
1087   result_add_value (&state, "primary", res->primary);
1088   result_add_value (&state, "sub", res->sub);
1089   if (res->fpr)
1090     result_add_fpr (&state, "fpr", res->fpr);
1091
1092   result_xml_tag_end (&state);
1093   
1094   return 0;
1095 }
1096
1097
1098 gpg_error_t
1099 result_keylist_to_xml (gpgme_ctx_t ctx, int indent,
1100                       result_xml_write_cb_t cb, void *hook)
1101 {
1102   struct result_xml_state state;
1103   gpgme_keylist_result_t res = gpgme_op_keylist_result (ctx);
1104
1105   if (! res)
1106     return 0;
1107
1108   result_init (&state, indent, cb, hook);
1109   result_xml_tag_start (&state, "keylist-result", NULL);
1110
1111   result_add_value (&state, "truncated", res->truncated);
1112
1113   result_xml_tag_end (&state);
1114   
1115   return 0;
1116 }
1117
1118
1119 gpg_error_t
1120 result_vfs_mount_to_xml (gpgme_ctx_t ctx, int indent,
1121                          result_xml_write_cb_t cb, void *hook)
1122 {
1123   struct result_xml_state state;
1124   gpgme_vfs_mount_result_t res = gpgme_op_vfs_mount_result (ctx);
1125
1126   if (! res)
1127     return 0;
1128
1129   result_init (&state, indent, cb, hook);
1130   result_xml_tag_start (&state, "vfs-mount-result", NULL);
1131
1132   result_add_string (&state, "mount-dir", res->mount_dir);
1133
1134   result_xml_tag_end (&state);
1135   
1136   return 0;
1137 }
1138
1139 \f
1140 typedef enum status
1141   {
1142     STATUS_PROTOCOL,
1143     STATUS_PROGRESS,
1144     STATUS_ENGINE,
1145     STATUS_ARMOR,
1146     STATUS_TEXTMODE,
1147     STATUS_INCLUDE_CERTS,
1148     STATUS_KEYLIST_MODE,
1149     STATUS_RECIPIENT,
1150     STATUS_ENCRYPT_RESULT
1151   } status_t;
1152
1153 const char *status_string[] =
1154   {
1155     "PROTOCOL",
1156     "PROGRESS",
1157     "ENGINE",
1158     "ARMOR",
1159     "TEXTMODE",
1160     "INCLUDE_CERTS",
1161     "KEYLIST_MODE",
1162     "RECIPIENT",
1163     "ENCRYPT_RESULT"
1164   };
1165
1166 struct gpgme_tool
1167 {
1168   gpgme_ctx_t ctx;
1169 #define MAX_RECIPIENTS 10
1170   gpgme_key_t recipients[MAX_RECIPIENTS + 1];
1171   int recipients_nr;
1172
1173   gpg_error_t (*write_status) (void *hook, const char *status, const char *msg);
1174   void *write_status_hook;
1175   gpg_error_t (*write_data) (void *hook, const void *buf, size_t len);
1176   void *write_data_hook;
1177 };
1178 typedef struct gpgme_tool *gpgme_tool_t;
1179
1180
1181 /* Forward declaration.  */
1182 void gt_write_status (gpgme_tool_t gt, 
1183                       status_t status, ...) GT_GCC_A_SENTINEL(0);
1184
1185 void
1186 _gt_progress_cb (void *opaque, const char *what,
1187                  int type, int current, int total)
1188 {
1189   gpgme_tool_t gt = opaque;
1190   char buf[100];
1191
1192   snprintf (buf, sizeof (buf), "0x%02x %i %i", type, current, total);
1193   gt_write_status (gt, STATUS_PROGRESS, what, buf, NULL);
1194 }
1195
1196
1197 gpg_error_t
1198 _gt_gpgme_new (gpgme_tool_t gt, gpgme_ctx_t *ctx)
1199 {
1200   gpg_error_t err;
1201
1202   err = gpgme_new (ctx);
1203   if (err)
1204     return err;
1205   gpgme_set_progress_cb (*ctx, _gt_progress_cb, gt);
1206   return 0;
1207 }
1208
1209
1210 void
1211 gt_init (gpgme_tool_t gt)
1212 {
1213   memset (gt, '\0', sizeof (*gt));
1214   gpg_error_t err;
1215
1216   err = _gt_gpgme_new (gt, &gt->ctx);
1217   if (err)
1218     log_error (1, err, "can't create gpgme context");
1219 }
1220
1221
1222 gpg_error_t
1223 gt_signers_add (gpgme_tool_t gt, const char *fpr)
1224 {
1225   gpg_error_t err;
1226   gpgme_key_t key;
1227
1228   err = gpgme_get_key (gt->ctx, fpr, &key, 0);
1229   if (err)
1230     return err;
1231
1232   return gpgme_signers_add (gt->ctx, key);
1233 }
1234
1235
1236 gpg_error_t
1237 gt_signers_clear (gpgme_tool_t gt)
1238 {
1239   gpgme_signers_clear (gt->ctx);
1240   return 0;
1241 }
1242
1243
1244 gpg_error_t
1245 gt_get_key (gpgme_tool_t gt, const char *pattern, gpgme_key_t *r_key)
1246 {
1247   gpgme_ctx_t ctx;
1248   gpgme_ctx_t listctx;
1249   gpgme_error_t err;
1250   gpgme_key_t key;
1251
1252   if (!gt || !r_key || !pattern)
1253     return gpg_error (GPG_ERR_INV_VALUE);
1254   
1255   ctx = gt->ctx;
1256
1257   err = gpgme_new (&listctx);
1258   if (err)
1259     return err;
1260
1261   {
1262     gpgme_protocol_t proto;
1263     gpgme_engine_info_t info;
1264
1265     /* Clone the relevant state.  */
1266     proto = gpgme_get_protocol (ctx);
1267     /* The g13 protocol does not allow keylisting, we need to choose
1268        something else.  */
1269     if (proto == GPGME_PROTOCOL_G13)
1270       proto = GPGME_PROTOCOL_OpenPGP;
1271
1272     gpgme_set_protocol (listctx, proto);
1273     gpgme_set_keylist_mode (listctx, gpgme_get_keylist_mode (ctx));
1274     info = gpgme_ctx_get_engine_info (ctx);
1275     while (info && info->protocol != proto)
1276       info = info->next;
1277     if (info)
1278       gpgme_ctx_set_engine_info (listctx, proto,
1279                                  info->file_name, info->home_dir);
1280   }
1281
1282   err = gpgme_op_keylist_start (listctx, pattern, 0);
1283   if (!err)
1284     err = gpgme_op_keylist_next (listctx, r_key);
1285   if (!err)
1286     {
1287     try_next_key:
1288       err = gpgme_op_keylist_next (listctx, &key);
1289       if (gpgme_err_code (err) == GPG_ERR_EOF)
1290         err = 0;
1291       else
1292         {
1293           if (!err
1294               && *r_key && (*r_key)->subkeys && (*r_key)->subkeys->fpr
1295               && key && key->subkeys && key->subkeys->fpr
1296               && !strcmp ((*r_key)->subkeys->fpr, key->subkeys->fpr))
1297             {
1298               /* The fingerprint is identical.  We assume that this is
1299                  the same key and don't mark it as an ambiguous.  This
1300                  problem may occur with corrupted keyrings and has
1301                  been noticed often with gpgsm.  In fact gpgsm uses a
1302                  similar hack to sort out such duplicates but it can't
1303                  do that while listing keys.  */
1304               gpgme_key_unref (key);
1305               goto try_next_key;
1306             }
1307           if (!err)
1308             {
1309               gpgme_key_unref (key);
1310               err = gpg_error (GPG_ERR_AMBIGUOUS_NAME);
1311             }
1312           gpgme_key_unref (*r_key);
1313         }
1314     }
1315   gpgme_release (listctx);
1316   
1317   if (! err)
1318     gt_write_status (gt, STATUS_RECIPIENT, 
1319                      ((*r_key)->subkeys && (*r_key)->subkeys->fpr) ? 
1320                      (*r_key)->subkeys->fpr : "invalid", NULL);
1321   return err;
1322 }
1323
1324
1325 gpg_error_t
1326 gt_recipients_add (gpgme_tool_t gt, const char *pattern)
1327 {
1328   gpg_error_t err;
1329   gpgme_key_t key;
1330
1331   if (gt->recipients_nr >= MAX_RECIPIENTS)
1332     return gpg_error_from_errno (ENOMEM);
1333
1334   if (gpgme_get_protocol (gt->ctx) == GPGME_PROTOCOL_UISERVER)
1335     err = gpgme_key_from_uid (&key, pattern);
1336   else
1337     err = gt_get_key (gt, pattern, &key);
1338   if (err)
1339     return err;
1340
1341   gt->recipients[gt->recipients_nr++] = key;
1342   return 0;
1343 }
1344
1345
1346 void
1347 gt_recipients_clear (gpgme_tool_t gt)
1348 {
1349   int idx;
1350
1351   for (idx = 0; idx < gt->recipients_nr; idx++)
1352     gpgme_key_unref (gt->recipients[idx]);
1353   memset (gt->recipients, '\0', gt->recipients_nr * sizeof (gpgme_key_t));
1354   gt->recipients_nr = 0;
1355 }
1356
1357
1358 gpg_error_t
1359 gt_reset (gpgme_tool_t gt)
1360 {
1361   gpg_error_t err;
1362   gpgme_ctx_t ctx;
1363   
1364   err = _gt_gpgme_new (gt, &ctx);
1365   if (err)
1366     return err;
1367
1368   gpgme_release (gt->ctx);
1369   gt->ctx = ctx;
1370   gt_recipients_clear (gt);
1371   return 0;
1372 }
1373
1374
1375 void
1376 gt_write_status (gpgme_tool_t gt, status_t status, ...)
1377 {
1378   va_list ap;
1379   const char *text;
1380   char buf[950];
1381   char *p;
1382   size_t n;
1383   gpg_error_t err;
1384
1385   va_start (ap, status);
1386   p = buf;
1387   n = 0;
1388   while ((text = va_arg (ap, const char *)))
1389     {
1390       if (n)
1391         {
1392           *p++ = ' ';
1393           n++;
1394         }
1395       while (*text && n < sizeof (buf) - 2)
1396         {
1397           *p++ = *text++;
1398           n++;
1399         }
1400     }
1401   *p = 0;
1402   va_end (ap);
1403
1404   err = gt->write_status (gt->write_status_hook, status_string[status], buf);
1405   if (err)
1406     log_error (1, err, "can't write status line");
1407 }
1408
1409
1410 gpg_error_t
1411 gt_write_data (gpgme_tool_t gt, const void *buf, size_t len)
1412 {
1413   return gt->write_data (gt->write_data_hook, buf, len);
1414 }
1415
1416
1417 gpg_error_t
1418 gt_get_engine_info (gpgme_tool_t gt, gpgme_protocol_t proto)
1419 {
1420   gpgme_engine_info_t info;
1421   info = gpgme_ctx_get_engine_info (gt->ctx);
1422   while (info)
1423     {
1424       if (proto == GPGME_PROTOCOL_UNKNOWN || proto == info->protocol)
1425         gt_write_status (gt, STATUS_ENGINE,
1426                          gpgme_get_protocol_name (info->protocol),
1427                          info->file_name, info->version,
1428                          info->req_version, info->home_dir, NULL);
1429       info = info->next;
1430     }
1431   return 0;
1432 }
1433
1434
1435 gpgme_protocol_t
1436 gt_protocol_from_name (const char *name)
1437 {
1438   if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_OpenPGP)))
1439     return GPGME_PROTOCOL_OpenPGP;
1440   if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_CMS)))
1441     return GPGME_PROTOCOL_CMS;
1442   if (! strcasecmp (name,gpgme_get_protocol_name (GPGME_PROTOCOL_GPGCONF)))
1443     return GPGME_PROTOCOL_GPGCONF;
1444   if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_ASSUAN)))
1445     return GPGME_PROTOCOL_ASSUAN;
1446   if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_G13)))
1447     return GPGME_PROTOCOL_G13;
1448   if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_UISERVER)))
1449     return GPGME_PROTOCOL_UISERVER;
1450   if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_DEFAULT)))
1451     return GPGME_PROTOCOL_DEFAULT;
1452   return GPGME_PROTOCOL_UNKNOWN;
1453 }
1454
1455   
1456 gpg_error_t
1457 gt_set_protocol (gpgme_tool_t gt, gpgme_protocol_t proto)
1458 {
1459   return gpgme_set_protocol (gt->ctx, proto);
1460 }
1461
1462
1463 gpg_error_t
1464 gt_get_protocol (gpgme_tool_t gt)
1465 {
1466   gpgme_protocol_t proto = gpgme_get_protocol (gt->ctx);
1467
1468   gt_write_status (gt, STATUS_PROTOCOL, gpgme_get_protocol_name (proto),
1469                    NULL);
1470
1471   return 0;
1472 }
1473
1474
1475 gpg_error_t
1476 gt_set_sub_protocol (gpgme_tool_t gt, gpgme_protocol_t proto)
1477 {
1478   return gpgme_set_sub_protocol (gt->ctx, proto);
1479 }
1480
1481
1482 gpg_error_t
1483 gt_get_sub_protocol (gpgme_tool_t gt)
1484 {
1485   gpgme_protocol_t proto = gpgme_get_sub_protocol (gt->ctx);
1486
1487   gt_write_status (gt, STATUS_PROTOCOL, gpgme_get_protocol_name (proto),
1488                    NULL);
1489
1490   return 0;
1491 }
1492
1493
1494 gpg_error_t
1495 gt_set_armor (gpgme_tool_t gt, int armor)
1496 {
1497   gpgme_set_armor (gt->ctx, armor);
1498   return 0;
1499 }
1500
1501
1502 gpg_error_t
1503 gt_get_armor (gpgme_tool_t gt)
1504 {
1505   gt_write_status (gt, STATUS_ARMOR,
1506                    gpgme_get_armor (gt->ctx) ? "true" : "false", NULL);
1507
1508   return 0;
1509 }
1510
1511
1512 gpg_error_t
1513 gt_set_textmode (gpgme_tool_t gt, int textmode)
1514 {
1515   gpgme_set_textmode (gt->ctx, textmode);
1516   return 0;
1517 }
1518
1519
1520 gpg_error_t
1521 gt_get_textmode (gpgme_tool_t gt)
1522 {
1523   gt_write_status (gt, STATUS_TEXTMODE,
1524                    gpgme_get_textmode (gt->ctx) ? "true" : "false", NULL);
1525
1526   return 0;
1527 }
1528
1529
1530 gpg_error_t
1531 gt_set_keylist_mode (gpgme_tool_t gt, gpgme_keylist_mode_t keylist_mode)
1532 {
1533   gpgme_set_keylist_mode (gt->ctx, keylist_mode);
1534   return 0;
1535 }
1536
1537
1538 gpg_error_t
1539 gt_get_keylist_mode (gpgme_tool_t gt)
1540 {
1541 #define NR_KEYLIST_MODES 6
1542   const char *modes[NR_KEYLIST_MODES + 1];
1543   int idx = 0;
1544   gpgme_keylist_mode_t mode = gpgme_get_keylist_mode (gt->ctx);
1545   
1546   if (mode & GPGME_KEYLIST_MODE_LOCAL)
1547     modes[idx++] = "local";
1548   if (mode & GPGME_KEYLIST_MODE_EXTERN)
1549     modes[idx++] = "extern";
1550   if (mode & GPGME_KEYLIST_MODE_SIGS)
1551     modes[idx++] = "sigs";
1552   if (mode & GPGME_KEYLIST_MODE_SIG_NOTATIONS)
1553     modes[idx++] = "sig_notations";
1554   if (mode & GPGME_KEYLIST_MODE_EPHEMERAL)
1555     modes[idx++] = "ephemeral";
1556   if (mode & GPGME_KEYLIST_MODE_VALIDATE)
1557     modes[idx++] = "validate";
1558   modes[idx++] = NULL;
1559
1560   gt_write_status (gt, STATUS_KEYLIST_MODE, modes[0], modes[1], modes[2],
1561                    modes[3], modes[4], modes[5], modes[6], NULL);
1562
1563   return 0;
1564 }
1565
1566
1567 gpg_error_t
1568 gt_set_include_certs (gpgme_tool_t gt, int include_certs)
1569 {
1570   gpgme_set_include_certs (gt->ctx, include_certs);
1571   return 0;
1572 }
1573
1574
1575 gpg_error_t
1576 gt_get_include_certs (gpgme_tool_t gt)
1577 {
1578   int include_certs = gpgme_get_include_certs (gt->ctx);
1579   char buf[100];
1580
1581   if (include_certs == GPGME_INCLUDE_CERTS_DEFAULT)
1582     strcpy (buf, "default");
1583   else
1584     snprintf (buf, sizeof (buf), "%i", include_certs);
1585
1586   gt_write_status (gt, STATUS_INCLUDE_CERTS, buf, NULL);
1587
1588   return 0;
1589 }
1590
1591
1592 gpg_error_t
1593 gt_decrypt_verify (gpgme_tool_t gt, gpgme_data_t cipher, gpgme_data_t plain,
1594                    int verify)
1595 {
1596   if (verify)
1597     return gpgme_op_decrypt_verify (gt->ctx, cipher, plain);
1598   else
1599     return gpgme_op_decrypt (gt->ctx, cipher, plain);
1600 }
1601
1602
1603 gpg_error_t
1604 gt_sign_encrypt (gpgme_tool_t gt, gpgme_encrypt_flags_t flags,
1605                  gpgme_data_t plain, gpgme_data_t cipher, int sign)
1606 {
1607   gpg_error_t err;
1608
1609   if (sign)
1610     err = gpgme_op_encrypt_sign (gt->ctx, gt->recipients, flags, plain, cipher);
1611   else
1612     err = gpgme_op_encrypt (gt->ctx, gt->recipients, flags, plain, cipher);
1613
1614   gt_recipients_clear (gt);
1615
1616   return err;
1617 }
1618
1619
1620 gpg_error_t
1621 gt_sign (gpgme_tool_t gt, gpgme_data_t plain, gpgme_data_t sig,
1622          gpgme_sig_mode_t mode)
1623 {
1624   return gpgme_op_sign (gt->ctx, plain, sig, mode);
1625 }
1626
1627
1628 gpg_error_t
1629 gt_verify (gpgme_tool_t gt, gpgme_data_t sig, gpgme_data_t sig_text,
1630            gpgme_data_t plain)
1631 {
1632   return gpgme_op_verify (gt->ctx, sig, sig_text, plain);
1633 }
1634
1635
1636 gpg_error_t
1637 gt_import (gpgme_tool_t gt, gpgme_data_t data)
1638 {
1639   return gpgme_op_import (gt->ctx, data);
1640 }
1641
1642
1643 gpg_error_t
1644 gt_export (gpgme_tool_t gt, const char *pattern[], gpgme_export_mode_t mode,
1645            gpgme_data_t data)
1646 {
1647   return gpgme_op_export_ext (gt->ctx, pattern, mode, data);
1648 }
1649
1650
1651 gpg_error_t
1652 gt_genkey (gpgme_tool_t gt, const char *parms, gpgme_data_t public,
1653            gpgme_data_t secret)
1654 {
1655   return gpgme_op_genkey (gt->ctx, parms, public, secret);
1656 }
1657
1658
1659 gpg_error_t
1660 gt_import_keys (gpgme_tool_t gt, char *fpr[])
1661 {
1662   gpg_error_t err = 0;
1663   int cnt;
1664   int idx;
1665   gpgme_key_t *keys;
1666   
1667   cnt = 0;
1668   while (fpr[cnt])
1669     cnt++;
1670   
1671   if (! cnt)
1672     return gpg_error (GPG_ERR_INV_VALUE);
1673
1674   keys = malloc ((cnt + 1) * sizeof (gpgme_key_t));
1675   if (! keys)
1676     return gpg_error_from_syserror ();
1677   
1678   for (idx = 0; idx < cnt; idx++)
1679     {
1680       err = gpgme_get_key (gt->ctx, fpr[idx], &keys[idx], 0);
1681       if (err)
1682         break;
1683     }
1684   if (! err)
1685     {
1686       keys[cnt] = NULL;
1687       err = gpgme_op_import_keys (gt->ctx, keys);
1688     }
1689   
1690   /* Rollback.  */
1691   while (--idx >= 0)
1692     gpgme_key_unref (keys[idx]);
1693   free (keys);
1694
1695   return err;
1696 }
1697
1698
1699 gpg_error_t
1700 gt_delete (gpgme_tool_t gt, char *fpr, int allow_secret)
1701 {
1702   gpg_error_t err;
1703   gpgme_key_t key;
1704
1705   err = gpgme_get_key (gt->ctx, fpr, &key, 0);
1706   if (err)
1707     return err;
1708
1709   err = gpgme_op_delete (gt->ctx, key, allow_secret);
1710   gpgme_key_unref (key);
1711   return err;
1712 }
1713
1714
1715 gpg_error_t
1716 gt_keylist_start (gpgme_tool_t gt, const char *pattern[], int secret_only)
1717 {
1718   return gpgme_op_keylist_ext_start (gt->ctx, pattern, secret_only, 0);
1719 }
1720
1721
1722 gpg_error_t
1723 gt_keylist_next (gpgme_tool_t gt, gpgme_key_t *key)
1724 {
1725   return gpgme_op_keylist_next (gt->ctx, key);
1726 }
1727
1728
1729 gpg_error_t
1730 gt_getauditlog (gpgme_tool_t gt, gpgme_data_t output, unsigned int flags)
1731 {
1732   return gpgme_op_getauditlog (gt->ctx, output, flags);
1733 }
1734
1735
1736 gpg_error_t
1737 gt_vfs_mount (gpgme_tool_t gt, const char *container_file,
1738               const char *mount_dir, int flags)
1739 {
1740   gpg_error_t err;
1741   gpg_error_t op_err;
1742   err = gpgme_op_vfs_mount (gt->ctx, container_file, mount_dir, flags, &op_err);
1743   return err ? err : op_err;
1744 }
1745
1746
1747 gpg_error_t
1748 gt_vfs_create (gpgme_tool_t gt, const char *container_file, int flags)
1749 {
1750   gpg_error_t err;
1751   gpg_error_t op_err;
1752   err = gpgme_op_vfs_create (gt->ctx, gt->recipients, container_file,
1753                              flags, &op_err);
1754   gt_recipients_clear (gt);
1755   return err ? err : op_err;
1756 }
1757
1758
1759 static const char hlp_passwd[] = 
1760   "PASSWD <user-id>\n"
1761   "\n"
1762   "Ask the backend to change the passphrase for the key\n"
1763   "specified by USER-ID.";
1764 gpg_error_t
1765 gt_passwd (gpgme_tool_t gt, char *fpr)
1766 {
1767   gpg_error_t err;
1768   gpgme_key_t key;
1769
1770   err = gpgme_get_key (gt->ctx, fpr, &key, 0);
1771   if (err)
1772     return gpg_err_code (err) == GPG_ERR_EOF? gpg_error (GPG_ERR_NO_PUBKEY):err;
1773
1774   err = gpgme_op_passwd (gt->ctx, key, 0);
1775   gpgme_key_unref (key);
1776   return err;
1777 }
1778
1779
1780 #define GT_RESULT_ENCRYPT 0x1
1781 #define GT_RESULT_DECRYPT 0x2
1782 #define GT_RESULT_SIGN 0x4
1783 #define GT_RESULT_VERIFY 0x8
1784 #define GT_RESULT_IMPORT 0x10
1785 #define GT_RESULT_GENKEY 0x20
1786 #define GT_RESULT_KEYLIST 0x40
1787 #define GT_RESULT_VFS_MOUNT 0x80
1788 #define GT_RESULT_ALL (~0U)
1789
1790 gpg_error_t
1791 gt_result (gpgme_tool_t gt, unsigned int flags)
1792 {
1793   static const char xml_preamble1[] = "<?xml version=\"1.0\" "
1794     "encoding=\"UTF-8\" standalone=\"yes\"?>\n";
1795   static const char xml_preamble2[] = "<gpgme>\n";
1796   static const char xml_end[] = "</gpgme>\n";
1797   int indent = 2;
1798
1799   gt_write_data (gt, xml_preamble1, sizeof (xml_preamble1));
1800   gt_write_data (gt, NULL, 0);
1801   gt_write_data (gt, xml_preamble2, sizeof (xml_preamble2));
1802   gt_write_data (gt, NULL, 0);
1803   if (flags & GT_RESULT_ENCRYPT)
1804     result_encrypt_to_xml (gt->ctx, indent,
1805                            (result_xml_write_cb_t) gt_write_data, gt);
1806   if (flags & GT_RESULT_DECRYPT)
1807     result_decrypt_to_xml (gt->ctx, indent,
1808                            (result_xml_write_cb_t) gt_write_data, gt);
1809   if (flags & GT_RESULT_SIGN)
1810     result_sign_to_xml (gt->ctx, indent,
1811                         (result_xml_write_cb_t) gt_write_data, gt);
1812   if (flags & GT_RESULT_VERIFY)
1813     result_verify_to_xml (gt->ctx, indent,
1814                           (result_xml_write_cb_t) gt_write_data, gt);
1815   if (flags & GT_RESULT_IMPORT)
1816     result_import_to_xml (gt->ctx, indent,
1817                           (result_xml_write_cb_t) gt_write_data, gt);
1818   if (flags & GT_RESULT_GENKEY)
1819     result_genkey_to_xml (gt->ctx, indent,
1820                           (result_xml_write_cb_t) gt_write_data, gt);
1821   if (flags & GT_RESULT_KEYLIST)
1822     result_keylist_to_xml (gt->ctx, indent,
1823                            (result_xml_write_cb_t) gt_write_data, gt);
1824   if (flags & GT_RESULT_VFS_MOUNT)
1825     result_vfs_mount_to_xml (gt->ctx, indent,
1826                              (result_xml_write_cb_t) gt_write_data, gt);
1827   gt_write_data (gt, xml_end, sizeof (xml_end));
1828
1829   return 0;
1830 }
1831
1832 \f
1833 /* GPGME SERVER.  */
1834
1835 #include <assuan.h>
1836
1837 struct server
1838 {
1839   gpgme_tool_t gt;
1840   assuan_context_t assuan_ctx;
1841
1842   gpgme_data_encoding_t input_enc;
1843   gpgme_data_encoding_t output_enc;
1844   assuan_fd_t input_fd;
1845   char *input_filename;
1846   FILE *input_stream;
1847   assuan_fd_t output_fd;
1848   char *output_filename;
1849   FILE *output_stream;
1850   assuan_fd_t message_fd;
1851   char *message_filename;
1852   FILE *message_stream;
1853   gpgme_data_encoding_t message_enc;
1854 };
1855
1856
1857 gpg_error_t
1858 server_write_status (void *hook, const char *status, const char *msg)
1859 {
1860   struct server *server = hook;
1861   return assuan_write_status (server->assuan_ctx, status, msg);
1862 }
1863
1864
1865 gpg_error_t
1866 server_write_data (void *hook, const void *buf, size_t len)
1867 {
1868   struct server *server = hook;
1869   return assuan_send_data (server->assuan_ctx, buf, len);
1870 }
1871
1872
1873
1874 static gpg_error_t
1875 server_parse_fd (assuan_context_t ctx, char *line, assuan_fd_t *rfd,
1876                  char **filename)
1877 {
1878   *rfd = ASSUAN_INVALID_FD;
1879   *filename = NULL;
1880
1881   if (! strncasecmp (line, "file=", 5))
1882     {
1883       char *term;
1884       *filename = strdup (line + 5);
1885       if (!*filename)
1886         return gpg_error_from_syserror();
1887       term = strchr (*filename, ' ');
1888       if (term)
1889         *term = '\0';
1890       return 0;
1891     }
1892   else
1893     return assuan_command_parse_fd (ctx, line, rfd);
1894 }
1895     
1896
1897 static gpgme_data_encoding_t
1898 server_data_encoding (const char *line)
1899 {
1900   if (strstr (line, "--binary"))
1901     return GPGME_DATA_ENCODING_BINARY;
1902   if (strstr (line, "--base64"))
1903     return GPGME_DATA_ENCODING_BASE64;
1904   if (strstr (line, "--armor"))
1905     return GPGME_DATA_ENCODING_ARMOR;
1906   if (strstr (line, "--url"))
1907     return GPGME_DATA_ENCODING_URL;
1908   if (strstr (line, "--urlesc"))
1909     return GPGME_DATA_ENCODING_URLESC;
1910   if (strstr (line, "--url0"))
1911     return GPGME_DATA_ENCODING_URL0;
1912   return GPGME_DATA_ENCODING_NONE;
1913 }
1914
1915
1916 static gpgme_error_t
1917 server_data_obj (assuan_fd_t fd, char *fn, int out,
1918                  gpgme_data_encoding_t encoding,
1919                  gpgme_data_t *data, FILE **fs)
1920 {
1921   gpgme_error_t err;
1922
1923   *fs = NULL;
1924   if (fn)
1925     {
1926       *fs = fopen (fn, out ? "wb" : "rb");
1927       if (!*fs)
1928         return gpg_error_from_syserror ();
1929
1930       err = gpgme_data_new_from_stream (data, *fs);
1931     }
1932   else
1933     err = gpgme_data_new_from_fd (data, (int) fd);
1934
1935   if (err)
1936     return err;
1937   return gpgme_data_set_encoding (*data, encoding);
1938 }
1939
1940
1941 void
1942 server_reset_fds (struct server *server)
1943 {
1944   /* assuan closes the input and output FDs for us when doing a RESET,
1945      but we use this same function after commands, so repeat it
1946      here.  */
1947   assuan_close_input_fd (server->assuan_ctx);
1948   assuan_close_output_fd (server->assuan_ctx);
1949   if (server->message_fd != ASSUAN_INVALID_FD)
1950     {
1951       /* FIXME: Assuan should provide a close function.  */
1952 #if HAVE_W32_SYSTEM
1953       CloseHandle (server->message_fd);
1954 #else
1955       close (server->message_fd);
1956 #endif
1957       server->message_fd = ASSUAN_INVALID_FD;
1958     }
1959   if (server->input_filename)
1960     {
1961       free (server->input_filename);
1962       server->input_filename = NULL;
1963     }
1964   if (server->output_filename)
1965     {
1966       free (server->output_filename);
1967       server->output_filename = NULL;
1968     }
1969   if (server->message_filename)
1970     {
1971       free (server->message_filename);
1972       server->message_filename = NULL;
1973     }
1974   if (server->input_stream)
1975     {
1976       fclose (server->input_stream);
1977       server->input_stream = NULL;
1978     }
1979   if (server->output_stream)
1980     {
1981       fclose (server->output_stream);
1982       server->output_stream = NULL;
1983     }
1984   if (server->message_stream)
1985     {
1986       fclose (server->message_stream);
1987       server->message_stream = NULL;
1988     }
1989
1990   server->input_enc = GPGME_DATA_ENCODING_NONE;
1991   server->output_enc = GPGME_DATA_ENCODING_NONE;
1992   server->message_enc = GPGME_DATA_ENCODING_NONE;
1993 }
1994
1995
1996 static gpg_error_t
1997 reset_notify (assuan_context_t ctx, char *line)
1998 {
1999   struct server *server = assuan_get_pointer (ctx);
2000   server_reset_fds (server);
2001   gt_reset (server->gt);
2002   return 0;
2003 }
2004
2005
2006 static const char hlp_version[] = 
2007   "VERSION [<string>]\n"
2008   "\n"
2009   "Call the function gpgme_check_version.";
2010 static gpg_error_t
2011 cmd_version (assuan_context_t ctx, char *line)
2012 {
2013   if (line && *line)
2014     {
2015       const char *version = gpgme_check_version (line);
2016       return version ? 0 : gpg_error (GPG_ERR_SELFTEST_FAILED);
2017     }
2018   else
2019     {
2020       const char *version = gpgme_check_version (NULL);
2021       return assuan_send_data (ctx, version, strlen (version));
2022     }
2023 }
2024
2025
2026 static gpg_error_t
2027 cmd_engine (assuan_context_t ctx, char *line)
2028 {
2029   struct server *server = assuan_get_pointer (ctx);
2030   return gt_get_engine_info (server->gt, gt_protocol_from_name (line));
2031 }
2032
2033
2034 static const char hlp_protocol[] = 
2035   "PROTOCOL [<name>]\n"
2036   "\n"
2037   "With NAME, set the protocol.  Without return the current protocol.";
2038 static gpg_error_t
2039 cmd_protocol (assuan_context_t ctx, char *line)
2040 {
2041   struct server *server = assuan_get_pointer (ctx);
2042   if (line && *line)
2043     return gt_set_protocol (server->gt, gt_protocol_from_name (line));
2044   else
2045     return gt_get_protocol (server->gt);
2046 }
2047
2048
2049 static gpg_error_t
2050 cmd_sub_protocol (assuan_context_t ctx, char *line)
2051 {
2052   struct server *server = assuan_get_pointer (ctx);
2053   if (line && *line)
2054     return gt_set_sub_protocol (server->gt, gt_protocol_from_name (line));
2055   else
2056     return gt_get_sub_protocol (server->gt);
2057 }
2058
2059
2060 static gpg_error_t
2061 cmd_armor (assuan_context_t ctx, char *line)
2062 {
2063   struct server *server = assuan_get_pointer (ctx);
2064   if (line && *line)
2065     {
2066       int flag = 0;
2067       
2068       if (! strcasecmp (line, "true") || ! strcasecmp (line, "yes")
2069           || line[0] == '1')
2070         flag = 1;
2071       
2072       return gt_set_armor (server->gt, flag);
2073     }
2074   else
2075     return gt_get_armor (server->gt);
2076 }
2077
2078
2079 static gpg_error_t
2080 cmd_textmode (assuan_context_t ctx, char *line)
2081 {
2082   struct server *server = assuan_get_pointer (ctx);
2083   if (line && *line)
2084     {
2085       int flag = 0;
2086
2087       if (! strcasecmp (line, "true") || ! strcasecmp (line, "yes")
2088           || line[0] == '1')
2089         flag = 1;
2090       
2091       return gt_set_textmode (server->gt, flag);
2092     }
2093   else
2094     return gt_get_textmode (server->gt);
2095 }
2096
2097
2098 static gpg_error_t
2099 cmd_include_certs (assuan_context_t ctx, char *line)
2100 {
2101   struct server *server = assuan_get_pointer (ctx);
2102
2103   if (line && *line)
2104     {
2105       int include_certs = 0;
2106       
2107       if (! strcasecmp (line, "default"))
2108         include_certs = GPGME_INCLUDE_CERTS_DEFAULT;
2109       else
2110         include_certs = atoi (line);
2111       
2112       return gt_set_include_certs (server->gt, include_certs);
2113     }
2114   else
2115     return gt_get_include_certs (server->gt);
2116 }
2117
2118
2119 static gpg_error_t
2120 cmd_keylist_mode (assuan_context_t ctx, char *line)
2121 {
2122   struct server *server = assuan_get_pointer (ctx);
2123
2124   if (line && *line)
2125     {
2126       gpgme_keylist_mode_t mode = 0;
2127       
2128       if (strstr (line, "local"))
2129         mode |= GPGME_KEYLIST_MODE_LOCAL;
2130       if (strstr (line, "extern"))
2131         mode |= GPGME_KEYLIST_MODE_EXTERN;
2132       if (strstr (line, "sigs"))
2133         mode |= GPGME_KEYLIST_MODE_SIGS;
2134       if (strstr (line, "sig_notations"))
2135         mode |= GPGME_KEYLIST_MODE_SIG_NOTATIONS;
2136       if (strstr (line, "ephemeral"))
2137         mode |= GPGME_KEYLIST_MODE_EPHEMERAL;
2138       if (strstr (line, "validate"))
2139         mode |= GPGME_KEYLIST_MODE_VALIDATE;
2140       
2141       return gt_set_keylist_mode (server->gt, mode);
2142     }
2143   else
2144     return gt_get_keylist_mode (server->gt);
2145 }
2146
2147
2148 static gpg_error_t
2149 cmd_input (assuan_context_t ctx, char *line)
2150 {
2151   struct server *server = assuan_get_pointer (ctx);
2152   gpg_error_t err;
2153   assuan_fd_t sysfd;
2154   char *filename;
2155
2156   err = server_parse_fd (ctx, line, &sysfd, &filename);
2157   if (err)
2158     return err;
2159   server->input_fd = sysfd;
2160   server->input_filename = filename;
2161   server->input_enc = server_data_encoding (line);
2162   return 0;
2163 }
2164
2165
2166 static gpg_error_t
2167 cmd_output (assuan_context_t ctx, char *line)
2168 {
2169   struct server *server = assuan_get_pointer (ctx);
2170   gpg_error_t err;
2171   assuan_fd_t sysfd;
2172   char *filename;
2173
2174   err = server_parse_fd (ctx, line, &sysfd, &filename);
2175   if (err)
2176     return err;
2177   server->output_fd = sysfd;
2178   server->output_filename = filename;
2179   server->output_enc = server_data_encoding (line);
2180   return 0;
2181 }
2182
2183
2184 static gpg_error_t
2185 cmd_message (assuan_context_t ctx, char *line)
2186 {
2187   struct server *server = assuan_get_pointer (ctx);
2188   gpg_error_t err;
2189   assuan_fd_t sysfd;
2190   char *filename;
2191
2192   err = server_parse_fd (ctx, line, &sysfd, &filename);
2193   if (err)
2194     return err;
2195   server->message_fd = sysfd;
2196   server->message_filename = filename;
2197   server->message_enc = server_data_encoding (line);
2198   return 0;
2199 }
2200
2201
2202 static gpg_error_t
2203 cmd_recipient (assuan_context_t ctx, char *line)
2204 {
2205   struct server *server = assuan_get_pointer (ctx);
2206
2207   return gt_recipients_add (server->gt, line);
2208 }
2209
2210
2211 static gpg_error_t
2212 cmd_signer (assuan_context_t ctx, char *line)
2213 {
2214   struct server *server = assuan_get_pointer (ctx);
2215
2216   return gt_signers_add (server->gt, line);
2217 }
2218
2219
2220 static gpg_error_t
2221 cmd_signers_clear (assuan_context_t ctx, char *line)
2222 {
2223   struct server *server = assuan_get_pointer (ctx);
2224
2225   return gt_signers_clear (server->gt);
2226 }
2227
2228
2229 static gpg_error_t
2230 _cmd_decrypt_verify (assuan_context_t ctx, char *line, int verify)
2231 {
2232   struct server *server = assuan_get_pointer (ctx);
2233   gpg_error_t err;
2234   assuan_fd_t inp_fd;
2235   char *inp_fn;
2236   assuan_fd_t out_fd;
2237   char *out_fn;
2238   gpgme_data_t inp_data;
2239   gpgme_data_t out_data;
2240
2241   inp_fd = assuan_get_input_fd (ctx);
2242   inp_fn = server->input_filename;
2243   if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
2244     return GPG_ERR_ASS_NO_INPUT;
2245   out_fd = assuan_get_output_fd (ctx);
2246   out_fn = server->output_filename;
2247   if (out_fd == ASSUAN_INVALID_FD && !out_fn)
2248     return GPG_ERR_ASS_NO_OUTPUT;
2249   
2250   err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2251                          &server->input_stream);
2252   if (err)
2253     return err;
2254   err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2255                          &server->output_stream);
2256   if (err)
2257     {
2258       gpgme_data_release (inp_data);
2259       return err;
2260     }
2261
2262   err = gt_decrypt_verify (server->gt, inp_data, out_data, verify); 
2263
2264   gpgme_data_release (inp_data);
2265   gpgme_data_release (out_data);
2266
2267   server_reset_fds (server);
2268
2269   return err;
2270 }
2271
2272
2273 static gpg_error_t
2274 cmd_decrypt (assuan_context_t ctx, char *line)
2275 {
2276   return _cmd_decrypt_verify (ctx, line, 0);
2277 }
2278
2279
2280 static gpg_error_t
2281 cmd_decrypt_verify (assuan_context_t ctx, char *line)
2282 {
2283   return _cmd_decrypt_verify (ctx, line, 1);
2284 }
2285
2286
2287 static gpg_error_t
2288 _cmd_sign_encrypt (assuan_context_t ctx, char *line, int sign)
2289 {
2290   struct server *server = assuan_get_pointer (ctx);
2291   gpg_error_t err;
2292   assuan_fd_t inp_fd;
2293   char *inp_fn;
2294   assuan_fd_t out_fd;
2295   char *out_fn;
2296   gpgme_data_t inp_data = NULL;
2297   gpgme_data_t out_data = NULL;
2298   gpgme_encrypt_flags_t flags = 0;
2299
2300   if (strstr (line, "--always-trust"))
2301     flags |= GPGME_ENCRYPT_ALWAYS_TRUST;
2302   if (strstr (line, "--no-encrypt-to"))
2303     flags |= GPGME_ENCRYPT_NO_ENCRYPT_TO;
2304   if (strstr (line, "--prepare"))
2305     flags |= GPGME_ENCRYPT_PREPARE;
2306   if (strstr (line, "--expect-sign"))
2307     flags |= GPGME_ENCRYPT_EXPECT_SIGN;
2308   
2309   inp_fd = assuan_get_input_fd (ctx);
2310   inp_fn = server->input_filename;
2311   out_fd = assuan_get_output_fd (ctx);
2312   out_fn = server->output_filename;
2313   if (inp_fd != ASSUAN_INVALID_FD || inp_fn)
2314     {
2315       err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2316                              &server->input_stream);
2317       if (err)
2318         return err;
2319     }
2320   if (out_fd != ASSUAN_INVALID_FD || out_fn)
2321     {
2322       err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2323                              &server->output_stream);
2324       if (err)
2325         {
2326           gpgme_data_release (inp_data);
2327           return err;
2328         }
2329     }
2330
2331   err = gt_sign_encrypt (server->gt, flags, inp_data, out_data, sign); 
2332
2333   gpgme_data_release (inp_data);
2334   gpgme_data_release (out_data);
2335
2336   server_reset_fds (server);
2337
2338   return err;
2339 }
2340
2341
2342 static gpg_error_t
2343 cmd_encrypt (assuan_context_t ctx, char *line)
2344 {
2345   return _cmd_sign_encrypt (ctx, line, 0);
2346 }
2347
2348
2349 static gpg_error_t
2350 cmd_sign_encrypt (assuan_context_t ctx, char *line)
2351 {
2352   return _cmd_sign_encrypt (ctx, line, 1);
2353 }
2354
2355
2356 static gpg_error_t
2357 cmd_sign (assuan_context_t ctx, char *line)
2358 {
2359   struct server *server = assuan_get_pointer (ctx);
2360   gpg_error_t err;
2361   assuan_fd_t inp_fd;
2362   char *inp_fn;
2363   assuan_fd_t out_fd;
2364   char *out_fn;
2365   gpgme_data_t inp_data;
2366   gpgme_data_t out_data;
2367   gpgme_sig_mode_t mode = GPGME_SIG_MODE_NORMAL;
2368
2369   if (strstr (line, "--clear"))
2370     mode = GPGME_SIG_MODE_CLEAR;
2371   if (strstr (line, "--detach"))
2372     mode = GPGME_SIG_MODE_DETACH;
2373
2374   inp_fd = assuan_get_input_fd (ctx);
2375   inp_fn = server->input_filename;
2376   if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
2377     return GPG_ERR_ASS_NO_INPUT;
2378   out_fd = assuan_get_output_fd (ctx);
2379   out_fn = server->output_filename;
2380   if (out_fd == ASSUAN_INVALID_FD && !out_fn)
2381     return GPG_ERR_ASS_NO_OUTPUT;
2382   
2383   err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2384                          &server->input_stream);
2385   if (err)
2386     return err;
2387   err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2388                          &server->output_stream);
2389   if (err)
2390     {
2391       gpgme_data_release (inp_data);
2392       return err;
2393     }
2394
2395   err = gt_sign (server->gt, inp_data, out_data, mode);
2396
2397   gpgme_data_release (inp_data);
2398   gpgme_data_release (out_data);
2399   server_reset_fds (server);
2400
2401   return err;
2402 }
2403
2404
2405 static gpg_error_t
2406 cmd_verify (assuan_context_t ctx, char *line)
2407 {
2408   struct server *server = assuan_get_pointer (ctx);
2409   gpg_error_t err;
2410   assuan_fd_t inp_fd;
2411   assuan_fd_t msg_fd;
2412   assuan_fd_t out_fd;
2413   char *inp_fn;
2414   char *msg_fn;
2415   char *out_fn;
2416   gpgme_data_t inp_data;
2417   gpgme_data_t msg_data = NULL;
2418   gpgme_data_t out_data = NULL;
2419
2420   inp_fd = assuan_get_input_fd (ctx);
2421   inp_fn = server->input_filename;
2422   if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
2423     return GPG_ERR_ASS_NO_INPUT;
2424   msg_fd = server->message_fd;
2425   msg_fn = server->message_filename;
2426   out_fd = assuan_get_output_fd (ctx);
2427   out_fn = server->output_filename;
2428
2429   err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2430                          &server->input_stream);
2431   if (err)
2432     return err;
2433   if (msg_fd != ASSUAN_INVALID_FD || msg_fn)
2434     {
2435       err = server_data_obj (msg_fd, msg_fn, 0, server->message_enc, &msg_data,
2436                              &server->message_stream);
2437       if (err)
2438         {
2439           gpgme_data_release (inp_data);
2440           return err;
2441         }
2442     }
2443   if (out_fd != ASSUAN_INVALID_FD || out_fn)
2444     {
2445       err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2446                              &server->output_stream);
2447       if (err)
2448         {
2449           gpgme_data_release (inp_data);
2450           gpgme_data_release (msg_data);
2451           return err;
2452         }
2453     }
2454
2455   err = gt_verify (server->gt, inp_data, msg_data, out_data);
2456
2457   gpgme_data_release (inp_data);
2458   if (msg_data)
2459     gpgme_data_release (msg_data);
2460   if (out_data)
2461     gpgme_data_release (out_data);
2462
2463   server_reset_fds (server);
2464
2465   return err;
2466 }
2467
2468
2469 static gpg_error_t
2470 cmd_import (assuan_context_t ctx, char *line)
2471 {
2472   struct server *server = assuan_get_pointer (ctx);
2473   
2474   if (line && *line)
2475     {
2476       char *fprs[2] = { line, NULL };
2477
2478       return gt_import_keys (server->gt, fprs);
2479     }
2480   else
2481     {
2482       gpg_error_t err;
2483       assuan_fd_t inp_fd;
2484       char *inp_fn;
2485       gpgme_data_t inp_data;
2486       
2487       inp_fd = assuan_get_input_fd (ctx);
2488       inp_fn = server->input_filename;
2489       if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
2490         return GPG_ERR_ASS_NO_INPUT;
2491
2492       err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2493                              &server->input_stream);
2494       if (err)
2495         return err;
2496       
2497       err = gt_import (server->gt, inp_data); 
2498       
2499       gpgme_data_release (inp_data);
2500       server_reset_fds (server);
2501
2502       return err;
2503     }
2504 }
2505
2506
2507 static const char hlp_export[] = 
2508   "EXPORT [--extern] [--minimal] [<pattern>]\n"
2509   "\n"
2510   "Export the keys described by PATTERN.  Write the\n"
2511   "the output to the object set by the last OUTPUT command.";
2512 static gpg_error_t
2513 cmd_export (assuan_context_t ctx, char *line)
2514 {
2515   struct server *server = assuan_get_pointer (ctx);
2516   gpg_error_t err;
2517   assuan_fd_t out_fd;
2518   char *out_fn;
2519   gpgme_data_t out_data;
2520   gpgme_export_mode_t mode = 0;
2521   const char *pattern[2];
2522
2523   out_fd = assuan_get_output_fd (ctx);
2524   out_fn = server->output_filename;
2525   if (out_fd == ASSUAN_INVALID_FD && !out_fn)
2526     return GPG_ERR_ASS_NO_OUTPUT;
2527   err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2528                          &server->output_stream);
2529   if (err)
2530     return err;
2531
2532   if (has_option (line, "--extern"))
2533     mode |= GPGME_EXPORT_MODE_EXTERN;
2534   if (has_option (line, "--minimal"))
2535     mode |= GPGME_EXPORT_MODE_MINIMAL;
2536
2537   line = skip_options (line);
2538
2539   pattern[0] = line;
2540   pattern[1] = NULL;
2541
2542   err = gt_export (server->gt, pattern, mode, out_data);
2543
2544   gpgme_data_release (out_data);
2545   server_reset_fds (server);
2546
2547   return err;
2548 }
2549
2550
2551 static gpg_error_t
2552 _cmd_genkey_write (gpgme_data_t data, const void *buf, size_t size)
2553 {
2554   while (size > 0)
2555     {
2556       ssize_t writen = gpgme_data_write (data, buf, size);
2557       if (writen < 0 && errno != EAGAIN)
2558         return gpg_error_from_syserror ();
2559       else if (writen > 0)
2560         {
2561           buf = (void *) (((char *) buf) + writen);
2562           size -= writen;
2563         }
2564     }
2565   return 0;
2566 }
2567
2568
2569 static gpg_error_t
2570 cmd_genkey (assuan_context_t ctx, char *line)
2571 {
2572   struct server *server = assuan_get_pointer (ctx);
2573   gpg_error_t err;
2574   assuan_fd_t inp_fd;
2575   char *inp_fn;
2576   assuan_fd_t out_fd;
2577   char *out_fn;
2578   gpgme_data_t inp_data;
2579   gpgme_data_t out_data = NULL;
2580   gpgme_data_t parms_data = NULL;
2581   const char *parms;
2582
2583   inp_fd = assuan_get_input_fd (ctx);
2584   inp_fn = server->input_filename;
2585   if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
2586     return GPG_ERR_ASS_NO_INPUT;
2587   out_fd = assuan_get_output_fd (ctx);
2588   out_fn = server->output_filename;
2589   
2590   err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2591                          &server->input_stream);
2592   if (err)
2593     return err;
2594   if (out_fd != ASSUAN_INVALID_FD || out_fn)
2595     {
2596       err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2597                              &server->output_stream);
2598       if (err)
2599         {
2600           gpgme_data_release (inp_data);
2601           return err;
2602         }
2603     }
2604
2605   /* Convert input data.  */
2606   err = gpgme_data_new (&parms_data);
2607   if (err)
2608     goto out;
2609   do
2610     {
2611       char buf[512];
2612       ssize_t readn = gpgme_data_read (inp_data, buf, sizeof (buf));
2613       if (readn < 0)
2614         {
2615           err = gpg_error_from_syserror ();
2616           goto out;
2617         }
2618       else if (readn == 0)
2619         break;
2620
2621       err = _cmd_genkey_write (parms_data, buf, readn);
2622       if (err)
2623         goto out;
2624     }
2625   while (1);
2626   err = _cmd_genkey_write (parms_data, "", 1);
2627   if (err)
2628     goto out;
2629   parms = gpgme_data_release_and_get_mem (parms_data, NULL);
2630   parms_data = NULL;
2631   if (! parms)
2632     {
2633       err = gpg_error (GPG_ERR_GENERAL);
2634       goto out;
2635     }
2636
2637   err = gt_genkey (server->gt, parms, out_data, NULL);
2638
2639   server_reset_fds (server);
2640
2641  out:
2642   gpgme_data_release (inp_data);
2643   if (out_data)
2644     gpgme_data_release (out_data);
2645   if (parms_data)
2646     gpgme_data_release (parms_data);
2647
2648   return err; 
2649 }
2650
2651
2652 static gpg_error_t
2653 cmd_delete (assuan_context_t ctx, char *line)
2654 {
2655   struct server *server = assuan_get_pointer (ctx);
2656   int allow_secret = 0;
2657   const char optstr[] = "--allow-secret";
2658
2659   if (!strncasecmp (line, optstr, strlen (optstr)))
2660     {
2661       allow_secret = 1;
2662       line += strlen (optstr);
2663       while (*line && !spacep (line))
2664         line++;
2665     }
2666   return gt_delete (server->gt, line, allow_secret);
2667 }
2668
2669
2670 static gpg_error_t
2671 cmd_keylist (assuan_context_t ctx, char *line)
2672 {
2673   struct server *server = assuan_get_pointer (ctx);
2674   gpg_error_t err;
2675   int secret_only = 0;
2676   const char *pattern[2];
2677   const char optstr[] = "--secret-only";
2678
2679   if (!strncasecmp (line, optstr, strlen (optstr)))
2680     {
2681       secret_only = 1;
2682       line += strlen (optstr);
2683       while (*line && !spacep (line))
2684         line++;
2685     }
2686   pattern[0] = line;
2687   pattern[1] = NULL;
2688
2689   err = gt_keylist_start (server->gt, pattern, secret_only);
2690   while (! err)
2691     {
2692       gpgme_key_t key;
2693
2694       err = gt_keylist_next (server->gt, &key);
2695       if (gpg_err_code (err) == GPG_ERR_EOF)
2696         {
2697           err = 0;
2698           break;
2699         }
2700       else if (! err)
2701         {
2702           char buf[100];
2703           /* FIXME: More data.  */
2704           snprintf (buf, sizeof (buf), "key:%s\n", key->subkeys->fpr);
2705           assuan_send_data (ctx, buf, strlen (buf));
2706           gpgme_key_unref (key);
2707         }
2708     }
2709   
2710   server_reset_fds (server);
2711
2712   return err;
2713 }
2714
2715
2716 static const char hlp_getauditlog[] = 
2717   "GETAUDITLOG [--html] [--with-help]\n"
2718   "\n"
2719   "Call the function gpgme_op_getauditlog with the given flags.  Write\n"
2720   "the output to the object set by the last OUTPUT command.";
2721 static gpg_error_t
2722 cmd_getauditlog (assuan_context_t ctx, char *line)
2723 {
2724   struct server *server = assuan_get_pointer (ctx);
2725   gpg_error_t err;
2726   assuan_fd_t out_fd;
2727   char *out_fn;
2728   gpgme_data_t out_data;
2729   unsigned int flags = 0;
2730
2731   out_fd = assuan_get_output_fd (ctx);
2732   out_fn = server->output_filename;
2733   if (out_fd == ASSUAN_INVALID_FD && !out_fn)
2734     return GPG_ERR_ASS_NO_OUTPUT;
2735   err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2736                          &server->output_stream);
2737   if (err)
2738     return err;
2739
2740   if (strstr (line, "--html"))
2741     flags |= GPGME_AUDITLOG_HTML;
2742   if (strstr (line, "--with-help"))
2743     flags |= GPGME_AUDITLOG_WITH_HELP;
2744
2745   err = gt_getauditlog (server->gt, out_data, flags);
2746
2747   gpgme_data_release (out_data);
2748   server_reset_fds (server);
2749
2750   return err;
2751 }
2752
2753
2754 static gpg_error_t
2755 cmd_vfs_mount (assuan_context_t ctx, char *line)
2756 {
2757   struct server *server = assuan_get_pointer (ctx);
2758   char *mount_dir;
2759   gpg_error_t err;
2760
2761   mount_dir = strchr (line, ' ');
2762   if (mount_dir)
2763     {
2764       *(mount_dir++) = '\0';
2765       while (*mount_dir == ' ')
2766         mount_dir++;
2767     }
2768
2769   err = gt_vfs_mount (server->gt, line, mount_dir, 0);
2770
2771   return err;
2772 }
2773
2774
2775 static gpg_error_t
2776 cmd_vfs_create (assuan_context_t ctx, char *line)
2777 {
2778   struct server *server = assuan_get_pointer (ctx);
2779   gpg_error_t err;
2780   char *end;
2781
2782   end = strchr (line, ' ');
2783   if (end)
2784     {
2785       *(end++) = '\0';
2786       while (*end == ' ')
2787         end++;
2788     }
2789
2790   err = gt_vfs_create (server->gt, line, 0);
2791
2792   return err;
2793 }
2794
2795
2796 static gpg_error_t
2797 cmd_passwd (assuan_context_t ctx, char *line)
2798 {
2799   struct server *server = assuan_get_pointer (ctx);
2800
2801   return gt_passwd (server->gt, line);
2802 }
2803
2804
2805
2806 static gpg_error_t
2807 cmd_result (assuan_context_t ctx, char *line)
2808 {
2809   struct server *server = assuan_get_pointer (ctx);
2810   return gt_result (server->gt, GT_RESULT_ALL);
2811 }
2812
2813
2814 /* STRERROR <err>  */
2815 static gpg_error_t
2816 cmd_strerror (assuan_context_t ctx, char *line)
2817 {
2818   gpg_error_t err;
2819   char buf[100];
2820
2821   err = atoi (line);
2822   snprintf (buf, sizeof (buf), "%s <%s>", gpgme_strerror (err),
2823             gpgme_strsource (err));
2824   return assuan_send_data (ctx, buf, strlen (buf));
2825 }
2826
2827
2828 static gpg_error_t
2829 cmd_pubkey_algo_name (assuan_context_t ctx, char *line)
2830 {
2831   gpgme_pubkey_algo_t algo;
2832   char buf[100];
2833
2834   algo = atoi (line);
2835   snprintf (buf, sizeof (buf), "%s", gpgme_pubkey_algo_name (algo));
2836   return assuan_send_data (ctx, buf, strlen (buf));
2837 }
2838
2839
2840 static gpg_error_t
2841 cmd_hash_algo_name (assuan_context_t ctx, char *line)
2842 {
2843   gpgme_hash_algo_t algo;
2844   char buf[100];
2845
2846   algo = atoi (line);
2847   snprintf (buf, sizeof (buf), "%s", gpgme_hash_algo_name (algo));
2848   return assuan_send_data (ctx, buf, strlen (buf));
2849 }
2850
2851
2852 /* Tell the assuan library about our commands.  */
2853 static gpg_error_t
2854 register_commands (assuan_context_t ctx)
2855 {
2856   gpg_error_t err;
2857   static struct {
2858     const char *name;
2859     assuan_handler_t handler;
2860     const char * const help;
2861   } table[] = {
2862     /* RESET, BYE are implicit.  */
2863     { "VERSION", cmd_version, hlp_version },
2864     /* TODO: Set engine info.  */
2865     { "ENGINE", cmd_engine },
2866     { "PROTOCOL", cmd_protocol, hlp_protocol },
2867     { "SUB_PROTOCOL", cmd_sub_protocol },
2868     { "ARMOR", cmd_armor },
2869     { "TEXTMODE", cmd_textmode },
2870     { "INCLUDE_CERTS", cmd_include_certs },
2871     { "KEYLIST_MODE", cmd_keylist_mode },
2872     { "INPUT", cmd_input }, 
2873     { "OUTPUT", cmd_output }, 
2874     { "MESSAGE", cmd_message },
2875     { "RECIPIENT", cmd_recipient },
2876     { "SIGNER", cmd_signer },
2877     { "SIGNERS_CLEAR", cmd_signers_clear },
2878      /* TODO: SIGNOTATION missing. */
2879      /* TODO: Could add wait interface if we allow more than one context */
2880      /* and add _START variants. */
2881      /* TODO: Could add data interfaces if we allow multiple data objects. */
2882     { "DECRYPT", cmd_decrypt },
2883     { "DECRYPT_VERIFY", cmd_decrypt_verify },
2884     { "ENCRYPT", cmd_encrypt },
2885     { "ENCRYPT_SIGN", cmd_sign_encrypt },
2886     { "SIGN_ENCRYPT", cmd_sign_encrypt },
2887     { "SIGN", cmd_sign },
2888     { "VERIFY", cmd_verify },
2889     { "IMPORT", cmd_import },
2890     { "EXPORT", cmd_export, hlp_export },
2891     { "GENKEY", cmd_genkey },
2892     { "DELETE", cmd_delete },
2893     /* TODO: EDIT, CARD_EDIT (with INQUIRE) */
2894     { "KEYLIST", cmd_keylist },
2895     { "LISTKEYS", cmd_keylist },
2896     /* TODO: TRUSTLIST, TRUSTLIST_EXT */
2897     { "GETAUDITLOG", cmd_getauditlog, hlp_getauditlog },
2898     /* TODO: ASSUAN */
2899     { "VFS_MOUNT", cmd_vfs_mount },
2900     { "MOUNT", cmd_vfs_mount },
2901     { "VFS_CREATE", cmd_vfs_create },
2902     { "CREATE", cmd_vfs_create },
2903     /* TODO: GPGCONF  */
2904     { "RESULT", cmd_result },
2905     { "STRERROR", cmd_strerror },
2906     { "PUBKEY_ALGO_NAME", cmd_pubkey_algo_name },
2907     { "HASH_ALGO_NAME", cmd_hash_algo_name },
2908     { "PASSWD", cmd_passwd, hlp_passwd },
2909     { NULL }
2910   };
2911   int idx;
2912
2913   for (idx = 0; table[idx].name; idx++)
2914     {
2915       err = assuan_register_command (ctx, table[idx].name, table[idx].handler,
2916                                      table[idx].help);
2917       if (err)
2918         return err;
2919     } 
2920   return 0;
2921 }
2922
2923
2924 /* TODO: password callback can do INQUIRE.  */
2925 void
2926 gpgme_server (gpgme_tool_t gt)
2927 {
2928   gpg_error_t err;
2929   assuan_fd_t filedes[2];
2930   struct server server;
2931   static const char hello[] = ("GPGME-Tool " VERSION " ready");
2932
2933   memset (&server, 0, sizeof (server));
2934   server.message_fd = ASSUAN_INVALID_FD;
2935   server.input_enc = GPGME_DATA_ENCODING_NONE;
2936   server.output_enc = GPGME_DATA_ENCODING_NONE;
2937   server.message_enc = GPGME_DATA_ENCODING_NONE;
2938
2939   server.gt = gt;
2940   gt->write_status = server_write_status;
2941   gt->write_status_hook = &server;
2942   gt->write_data = server_write_data;
2943   gt->write_data_hook = &server;
2944
2945   /* We use a pipe based server so that we can work from scripts.
2946      assuan_init_pipe_server will automagically detect when we are
2947      called with a socketpair and ignore FIELDES in this case. */
2948 #ifdef HAVE_W32CE_SYSTEM
2949   filedes[0] = ASSUAN_STDIN;
2950   filedes[1] = ASSUAN_STDOUT;
2951 #else
2952   filedes[0] = assuan_fdopen (0);
2953   filedes[1] = assuan_fdopen (1);
2954 #endif
2955   err = assuan_new (&server.assuan_ctx);
2956   if (err)
2957     log_error (1, err, "can't create assuan context");
2958
2959   assuan_set_pointer (server.assuan_ctx, &server);
2960
2961   err = assuan_init_pipe_server (server.assuan_ctx, filedes);
2962   if (err)
2963     log_error (1, err, "can't initialize assuan server");
2964   err = register_commands (server.assuan_ctx);
2965   if (err)
2966     log_error (1, err, "can't register assuan commands");
2967   assuan_set_hello_line (server.assuan_ctx, hello);
2968
2969   assuan_register_reset_notify (server.assuan_ctx, reset_notify);
2970
2971 #define DBG_ASSUAN 0
2972   if (DBG_ASSUAN)
2973     assuan_set_log_stream (server.assuan_ctx, log_stream);
2974
2975   for (;;)
2976     {
2977       err = assuan_accept (server.assuan_ctx);
2978       if (err == -1)
2979         break;
2980       else if (err)
2981         {
2982           log_error (0, err, "assuan accept problem");
2983           break;
2984         }
2985       
2986       err = assuan_process (server.assuan_ctx);
2987       if (err)
2988         log_error (0, err, "assuan processing failed");
2989     }
2990
2991   assuan_release (server.assuan_ctx);
2992 }
2993
2994
2995 \f
2996 /* MAIN PROGRAM STARTS HERE.  */
2997
2998 const char *argp_program_version = VERSION;
2999 const char *argp_program_bug_address = "bug-gpgme@gnupg.org";
3000 error_t argp_err_exit_status = 1;
3001
3002 static char doc[] = "GPGME Tool -- invoke GPGME operations";
3003 static char args_doc[] = "COMMAND [OPTIONS...]";
3004
3005 static struct argp_option options[] = {
3006   { "server", 's', 0, 0, "Server mode" },
3007   { 0 }
3008 };
3009
3010 static error_t parse_options (int key, char *arg, struct argp_state *state);
3011 static struct argp argp = { options, parse_options, args_doc, doc };
3012
3013 struct args
3014 {
3015   enum { CMD_DEFAULT, CMD_SERVER } cmd;
3016 };
3017
3018 void
3019 args_init (struct args *args)
3020 {
3021   memset (args, '\0', sizeof (*args));
3022   args->cmd = CMD_DEFAULT;
3023 }
3024
3025
3026 static error_t
3027 parse_options (int key, char *arg, struct argp_state *state)
3028 {
3029   struct args *args = state->input;
3030
3031   switch (key)
3032     {
3033     case 's':
3034       args->cmd = CMD_SERVER;
3035       break;
3036 #if 0
3037     case ARGP_KEY_ARG:
3038       if (state->arg_num >= 2)
3039         argp_usage (state);
3040       printf ("Arg[%i] = %s\n", state->arg_num, arg);
3041       break;
3042     case ARGP_KEY_END:
3043       if (state->arg_num < 2)
3044         argp_usage (state);
3045       break;
3046 #endif
3047
3048     default:
3049       return ARGP_ERR_UNKNOWN;
3050     }
3051   return 0;
3052 }
3053
3054 \f
3055 int
3056 main (int argc, char *argv[])
3057 {
3058   struct args args;
3059   struct gpgme_tool gt;
3060
3061 #ifdef HAVE_SETLOCALE
3062   setlocale (LC_ALL, "");
3063 #endif
3064   gpgme_check_version (NULL);
3065 #ifdef LC_CTYPE
3066   gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
3067 #endif
3068 #ifdef LC_MESSAGES
3069   gpgme_set_locale (NULL, LC_MESSAGES, setlocale (LC_MESSAGES, NULL));
3070 #endif
3071
3072   args_init (&args);
3073
3074   argp_parse (&argp, argc, argv, 0, 0, &args);
3075   log_init ();
3076
3077   gt_init (&gt);
3078
3079   switch (args.cmd)
3080     {
3081     case CMD_DEFAULT:
3082     case CMD_SERVER:
3083       gpgme_server (&gt);
3084       break;
3085     }
3086
3087   gpgme_release (gt.ctx);
3088
3089 #ifdef HAVE_W32CE_SYSTEM
3090   /* Give the buggy ssh server time to flush the output buffers.  */
3091   Sleep (300);
3092 #endif
3093
3094   return 0;
3095 }
3096