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