2009-11-25 Marcus Brinkmann <marcus@g10code.de>
[gpgme.git] / src / gpgme-tool.c
1 /* gpgme-tool.c - GnuPG Made Easy.
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007 g10 Code GmbH
4
5    This file is part of GPGME.
6  
7    GPGME is free software; you can redistribute it and/or modify it
8    under the terms of the GNU Lesser General Public License as
9    published by the Free Software Foundation; either version 2.1 of
10    the License, or (at your option) any later version.
11    
12    GPGME is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    Lesser General Public License for more details.
16    
17    You should have received a copy of the GNU Lesser General Public
18    License along with this program; if not, write to the Free Software
19    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20    02111-1307, USA.  */
21
22 #if HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <getopt.h>
31 #include <ctype.h>
32 #include <stdarg.h>
33 #include <locale.h>
34 #ifdef HAVE_ARGP_H
35 #include <argp.h>
36 #endif
37
38 #include <assuan.h>
39
40 #include "gpgme.h"
41
42 \f
43 #ifndef HAVE_ARGP_H
44 /* Minimal argp implementation.  */
45
46 /* Differences to ARGP:
47    argp_program_version: Required.
48    argp_program_bug_address: Required.
49    argp_program_version_hook: Not supported.
50    argp_err_exit_status: Required.
51    struct argp: Children and help_filter not supported.
52    argp_domain: Not supported.
53    struct argp_option: Group not supported.  Options are printed in
54    order given.  Flags OPTION_ALIAS, OPTION_DOC and OPTION_NO_USAGE
55    are not supported.
56    argp_parse: No flags are supported (ARGP_PARSE_ARGV0, ARGP_NO_ERRS,
57    ARGP_NO_ARGS, ARGP_IN_ORDER, ARGP_NO_HELP, ARGP_NO_EXIT,
58    ARGP_LONG_ONLY, ARGP_SILENT).  ARGP must not be NULL.
59    argp_help: Flag ARGP_HELP_LONG_ONLY not supported.
60    argp_state: argc, argv, next may not be modified and should not be used.  */
61
62 extern const char *argp_program_version;
63 extern const char *argp_program_bug_address;
64 extern error_t argp_err_exit_status;
65
66 struct argp_option
67 {
68   const char *name;
69   int key;
70   const char *arg;
71 #define OPTION_ARG_OPTIONAL 0x1
72 #define OPTION_HIDDEN 0x2
73   int flags;
74   const char *doc;
75   int group;
76 };
77
78 struct argp;
79 struct argp_state
80 {
81   const struct argp *const root_argp;
82   int argc;
83   char **argv;
84   int next;
85   unsigned flags;
86   unsigned arg_num;
87   int quoted;
88   void *input;
89   void **child_inputs;
90   void *hook;
91   char *name;
92   FILE *err_stream;
93   FILE *out_stream;
94   void *pstate;
95 };
96
97 #define ARGP_ERR_UNKNOWN E2BIG
98 #define ARGP_KEY_ARG 0
99 #define ARGP_KEY_ARGS 0x1000006
100 #define ARGP_KEY_END 0x1000001
101 #define ARGP_KEY_NO_ARGS 0x1000002
102 #define ARGP_KEY_INIT 0x1000003
103 #define ARGP_KEY_FINI 0x1000007
104 #define ARGP_KEY_SUCCESS 0x1000004
105 #define ARGP_KEY_ERROR 0x1000005
106 typedef error_t (*argp_parser_t) (int key, char *arg, struct argp_state *state);
107
108 struct argp
109 {
110   const struct argp_option *options;
111   argp_parser_t parser;
112   const char *args_doc;
113   const char *doc;
114
115   const struct argp_child *children;
116   char *(*help_filter) (int key, const char *text, void *input);
117   const char *argp_domain;
118 };
119
120 #define ARGP_HELP_USAGE ARGP_HELP_SHORT_USAGE
121 #define ARGP_HELP_SHORT_USAGE 0x02
122 #define ARGP_HELP_SEE 0x04
123 #define ARGP_HELP_LONG 0x08
124 #define ARGP_HELP_PRE_DOC 0x10
125 #define ARGP_HELP_POST_DOC 0x20
126 #define ARGP_HELP_DOC (ARGP_HELP_PRE_DOC | ARGP_HELP_POST_DOC)
127 #define ARGP_HELP_BUG_ADDR 0x40
128 #define ARGP_HELP_EXIT_ERR 0x100
129 #define ARGP_HELP_EXIT_OK 0x200
130 #define ARGP_HELP_STD_ERR (ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR)
131 #define ARGP_HELP_STD_USAGE \
132   (ARGP_HELP_SHORT_USAGE | ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR)
133 #define ARGP_HELP_STD_HELP \
134   (ARGP_HELP_SHORT_USAGE | ARGP_HELP_LONG | ARGP_HELP_EXIT_OK   \
135    | ARGP_HELP_DOC | ARGP_HELP_BUG_ADDR)
136
137
138 char *
139 _argp_pname (char *name)
140 {
141   char *pname = name;
142   char *bname = strrchr (pname, '/');
143   if (! bname)
144     bname = strrchr (pname, '\\');
145   if (bname)
146     pname = bname + 1;
147   return pname;
148 }
149
150
151 void
152 _argp_state_help (const struct argp *argp, const struct argp_state *state,
153                   FILE *stream, unsigned flags, char *name)
154 {
155   if (state)
156     name = state->name;
157
158   if (flags & ARGP_HELP_SHORT_USAGE)
159     fprintf (stream, "Usage: %s [OPTIONS...] %s\n", name, argp->args_doc);
160   if (flags & ARGP_HELP_SEE)
161     fprintf (stream, "Try `%s --help' or `%s --usage' for more information.\n",
162              name, name);
163   if (flags & ARGP_HELP_PRE_DOC)
164     {
165       char buf[1024];
166       char *end;
167       strncpy (buf, argp->doc, sizeof (buf));
168       buf[sizeof (buf) - 1] = '\0';
169       end = strchr (buf, '\v');
170       if (end)
171         *end = '\0';
172       fprintf (stream, "%s\n%s", buf, buf[0] ? "\n" : "");
173     }
174   if (flags & ARGP_HELP_LONG)
175     {
176       const struct argp_option *opt = argp->options;
177       while (opt->key)
178         {
179           #define NSPACES 29
180           char spaces[NSPACES + 1] = "                              ";
181           int len = 0;
182           fprintf (stream, "  ");
183           len += 2;
184           if (isascii (opt->key))
185             {
186               fprintf (stream, "-%c", opt->key);
187               len += 2;
188               if (opt->name)
189                 {
190                   fprintf (stream, ", ");
191                   len += 2;
192                 }
193             }
194           if (opt->name)
195             {
196               fprintf (stream, "--%s", opt->name);
197               len += 2 + strlen (opt->name);
198             }
199           if (opt->arg && (opt->flags & OPTION_ARG_OPTIONAL))
200             {
201               fprintf (stream, "[=%s]", opt->arg);
202               len += 3 + strlen (opt->arg);
203             }
204           else if (opt->arg)
205             {
206               fprintf (stream, "=%s", opt->arg);
207               len += 1 + strlen (opt->arg);
208             }
209           if (len >= NSPACES)
210             len = NSPACES - 1;
211           spaces[NSPACES - len] = '\0';
212           fprintf (stream, "%s%s\n", spaces, opt->doc);
213           opt++;
214         }
215       fprintf (stream, "  -?, --help                 Give this help list\n");
216       fprintf (stream, "      --usage                Give a short usage "
217                "message\n");
218     }
219   if (flags & ARGP_HELP_POST_DOC)
220     {
221       char buf[1024];
222       char *end;
223       strncpy (buf, argp->doc, sizeof (buf));
224       buf[sizeof (buf) - 1] = '\0';
225       end = strchr (buf, '\v');
226       if (end)
227         {
228           end++;
229           if (*end)
230             fprintf (stream, "\n%s\n", end);
231         }
232       fprintf (stream, "\nMandatory or optional arguments to long options are also mandatory or optional\n");
233       fprintf (stream, "for any corresponding short options.\n");
234     }
235   if (flags & ARGP_HELP_BUG_ADDR)
236     fprintf (stream, "\nReport bugs to %s.\n", argp_program_bug_address);
237
238   if (flags & ARGP_HELP_EXIT_ERR)
239     exit (argp_err_exit_status);
240   if (flags & ARGP_HELP_EXIT_OK)
241     exit (0);
242 }
243
244
245 void
246 argp_usage (const struct argp_state *state)
247 {
248   _argp_state_help (state->root_argp, state, state->err_stream,
249                     ARGP_HELP_STD_USAGE, state->name);
250 }
251
252
253 void
254 argp_state_help (const struct argp_state *state, FILE *stream, unsigned flags)
255 {
256   _argp_state_help (state->root_argp, state, stream, flags, state->name);
257 }
258
259
260 void
261 argp_error (const struct argp_state *state, const char *fmt, ...)
262 {
263   va_list ap;
264
265   fprintf (state->err_stream, "%s: ", state->name);
266   va_start (ap, fmt);
267   vfprintf (state->err_stream, fmt, ap);
268   va_end (ap);
269   fprintf (state->err_stream, "\n");
270   argp_state_help (state, state->err_stream, ARGP_HELP_STD_ERR);
271   exit (argp_err_exit_status);
272 }
273
274
275 void
276 argp_help (const struct argp *argp, FILE *stream, unsigned flags, char *name)
277 {
278   _argp_state_help (argp, NULL, stream, flags, name);
279 }
280
281
282 error_t
283 argp_parse (const struct argp *argp, int argc,
284             char **argv, unsigned flags, int *arg_index, void *input)
285 {
286   int rc = 0;
287   struct argp_state state = { argp, argc, argv, 1, flags, 0, 0, input,
288                               NULL, NULL, _argp_pname (argv[0]),
289                               stderr, stdout, NULL };
290   /* All non-option arguments are collected at the beginning of
291      &argv[1] during processing.  This is a counter for their number.  */
292   int non_opt_args = 0;
293
294   rc = argp->parser (ARGP_KEY_INIT, NULL, &state);
295   if (rc && rc != ARGP_ERR_UNKNOWN)
296     goto argperror;
297
298   while (state.next < state.argc - non_opt_args)
299     {
300       int idx = state.next;
301       state.next++;
302
303       if (! strcasecmp (state.argv[idx], "--"))
304         {
305           state.quoted = idx;
306           continue;
307         }
308
309       if (state.quoted || state.argv[idx][0] != '-')
310         {
311           char *arg_saved = state.argv[idx];
312           non_opt_args++;
313           memmove (&state.argv[idx], &state.argv[idx + 1],
314                    (state.argc - 1 - idx) * sizeof (char *));
315           state.argv[argc - 1] = arg_saved;
316           state.next--;
317         }
318       else if (! strcasecmp (state.argv[idx], "--help")
319                || !strcmp (state.argv[idx], "-?"))
320         {
321           argp_state_help (&state, state.out_stream, ARGP_HELP_STD_HELP);
322         }
323       else if (! strcasecmp (state.argv[idx], "--usage"))
324         {
325           argp_state_help (&state, state.out_stream,
326                            ARGP_HELP_USAGE | ARGP_HELP_EXIT_OK);
327         }
328       else if (! strcasecmp (state.argv[idx], "--version")
329                || !strcmp (state.argv[idx], "-V"))
330         {
331           fprintf (state.out_stream, "%s\n", argp_program_version);
332           exit (0);
333         }
334       else
335         {
336           /* Search for option and call parser with its KEY.  */
337           int key = ARGP_KEY_ARG; /* Just some dummy value.  */
338           const struct argp_option *opt = argp->options;
339           char *arg = NULL;
340           int found = 0;
341
342           /* Check for --opt=value syntax.  */
343           arg = strchr (state.argv[idx], '=');
344           if (arg)
345             {
346               *arg = '\0';
347               arg++;
348             }
349             
350           if (state.argv[idx][1] != '-')
351             key = state.argv[idx][1];
352           
353           while (! found && opt->key)
354             {
355               if (key == opt->key
356                   || (key == ARGP_KEY_ARG
357                       && ! strcasecmp (&state.argv[idx][2], opt->name)))
358                 {
359                   if (arg && !opt->arg)
360                     argp_error (&state, "Option %s does not take an argument",
361                                 state.argv[idx]);
362                   if (opt->arg && state.next < state.argc
363                       && state.argv[idx + 1][0] != '-')
364                     {
365                       arg = state.argv[idx + 1];
366                       state.next++;
367                     }
368                   if (opt->arg && !(opt->flags & OPTION_ARG_OPTIONAL))
369                     argp_error (&state, "Option %s requires an argument",
370                                 state.argv[idx]);
371
372                   rc = argp->parser (opt->key, arg, &state);
373                   if (rc == ARGP_ERR_UNKNOWN)
374                     break;
375                   else if (rc)
376                     goto argperror;
377                   found = 1;
378                 }
379               opt++;
380             }
381           if (! found)
382             argp_error (&state, "Unknown option %s", state.argv[idx]);
383         }
384     }
385
386   while (state.next < state.argc)
387     {
388       /* Call parser for all non-option args.  */
389       int idx = state.next;
390       state.next++;
391       rc = argp->parser (ARGP_KEY_ARG, state.argv[idx], &state);
392       if (rc && rc != ARGP_ERR_UNKNOWN)
393         goto argperror;
394       if (rc == ARGP_ERR_UNKNOWN)
395         {
396           int old_next = state.next;
397           rc = argp->parser (ARGP_KEY_ARGS, NULL, &state);
398           if (rc == ARGP_ERR_UNKNOWN)
399             {
400               argp_error (&state, "Too many arguments", state.argv[idx]);
401               goto argperror;
402             }
403           if (! rc && state.next == old_next)
404             {
405               state.arg_num += state.argc - state.next;
406               state.next = state.argc;
407             }
408         }
409       else
410         state.arg_num++;
411     }
412
413   if (state.arg_num == 0)
414     {
415       rc = argp->parser (ARGP_KEY_NO_ARGS, NULL, &state);
416       if (rc && rc != ARGP_ERR_UNKNOWN)
417         goto argperror;
418     }
419   if (state.next == state.argc)
420     {
421       rc = argp->parser (ARGP_KEY_END, NULL, &state);
422       if (rc && rc != ARGP_ERR_UNKNOWN)
423         goto argperror;
424     }
425   rc = argp->parser (ARGP_KEY_FINI, NULL, &state);
426   if (rc && rc != ARGP_ERR_UNKNOWN)
427     goto argperror;
428   
429   rc = 0;
430   argp->parser (ARGP_KEY_SUCCESS, NULL, &state);
431
432  argperror:
433   if (rc)
434     {
435       argp_error (&state, "unexpected error: %s", strerror (rc));
436       argp->parser (ARGP_KEY_ERROR, NULL, &state);
437     }
438
439   argp->parser (ARGP_KEY_FINI, NULL, &state);
440
441   if (arg_index)
442     *arg_index = state.next - 1;
443
444   return 0;
445 }
446 #endif
447
448 \f
449 /* SUPPORT.  */
450 FILE *log_stream;
451 char *program_name = "gpgme-tool";
452
453 void
454 log_init (void)
455 {
456   log_stream = stderr;
457 }
458
459
460 void
461 log_error (int status, gpg_error_t errnum, const char *fmt, ...)
462 {
463   va_list ap;
464
465   fprintf (log_stream, "%s: ", program_name);
466   va_start (ap, fmt);
467   vfprintf (log_stream, fmt, ap);
468   va_end (ap);
469   if (errnum)
470     fprintf (log_stream, ": %s <%s>", gpg_strerror (errnum),
471              gpg_strsource (errnum));
472   fprintf (log_stream, "\n");
473   if (status)
474     exit (status);
475 }
476
477
478 \f
479 typedef enum status
480   {
481     STATUS_PROTOCOL,
482     STATUS_PROGRESS,
483     STATUS_ENGINE,
484     STATUS_ARMOR,
485     STATUS_TEXTMODE,
486     STATUS_INCLUDE_CERTS,
487     STATUS_KEYLIST_MODE,
488     STATUS_RECIPIENT,
489     STATUS_ENCRYPT_RESULT
490   } status_t;
491
492 const char *status_string[] =
493   {
494     "PROTOCOL",
495     "PROGRESS",
496     "ENGINE",
497     "ARMOR",
498     "TEXTMODE",
499     "INCLUDE_CERTS",
500     "KEYLIST_MODE",
501     "RECIPIENT",
502     "ENCRYPT_RESULT"
503   };
504
505 struct gpgme_tool
506 {
507   gpgme_ctx_t ctx;
508 #define MAX_RECIPIENTS 10
509   gpgme_key_t recipients[MAX_RECIPIENTS + 1];
510   int recipients_nr;
511
512   gpg_error_t (*write_status) (void *hook, const char *status, const char *msg);
513   void *write_status_hook;
514   gpg_error_t (*write_data) (void *hook, const void *buf, size_t len);
515   void *write_data_hook;
516 };
517 typedef struct gpgme_tool *gpgme_tool_t;
518
519
520 /* Forward declaration.  */
521 void gt_write_status (gpgme_tool_t gt, status_t status, ...);
522
523 void
524 _gt_progress_cb (void *opaque, const char *what,
525                  int type, int current, int total)
526 {
527   gpgme_tool_t gt = opaque;
528   char buf[100];
529
530   snprintf (buf, sizeof (buf), "0x%02x %i %i", type, current, total);
531   gt_write_status (gt, STATUS_PROGRESS, what, buf);
532 }
533
534
535 gpg_error_t
536 _gt_gpgme_new (gpgme_tool_t gt, gpgme_ctx_t *ctx)
537 {
538   gpg_error_t err;
539
540   err = gpgme_new (ctx);
541   if (err)
542     return err;
543    gpgme_set_progress_cb (*ctx, _gt_progress_cb, gt);
544    return 0;
545 }
546
547
548 void
549 gt_init (gpgme_tool_t gt)
550 {
551   memset (gt, '\0', sizeof (*gt));
552   gpg_error_t err;
553
554   err = _gt_gpgme_new (gt, &gt->ctx);
555   if (err)
556     log_error (1, err, "can't create gpgme context");
557 }
558
559
560 gpg_error_t
561 gt_signers_add (gpgme_tool_t gt, const char *fpr)
562 {
563   gpg_error_t err;
564   gpgme_key_t key;
565
566   err = gpgme_get_key (gt->ctx, fpr, &key, 0);
567   if (err)
568     return err;
569
570   return gpgme_signers_add (gt->ctx, key);
571 }
572
573
574 gpg_error_t
575 gt_signers_clear (gpgme_tool_t gt)
576 {
577   gpgme_signers_clear (gt->ctx);
578   return 0;
579 }
580
581
582 gpg_error_t
583 gt_get_key (gpgme_tool_t gt, const char *pattern, gpgme_key_t *r_key)
584 {
585   gpgme_ctx_t ctx;
586   gpgme_ctx_t listctx;
587   gpgme_error_t err;
588   gpgme_key_t key;
589
590   if (!gt || !r_key || !pattern)
591     return gpg_error (GPG_ERR_INV_VALUE);
592   
593   ctx = gt->ctx;
594
595   err = gpgme_new (&listctx);
596   if (err)
597     return err;
598
599   {
600     gpgme_protocol_t proto;
601     gpgme_engine_info_t info;
602
603     /* Clone the relevant state.  */
604     proto = gpgme_get_protocol (ctx);
605     /* The g13 protocol does not allow keylisting, we need to choose
606        something else.  */
607     if (proto == GPGME_PROTOCOL_G13)
608       proto = GPGME_PROTOCOL_OpenPGP;
609
610     gpgme_set_protocol (listctx, proto);
611     gpgme_set_keylist_mode (listctx, gpgme_get_keylist_mode (ctx));
612     info = gpgme_ctx_get_engine_info (ctx);
613     while (info && info->protocol != proto)
614       info = info->next;
615     if (info)
616       gpgme_ctx_set_engine_info (listctx, proto,
617                                  info->file_name, info->home_dir);
618   }
619
620   err = gpgme_op_keylist_start (listctx, pattern, 0);
621   if (!err)
622     err = gpgme_op_keylist_next (listctx, r_key);
623   if (!err)
624     {
625     try_next_key:
626       err = gpgme_op_keylist_next (listctx, &key);
627       if (gpgme_err_code (err) == GPG_ERR_EOF)
628         err = 0;
629       else
630         {
631           if (!err
632               && *r_key && (*r_key)->subkeys && (*r_key)->subkeys->fpr
633               && key && key->subkeys && key->subkeys->fpr
634               && !strcmp ((*r_key)->subkeys->fpr, key->subkeys->fpr))
635             {
636               /* The fingerprint is identical.  We assume that this is
637                  the same key and don't mark it as an ambiguous.  This
638                  problem may occur with corrupted keyrings and has
639                  been noticed often with gpgsm.  In fact gpgsm uses a
640                  similar hack to sort out such duplicates but it can't
641                  do that while listing keys.  */
642               gpgme_key_unref (key);
643               goto try_next_key;
644             }
645           if (!err)
646             {
647               gpgme_key_unref (key);
648               err = gpg_error (GPG_ERR_AMBIGUOUS_NAME);
649             }
650           gpgme_key_unref (*r_key);
651         }
652     }
653   gpgme_release (listctx);
654   
655   if (! err)
656     gt_write_status (gt, STATUS_RECIPIENT, 
657                      ((*r_key)->subkeys && (*r_key)->subkeys->fpr) ? 
658                      (*r_key)->subkeys->fpr : "invalid", NULL);
659   return err;
660 }
661
662
663 gpg_error_t
664 gt_recipients_add (gpgme_tool_t gt, const char *pattern)
665 {
666   gpg_error_t err;
667   gpgme_key_t key;
668
669   if (gt->recipients_nr >= MAX_RECIPIENTS)
670     return gpg_error_from_errno (ENOMEM);
671
672   if (gpgme_get_protocol (gt->ctx) == GPGME_PROTOCOL_UISERVER)
673     err = gpgme_key_from_uid (&key, pattern);
674   else
675     err = gt_get_key (gt, pattern, &key);
676   if (err)
677     return err;
678
679   gt->recipients[gt->recipients_nr++] = key;
680   return 0;
681 }
682
683
684 void
685 gt_recipients_clear (gpgme_tool_t gt)
686 {
687   int idx;
688
689   for (idx = 0; idx < gt->recipients_nr; idx++)
690     gpgme_key_unref (gt->recipients[idx]);
691   memset (gt->recipients, '\0', gt->recipients_nr * sizeof (gpgme_key_t));
692   gt->recipients_nr = 0;
693 }
694
695
696 gpg_error_t
697 gt_reset (gpgme_tool_t gt)
698 {
699   gpg_error_t err;
700   gpgme_ctx_t ctx;
701   
702   err = _gt_gpgme_new (gt, &ctx);
703   if (err)
704     return err;
705
706   gpgme_release (gt->ctx);
707   gt->ctx = ctx;
708   gt_recipients_clear (gt);
709   return 0;
710 }
711
712
713 void
714 gt_write_status (gpgme_tool_t gt, status_t status, ...)
715 {
716   va_list ap;
717   const char *text;
718   char buf[950];
719   char *p;
720   size_t n;
721   gpg_error_t err;
722
723   va_start (ap, status);
724   p = buf;
725   n = 0;
726   while ((text = va_arg (ap, const char *)))
727     {
728       if (n)
729         {
730           *p++ = ' ';
731           n++;
732         }
733       while (*text && n < sizeof (buf) - 2)
734         {
735           *p++ = *text++;
736           n++;
737         }
738     }
739   *p = 0;
740   va_end (ap);
741
742   err = gt->write_status (gt->write_status_hook, status_string[status], buf);
743   if (err)
744     log_error (1, err, "can't write status line");
745 }
746
747
748 gpg_error_t
749 gt_write_data (gpgme_tool_t gt, void *buf, size_t len)
750 {
751   return gt->write_data (gt->write_data_hook, buf, len);
752 }
753
754
755 gpg_error_t
756 gt_get_engine_info (gpgme_tool_t gt, gpgme_protocol_t proto)
757 {
758   gpgme_engine_info_t info;
759   info = gpgme_ctx_get_engine_info (gt->ctx);
760   while (info)
761     {
762       if (proto == GPGME_PROTOCOL_UNKNOWN || proto == info->protocol)
763         gt_write_status (gt, STATUS_ENGINE,
764                          gpgme_get_protocol_name (info->protocol),
765                          info->file_name, info->version,
766                          info->req_version, info->home_dir);
767       info = info->next;
768     }
769   return 0;
770 }
771
772
773 gpgme_protocol_t
774 gt_protocol_from_name (const char *name)
775 {
776   if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_OpenPGP)))
777     return GPGME_PROTOCOL_OpenPGP;
778   if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_CMS)))
779     return GPGME_PROTOCOL_CMS;
780   if (! strcasecmp (name,gpgme_get_protocol_name (GPGME_PROTOCOL_GPGCONF)))
781     return GPGME_PROTOCOL_GPGCONF;
782   if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_ASSUAN)))
783     return GPGME_PROTOCOL_ASSUAN;
784   if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_G13)))
785     return GPGME_PROTOCOL_G13;
786   if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_UISERVER)))
787     return GPGME_PROTOCOL_UISERVER;
788   if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_DEFAULT)))
789     return GPGME_PROTOCOL_DEFAULT;
790   return GPGME_PROTOCOL_UNKNOWN;
791 }
792
793   
794 gpg_error_t
795 gt_set_protocol (gpgme_tool_t gt, gpgme_protocol_t proto)
796 {
797   return gpgme_set_protocol (gt->ctx, proto);
798 }
799
800
801 gpg_error_t
802 gt_get_protocol (gpgme_tool_t gt)
803 {
804   gpgme_protocol_t proto = gpgme_get_protocol (gt->ctx);
805
806   gt_write_status (gt, STATUS_PROTOCOL, gpgme_get_protocol_name (proto),
807                    NULL);
808
809   return 0;
810 }
811
812
813 gpg_error_t
814 gt_set_sub_protocol (gpgme_tool_t gt, gpgme_protocol_t proto)
815 {
816   return gpgme_set_sub_protocol (gt->ctx, proto);
817 }
818
819
820 gpg_error_t
821 gt_get_sub_protocol (gpgme_tool_t gt)
822 {
823   gpgme_protocol_t proto = gpgme_get_sub_protocol (gt->ctx);
824
825   gt_write_status (gt, STATUS_PROTOCOL, gpgme_get_protocol_name (proto),
826                    NULL);
827
828   return 0;
829 }
830
831
832 gpg_error_t
833 gt_set_armor (gpgme_tool_t gt, int armor)
834 {
835   gpgme_set_armor (gt->ctx, armor);
836   return 0;
837 }
838
839
840 gpg_error_t
841 gt_get_armor (gpgme_tool_t gt)
842 {
843   gt_write_status (gt, STATUS_ARMOR,
844                    gpgme_get_armor (gt->ctx) ? "true" : "false", NULL);
845
846   return 0;
847 }
848
849
850 gpg_error_t
851 gt_set_textmode (gpgme_tool_t gt, int textmode)
852 {
853   gpgme_set_textmode (gt->ctx, textmode);
854   return 0;
855 }
856
857
858 gpg_error_t
859 gt_get_textmode (gpgme_tool_t gt)
860 {
861   gt_write_status (gt, STATUS_TEXTMODE,
862                    gpgme_get_textmode (gt->ctx) ? "true" : "false", NULL);
863
864   return 0;
865 }
866
867
868 gpg_error_t
869 gt_set_keylist_mode (gpgme_tool_t gt, gpgme_keylist_mode_t keylist_mode)
870 {
871   gpgme_set_keylist_mode (gt->ctx, keylist_mode);
872   return 0;
873 }
874
875
876 gpg_error_t
877 gt_get_keylist_mode (gpgme_tool_t gt)
878 {
879 #define NR_KEYLIST_MODES 6
880   const char *modes[NR_KEYLIST_MODES + 1];
881   int idx = 0;
882   gpgme_keylist_mode_t mode = gpgme_get_keylist_mode (gt->ctx);
883   
884   if (mode & GPGME_KEYLIST_MODE_LOCAL)
885     modes[idx++] = "local";
886   if (mode & GPGME_KEYLIST_MODE_EXTERN)
887     modes[idx++] = "extern";
888   if (mode & GPGME_KEYLIST_MODE_SIGS)
889     modes[idx++] = "sigs";
890   if (mode & GPGME_KEYLIST_MODE_SIG_NOTATIONS)
891     modes[idx++] = "sig_notations";
892   if (mode & GPGME_KEYLIST_MODE_EPHEMERAL)
893     modes[idx++] = "ephemeral";
894   if (mode & GPGME_KEYLIST_MODE_VALIDATE)
895     modes[idx++] = "validate";
896   modes[idx++] = NULL;
897
898   gt_write_status (gt, STATUS_KEYLIST_MODE, modes[0], modes[1], modes[2],
899                    modes[3], modes[4], modes[5], modes[6]);
900
901   return 0;
902 }
903
904
905 gpg_error_t
906 gt_set_include_certs (gpgme_tool_t gt, int include_certs)
907 {
908   gpgme_set_include_certs (gt->ctx, include_certs);
909   return 0;
910 }
911
912
913 gpg_error_t
914 gt_get_include_certs (gpgme_tool_t gt)
915 {
916   int include_certs = gpgme_get_include_certs (gt->ctx);
917   char buf[100];
918
919   if (include_certs == GPGME_INCLUDE_CERTS_DEFAULT)
920     strcpy (buf, "default");
921   else
922     snprintf (buf, sizeof (buf), "%i", include_certs);
923
924   gt_write_status (gt, STATUS_INCLUDE_CERTS, buf, NULL);
925
926   return 0;
927 }
928
929
930 gpg_error_t
931 gt_decrypt_verify (gpgme_tool_t gt, gpgme_data_t cipher, gpgme_data_t plain,
932                    int verify)
933 {
934   if (verify)
935     return gpgme_op_decrypt_verify (gt->ctx, cipher, plain);
936   else
937     return gpgme_op_decrypt (gt->ctx, cipher, plain);
938 }
939
940
941 gpg_error_t
942 gt_sign_encrypt (gpgme_tool_t gt, gpgme_encrypt_flags_t flags,
943                  gpgme_data_t plain, gpgme_data_t cipher, int sign)
944 {
945   gpg_error_t err;
946
947   if (sign)
948     err = gpgme_op_encrypt (gt->ctx, gt->recipients, flags, plain, cipher);
949   else
950     err = gpgme_op_encrypt_sign (gt->ctx, gt->recipients, flags, plain, cipher);
951
952   gt_recipients_clear (gt);
953
954   return err;
955 }
956
957
958 gpg_error_t
959 gt_sign (gpgme_tool_t gt, gpgme_data_t plain, gpgme_data_t sig,
960          gpgme_sig_mode_t mode)
961 {
962   return gpgme_op_sign (gt->ctx, plain, sig, mode);
963 }
964
965
966 gpg_error_t
967 gt_verify (gpgme_tool_t gt, gpgme_data_t sig, gpgme_data_t sig_text,
968            gpgme_data_t plain)
969 {
970   return gpgme_op_verify (gt->ctx, sig, sig_text, plain);
971 }
972
973
974 gpg_error_t
975 gt_import (gpgme_tool_t gt, gpgme_data_t data)
976 {
977   return gpgme_op_import (gt->ctx, data);
978 }
979
980
981 gpg_error_t
982 gt_export (gpgme_tool_t gt, const char *pattern[], gpgme_export_mode_t mode,
983            gpgme_data_t data)
984 {
985   return gpgme_op_export_ext (gt->ctx, pattern, mode, data);
986 }
987
988
989 gpg_error_t
990 gt_genkey (gpgme_tool_t gt, const char *parms, gpgme_data_t public,
991            gpgme_data_t secret)
992 {
993   return gpgme_op_genkey (gt->ctx, parms, public, secret);
994 }
995
996
997 gpg_error_t
998 gt_import_keys (gpgme_tool_t gt, char *fpr[])
999 {
1000   gpg_error_t err;
1001   int cnt;
1002   int idx;
1003   gpgme_key_t *keys;
1004   
1005   cnt = 0;
1006   while (fpr[cnt])
1007     cnt++;
1008   
1009   if (! cnt)
1010     return gpg_error (GPG_ERR_INV_VALUE);
1011
1012   keys = malloc ((cnt + 1) * sizeof (gpgme_key_t));
1013   if (! keys)
1014     return gpg_error_from_syserror ();
1015   
1016   for (idx = 0; idx < cnt; idx++)
1017     {
1018       err = gpgme_get_key (gt->ctx, fpr[idx], &keys[idx], 0);
1019       if (err)
1020         break;
1021     }
1022   if (! err)
1023     {
1024       keys[cnt] = NULL;
1025       err = gpgme_op_import_keys (gt->ctx, keys);
1026     }
1027   
1028   /* Rollback.  */
1029   while (--idx >= 0)
1030     gpgme_key_unref (keys[idx]);
1031   free (keys);
1032
1033   return err;
1034 }
1035
1036
1037 gpg_error_t
1038 gt_delete (gpgme_tool_t gt, char *fpr, int allow_secret)
1039 {
1040   gpg_error_t err;
1041   gpgme_key_t key;
1042
1043   err = gpgme_get_key (gt->ctx, fpr, &key, 0);
1044   if (err)
1045     return err;
1046
1047   err = gpgme_op_delete (gt->ctx, key, allow_secret);
1048   gpgme_key_unref (key);
1049   return err;
1050 }
1051
1052
1053 gpg_error_t
1054 gt_keylist_start (gpgme_tool_t gt, const char *pattern[], int secret_only)
1055 {
1056   return gpgme_op_keylist_ext_start (gt->ctx, pattern, secret_only, 0);
1057 }
1058
1059
1060 gpg_error_t
1061 gt_keylist_next (gpgme_tool_t gt, gpgme_key_t *key)
1062 {
1063   return gpgme_op_keylist_next (gt->ctx, key);
1064 }
1065
1066
1067 gpg_error_t
1068 gt_getauditlog (gpgme_tool_t gt, gpgme_data_t output, unsigned int flags)
1069 {
1070   return gpgme_op_getauditlog (gt->ctx, output, flags);
1071 }
1072
1073
1074 gpg_error_t
1075 gt_vfs_mount (gpgme_tool_t gt, const char *container_file,
1076               const char *mount_dir, int flags)
1077 {
1078   gpg_error_t err;
1079   gpg_error_t op_err;
1080   err = gpgme_op_vfs_mount (gt->ctx, container_file, mount_dir, flags, &op_err);
1081   return err ? err : op_err;
1082 }
1083
1084
1085 gpg_error_t
1086 gt_vfs_create (gpgme_tool_t gt, const char *container_file, int flags)
1087 {
1088   gpg_error_t err;
1089   gpg_error_t op_err;
1090   err = gpgme_op_vfs_create (gt->ctx, gt->recipients, container_file,
1091                              flags, &op_err);
1092   gt_recipients_clear (gt);
1093   return err ? err : op_err;
1094 }
1095
1096
1097 // TODO
1098 #define GT_RESULT_ENCRYPT 0x1
1099 #define GT_RESULT_DECRYPT 0x2
1100 #define GT_RESULT_SIGN 0x4
1101 #define GT_RESULT_VERIFY 0x8
1102 #define GT_RESULT_IMPORT 0x10
1103 #define GT_RESULT_GENKEY 0x20
1104 #define GT_RESULT_KEYLIST 0x40
1105 #define GT_RESULT_VFS_MOUNT 0x80
1106 #define GT_RESULT_ALL (~0U)
1107
1108 gpg_error_t
1109 gt_result (gpgme_tool_t gt, unsigned int flags)
1110 {
1111   if (flags & GT_RESULT_ENCRYPT)
1112     {
1113       gpgme_encrypt_result_t res = gpgme_op_encrypt_result (gt->ctx);
1114       if (res)
1115         {
1116           gpgme_invalid_key_t invrec = res->invalid_recipients;
1117           while (invrec)
1118             {
1119               gt_write_status (gt, STATUS_ENCRYPT_RESULT, "invalid_recipient",
1120                                invrec->fpr, invrec->reason);
1121               invrec = invrec->next;
1122             }
1123         }
1124     }
1125   if (flags & GT_RESULT_VFS_MOUNT)
1126     {
1127       gpgme_vfs_mount_result_t res = gpgme_op_vfs_mount_result (gt->ctx);
1128       if (res)
1129         {
1130           gt_write_data (gt, "vfs_mount\n", 10);
1131           gt_write_data (gt, "mount_dir:", 10);
1132           gt_write_data (gt, res->mount_dir, strlen (res->mount_dir));
1133           gt_write_data (gt, "\n", 1);
1134         }
1135     }
1136
1137   return 0;
1138 }
1139
1140 \f
1141 /* GPGME SERVER.  */
1142
1143 #include <assuan.h>
1144
1145 struct server
1146 {
1147   gpgme_tool_t gt;
1148   assuan_context_t assuan_ctx;
1149
1150   gpgme_data_encoding_t input_enc;
1151   gpgme_data_encoding_t output_enc;
1152   assuan_fd_t message_fd;
1153   gpgme_data_encoding_t message_enc;
1154 };
1155
1156
1157 gpg_error_t
1158 server_write_status (void *hook, const char *status, const char *msg)
1159 {
1160   struct server *server = hook;
1161   return assuan_write_status (server->assuan_ctx, status, msg);
1162 }
1163
1164
1165 gpg_error_t
1166 server_write_data (void *hook, const void *buf, size_t len)
1167 {
1168   struct server *server = hook;
1169   return assuan_send_data (server->assuan_ctx, buf, len);
1170 }
1171
1172
1173 static gpgme_data_encoding_t
1174 server_data_encoding (const char *line)
1175 {
1176   if (strstr (line, "--binary"))
1177     return GPGME_DATA_ENCODING_BINARY;
1178   if (strstr (line, "--base64"))
1179     return GPGME_DATA_ENCODING_BASE64;
1180   if (strstr (line, "--armor"))
1181     return GPGME_DATA_ENCODING_ARMOR;
1182   if (strstr (line, "--url"))
1183     return GPGME_DATA_ENCODING_URL;
1184   if (strstr (line, "--urlesc"))
1185     return GPGME_DATA_ENCODING_URLESC;
1186   if (strstr (line, "--url0"))
1187     return GPGME_DATA_ENCODING_URL0;
1188   return GPGME_DATA_ENCODING_NONE;
1189 }
1190
1191
1192 static gpgme_error_t
1193 server_data_obj (assuan_fd_t fd, gpgme_data_encoding_t encoding,
1194                  gpgme_data_t *data)
1195 {
1196   gpgme_error_t err;
1197
1198   err = gpgme_data_new_from_fd (data, fd);
1199   if (err)
1200     return err;
1201   return gpgme_data_set_encoding (*data, encoding);
1202 }
1203
1204
1205 void
1206 server_reset_fds (struct server *server)
1207 {
1208   /* assuan closes the input and output FDs for us when doing a RESET,
1209      but we use this same function after commands, so repeat it
1210      here.  */
1211   assuan_close_input_fd (server->assuan_ctx);
1212   assuan_close_output_fd (server->assuan_ctx);
1213   if (server->message_fd != -1)
1214     {
1215       /* FIXME: Assuan should provide a close function.  */
1216       close (server->message_fd);
1217       server->message_fd = -1;
1218     }
1219   server->input_enc = GPGME_DATA_ENCODING_NONE;
1220   server->output_enc = GPGME_DATA_ENCODING_NONE;
1221   server->message_enc = GPGME_DATA_ENCODING_NONE;
1222 }
1223
1224
1225 static gpg_error_t
1226 reset_notify (assuan_context_t ctx, char *line)
1227 {
1228   struct server *server = assuan_get_pointer (ctx);
1229   server_reset_fds (server);
1230   gt_reset (server->gt);
1231   return 0;
1232 }
1233
1234 static const char hlp_version[] = 
1235   "VERSION [<string>]\n"
1236   "\n"
1237   "Call the function gpgme_check_version.";
1238 static gpg_error_t
1239 cmd_version (assuan_context_t ctx, char *line)
1240 {
1241   if (line && *line)
1242     {
1243       const char *version = gpgme_check_version (line);
1244       return version ? 0 : gpg_error (GPG_ERR_SELFTEST_FAILED);
1245     }
1246   else
1247     {
1248       const char *version = gpgme_check_version (NULL);
1249       return assuan_send_data (ctx, version, strlen (version));
1250     }
1251 }
1252
1253
1254 static gpg_error_t
1255 cmd_engine (assuan_context_t ctx, char *line)
1256 {
1257   struct server *server = assuan_get_pointer (ctx);
1258   return gt_get_engine_info (server->gt, gt_protocol_from_name (line));
1259 }
1260
1261
1262 static const char hlp_protocol[] = 
1263   "PROTOCOL [<name>]\n"
1264   "\n"
1265   "With NAME, set the protocol.  Without return the current protocol.";
1266 static gpg_error_t
1267 cmd_protocol (assuan_context_t ctx, char *line)
1268 {
1269   struct server *server = assuan_get_pointer (ctx);
1270   if (line && *line)
1271     return gt_set_protocol (server->gt, gt_protocol_from_name (line));
1272   else
1273     return gt_get_protocol (server->gt);
1274 }
1275
1276
1277 static gpg_error_t
1278 cmd_sub_protocol (assuan_context_t ctx, char *line)
1279 {
1280   struct server *server = assuan_get_pointer (ctx);
1281   if (line && *line)
1282     return gt_set_sub_protocol (server->gt, gt_protocol_from_name (line));
1283   else
1284     return gt_get_sub_protocol (server->gt);
1285 }
1286
1287
1288 static gpg_error_t
1289 cmd_armor (assuan_context_t ctx, char *line)
1290 {
1291   struct server *server = assuan_get_pointer (ctx);
1292   if (line && *line)
1293     {
1294       int flag = 0;
1295       
1296       if (! strcasecmp (line, "true") || ! strcasecmp (line, "yes")
1297           || line[0] == '1')
1298         flag = 1;
1299       
1300       return gt_set_armor (server->gt, flag);
1301     }
1302   else
1303     return gt_get_armor (server->gt);
1304 }
1305
1306
1307 static gpg_error_t
1308 cmd_textmode (assuan_context_t ctx, char *line)
1309 {
1310   struct server *server = assuan_get_pointer (ctx);
1311   if (line && *line)
1312     {
1313       int flag = 0;
1314
1315       if (! strcasecmp (line, "true") || ! strcasecmp (line, "yes")
1316           || line[0] == '1')
1317         flag = 1;
1318       
1319       return gt_set_textmode (server->gt, flag);
1320     }
1321   else
1322     return gt_get_textmode (server->gt);
1323 }
1324
1325
1326 static gpg_error_t
1327 cmd_include_certs (assuan_context_t ctx, char *line)
1328 {
1329   struct server *server = assuan_get_pointer (ctx);
1330
1331   if (line && *line)
1332     {
1333       int include_certs = 0;
1334       
1335       if (! strcasecmp (line, "default"))
1336         include_certs = GPGME_INCLUDE_CERTS_DEFAULT;
1337       else
1338         include_certs = atoi (line);
1339       
1340       return gt_set_include_certs (server->gt, include_certs);
1341     }
1342   else
1343     return gt_get_include_certs (server->gt);
1344 }
1345
1346
1347 static gpg_error_t
1348 cmd_keylist_mode (assuan_context_t ctx, char *line)
1349 {
1350   struct server *server = assuan_get_pointer (ctx);
1351
1352   if (line && *line)
1353     {
1354       gpgme_keylist_mode_t mode = 0;
1355       
1356       if (strstr (line, "local"))
1357         mode |= GPGME_KEYLIST_MODE_LOCAL;
1358       if (strstr (line, "extern"))
1359         mode |= GPGME_KEYLIST_MODE_EXTERN;
1360       if (strstr (line, "sigs"))
1361         mode |= GPGME_KEYLIST_MODE_SIGS;
1362       if (strstr (line, "sig_notations"))
1363         mode |= GPGME_KEYLIST_MODE_SIG_NOTATIONS;
1364       if (strstr (line, "ephemeral"))
1365         mode |= GPGME_KEYLIST_MODE_EPHEMERAL;
1366       if (strstr (line, "validate"))
1367         mode |= GPGME_KEYLIST_MODE_VALIDATE;
1368       
1369       return gt_set_keylist_mode (server->gt, mode);
1370     }
1371   else
1372     return gt_get_keylist_mode (server->gt);
1373 }
1374
1375
1376 static gpg_error_t
1377 input_notify (assuan_context_t ctx, char *line)
1378 {
1379   struct server *server = assuan_get_pointer (ctx);
1380   server->input_enc = server_data_encoding (line);
1381   return 0;
1382 }
1383
1384
1385 static gpg_error_t
1386 output_notify (assuan_context_t ctx, char *line)
1387 {
1388   struct server *server = assuan_get_pointer (ctx);
1389   server->output_enc = server_data_encoding (line);
1390   return 0;
1391 }
1392
1393
1394 static gpg_error_t
1395 cmd_message (assuan_context_t ctx, char *line)
1396 {
1397   struct server *server = assuan_get_pointer (ctx);
1398   gpg_error_t err;
1399   assuan_fd_t sysfd;
1400
1401   err = assuan_command_parse_fd (ctx, line, &sysfd);
1402   if (err)
1403     return err;
1404   server->message_fd = sysfd;
1405   server->message_enc = server_data_encoding (line);
1406   return 0;
1407 }
1408
1409
1410 static gpg_error_t
1411 cmd_recipient (assuan_context_t ctx, char *line)
1412 {
1413   struct server *server = assuan_get_pointer (ctx);
1414
1415   return gt_recipients_add (server->gt, line);
1416 }
1417
1418
1419 static gpg_error_t
1420 cmd_signer (assuan_context_t ctx, char *line)
1421 {
1422   struct server *server = assuan_get_pointer (ctx);
1423
1424   return gt_signers_add (server->gt, line);
1425 }
1426
1427
1428 static gpg_error_t
1429 cmd_signers_clear (assuan_context_t ctx, char *line)
1430 {
1431   struct server *server = assuan_get_pointer (ctx);
1432
1433   return gt_signers_clear (server->gt);
1434 }
1435
1436
1437 static gpg_error_t
1438 _cmd_decrypt_verify (assuan_context_t ctx, char *line, int verify)
1439 {
1440   struct server *server = assuan_get_pointer (ctx);
1441   gpg_error_t err;
1442   assuan_fd_t inp_fd;
1443   assuan_fd_t out_fd;
1444   gpgme_data_t inp_data;
1445   gpgme_data_t out_data;
1446
1447   inp_fd = assuan_get_input_fd (ctx);
1448   if (inp_fd == ASSUAN_INVALID_FD)
1449     return GPG_ERR_ASS_NO_INPUT;
1450   out_fd = assuan_get_output_fd (ctx);
1451   if (out_fd == ASSUAN_INVALID_FD)
1452     return GPG_ERR_ASS_NO_OUTPUT;
1453   
1454   err = server_data_obj (inp_fd, server->input_enc, &inp_data);
1455   if (err)
1456     return err;
1457   err = server_data_obj (out_fd, server->output_enc, &out_data);
1458   if (err)
1459     {
1460       gpgme_data_release (inp_data);
1461       return err;
1462     }
1463
1464   err = gt_decrypt_verify (server->gt, inp_data, out_data, verify); 
1465
1466   gpgme_data_release (inp_data);
1467   gpgme_data_release (out_data);
1468
1469   server_reset_fds (server);
1470
1471   return err;
1472 }
1473
1474
1475 static gpg_error_t
1476 cmd_decrypt (assuan_context_t ctx, char *line)
1477 {
1478   return _cmd_decrypt_verify (ctx, line, 0);
1479 }
1480
1481
1482 static gpg_error_t
1483 cmd_decrypt_verify (assuan_context_t ctx, char *line)
1484 {
1485   return _cmd_decrypt_verify (ctx, line, 1);
1486 }
1487
1488
1489 static gpg_error_t
1490 _cmd_sign_encrypt (assuan_context_t ctx, char *line, int sign)
1491 {
1492   struct server *server = assuan_get_pointer (ctx);
1493   gpg_error_t err;
1494   assuan_fd_t inp_fd;
1495   assuan_fd_t out_fd;
1496   gpgme_data_t inp_data = NULL;
1497   gpgme_data_t out_data = NULL;
1498   gpgme_encrypt_flags_t flags = 0;
1499
1500   if (strstr (line, "--always-trust"))
1501     flags |= GPGME_ENCRYPT_ALWAYS_TRUST;
1502   if (strstr (line, "--no-encrypt-to"))
1503     flags |= GPGME_ENCRYPT_NO_ENCRYPT_TO;
1504   if (strstr (line, "--prepare"))
1505     flags |= GPGME_ENCRYPT_PREPARE;
1506   if (strstr (line, "--expect-sign"))
1507     flags |= GPGME_ENCRYPT_EXPECT_SIGN;
1508   
1509   inp_fd = assuan_get_input_fd (ctx);
1510   out_fd = assuan_get_output_fd (ctx);
1511   if (inp_fd != ASSUAN_INVALID_FD)
1512     {
1513       err = server_data_obj (inp_fd, server->input_enc, &inp_data);
1514       if (err)
1515         return err;
1516     }
1517   if (out_fd != ASSUAN_INVALID_FD)
1518     {
1519       err = server_data_obj (out_fd, server->output_enc, &out_data);
1520       if (err)
1521         {
1522           gpgme_data_release (inp_data);
1523           return err;
1524         }
1525     }
1526
1527   err = gt_sign_encrypt (server->gt, flags, inp_data, out_data, sign); 
1528
1529   gpgme_data_release (inp_data);
1530   gpgme_data_release (out_data);
1531
1532   server_reset_fds (server);
1533
1534   return err;
1535 }
1536
1537
1538 static gpg_error_t
1539 cmd_encrypt (assuan_context_t ctx, char *line)
1540 {
1541   return _cmd_sign_encrypt (ctx, line, 0);
1542 }
1543
1544
1545 static gpg_error_t
1546 cmd_sign_encrypt (assuan_context_t ctx, char *line)
1547 {
1548   return _cmd_sign_encrypt (ctx, line, 1);
1549 }
1550
1551
1552 static gpg_error_t
1553 cmd_sign (assuan_context_t ctx, char *line)
1554 {
1555   struct server *server = assuan_get_pointer (ctx);
1556   gpg_error_t err;
1557   assuan_fd_t inp_fd;
1558   assuan_fd_t out_fd;
1559   gpgme_data_t inp_data;
1560   gpgme_data_t out_data;
1561   gpgme_sig_mode_t mode = GPGME_SIG_MODE_NORMAL;
1562
1563   if (strstr (line, "--clear"))
1564     mode = GPGME_SIG_MODE_CLEAR;
1565   if (strstr (line, "--detach"))
1566     mode = GPGME_SIG_MODE_DETACH;
1567
1568   inp_fd = assuan_get_input_fd (ctx);
1569   if (inp_fd == ASSUAN_INVALID_FD)
1570     return GPG_ERR_ASS_NO_INPUT;
1571   out_fd = assuan_get_output_fd (ctx);
1572   if (out_fd == ASSUAN_INVALID_FD)
1573     return GPG_ERR_ASS_NO_OUTPUT;
1574   
1575   err = server_data_obj (inp_fd, server->input_enc, &inp_data);
1576   if (err)
1577     return err;
1578   err = server_data_obj (out_fd, server->output_enc, &out_data);
1579   if (err)
1580     {
1581       gpgme_data_release (inp_data);
1582       return err;
1583     }
1584
1585   err = gt_sign (server->gt, inp_data, out_data, mode);
1586
1587   gpgme_data_release (inp_data);
1588   gpgme_data_release (out_data);
1589   server_reset_fds (server);
1590
1591   return err;
1592 }
1593
1594
1595 static gpg_error_t
1596 cmd_verify (assuan_context_t ctx, char *line)
1597 {
1598   struct server *server = assuan_get_pointer (ctx);
1599   gpg_error_t err;
1600   assuan_fd_t inp_fd;
1601   assuan_fd_t msg_fd;
1602   assuan_fd_t out_fd;
1603   gpgme_data_t inp_data;
1604   gpgme_data_t msg_data = NULL;
1605   gpgme_data_t out_data = NULL;
1606
1607   inp_fd = assuan_get_input_fd (ctx);
1608   if (inp_fd == ASSUAN_INVALID_FD)
1609     return GPG_ERR_ASS_NO_INPUT;
1610   msg_fd = server->message_fd;
1611   out_fd = assuan_get_output_fd (ctx);
1612   
1613   err = server_data_obj (inp_fd, server->input_enc, &inp_data);
1614   if (err)
1615     return err;
1616   if (msg_fd != ASSUAN_INVALID_FD)
1617     {
1618       err = server_data_obj (msg_fd, server->message_enc, &msg_data);
1619       if (err)
1620         {
1621           gpgme_data_release (inp_data);
1622           return err;
1623         }
1624     }
1625   if (out_fd != ASSUAN_INVALID_FD)
1626     {
1627       err = server_data_obj (out_fd, server->output_enc, &out_data);
1628       if (err)
1629         {
1630           gpgme_data_release (inp_data);
1631           gpgme_data_release (msg_data);
1632           return err;
1633         }
1634     }
1635
1636   err = gt_verify (server->gt, inp_data, msg_data, out_data);
1637
1638   gpgme_data_release (inp_data);
1639   if (msg_data)
1640     gpgme_data_release (msg_data);
1641   if (out_data)
1642     gpgme_data_release (out_data);
1643
1644   server_reset_fds (server);
1645
1646   return err;
1647 }
1648
1649
1650 static gpg_error_t
1651 cmd_import (assuan_context_t ctx, char *line)
1652 {
1653   struct server *server = assuan_get_pointer (ctx);
1654   
1655   if (line && *line)
1656     {
1657       char *fprs[2] = { line, NULL };
1658
1659       return gt_import_keys (server->gt, fprs);
1660     }
1661   else
1662     {
1663       gpg_error_t err;
1664       assuan_fd_t inp_fd;
1665       gpgme_data_t inp_data;
1666       
1667       inp_fd = assuan_get_input_fd (ctx);
1668       if (inp_fd == ASSUAN_INVALID_FD)
1669         return GPG_ERR_ASS_NO_INPUT;
1670
1671       err = server_data_obj (inp_fd, server->input_enc, &inp_data);
1672       if (err)
1673         return err;
1674       
1675       err = gt_import (server->gt, inp_data); 
1676       
1677       gpgme_data_release (inp_data);
1678       server_reset_fds (server);
1679
1680       return err;
1681     }
1682 }
1683
1684
1685 static gpg_error_t
1686 cmd_export (assuan_context_t ctx, char *line)
1687 {
1688   struct server *server = assuan_get_pointer (ctx);
1689   gpg_error_t err;
1690   assuan_fd_t out_fd;
1691   gpgme_data_t out_data;
1692   gpgme_export_mode_t mode = 0;
1693   const char *pattern[2];
1694   const char optstr[] = "--extern ";
1695
1696   out_fd = assuan_get_output_fd (ctx);
1697   if (out_fd == ASSUAN_INVALID_FD)
1698     return GPG_ERR_ASS_NO_OUTPUT;
1699   err = server_data_obj (out_fd, server->output_enc, &out_data);
1700   if (err)
1701     return err;
1702
1703   if (strncasecmp (line, optstr, strlen (optstr)))
1704     {
1705       mode |= GPGME_EXPORT_MODE_EXTERN;
1706       line += strlen (optstr);
1707     }
1708   pattern[0] = line;
1709   pattern[1] = NULL;
1710
1711   err = gt_export (server->gt, pattern, mode, out_data);
1712
1713   gpgme_data_release (out_data);
1714   server_reset_fds (server);
1715
1716   return err;
1717 }
1718
1719
1720 static gpg_error_t
1721 _cmd_genkey_write (gpgme_data_t data, const void *buf, size_t size)
1722 {
1723   while (size > 0)
1724     {
1725       ssize_t writen = gpgme_data_write (data, buf, size);
1726       if (writen < 0 && errno != EAGAIN)
1727         return gpg_error_from_syserror ();
1728       else if (writen > 0)
1729         {
1730           buf = (void *) (((char *) buf) + writen);
1731           size -= writen;
1732         }
1733     }
1734   return 0;
1735 }
1736
1737
1738 static gpg_error_t
1739 cmd_genkey (assuan_context_t ctx, char *line)
1740 {
1741   struct server *server = assuan_get_pointer (ctx);
1742   gpg_error_t err;
1743   assuan_fd_t inp_fd;
1744   assuan_fd_t out_fd;
1745   gpgme_data_t inp_data;
1746   gpgme_data_t out_data = NULL;
1747   gpgme_data_t parms_data = NULL;
1748   const char *parms;
1749
1750   inp_fd = assuan_get_input_fd (ctx);
1751   if (inp_fd == ASSUAN_INVALID_FD)
1752     return GPG_ERR_ASS_NO_INPUT;
1753   out_fd = assuan_get_output_fd (ctx);
1754   
1755   err = server_data_obj (inp_fd, server->input_enc, &inp_data);
1756   if (err)
1757     return err;
1758   if (out_fd != ASSUAN_INVALID_FD)
1759     {
1760       err = server_data_obj (out_fd, server->output_enc, &out_data);
1761       if (err)
1762         {
1763           gpgme_data_release (inp_data);
1764           return err;
1765         }
1766     }
1767
1768   /* Convert input data.  */
1769   err = gpgme_data_new (&parms_data);
1770   if (err)
1771     goto out;
1772   do
1773     {
1774       char buf[512];
1775       ssize_t readn = gpgme_data_read (inp_data, buf, sizeof (buf));
1776       if (readn < 0)
1777         {
1778           err = gpg_error_from_syserror ();
1779           goto out;
1780         }
1781       else if (readn == 0)
1782         break;
1783
1784       err = _cmd_genkey_write (parms_data, buf, readn);
1785       if (err)
1786         goto out;
1787     }
1788   while (1);
1789   err = _cmd_genkey_write (parms_data, "", 1);
1790   if (err)
1791     goto out;
1792   parms = gpgme_data_release_and_get_mem (parms_data, NULL);
1793   parms_data = NULL;
1794   if (! parms)
1795     {
1796       err = gpg_error (GPG_ERR_GENERAL);
1797       goto out;
1798     }
1799
1800   err = gt_genkey (server->gt, parms, out_data, NULL);
1801
1802   server_reset_fds (server);
1803
1804  out:
1805   gpgme_data_release (inp_data);
1806   if (out_data)
1807     gpgme_data_release (out_data);
1808   if (parms_data)
1809     gpgme_data_release (parms_data);
1810
1811   return err; 
1812 }
1813
1814
1815 static gpg_error_t
1816 cmd_delete (assuan_context_t ctx, char *line)
1817 {
1818   struct server *server = assuan_get_pointer (ctx);
1819   int allow_secret = 0;
1820   const char optstr[] = "--allow-secret ";
1821
1822   if (strncasecmp (line, optstr, strlen (optstr)))
1823     {
1824       allow_secret = 1;
1825       line += strlen (optstr);
1826     }
1827   return gt_delete (server->gt, line, allow_secret);
1828 }
1829
1830
1831 static gpg_error_t
1832 cmd_keylist (assuan_context_t ctx, char *line)
1833 {
1834   struct server *server = assuan_get_pointer (ctx);
1835   gpg_error_t err;
1836   int secret_only = 0;
1837   const char *pattern[2];
1838   const char optstr[] = "--secret-only ";
1839
1840   if (strncasecmp (line, optstr, strlen (optstr)))
1841     {
1842       secret_only = 1;
1843       line += strlen (optstr);
1844     }
1845   pattern[0] = line;
1846   pattern[1] = NULL;
1847
1848   err = gt_keylist_start (server->gt, pattern, secret_only);
1849   while (! err)
1850     {
1851       gpgme_key_t key;
1852
1853       err = gt_keylist_next (server->gt, &key);
1854       if (gpg_err_code (err) == GPG_ERR_EOF)
1855         {
1856           err = 0;
1857           break;
1858         }
1859       else if (! err)
1860         {
1861           char buf[100];
1862           /* FIXME: More data.  */
1863           snprintf (buf, sizeof (buf), "key:%s\n", key->subkeys->fpr);
1864           assuan_send_data (ctx, buf, strlen (buf));
1865           gpgme_key_unref (key);
1866         }
1867     }
1868   
1869   server_reset_fds (server);
1870
1871   return err;
1872 }
1873
1874
1875 static gpg_error_t
1876 cmd_getauditlog (assuan_context_t ctx, char *line)
1877 {
1878   struct server *server = assuan_get_pointer (ctx);
1879   gpg_error_t err;
1880   assuan_fd_t out_fd;
1881   gpgme_data_t out_data;
1882
1883   out_fd = assuan_get_output_fd (ctx);
1884   if (out_fd == ASSUAN_INVALID_FD)
1885     return GPG_ERR_ASS_NO_OUTPUT;
1886   err = server_data_obj (out_fd, server->output_enc, &out_data);
1887   if (err)
1888     return err;
1889
1890   err = gt_getauditlog (server->gt, out_data, 0);
1891
1892   gpgme_data_release (out_data);
1893   server_reset_fds (server);
1894
1895   return err;
1896 }
1897
1898
1899 static gpg_error_t
1900 cmd_vfs_mount (assuan_context_t ctx, char *line)
1901 {
1902   struct server *server = assuan_get_pointer (ctx);
1903   char *mount_dir;
1904   gpg_error_t err;
1905
1906   mount_dir = strchr (line, ' ');
1907   if (mount_dir)
1908     {
1909       *(mount_dir++) = '\0';
1910       while (*mount_dir == ' ')
1911         mount_dir++;
1912     }
1913
1914   err = gt_vfs_mount (server->gt, line, mount_dir, 0);
1915
1916   return err;
1917 }
1918
1919
1920 static gpg_error_t
1921 cmd_vfs_create (assuan_context_t ctx, char *line)
1922 {
1923   struct server *server = assuan_get_pointer (ctx);
1924   gpg_error_t err;
1925   char *end;
1926
1927   end = strchr (line, ' ');
1928   if (end)
1929     {
1930       *(end++) = '\0';
1931       while (*end == ' ')
1932         end++;
1933     }
1934
1935   err = gt_vfs_create (server->gt, line, 0);
1936
1937   return err;
1938 }
1939
1940
1941 static gpg_error_t
1942 cmd_result (assuan_context_t ctx, char *line)
1943 {
1944   struct server *server = assuan_get_pointer (ctx);
1945   return gt_result (server->gt, GT_RESULT_ALL);
1946 }
1947
1948
1949 /* STRERROR <err>  */
1950 static gpg_error_t
1951 cmd_strerror (assuan_context_t ctx, char *line)
1952 {
1953   gpg_error_t err;
1954   char buf[100];
1955
1956   err = atoi (line);
1957   snprintf (buf, sizeof (buf), "%s <%s>", gpgme_strerror (err),
1958             gpgme_strsource (err));
1959   return assuan_send_data (ctx, buf, strlen (buf));
1960 }
1961
1962
1963 static gpg_error_t
1964 cmd_pubkey_algo_name (assuan_context_t ctx, char *line)
1965 {
1966   gpgme_pubkey_algo_t algo;
1967   char buf[100];
1968
1969   algo = atoi (line);
1970   snprintf (buf, sizeof (buf), "%s", gpgme_pubkey_algo_name (algo));
1971   return assuan_send_data (ctx, buf, strlen (buf));
1972 }
1973
1974
1975 static gpg_error_t
1976 cmd_hash_algo_name (assuan_context_t ctx, char *line)
1977 {
1978   gpgme_hash_algo_t algo;
1979   char buf[100];
1980
1981   algo = atoi (line);
1982   snprintf (buf, sizeof (buf), "%s", gpgme_hash_algo_name (algo));
1983   return assuan_send_data (ctx, buf, strlen (buf));
1984 }
1985
1986
1987 /* Tell the assuan library about our commands.  */
1988 static gpg_error_t
1989 register_commands (assuan_context_t ctx)
1990 {
1991   gpg_error_t err;
1992   static struct {
1993     const char *name;
1994     assuan_handler_t handler;
1995     const char * const help;
1996   } table[] = {
1997     // RESET, BYE are implicit.
1998     { "VERSION", cmd_version, hlp_version },
1999     // TODO: Set engine info.
2000     { "ENGINE", cmd_engine },
2001     { "PROTOCOL", cmd_protocol, hlp_protocol },
2002     { "SUB_PROTOCOL", cmd_sub_protocol },
2003     { "ARMOR", cmd_armor },
2004     { "TEXTMODE", cmd_textmode },
2005     { "INCLUDE_CERTS", cmd_include_certs },
2006     { "KEYLIST_MODE", cmd_keylist_mode },
2007     { "INPUT", NULL }, 
2008     { "OUTPUT", NULL }, 
2009     { "MESSAGE", cmd_message },
2010     { "RECIPIENT", cmd_recipient },
2011     { "SIGNER", cmd_signer },
2012     { "SIGNERS_CLEAR", cmd_signers_clear },
2013     // TODO: SIGNOTATION missing.
2014     // TODO: Could add wait interface if we allow more than one context
2015     // and add _START variants.
2016     // TODO: Could add data interfaces if we allow multiple data objects.
2017     { "DECRYPT", cmd_decrypt },
2018     { "DECRYPT_VERIFY", cmd_decrypt_verify },
2019     { "ENCRYPT", cmd_encrypt },
2020     { "ENCRYPT_SIGN", cmd_sign_encrypt },
2021     { "SIGN_ENCRYPT", cmd_sign_encrypt },
2022     { "SIGN", cmd_sign },
2023     { "VERIFY", cmd_verify },
2024     { "IMPORT", cmd_import },
2025     { "EXPORT", cmd_export },
2026     { "GENKEY", cmd_genkey },
2027     { "DELETE", cmd_delete },
2028     // TODO: EDIT, CARD_EDIT (with INQUIRE)
2029     { "KEYLIST", cmd_keylist },
2030     { "LISTKEYS", cmd_keylist },
2031     // TODO: TRUSTLIST, TRUSTLIST_EXT
2032     { "GETAUDITLOG", cmd_getauditlog },
2033     // TODO: ASSUAN
2034     { "VFS_MOUNT", cmd_vfs_mount },
2035     { "MOUNT", cmd_vfs_mount },
2036     { "VFS_CREATE", cmd_vfs_create },
2037     { "CREATE", cmd_vfs_create },
2038     // TODO: GPGCONF
2039     { "RESULT", cmd_result },
2040     { "STRERROR", cmd_strerror },
2041     { "PUBKEY_ALGO_NAME", cmd_pubkey_algo_name },
2042     { "HASH_ALGO_NAME", cmd_hash_algo_name },
2043     { NULL }
2044   };
2045   int idx;
2046
2047   for (idx = 0; table[idx].name; idx++)
2048     {
2049       err = assuan_register_command (ctx, table[idx].name, table[idx].handler,
2050                                      table[idx].help);
2051       if (err)
2052         return err;
2053     } 
2054   return 0;
2055 }
2056
2057
2058 /* TODO: password callback can do INQUIRE.  */
2059 void
2060 gpgme_server (gpgme_tool_t gt)
2061 {
2062   gpg_error_t err;
2063   assuan_fd_t filedes[2];
2064   struct server server;
2065   static const char hello[] = ("GPGME-Tool " VERSION " ready");
2066
2067   memset (&server, 0, sizeof (server));
2068   server.message_fd = -1;
2069   server.input_enc = GPGME_DATA_ENCODING_NONE;
2070   server.output_enc = GPGME_DATA_ENCODING_NONE;
2071   server.message_enc = GPGME_DATA_ENCODING_NONE;
2072
2073   server.gt = gt;
2074   gt->write_status = server_write_status;
2075   gt->write_status_hook = &server;
2076   gt->write_data = server_write_data;
2077   gt->write_data_hook = &server;
2078
2079   /* We use a pipe based server so that we can work from scripts.
2080      assuan_init_pipe_server will automagically detect when we are
2081      called with a socketpair and ignore FIELDES in this case. */
2082   filedes[0] = assuan_fdopen (0);
2083   filedes[1] = assuan_fdopen (1);
2084   err = assuan_new (&server.assuan_ctx);
2085   if (err)
2086     log_error (1, err, "can't create assuan context");
2087
2088   assuan_set_pointer (server.assuan_ctx, &server);
2089
2090   err = assuan_init_pipe_server (server.assuan_ctx, filedes);
2091   if (err)
2092     log_error (1, err, "can't initialize assuan server");
2093   err = register_commands (server.assuan_ctx);
2094   if (err)
2095     log_error (1, err, "can't register assuan commands");
2096   assuan_set_hello_line (server.assuan_ctx, hello);
2097
2098   assuan_register_reset_notify (server.assuan_ctx, reset_notify);
2099   assuan_register_input_notify (server.assuan_ctx, input_notify);
2100   assuan_register_output_notify (server.assuan_ctx, output_notify);
2101
2102 #define DBG_ASSUAN 0
2103   if (DBG_ASSUAN)
2104     assuan_set_log_stream (server.assuan_ctx, log_stream);
2105
2106   for (;;)
2107     {
2108       err = assuan_accept (server.assuan_ctx);
2109       if (err == -1)
2110         break;
2111       else if (err)
2112         {
2113           log_error (0, err, "assuan accept problem");
2114           break;
2115         }
2116       
2117       err = assuan_process (server.assuan_ctx);
2118       if (err)
2119         log_error (0, err, "assuan processing failed");
2120     }
2121
2122   assuan_release (server.assuan_ctx);
2123 }
2124
2125
2126 \f
2127 /* MAIN PROGRAM STARTS HERE.  */
2128
2129 const char *argp_program_version = VERSION;
2130 const char *argp_program_bug_address = "bug-gpgme@gnupg.org";
2131 error_t argp_err_exit_status = 1;
2132
2133 static char doc[] = "GPGME Tool -- invoke GPGME operations";
2134 static char args_doc[] = "COMMAND [OPTIONS...]";
2135
2136 static struct argp_option options[] = {
2137   { "server", 's', 0, 0, "Server mode" },
2138   { 0 }
2139 };
2140
2141 static error_t parse_options (int key, char *arg, struct argp_state *state);
2142 static struct argp argp = { options, parse_options, args_doc, doc };
2143
2144 struct args
2145 {
2146   enum { CMD_DEFAULT, CMD_SERVER } cmd;
2147 };
2148
2149 void
2150 args_init (struct args *args)
2151 {
2152   memset (args, '\0', sizeof (*args));
2153   args->cmd = CMD_DEFAULT;
2154 }
2155
2156
2157 static error_t
2158 parse_options (int key, char *arg, struct argp_state *state)
2159 {
2160   struct args *args = state->input;
2161
2162   switch (key)
2163     {
2164     case 's':
2165       args->cmd = CMD_SERVER;
2166       break;
2167 #if 0
2168     case ARGP_KEY_ARG:
2169       if (state->arg_num >= 2)
2170         argp_usage (state);
2171       printf ("Arg[%i] = %s\n", state->arg_num, arg);
2172       break;
2173     case ARGP_KEY_END:
2174       if (state->arg_num < 2)
2175         argp_usage (state);
2176       break;
2177 #endif
2178
2179     default:
2180       return ARGP_ERR_UNKNOWN;
2181     }
2182   return 0;
2183 }
2184
2185 \f
2186 int
2187 main (int argc, char *argv[])
2188 {
2189   struct args args;
2190   struct gpgme_tool gt;
2191
2192   setlocale (LC_ALL, "");
2193   gpgme_check_version (NULL);
2194   gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
2195 #ifdef LC_MESSAGES
2196   gpgme_set_locale (NULL, LC_MESSAGES, setlocale (LC_MESSAGES, NULL));
2197 #endif
2198   args_init (&args);
2199
2200   argp_parse (&argp, argc, argv, 0, 0, &args);
2201   log_init ();
2202
2203   gt_init (&gt);
2204
2205   switch (args.cmd)
2206     {
2207     case CMD_DEFAULT:
2208     case CMD_SERVER:
2209       gpgme_server (&gt);
2210       break;
2211     }
2212
2213   gpgme_release (gt.ctx);
2214
2215   return 0;
2216 }
2217