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