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