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