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