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