gpgme-tool: Switch to argparse.c for option parsing.
[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_OTHER    : s = "PGP"; break;
1687     case GPGME_DATA_TYPE_PGP_KEY      : s = "PGP-key"; break;
1688     case GPGME_DATA_TYPE_CMS_SIGNED   : s = "CMS-signed"; break;
1689     case GPGME_DATA_TYPE_CMS_ENCRYPTED: s = "CMS-encrypted"; break;
1690     case GPGME_DATA_TYPE_CMS_OTHER    : s = "CMS"; break;
1691     case GPGME_DATA_TYPE_X509_CERT    : s = "X.509"; break;
1692     case GPGME_DATA_TYPE_PKCS12       : s = "PKCS12"; break;
1693     }
1694   gt_write_status (gt, STATUS_IDENTIFY_RESULT, s, NULL);
1695   return 0;
1696 }
1697
1698
1699 gpg_error_t
1700 gt_spawn (gpgme_tool_t gt, const char *pgm,
1701           gpgme_data_t inp, gpgme_data_t outp)
1702 {
1703   gpg_error_t err;
1704
1705   err = gpgme_op_spawn (gt->ctx, pgm, NULL, inp, outp, outp, 0);
1706
1707   return err;
1708 }
1709
1710
1711 #define GT_RESULT_ENCRYPT 0x1
1712 #define GT_RESULT_DECRYPT 0x2
1713 #define GT_RESULT_SIGN 0x4
1714 #define GT_RESULT_VERIFY 0x8
1715 #define GT_RESULT_IMPORT 0x10
1716 #define GT_RESULT_GENKEY 0x20
1717 #define GT_RESULT_KEYLIST 0x40
1718 #define GT_RESULT_VFS_MOUNT 0x80
1719 #define GT_RESULT_ALL (~0U)
1720
1721 gpg_error_t
1722 gt_result (gpgme_tool_t gt, unsigned int flags)
1723 {
1724   int indent = 2;
1725
1726   gt_write_data (gt, xml_preamble1, sizeof (xml_preamble1));
1727   gt_write_data (gt, NULL, 0);
1728   gt_write_data (gt, xml_preamble2, sizeof (xml_preamble2));
1729   gt_write_data (gt, NULL, 0);
1730   if (flags & GT_RESULT_ENCRYPT)
1731     result_encrypt_to_xml (gt->ctx, indent,
1732                            (result_xml_write_cb_t) gt_write_data, gt);
1733   if (flags & GT_RESULT_DECRYPT)
1734     result_decrypt_to_xml (gt->ctx, indent,
1735                            (result_xml_write_cb_t) gt_write_data, gt);
1736   if (flags & GT_RESULT_SIGN)
1737     result_sign_to_xml (gt->ctx, indent,
1738                         (result_xml_write_cb_t) gt_write_data, gt);
1739   if (flags & GT_RESULT_VERIFY)
1740     result_verify_to_xml (gt->ctx, indent,
1741                           (result_xml_write_cb_t) gt_write_data, gt);
1742   if (flags & GT_RESULT_IMPORT)
1743     result_import_to_xml (gt->ctx, indent,
1744                           (result_xml_write_cb_t) gt_write_data, gt);
1745   if (flags & GT_RESULT_GENKEY)
1746     result_genkey_to_xml (gt->ctx, indent,
1747                           (result_xml_write_cb_t) gt_write_data, gt);
1748   if (flags & GT_RESULT_KEYLIST)
1749     result_keylist_to_xml (gt->ctx, indent,
1750                            (result_xml_write_cb_t) gt_write_data, gt);
1751   if (flags & GT_RESULT_VFS_MOUNT)
1752     result_vfs_mount_to_xml (gt->ctx, indent,
1753                              (result_xml_write_cb_t) gt_write_data, gt);
1754   gt_write_data (gt, xml_end, sizeof (xml_end));
1755
1756   return 0;
1757 }
1758
1759 \f
1760 /* GPGME SERVER.  */
1761
1762 #include <assuan.h>
1763
1764 struct server
1765 {
1766   gpgme_tool_t gt;
1767   assuan_context_t assuan_ctx;
1768
1769   gpgme_data_encoding_t input_enc;
1770   gpgme_data_encoding_t output_enc;
1771   assuan_fd_t input_fd;
1772   char *input_filename;
1773   FILE *input_stream;
1774   assuan_fd_t output_fd;
1775   char *output_filename;
1776   FILE *output_stream;
1777   assuan_fd_t message_fd;
1778   char *message_filename;
1779   FILE *message_stream;
1780   gpgme_data_encoding_t message_enc;
1781 };
1782
1783
1784 gpg_error_t
1785 server_write_status (void *hook, const char *status, const char *msg)
1786 {
1787   struct server *server = hook;
1788   return assuan_write_status (server->assuan_ctx, status, msg);
1789 }
1790
1791
1792 gpg_error_t
1793 server_write_data (void *hook, const void *buf, size_t len)
1794 {
1795   struct server *server = hook;
1796   return assuan_send_data (server->assuan_ctx, buf, len);
1797 }
1798
1799
1800 static gpg_error_t
1801 server_passphrase_cb (void *opaque, const char *uid_hint, const char *info,
1802                       int was_bad, int fd)
1803 {
1804   struct server *server = opaque;
1805   gpg_error_t err;
1806   unsigned char *buf = NULL;
1807   size_t buflen = 0;
1808
1809   if (server && server->assuan_ctx)
1810     {
1811       if (uid_hint)
1812         assuan_write_status (server->assuan_ctx, "USERID_HINT", uid_hint);
1813       if (info)
1814         assuan_write_status (server->assuan_ctx, "NEED_PASSPHRASE", info);
1815
1816       err = assuan_inquire (server->assuan_ctx, "PASSPHRASE",
1817                             &buf, &buflen, 100);
1818     }
1819   else
1820     err = gpg_error (GPG_ERR_NO_PASSPHRASE);
1821
1822   if (!err)
1823     {
1824       /* We take care to always send a LF.  */
1825       if (gpgme_io_writen (fd, buf, buflen))
1826         err = gpg_error_from_syserror ();
1827       else if (!memchr (buf, '\n', buflen) && gpgme_io_writen (fd, "\n", 1))
1828         err = gpg_error_from_syserror ();
1829     }
1830   free (buf);
1831   return err;
1832 }
1833
1834
1835 /* Wrapper around assuan_command_parse_fd to also handle a
1836    "file=FILENAME" argument.  On success either a filename is returned
1837    at FILENAME or a file descriptor at RFD; the other one is set to
1838    NULL respective ASSUAN_INVALID_FD.  */
1839 static gpg_error_t
1840 server_parse_fd (assuan_context_t ctx, char *line, assuan_fd_t *rfd,
1841                  char **filename)
1842 {
1843   *rfd = ASSUAN_INVALID_FD;
1844   *filename = NULL;
1845
1846   if (! strncasecmp (line, "file=", 5))
1847     {
1848       char *term;
1849       *filename = strdup (line + 5);
1850       if (!*filename)
1851         return gpg_error_from_syserror();
1852       term = strchr (*filename, ' ');
1853       if (term)
1854         *term = '\0';
1855       return 0;
1856     }
1857   else
1858     return assuan_command_parse_fd (ctx, line, rfd);
1859 }
1860
1861
1862 static gpgme_data_encoding_t
1863 server_data_encoding (const char *line)
1864 {
1865   if (strstr (line, "--binary"))
1866     return GPGME_DATA_ENCODING_BINARY;
1867   if (strstr (line, "--base64"))
1868     return GPGME_DATA_ENCODING_BASE64;
1869   if (strstr (line, "--armor"))
1870     return GPGME_DATA_ENCODING_ARMOR;
1871   if (strstr (line, "--url"))
1872     return GPGME_DATA_ENCODING_URL;
1873   if (strstr (line, "--urlesc"))
1874     return GPGME_DATA_ENCODING_URLESC;
1875   if (strstr (line, "--url0"))
1876     return GPGME_DATA_ENCODING_URL0;
1877   return GPGME_DATA_ENCODING_NONE;
1878 }
1879
1880
1881 static gpgme_error_t
1882 server_data_obj (assuan_fd_t fd, char *fn, int out,
1883                  gpgme_data_encoding_t encoding,
1884                  gpgme_data_t *data, FILE **fs)
1885 {
1886   gpgme_error_t err;
1887
1888   *fs = NULL;
1889   if (fn)
1890     {
1891       *fs = fopen (fn, out ? "wb" : "rb");
1892       if (!*fs)
1893         return gpg_error_from_syserror ();
1894
1895       err = gpgme_data_new_from_stream (data, *fs);
1896     }
1897   else
1898     err = gpgme_data_new_from_fd (data, (int) fd);
1899
1900   if (err)
1901     return err;
1902   return gpgme_data_set_encoding (*data, encoding);
1903 }
1904
1905
1906 void
1907 server_reset_fds (struct server *server)
1908 {
1909   /* assuan closes the input and output FDs for us when doing a RESET,
1910      but we use this same function after commands, so repeat it
1911      here.  */
1912   if (server->input_fd != ASSUAN_INVALID_FD)
1913     {
1914 #if HAVE_W32_SYSTEM
1915       CloseHandle (server->input_fd);
1916 #else
1917       close (server->input_fd);
1918 #endif
1919       server->input_fd = ASSUAN_INVALID_FD;
1920     }
1921   if (server->output_fd != ASSUAN_INVALID_FD)
1922     {
1923 #if HAVE_W32_SYSTEM
1924       CloseHandle (server->output_fd);
1925 #else
1926       close (server->output_fd);
1927 #endif
1928       server->output_fd = ASSUAN_INVALID_FD;
1929     }
1930   if (server->message_fd != ASSUAN_INVALID_FD)
1931     {
1932       /* FIXME: Assuan should provide a close function.  */
1933 #if HAVE_W32_SYSTEM
1934       CloseHandle (server->message_fd);
1935 #else
1936       close (server->message_fd);
1937 #endif
1938       server->message_fd = ASSUAN_INVALID_FD;
1939     }
1940   if (server->input_filename)
1941     {
1942       free (server->input_filename);
1943       server->input_filename = NULL;
1944     }
1945   if (server->output_filename)
1946     {
1947       free (server->output_filename);
1948       server->output_filename = NULL;
1949     }
1950   if (server->message_filename)
1951     {
1952       free (server->message_filename);
1953       server->message_filename = NULL;
1954     }
1955   if (server->input_stream)
1956     {
1957       fclose (server->input_stream);
1958       server->input_stream = NULL;
1959     }
1960   if (server->output_stream)
1961     {
1962       fclose (server->output_stream);
1963       server->output_stream = NULL;
1964     }
1965   if (server->message_stream)
1966     {
1967       fclose (server->message_stream);
1968       server->message_stream = NULL;
1969     }
1970
1971   server->input_enc = GPGME_DATA_ENCODING_NONE;
1972   server->output_enc = GPGME_DATA_ENCODING_NONE;
1973   server->message_enc = GPGME_DATA_ENCODING_NONE;
1974 }
1975
1976
1977 static gpg_error_t
1978 reset_notify (assuan_context_t ctx, char *line)
1979 {
1980   struct server *server = assuan_get_pointer (ctx);
1981   server_reset_fds (server);
1982   gt_reset (server->gt);
1983   return 0;
1984 }
1985
1986
1987 static const char hlp_version[] =
1988   "VERSION [<string>]\n"
1989   "\n"
1990   "Call the function gpgme_check_version.";
1991 static gpg_error_t
1992 cmd_version (assuan_context_t ctx, char *line)
1993 {
1994   if (line && *line)
1995     {
1996       const char *version = gpgme_check_version (line);
1997       return version ? 0 : gpg_error (GPG_ERR_SELFTEST_FAILED);
1998     }
1999   else
2000     {
2001       const char *version = gpgme_check_version (NULL);
2002       return assuan_send_data (ctx, version, strlen (version));
2003     }
2004 }
2005
2006
2007 static const char hlp_engine[] =
2008   "ENGINE [<string>]\n"
2009   "\n"
2010   "Get information about a GPGME engine (a.k.a. protocol).";
2011 static gpg_error_t
2012 cmd_engine (assuan_context_t ctx, char *line)
2013 {
2014   struct server *server = assuan_get_pointer (ctx);
2015   return gt_get_engine_info (server->gt, gt_protocol_from_name (line));
2016 }
2017
2018
2019 static const char hlp_protocol[] =
2020   "PROTOCOL [<name>]\n"
2021   "\n"
2022   "With NAME, set the protocol.  Without, return the current\n"
2023   "protocol.";
2024 static gpg_error_t
2025 cmd_protocol (assuan_context_t ctx, char *line)
2026 {
2027   struct server *server = assuan_get_pointer (ctx);
2028   if (line && *line)
2029     return gt_set_protocol (server->gt, gt_protocol_from_name (line));
2030   else
2031     return gt_get_protocol (server->gt);
2032 }
2033
2034
2035 static const char hlp_sub_protocol[] =
2036   "SUB_PROTOCOL [<name>]\n"
2037   "\n"
2038   "With NAME, set the sub-protocol.  Without, return the\n"
2039   "current sub-protocol.";
2040 static gpg_error_t
2041 cmd_sub_protocol (assuan_context_t ctx, char *line)
2042 {
2043   struct server *server = assuan_get_pointer (ctx);
2044   if (line && *line)
2045     return gt_set_sub_protocol (server->gt, gt_protocol_from_name (line));
2046   else
2047     return gt_get_sub_protocol (server->gt);
2048 }
2049
2050
2051 static const char hlp_pinentry_mode[] =
2052   "PINENTRY_MODE <name>\n"
2053   "\n"
2054   "Set the pinentry mode to NAME.   Allowedvalues for NAME are:\n"
2055   "  default  - reset to the default of the engine,\n"
2056   "  ask      - force the use of the pinentry,\n"
2057   "  cancel   - emulate use of pinentry's cancel button,\n"
2058   "  error    - return a pinentry error,\n"
2059   "  loopback - redirect pinentry queries to the caller.\n"
2060   "Note that only recent versions of GPG support changing the pinentry mode.";
2061 static gpg_error_t
2062 cmd_pinentry_mode (assuan_context_t ctx, char *line)
2063 {
2064   struct server *server = assuan_get_pointer (ctx);
2065   gpgme_pinentry_mode_t mode;
2066
2067   if (!line || !*line || !strcmp (line, "default"))
2068     mode = GPGME_PINENTRY_MODE_DEFAULT;
2069   else if (!strcmp (line, "ask"))
2070     mode = GPGME_PINENTRY_MODE_ASK;
2071   else if (!strcmp (line, "cancel"))
2072     mode = GPGME_PINENTRY_MODE_CANCEL;
2073   else if (!strcmp (line, "error"))
2074     mode = GPGME_PINENTRY_MODE_ERROR;
2075   else if (!strcmp (line, "loopback"))
2076     mode = GPGME_PINENTRY_MODE_LOOPBACK;
2077   else
2078     return gpg_error (GPG_ERR_INV_VALUE);
2079
2080   return gt_set_pinentry_mode (server->gt, mode, server);
2081 }
2082
2083
2084 static const char hlp_armor[] =
2085   "ARMOR [true|false]\n"
2086   "\n"
2087   "With 'true' or 'false', turn output ASCII armoring on or\n"
2088   "off.  Without, return the current armoring status.";
2089 static gpg_error_t
2090 cmd_armor (assuan_context_t ctx, char *line)
2091 {
2092   struct server *server = assuan_get_pointer (ctx);
2093   if (line && *line)
2094     {
2095       int flag = 0;
2096
2097       if (! strcasecmp (line, "true") || ! strcasecmp (line, "yes")
2098           || line[0] == '1')
2099         flag = 1;
2100
2101       return gt_set_armor (server->gt, flag);
2102     }
2103   else
2104     return gt_get_armor (server->gt);
2105 }
2106
2107
2108 static const char hlp_textmode[] =
2109   "TEXTMODE [true|false]\n"
2110   "\n"
2111   "With 'true' or 'false', turn text mode on or off.\n"
2112   "Without, return the current text mode status.";
2113 static gpg_error_t
2114 cmd_textmode (assuan_context_t ctx, char *line)
2115 {
2116   struct server *server = assuan_get_pointer (ctx);
2117   if (line && *line)
2118     {
2119       int flag = 0;
2120
2121       if (! strcasecmp (line, "true") || ! strcasecmp (line, "yes")
2122           || line[0] == '1')
2123         flag = 1;
2124
2125       return gt_set_textmode (server->gt, flag);
2126     }
2127   else
2128     return gt_get_textmode (server->gt);
2129 }
2130
2131
2132 static const char hlp_include_certs[] =
2133   "INCLUDE_CERTS [default|<n>]\n"
2134   "\n"
2135   "With DEFAULT or N, set how many certificates should be\n"
2136   "included in the next S/MIME signed message.  See the\n"
2137   "GPGME documentation for details on the meaning of"
2138   "various N.  Without either, return the current setting.";
2139 static gpg_error_t
2140 cmd_include_certs (assuan_context_t ctx, char *line)
2141 {
2142   struct server *server = assuan_get_pointer (ctx);
2143
2144   if (line && *line)
2145     {
2146       int include_certs = 0;
2147
2148       if (! strcasecmp (line, "default"))
2149         include_certs = GPGME_INCLUDE_CERTS_DEFAULT;
2150       else
2151         include_certs = atoi (line);
2152
2153       return gt_set_include_certs (server->gt, include_certs);
2154     }
2155   else
2156     return gt_get_include_certs (server->gt);
2157 }
2158
2159
2160 static const char hlp_keylist_mode[] =
2161   "KEYLIST_MODE [local] [extern] [sigs] [sig_notations]\n"
2162   "  [ephemeral] [validate]\n"
2163   "\n"
2164   "Set the mode for the next KEYLIST command.";
2165 static gpg_error_t
2166 cmd_keylist_mode (assuan_context_t ctx, char *line)
2167 {
2168   struct server *server = assuan_get_pointer (ctx);
2169
2170   if (line && *line)
2171     {
2172       gpgme_keylist_mode_t mode = 0;
2173
2174       if (strstr (line, "local"))
2175         mode |= GPGME_KEYLIST_MODE_LOCAL;
2176       if (strstr (line, "extern"))
2177         mode |= GPGME_KEYLIST_MODE_EXTERN;
2178       if (strstr (line, "sigs"))
2179         mode |= GPGME_KEYLIST_MODE_SIGS;
2180       if (strstr (line, "sig_notations"))
2181         mode |= GPGME_KEYLIST_MODE_SIG_NOTATIONS;
2182       if (strstr (line, "with_secret"))
2183         mode |= GPGME_KEYLIST_MODE_WITH_SECRET;
2184       if (strstr (line, "ephemeral"))
2185         mode |= GPGME_KEYLIST_MODE_EPHEMERAL;
2186       if (strstr (line, "validate"))
2187         mode |= GPGME_KEYLIST_MODE_VALIDATE;
2188
2189       return gt_set_keylist_mode (server->gt, mode);
2190     }
2191   else
2192     return gt_get_keylist_mode (server->gt);
2193 }
2194
2195
2196 static const char hlp_input[] =
2197   "INPUT [<fd>|FILE=<path>]\n"
2198   "\n"
2199   "Set the input for the next command.  Use either the\n"
2200   "Assuan file descriptor FD or a filesystem PATH.";
2201 static gpg_error_t
2202 cmd_input (assuan_context_t ctx, char *line)
2203 {
2204   struct server *server = assuan_get_pointer (ctx);
2205   gpg_error_t err;
2206   assuan_fd_t sysfd;
2207   char *filename;
2208
2209   err = server_parse_fd (ctx, line, &sysfd, &filename);
2210   if (err)
2211     return err;
2212   server->input_fd = sysfd;
2213   server->input_filename = filename;
2214   server->input_enc = server_data_encoding (line);
2215   return 0;
2216 }
2217
2218
2219 static const char hlp_output[] =
2220   "OUTPUT [<fd>|FILE=<path>]\n"
2221   "\n"
2222   "Set the output for the next command.  Use either the\n"
2223   "Assuan file descriptor FD or a filesystem PATH.";
2224 static gpg_error_t
2225 cmd_output (assuan_context_t ctx, char *line)
2226 {
2227   struct server *server = assuan_get_pointer (ctx);
2228   gpg_error_t err;
2229   assuan_fd_t sysfd;
2230   char *filename;
2231
2232   err = server_parse_fd (ctx, line, &sysfd, &filename);
2233   if (err)
2234     return err;
2235   server->output_fd = sysfd;
2236   server->output_filename = filename;
2237   server->output_enc = server_data_encoding (line);
2238   return 0;
2239 }
2240
2241
2242 static const char hlp_message[] =
2243   "MESSAGE [<fd>|FILE=<path>]\n"
2244   "\n"
2245   "Set the plaintext message for the next VERIFY command\n"
2246   "with a detached signature.  Use either the Assuan file\n"
2247   "descriptor FD or a filesystem PATH.";
2248 static gpg_error_t
2249 cmd_message (assuan_context_t ctx, char *line)
2250 {
2251   struct server *server = assuan_get_pointer (ctx);
2252   gpg_error_t err;
2253   assuan_fd_t sysfd;
2254   char *filename;
2255
2256   err = server_parse_fd (ctx, line, &sysfd, &filename);
2257   if (err)
2258     return err;
2259   server->message_fd = sysfd;
2260   server->message_filename = filename;
2261   server->message_enc = server_data_encoding (line);
2262   return 0;
2263 }
2264
2265
2266 static const char hlp_recipient[] =
2267   "RECIPIENT <pattern>\n"
2268   "\n"
2269   "Add the key matching PATTERN to the list of recipients\n"
2270   "for the next encryption command.";
2271 static gpg_error_t
2272 cmd_recipient (assuan_context_t ctx, char *line)
2273 {
2274   struct server *server = assuan_get_pointer (ctx);
2275
2276   return gt_recipients_add (server->gt, line);
2277 }
2278
2279
2280 static const char hlp_signer[] =
2281   "SIGNER <fingerprint>\n"
2282   "\n"
2283   "Add the key with FINGERPRINT to the list of signers to\n"
2284   "be used for the next signing command.";
2285 static gpg_error_t
2286 cmd_signer (assuan_context_t ctx, char *line)
2287 {
2288   struct server *server = assuan_get_pointer (ctx);
2289
2290   return gt_signers_add (server->gt, line);
2291 }
2292
2293
2294 static const char hlp_signers_clear[] =
2295   "SIGNERS_CLEAR\n"
2296   "\n"
2297   "Clear the list of signers specified by previous SIGNER\n"
2298   "commands.";
2299 static gpg_error_t
2300 cmd_signers_clear (assuan_context_t ctx, char *line)
2301 {
2302   struct server *server = assuan_get_pointer (ctx);
2303
2304   return gt_signers_clear (server->gt);
2305 }
2306
2307
2308 static gpg_error_t
2309 _cmd_decrypt_verify (assuan_context_t ctx, char *line, int verify)
2310 {
2311   struct server *server = assuan_get_pointer (ctx);
2312   gpg_error_t err;
2313   assuan_fd_t inp_fd;
2314   char *inp_fn;
2315   assuan_fd_t out_fd;
2316   char *out_fn;
2317   gpgme_data_t inp_data;
2318   gpgme_data_t out_data;
2319
2320   inp_fd = server->input_fd;
2321   inp_fn = server->input_filename;
2322   if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
2323     return GPG_ERR_ASS_NO_INPUT;
2324   out_fd = server->output_fd;
2325   out_fn = server->output_filename;
2326   if (out_fd == ASSUAN_INVALID_FD && !out_fn)
2327     return GPG_ERR_ASS_NO_OUTPUT;
2328
2329   err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2330                          &server->input_stream);
2331   if (err)
2332     return err;
2333   err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2334                          &server->output_stream);
2335   if (err)
2336     {
2337       gpgme_data_release (inp_data);
2338       return err;
2339     }
2340
2341   err = gt_decrypt_verify (server->gt, inp_data, out_data, verify);
2342
2343   gpgme_data_release (inp_data);
2344   gpgme_data_release (out_data);
2345
2346   server_reset_fds (server);
2347
2348   return err;
2349 }
2350
2351
2352 static const char hlp_decrypt[] =
2353   "DECRYPT\n"
2354   "\n"
2355   "Decrypt the object set by the last INPUT command and\n"
2356   "write the decrypted message to the object set by the\n"
2357   "last OUTPUT command.";
2358 static gpg_error_t
2359 cmd_decrypt (assuan_context_t ctx, char *line)
2360 {
2361   return _cmd_decrypt_verify (ctx, line, 0);
2362 }
2363
2364
2365 static const char hlp_decrypt_verify[] =
2366   "DECRYPT_VERIFY\n"
2367   "\n"
2368   "Decrypt the object set by the last INPUT command and\n"
2369   "verify any embedded signatures.  Write the decrypted\n"
2370   "message to the object set by the last OUTPUT command.";
2371 static gpg_error_t
2372 cmd_decrypt_verify (assuan_context_t ctx, char *line)
2373 {
2374   return _cmd_decrypt_verify (ctx, line, 1);
2375 }
2376
2377
2378 static gpg_error_t
2379 _cmd_sign_encrypt (assuan_context_t ctx, char *line, int sign)
2380 {
2381   struct server *server = assuan_get_pointer (ctx);
2382   gpg_error_t err;
2383   assuan_fd_t inp_fd;
2384   char *inp_fn;
2385   assuan_fd_t out_fd;
2386   char *out_fn;
2387   gpgme_data_t inp_data = NULL;
2388   gpgme_data_t out_data = NULL;
2389   gpgme_encrypt_flags_t flags = 0;
2390
2391   if (strstr (line, "--always-trust"))
2392     flags |= GPGME_ENCRYPT_ALWAYS_TRUST;
2393   if (strstr (line, "--no-encrypt-to"))
2394     flags |= GPGME_ENCRYPT_NO_ENCRYPT_TO;
2395   if (strstr (line, "--prepare"))
2396     flags |= GPGME_ENCRYPT_PREPARE;
2397   if (strstr (line, "--expect-sign"))
2398     flags |= GPGME_ENCRYPT_EXPECT_SIGN;
2399   if (strstr (line, "--no-compress"))
2400     flags |= GPGME_ENCRYPT_NO_COMPRESS;
2401
2402   inp_fd = server->input_fd;
2403   inp_fn = server->input_filename;
2404   out_fd = server->output_fd;
2405   out_fn = server->output_filename;
2406   if (inp_fd != ASSUAN_INVALID_FD || inp_fn)
2407     {
2408       err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2409                              &server->input_stream);
2410       if (err)
2411         return err;
2412     }
2413   if (out_fd != ASSUAN_INVALID_FD || out_fn)
2414     {
2415       err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2416                              &server->output_stream);
2417       if (err)
2418         {
2419           gpgme_data_release (inp_data);
2420           return err;
2421         }
2422     }
2423
2424   err = gt_sign_encrypt (server->gt, flags, inp_data, out_data, sign);
2425
2426   gpgme_data_release (inp_data);
2427   gpgme_data_release (out_data);
2428
2429   server_reset_fds (server);
2430
2431   return err;
2432 }
2433
2434
2435 static const char hlp_encrypt[] =
2436   "ENCRYPT [--always-trust] [--no-encrypt-to]\n"
2437   "  [--no-compress] [--prepare] [--expect-sign]\n"
2438   "\n"
2439   "Encrypt the object set by the last INPUT command to\n"
2440   "the keys specified by previous RECIPIENT commands.  \n"
2441   "Write the signed and encrypted message to the object\n"
2442   "set by the last OUTPUT command.";
2443 static gpg_error_t
2444 cmd_encrypt (assuan_context_t ctx, char *line)
2445 {
2446   return _cmd_sign_encrypt (ctx, line, 0);
2447 }
2448
2449
2450 static const char hlp_sign_encrypt[] =
2451   "SIGN_ENCRYPT [--always-trust] [--no-encrypt-to]\n"
2452   "  [--no-compress] [--prepare] [--expect-sign]\n"
2453   "\n"
2454   "Sign the object set by the last INPUT command with the\n"
2455   "keys specified by previous SIGNER commands and encrypt\n"
2456   "it to the keys specified by previous RECIPIENT\n"
2457   "commands.  Write the signed and encrypted message to\n"
2458   "the object set by the last OUTPUT command.";
2459 static gpg_error_t
2460 cmd_sign_encrypt (assuan_context_t ctx, char *line)
2461 {
2462   return _cmd_sign_encrypt (ctx, line, 1);
2463 }
2464
2465
2466 static const char hlp_sign[] =
2467   "SIGN [--clear|--detach]\n"
2468   "\n"
2469   "Sign the object set by the last INPUT command with the\n"
2470   "keys specified by previous SIGNER commands.  Write the\n"
2471   "signed message to the object set by the last OUTPUT\n"
2472   "command.  With `--clear`, generate a clear text\n"
2473   "signature.  With `--detach`, generate a detached\n"
2474   "signature.";
2475 static gpg_error_t
2476 cmd_sign (assuan_context_t ctx, char *line)
2477 {
2478   struct server *server = assuan_get_pointer (ctx);
2479   gpg_error_t err;
2480   assuan_fd_t inp_fd;
2481   char *inp_fn;
2482   assuan_fd_t out_fd;
2483   char *out_fn;
2484   gpgme_data_t inp_data;
2485   gpgme_data_t out_data;
2486   gpgme_sig_mode_t mode = GPGME_SIG_MODE_NORMAL;
2487
2488   if (strstr (line, "--clear"))
2489     mode = GPGME_SIG_MODE_CLEAR;
2490   if (strstr (line, "--detach"))
2491     mode = GPGME_SIG_MODE_DETACH;
2492
2493   inp_fd = server->input_fd;
2494   inp_fn = server->input_filename;
2495   if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
2496     return GPG_ERR_ASS_NO_INPUT;
2497   out_fd = server->output_fd;
2498   out_fn = server->output_filename;
2499   if (out_fd == ASSUAN_INVALID_FD && !out_fn)
2500     return GPG_ERR_ASS_NO_OUTPUT;
2501
2502   err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2503                          &server->input_stream);
2504   if (err)
2505     return err;
2506   err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2507                          &server->output_stream);
2508   if (err)
2509     {
2510       gpgme_data_release (inp_data);
2511       return err;
2512     }
2513
2514   err = gt_sign (server->gt, inp_data, out_data, mode);
2515
2516   gpgme_data_release (inp_data);
2517   gpgme_data_release (out_data);
2518   server_reset_fds (server);
2519
2520   return err;
2521 }
2522
2523
2524 static const char hlp_verify[] =
2525   "VERIFY\n"
2526   "\n"
2527   "Verify signatures on the object set by the last INPUT\n"
2528   "and MESSAGE commands.  If the message was encrypted,\n"
2529   "write the plaintext to the object set by the last\n"
2530   "OUTPUT command.";
2531 static gpg_error_t
2532 cmd_verify (assuan_context_t ctx, char *line)
2533 {
2534   struct server *server = assuan_get_pointer (ctx);
2535   gpg_error_t err;
2536   assuan_fd_t inp_fd;
2537   assuan_fd_t msg_fd;
2538   assuan_fd_t out_fd;
2539   char *inp_fn;
2540   char *msg_fn;
2541   char *out_fn;
2542   gpgme_data_t inp_data;
2543   gpgme_data_t msg_data = NULL;
2544   gpgme_data_t out_data = NULL;
2545
2546   inp_fd = server->input_fd;
2547   inp_fn = server->input_filename;
2548   if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
2549     return GPG_ERR_ASS_NO_INPUT;
2550   msg_fd = server->message_fd;
2551   msg_fn = server->message_filename;
2552   out_fd = server->output_fd;
2553   out_fn = server->output_filename;
2554
2555   err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2556                          &server->input_stream);
2557   if (err)
2558     return err;
2559   if (msg_fd != ASSUAN_INVALID_FD || msg_fn)
2560     {
2561       err = server_data_obj (msg_fd, msg_fn, 0, server->message_enc, &msg_data,
2562                              &server->message_stream);
2563       if (err)
2564         {
2565           gpgme_data_release (inp_data);
2566           return err;
2567         }
2568     }
2569   if (out_fd != ASSUAN_INVALID_FD || out_fn)
2570     {
2571       err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2572                              &server->output_stream);
2573       if (err)
2574         {
2575           gpgme_data_release (inp_data);
2576           gpgme_data_release (msg_data);
2577           return err;
2578         }
2579     }
2580
2581   err = gt_verify (server->gt, inp_data, msg_data, out_data);
2582
2583   gpgme_data_release (inp_data);
2584   if (msg_data)
2585     gpgme_data_release (msg_data);
2586   if (out_data)
2587     gpgme_data_release (out_data);
2588
2589   server_reset_fds (server);
2590
2591   return err;
2592 }
2593
2594
2595 static const char hlp_import[] =
2596   "IMPORT [<pattern>]\n"
2597   "\n"
2598   "With PATTERN, import the keys described by PATTERN.\n"
2599   "Without, read a key (or keys) from the object set by the\n"
2600   "last INPUT command.";
2601 static gpg_error_t
2602 cmd_import (assuan_context_t ctx, char *line)
2603 {
2604   struct server *server = assuan_get_pointer (ctx);
2605
2606   if (line && *line)
2607     {
2608       char *fprs[2] = { line, NULL };
2609
2610       return gt_import_keys (server->gt, fprs);
2611     }
2612   else
2613     {
2614       gpg_error_t err;
2615       assuan_fd_t inp_fd;
2616       char *inp_fn;
2617       gpgme_data_t inp_data;
2618
2619       inp_fd = server->input_fd;
2620       inp_fn = server->input_filename;
2621       if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
2622         return GPG_ERR_ASS_NO_INPUT;
2623
2624       err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2625                              &server->input_stream);
2626       if (err)
2627         return err;
2628
2629       err = gt_import (server->gt, inp_data);
2630
2631       gpgme_data_release (inp_data);
2632       server_reset_fds (server);
2633
2634       return err;
2635     }
2636 }
2637
2638
2639 static const char hlp_export[] =
2640   "EXPORT [--extern] [--minimal] [--secret [--pkcs12] [--raw]] [<pattern>]\n"
2641   "\n"
2642   "Export the keys described by PATTERN.  Write the\n"
2643   "the output to the object set by the last OUTPUT command.";
2644 static gpg_error_t
2645 cmd_export (assuan_context_t ctx, char *line)
2646 {
2647   struct server *server = assuan_get_pointer (ctx);
2648   gpg_error_t err;
2649   assuan_fd_t out_fd;
2650   char *out_fn;
2651   gpgme_data_t out_data;
2652   gpgme_export_mode_t mode = 0;
2653   const char *pattern[2];
2654
2655   out_fd = server->output_fd;
2656   out_fn = server->output_filename;
2657   if (out_fd == ASSUAN_INVALID_FD && !out_fn)
2658     return GPG_ERR_ASS_NO_OUTPUT;
2659   err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2660                          &server->output_stream);
2661   if (err)
2662     return err;
2663
2664   if (has_option (line, "--extern"))
2665     mode |= GPGME_EXPORT_MODE_EXTERN;
2666   if (has_option (line, "--minimal"))
2667     mode |= GPGME_EXPORT_MODE_MINIMAL;
2668   if (has_option (line, "--secret"))
2669     mode |= GPGME_EXPORT_MODE_SECRET;
2670   if (has_option (line, "--raw"))
2671     mode |= GPGME_EXPORT_MODE_RAW;
2672   if (has_option (line, "--pkcs12"))
2673     mode |= GPGME_EXPORT_MODE_PKCS12;
2674
2675   line = skip_options (line);
2676
2677   pattern[0] = line;
2678   pattern[1] = NULL;
2679
2680   err = gt_export (server->gt, pattern, mode, out_data);
2681
2682   gpgme_data_release (out_data);
2683   server_reset_fds (server);
2684
2685   return err;
2686 }
2687
2688
2689 static gpg_error_t
2690 _cmd_genkey_write (gpgme_data_t data, const void *buf, size_t size)
2691 {
2692   while (size > 0)
2693     {
2694       gpgme_ssize_t writen = gpgme_data_write (data, buf, size);
2695       if (writen < 0 && errno != EAGAIN)
2696         return gpg_error_from_syserror ();
2697       else if (writen > 0)
2698         {
2699           buf = (void *) (((char *) buf) + writen);
2700           size -= writen;
2701         }
2702     }
2703   return 0;
2704 }
2705
2706
2707 static gpg_error_t
2708 cmd_genkey (assuan_context_t ctx, char *line)
2709 {
2710   struct server *server = assuan_get_pointer (ctx);
2711   gpg_error_t err;
2712   assuan_fd_t inp_fd;
2713   char *inp_fn;
2714   assuan_fd_t out_fd;
2715   char *out_fn;
2716   gpgme_data_t inp_data;
2717   gpgme_data_t out_data = NULL;
2718   gpgme_data_t parms_data = NULL;
2719   const char *parms;
2720
2721   inp_fd = server->input_fd;
2722   inp_fn = server->input_filename;
2723   if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
2724     return GPG_ERR_ASS_NO_INPUT;
2725   out_fd = server->output_fd;
2726   out_fn = server->output_filename;
2727
2728   err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
2729                          &server->input_stream);
2730   if (err)
2731     return err;
2732   if (out_fd != ASSUAN_INVALID_FD || out_fn)
2733     {
2734       err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2735                              &server->output_stream);
2736       if (err)
2737         {
2738           gpgme_data_release (inp_data);
2739           return err;
2740         }
2741     }
2742
2743   /* Convert input data.  */
2744   err = gpgme_data_new (&parms_data);
2745   if (err)
2746     goto out;
2747   do
2748     {
2749       char buf[512];
2750       gpgme_ssize_t readn = gpgme_data_read (inp_data, buf, sizeof (buf));
2751       if (readn < 0)
2752         {
2753           err = gpg_error_from_syserror ();
2754           goto out;
2755         }
2756       else if (readn == 0)
2757         break;
2758
2759       err = _cmd_genkey_write (parms_data, buf, readn);
2760       if (err)
2761         goto out;
2762     }
2763   while (1);
2764   err = _cmd_genkey_write (parms_data, "", 1);
2765   if (err)
2766     goto out;
2767   parms = gpgme_data_release_and_get_mem (parms_data, NULL);
2768   parms_data = NULL;
2769   if (! parms)
2770     {
2771       err = gpg_error (GPG_ERR_GENERAL);
2772       goto out;
2773     }
2774
2775   err = gt_genkey (server->gt, parms, out_data, NULL);
2776
2777   server_reset_fds (server);
2778
2779  out:
2780   gpgme_data_release (inp_data);
2781   if (out_data)
2782     gpgme_data_release (out_data);
2783   if (parms_data)
2784     gpgme_data_release (parms_data);
2785
2786   return err;
2787 }
2788
2789
2790 static gpg_error_t
2791 cmd_delete (assuan_context_t ctx, char *line)
2792 {
2793   struct server *server = assuan_get_pointer (ctx);
2794   int allow_secret = 0;
2795   const char optstr[] = "--allow-secret";
2796
2797   if (!strncasecmp (line, optstr, strlen (optstr)))
2798     {
2799       allow_secret = 1;
2800       line += strlen (optstr);
2801       while (*line && !spacep (line))
2802         line++;
2803     }
2804   return gt_delete (server->gt, line, allow_secret);
2805 }
2806
2807
2808 static const char hlp_keylist[] =
2809   "KEYLIST [--secret-only] [<patterns>]\n"
2810   "\n"
2811   "List all certificates or only those specified by PATTERNS.  Each\n"
2812   "pattern shall be a percent-plus escaped certificate specification.";
2813 static gpg_error_t
2814 cmd_keylist (assuan_context_t ctx, char *line)
2815 {
2816 #define MAX_CMD_KEYLIST_PATTERN 20
2817   struct server *server = assuan_get_pointer (ctx);
2818   gpgme_tool_t gt = server->gt;
2819   struct result_xml_state state;
2820   gpg_error_t err;
2821   int secret_only = 0;
2822   int idx, indent=2;
2823   const char *pattern[MAX_CMD_KEYLIST_PATTERN+1];
2824   const char optstr[] = "--secret-only";
2825   char *p;
2826
2827   if (!strncasecmp (line, optstr, strlen (optstr)))
2828     {
2829       secret_only = 1;
2830       line += strlen (optstr);
2831       while (*line && !spacep (line))
2832         line++;
2833     }
2834
2835   idx = 0;
2836   for (p=line; *p; line = p)
2837     {
2838       while (*p && *p != ' ')
2839         p++;
2840       if (*p)
2841         *p++ = 0;
2842       if (*line)
2843         {
2844           if (idx+1 == DIM (pattern))
2845             return gpg_error (GPG_ERR_TOO_MANY);
2846           strcpy_escaped_plus (line, line);
2847           pattern[idx++] = line;
2848         }
2849     }
2850   pattern[idx] = NULL;
2851
2852   gt_write_data (gt, xml_preamble1, sizeof (xml_preamble1));
2853   gt_write_data (gt, NULL, 0);
2854   gt_write_data (gt, xml_preamble2, sizeof (xml_preamble2));
2855   gt_write_data (gt, NULL, 0);
2856   result_init (&state, indent, (result_xml_write_cb_t) gt_write_data, gt);
2857   result_xml_tag_start (&state, "keylist", NULL);
2858
2859   err = gt_keylist_start (server->gt, pattern, secret_only);
2860   while (! err)
2861     {
2862       gpgme_key_t key;
2863       gpgme_subkey_t subkey;
2864       gpgme_user_id_t uid;
2865
2866       err = gt_keylist_next (server->gt, &key);
2867       if (gpg_err_code (err) == GPG_ERR_EOF)
2868         {
2869           err = 0;
2870           break;
2871         }
2872       else if (! err)
2873         {
2874           result_xml_tag_start (&state, "key", NULL);
2875           result_add_value (&state, "revoked", key->revoked);
2876           result_add_value (&state, "expired", key->expired);
2877           result_add_value (&state, "disabled", key->disabled);
2878           result_add_value (&state, "invalid", key->invalid);
2879           result_add_value (&state, "can-encrypt", key->can_encrypt);
2880           result_add_value (&state, "can-sign", key->can_sign);
2881           result_add_value (&state, "can-certify", key->can_certify);
2882           result_add_value (&state, "can-authenticate", key->can_authenticate);
2883           result_add_value (&state, "is-qualified", key->is_qualified);
2884           result_add_value (&state, "secret", key->secret);
2885           result_add_protocol (&state, "protocol", key->protocol);
2886           result_xml_tag_start (&state, "issuer", NULL);
2887           result_add_string (&state, "serial", key->issuer_serial);
2888           result_add_string (&state, "name", key->issuer_name);
2889           result_xml_tag_end (&state);  /* issuer */
2890           result_add_string (&state, "chain-id", key->chain_id);
2891           result_add_validity (&state, "owner-trust", key->owner_trust);
2892           result_xml_tag_start (&state, "subkeys", NULL);
2893           subkey = key->subkeys;
2894           while (subkey) {
2895             result_xml_tag_start (&state, "subkey", NULL);
2896             /* FIXME: more data */
2897             result_add_keyid (&state, "keyid", subkey->keyid);
2898             if (subkey->fpr)
2899               result_add_fpr (&state, "fpr", subkey->fpr);
2900             result_add_value (&state, "secret", subkey->secret);
2901             result_add_value (&state, "is_cardkey", subkey->is_cardkey);
2902             if (subkey->card_number)
2903               result_add_string (&state, "card_number", subkey->card_number);
2904             if (subkey->curve)
2905               result_add_string (&state, "curve", subkey->curve);
2906             result_xml_tag_end (&state);  /* subkey */
2907             subkey = subkey->next;
2908           }
2909           result_xml_tag_end (&state);  /* subkeys */
2910           result_xml_tag_start (&state, "uids", NULL);
2911           uid = key->uids;
2912           while (uid) {
2913             result_xml_tag_start (&state, "uid", NULL);
2914             /* FIXME: more data */
2915             result_add_string (&state, "uid", uid->uid);
2916             result_add_string (&state, "name", uid->name);
2917             result_add_string (&state, "email", uid->email);
2918             result_add_string (&state, "comment", uid->comment);
2919             result_xml_tag_end (&state);  /* uid */
2920             uid = uid->next;
2921           }
2922           result_xml_tag_end (&state);  /* uids */
2923           result_xml_tag_end (&state);  /* key */
2924           gpgme_key_unref (key);
2925         }
2926     }
2927
2928   result_xml_tag_end (&state);  /* keylist */
2929   gt_write_data (gt, xml_end, sizeof (xml_end));
2930
2931   server_reset_fds (server);
2932
2933   return err;
2934 }
2935
2936
2937 static const char hlp_getauditlog[] =
2938   "GETAUDITLOG [--html] [--with-help]\n"
2939   "\n"
2940   "Call the function gpgme_op_getauditlog with the given flags.  Write\n"
2941   "the output to the object set by the last OUTPUT command.";
2942 static gpg_error_t
2943 cmd_getauditlog (assuan_context_t ctx, char *line)
2944 {
2945   struct server *server = assuan_get_pointer (ctx);
2946   gpg_error_t err;
2947   assuan_fd_t out_fd;
2948   char *out_fn;
2949   gpgme_data_t out_data;
2950   unsigned int flags = 0;
2951
2952   out_fd = server->output_fd;
2953   out_fn = server->output_filename;
2954   if (out_fd == ASSUAN_INVALID_FD && !out_fn)
2955     return GPG_ERR_ASS_NO_OUTPUT;
2956   err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
2957                          &server->output_stream);
2958   if (err)
2959     return err;
2960
2961   if (strstr (line, "--html"))
2962     flags |= GPGME_AUDITLOG_HTML;
2963   if (strstr (line, "--with-help"))
2964     flags |= GPGME_AUDITLOG_WITH_HELP;
2965
2966   err = gt_getauditlog (server->gt, out_data, flags);
2967
2968   gpgme_data_release (out_data);
2969   server_reset_fds (server);
2970
2971   return err;
2972 }
2973
2974
2975 static gpg_error_t
2976 cmd_vfs_mount (assuan_context_t ctx, char *line)
2977 {
2978   struct server *server = assuan_get_pointer (ctx);
2979   char *mount_dir;
2980   gpg_error_t err;
2981
2982   mount_dir = strchr (line, ' ');
2983   if (mount_dir)
2984     {
2985       *(mount_dir++) = '\0';
2986       while (*mount_dir == ' ')
2987         mount_dir++;
2988     }
2989
2990   err = gt_vfs_mount (server->gt, line, mount_dir, 0);
2991
2992   return err;
2993 }
2994
2995
2996 static gpg_error_t
2997 cmd_vfs_create (assuan_context_t ctx, char *line)
2998 {
2999   struct server *server = assuan_get_pointer (ctx);
3000   gpg_error_t err;
3001   char *end;
3002
3003   end = strchr (line, ' ');
3004   if (end)
3005     {
3006       *(end++) = '\0';
3007       while (*end == ' ')
3008         end++;
3009     }
3010
3011   err = gt_vfs_create (server->gt, line, 0);
3012
3013   return err;
3014 }
3015
3016
3017 static const char hlp_passwd[] =
3018   "PASSWD <user-id>\n"
3019   "\n"
3020   "Ask the backend to change the passphrase for the key\n"
3021   "specified by USER-ID.";
3022 static gpg_error_t
3023 cmd_passwd (assuan_context_t ctx, char *line)
3024 {
3025   struct server *server = assuan_get_pointer (ctx);
3026
3027   return gt_passwd (server->gt, line);
3028 }
3029
3030
3031
3032 static gpg_error_t
3033 cmd_result (assuan_context_t ctx, char *line)
3034 {
3035   struct server *server = assuan_get_pointer (ctx);
3036   return gt_result (server->gt, GT_RESULT_ALL);
3037 }
3038
3039
3040 /* STRERROR <err>  */
3041 static gpg_error_t
3042 cmd_strerror (assuan_context_t ctx, char *line)
3043 {
3044   gpg_error_t err;
3045   char buf[100];
3046
3047   err = atoi (line);
3048   snprintf (buf, sizeof (buf), "%s <%s>", gpgme_strerror (err),
3049             gpgme_strsource (err));
3050   return assuan_send_data (ctx, buf, strlen (buf));
3051 }
3052
3053
3054 static gpg_error_t
3055 cmd_pubkey_algo_name (assuan_context_t ctx, char *line)
3056 {
3057   gpgme_pubkey_algo_t algo;
3058   char buf[100];
3059
3060   algo = atoi (line);
3061   snprintf (buf, sizeof (buf), "%s", gpgme_pubkey_algo_name (algo));
3062   return assuan_send_data (ctx, buf, strlen (buf));
3063 }
3064
3065
3066 static gpg_error_t
3067 cmd_hash_algo_name (assuan_context_t ctx, char *line)
3068 {
3069   gpgme_hash_algo_t algo;
3070   char buf[100];
3071
3072   algo = atoi (line);
3073   snprintf (buf, sizeof (buf), "%s", gpgme_hash_algo_name (algo));
3074   return assuan_send_data (ctx, buf, strlen (buf));
3075 }
3076
3077
3078 static const char hlp_identify[] =
3079   "IDENTIY\n"
3080   "\n"
3081   "Identify the type of data set with the INPUT command.";
3082 static gpg_error_t
3083 cmd_identify (assuan_context_t ctx, char *line)
3084 {
3085   struct server *server = assuan_get_pointer (ctx);
3086   gpg_error_t err;
3087   assuan_fd_t inp_fd;
3088   char *inp_fn;
3089   gpgme_data_t inp_data;
3090
3091   inp_fd = server->input_fd;
3092   inp_fn = server->input_filename;
3093   if (inp_fd == ASSUAN_INVALID_FD && !inp_fn)
3094     return GPG_ERR_ASS_NO_INPUT;
3095
3096   err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
3097                          &server->input_stream);
3098   if (err)
3099     return err;
3100
3101   err = gt_identify (server->gt, inp_data);
3102
3103   gpgme_data_release (inp_data);
3104   server_reset_fds (server);
3105
3106   return err;
3107 }
3108
3109
3110 static const char hlp_spawn[] =
3111   "SPAWN PGM [args]\n"
3112   "\n"
3113   "Run program PGM with stdin connected to the INPUT source;\n"
3114   "stdout and stderr to the OUTPUT source.";
3115 static gpg_error_t
3116 cmd_spawn (assuan_context_t ctx, char *line)
3117 {
3118   struct server *server = assuan_get_pointer (ctx);
3119   gpg_error_t err;
3120   assuan_fd_t inp_fd;
3121   char *inp_fn;
3122   assuan_fd_t out_fd;
3123   char *out_fn;
3124   gpgme_data_t inp_data = NULL;
3125   gpgme_data_t out_data = NULL;
3126
3127   inp_fd = server->input_fd;
3128   inp_fn = server->input_filename;
3129   out_fd = server->output_fd;
3130   out_fn = server->output_filename;
3131   if (inp_fd != ASSUAN_INVALID_FD || inp_fn)
3132     {
3133       err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
3134                              &server->input_stream);
3135       if (err)
3136         return err;
3137     }
3138   if (out_fd != ASSUAN_INVALID_FD || out_fn)
3139     {
3140       err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
3141                              &server->output_stream);
3142       if (err)
3143         {
3144           gpgme_data_release (inp_data);
3145           return err;
3146         }
3147     }
3148
3149   err = gt_spawn (server->gt, line, inp_data, out_data);
3150
3151   gpgme_data_release (inp_data);
3152   gpgme_data_release (out_data);
3153
3154   server_reset_fds (server);
3155
3156   return err;
3157 }
3158
3159
3160 /* Tell the assuan library about our commands.  */
3161 static gpg_error_t
3162 register_commands (assuan_context_t ctx)
3163 {
3164   gpg_error_t err;
3165   static struct {
3166     const char *name;
3167     assuan_handler_t handler;
3168     const char * const help;
3169   } table[] = {
3170     /* RESET, BYE are implicit.  */
3171     { "VERSION", cmd_version, hlp_version },
3172     /* TODO: Set engine info.  */
3173     { "ENGINE", cmd_engine, hlp_engine },
3174     { "PROTOCOL", cmd_protocol, hlp_protocol },
3175     { "SUB_PROTOCOL", cmd_sub_protocol, hlp_sub_protocol },
3176     { "PINENTRY_MODE", cmd_pinentry_mode, hlp_pinentry_mode },
3177     { "ARMOR", cmd_armor, hlp_armor },
3178     { "TEXTMODE", cmd_textmode, hlp_textmode },
3179     { "INCLUDE_CERTS", cmd_include_certs, hlp_include_certs },
3180     { "KEYLIST_MODE", cmd_keylist_mode, hlp_keylist_mode },
3181     { "INPUT", cmd_input, hlp_input },
3182     { "OUTPUT", cmd_output, hlp_output },
3183     { "MESSAGE", cmd_message, hlp_message },
3184     { "RECIPIENT", cmd_recipient, hlp_recipient },
3185     { "SIGNER", cmd_signer, hlp_signer },
3186     { "SIGNERS_CLEAR", cmd_signers_clear, hlp_signers_clear },
3187      /* TODO: SIGNOTATION missing. */
3188      /* TODO: Could add wait interface if we allow more than one context */
3189      /* and add _START variants. */
3190      /* TODO: Could add data interfaces if we allow multiple data objects. */
3191     { "DECRYPT", cmd_decrypt, hlp_decrypt },
3192     { "DECRYPT_VERIFY", cmd_decrypt_verify, hlp_decrypt_verify },
3193     { "ENCRYPT", cmd_encrypt, hlp_encrypt },
3194     { "ENCRYPT_SIGN", cmd_sign_encrypt, hlp_sign_encrypt },
3195     { "SIGN_ENCRYPT", cmd_sign_encrypt, hlp_sign_encrypt },
3196     { "SIGN", cmd_sign, hlp_sign },
3197     { "VERIFY", cmd_verify, hlp_verify },
3198     { "IMPORT", cmd_import, hlp_import },
3199     { "EXPORT", cmd_export, hlp_export },
3200     { "GENKEY", cmd_genkey },
3201     { "DELETE", cmd_delete },
3202     /* TODO: EDIT, CARD_EDIT (with INQUIRE) */
3203     { "KEYLIST", cmd_keylist, hlp_keylist },
3204     { "LISTKEYS", cmd_keylist, hlp_keylist },
3205     /* TODO: TRUSTLIST, TRUSTLIST_EXT */
3206     { "GETAUDITLOG", cmd_getauditlog, hlp_getauditlog },
3207     /* TODO: ASSUAN */
3208     { "VFS_MOUNT", cmd_vfs_mount },
3209     { "MOUNT", cmd_vfs_mount },
3210     { "VFS_CREATE", cmd_vfs_create },
3211     { "CREATE", cmd_vfs_create },
3212     /* TODO: GPGCONF  */
3213     { "RESULT", cmd_result },
3214     { "STRERROR", cmd_strerror },
3215     { "PUBKEY_ALGO_NAME", cmd_pubkey_algo_name },
3216     { "HASH_ALGO_NAME", cmd_hash_algo_name },
3217     { "PASSWD", cmd_passwd, hlp_passwd },
3218     { "IDENTIFY", cmd_identify, hlp_identify },
3219     { "SPAWN", cmd_spawn, hlp_spawn },
3220     { NULL }
3221   };
3222   int idx;
3223
3224   for (idx = 0; table[idx].name; idx++)
3225     {
3226       err = assuan_register_command (ctx, table[idx].name, table[idx].handler,
3227                                      table[idx].help);
3228       if (err)
3229         return err;
3230     }
3231   return 0;
3232 }
3233
3234
3235 void
3236 gpgme_server (gpgme_tool_t gt)
3237 {
3238   gpg_error_t err;
3239   assuan_fd_t filedes[2];
3240   struct server server;
3241   static const char hello[] = ("GPGME-Tool " VERSION " ready");
3242
3243   memset (&server, 0, sizeof (server));
3244   server.input_fd = ASSUAN_INVALID_FD;
3245   server.output_fd = ASSUAN_INVALID_FD;
3246   server.message_fd = ASSUAN_INVALID_FD;
3247   server.input_enc = GPGME_DATA_ENCODING_NONE;
3248   server.output_enc = GPGME_DATA_ENCODING_NONE;
3249   server.message_enc = GPGME_DATA_ENCODING_NONE;
3250
3251   server.gt = gt;
3252   gt->write_status = server_write_status;
3253   gt->write_status_hook = &server;
3254   gt->write_data = server_write_data;
3255   gt->write_data_hook = &server;
3256
3257   /* We use a pipe based server so that we can work from scripts.
3258      assuan_init_pipe_server will automagically detect when we are
3259      called with a socketpair and ignore FIELDES in this case. */
3260 #ifdef HAVE_W32CE_SYSTEM
3261   filedes[0] = ASSUAN_STDIN;
3262   filedes[1] = ASSUAN_STDOUT;
3263 #else
3264   filedes[0] = assuan_fdopen (0);
3265   filedes[1] = assuan_fdopen (1);
3266 #endif
3267   err = assuan_new (&server.assuan_ctx);
3268   if (err)
3269     log_error (1, err, "can't create assuan context");
3270
3271   assuan_set_pointer (server.assuan_ctx, &server);
3272
3273   err = assuan_init_pipe_server (server.assuan_ctx, filedes);
3274   if (err)
3275     log_error (1, err, "can't initialize assuan server");
3276   err = register_commands (server.assuan_ctx);
3277   if (err)
3278     log_error (1, err, "can't register assuan commands");
3279   assuan_set_hello_line (server.assuan_ctx, hello);
3280
3281   assuan_register_reset_notify (server.assuan_ctx, reset_notify);
3282
3283 #define DBG_ASSUAN 0
3284   if (DBG_ASSUAN)
3285     assuan_set_log_stream (server.assuan_ctx, log_stream);
3286
3287   for (;;)
3288     {
3289       err = assuan_accept (server.assuan_ctx);
3290       if (err == -1)
3291         break;
3292       else if (err)
3293         {
3294           log_error (0, err, "assuan accept problem");
3295           break;
3296         }
3297
3298       err = assuan_process (server.assuan_ctx);
3299       if (err)
3300         log_error (0, err, "assuan processing failed");
3301     }
3302
3303   assuan_release (server.assuan_ctx);
3304 }
3305
3306
3307 \f
3308 static const char *
3309 my_strusage( int level )
3310 {
3311   const char *p;
3312
3313   switch (level)
3314     {
3315     case 11: p = "gpgme-tool"; break;
3316     case 13: p = PACKAGE_VERSION; break;
3317     case 14: p = "Copyright (C) 2015 g10 Code GmbH"; break;
3318     case 19: p = "Please report bugs to <" PACKAGE_BUGREPORT ">.\n"; break;
3319     case 1:
3320     case 40:
3321       p = "Usage: gpgme-tool [OPTIONS] [COMMANDS]";
3322       break;
3323     case 41:
3324       p = "GPGME Tool -- Assuan server exposing GPGME operations\n";
3325       break;
3326     case 42:
3327       p = "1"; /* Flag print 40 as part of 41. */
3328       break;
3329     default: p = NULL; break;
3330     }
3331   return p;
3332 }
3333
3334
3335 int
3336 main (int argc, char *argv[])
3337 {
3338   static ARGPARSE_OPTS opts[] = {
3339     ARGPARSE_c  ('s', "server",      "Server mode"),
3340     ARGPARSE_s_s(501, "gpg-binary",  "|FILE|Use FILE for the GPG backend"),
3341     ARGPARSE_c  (502, "lib-version", "Show library version"),
3342     ARGPARSE_end()
3343   };
3344   ARGPARSE_ARGS pargs = { &argc, &argv, 0 };
3345   enum { CMD_DEFAULT, CMD_SERVER, CMD_LIBVERSION } cmd = CMD_DEFAULT;
3346   const char *gpg_binary = NULL;
3347   struct gpgme_tool gt;
3348   gpg_error_t err;
3349   int needgt = 1;
3350
3351   set_strusage (my_strusage);
3352
3353 #ifdef HAVE_SETLOCALE
3354   setlocale (LC_ALL, "");
3355 #endif
3356   gpgme_check_version (NULL);
3357 #ifdef LC_CTYPE
3358   gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
3359 #endif
3360 #ifdef LC_MESSAGES
3361   gpgme_set_locale (NULL, LC_MESSAGES, setlocale (LC_MESSAGES, NULL));
3362 #endif
3363
3364   log_init ();
3365
3366   while (arg_parse  (&pargs, opts))
3367     {
3368       switch (pargs.r_opt)
3369         {
3370         case 's': cmd = CMD_SERVER; break;
3371         case 501: gpg_binary = pargs.r.ret_str; break;
3372         case 502: cmd = CMD_LIBVERSION; break;
3373         default:
3374           pargs.err = ARGPARSE_PRINT_WARNING;
3375           break;
3376         }
3377     }
3378
3379   if (cmd == CMD_LIBVERSION)
3380     needgt = 0;
3381
3382   if (needgt && gpg_binary)
3383     {
3384       if (access (gpg_binary, X_OK))
3385         err = gpg_error_from_syserror ();
3386       else
3387         err = gpgme_set_engine_info (GPGME_PROTOCOL_OpenPGP,
3388                                      gpg_binary, NULL);
3389       if (err)
3390         log_error (1, err, "error witching OpenPGP engine to '%s'",
3391                    gpg_binary);
3392     }
3393
3394   if (needgt)
3395     gt_init (&gt);
3396
3397   switch (cmd)
3398     {
3399     case CMD_DEFAULT:
3400     case CMD_SERVER:
3401       gpgme_server (&gt);
3402       break;
3403
3404     case CMD_LIBVERSION:
3405       printf ("Version from header: %s (0x%06x)\n",
3406               GPGME_VERSION, GPGME_VERSION_NUMBER);
3407       printf ("Version from binary: %s\n", gpgme_check_version (NULL));
3408       printf ("Copyright blurb ...:%s\n", gpgme_check_version ("\x01\x01"));
3409       break;
3410     }
3411
3412   if (needgt)
3413     gpgme_release (gt.ctx);
3414
3415 #ifdef HAVE_W32CE_SYSTEM
3416   /* Give the buggy ssh server time to flush the output buffers.  */
3417   Sleep (300);
3418 #endif
3419
3420   return 0;
3421 }