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