Add function gpgme_data_identify.
[gpgme.git] / src / gpgme-tool.c
1 /* gpgme-tool.c - Assuan server exposing GnuPG Made Easy operations.
2    Copyright (C) 2009, 2010, 2012, 2013 g10 Code GmbH
3    Copyright (C) 2001, 2003, 2009, 2011 Free Software Foundation, Inc.
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 General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (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, see <http://www.gnu.org/licenses/>.
19  */
20
21 #if HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <getopt.h>
30 #include <ctype.h>
31 #include <stdarg.h>
32 #ifdef HAVE_LOCALE_H
33 #include <locale.h>
34 #endif
35 #ifdef HAVE_ARGP_H
36 #include <argp.h>
37 #endif
38
39 #include <assuan.h>
40
41 #include "gpgme.h"
42
43 /* GCC attributes.  */
44 #if __GNUC__ >= 4
45 # define GT_GCC_A_SENTINEL(a) __attribute__ ((sentinel(a)))
46 #else
47 # define GT_GCC_A_SENTINEL(a)
48 #endif
49
50 #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )
51 # define GT_GCC_A_PRINTF(f, a)  __attribute__ ((format (printf,f,a)))
52 #else
53 # define GT_GCC_A_PRINTF(f, a)
54 #endif
55
56 #define DIM(v) (sizeof(v)/sizeof((v)[0]))
57 #define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
58                      *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
59 #define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
60
61
62 \f
63 #ifndef HAVE_ARGP_H
64 /* Minimal argp implementation.  */
65
66 /* Differences to ARGP:
67    argp_program_version: Required.
68    argp_program_bug_address: Required.
69    argp_program_version_hook: Not supported.
70    argp_err_exit_status: Required.
71    struct argp: Children and help_filter not supported.
72    argp_domain: Not supported.
73    struct argp_option: Group not supported.  Options are printed in
74    order given.  Flags OPTION_ALIAS, OPTION_DOC and OPTION_NO_USAGE
75    are not supported.
76    argp_parse: No flags are supported (ARGP_PARSE_ARGV0, ARGP_NO_ERRS,
77    ARGP_NO_ARGS, ARGP_IN_ORDER, ARGP_NO_HELP, ARGP_NO_EXIT,
78    ARGP_LONG_ONLY, ARGP_SILENT).  ARGP must not be NULL.
79    argp_help: Flag ARGP_HELP_LONG_ONLY not supported.
80    argp_state: argc, argv, next may not be modified and should not be used.  */
81
82 extern const char *argp_program_version;
83 extern const char *argp_program_bug_address;
84 extern error_t argp_err_exit_status;
85
86 struct argp_option
87 {
88   const char *name;
89   int key;
90   const char *arg;
91 #define OPTION_ARG_OPTIONAL 0x1
92 #define OPTION_HIDDEN 0x2
93   int flags;
94   const char *doc;
95   int group;
96 };
97
98 struct argp;
99 struct argp_state
100 {
101   const struct argp *const root_argp;
102   int argc;
103   char **argv;
104   int next;
105   unsigned flags;
106   unsigned arg_num;
107   int quoted;
108   void *input;
109   void **child_inputs;
110   void *hook;
111   char *name;
112   FILE *err_stream;
113   FILE *out_stream;
114   void *pstate;
115 };
116
117 #ifdef EDEADLK
118 # define ARGP_ERR_UNKNOWN EDEADLK /* POSIX */
119 #else
120 # define ARGP_ERR_UNKNOWN EDEADLOCK /* *GNU/kFreebsd does not define this) */
121 #endif
122 #define ARGP_KEY_ARG 0
123 #define ARGP_KEY_ARGS 0x1000006
124 #define ARGP_KEY_END 0x1000001
125 #define ARGP_KEY_NO_ARGS 0x1000002
126 #define ARGP_KEY_INIT 0x1000003
127 #define ARGP_KEY_FINI 0x1000007
128 #define ARGP_KEY_SUCCESS 0x1000004
129 #define ARGP_KEY_ERROR 0x1000005
130 typedef error_t (*argp_parser_t) (int key, char *arg, struct argp_state *state);
131
132 struct argp
133 {
134   const struct argp_option *options;
135   argp_parser_t parser;
136   const char *args_doc;
137   const char *doc;
138
139   const struct argp_child *children;
140   char *(*help_filter) (int key, const char *text, void *input);
141   const char *argp_domain;
142 };
143
144 #define ARGP_HELP_USAGE ARGP_HELP_SHORT_USAGE
145 #define ARGP_HELP_SHORT_USAGE 0x02
146 #define ARGP_HELP_SEE 0x04
147 #define ARGP_HELP_LONG 0x08
148 #define ARGP_HELP_PRE_DOC 0x10
149 #define ARGP_HELP_POST_DOC 0x20
150 #define ARGP_HELP_DOC (ARGP_HELP_PRE_DOC | ARGP_HELP_POST_DOC)
151 #define ARGP_HELP_BUG_ADDR 0x40
152 #define ARGP_HELP_EXIT_ERR 0x100
153 #define ARGP_HELP_EXIT_OK 0x200
154 #define ARGP_HELP_STD_ERR (ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR)
155 #define ARGP_HELP_STD_USAGE \
156   (ARGP_HELP_SHORT_USAGE | ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR)
157 #define ARGP_HELP_STD_HELP \
158   (ARGP_HELP_SHORT_USAGE | ARGP_HELP_LONG | ARGP_HELP_EXIT_OK   \
159    | ARGP_HELP_DOC | ARGP_HELP_BUG_ADDR)
160
161
162 void argp_error (const struct argp_state *state,
163                  const char *fmt, ...) GT_GCC_A_PRINTF(2, 3);
164
165
166
167 char *
168 _argp_pname (char *name)
169 {
170   char *pname = name;
171   char *bname = strrchr (pname, '/');
172   if (! bname)
173     bname = strrchr (pname, '\\');
174   if (bname)
175     pname = bname + 1;
176   return pname;
177 }
178
179
180 void
181 _argp_state_help (const struct argp *argp, const struct argp_state *state,
182                   FILE *stream, unsigned flags, char *name)
183 {
184   if (state)
185     name = state->name;
186
187   if (flags & ARGP_HELP_SHORT_USAGE)
188     fprintf (stream, "Usage: %s [OPTIONS...] %s\n", name, argp->args_doc);
189   if (flags & ARGP_HELP_SEE)
190     fprintf (stream, "Try `%s --help' or `%s --usage' for more information.\n",
191              name, name);
192   if (flags & ARGP_HELP_PRE_DOC)
193     {
194       char buf[1024];
195       char *end;
196       strncpy (buf, argp->doc, sizeof (buf));
197       buf[sizeof (buf) - 1] = '\0';
198       end = strchr (buf, '\v');
199       if (end)
200         *end = '\0';
201       fprintf (stream, "%s\n%s", buf, buf[0] ? "\n" : "");
202     }
203   if (flags & ARGP_HELP_LONG)
204     {
205       const struct argp_option *opt = argp->options;
206       while (opt->key)
207         {
208           #define NSPACES 29
209           char spaces[NSPACES + 1] = "                              ";
210           int len = 0;
211           fprintf (stream, "  ");
212           len += 2;
213           if (isascii (opt->key))
214             {
215               fprintf (stream, "-%c", opt->key);
216               len += 2;
217               if (opt->name)
218                 {
219                   fprintf (stream, ", ");
220                   len += 2;
221                 }
222             }
223           if (opt->name)
224             {
225               fprintf (stream, "--%s", opt->name);
226               len += 2 + strlen (opt->name);
227             }
228           if (opt->arg && (opt->flags & OPTION_ARG_OPTIONAL))
229             {
230               fprintf (stream, "[=%s]", opt->arg);
231               len += 3 + strlen (opt->arg);
232             }
233           else if (opt->arg)
234             {
235               fprintf (stream, "=%s", opt->arg);
236               len += 1 + strlen (opt->arg);
237             }
238           if (len >= NSPACES)
239             len = NSPACES - 1;
240           spaces[NSPACES - len] = '\0';
241           fprintf (stream, "%s%s\n", spaces, opt->doc);
242           opt++;
243         }
244       fprintf (stream, "  -?, --help                 Give this help list\n");
245       fprintf (stream, "      --usage                Give a short usage "
246                "message\n");
247     }
248   if (flags & ARGP_HELP_POST_DOC)
249     {
250       char buf[1024];
251       char *end;
252       strncpy (buf, argp->doc, sizeof (buf));
253       buf[sizeof (buf) - 1] = '\0';
254       end = strchr (buf, '\v');
255       if (end)
256         {
257           end++;
258           if (*end)
259             fprintf (stream, "\n%s\n", end);
260         }
261       fprintf (stream, "\nMandatory or optional arguments to long options are also mandatory or optional\n");
262       fprintf (stream, "for any corresponding short options.\n");
263     }
264   if (flags & ARGP_HELP_BUG_ADDR)
265     fprintf (stream, "\nReport bugs to %s.\n", argp_program_bug_address);
266
267   if (flags & ARGP_HELP_EXIT_ERR)
268     exit (argp_err_exit_status);
269   if (flags & ARGP_HELP_EXIT_OK)
270     exit (0);
271 }
272
273
274 void
275 argp_usage (const struct argp_state *state)
276 {
277   _argp_state_help (state->root_argp, state, state->err_stream,
278                     ARGP_HELP_STD_USAGE, state->name);
279 }
280
281
282 void
283 argp_state_help (const struct argp_state *state, FILE *stream, unsigned flags)
284 {
285   _argp_state_help (state->root_argp, state, stream, flags, state->name);
286 }
287
288
289 void
290 argp_error (const struct argp_state *state, const char *fmt, ...)
291 {
292   va_list ap;
293
294   fprintf (state->err_stream, "%s: ", state->name);
295   va_start (ap, fmt);
296   vfprintf (state->err_stream, fmt, ap);
297   va_end (ap);
298   fprintf (state->err_stream, "\n");
299   argp_state_help (state, state->err_stream, ARGP_HELP_STD_ERR);
300   exit (argp_err_exit_status);
301 }
302
303
304 void
305 argp_help (const struct argp *argp, FILE *stream, unsigned flags, char *name)
306 {
307   _argp_state_help (argp, NULL, stream, flags, name);
308 }
309
310
311 error_t
312 argp_parse (const struct argp *argp, int argc,
313             char **argv, unsigned flags, int *arg_index, void *input)
314 {
315   int rc = 0;
316   struct argp_state state = { argp, argc, argv, 1, flags, 0, 0, input,
317                               NULL, NULL, _argp_pname (argv[0]),
318                               stderr, stdout, NULL };
319   /* All non-option arguments are collected at the beginning of
320      &argv[1] during processing.  This is a counter for their number.  */
321   int non_opt_args = 0;
322
323   rc = argp->parser (ARGP_KEY_INIT, NULL, &state);
324   if (rc && rc != ARGP_ERR_UNKNOWN)
325     goto argperror;
326
327   while (state.next < state.argc - non_opt_args)
328     {
329       int idx = state.next;
330       state.next++;
331
332       if (! strcasecmp (state.argv[idx], "--"))
333         {
334           state.quoted = idx;
335           continue;
336         }
337
338       if (state.quoted || state.argv[idx][0] != '-')
339         {
340           char *arg_saved = state.argv[idx];
341           non_opt_args++;
342           memmove (&state.argv[idx], &state.argv[idx + 1],
343                    (state.argc - 1 - idx) * sizeof (char *));
344           state.argv[argc - 1] = arg_saved;
345           state.next--;
346         }
347       else if (! strcasecmp (state.argv[idx], "--help")
348                || !strcmp (state.argv[idx], "-?"))
349         {
350           argp_state_help (&state, state.out_stream, ARGP_HELP_STD_HELP);
351         }
352       else if (! strcasecmp (state.argv[idx], "--usage"))
353         {
354           argp_state_help (&state, state.out_stream,
355                            ARGP_HELP_USAGE | ARGP_HELP_EXIT_OK);
356         }
357       else if (! strcasecmp (state.argv[idx], "--version")
358                || !strcmp (state.argv[idx], "-V"))
359         {
360           fprintf (state.out_stream, "%s\n", argp_program_version);
361           exit (0);
362         }
363       else
364         {
365           /* Search for option and call parser with its KEY.  */
366           int key = ARGP_KEY_ARG; /* Just some dummy value.  */
367           const struct argp_option *opt = argp->options;
368           char *arg = NULL;
369           int found = 0;
370
371           /* Check for --opt=value syntax.  */
372           arg = strchr (state.argv[idx], '=');
373           if (arg)
374             {
375               *arg = '\0';
376               arg++;
377             }
378
379           if (state.argv[idx][1] != '-')
380             key = state.argv[idx][1];
381
382           while (! found && opt->key)
383             {
384               if (key == opt->key
385                   || (key == ARGP_KEY_ARG
386                       && ! strcasecmp (&state.argv[idx][2], opt->name)))
387                 {
388                   if (arg && !opt->arg)
389                     argp_error (&state, "Option %s does not take an argument",
390                                 state.argv[idx]);
391                   if (opt->arg && state.next < state.argc
392                       && state.argv[idx + 1][0] != '-')
393                     {
394                       arg = state.argv[idx + 1];
395                       state.next++;
396                     }
397                   if (opt->arg && !(opt->flags & OPTION_ARG_OPTIONAL))
398                     argp_error (&state, "Option %s requires an argument",
399                                 state.argv[idx]);
400
401                   rc = argp->parser (opt->key, arg, &state);
402                   if (rc == ARGP_ERR_UNKNOWN)
403                     break;
404                   else if (rc)
405                     goto argperror;
406                   found = 1;
407                 }
408               opt++;
409             }
410           if (! found)
411             argp_error (&state, "Unknown option %s", state.argv[idx]);
412         }
413     }
414
415   while (state.next < state.argc)
416     {
417       /* Call parser for all non-option args.  */
418       int idx = state.next;
419       state.next++;
420       rc = argp->parser (ARGP_KEY_ARG, state.argv[idx], &state);
421       if (rc && rc != ARGP_ERR_UNKNOWN)
422         goto argperror;
423       if (rc == ARGP_ERR_UNKNOWN)
424         {
425           int old_next = state.next;
426           rc = argp->parser (ARGP_KEY_ARGS, NULL, &state);
427           if (rc == ARGP_ERR_UNKNOWN)
428             {
429               argp_error (&state, "Too many arguments");
430               goto argperror;
431             }
432           if (! rc && state.next == old_next)
433             {
434               state.arg_num += state.argc - state.next;
435               state.next = state.argc;
436             }
437         }
438       else
439         state.arg_num++;
440     }
441
442   if (state.arg_num == 0)
443     {
444       rc = argp->parser (ARGP_KEY_NO_ARGS, NULL, &state);
445       if (rc && rc != ARGP_ERR_UNKNOWN)
446         goto argperror;
447     }
448   if (state.next == state.argc)
449     {
450       rc = argp->parser (ARGP_KEY_END, NULL, &state);
451       if (rc && rc != ARGP_ERR_UNKNOWN)
452         goto argperror;
453     }
454   rc = argp->parser (ARGP_KEY_FINI, NULL, &state);
455   if (rc && rc != ARGP_ERR_UNKNOWN)
456     goto argperror;
457
458   rc = 0;
459   argp->parser (ARGP_KEY_SUCCESS, NULL, &state);
460
461  argperror:
462   if (rc)
463     {
464       argp_error (&state, "unexpected error: %s", strerror (rc));
465       argp->parser (ARGP_KEY_ERROR, NULL, &state);
466     }
467
468   argp->parser (ARGP_KEY_FINI, NULL, &state);
469
470   if (arg_index)
471     *arg_index = state.next - 1;
472
473   return 0;
474 }
475 #endif
476
477 \f
478 /* MEMBUF */
479
480 /* A simple implementation of a dynamic buffer.  Use init_membuf() to
481    create a buffer, put_membuf to append bytes and get_membuf to
482    release and return the buffer.  Allocation errors are detected but
483    only returned at the final get_membuf(), this helps not to clutter
484    the code with out-of-core checks.  */
485
486 /* The definition of the structure is private, we only need it here,
487    so it can be allocated on the stack. */
488 struct private_membuf_s
489 {
490   size_t len;
491   size_t size;
492   char *buf;
493   int out_of_core;
494 };
495
496 typedef struct private_membuf_s membuf_t;
497
498 /* Return the current length of the membuf.  */
499 #define get_membuf_len(a)  ((a)->len)
500 #define is_membuf_ready(a) ((a)->buf || (a)->out_of_core)
501 #define MEMBUF_ZERO        { 0, 0, NULL, 0}
502
503
504 static void
505 init_membuf (membuf_t *mb, int initiallen)
506 {
507   mb->len = 0;
508   mb->size = initiallen;
509   mb->out_of_core = 0;
510   mb->buf = malloc (initiallen);
511   if (!mb->buf)
512     mb->out_of_core = errno;
513 }
514
515
516 /* Shift the the content of the membuf MB by AMOUNT bytes.  The next
517    operation will then behave as if AMOUNT bytes had not been put into
518    the buffer.  If AMOUNT is greater than the actual accumulated
519    bytes, the membuf is basically reset to its initial state.  */
520 #if 0 /* Not yet used.  */
521 static void
522 clear_membuf (membuf_t *mb, size_t amount)
523 {
524   /* No need to clear if we are already out of core.  */
525   if (mb->out_of_core)
526     return;
527   if (amount >= mb->len)
528     mb->len = 0;
529   else
530     {
531       mb->len -= amount;
532       memmove (mb->buf, mb->buf+amount, mb->len);
533     }
534 }
535 #endif /* unused */
536
537 static void
538 put_membuf (membuf_t *mb, const void *buf, size_t len)
539 {
540   if (mb->out_of_core || !len)
541     return;
542
543   if (mb->len + len >= mb->size)
544     {
545       char *p;
546
547       mb->size += len + 1024;
548       p = realloc (mb->buf, mb->size);
549       if (!p)
550         {
551           mb->out_of_core = errno ? errno : ENOMEM;
552           return;
553         }
554       mb->buf = p;
555     }
556   memcpy (mb->buf + mb->len, buf, len);
557   mb->len += len;
558 }
559
560
561 #if 0 /* Not yet used.  */
562 static void
563 put_membuf_str (membuf_t *mb, const char *string)
564 {
565   put_membuf (mb, string, strlen (string));
566 }
567 #endif /* unused */
568
569
570 static void *
571 get_membuf (membuf_t *mb, size_t *len)
572 {
573   char *p;
574
575   if (mb->out_of_core)
576     {
577       if (mb->buf)
578         {
579           free (mb->buf);
580           mb->buf = NULL;
581         }
582       gpg_err_set_errno (mb->out_of_core);
583       return NULL;
584     }
585
586   p = mb->buf;
587   if (len)
588     *len = mb->len;
589   mb->buf = NULL;
590   mb->out_of_core = ENOMEM; /* hack to make sure it won't get reused. */
591   return p;
592 }
593
594
595 /* Peek at the membuf MB.  On success a pointer to the buffer is
596    returned which is valid until the next operation on MB.  If LEN is
597    not NULL the current LEN of the buffer is stored there.  On error
598    NULL is returned and ERRNO is set.  */
599 #if 0 /* Not yet used.  */
600 static const void *
601 peek_membuf (membuf_t *mb, size_t *len)
602 {
603   const char *p;
604
605   if (mb->out_of_core)
606     {
607       gpg_err_set_errno (mb->out_of_core);
608       return NULL;
609     }
610
611   p = mb->buf;
612   if (len)
613     *len = mb->len;
614   return p;
615 }
616 #endif /* unused */
617
618
619 \f
620 /* SUPPORT.  */
621 FILE *log_stream;
622 char *program_name = "gpgme-tool";
623
624 #define spacep(p)   (*(p) == ' ' || *(p) == '\t')
625
626
627 void log_error (int status, gpg_error_t errnum,
628                 const char *fmt, ...) GT_GCC_A_PRINTF(3,4);
629
630
631 void
632 log_init (void)
633 {
634   log_stream = stderr;
635 }
636
637
638 void
639 log_error (int status, gpg_error_t errnum, const char *fmt, ...)
640 {
641   va_list ap;
642
643   fprintf (log_stream, "%s: ", program_name);
644   va_start (ap, fmt);
645   vfprintf (log_stream, fmt, ap);
646   va_end (ap);
647   if (errnum)
648     {
649       fprintf (log_stream, ": %s", gpg_strerror (errnum));
650       if (gpg_err_source (errnum) != GPG_ERR_SOURCE_GPGME)
651         fprintf (log_stream, " <%s>", gpg_strsource (errnum));
652     }
653   fprintf (log_stream, "\n");
654   if (status)
655     exit (status);
656 }
657
658
659 /* Note that it is sufficient to allocate the target string D as long
660    as the source string S, i.e.: strlen(s)+1;.  D == S is allowed.  */
661 static void
662 strcpy_escaped_plus (char *d, const char *s)
663 {
664   while (*s)
665     {
666       if (*s == '%' && s[1] && s[2])
667         {
668           s++;
669           *d++ = xtoi_2 (s);
670           s += 2;
671         }
672       else if (*s == '+')
673         *d++ = ' ', s++;
674       else
675         *d++ = *s++;
676     }
677   *d = 0;
678 }
679
680
681 /* Check whether the option NAME appears in LINE.  */
682 static int
683 has_option (const char *line, const char *name)
684 {
685   const char *s;
686   int n = strlen (name);
687
688   s = strstr (line, name);
689   return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
690 }
691
692 /* Skip over options.  It is assumed that leading spaces have been
693    removed (this is the case for lines passed to a handler from
694    assuan).  Blanks after the options are also removed.  */
695 static char *
696 skip_options (char *line)
697 {
698   while ( *line == '-' && line[1] == '-' )
699     {
700       while (*line && !spacep (line))
701         line++;
702       while (spacep (line))
703         line++;
704     }
705   return line;
706 }
707
708
709
710 \f
711 typedef gpg_error_t (*result_xml_write_cb_t) (void *hook, const void *buf,
712                                               size_t len);
713
714 static char xml_preamble1[] = "<?xml version=\"1.0\" "
715   "encoding=\"UTF-8\" standalone=\"yes\"?>\n";
716 static const char xml_preamble2[] = "<gpgme>\n";
717 static const char xml_end[] = "</gpgme>\n";
718
719
720 struct result_xml_state
721 {
722   int indent;
723   result_xml_write_cb_t cb;
724   void *hook;
725
726 #define MAX_TAGS 20
727   int next_tag;
728   char *tag[MAX_TAGS];
729   int had_data[MAX_TAGS];
730 };
731
732
733 void
734 result_init (struct result_xml_state *state, int indent,
735              result_xml_write_cb_t cb, void *hook)
736 {
737   memset (state, '\0', sizeof (*state));
738   state->indent = indent;
739   state->cb = cb;
740   state->hook = hook;
741 }
742
743
744 gpg_error_t
745 result_xml_indent (struct result_xml_state *state)
746 {
747   char spaces[state->indent + 1];
748   int i;
749   for (i = 0; i < state->indent; i++)
750     spaces[i] = ' ';
751   spaces[i] = '\0';
752   return (*state->cb) (state->hook, spaces, i);
753 }
754
755
756 gpg_error_t
757 result_xml_tag_start (struct result_xml_state *state, char *name, ...)
758 {
759   result_xml_write_cb_t cb = state->cb;
760   void *hook = state->hook;
761   va_list ap;
762   char *attr;
763   char *attr_val;
764
765   va_start (ap, name);
766
767   if (state->next_tag > 0)
768     {
769       if (! state->had_data[state->next_tag - 1])
770         {
771           (*cb) (hook, ">\n", 2);
772           (*cb) (hook, NULL, 0);
773         }
774       state->had_data[state->next_tag - 1] = 1;
775     }
776
777   result_xml_indent (state);
778   (*cb) (hook, "<", 1);
779   (*cb) (hook, name, strlen (name));
780
781   state->tag[state->next_tag] = name;
782   state->had_data[state->next_tag] = 0;
783   state->indent += 2;
784   state->next_tag++;
785
786   while (1)
787     {
788       attr = va_arg (ap, char *);
789       if (attr == NULL)
790         break;
791
792       attr_val = va_arg (ap, char *);
793       if (attr_val == NULL)
794         attr_val = "(null)";
795
796       (*cb) (hook, " ", 1);
797       (*cb) (hook, attr, strlen (attr));
798       (*cb) (hook, "=\"", 2);
799       (*cb) (hook, attr_val, strlen (attr_val));
800       (*cb) (hook, "\"", 1);
801     }
802   va_end (ap);
803   return 0;
804 }
805
806 /* Return a constant string with an XML entity for C.  */
807 static const char *
808 result_xml_escape_replacement(char c)
809 {
810   switch (c)
811     {
812     case '<':
813       return "&lt;";
814     case '>':
815       return "&gt;";
816     case '&':
817       return "&amp;";
818     default:
819       return NULL;
820     }
821 }
822
823 /* Escape DATA by replacing certain characters with their XML
824    entities.  The result is stored in a newly allocated buffer which
825    address will be stored at BUF.   Returns 0 on success. */
826 static gpg_error_t
827 result_xml_escape (const char *data, char **buf)
828 {
829   int data_len, i;
830   const char *r;
831   membuf_t mb;
832
833   init_membuf (&mb, 128);
834   data_len = strlen (data);
835   for (i = 0; i < data_len; i++)
836     {
837       r = result_xml_escape_replacement (data[i]);
838       if (r)
839         put_membuf (&mb, r, strlen (r));
840       else
841         put_membuf (&mb, data+i, 1);
842     }
843   put_membuf (&mb, "", 1);
844   *buf = get_membuf (&mb, NULL);
845   return *buf? 0 : gpg_error_from_syserror ();
846 }
847
848
849 gpg_error_t
850 result_xml_tag_data (struct result_xml_state *state, const char *data)
851 {
852   gpg_error_t err;
853   result_xml_write_cb_t cb = state->cb;
854   void *hook = state->hook;
855   char *buf = NULL;
856
857   if (state->had_data[state->next_tag - 1])
858     {
859       (*cb) (hook, "\n", 2);
860       (*cb) (hook, NULL, 0);
861       result_xml_indent (state);
862     }
863   else
864     (*cb) (hook, ">", 1);
865   state->had_data[state->next_tag - 1] = 2;
866
867   err = result_xml_escape (data, &buf);
868   if (err)
869     return err;
870
871   (*cb) (hook, buf, strlen (buf));
872
873   free (buf);
874
875   return 0;
876 }
877
878
879 gpg_error_t
880 result_xml_tag_end (struct result_xml_state *state)
881 {
882   result_xml_write_cb_t cb = state->cb;
883   void *hook = state->hook;
884
885   state->next_tag--;
886   state->indent -= 2;
887
888   if (state->had_data[state->next_tag])
889     {
890       if (state->had_data[state->next_tag] == 1)
891         result_xml_indent (state);
892       (*cb) (hook, "</", 2);
893       (*cb) (hook, state->tag[state->next_tag],
894              strlen (state->tag[state->next_tag]));
895       (*cb) (hook, ">\n", 2);
896       (*cb) (hook, NULL, 0);
897     }
898   else
899     {
900       (*cb) (hook, " />\n", 4);
901       (*cb) (hook, NULL, 0);
902     }
903   return 0;
904 }
905
906
907 gpg_error_t
908 result_add_error (struct result_xml_state *state, char *name, gpg_error_t err)
909 {
910   char code[20];
911   char msg[1024];
912   snprintf (code, sizeof (code) - 1, "0x%x", err);
913   snprintf (msg, sizeof (msg) - 1, "%s <%s>",
914             gpg_strerror (err), gpg_strsource (err));
915   result_xml_tag_start (state, name, "value", code, NULL);
916   result_xml_tag_data (state, msg);
917   result_xml_tag_end (state);
918   return 0;
919 }
920
921
922 gpg_error_t
923 result_add_pubkey_algo (struct result_xml_state *state,
924                         char *name, gpgme_pubkey_algo_t algo)
925 {
926   char code[20];
927   char msg[80];
928   snprintf (code, sizeof (code) - 1, "0x%x", algo);
929   snprintf (msg, sizeof (msg) - 1, "%s",
930             gpgme_pubkey_algo_name (algo));
931   result_xml_tag_start (state, name, "value", code, NULL);
932   result_xml_tag_data (state, msg);
933   result_xml_tag_end (state);
934   return 0;
935 }
936
937
938 gpg_error_t
939 result_add_hash_algo (struct result_xml_state *state,
940                          char *name, gpgme_hash_algo_t algo)
941 {
942   char code[20];
943   char msg[80];
944   snprintf (code, sizeof (code) - 1, "0x%x", algo);
945   snprintf (msg, sizeof (msg) - 1, "%s",
946             gpgme_hash_algo_name (algo));
947   result_xml_tag_start (state, name, "value", code, NULL);
948   result_xml_tag_data (state, msg);
949   result_xml_tag_end (state);
950   return 0;
951 }
952
953
954 gpg_error_t
955 result_add_keyid (struct result_xml_state *state, char *name, char *keyid)
956 {
957   result_xml_tag_start (state, name, NULL);
958   result_xml_tag_data (state, keyid);
959   result_xml_tag_end (state);
960   return 0;
961 }
962
963
964 gpg_error_t
965 result_add_fpr (struct result_xml_state *state, char *name, char *fpr)
966 {
967   result_xml_tag_start (state, name, NULL);
968   result_xml_tag_data (state, fpr);
969   result_xml_tag_end (state);
970   return 0;
971 }
972
973
974 gpg_error_t
975 result_add_timestamp (struct result_xml_state *state, char *name,
976                       unsigned int timestamp)
977 {
978   char code[20];
979
980   snprintf (code, sizeof (code) - 1, "%ui", timestamp);
981   result_xml_tag_start (state, name, "unix", code, NULL);
982   result_xml_tag_end (state);
983   return 0;
984 }
985
986
987 gpg_error_t
988 result_add_sig_mode (struct result_xml_state *state, char *name,
989                      gpgme_sig_mode_t sig_mode)
990 {
991   char *mode;
992   char code[20];
993
994   snprintf (code, sizeof (code) - 1, "%i", sig_mode);
995   switch (sig_mode)
996     {
997     case GPGME_SIG_MODE_NORMAL:
998       mode = "normal";
999       break;
1000     case GPGME_SIG_MODE_DETACH:
1001       mode = "detach";
1002       break;
1003     case GPGME_SIG_MODE_CLEAR:
1004       mode = "clear";
1005       break;
1006     default:
1007       mode = "unknown";
1008     }
1009
1010   result_xml_tag_start (state, name, "type", mode, "value", code, NULL);
1011   result_xml_tag_data (state, mode);
1012   result_xml_tag_end (state);
1013   return 0;
1014 }
1015
1016
1017 gpg_error_t
1018 result_add_protocol (struct result_xml_state *state, char *name,
1019                      gpgme_protocol_t protocol)
1020 {
1021   const char *str;
1022   char code[20];
1023
1024   snprintf (code, sizeof (code) - 1, "%i", protocol);
1025   str = gpgme_get_protocol_name(protocol);
1026   if (!str)
1027     str = "invalid";
1028   result_xml_tag_start (state, name, "value", code, NULL);
1029   result_xml_tag_data (state, str);
1030   result_xml_tag_end (state);
1031   return 0;
1032 }
1033
1034
1035 gpg_error_t
1036 result_add_validity (struct result_xml_state *state, char *name,
1037                      gpgme_validity_t validity)
1038 {
1039   const char *str;
1040   char code[20];
1041
1042   snprintf (code, sizeof (code) - 1, "%i", validity);
1043   switch (validity)
1044     {
1045     case GPGME_VALIDITY_UNDEFINED:
1046       str ="undefined";
1047       break;
1048     case GPGME_VALIDITY_NEVER:
1049       str ="never";
1050       break;
1051     case GPGME_VALIDITY_MARGINAL:
1052       str ="marginal";
1053       break;
1054     case GPGME_VALIDITY_FULL:
1055       str ="full";
1056       break;
1057     case GPGME_VALIDITY_ULTIMATE:
1058       str ="ultimate";
1059       break;
1060     default:
1061       str ="unknown";
1062     }
1063
1064   result_xml_tag_start (state, name, "value", code, NULL);
1065   result_xml_tag_data (state, str);
1066   result_xml_tag_end (state);
1067   return 0;
1068 }
1069
1070
1071 gpg_error_t
1072 result_add_value (struct result_xml_state *state,
1073                   char *name, unsigned int val)
1074 {
1075   char code[20];
1076
1077   snprintf (code, sizeof (code) - 1, "0x%x", val);
1078   result_xml_tag_start (state, name, "value", code, NULL);
1079   result_xml_tag_end (state);
1080   return 0;
1081 }
1082
1083
1084 gpg_error_t
1085 result_add_string (struct result_xml_state *state,
1086                    char *name, char *str)
1087 {
1088   if (!str)
1089     str = "";
1090   result_xml_tag_start (state, name, NULL);
1091   result_xml_tag_data (state, str);
1092   result_xml_tag_end (state);
1093   return 0;
1094 }
1095
1096
1097 gpg_error_t
1098 result_encrypt_to_xml (gpgme_ctx_t ctx, int indent,
1099                        result_xml_write_cb_t cb, void *hook)
1100 {
1101   struct result_xml_state state;
1102   gpgme_encrypt_result_t res = gpgme_op_encrypt_result (ctx);
1103   gpgme_invalid_key_t inv_recp;
1104
1105   if (! res)
1106     return 0;
1107
1108   result_init (&state, indent, cb, hook);
1109   result_xml_tag_start (&state, "encrypt-result", NULL);
1110
1111   inv_recp = res->invalid_recipients;
1112   if (inv_recp)
1113     {
1114       result_xml_tag_start (&state, "invalid-recipients", NULL);
1115
1116       while (inv_recp)
1117         {
1118           result_xml_tag_start (&state, "invalid-key", NULL);
1119           if (inv_recp->fpr)
1120             result_add_fpr (&state, "fpr", inv_recp->fpr);
1121           result_add_error (&state, "reason", inv_recp->reason);
1122           result_xml_tag_end (&state);
1123           inv_recp = inv_recp->next;
1124         }
1125       result_xml_tag_end (&state);
1126     }
1127   result_xml_tag_end (&state);
1128
1129   return 0;
1130 }
1131
1132
1133 gpg_error_t
1134 result_decrypt_to_xml (gpgme_ctx_t ctx, int indent,
1135                        result_xml_write_cb_t cb, void *hook)
1136 {
1137   struct result_xml_state state;
1138   gpgme_decrypt_result_t res = gpgme_op_decrypt_result (ctx);
1139   gpgme_recipient_t recp;
1140
1141   if (! res)
1142     return 0;
1143
1144   result_init (&state, indent, cb, hook);
1145   result_xml_tag_start (&state, "decrypt-result", NULL);
1146
1147   if (res->file_name)
1148     {
1149       result_xml_tag_start (&state, "file-name", NULL);
1150       result_xml_tag_data (&state, res->file_name);
1151       result_xml_tag_end (&state);
1152     }
1153   if (res->unsupported_algorithm)
1154     {
1155       result_xml_tag_start (&state, "unsupported-alogorithm", NULL);
1156       result_xml_tag_data (&state, res->unsupported_algorithm);
1157       result_xml_tag_end (&state);
1158     }
1159   if (res->wrong_key_usage)
1160     {
1161       result_xml_tag_start (&state, "wrong-key-usage", NULL);
1162       result_xml_tag_end (&state);
1163     }
1164
1165   recp = res->recipients;
1166   if (recp)
1167     {
1168       result_xml_tag_start (&state, "recipients", NULL);
1169       while (recp)
1170         {
1171           result_xml_tag_start (&state, "recipient", NULL);
1172           result_add_keyid (&state, "keyid", recp->keyid);
1173           result_add_pubkey_algo (&state, "pubkey-algo", recp->pubkey_algo);
1174           result_add_error (&state, "status", recp->status);
1175           result_xml_tag_end (&state);
1176           recp = recp->next;
1177         }
1178       result_xml_tag_end (&state);
1179     }
1180   result_xml_tag_end (&state);
1181
1182   return 0;
1183 }
1184
1185
1186 gpg_error_t
1187 result_sign_to_xml (gpgme_ctx_t ctx, int indent,
1188                     result_xml_write_cb_t cb, void *hook)
1189 {
1190   struct result_xml_state state;
1191   gpgme_sign_result_t res = gpgme_op_sign_result (ctx);
1192   gpgme_invalid_key_t inv_key;
1193   gpgme_new_signature_t new_sig;
1194
1195   if (! res)
1196     return 0;
1197
1198   result_init (&state, indent, cb, hook);
1199   result_xml_tag_start (&state, "sign-result", NULL);
1200
1201   inv_key = res->invalid_signers;
1202   if (inv_key)
1203     {
1204       result_xml_tag_start (&state, "invalid-signers", NULL);
1205
1206       while (inv_key)
1207         {
1208           result_xml_tag_start (&state, "invalid-key", NULL);
1209           if (inv_key->fpr)
1210             result_add_fpr (&state, "fpr", inv_key->fpr);
1211           result_add_error (&state, "reason", inv_key->reason);
1212           result_xml_tag_end (&state);
1213           inv_key = inv_key->next;
1214         }
1215       result_xml_tag_end (&state);
1216     }
1217
1218   new_sig = res->signatures;
1219   if (new_sig)
1220     {
1221       result_xml_tag_start (&state, "signatures", NULL);
1222
1223       while (new_sig)
1224         {
1225           result_xml_tag_start (&state, "new-signature", NULL);
1226           result_add_sig_mode (&state, "type", new_sig->type);
1227           result_add_pubkey_algo (&state, "pubkey-algo", new_sig->pubkey_algo);
1228           result_add_hash_algo (&state, "hash-algo", new_sig->hash_algo);
1229           result_add_timestamp (&state, "timestamp", new_sig->timestamp);
1230           if (new_sig->fpr)
1231             result_add_fpr (&state, "fpr", new_sig->fpr);
1232           result_add_value (&state, "sig-class", new_sig->sig_class);
1233
1234           result_xml_tag_end (&state);
1235           new_sig = new_sig->next;
1236         }
1237       result_xml_tag_end (&state);
1238     }
1239
1240   result_xml_tag_end (&state);
1241
1242   return 0;
1243 }
1244
1245
1246 gpg_error_t
1247 result_verify_to_xml (gpgme_ctx_t ctx, int indent,
1248                       result_xml_write_cb_t cb, void *hook)
1249 {
1250   struct result_xml_state state;
1251   gpgme_verify_result_t res = gpgme_op_verify_result (ctx);
1252   gpgme_signature_t sig;
1253
1254   if (! res)
1255     return 0;
1256
1257   result_init (&state, indent, cb, hook);
1258   result_xml_tag_start (&state, "verify-result", NULL);
1259
1260   if (res->file_name)
1261     {
1262       result_xml_tag_start (&state, "file-name", NULL);
1263       result_xml_tag_data (&state, res->file_name);
1264       result_xml_tag_end (&state);
1265     }
1266
1267   sig = res->signatures;
1268   if (sig)
1269     {
1270       result_xml_tag_start (&state, "signatures", NULL);
1271
1272       while (sig)
1273         {
1274           result_xml_tag_start (&state, "signature", NULL);
1275
1276           /* FIXME: Could be done better. */
1277           result_add_value (&state, "summary", sig->summary);
1278           if (sig->fpr)
1279             result_add_fpr (&state, "fpr", sig->fpr);
1280           result_add_error (&state, "status", sig->status);
1281           /* FIXME: notations */
1282           result_add_timestamp (&state, "timestamp", sig->timestamp);
1283           result_add_timestamp (&state, "exp-timestamp", sig->exp_timestamp);
1284           result_add_value (&state, "wrong-key-usage", sig->wrong_key_usage);
1285           result_add_value (&state, "pka-trust", sig->pka_trust);
1286           result_add_value (&state, "chain-model", sig->chain_model);
1287           result_add_value (&state, "validity", sig->validity);
1288           result_add_error (&state, "validity-reason", sig->validity_reason);
1289           result_add_pubkey_algo (&state, "pubkey-algo", sig->pubkey_algo);
1290           result_add_hash_algo (&state, "hash-algo", sig->hash_algo);
1291           if (sig->pka_address)
1292             result_add_string (&state, "pka_address", sig->pka_address);
1293
1294           result_xml_tag_end (&state);
1295           sig = sig->next;
1296         }
1297       result_xml_tag_end (&state);
1298     }
1299
1300   result_xml_tag_end (&state);
1301
1302   return 0;
1303 }
1304
1305
1306 gpg_error_t
1307 result_import_to_xml (gpgme_ctx_t ctx, int indent,
1308                       result_xml_write_cb_t cb, void *hook)
1309 {
1310   struct result_xml_state state;
1311   gpgme_import_result_t res = gpgme_op_import_result (ctx);
1312   gpgme_import_status_t stat;
1313
1314   if (! res)
1315     return 0;
1316
1317   result_init (&state, indent, cb, hook);
1318   result_xml_tag_start (&state, "import-result", NULL);
1319
1320   result_add_value (&state, "considered", res->considered);
1321   result_add_value (&state, "no-user-id", res->no_user_id);
1322   result_add_value (&state, "imported", res->imported);
1323   result_add_value (&state, "imported-rsa", res->imported_rsa);
1324   result_add_value (&state, "unchanged", res->unchanged);
1325   result_add_value (&state, "new-user-ids", res->new_user_ids);
1326   result_add_value (&state, "new-sub-keys", res->new_sub_keys);
1327   result_add_value (&state, "new-signatures", res->new_signatures);
1328   result_add_value (&state, "new-revocations", res->new_revocations);
1329   result_add_value (&state, "secret-read", res->secret_read);
1330   result_add_value (&state, "secret-imported", res->secret_imported);
1331   result_add_value (&state, "secret-unchanged", res->secret_unchanged);
1332   result_add_value (&state, "skipped-new-keys", res->skipped_new_keys);
1333   result_add_value (&state, "not-imported", res->not_imported);
1334
1335   stat = res->imports;
1336   if (stat)
1337     {
1338       result_xml_tag_start (&state, "imports", NULL);
1339
1340       while (stat)
1341         {
1342           result_xml_tag_start (&state, "import-status", NULL);
1343
1344           if (stat->fpr)
1345             result_add_fpr (&state, "fpr", stat->fpr);
1346           result_add_error (&state, "result", stat->result);
1347           /* FIXME: Could be done better. */
1348           result_add_value (&state, "status", stat->status);
1349
1350           result_xml_tag_end (&state);
1351           stat = stat->next;
1352         }
1353       result_xml_tag_end (&state);
1354     }
1355
1356   result_xml_tag_end (&state);
1357
1358   return 0;
1359 }
1360
1361
1362 gpg_error_t
1363 result_genkey_to_xml (gpgme_ctx_t ctx, int indent,
1364                       result_xml_write_cb_t cb, void *hook)
1365 {
1366   struct result_xml_state state;
1367   gpgme_genkey_result_t res = gpgme_op_genkey_result (ctx);
1368
1369   if (! res)
1370     return 0;
1371
1372   result_init (&state, indent, cb, hook);
1373   result_xml_tag_start (&state, "genkey-result", NULL);
1374
1375   result_add_value (&state, "primary", res->primary);
1376   result_add_value (&state, "sub", res->sub);
1377   if (res->fpr)
1378     result_add_fpr (&state, "fpr", res->fpr);
1379
1380   result_xml_tag_end (&state);
1381
1382   return 0;
1383 }
1384
1385
1386 gpg_error_t
1387 result_keylist_to_xml (gpgme_ctx_t ctx, int indent,
1388                       result_xml_write_cb_t cb, void *hook)
1389 {
1390   struct result_xml_state state;
1391   gpgme_keylist_result_t res = gpgme_op_keylist_result (ctx);
1392
1393   if (! res)
1394     return 0;
1395
1396   result_init (&state, indent, cb, hook);
1397   result_xml_tag_start (&state, "keylist-result", NULL);
1398
1399   result_add_value (&state, "truncated", res->truncated);
1400
1401   result_xml_tag_end (&state);
1402
1403   return 0;
1404 }
1405
1406
1407 gpg_error_t
1408 result_vfs_mount_to_xml (gpgme_ctx_t ctx, int indent,
1409                          result_xml_write_cb_t cb, void *hook)
1410 {
1411   struct result_xml_state state;
1412   gpgme_vfs_mount_result_t res = gpgme_op_vfs_mount_result (ctx);
1413
1414   if (! res)
1415     return 0;
1416
1417   result_init (&state, indent, cb, hook);
1418   result_xml_tag_start (&state, "vfs-mount-result", NULL);
1419
1420   result_add_string (&state, "mount-dir", res->mount_dir);
1421
1422   result_xml_tag_end (&state);
1423
1424   return 0;
1425 }
1426
1427 \f
1428 typedef enum status
1429   {
1430     STATUS_PROTOCOL,
1431     STATUS_PROGRESS,
1432     STATUS_ENGINE,
1433     STATUS_ARMOR,
1434     STATUS_TEXTMODE,
1435     STATUS_INCLUDE_CERTS,
1436     STATUS_KEYLIST_MODE,
1437     STATUS_RECIPIENT,
1438     STATUS_ENCRYPT_RESULT,
1439     STATUS_IDENTIFY_RESULT
1440   } status_t;
1441
1442 const char *status_string[] =
1443   {
1444     "PROTOCOL",
1445     "PROGRESS",
1446     "ENGINE",
1447     "ARMOR",
1448     "TEXTMODE",
1449     "INCLUDE_CERTS",
1450     "KEYLIST_MODE",
1451     "RECIPIENT",
1452     "ENCRYPT_RESULT",
1453     "IDENTIFY_RESULT"
1454   };
1455
1456 struct gpgme_tool
1457 {
1458   gpgme_ctx_t ctx;
1459 #define MAX_RECIPIENTS 10
1460   gpgme_key_t recipients[MAX_RECIPIENTS + 1];
1461   int recipients_nr;
1462
1463   gpg_error_t (*write_status) (void *hook, const char *status, const char *msg);
1464   void *write_status_hook;
1465   gpg_error_t (*write_data) (void *hook, const void *buf, size_t len);
1466   void *write_data_hook;
1467 };
1468 typedef struct gpgme_tool *gpgme_tool_t;
1469
1470
1471 /* Forward declaration.  */
1472 void gt_write_status (gpgme_tool_t gt,
1473                       status_t status, ...) GT_GCC_A_SENTINEL(0);
1474 static gpg_error_t
1475 server_passphrase_cb (void *opaque, const char *uid_hint, const char *info,
1476                       int was_bad, int fd);
1477
1478
1479 void
1480 _gt_progress_cb (void *opaque, const char *what,
1481                  int type, int current, int total)
1482 {
1483   gpgme_tool_t gt = opaque;
1484   char buf[100];
1485
1486   snprintf (buf, sizeof (buf), "0x%02x %i %i", type, current, total);
1487   gt_write_status (gt, STATUS_PROGRESS, what, buf, NULL);
1488 }
1489
1490
1491 gpg_error_t
1492 _gt_gpgme_new (gpgme_tool_t gt, gpgme_ctx_t *ctx)
1493 {
1494   gpg_error_t err;
1495
1496   err = gpgme_new (ctx);
1497   if (err)
1498     return err;
1499   gpgme_set_progress_cb (*ctx, _gt_progress_cb, gt);
1500   return 0;
1501 }
1502
1503
1504 void
1505 gt_init (gpgme_tool_t gt)
1506 {
1507   gpg_error_t err;
1508
1509   memset (gt, '\0', sizeof (*gt));
1510
1511   err = _gt_gpgme_new (gt, &gt->ctx);
1512   if (err)
1513     log_error (1, err, "can't create gpgme context");
1514 }
1515
1516
1517 gpg_error_t
1518 gt_signers_add (gpgme_tool_t gt, const char *fpr)
1519 {
1520   gpg_error_t err;
1521   gpgme_key_t key;
1522
1523   err = gpgme_get_key (gt->ctx, fpr, &key, 0);
1524   if (err)
1525     return err;
1526
1527   return gpgme_signers_add (gt->ctx, key);
1528 }
1529
1530
1531 gpg_error_t
1532 gt_signers_clear (gpgme_tool_t gt)
1533 {
1534   gpgme_signers_clear (gt->ctx);
1535   return 0;
1536 }
1537
1538
1539 gpg_error_t
1540 gt_get_key (gpgme_tool_t gt, const char *pattern, gpgme_key_t *r_key)
1541 {
1542   gpgme_ctx_t ctx;
1543   gpgme_ctx_t listctx;
1544   gpgme_error_t err;
1545   gpgme_key_t key;
1546
1547   if (!gt || !r_key || !pattern)
1548     return gpg_error (GPG_ERR_INV_VALUE);
1549
1550   ctx = gt->ctx;
1551
1552   err = gpgme_new (&listctx);
1553   if (err)
1554     return err;
1555
1556   {
1557     gpgme_protocol_t proto;
1558     gpgme_engine_info_t info;
1559
1560     /* Clone the relevant state.  */
1561     proto = gpgme_get_protocol (ctx);
1562     /* The g13 protocol does not allow keylisting, we need to choose
1563        something else.  */
1564     if (proto == GPGME_PROTOCOL_G13)
1565       proto = GPGME_PROTOCOL_OpenPGP;
1566
1567     gpgme_set_protocol (listctx, proto);
1568     gpgme_set_keylist_mode (listctx, gpgme_get_keylist_mode (ctx));
1569     info = gpgme_ctx_get_engine_info (ctx);
1570     while (info && info->protocol != proto)
1571       info = info->next;
1572     if (info)
1573       gpgme_ctx_set_engine_info (listctx, proto,
1574                                  info->file_name, info->home_dir);
1575   }
1576
1577   err = gpgme_op_keylist_start (listctx, pattern, 0);
1578   if (!err)
1579     err = gpgme_op_keylist_next (listctx, r_key);
1580   if (!err)
1581     {
1582     try_next_key:
1583       err = gpgme_op_keylist_next (listctx, &key);
1584       if (gpgme_err_code (err) == GPG_ERR_EOF)
1585         err = 0;
1586       else
1587         {
1588           if (!err
1589               && *r_key && (*r_key)->subkeys && (*r_key)->subkeys->fpr
1590               && key && key->subkeys && key->subkeys->fpr
1591               && !strcmp ((*r_key)->subkeys->fpr, key->subkeys->fpr))
1592             {
1593               /* The fingerprint is identical.  We assume that this is
1594                  the same key and don't mark it as an ambiguous.  This
1595                  problem may occur with corrupted keyrings and has
1596                  been noticed often with gpgsm.  In fact gpgsm uses a
1597                  similar hack to sort out such duplicates but it can't
1598                  do that while listing keys.  */
1599               gpgme_key_unref (key);
1600               goto try_next_key;
1601             }
1602           if (!err)
1603             {
1604               gpgme_key_unref (key);
1605               err = gpg_error (GPG_ERR_AMBIGUOUS_NAME);
1606             }
1607           gpgme_key_unref (*r_key);
1608         }
1609     }
1610   gpgme_release (listctx);
1611
1612   if (! err)
1613     gt_write_status (gt, STATUS_RECIPIENT,
1614                      ((*r_key)->subkeys && (*r_key)->subkeys->fpr) ?
1615                      (*r_key)->subkeys->fpr : "invalid", NULL);
1616   return err;
1617 }
1618
1619
1620 gpg_error_t
1621 gt_recipients_add (gpgme_tool_t gt, const char *pattern)
1622 {
1623   gpg_error_t err;
1624   gpgme_key_t key;
1625
1626   if (gt->recipients_nr >= MAX_RECIPIENTS)
1627     return gpg_error (GPG_ERR_ENOMEM);
1628
1629   if (gpgme_get_protocol (gt->ctx) == GPGME_PROTOCOL_UISERVER)
1630     err = gpgme_key_from_uid (&key, pattern);
1631   else
1632     err = gt_get_key (gt, pattern, &key);
1633   if (err)
1634     return err;
1635
1636   gt->recipients[gt->recipients_nr++] = key;
1637   return 0;
1638 }
1639
1640
1641 void
1642 gt_recipients_clear (gpgme_tool_t gt)
1643 {
1644   int idx;
1645
1646   for (idx = 0; idx < gt->recipients_nr; idx++)
1647     gpgme_key_unref (gt->recipients[idx]);
1648   memset (gt->recipients, '\0', gt->recipients_nr * sizeof (gpgme_key_t));
1649   gt->recipients_nr = 0;
1650 }
1651
1652
1653 gpg_error_t
1654 gt_reset (gpgme_tool_t gt)
1655 {
1656   gpg_error_t err;
1657   gpgme_ctx_t ctx;
1658
1659   err = _gt_gpgme_new (gt, &ctx);
1660   if (err)
1661     return err;
1662
1663   gpgme_release (gt->ctx);
1664   gt->ctx = ctx;
1665   gt_recipients_clear (gt);
1666   return 0;
1667 }
1668
1669
1670 void
1671 gt_write_status (gpgme_tool_t gt, status_t status, ...)
1672 {
1673   va_list ap;
1674   const char *text;
1675   char buf[950];
1676   char *p;
1677   size_t n;
1678   gpg_error_t err;
1679
1680   va_start (ap, status);
1681   p = buf;
1682   n = 0;
1683   while ((text = va_arg (ap, const char *)))
1684     {
1685       if (n)
1686         {
1687           *p++ = ' ';
1688           n++;
1689         }
1690       while (*text && n < sizeof (buf) - 2)
1691         {
1692           *p++ = *text++;
1693           n++;
1694         }
1695     }
1696   *p = 0;
1697   va_end (ap);
1698
1699   err = gt->write_status (gt->write_status_hook, status_string[status], buf);
1700   if (err)
1701     log_error (1, err, "can't write status line");
1702 }
1703
1704
1705 gpg_error_t
1706 gt_write_data (gpgme_tool_t gt, const void *buf, size_t len)
1707 {
1708   return gt->write_data (gt->write_data_hook, buf, len);
1709 }
1710
1711
1712 gpg_error_t
1713 gt_get_engine_info (gpgme_tool_t gt, gpgme_protocol_t proto)
1714 {
1715   gpgme_engine_info_t info;
1716   info = gpgme_ctx_get_engine_info (gt->ctx);
1717   while (info)
1718     {
1719       if (proto == GPGME_PROTOCOL_UNKNOWN || proto == info->protocol)
1720         gt_write_status (gt, STATUS_ENGINE,
1721                          gpgme_get_protocol_name (info->protocol),
1722                          info->file_name, info->version,
1723                          info->req_version, info->home_dir, NULL);
1724       info = info->next;
1725     }
1726   return 0;
1727 }
1728
1729
1730 gpgme_protocol_t
1731 gt_protocol_from_name (const char *name)
1732 {
1733   if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_OpenPGP)))
1734     return GPGME_PROTOCOL_OpenPGP;
1735   if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_CMS)))
1736     return GPGME_PROTOCOL_CMS;
1737   if (! strcasecmp (name,gpgme_get_protocol_name (GPGME_PROTOCOL_GPGCONF)))
1738     return GPGME_PROTOCOL_GPGCONF;
1739   if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_ASSUAN)))
1740     return GPGME_PROTOCOL_ASSUAN;
1741   if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_G13)))
1742     return GPGME_PROTOCOL_G13;
1743   if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_UISERVER)))
1744     return GPGME_PROTOCOL_UISERVER;
1745   if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_DEFAULT)))
1746     return GPGME_PROTOCOL_DEFAULT;
1747   return GPGME_PROTOCOL_UNKNOWN;
1748 }
1749
1750
1751 gpg_error_t
1752 gt_set_protocol (gpgme_tool_t gt, gpgme_protocol_t proto)
1753 {
1754   return gpgme_set_protocol (gt->ctx, proto);
1755 }
1756
1757
1758 gpg_error_t
1759 gt_get_protocol (gpgme_tool_t gt)
1760 {
1761   gpgme_protocol_t proto = gpgme_get_protocol (gt->ctx);
1762
1763   gt_write_status (gt, STATUS_PROTOCOL, gpgme_get_protocol_name (proto),
1764                    NULL);
1765
1766   return 0;
1767 }
1768
1769
1770 gpg_error_t
1771 gt_set_sub_protocol (gpgme_tool_t gt, gpgme_protocol_t proto)
1772 {
1773   return gpgme_set_sub_protocol (gt->ctx, proto);
1774 }
1775
1776
1777 gpg_error_t
1778 gt_get_sub_protocol (gpgme_tool_t gt)
1779 {
1780   gpgme_protocol_t proto = gpgme_get_sub_protocol (gt->ctx);
1781
1782   gt_write_status (gt, STATUS_PROTOCOL, gpgme_get_protocol_name (proto),
1783                    NULL);
1784
1785   return 0;
1786 }
1787
1788
1789 gpg_error_t
1790 gt_set_pinentry_mode (gpgme_tool_t gt, gpgme_pinentry_mode_t mode, void *opaque)
1791 {
1792   gpg_error_t err;
1793
1794   gpgme_set_passphrase_cb (gt->ctx, NULL, NULL);
1795   err = gpgme_set_pinentry_mode (gt->ctx, mode);
1796   if (!err && mode == GPGME_PINENTRY_MODE_LOOPBACK)
1797     gpgme_set_passphrase_cb (gt->ctx, server_passphrase_cb, opaque);
1798   return err;
1799 }
1800
1801
1802 gpg_error_t
1803 gt_set_armor (gpgme_tool_t gt, int armor)
1804 {
1805   gpgme_set_armor (gt->ctx, armor);
1806   return 0;
1807 }
1808
1809
1810 gpg_error_t
1811 gt_get_armor (gpgme_tool_t gt)
1812 {
1813   gt_write_status (gt, STATUS_ARMOR,
1814                    gpgme_get_armor (gt->ctx) ? "true" : "false", NULL);
1815
1816   return 0;
1817 }
1818
1819
1820 gpg_error_t
1821 gt_set_textmode (gpgme_tool_t gt, int textmode)
1822 {
1823   gpgme_set_textmode (gt->ctx, textmode);
1824   return 0;
1825 }
1826
1827
1828 gpg_error_t
1829 gt_get_textmode (gpgme_tool_t gt)
1830 {
1831   gt_write_status (gt, STATUS_TEXTMODE,
1832                    gpgme_get_textmode (gt->ctx) ? "true" : "false", NULL);
1833
1834   return 0;
1835 }
1836
1837
1838 gpg_error_t
1839 gt_set_keylist_mode (gpgme_tool_t gt, gpgme_keylist_mode_t keylist_mode)
1840 {
1841   gpgme_set_keylist_mode (gt->ctx, keylist_mode);
1842   return 0;
1843 }
1844
1845
1846 gpg_error_t
1847 gt_get_keylist_mode (gpgme_tool_t gt)
1848 {
1849 #define NR_KEYLIST_MODES 6
1850   const char *modes[NR_KEYLIST_MODES + 1];
1851   int idx = 0;
1852   gpgme_keylist_mode_t mode = gpgme_get_keylist_mode (gt->ctx);
1853
1854   if (mode & GPGME_KEYLIST_MODE_LOCAL)
1855     modes[idx++] = "local";
1856   if (mode & GPGME_KEYLIST_MODE_EXTERN)
1857     modes[idx++] = "extern";
1858   if (mode & GPGME_KEYLIST_MODE_SIGS)
1859     modes[idx++] = "sigs";
1860   if (mode & GPGME_KEYLIST_MODE_SIG_NOTATIONS)
1861     modes[idx++] = "sig_notations";
1862   if (mode & GPGME_KEYLIST_MODE_EPHEMERAL)
1863     modes[idx++] = "ephemeral";
1864   if (mode & GPGME_KEYLIST_MODE_VALIDATE)
1865     modes[idx++] = "validate";
1866   modes[idx++] = NULL;
1867
1868   gt_write_status (gt, STATUS_KEYLIST_MODE, modes[0], modes[1], modes[2],
1869                    modes[3], modes[4], modes[5], modes[6], NULL);
1870
1871   return 0;
1872 }
1873
1874
1875 gpg_error_t
1876 gt_set_include_certs (gpgme_tool_t gt, int include_certs)
1877 {
1878   gpgme_set_include_certs (gt->ctx, include_certs);
1879   return 0;
1880 }
1881
1882
1883 gpg_error_t
1884 gt_get_include_certs (gpgme_tool_t gt)
1885 {
1886   int include_certs = gpgme_get_include_certs (gt->ctx);
1887   char buf[100];
1888
1889   if (include_certs == GPGME_INCLUDE_CERTS_DEFAULT)
1890     strcpy (buf, "default");
1891   else
1892     snprintf (buf, sizeof (buf), "%i", include_certs);
1893
1894   gt_write_status (gt, STATUS_INCLUDE_CERTS, buf, NULL);
1895
1896   return 0;
1897 }
1898
1899
1900 gpg_error_t
1901 gt_decrypt_verify (gpgme_tool_t gt, gpgme_data_t cipher, gpgme_data_t plain,
1902                    int verify)
1903 {
1904   if (verify)
1905     return gpgme_op_decrypt_verify (gt->ctx, cipher, plain);
1906   else
1907     return gpgme_op_decrypt (gt->ctx, cipher, plain);
1908 }
1909
1910
1911 gpg_error_t
1912 gt_sign_encrypt (gpgme_tool_t gt, gpgme_encrypt_flags_t flags,
1913                  gpgme_data_t plain, gpgme_data_t cipher, int sign)
1914 {
1915   gpg_error_t err;
1916   gpgme_key_t *recp;
1917
1918   recp = gt->recipients_nr? gt->recipients : NULL;
1919
1920   if (sign)
1921     err = gpgme_op_encrypt_sign (gt->ctx, recp, flags, plain, cipher);
1922   else
1923     err = gpgme_op_encrypt (gt->ctx, recp, flags, plain, cipher);
1924
1925   gt_recipients_clear (gt);
1926
1927   return err;
1928 }
1929
1930
1931 gpg_error_t
1932 gt_sign (gpgme_tool_t gt, gpgme_data_t plain, gpgme_data_t sig,
1933          gpgme_sig_mode_t mode)
1934 {
1935   return gpgme_op_sign (gt->ctx, plain, sig, mode);
1936 }
1937
1938
1939 gpg_error_t
1940 gt_verify (gpgme_tool_t gt, gpgme_data_t sig, gpgme_data_t sig_text,
1941            gpgme_data_t plain)
1942 {
1943   return gpgme_op_verify (gt->ctx, sig, sig_text, plain);
1944 }
1945
1946
1947 gpg_error_t
1948 gt_import (gpgme_tool_t gt, gpgme_data_t data)
1949 {
1950   return gpgme_op_import (gt->ctx, data);
1951 }
1952
1953
1954 gpg_error_t
1955 gt_export (gpgme_tool_t gt, const char *pattern[], gpgme_export_mode_t mode,
1956            gpgme_data_t data)
1957 {
1958   return gpgme_op_export_ext (gt->ctx, pattern, mode, data);
1959 }
1960
1961
1962 gpg_error_t
1963 gt_genkey (gpgme_tool_t gt, const char *parms, gpgme_data_t public,
1964            gpgme_data_t secret)
1965 {
1966   return gpgme_op_genkey (gt->ctx, parms, public, secret);
1967 }
1968
1969
1970 gpg_error_t
1971 gt_import_keys (gpgme_tool_t gt, char *fpr[])
1972 {
1973   gpg_error_t err = 0;
1974   int cnt;
1975   int idx;
1976   gpgme_key_t *keys;
1977
1978   cnt = 0;
1979   while (fpr[cnt])
1980     cnt++;
1981
1982   if (! cnt)
1983     return gpg_error (GPG_ERR_INV_VALUE);
1984
1985   keys = malloc ((cnt + 1) * sizeof (gpgme_key_t));
1986   if (! keys)
1987     return gpg_error_from_syserror ();
1988
1989   for (idx = 0; idx < cnt; idx++)
1990     {
1991       err = gpgme_get_key (gt->ctx, fpr[idx], &keys[idx], 0);
1992       if (err)
1993         break;
1994     }
1995   if (! err)
1996     {
1997       keys[cnt] = NULL;
1998       err = gpgme_op_import_keys (gt->ctx, keys);
1999     }
2000
2001   /* Rollback.  */
2002   while (--idx >= 0)
2003     gpgme_key_unref (keys[idx]);
2004   free (keys);
2005
2006   return err;
2007 }
2008
2009
2010 gpg_error_t
2011 gt_delete (gpgme_tool_t gt, char *fpr, int allow_secret)
2012 {
2013   gpg_error_t err;
2014   gpgme_key_t key;
2015
2016   err = gpgme_get_key (gt->ctx, fpr, &key, 0);
2017   if (err)
2018     return err;
2019
2020   err = gpgme_op_delete (gt->ctx, key, allow_secret);
2021   gpgme_key_unref (key);
2022   return err;
2023 }
2024
2025
2026 gpg_error_t
2027 gt_keylist_start (gpgme_tool_t gt, const char *pattern[], int secret_only)
2028 {
2029   return gpgme_op_keylist_ext_start (gt->ctx, pattern, secret_only, 0);
2030 }
2031
2032
2033 gpg_error_t
2034 gt_keylist_next (gpgme_tool_t gt, gpgme_key_t *key)
2035 {
2036   return gpgme_op_keylist_next (gt->ctx, key);
2037 }
2038
2039
2040 gpg_error_t
2041 gt_getauditlog (gpgme_tool_t gt, gpgme_data_t output, unsigned int flags)
2042 {
2043   return gpgme_op_getauditlog (gt->ctx, output, flags);
2044 }
2045
2046
2047 gpg_error_t
2048 gt_vfs_mount (gpgme_tool_t gt, const char *container_file,
2049               const char *mount_dir, int flags)
2050 {
2051   gpg_error_t err;
2052   gpg_error_t op_err;
2053   err = gpgme_op_vfs_mount (gt->ctx, container_file, mount_dir, flags, &op_err);
2054   return err ? err : op_err;
2055 }
2056
2057
2058 gpg_error_t
2059 gt_vfs_create (gpgme_tool_t gt, const char *container_file, int flags)
2060 {
2061   gpg_error_t err;
2062   gpg_error_t op_err;
2063   err = gpgme_op_vfs_create (gt->ctx, gt->recipients, container_file,
2064                              flags, &op_err);
2065   gt_recipients_clear (gt);
2066   return err ? err : op_err;
2067 }
2068
2069
2070 gpg_error_t
2071 gt_passwd (gpgme_tool_t gt, char *fpr)
2072 {
2073   gpg_error_t err;
2074   gpgme_key_t key;
2075
2076   err = gpgme_get_key (gt->ctx, fpr, &key, 0);
2077   if (err)
2078     return gpg_err_code (err) == GPG_ERR_EOF? gpg_error (GPG_ERR_NO_PUBKEY):err;
2079
2080   err = gpgme_op_passwd (gt->ctx, key, 0);
2081   gpgme_key_unref (key);
2082   return err;
2083 }
2084
2085
2086 gpg_error_t
2087 gt_identify (gpgme_tool_t gt, gpgme_data_t data)
2088 {
2089   const char *s = "?";
2090
2091   switch (gpgme_data_identify (data, 0))
2092     {
2093     case GPGME_DATA_TYPE_INVALID: return gpg_error (GPG_ERR_GENERAL);
2094     case GPGME_DATA_TYPE_UNKNOWN      : s = "unknown"; break;
2095     case GPGME_DATA_TYPE_PGP_SIGNED   : s = "PGP-signed"; break;
2096     case GPGME_DATA_TYPE_PGP_OTHER    : s = "PGP"; break;
2097     case GPGME_DATA_TYPE_PGP_KEY      : s = "PGP-key"; break;
2098     case GPGME_DATA_TYPE_CMS_SIGNED   : s = "CMS-signed"; break;
2099     case GPGME_DATA_TYPE_CMS_ENCRYPTED: s = "CMS-encrypted"; break;
2100     case GPGME_DATA_TYPE_CMS_OTHER    : s = "CMS"; break;
2101     case GPGME_DATA_TYPE_X509_CERT    : s = "X.509"; break;
2102     case GPGME_DATA_TYPE_PKCS12       : s = "PKCS12"; break;
2103     }
2104   gt_write_status (gt, STATUS_IDENTIFY_RESULT, s, NULL);
2105   return 0;
2106 }
2107
2108
2109 #define GT_RESULT_ENCRYPT 0x1
2110 #define GT_RESULT_DECRYPT 0x2
2111 #define GT_RESULT_SIGN 0x4
2112 #define GT_RESULT_VERIFY 0x8
2113 #define GT_RESULT_IMPORT 0x10
2114 #define GT_RESULT_GENKEY 0x20
2115 #define GT_RESULT_KEYLIST 0x40
2116 #define GT_RESULT_VFS_MOUNT 0x80
2117 #define GT_RESULT_ALL (~0U)
2118
2119 gpg_error_t
2120 gt_result (gpgme_tool_t gt, unsigned int flags)
2121 {
2122   int indent = 2;
2123
2124   gt_write_data (gt, xml_preamble1, sizeof (xml_preamble1));
2125   gt_write_data (gt, NULL, 0);
2126   gt_write_data (gt, xml_preamble2, sizeof (xml_preamble2));
2127   gt_write_data (gt, NULL, 0);
2128   if (flags & GT_RESULT_ENCRYPT)
2129     result_encrypt_to_xml (gt->ctx, indent,
2130                            (result_xml_write_cb_t) gt_write_data, gt);
2131   if (flags & GT_RESULT_DECRYPT)
2132     result_decrypt_to_xml (gt->ctx, indent,
2133                            (result_xml_write_cb_t) gt_write_data, gt);
2134   if (flags & GT_RESULT_SIGN)
2135     result_sign_to_xml (gt->ctx, indent,
2136                         (result_xml_write_cb_t) gt_write_data, gt);
2137   if (flags & GT_RESULT_VERIFY)
2138     result_verify_to_xml (gt->ctx, indent,
2139                           (result_xml_write_cb_t) gt_write_data, gt);
2140   if (flags & GT_RESULT_IMPORT)
2141     result_import_to_xml (gt->ctx, indent,
2142                           (result_xml_write_cb_t) gt_write_data, gt);
2143   if (flags & GT_RESULT_GENKEY)
2144     result_genkey_to_xml (gt->ctx, indent,
2145                           (result_xml_write_cb_t) gt_write_data, gt);
2146   if (flags & GT_RESULT_KEYLIST)
2147     result_keylist_to_xml (gt->ctx, indent,
2148                            (result_xml_write_cb_t) gt_write_data, gt);
2149   if (flags & GT_RESULT_VFS_MOUNT)
2150     result_vfs_mount_to_xml (gt->ctx, indent,
2151                              (result_xml_write_cb_t) gt_write_data, gt);
2152   gt_write_data (gt, xml_end, sizeof (xml_end));
2153
2154   return 0;
2155 }
2156
2157 \f
2158 /* GPGME SERVER.  */
2159
2160 #include <assuan.h>
2161
2162 struct server
2163 {
2164   gpgme_tool_t gt;
2165   assuan_context_t assuan_ctx;
2166
2167   gpgme_data_encoding_t input_enc;
2168   gpgme_data_encoding_t output_enc;
2169   assuan_fd_t input_fd;
2170   char *input_filename;
2171   FILE *input_stream;
2172   assuan_fd_t output_fd;
2173   char *output_filename;
2174   FILE *output_stream;
2175   assuan_fd_t message_fd;
2176   char *message_filename;
2177   FILE *message_stream;
2178   gpgme_data_encoding_t message_enc;
2179 };
2180
2181
2182 gpg_error_t
2183 server_write_status (void *hook, const char *status, const char *msg)
2184 {
2185   struct server *server = hook;
2186   return assuan_write_status (server->assuan_ctx, status, msg);
2187 }
2188
2189
2190 gpg_error_t
2191 server_write_data (void *hook, const void *buf, size_t len)
2192 {
2193   struct server *server = hook;
2194   return assuan_send_data (server->assuan_ctx, buf, len);
2195 }
2196
2197
2198 static gpg_error_t
2199 server_passphrase_cb (void *opaque, const char *uid_hint, const char *info,
2200                       int was_bad, int fd)
2201 {
2202   struct server *server = opaque;
2203   gpg_error_t err;
2204   unsigned char *buf = NULL;
2205   size_t buflen = 0;
2206
2207   if (server && server->assuan_ctx)
2208     {
2209       if (uid_hint)
2210         assuan_write_status (server->assuan_ctx, "USERID_HINT", uid_hint);
2211       if (info)
2212         assuan_write_status (server->assuan_ctx, "NEED_PASSPHRASE", info);
2213
2214       err = assuan_inquire (server->assuan_ctx, "PASSPHRASE",
2215                             &buf, &buflen, 100);
2216     }
2217   else
2218     err = gpg_error (GPG_ERR_NO_PASSPHRASE);
2219
2220   if (!err)
2221     {
2222       /* We take care to always send a LF.  */
2223       if (gpgme_io_writen (fd, buf, buflen))
2224         err = gpg_error_from_syserror ();
2225       else if (!memchr (buf, '\n', buflen) && gpgme_io_writen (fd, "\n", 1))
2226         err = gpg_error_from_syserror ();
2227     }
2228   free (buf);
2229   return err;
2230 }
2231
2232
2233 /* Wrapper around assuan_command_parse_fd to also handle a
2234    "file=FILENAME" argument.  On success either a filename is returned
2235    at FILENAME or a file descriptor at RFD; the other one is set to
2236    NULL respective ASSUAN_INVALID_FD.  */
2237 static gpg_error_t
2238 server_parse_fd (assuan_context_t ctx, char *line, assuan_fd_t *rfd,
2239                  char **filename)
2240 {
2241   *rfd = ASSUAN_INVALID_FD;
2242   *filename = NULL;
2243
2244   if (! strncasecmp (line, "file=", 5))
2245     {
2246       char *term;
2247       *filename = strdup (line + 5);
2248       if (!*filename)
2249         return gpg_error_from_syserror();
2250       term = strchr (*filename, ' ');
2251       if (term)
2252         *term = '\0';
2253       return 0;
2254     }
2255   else
2256     return assuan_command_parse_fd (ctx, line, rfd);
2257 }
2258
2259
2260 static gpgme_data_encoding_t
2261 server_data_encoding (const char *line)
2262 {
2263   if (strstr (line, "--binary"))
2264     return GPGME_DATA_ENCODING_BINARY;
2265   if (strstr (line, "--base64"))
2266     return GPGME_DATA_ENCODING_BASE64;
2267   if (strstr (line, "--armor"))
2268     return GPGME_DATA_ENCODING_ARMOR;
2269   if (strstr (line, "--url"))
2270     return GPGME_DATA_ENCODING_URL;
2271   if (strstr (line, "--urlesc"))
2272     return GPGME_DATA_ENCODING_URLESC;
2273   if (strstr (line, "--url0"))
2274     return GPGME_DATA_ENCODING_URL0;
2275   return GPGME_DATA_ENCODING_NONE;
2276 }
2277
2278
2279 static gpgme_error_t
2280 server_data_obj (assuan_fd_t fd, char *fn, int out,
2281                  gpgme_data_encoding_t encoding,
2282                  gpgme_data_t *data, FILE **fs)
2283 {
2284   gpgme_error_t err;
2285
2286   *fs = NULL;
2287   if (fn)
2288     {
2289       *fs = fopen (fn, out ? "wb" : "rb");
2290       if (!*fs)
2291         return gpg_error_from_syserror ();
2292
2293       err = gpgme_data_new_from_stream (data, *fs);
2294     }
2295   else
2296     err = gpgme_data_new_from_fd (data, (int) fd);
2297
2298   if (err)
2299     return err;
2300   return gpgme_data_set_encoding (*data, encoding);
2301 }
2302
2303
2304 void
2305 server_reset_fds (struct server *server)
2306 {
2307   /* assuan closes the input and output FDs for us when doing a RESET,
2308      but we use this same function after commands, so repeat it
2309      here.  */
2310   if (server->input_fd != ASSUAN_INVALID_FD)
2311     {
2312 #if HAVE_W32_SYSTEM
2313       CloseHandle (server->input_fd);
2314 #else
2315       close (server->input_fd);
2316 #endif
2317       server->input_fd = ASSUAN_INVALID_FD;
2318     }
2319   if (server->output_fd != ASSUAN_INVALID_FD)
2320     {
2321 #if HAVE_W32_SYSTEM
2322       CloseHandle (server->output_fd);
2323 #else
2324       close (server->output_fd);
2325 #endif
2326       server->output_fd = ASSUAN_INVALID_FD;
2327     }
2328   if (server->message_fd != ASSUAN_INVALID_FD)
2329     {
2330       /* FIXME: Assuan should provide a close function.  */
2331 #if HAVE_W32_SYSTEM
2332       CloseHandle (server->message_fd);
2333 #else
2334       close (server->message_fd);
2335 #endif
2336       server->message_fd = ASSUAN_INVALID_FD;
2337     }
2338   if (server->input_filename)
2339     {
2340       free (server->input_filename);
2341       server->input_filename = NULL;
2342     }
2343   if (server->output_filename)
2344     {
2345       free (server->output_filename);
2346       server->output_filename = NULL;
2347     }
2348   if (server->message_filename)
2349     {
2350       free (server->message_filename);
2351       server->message_filename = NULL;
2352     }
2353   if (server->input_stream)
2354     {
2355       fclose (server->input_stream);
2356       server->input_stream = NULL;
2357     }
2358   if (server->output_stream)
2359     {
2360       fclose (server->output_stream);
2361       server->output_stream = NULL;
2362     }
2363   if (server->message_stream)
2364     {
2365       fclose (server->message_stream);
2366       server->message_stream = NULL;
2367     }
2368
2369   server->input_enc = GPGME_DATA_ENCODING_NONE;
2370   server->output_enc = GPGME_DATA_ENCODING_NONE;
2371   server->message_enc = GPGME_DATA_ENCODING_NONE;
2372 }
2373
2374
2375 static gpg_error_t
2376 reset_notify (assuan_context_t ctx, char *line)
2377 {
2378   struct server *server = assuan_get_pointer (ctx);
2379   server_reset_fds (server);
2380   gt_reset (server->gt);
2381   return 0;
2382 }
2383
2384
2385 static const char hlp_version[] =
2386   "VERSION [<string>]\n"
2387   "\n"
2388   "Call the function gpgme_check_version.";
2389 static gpg_error_t
2390 cmd_version (assuan_context_t ctx, char *line)
2391 {
2392   if (line && *line)
2393     {
2394       const char *version = gpgme_check_version (line);
2395       return version ? 0 : gpg_error (GPG_ERR_SELFTEST_FAILED);
2396     }
2397   else
2398     {
2399       const char *version = gpgme_check_version (NULL);
2400       return assuan_send_data (ctx, version, strlen (version));
2401     }
2402 }
2403
2404
2405 static const char hlp_engine[] =
2406   "ENGINE [<string>]\n"
2407   "\n"
2408   "Get information about a GPGME engine (a.k.a. protocol).";
2409 static gpg_error_t
2410 cmd_engine (assuan_context_t ctx, char *line)
2411 {
2412   struct server *server = assuan_get_pointer (ctx);
2413   return gt_get_engine_info (server->gt, gt_protocol_from_name (line));
2414 }
2415
2416
2417 static const char hlp_protocol[] =
2418   "PROTOCOL [<name>]\n"
2419   "\n"
2420   "With NAME, set the protocol.  Without, return the current\n"
2421   "protocol.";
2422 static gpg_error_t
2423 cmd_protocol (assuan_context_t ctx, char *line)
2424 {
2425   struct server *server = assuan_get_pointer (ctx);
2426   if (line && *line)
2427     return gt_set_protocol (server->gt, gt_protocol_from_name (line));
2428   else
2429     return gt_get_protocol (server->gt);
2430 }
2431
2432
2433 static const char hlp_sub_protocol[] =
2434   "SUB_PROTOCOL [<name>]\n"
2435   "\n"
2436   "With NAME, set the sub-protocol.  Without, return the\n"
2437   "current sub-protocol.";
2438 static gpg_error_t
2439 cmd_sub_protocol (assuan_context_t ctx, char *line)
2440 {
2441   struct server *server = assuan_get_pointer (ctx);
2442   if (line && *line)
2443     return gt_set_sub_protocol (server->gt, gt_protocol_from_name (line));
2444   else
2445     return gt_get_sub_protocol (server->gt);
2446 }
2447
2448
2449 static const char hlp_pinentry_mode[] =
2450   "PINENTRY_MODE <name>\n"
2451   "\n"
2452   "Set the pinentry mode to NAME.   Allowedvalues for NAME are:\n"
2453   "  default  - reset to the default of the engine,\n"
2454   "  ask      - force the use of the pinentry,\n"
2455   "  cancel   - emulate use of pinentry's cancel button,\n"
2456   "  error    - return a pinentry error,\n"
2457   "  loopback - redirect pinentry queries to the caller.\n"
2458   "Note that only recent versions of GPG support changing the pinentry mode.";
2459 static gpg_error_t
2460 cmd_pinentry_mode (assuan_context_t ctx, char *line)
2461 {
2462   struct server *server = assuan_get_pointer (ctx);
2463   gpgme_pinentry_mode_t mode;
2464
2465   if (!line || !*line || !strcmp (line, "default"))
2466     mode = GPGME_PINENTRY_MODE_DEFAULT;
2467   else if (!strcmp (line, "ask"))
2468     mode = GPGME_PINENTRY_MODE_ASK;
2469   else if (!strcmp (line, "cancel"))
2470     mode = GPGME_PINENTRY_MODE_CANCEL;
2471   else if (!strcmp (line, "error"))
2472     mode = GPGME_PINENTRY_MODE_ERROR;
2473   else if (!strcmp (line, "loopback"))
2474     mode = GPGME_PINENTRY_MODE_LOOPBACK;
2475   else
2476     return gpg_error (GPG_ERR_INV_VALUE);
2477
2478   return gt_set_pinentry_mode (server->gt, mode, server);
2479 }
2480
2481
2482 static const char hlp_armor[] =
2483   "ARMOR [true|false]\n"
2484   "\n"
2485   "With 'true' or 'false', turn output ASCII armoring on or\n"
2486   "off.  Without, return the current armoring status.";
2487 static gpg_error_t
2488 cmd_armor (assuan_context_t ctx, char *line)
2489 {
2490   struct server *server = assuan_get_pointer (ctx);
2491   if (line && *line)
2492     {
2493       int flag = 0;
2494
2495       if (! strcasecmp (line, "true") || ! strcasecmp (line, "yes")
2496           || line[0] == '1')
2497         flag = 1;
2498
2499       return gt_set_armor (server->gt, flag);
2500     }
2501   else
2502     return gt_get_armor (server->gt);
2503 }
2504
2505
2506 static const char hlp_textmode[] =
2507   "TEXTMODE [true|false]\n"
2508   "\n"
2509   "With 'true' or 'false', turn text mode on or off.\n"
2510   "Without, return the current text mode status.";
2511 static gpg_error_t
2512 cmd_textmode (assuan_context_t ctx, char *line)
2513 {
2514   struct server *server = assuan_get_pointer (ctx);
2515   if (line && *line)
2516     {
2517       int flag = 0;
2518
2519       if (! strcasecmp (line, "true") || ! strcasecmp (line, "yes")
2520           || line[0] == '1')
2521         flag = 1;
2522
2523       return gt_set_textmode (server->gt, flag);
2524     }
2525   else
2526     return gt_get_textmode (server->gt);
2527 }
2528
2529
2530 static const char hlp_include_certs[] =
2531   "INCLUDE_CERTS [default|<n>]\n"
2532   "\n"
2533   "With DEFAULT or N, set how many certificates should be\n"
2534   "included in the next S/MIME signed message.  See the\n"
2535   "GPGME documentation for details on the meaning of"
2536   "various N.  Without either, return the current setting.";
2537 static gpg_error_t
2538 cmd_include_certs (assuan_context_t ctx, char *line)
2539 {
2540   struct server *server = assuan_get_pointer (ctx);
2541
2542   if (line && *line)
2543     {
2544       int include_certs = 0;
2545
2546       if (! strcasecmp (line, "default"))
2547         include_certs = GPGME_INCLUDE_CERTS_DEFAULT;
2548       else
2549         include_certs = atoi (line);
2550
2551       return gt_set_include_certs (server->gt, include_certs);
2552     }
2553   else
2554     return gt_get_include_certs (server->gt);
2555 }
2556
2557
2558 static const char hlp_keylist_mode[] =
2559   "KEYLIST_MODE [local] [extern] [sigs] [sig_notations]\n"
2560   "  [ephemeral] [validate]\n"
2561   "\n"
2562   "Set the mode for the next KEYLIST command.";
2563 static gpg_error_t
2564 cmd_keylist_mode (assuan_context_t ctx, char *line)
2565 {
2566   struct server *server = assuan_get_pointer (ctx);
2567
2568   if (line && *line)
2569     {
2570       gpgme_keylist_mode_t mode = 0;
2571
2572       if (strstr (line, "local"))
2573         mode |= GPGME_KEYLIST_MODE_LOCAL;
2574       if (strstr (line, "extern"))
2575         mode |= GPGME_KEYLIST_MODE_EXTERN;
2576       if (strstr (line, "sigs"))
2577         mode |= GPGME_KEYLIST_MODE_SIGS;
2578       if (strstr (line, "sig_notations"))
2579         mode |= GPGME_KEYLIST_MODE_SIG_NOTATIONS;
2580       if (strstr (line, "ephemeral"))
2581         mode |= GPGME_KEYLIST_MODE_EPHEMERAL;
2582       if (strstr (line, "validate"))
2583         mode |= GPGME_KEYLIST_MODE_VALIDATE;
2584
2585       return gt_set_keylist_mode (server->gt, mode);
2586     }
2587   else
2588     return gt_get_keylist_mode (server->gt);
2589 }
2590
2591
2592 static const char hlp_input[] =
2593   "INPUT [<fd>|FILE=<path>]\n"
2594   "\n"
2595   "Set the input for the next command.  Use either the\n"
2596   "Assuan file descriptor FD or a filesystem PATH.";
2597 static gpg_error_t
2598 cmd_input (assuan_context_t ctx, char *line)
2599 {
2600   struct server *server = assuan_get_pointer (ctx);
2601   gpg_error_t err;
2602   assuan_fd_t sysfd;
2603   char *filename;
2604
2605   err = server_parse_fd (ctx, line, &sysfd, &filename);
2606   if (err)
2607     return err;
2608   server->input_fd = sysfd;
2609   server->input_filename = filename;
2610   server->input_enc = server_data_encoding (line);
2611   return 0;
2612 }
2613
2614
2615 static const char hlp_output[] =
2616   "OUTPUT [<fd>|FILE=<path>]\n"
2617   "\n"
2618   "Set the output for the next command.  Use either the\n"
2619   "Assuan file descriptor FD or a filesystem PATH.";
2620 static gpg_error_t
2621 cmd_output (assuan_context_t ctx, char *line)
2622 {
2623   struct server *server = assuan_get_pointer (ctx);
2624   gpg_error_t err;
2625   assuan_fd_t sysfd;
2626   char *filename;
2627
2628   err = server_parse_fd (ctx, line, &sysfd, &filename);
2629   if (err)
2630     return err;
2631   server->output_fd = sysfd;
2632   server->output_filename = filename;
2633   server->output_enc = server_data_encoding (line);
2634   return 0;
2635 }
2636
2637
2638 static const char hlp_message[] =
2639   "MESSAGE [<fd>|FILE=<path>]\n"
2640   "\n"
2641   "Set the plaintext message for the next VERIFY command\n"
2642   "with a detached signature.  Use either the Assuan file\n"
2643   "descriptor FD or a filesystem PATH.";
2644 static gpg_error_t
2645 cmd_message (assuan_context_t ctx, char *line)
2646 {
2647   struct server *server = assuan_get_pointer (ctx);
2648   gpg_error_t err;
2649   assuan_fd_t sysfd;
2650   char *filename;
2651
2652   err = server_parse_fd (ctx, line, &sysfd, &filename);
2653   if (err)
2654     return err;
2655   server->message_fd = sysfd;
2656   server->message_filename = filename;
2657   server->message_enc = server_data_encoding (line);
2658   return 0;
2659 }
2660
2661
2662 static const char hlp_recipient[] =
2663   "RECIPIENT <pattern>\n"
2664   "\n"
2665   "Add the key matching PATTERN to the list of recipients\n"
2666   "for the next encryption command.";
2667 static gpg_error_t
2668 cmd_recipient (assuan_context_t ctx, char *line)
2669 {
2670   struct server *server = assuan_get_pointer (ctx);
2671
2672   return gt_recipients_add (server->gt, line);
2673 }
2674
2675
2676 static const char hlp_signer[] =
2677   "SIGNER <fingerprint>\n"
2678   "\n"
2679   "Add the key with FINGERPRINT to the list of signers to\n"
2680   "be used for the next signing command.";
2681 static gpg_error_t
2682 cmd_signer (assuan_context_t ctx, char *line)
2683 {
2684   struct server *server = assuan_get_pointer (ctx);
2685
2686   return gt_signers_add (server->gt, line);
2687 }
2688
2689
2690 static const char hlp_signers_clear[] =
2691   "SIGNERS_CLEAR\n"
2692   "\n"
2693   "Clear the list of signers specified by previous SIGNER\n"
2694   "commands.";
2695 static gpg_error_t
2696 cmd_signers_clear (assuan_context_t ctx, char *line)
2697 {
2698   struct server *server = assuan_get_pointer (ctx);
2699
2700   return gt_signers_clear (server->gt);
2701 }
2702
2703
2704 static gpg_error_t
2705 _cmd_decrypt_verify (assuan_context_t ctx, char *line, int verify)
2706 {
2707   struct server *server = assuan_get_pointer (ctx);
2708   gpg_error_t err;
2709   assuan_fd_t inp_fd;
2710   char *inp_fn;
2711   assuan_fd_t out_fd;
2712   char *out_fn;
2713   gpgme_data_t inp_data;
2714   gpgme_data_t out_data;
2715
2716   inp_fd = server->input_fd;
2717   inp_fn = server->input_filename;
2718   if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
2719     return GPG_ERR_ASS_NO_INPUT;
2720   out_fd = server->output_fd;
2721   out_fn = server->output_filename;
2722   if (out_fd == ASSUAN_INVALID_FD && !out_fn)
2723     return GPG_ERR_ASS_NO_OUTPUT;
2724
2725   err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2726                          &server->input_stream);
2727   if (err)
2728     return err;
2729   err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2730                          &server->output_stream);
2731   if (err)
2732     {
2733       gpgme_data_release (inp_data);
2734       return err;
2735     }
2736
2737   err = gt_decrypt_verify (server->gt, inp_data, out_data, verify);
2738
2739   gpgme_data_release (inp_data);
2740   gpgme_data_release (out_data);
2741
2742   server_reset_fds (server);
2743
2744   return err;
2745 }
2746
2747
2748 static const char hlp_decrypt[] =
2749   "DECRYPT\n"
2750   "\n"
2751   "Decrypt the object set by the last INPUT command and\n"
2752   "write the decrypted message to the object set by the\n"
2753   "last OUTPUT command.";
2754 static gpg_error_t
2755 cmd_decrypt (assuan_context_t ctx, char *line)
2756 {
2757   return _cmd_decrypt_verify (ctx, line, 0);
2758 }
2759
2760
2761 static const char hlp_decrypt_verify[] =
2762   "DECRYPT_VERIFY\n"
2763   "\n"
2764   "Decrypt the object set by the last INPUT command and\n"
2765   "verify any embedded signatures.  Write the decrypted\n"
2766   "message to the object set by the last OUTPUT command.";
2767 static gpg_error_t
2768 cmd_decrypt_verify (assuan_context_t ctx, char *line)
2769 {
2770   return _cmd_decrypt_verify (ctx, line, 1);
2771 }
2772
2773
2774 static gpg_error_t
2775 _cmd_sign_encrypt (assuan_context_t ctx, char *line, int sign)
2776 {
2777   struct server *server = assuan_get_pointer (ctx);
2778   gpg_error_t err;
2779   assuan_fd_t inp_fd;
2780   char *inp_fn;
2781   assuan_fd_t out_fd;
2782   char *out_fn;
2783   gpgme_data_t inp_data = NULL;
2784   gpgme_data_t out_data = NULL;
2785   gpgme_encrypt_flags_t flags = 0;
2786
2787   if (strstr (line, "--always-trust"))
2788     flags |= GPGME_ENCRYPT_ALWAYS_TRUST;
2789   if (strstr (line, "--no-encrypt-to"))
2790     flags |= GPGME_ENCRYPT_NO_ENCRYPT_TO;
2791   if (strstr (line, "--prepare"))
2792     flags |= GPGME_ENCRYPT_PREPARE;
2793   if (strstr (line, "--expect-sign"))
2794     flags |= GPGME_ENCRYPT_EXPECT_SIGN;
2795
2796   inp_fd = server->input_fd;
2797   inp_fn = server->input_filename;
2798   out_fd = server->output_fd;
2799   out_fn = server->output_filename;
2800   if (inp_fd != ASSUAN_INVALID_FD || inp_fn)
2801     {
2802       err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2803                              &server->input_stream);
2804       if (err)
2805         return err;
2806     }
2807   if (out_fd != ASSUAN_INVALID_FD || out_fn)
2808     {
2809       err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2810                              &server->output_stream);
2811       if (err)
2812         {
2813           gpgme_data_release (inp_data);
2814           return err;
2815         }
2816     }
2817
2818   err = gt_sign_encrypt (server->gt, flags, inp_data, out_data, sign);
2819
2820   gpgme_data_release (inp_data);
2821   gpgme_data_release (out_data);
2822
2823   server_reset_fds (server);
2824
2825   return err;
2826 }
2827
2828
2829 static const char hlp_encrypt[] =
2830   "ENCRYPT [--always-trust] [--no-encrypt-to]\n"
2831   "  [--prepare] [--expect-sign]\n"
2832   "\n"
2833   "Encrypt the object set by the last INPUT command to\n"
2834   "the keys specified by previous RECIPIENT commands.  \n"
2835   "Write the signed and encrypted message to the object\n"
2836   "set by the last OUTPUT command.";
2837 static gpg_error_t
2838 cmd_encrypt (assuan_context_t ctx, char *line)
2839 {
2840   return _cmd_sign_encrypt (ctx, line, 0);
2841 }
2842
2843
2844 static const char hlp_sign_encrypt[] =
2845   "SIGN_ENCRYPT [--always-trust] [--no-encrypt-to]\n"
2846   "  [--prepare] [--expect-sign]\n"
2847   "\n"
2848   "Sign the object set by the last INPUT command with the\n"
2849   "keys specified by previous SIGNER commands and encrypt\n"
2850   "it to the keys specified by previous RECIPIENT\n"
2851   "commands.  Write the signed and encrypted message to\n"
2852   "the object set by the last OUTPUT command.";
2853 static gpg_error_t
2854 cmd_sign_encrypt (assuan_context_t ctx, char *line)
2855 {
2856   return _cmd_sign_encrypt (ctx, line, 1);
2857 }
2858
2859
2860 static const char hlp_sign[] =
2861   "SIGN [--clear|--detach]\n"
2862   "\n"
2863   "Sign the object set by the last INPUT command with the\n"
2864   "keys specified by previous SIGNER commands.  Write the\n"
2865   "signed message to the object set by the last OUTPUT\n"
2866   "command.  With `--clear`, generate a clear text\n"
2867   "signature.  With `--detach`, generate a detached\n"
2868   "signature.";
2869 static gpg_error_t
2870 cmd_sign (assuan_context_t ctx, char *line)
2871 {
2872   struct server *server = assuan_get_pointer (ctx);
2873   gpg_error_t err;
2874   assuan_fd_t inp_fd;
2875   char *inp_fn;
2876   assuan_fd_t out_fd;
2877   char *out_fn;
2878   gpgme_data_t inp_data;
2879   gpgme_data_t out_data;
2880   gpgme_sig_mode_t mode = GPGME_SIG_MODE_NORMAL;
2881
2882   if (strstr (line, "--clear"))
2883     mode = GPGME_SIG_MODE_CLEAR;
2884   if (strstr (line, "--detach"))
2885     mode = GPGME_SIG_MODE_DETACH;
2886
2887   inp_fd = server->input_fd;
2888   inp_fn = server->input_filename;
2889   if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
2890     return GPG_ERR_ASS_NO_INPUT;
2891   out_fd = server->output_fd;
2892   out_fn = server->output_filename;
2893   if (out_fd == ASSUAN_INVALID_FD && !out_fn)
2894     return GPG_ERR_ASS_NO_OUTPUT;
2895
2896   err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2897                          &server->input_stream);
2898   if (err)
2899     return err;
2900   err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2901                          &server->output_stream);
2902   if (err)
2903     {
2904       gpgme_data_release (inp_data);
2905       return err;
2906     }
2907
2908   err = gt_sign (server->gt, inp_data, out_data, mode);
2909
2910   gpgme_data_release (inp_data);
2911   gpgme_data_release (out_data);
2912   server_reset_fds (server);
2913
2914   return err;
2915 }
2916
2917
2918 static const char hlp_verify[] =
2919   "VERIFY\n"
2920   "\n"
2921   "Verify signatures on the object set by the last INPUT\n"
2922   "and MESSAGE commands.  If the message was encrypted,\n"
2923   "write the plaintext to the object set by the last\n"
2924   "OUTPUT command.";
2925 static gpg_error_t
2926 cmd_verify (assuan_context_t ctx, char *line)
2927 {
2928   struct server *server = assuan_get_pointer (ctx);
2929   gpg_error_t err;
2930   assuan_fd_t inp_fd;
2931   assuan_fd_t msg_fd;
2932   assuan_fd_t out_fd;
2933   char *inp_fn;
2934   char *msg_fn;
2935   char *out_fn;
2936   gpgme_data_t inp_data;
2937   gpgme_data_t msg_data = NULL;
2938   gpgme_data_t out_data = NULL;
2939
2940   inp_fd = server->input_fd;
2941   inp_fn = server->input_filename;
2942   if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
2943     return GPG_ERR_ASS_NO_INPUT;
2944   msg_fd = server->message_fd;
2945   msg_fn = server->message_filename;
2946   out_fd = server->output_fd;
2947   out_fn = server->output_filename;
2948
2949   err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2950                          &server->input_stream);
2951   if (err)
2952     return err;
2953   if (msg_fd != ASSUAN_INVALID_FD || msg_fn)
2954     {
2955       err = server_data_obj (msg_fd, msg_fn, 0, server->message_enc, &msg_data,
2956                              &server->message_stream);
2957       if (err)
2958         {
2959           gpgme_data_release (inp_data);
2960           return err;
2961         }
2962     }
2963   if (out_fd != ASSUAN_INVALID_FD || out_fn)
2964     {
2965       err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2966                              &server->output_stream);
2967       if (err)
2968         {
2969           gpgme_data_release (inp_data);
2970           gpgme_data_release (msg_data);
2971           return err;
2972         }
2973     }
2974
2975   err = gt_verify (server->gt, inp_data, msg_data, out_data);
2976
2977   gpgme_data_release (inp_data);
2978   if (msg_data)
2979     gpgme_data_release (msg_data);
2980   if (out_data)
2981     gpgme_data_release (out_data);
2982
2983   server_reset_fds (server);
2984
2985   return err;
2986 }
2987
2988
2989 static const char hlp_import[] =
2990   "IMPORT [<pattern>]\n"
2991   "\n"
2992   "With PATTERN, import the keys described by PATTERN.\n"
2993   "Without, read a key (or keys) from the object set by the\n"
2994   "last INPUT command.";
2995 static gpg_error_t
2996 cmd_import (assuan_context_t ctx, char *line)
2997 {
2998   struct server *server = assuan_get_pointer (ctx);
2999
3000   if (line && *line)
3001     {
3002       char *fprs[2] = { line, NULL };
3003
3004       return gt_import_keys (server->gt, fprs);
3005     }
3006   else
3007     {
3008       gpg_error_t err;
3009       assuan_fd_t inp_fd;
3010       char *inp_fn;
3011       gpgme_data_t inp_data;
3012
3013       inp_fd = server->input_fd;
3014       inp_fn = server->input_filename;
3015       if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
3016         return GPG_ERR_ASS_NO_INPUT;
3017
3018       err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
3019                              &server->input_stream);
3020       if (err)
3021         return err;
3022
3023       err = gt_import (server->gt, inp_data);
3024
3025       gpgme_data_release (inp_data);
3026       server_reset_fds (server);
3027
3028       return err;
3029     }
3030 }
3031
3032
3033 static const char hlp_export[] =
3034   "EXPORT [--extern] [--minimal] [<pattern>]\n"
3035   "\n"
3036   "Export the keys described by PATTERN.  Write the\n"
3037   "the output to the object set by the last OUTPUT command.";
3038 static gpg_error_t
3039 cmd_export (assuan_context_t ctx, char *line)
3040 {
3041   struct server *server = assuan_get_pointer (ctx);
3042   gpg_error_t err;
3043   assuan_fd_t out_fd;
3044   char *out_fn;
3045   gpgme_data_t out_data;
3046   gpgme_export_mode_t mode = 0;
3047   const char *pattern[2];
3048
3049   out_fd = server->output_fd;
3050   out_fn = server->output_filename;
3051   if (out_fd == ASSUAN_INVALID_FD && !out_fn)
3052     return GPG_ERR_ASS_NO_OUTPUT;
3053   err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
3054                          &server->output_stream);
3055   if (err)
3056     return err;
3057
3058   if (has_option (line, "--extern"))
3059     mode |= GPGME_EXPORT_MODE_EXTERN;
3060   if (has_option (line, "--minimal"))
3061     mode |= GPGME_EXPORT_MODE_MINIMAL;
3062
3063   line = skip_options (line);
3064
3065   pattern[0] = line;
3066   pattern[1] = NULL;
3067
3068   err = gt_export (server->gt, pattern, mode, out_data);
3069
3070   gpgme_data_release (out_data);
3071   server_reset_fds (server);
3072
3073   return err;
3074 }
3075
3076
3077 static gpg_error_t
3078 _cmd_genkey_write (gpgme_data_t data, const void *buf, size_t size)
3079 {
3080   while (size > 0)
3081     {
3082       gpgme_ssize_t writen = gpgme_data_write (data, buf, size);
3083       if (writen < 0 && errno != EAGAIN)
3084         return gpg_error_from_syserror ();
3085       else if (writen > 0)
3086         {
3087           buf = (void *) (((char *) buf) + writen);
3088           size -= writen;
3089         }
3090     }
3091   return 0;
3092 }
3093
3094
3095 static gpg_error_t
3096 cmd_genkey (assuan_context_t ctx, char *line)
3097 {
3098   struct server *server = assuan_get_pointer (ctx);
3099   gpg_error_t err;
3100   assuan_fd_t inp_fd;
3101   char *inp_fn;
3102   assuan_fd_t out_fd;
3103   char *out_fn;
3104   gpgme_data_t inp_data;
3105   gpgme_data_t out_data = NULL;
3106   gpgme_data_t parms_data = NULL;
3107   const char *parms;
3108
3109   inp_fd = server->input_fd;
3110   inp_fn = server->input_filename;
3111   if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
3112     return GPG_ERR_ASS_NO_INPUT;
3113   out_fd = server->output_fd;
3114   out_fn = server->output_filename;
3115
3116   err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
3117                          &server->input_stream);
3118   if (err)
3119     return err;
3120   if (out_fd != ASSUAN_INVALID_FD || out_fn)
3121     {
3122       err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
3123                              &server->output_stream);
3124       if (err)
3125         {
3126           gpgme_data_release (inp_data);
3127           return err;
3128         }
3129     }
3130
3131   /* Convert input data.  */
3132   err = gpgme_data_new (&parms_data);
3133   if (err)
3134     goto out;
3135   do
3136     {
3137       char buf[512];
3138       gpgme_ssize_t readn = gpgme_data_read (inp_data, buf, sizeof (buf));
3139       if (readn < 0)
3140         {
3141           err = gpg_error_from_syserror ();
3142           goto out;
3143         }
3144       else if (readn == 0)
3145         break;
3146
3147       err = _cmd_genkey_write (parms_data, buf, readn);
3148       if (err)
3149         goto out;
3150     }
3151   while (1);
3152   err = _cmd_genkey_write (parms_data, "", 1);
3153   if (err)
3154     goto out;
3155   parms = gpgme_data_release_and_get_mem (parms_data, NULL);
3156   parms_data = NULL;
3157   if (! parms)
3158     {
3159       err = gpg_error (GPG_ERR_GENERAL);
3160       goto out;
3161     }
3162
3163   err = gt_genkey (server->gt, parms, out_data, NULL);
3164
3165   server_reset_fds (server);
3166
3167  out:
3168   gpgme_data_release (inp_data);
3169   if (out_data)
3170     gpgme_data_release (out_data);
3171   if (parms_data)
3172     gpgme_data_release (parms_data);
3173
3174   return err;
3175 }
3176
3177
3178 static gpg_error_t
3179 cmd_delete (assuan_context_t ctx, char *line)
3180 {
3181   struct server *server = assuan_get_pointer (ctx);
3182   int allow_secret = 0;
3183   const char optstr[] = "--allow-secret";
3184
3185   if (!strncasecmp (line, optstr, strlen (optstr)))
3186     {
3187       allow_secret = 1;
3188       line += strlen (optstr);
3189       while (*line && !spacep (line))
3190         line++;
3191     }
3192   return gt_delete (server->gt, line, allow_secret);
3193 }
3194
3195
3196 static const char hlp_keylist[] =
3197   "KEYLIST [--secret-only] [<patterns>]\n"
3198   "\n"
3199   "List all certificates or only those specified by PATTERNS.  Each\n"
3200   "pattern shall be a percent-plus escaped certificate specification.";
3201 static gpg_error_t
3202 cmd_keylist (assuan_context_t ctx, char *line)
3203 {
3204 #define MAX_CMD_KEYLIST_PATTERN 20
3205   struct server *server = assuan_get_pointer (ctx);
3206   gpgme_tool_t gt = server->gt;
3207   struct result_xml_state state;
3208   gpg_error_t err;
3209   int secret_only = 0;
3210   int idx, indent=2;
3211   const char *pattern[MAX_CMD_KEYLIST_PATTERN+1];
3212   const char optstr[] = "--secret-only";
3213   char *p;
3214
3215   if (!strncasecmp (line, optstr, strlen (optstr)))
3216     {
3217       secret_only = 1;
3218       line += strlen (optstr);
3219       while (*line && !spacep (line))
3220         line++;
3221     }
3222
3223   idx = 0;
3224   for (p=line; *p; line = p)
3225     {
3226       while (*p && *p != ' ')
3227         p++;
3228       if (*p)
3229         *p++ = 0;
3230       if (*line)
3231         {
3232           if (idx+1 == DIM (pattern))
3233             return gpg_error (GPG_ERR_TOO_MANY);
3234           strcpy_escaped_plus (line, line);
3235           pattern[idx++] = line;
3236         }
3237     }
3238   pattern[idx] = NULL;
3239
3240   gt_write_data (gt, xml_preamble1, sizeof (xml_preamble1));
3241   gt_write_data (gt, NULL, 0);
3242   gt_write_data (gt, xml_preamble2, sizeof (xml_preamble2));
3243   gt_write_data (gt, NULL, 0);
3244   result_init (&state, indent, (result_xml_write_cb_t) gt_write_data, gt);
3245   result_xml_tag_start (&state, "keylist", NULL);
3246
3247   err = gt_keylist_start (server->gt, pattern, secret_only);
3248   while (! err)
3249     {
3250       gpgme_key_t key;
3251       gpgme_subkey_t subkey;
3252       gpgme_user_id_t uid;
3253
3254       err = gt_keylist_next (server->gt, &key);
3255       if (gpg_err_code (err) == GPG_ERR_EOF)
3256         {
3257           err = 0;
3258           break;
3259         }
3260       else if (! err)
3261         {
3262           result_xml_tag_start (&state, "key", NULL);
3263           result_add_value (&state, "revoked", key->revoked);
3264           result_add_value (&state, "expired", key->expired);
3265           result_add_value (&state, "disabled", key->disabled);
3266           result_add_value (&state, "invalid", key->invalid);
3267           result_add_value (&state, "can-encrypt", key->can_encrypt);
3268           result_add_value (&state, "can-sign", key->can_sign);
3269           result_add_value (&state, "can-certify", key->can_certify);
3270           result_add_value (&state, "can-authenticate", key->can_authenticate);
3271           result_add_value (&state, "is-qualified", key->is_qualified);
3272           result_add_value (&state, "secret", key->secret);
3273           result_add_protocol (&state, "protocol", key->protocol);
3274           result_xml_tag_start (&state, "issuer", NULL);
3275           result_add_string (&state, "serial", key->issuer_serial);
3276           result_add_string (&state, "name", key->issuer_name);
3277           result_xml_tag_end (&state);  /* issuer */
3278           result_add_string (&state, "chain-id", key->chain_id);
3279           result_add_validity (&state, "owner-trust", key->owner_trust);
3280           result_xml_tag_start (&state, "subkeys", NULL);
3281           subkey = key->subkeys;
3282           while (subkey) {
3283             result_xml_tag_start (&state, "subkey", NULL);
3284             /* FIXME: more data */
3285             result_add_fpr (&state, "fpr", subkey->fpr);
3286             result_xml_tag_end (&state);  /* subkey */
3287             subkey = subkey->next;
3288           }
3289           result_xml_tag_end (&state);  /* subkeys */
3290           result_xml_tag_start (&state, "uids", NULL);
3291           uid = key->uids;
3292           while (uid) {
3293             result_xml_tag_start (&state, "uid", NULL);
3294             /* FIXME: more data */
3295             result_add_string (&state, "uid", uid->uid);
3296             result_add_string (&state, "name", uid->name);
3297             result_add_string (&state, "email", uid->email);
3298             result_add_string (&state, "comment", uid->comment);
3299             result_xml_tag_end (&state);  /* uid */
3300             uid = uid->next;
3301           }
3302           result_xml_tag_end (&state);  /* uids */
3303           result_xml_tag_end (&state);  /* key */
3304           gpgme_key_unref (key);
3305         }
3306     }
3307
3308   result_xml_tag_end (&state);  /* keylist */
3309   gt_write_data (gt, xml_end, sizeof (xml_end));
3310
3311   server_reset_fds (server);
3312
3313   return err;
3314 }
3315
3316
3317 static const char hlp_getauditlog[] =
3318   "GETAUDITLOG [--html] [--with-help]\n"
3319   "\n"
3320   "Call the function gpgme_op_getauditlog with the given flags.  Write\n"
3321   "the output to the object set by the last OUTPUT command.";
3322 static gpg_error_t
3323 cmd_getauditlog (assuan_context_t ctx, char *line)
3324 {
3325   struct server *server = assuan_get_pointer (ctx);
3326   gpg_error_t err;
3327   assuan_fd_t out_fd;
3328   char *out_fn;
3329   gpgme_data_t out_data;
3330   unsigned int flags = 0;
3331
3332   out_fd = server->output_fd;
3333   out_fn = server->output_filename;
3334   if (out_fd == ASSUAN_INVALID_FD && !out_fn)
3335     return GPG_ERR_ASS_NO_OUTPUT;
3336   err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
3337                          &server->output_stream);
3338   if (err)
3339     return err;
3340
3341   if (strstr (line, "--html"))
3342     flags |= GPGME_AUDITLOG_HTML;
3343   if (strstr (line, "--with-help"))
3344     flags |= GPGME_AUDITLOG_WITH_HELP;
3345
3346   err = gt_getauditlog (server->gt, out_data, flags);
3347
3348   gpgme_data_release (out_data);
3349   server_reset_fds (server);
3350
3351   return err;
3352 }
3353
3354
3355 static gpg_error_t
3356 cmd_vfs_mount (assuan_context_t ctx, char *line)
3357 {
3358   struct server *server = assuan_get_pointer (ctx);
3359   char *mount_dir;
3360   gpg_error_t err;
3361
3362   mount_dir = strchr (line, ' ');
3363   if (mount_dir)
3364     {
3365       *(mount_dir++) = '\0';
3366       while (*mount_dir == ' ')
3367         mount_dir++;
3368     }
3369
3370   err = gt_vfs_mount (server->gt, line, mount_dir, 0);
3371
3372   return err;
3373 }
3374
3375
3376 static gpg_error_t
3377 cmd_vfs_create (assuan_context_t ctx, char *line)
3378 {
3379   struct server *server = assuan_get_pointer (ctx);
3380   gpg_error_t err;
3381   char *end;
3382
3383   end = strchr (line, ' ');
3384   if (end)
3385     {
3386       *(end++) = '\0';
3387       while (*end == ' ')
3388         end++;
3389     }
3390
3391   err = gt_vfs_create (server->gt, line, 0);
3392
3393   return err;
3394 }
3395
3396
3397 static const char hlp_passwd[] =
3398   "PASSWD <user-id>\n"
3399   "\n"
3400   "Ask the backend to change the passphrase for the key\n"
3401   "specified by USER-ID.";
3402 static gpg_error_t
3403 cmd_passwd (assuan_context_t ctx, char *line)
3404 {
3405   struct server *server = assuan_get_pointer (ctx);
3406
3407   return gt_passwd (server->gt, line);
3408 }
3409
3410
3411
3412 static gpg_error_t
3413 cmd_result (assuan_context_t ctx, char *line)
3414 {
3415   struct server *server = assuan_get_pointer (ctx);
3416   return gt_result (server->gt, GT_RESULT_ALL);
3417 }
3418
3419
3420 /* STRERROR <err>  */
3421 static gpg_error_t
3422 cmd_strerror (assuan_context_t ctx, char *line)
3423 {
3424   gpg_error_t err;
3425   char buf[100];
3426
3427   err = atoi (line);
3428   snprintf (buf, sizeof (buf), "%s <%s>", gpgme_strerror (err),
3429             gpgme_strsource (err));
3430   return assuan_send_data (ctx, buf, strlen (buf));
3431 }
3432
3433
3434 static gpg_error_t
3435 cmd_pubkey_algo_name (assuan_context_t ctx, char *line)
3436 {
3437   gpgme_pubkey_algo_t algo;
3438   char buf[100];
3439
3440   algo = atoi (line);
3441   snprintf (buf, sizeof (buf), "%s", gpgme_pubkey_algo_name (algo));
3442   return assuan_send_data (ctx, buf, strlen (buf));
3443 }
3444
3445
3446 static gpg_error_t
3447 cmd_hash_algo_name (assuan_context_t ctx, char *line)
3448 {
3449   gpgme_hash_algo_t algo;
3450   char buf[100];
3451
3452   algo = atoi (line);
3453   snprintf (buf, sizeof (buf), "%s", gpgme_hash_algo_name (algo));
3454   return assuan_send_data (ctx, buf, strlen (buf));
3455 }
3456
3457
3458 static const char hlp_identify[] =
3459   "IDENTIY\n"
3460   "\n"
3461   "Identify the type of data set with the INPUT command.";
3462 static gpg_error_t
3463 cmd_identify (assuan_context_t ctx, char *line)
3464 {
3465   struct server *server = assuan_get_pointer (ctx);
3466   gpg_error_t err;
3467   assuan_fd_t inp_fd;
3468   char *inp_fn;
3469   gpgme_data_t inp_data;
3470
3471   inp_fd = server->input_fd;
3472   inp_fn = server->input_filename;
3473   if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
3474     return GPG_ERR_ASS_NO_INPUT;
3475
3476   err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
3477                          &server->input_stream);
3478   if (err)
3479     return err;
3480
3481   err = gt_identify (server->gt, inp_data);
3482
3483   gpgme_data_release (inp_data);
3484   server_reset_fds (server);
3485
3486   return err;
3487 }
3488
3489
3490
3491 /* Tell the assuan library about our commands.  */
3492 static gpg_error_t
3493 register_commands (assuan_context_t ctx)
3494 {
3495   gpg_error_t err;
3496   static struct {
3497     const char *name;
3498     assuan_handler_t handler;
3499     const char * const help;
3500   } table[] = {
3501     /* RESET, BYE are implicit.  */
3502     { "VERSION", cmd_version, hlp_version },
3503     /* TODO: Set engine info.  */
3504     { "ENGINE", cmd_engine, hlp_engine },
3505     { "PROTOCOL", cmd_protocol, hlp_protocol },
3506     { "SUB_PROTOCOL", cmd_sub_protocol, hlp_sub_protocol },
3507     { "PINENTRY_MODE", cmd_pinentry_mode, hlp_pinentry_mode },
3508     { "ARMOR", cmd_armor, hlp_armor },
3509     { "TEXTMODE", cmd_textmode, hlp_textmode },
3510     { "INCLUDE_CERTS", cmd_include_certs, hlp_include_certs },
3511     { "KEYLIST_MODE", cmd_keylist_mode, hlp_keylist_mode },
3512     { "INPUT", cmd_input, hlp_input },
3513     { "OUTPUT", cmd_output, hlp_output },
3514     { "MESSAGE", cmd_message, hlp_message },
3515     { "RECIPIENT", cmd_recipient, hlp_recipient },
3516     { "SIGNER", cmd_signer, hlp_signer },
3517     { "SIGNERS_CLEAR", cmd_signers_clear, hlp_signers_clear },
3518      /* TODO: SIGNOTATION missing. */
3519      /* TODO: Could add wait interface if we allow more than one context */
3520      /* and add _START variants. */
3521      /* TODO: Could add data interfaces if we allow multiple data objects. */
3522     { "DECRYPT", cmd_decrypt, hlp_decrypt },
3523     { "DECRYPT_VERIFY", cmd_decrypt_verify, hlp_decrypt_verify },
3524     { "ENCRYPT", cmd_encrypt, hlp_encrypt },
3525     { "ENCRYPT_SIGN", cmd_sign_encrypt, hlp_sign_encrypt },
3526     { "SIGN_ENCRYPT", cmd_sign_encrypt, hlp_sign_encrypt },
3527     { "SIGN", cmd_sign, hlp_sign },
3528     { "VERIFY", cmd_verify, hlp_verify },
3529     { "IMPORT", cmd_import, hlp_import },
3530     { "EXPORT", cmd_export, hlp_export },
3531     { "GENKEY", cmd_genkey },
3532     { "DELETE", cmd_delete },
3533     /* TODO: EDIT, CARD_EDIT (with INQUIRE) */
3534     { "KEYLIST", cmd_keylist, hlp_keylist },
3535     { "LISTKEYS", cmd_keylist, hlp_keylist },
3536     /* TODO: TRUSTLIST, TRUSTLIST_EXT */
3537     { "GETAUDITLOG", cmd_getauditlog, hlp_getauditlog },
3538     /* TODO: ASSUAN */
3539     { "VFS_MOUNT", cmd_vfs_mount },
3540     { "MOUNT", cmd_vfs_mount },
3541     { "VFS_CREATE", cmd_vfs_create },
3542     { "CREATE", cmd_vfs_create },
3543     /* TODO: GPGCONF  */
3544     { "RESULT", cmd_result },
3545     { "STRERROR", cmd_strerror },
3546     { "PUBKEY_ALGO_NAME", cmd_pubkey_algo_name },
3547     { "HASH_ALGO_NAME", cmd_hash_algo_name },
3548     { "PASSWD", cmd_passwd, hlp_passwd },
3549     { "IDENTIFY", cmd_identify, hlp_identify },
3550     { NULL }
3551   };
3552   int idx;
3553
3554   for (idx = 0; table[idx].name; idx++)
3555     {
3556       err = assuan_register_command (ctx, table[idx].name, table[idx].handler,
3557                                      table[idx].help);
3558       if (err)
3559         return err;
3560     }
3561   return 0;
3562 }
3563
3564
3565 void
3566 gpgme_server (gpgme_tool_t gt)
3567 {
3568   gpg_error_t err;
3569   assuan_fd_t filedes[2];
3570   struct server server;
3571   static const char hello[] = ("GPGME-Tool " VERSION " ready");
3572
3573   memset (&server, 0, sizeof (server));
3574   server.input_fd = ASSUAN_INVALID_FD;
3575   server.output_fd = ASSUAN_INVALID_FD;
3576   server.message_fd = ASSUAN_INVALID_FD;
3577   server.input_enc = GPGME_DATA_ENCODING_NONE;
3578   server.output_enc = GPGME_DATA_ENCODING_NONE;
3579   server.message_enc = GPGME_DATA_ENCODING_NONE;
3580
3581   server.gt = gt;
3582   gt->write_status = server_write_status;
3583   gt->write_status_hook = &server;
3584   gt->write_data = server_write_data;
3585   gt->write_data_hook = &server;
3586
3587   /* We use a pipe based server so that we can work from scripts.
3588      assuan_init_pipe_server will automagically detect when we are
3589      called with a socketpair and ignore FIELDES in this case. */
3590 #ifdef HAVE_W32CE_SYSTEM
3591   filedes[0] = ASSUAN_STDIN;
3592   filedes[1] = ASSUAN_STDOUT;
3593 #else
3594   filedes[0] = assuan_fdopen (0);
3595   filedes[1] = assuan_fdopen (1);
3596 #endif
3597   err = assuan_new (&server.assuan_ctx);
3598   if (err)
3599     log_error (1, err, "can't create assuan context");
3600
3601   assuan_set_pointer (server.assuan_ctx, &server);
3602
3603   err = assuan_init_pipe_server (server.assuan_ctx, filedes);
3604   if (err)
3605     log_error (1, err, "can't initialize assuan server");
3606   err = register_commands (server.assuan_ctx);
3607   if (err)
3608     log_error (1, err, "can't register assuan commands");
3609   assuan_set_hello_line (server.assuan_ctx, hello);
3610
3611   assuan_register_reset_notify (server.assuan_ctx, reset_notify);
3612
3613 #define DBG_ASSUAN 0
3614   if (DBG_ASSUAN)
3615     assuan_set_log_stream (server.assuan_ctx, log_stream);
3616
3617   for (;;)
3618     {
3619       err = assuan_accept (server.assuan_ctx);
3620       if (err == -1)
3621         break;
3622       else if (err)
3623         {
3624           log_error (0, err, "assuan accept problem");
3625           break;
3626         }
3627
3628       err = assuan_process (server.assuan_ctx);
3629       if (err)
3630         log_error (0, err, "assuan processing failed");
3631     }
3632
3633   assuan_release (server.assuan_ctx);
3634 }
3635
3636
3637 \f
3638 /* MAIN PROGRAM STARTS HERE.  */
3639
3640 const char *argp_program_version = VERSION;
3641 const char *argp_program_bug_address = "bug-gpgme@gnupg.org";
3642 error_t argp_err_exit_status = 1;
3643
3644 static char doc[] = "GPGME Tool -- Assuan server exposing GPGME operations";
3645 static char args_doc[] = "COMMAND [OPTIONS...]";
3646
3647 static struct argp_option options[] = {
3648   { "server", 's', 0, 0, "Server mode" },
3649   { "gpg-binary", 501, "FILE", 0, "Use FILE for the GPG backend" },
3650   { 0 }
3651 };
3652
3653 static error_t parse_options (int key, char *arg, struct argp_state *state);
3654 static struct argp argp = { options, parse_options, args_doc, doc };
3655
3656 struct args
3657 {
3658   enum { CMD_DEFAULT, CMD_SERVER } cmd;
3659   const char *gpg_binary;
3660 };
3661
3662 void
3663 args_init (struct args *args)
3664 {
3665   memset (args, '\0', sizeof (*args));
3666   args->cmd = CMD_DEFAULT;
3667 }
3668
3669
3670 static error_t
3671 parse_options (int key, char *arg, struct argp_state *state)
3672 {
3673   struct args *args = state->input;
3674
3675   switch (key)
3676     {
3677     case 's':
3678       args->cmd = CMD_SERVER;
3679       break;
3680
3681     case 501:
3682       args->gpg_binary = arg;
3683       break;
3684 #if 0
3685     case ARGP_KEY_ARG:
3686       if (state->arg_num >= 2)
3687         argp_usage (state);
3688       printf ("Arg[%i] = %s\n", state->arg_num, arg);
3689       break;
3690     case ARGP_KEY_END:
3691       if (state->arg_num < 2)
3692         argp_usage (state);
3693       break;
3694 #endif
3695
3696     default:
3697       return ARGP_ERR_UNKNOWN;
3698     }
3699   return 0;
3700 }
3701
3702 \f
3703 int
3704 main (int argc, char *argv[])
3705 {
3706   struct args args;
3707   struct gpgme_tool gt;
3708   gpg_error_t err;
3709
3710 #ifdef HAVE_SETLOCALE
3711   setlocale (LC_ALL, "");
3712 #endif
3713   gpgme_check_version (NULL);
3714 #ifdef LC_CTYPE
3715   gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
3716 #endif
3717 #ifdef LC_MESSAGES
3718   gpgme_set_locale (NULL, LC_MESSAGES, setlocale (LC_MESSAGES, NULL));
3719 #endif
3720
3721   args_init (&args);
3722
3723   argp_parse (&argp, argc, argv, 0, 0, &args);
3724   log_init ();
3725
3726   if (args.gpg_binary)
3727     {
3728       if (access (args.gpg_binary, X_OK))
3729         err = gpg_error_from_syserror ();
3730       else
3731         err = gpgme_set_engine_info (GPGME_PROTOCOL_OpenPGP,
3732                                      args.gpg_binary, NULL);
3733       if (err)
3734         log_error (1, err, "error witching OpenPGP engine to '%s'",
3735                    args.gpg_binary);
3736     }
3737
3738   gt_init (&gt);
3739
3740   switch (args.cmd)
3741     {
3742     case CMD_DEFAULT:
3743     case CMD_SERVER:
3744       gpgme_server (&gt);
3745       break;
3746     }
3747
3748   gpgme_release (gt.ctx);
3749
3750 #ifdef HAVE_W32CE_SYSTEM
3751   /* Give the buggy ssh server time to flush the output buffers.  */
3752   Sleep (300);
3753 #endif
3754
3755   return 0;
3756 }
3757