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