2009-11-02 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 gpg_error_t
1207 input_notify (assuan_context_t ctx, char *line)
1208 {
1209   struct server *server = assuan_get_pointer (ctx);
1210   server->input_enc = server_data_encoding (line);
1211   return 0;
1212 }
1213
1214
1215 static gpg_error_t
1216 output_notify (assuan_context_t ctx, char *line)
1217 {
1218   struct server *server = assuan_get_pointer (ctx);
1219   server->output_enc = server_data_encoding (line);
1220   return 0;
1221 }
1222
1223
1224 static gpg_error_t
1225 cmd_message (assuan_context_t ctx, char *line)
1226 {
1227   struct server *server = assuan_get_pointer (ctx);
1228   gpg_error_t err;
1229   assuan_fd_t sysfd;
1230
1231   err = assuan_command_parse_fd (ctx, line, &sysfd);
1232   if (err)
1233     return err;
1234   server->message_fd = sysfd;
1235   server->message_enc = server_data_encoding (line);
1236   return 0;
1237 }
1238
1239
1240 static gpg_error_t
1241 cmd_recipient (assuan_context_t ctx, char *line)
1242 {
1243   struct server *server = assuan_get_pointer (ctx);
1244
1245   return gt_recipients_add (server->gt, line);
1246 }
1247
1248
1249 static gpg_error_t
1250 cmd_signer (assuan_context_t ctx, char *line)
1251 {
1252   struct server *server = assuan_get_pointer (ctx);
1253
1254   return gt_signers_add (server->gt, line);
1255 }
1256
1257
1258 static gpg_error_t
1259 cmd_signers_clear (assuan_context_t ctx, char *line)
1260 {
1261   struct server *server = assuan_get_pointer (ctx);
1262
1263   return gt_signers_clear (server->gt);
1264 }
1265
1266
1267 static gpg_error_t
1268 _cmd_decrypt_verify (assuan_context_t ctx, char *line, int verify)
1269 {
1270   struct server *server = assuan_get_pointer (ctx);
1271   gpg_error_t err;
1272   assuan_fd_t inp_fd;
1273   assuan_fd_t out_fd;
1274   gpgme_data_t inp_data;
1275   gpgme_data_t out_data;
1276
1277   inp_fd = assuan_get_input_fd (ctx);
1278   if (inp_fd == ASSUAN_INVALID_FD)
1279     return GPG_ERR_ASS_NO_INPUT;
1280   out_fd = assuan_get_output_fd (ctx);
1281   if (out_fd == ASSUAN_INVALID_FD)
1282     return GPG_ERR_ASS_NO_OUTPUT;
1283   
1284   err = server_data_obj (inp_fd, server->input_enc, &inp_data);
1285   if (err)
1286     return err;
1287   err = server_data_obj (out_fd, server->output_enc, &out_data);
1288   if (err)
1289     {
1290       gpgme_data_release (inp_data);
1291       return err;
1292     }
1293
1294   err = gt_decrypt_verify (server->gt, inp_data, out_data, verify); 
1295
1296   gpgme_data_release (inp_data);
1297   gpgme_data_release (out_data);
1298
1299   server_reset_fds (server);
1300
1301   return err;
1302 }
1303
1304
1305 static gpg_error_t
1306 cmd_decrypt (assuan_context_t ctx, char *line)
1307 {
1308   return _cmd_decrypt_verify (ctx, line, 0);
1309 }
1310
1311
1312 static gpg_error_t
1313 cmd_decrypt_verify (assuan_context_t ctx, char *line)
1314 {
1315   return _cmd_decrypt_verify (ctx, line, 1);
1316 }
1317
1318
1319 static gpg_error_t
1320 _cmd_sign_encrypt (assuan_context_t ctx, char *line, int sign)
1321 {
1322   struct server *server = assuan_get_pointer (ctx);
1323   gpg_error_t err;
1324   assuan_fd_t inp_fd;
1325   assuan_fd_t out_fd;
1326   gpgme_data_t inp_data;
1327   gpgme_data_t out_data;
1328   gpgme_encrypt_flags_t flags = 0;
1329
1330   if (strstr (line, "--always-trust"))
1331     flags |= GPGME_ENCRYPT_ALWAYS_TRUST;
1332   if (strstr (line, "--no-encrypt-to"))
1333     flags |= GPGME_ENCRYPT_NO_ENCRYPT_TO;
1334   
1335   inp_fd = assuan_get_input_fd (ctx);
1336   if (inp_fd == ASSUAN_INVALID_FD)
1337     return GPG_ERR_ASS_NO_INPUT;
1338   out_fd = assuan_get_output_fd (ctx);
1339   if (out_fd == ASSUAN_INVALID_FD)
1340     return GPG_ERR_ASS_NO_OUTPUT;
1341   
1342   err = server_data_obj (inp_fd, server->input_enc, &inp_data);
1343   if (err)
1344     return err;
1345   err = server_data_obj (out_fd, server->output_enc, &out_data);
1346   if (err)
1347     {
1348       gpgme_data_release (inp_data);
1349       return err;
1350     }
1351
1352   err = gt_sign_encrypt (server->gt, flags, inp_data, out_data, sign); 
1353
1354   gpgme_data_release (inp_data);
1355   gpgme_data_release (out_data);
1356
1357   server_reset_fds (server);
1358
1359   return err;
1360 }
1361
1362
1363 static gpg_error_t
1364 cmd_encrypt (assuan_context_t ctx, char *line)
1365 {
1366   return _cmd_sign_encrypt (ctx, line, 0);
1367 }
1368
1369
1370 static gpg_error_t
1371 cmd_sign_encrypt (assuan_context_t ctx, char *line)
1372 {
1373   return _cmd_sign_encrypt (ctx, line, 1);
1374 }
1375
1376
1377 static gpg_error_t
1378 cmd_sign (assuan_context_t ctx, char *line)
1379 {
1380   struct server *server = assuan_get_pointer (ctx);
1381   gpg_error_t err;
1382   assuan_fd_t inp_fd;
1383   assuan_fd_t out_fd;
1384   gpgme_data_t inp_data;
1385   gpgme_data_t out_data;
1386   gpgme_sig_mode_t mode = GPGME_SIG_MODE_NORMAL;
1387
1388   if (strstr (line, "--clear"))
1389     mode = GPGME_SIG_MODE_CLEAR;
1390   if (strstr (line, "--detach"))
1391     mode = GPGME_SIG_MODE_DETACH;
1392
1393   inp_fd = assuan_get_input_fd (ctx);
1394   if (inp_fd == ASSUAN_INVALID_FD)
1395     return GPG_ERR_ASS_NO_INPUT;
1396   out_fd = assuan_get_output_fd (ctx);
1397   if (out_fd == ASSUAN_INVALID_FD)
1398     return GPG_ERR_ASS_NO_OUTPUT;
1399   
1400   err = server_data_obj (inp_fd, server->input_enc, &inp_data);
1401   if (err)
1402     return err;
1403   err = server_data_obj (out_fd, server->output_enc, &out_data);
1404   if (err)
1405     {
1406       gpgme_data_release (inp_data);
1407       return err;
1408     }
1409
1410   err = gt_sign (server->gt, inp_data, out_data, mode);
1411
1412   gpgme_data_release (inp_data);
1413   gpgme_data_release (out_data);
1414   server_reset_fds (server);
1415
1416   return err;
1417 }
1418
1419
1420 static gpg_error_t
1421 cmd_verify (assuan_context_t ctx, char *line)
1422 {
1423   struct server *server = assuan_get_pointer (ctx);
1424   gpg_error_t err;
1425   assuan_fd_t inp_fd;
1426   assuan_fd_t msg_fd;
1427   assuan_fd_t out_fd;
1428   gpgme_data_t inp_data;
1429   gpgme_data_t msg_data = NULL;
1430   gpgme_data_t out_data = NULL;
1431
1432   inp_fd = assuan_get_input_fd (ctx);
1433   if (inp_fd == ASSUAN_INVALID_FD)
1434     return GPG_ERR_ASS_NO_INPUT;
1435   msg_fd = server->message_fd;
1436   out_fd = assuan_get_output_fd (ctx);
1437   
1438   err = server_data_obj (inp_fd, server->input_enc, &inp_data);
1439   if (err)
1440     return err;
1441   if (msg_fd != ASSUAN_INVALID_FD)
1442     {
1443       err = server_data_obj (msg_fd, server->message_enc, &msg_data);
1444       if (err)
1445         {
1446           gpgme_data_release (inp_data);
1447           return err;
1448         }
1449     }
1450   if (out_fd != ASSUAN_INVALID_FD)
1451     {
1452       err = server_data_obj (out_fd, server->output_enc, &out_data);
1453       if (err)
1454         {
1455           gpgme_data_release (inp_data);
1456           gpgme_data_release (msg_data);
1457           return err;
1458         }
1459     }
1460
1461   err = gt_verify (server->gt, inp_data, msg_data, out_data);
1462
1463   gpgme_data_release (inp_data);
1464   if (msg_data)
1465     gpgme_data_release (msg_data);
1466   if (out_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_import (assuan_context_t ctx, char *line)
1477 {
1478   struct server *server = assuan_get_pointer (ctx);
1479   
1480   if (line && *line)
1481     {
1482       char *fprs[2] = { line, NULL };
1483
1484       return gt_import_keys (server->gt, fprs);
1485     }
1486   else
1487     {
1488       gpg_error_t err;
1489       assuan_fd_t inp_fd;
1490       gpgme_data_t inp_data;
1491       
1492       inp_fd = assuan_get_input_fd (ctx);
1493       if (inp_fd == ASSUAN_INVALID_FD)
1494         return GPG_ERR_ASS_NO_INPUT;
1495
1496       err = server_data_obj (inp_fd, server->input_enc, &inp_data);
1497       if (err)
1498         return err;
1499       
1500       err = gt_import (server->gt, inp_data); 
1501       
1502       gpgme_data_release (inp_data);
1503       server_reset_fds (server);
1504
1505       return err;
1506     }
1507 }
1508
1509
1510 static gpg_error_t
1511 cmd_export (assuan_context_t ctx, char *line)
1512 {
1513   struct server *server = assuan_get_pointer (ctx);
1514   gpg_error_t err;
1515   assuan_fd_t out_fd;
1516   gpgme_data_t out_data;
1517   gpgme_export_mode_t mode = 0;
1518   const char *pattern[2];
1519   const char optstr[] = "--extern ";
1520
1521   out_fd = assuan_get_output_fd (ctx);
1522   if (out_fd == ASSUAN_INVALID_FD)
1523     return GPG_ERR_ASS_NO_OUTPUT;
1524   err = server_data_obj (out_fd, server->output_enc, &out_data);
1525   if (err)
1526     return err;
1527
1528   if (strncasecmp (line, optstr, strlen (optstr)))
1529     {
1530       mode |= GPGME_EXPORT_MODE_EXTERN;
1531       line += strlen (optstr);
1532     }
1533   pattern[0] = line;
1534   pattern[1] = NULL;
1535
1536   err = gt_export (server->gt, pattern, mode, out_data);
1537
1538   gpgme_data_release (out_data);
1539   server_reset_fds (server);
1540
1541   return err;
1542 }
1543
1544
1545 static gpg_error_t
1546 _cmd_genkey_write (gpgme_data_t data, const void *buf, size_t size)
1547 {
1548   while (size > 0)
1549     {
1550       ssize_t writen = gpgme_data_write (data, buf, size);
1551       if (writen < 0 && errno != EAGAIN)
1552         return gpg_error_from_syserror ();
1553       else if (writen > 0)
1554         {
1555           buf = (void *) (((char *) buf) + writen);
1556           size -= writen;
1557         }
1558     }
1559   return 0;
1560 }
1561
1562
1563 static gpg_error_t
1564 cmd_genkey (assuan_context_t ctx, char *line)
1565 {
1566   struct server *server = assuan_get_pointer (ctx);
1567   gpg_error_t err;
1568   assuan_fd_t inp_fd;
1569   assuan_fd_t out_fd;
1570   gpgme_data_t inp_data;
1571   gpgme_data_t out_data = NULL;
1572   gpgme_data_t parms_data = NULL;
1573   const char *parms;
1574
1575   inp_fd = assuan_get_input_fd (ctx);
1576   if (inp_fd == ASSUAN_INVALID_FD)
1577     return GPG_ERR_ASS_NO_INPUT;
1578   out_fd = assuan_get_output_fd (ctx);
1579   
1580   err = server_data_obj (inp_fd, server->input_enc, &inp_data);
1581   if (err)
1582     return err;
1583   if (out_fd != ASSUAN_INVALID_FD)
1584     {
1585       err = server_data_obj (out_fd, server->output_enc, &out_data);
1586       if (err)
1587         {
1588           gpgme_data_release (inp_data);
1589           return err;
1590         }
1591     }
1592
1593   /* Convert input data.  */
1594   err = gpgme_data_new (&parms_data);
1595   if (err)
1596     goto out;
1597   do
1598     {
1599       char buf[512];
1600       ssize_t readn = gpgme_data_read (inp_data, buf, sizeof (buf));
1601       if (readn < 0)
1602         {
1603           err = gpg_error_from_syserror ();
1604           goto out;
1605         }
1606       else if (readn == 0)
1607         break;
1608
1609       err = _cmd_genkey_write (parms_data, buf, readn);
1610       if (err)
1611         goto out;
1612     }
1613   while (1);
1614   err = _cmd_genkey_write (parms_data, "", 1);
1615   if (err)
1616     goto out;
1617   parms = gpgme_data_release_and_get_mem (parms_data, NULL);
1618   parms_data = NULL;
1619   if (! parms)
1620     {
1621       err = gpg_error (GPG_ERR_GENERAL);
1622       goto out;
1623     }
1624
1625   err = gt_genkey (server->gt, parms, out_data, NULL);
1626
1627   server_reset_fds (server);
1628
1629  out:
1630   gpgme_data_release (inp_data);
1631   if (out_data)
1632     gpgme_data_release (out_data);
1633   if (parms_data)
1634     gpgme_data_release (parms_data);
1635
1636   return err; 
1637 }
1638
1639
1640 static gpg_error_t
1641 cmd_delete (assuan_context_t ctx, char *line)
1642 {
1643   struct server *server = assuan_get_pointer (ctx);
1644   int allow_secret = 0;
1645   const char optstr[] = "--allow-secret ";
1646
1647   if (strncasecmp (line, optstr, strlen (optstr)))
1648     {
1649       allow_secret = 1;
1650       line += strlen (optstr);
1651     }
1652   return gt_delete (server->gt, line, allow_secret);
1653 }
1654
1655
1656 static gpg_error_t
1657 cmd_keylist (assuan_context_t ctx, char *line)
1658 {
1659   struct server *server = assuan_get_pointer (ctx);
1660   gpg_error_t err;
1661   int secret_only = 0;
1662   const char *pattern[2];
1663   const char optstr[] = "--secret-only ";
1664
1665   if (strncasecmp (line, optstr, strlen (optstr)))
1666     {
1667       secret_only = 1;
1668       line += strlen (optstr);
1669     }
1670   pattern[0] = line;
1671   pattern[1] = NULL;
1672
1673   err = gt_keylist_start (server->gt, pattern, secret_only);
1674   while (! err)
1675     {
1676       gpgme_key_t key;
1677
1678       err = gt_keylist_next (server->gt, &key);
1679       if (gpg_err_code (err) == GPG_ERR_EOF)
1680         {
1681           err = 0;
1682           break;
1683         }
1684       else if (! err)
1685         {
1686           char buf[100];
1687           /* FIXME: More data.  */
1688           snprintf (buf, sizeof (buf), "key:%s\n", key->subkeys->fpr);
1689           assuan_send_data (ctx, buf, strlen (buf));
1690           gpgme_key_unref (key);
1691         }
1692     }
1693   
1694   server_reset_fds (server);
1695
1696   return err;
1697 }
1698
1699
1700 static gpg_error_t
1701 cmd_getauditlog (assuan_context_t ctx, char *line)
1702 {
1703   struct server *server = assuan_get_pointer (ctx);
1704   gpg_error_t err;
1705   assuan_fd_t out_fd;
1706   gpgme_data_t out_data;
1707
1708   out_fd = assuan_get_output_fd (ctx);
1709   if (out_fd == ASSUAN_INVALID_FD)
1710     return GPG_ERR_ASS_NO_OUTPUT;
1711   err = server_data_obj (out_fd, server->output_enc, &out_data);
1712   if (err)
1713     return err;
1714
1715   err = gt_getauditlog (server->gt, out_data, 0);
1716
1717   gpgme_data_release (out_data);
1718   server_reset_fds (server);
1719
1720   return err;
1721 }
1722
1723
1724 static gpg_error_t
1725 cmd_vfs_mount (assuan_context_t ctx, char *line)
1726 {
1727   struct server *server = assuan_get_pointer (ctx);
1728   char *mount_dir;
1729   gpg_error_t err;
1730
1731   mount_dir = strchr (line, ' ');
1732   if (mount_dir)
1733     {
1734       *(mount_dir++) = '\0';
1735       while (*mount_dir == ' ')
1736         mount_dir++;
1737     }
1738
1739   err = gt_vfs_mount (server->gt, line, mount_dir, 0);
1740
1741   return err;
1742 }
1743
1744
1745 static gpg_error_t
1746 cmd_result (assuan_context_t ctx, char *line)
1747 {
1748   struct server *server = assuan_get_pointer (ctx);
1749   return gt_result (server->gt, GT_RESULT_ALL);
1750 }
1751
1752
1753 /* STRERROR <err>  */
1754 static gpg_error_t
1755 cmd_strerror (assuan_context_t ctx, char *line)
1756 {
1757   gpg_error_t err;
1758   char buf[100];
1759
1760   err = atoi (line);
1761   snprintf (buf, sizeof (buf), "%s <%s>", gpgme_strerror (err),
1762             gpgme_strsource (err));
1763   return assuan_send_data (ctx, buf, strlen (buf));
1764 }
1765
1766
1767 static gpg_error_t
1768 cmd_pubkey_algo_name (assuan_context_t ctx, char *line)
1769 {
1770   gpgme_pubkey_algo_t algo;
1771   char buf[100];
1772
1773   algo = atoi (line);
1774   snprintf (buf, sizeof (buf), "%s", gpgme_pubkey_algo_name (algo));
1775   return assuan_send_data (ctx, buf, strlen (buf));
1776 }
1777
1778
1779 static gpg_error_t
1780 cmd_hash_algo_name (assuan_context_t ctx, char *line)
1781 {
1782   gpgme_hash_algo_t algo;
1783   char buf[100];
1784
1785   algo = atoi (line);
1786   snprintf (buf, sizeof (buf), "%s", gpgme_hash_algo_name (algo));
1787   return assuan_send_data (ctx, buf, strlen (buf));
1788 }
1789
1790
1791 /* Tell the assuan library about our commands.  */
1792 static gpg_error_t
1793 register_commands (assuan_context_t ctx)
1794 {
1795   gpg_error_t err;
1796   static struct {
1797     const char *name;
1798     gpg_error_t (*handler)(assuan_context_t, char *line);
1799   } table[] = {
1800     // RESET, BYE are implicit.
1801     { "VERSION", cmd_version },
1802     // TODO: Set engine info.
1803     { "ENGINE", cmd_engine },
1804     { "PROTOCOL", cmd_protocol },
1805     { "ARMOR", cmd_armor },
1806     { "TEXTMODE", cmd_textmode },
1807     { "INCLUDE_CERTS", cmd_include_certs },
1808     { "KEYLIST_MODE", cmd_keylist_mode },
1809     { "INPUT", NULL }, 
1810     { "OUTPUT", NULL }, 
1811     { "MESSAGE", cmd_message },
1812     { "RECIPIENT", cmd_recipient },
1813     { "SIGNER", cmd_signer },
1814     { "SIGNERS_CLEAR", cmd_signers_clear },
1815     // TODO: SIGNOTATION missing.
1816     // TODO: Could add wait interface if we allow more than one context
1817     // and add _START variants.
1818     // TODO: Could add data interfaces if we allow multiple data objects.
1819     { "DECRYPT", cmd_decrypt },
1820     { "DECRYPT_VERIFY", cmd_decrypt_verify },
1821     { "ENCRYPT", cmd_encrypt },
1822     { "ENCRYPT_SIGN", cmd_sign_encrypt },
1823     { "SIGN_ENCRYPT", cmd_sign_encrypt },
1824     { "SIGN", cmd_sign },
1825     { "VERIFY", cmd_verify },
1826     { "IMPORT", cmd_import },
1827     { "EXPORT", cmd_export },
1828     { "GENKEY", cmd_genkey },
1829     { "DELETE", cmd_delete },
1830     // TODO: EDIT, CARD_EDIT (with INQUIRE)
1831     { "KEYLIST", cmd_keylist },
1832     { "LISTKEYS", cmd_keylist },
1833     // TODO: TRUSTLIST, TRUSTLIST_EXT
1834     { "GETAUDITLOG", cmd_getauditlog },
1835     // TODO: ASSUAN
1836     { "VFS_MOUNT", cmd_vfs_mount },
1837     { "MOUNT", cmd_vfs_mount },
1838     // TODO: GPGCONF
1839     { "RESULT", cmd_result },
1840     { "STRERROR", cmd_strerror },
1841     { "PUBKEY_ALGO_NAME", cmd_pubkey_algo_name },
1842     { "HASH_ALGO_NAME", cmd_hash_algo_name },
1843     { NULL }
1844   };
1845   int idx;
1846
1847   for (idx = 0; table[idx].name; idx++)
1848     {
1849       err = assuan_register_command (ctx, table[idx].name, table[idx].handler);
1850       if (err)
1851         return err;
1852     } 
1853   return 0;
1854 }
1855
1856
1857 /* TODO: password callback can do INQUIRE.  */
1858 void
1859 gpgme_server (gpgme_tool_t gt)
1860 {
1861   gpg_error_t err;
1862   int filedes[2];
1863   struct server server;
1864   static const char hello[] = ("GPGME-Tool " VERSION " ready");
1865
1866   memset (&server, 0, sizeof (server));
1867   server.message_fd = -1;
1868   server.input_enc = GPGME_DATA_ENCODING_NONE;
1869   server.output_enc = GPGME_DATA_ENCODING_NONE;
1870   server.message_enc = GPGME_DATA_ENCODING_NONE;
1871
1872   server.gt = gt;
1873   gt->write_status = server_write_status;
1874   gt->write_status_hook = &server;
1875
1876   /* We use a pipe based server so that we can work from scripts.
1877      assuan_init_pipe_server will automagically detect when we are
1878      called with a socketpair and ignore FIELDES in this case. */
1879   filedes[0] = 0;
1880   filedes[1] = 1;
1881   err = assuan_new (&server.assuan_ctx);
1882   if (err)
1883     log_error (1, err, "can't create assuan context");
1884
1885   assuan_set_pointer (server.assuan_ctx, &server);
1886
1887   err = assuan_init_pipe_server (server.assuan_ctx, filedes);
1888   if (err)
1889     log_error (1, err, "can't initialize assuan server");
1890   err = register_commands (server.assuan_ctx);
1891   if (err)
1892     log_error (1, err, "can't register assuan commands");
1893   assuan_set_hello_line (server.assuan_ctx, hello);
1894
1895   assuan_register_reset_notify (server.assuan_ctx, reset_notify);
1896   assuan_register_input_notify (server.assuan_ctx, input_notify);
1897   assuan_register_output_notify (server.assuan_ctx, output_notify);
1898
1899 #define DBG_ASSUAN 0
1900   if (DBG_ASSUAN)
1901     assuan_set_log_stream (server.assuan_ctx, log_stream);
1902
1903   for (;;)
1904     {
1905       err = assuan_accept (server.assuan_ctx);
1906       if (err == -1)
1907         break;
1908       else if (err)
1909         {
1910           log_error (0, err, "assuan accept problem");
1911           break;
1912         }
1913       
1914       err = assuan_process (server.assuan_ctx);
1915       if (err)
1916         log_error (0, err, "assuan processing failed");
1917     }
1918
1919   assuan_release (server.assuan_ctx);
1920 }
1921
1922
1923 \f
1924 /* MAIN PROGRAM STARTS HERE.  */
1925
1926 const char *argp_program_version = VERSION;
1927 const char *argp_program_bug_address = "bug-gpgme@gnupg.org";
1928 error_t argp_err_exit_status = 1;
1929
1930 static char doc[] = "GPGME Tool -- invoke GPGME operations";
1931 static char args_doc[] = "COMMAND [OPTIONS...]";
1932
1933 static struct argp_option options[] = {
1934   { "server", 's', 0, 0, "Server mode" },
1935   { 0 }
1936 };
1937
1938 static error_t parse_options (int key, char *arg, struct argp_state *state);
1939 static struct argp argp = { options, parse_options, args_doc, doc };
1940
1941 struct args
1942 {
1943   enum { CMD_DEFAULT, CMD_SERVER } cmd;
1944 };
1945
1946 void
1947 args_init (struct args *args)
1948 {
1949   memset (args, '\0', sizeof (*args));
1950   args->cmd = CMD_DEFAULT;
1951 }
1952
1953
1954 static error_t
1955 parse_options (int key, char *arg, struct argp_state *state)
1956 {
1957   struct args *args = state->input;
1958
1959   switch (key)
1960     {
1961     case 's':
1962       args->cmd = CMD_SERVER;
1963       break;
1964 #if 0
1965     case ARGP_KEY_ARG:
1966       if (state->arg_num >= 2)
1967         argp_usage (state);
1968       printf ("Arg[%i] = %s\n", state->arg_num, arg);
1969       break;
1970     case ARGP_KEY_END:
1971       if (state->arg_num < 2)
1972         argp_usage (state);
1973       break;
1974 #endif
1975
1976     default:
1977       return ARGP_ERR_UNKNOWN;
1978     }
1979   return 0;
1980 }
1981
1982 \f
1983 int
1984 main (int argc, char *argv[])
1985 {
1986   struct args args;
1987   struct gpgme_tool gt;
1988
1989   setlocale (LC_ALL, "");
1990   gpgme_check_version (NULL);
1991   gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
1992 #ifdef LC_MESSAGES
1993   gpgme_set_locale (NULL, LC_MESSAGES, setlocale (LC_MESSAGES, NULL));
1994 #endif
1995   args_init (&args);
1996
1997   argp_parse (&argp, argc, argv, 0, 0, &args);
1998   log_init ();
1999
2000   gt_init (&gt);
2001
2002   switch (args.cmd)
2003     {
2004     case CMD_DEFAULT:
2005     case CMD_SERVER:
2006       gpgme_server (&gt);
2007       break;
2008     }
2009
2010   gpgme_release (gt.ctx);
2011
2012   return 0;
2013 }
2014