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