json: Fix memleak in native msging repl
[gpgme.git] / src / gpgme-json.c
1 /* gpgme-json.c - JSON based interface to gpgme (server)
2  * Copyright (C) 2018 g10 Code GmbH
3  *
4  * This file is part of GPGME.
5  *
6  * GPGME is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * GPGME is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
18  * SPDX-License-Identifier: LGPL-2.1+
19  */
20
21 /* This is tool implements the Native Messaging protocol of web
22  * browsers and provides the server part of it.  A Javascript based
23  * client can be found in lang/javascript.
24  */
25
26 #include <config.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <stdarg.h>
31 #ifdef HAVE_LOCALE_H
32 #include <locale.h>
33 #endif
34 #include <stdint.h>
35 #include <sys/stat.h>
36
37 #define GPGRT_ENABLE_ES_MACROS 1
38 #define GPGRT_ENABLE_LOG_MACROS 1
39 #define GPGRT_ENABLE_ARGPARSE_MACROS 1
40 #include "gpgme.h"
41 #include "cJSON.h"
42
43
44 #if GPGRT_VERSION_NUMBER < 0x011c00 /* 1.28 */
45 int main (void){fputs ("Build with Libgpg-error >= 1.28!\n", stderr);return 1;}
46 #else /* libgpg-error >= 1.28 */
47
48 /* We don't allow a request with more than 64 MiB.  */
49 #define MAX_REQUEST_SIZE (64 * 1024 * 1024)
50
51 /* Minimal chunk size for returned data.*/
52 #define MIN_REPLY_CHUNK_SIZE  30
53
54 /* If no chunksize is provided we print everything.  Changing
55  * this to a positive value will result in all messages beeing
56  * chunked. */
57 #define DEF_REPLY_CHUNK_SIZE  0
58 #define MAX_REPLY_CHUNK_SIZE (10 * 1024 * 1024)
59
60
61 static void xoutofcore (const char *type) GPGRT_ATTR_NORETURN;
62 static cjson_t error_object_v (cjson_t json, const char *message,
63                                va_list arg_ptr, gpg_error_t err)
64                                GPGRT_ATTR_PRINTF(2,0);
65 static cjson_t error_object (cjson_t json, const char *message,
66                             ...) GPGRT_ATTR_PRINTF(2,3);
67 static char *error_object_string (const char *message,
68                                   ...) GPGRT_ATTR_PRINTF(1,2);
69 static char *process_request (const char *request);
70
71
72 /* True if interactive mode is active.  */
73 static int opt_interactive;
74 /* True is debug mode is active.  */
75 static int opt_debug;
76
77 /* Pending data to be returned by a getmore command.  */
78 static struct
79 {
80   char  *buffer;   /* Malloced data or NULL if not used.  */
81   size_t length;   /* Length of that data.  */
82   size_t written;  /* # of already written bytes from BUFFER.  */
83 } pending_data;
84
85
86 /*
87  * Helper functions and macros
88  */
89
90 #define xtrymalloc(a)  gpgrt_malloc ((a))
91 #define xtrystrdup(a)  gpgrt_strdup ((a))
92 #define xmalloc(a) ({                           \
93       void *_r = gpgrt_malloc ((a));            \
94       if (!_r)                                  \
95         xoutofcore ("malloc");                  \
96       _r; })
97 #define xcalloc(a,b) ({                         \
98       void *_r = gpgrt_calloc ((a), (b));       \
99       if (!_r)                                  \
100         xoutofcore ("calloc");                  \
101       _r; })
102 #define xstrdup(a) ({                           \
103       char *_r = gpgrt_strdup ((a));            \
104       if (!_r)                                  \
105         xoutofcore ("strdup");                  \
106       _r; })
107 #define xstrconcat(a, ...) ({                           \
108       char *_r = gpgrt_strconcat ((a), __VA_ARGS__);    \
109       if (!_r)                                          \
110         xoutofcore ("strconcat");                       \
111       _r; })
112 #define xfree(a) gpgrt_free ((a))
113
114 #define spacep(p)   (*(p) == ' ' || *(p) == '\t')
115
116 #ifndef HAVE_STPCPY
117 static GPGRT_INLINE char *
118 _my_stpcpy (char *a, const char *b)
119 {
120   while (*b)
121     *a++ = *b++;
122   *a = 0;
123   return a;
124 }
125 #define stpcpy(a,b) _my_stpcpy ((a), (b))
126 #endif /*!HAVE_STPCPY*/
127
128
129 /* Free a NULL terminated array */
130 static void
131 xfree_array (char **array)
132 {
133   if (array)
134     {
135       int idx;
136       for (idx = 0; array[idx]; idx++)
137         xfree (array[idx]);
138       xfree (array);
139     }
140 }
141
142
143 static void
144 xoutofcore (const char *type)
145 {
146   gpg_error_t err = gpg_error_from_syserror ();
147   log_error ("%s failed: %s\n", type, gpg_strerror (err));
148   exit (2);
149 }
150
151
152 /* Call cJSON_CreateObject but terminate in case of an error.  */
153 static cjson_t
154 xjson_CreateObject (void)
155 {
156   cjson_t json = cJSON_CreateObject ();
157   if (!json)
158     xoutofcore ("cJSON_CreateObject");
159   return json;
160 }
161
162 /* Call cJSON_CreateArray but terminate in case of an error.  */
163 static cjson_t
164 xjson_CreateArray (void)
165 {
166   cjson_t json = cJSON_CreateArray ();
167   if (!json)
168     xoutofcore ("cJSON_CreateArray");
169   return json;
170 }
171
172
173 /* Wrapper around cJSON_AddStringToObject which returns an gpg-error
174  * code instead of the NULL or the new object.  */
175 static gpg_error_t
176 cjson_AddStringToObject (cjson_t object, const char *name, const char *string)
177 {
178   if (!cJSON_AddStringToObject (object, name, string))
179     return gpg_error_from_syserror ();
180   return 0;
181 }
182
183
184 /* Same as cjson_AddStringToObject but prints an error message and
185  * terminates the process.  */
186 static void
187 xjson_AddStringToObject (cjson_t object, const char *name, const char *string)
188 {
189   if (!cJSON_AddStringToObject (object, name, string))
190     xoutofcore ("cJSON_AddStringToObject");
191 }
192
193
194 /* Same as xjson_AddStringToObject but ignores NULL strings */
195 static void
196 xjson_AddStringToObject0 (cjson_t object, const char *name, const char *string)
197 {
198   if (!string)
199     return;
200   xjson_AddStringToObject (object, name, string);
201 }
202
203 /* Wrapper around cJSON_AddBoolToObject which terminates the process
204  * in case of an error.  */
205 static void
206 xjson_AddBoolToObject (cjson_t object, const char *name, int abool)
207 {
208   if (!cJSON_AddBoolToObject (object, name, abool))
209     xoutofcore ("cJSON_AddStringToObject");
210   return ;
211 }
212
213 /* Wrapper around cJSON_AddNumberToObject which terminates the process
214  * in case of an error.  */
215 static void
216 xjson_AddNumberToObject (cjson_t object, const char *name, double dbl)
217 {
218   if (!cJSON_AddNumberToObject (object, name, dbl))
219     xoutofcore ("cJSON_AddNumberToObject");
220   return ;
221 }
222
223 /* Wrapper around cJSON_AddItemToObject which terminates the process
224  * in case of an error.  */
225 static void
226 xjson_AddItemToObject (cjson_t object, const char *name, cjson_t item)
227 {
228   if (!cJSON_AddItemToObject (object, name, item))
229     xoutofcore ("cJSON_AddItemToObject");
230   return ;
231 }
232
233 /* This is similar to cJSON_AddStringToObject but takes (DATA,
234  * DATALEN) and adds it under NAME as a base 64 encoded string to
235  * OBJECT.  */
236 static gpg_error_t
237 add_base64_to_object (cjson_t object, const char *name,
238                       const void *data, size_t datalen)
239 {
240 #if GPGRT_VERSION_NUMBER < 0x011d00 /* 1.29 */
241   return gpg_error (GPG_ERR_NOT_SUPPORTED);
242 #else
243   gpg_err_code_t err;
244   estream_t fp = NULL;
245   gpgrt_b64state_t state = NULL;
246   cjson_t j_str = NULL;
247   void *buffer = NULL;
248
249   fp = es_fopenmem (0, "rwb");
250   if (!fp)
251     {
252       err = gpg_err_code_from_syserror ();
253       goto leave;
254     }
255   state = gpgrt_b64enc_start (fp, "");
256   if (!state)
257     {
258       err = gpg_err_code_from_syserror ();
259       goto leave;
260     }
261
262   err = gpgrt_b64enc_write (state, data, datalen);
263   if (err)
264     goto leave;
265
266   err = gpgrt_b64enc_finish (state);
267   state = NULL;
268   if (err)
269     return err;
270
271   es_fputc (0, fp);
272   if (es_fclose_snatch (fp, &buffer, NULL))
273     {
274       fp = NULL;
275       err = gpg_error_from_syserror ();
276       goto leave;
277     }
278   fp = NULL;
279
280   j_str = cJSON_CreateStringConvey (buffer);
281   if (!j_str)
282     {
283       err = gpg_error_from_syserror ();
284       goto leave;
285     }
286   buffer = NULL;
287
288   if (!cJSON_AddItemToObject (object, name, j_str))
289     {
290       err = gpg_error_from_syserror ();
291       cJSON_Delete (j_str);
292       j_str = NULL;
293       goto leave;
294     }
295   j_str = NULL;
296
297  leave:
298   xfree (buffer);
299   cJSON_Delete (j_str);
300   gpgrt_b64enc_finish (state);
301   es_fclose (fp);
302   return err;
303 #endif
304 }
305
306
307 /* Create a JSON error object.  If JSON is not NULL the error message
308  * is appended to that object.  An existing "type" item will be replaced. */
309 static cjson_t
310 error_object_v (cjson_t json, const char *message, va_list arg_ptr,
311                 gpg_error_t err)
312 {
313   cjson_t response, j_tmp;
314   char *msg;
315
316   msg = gpgrt_vbsprintf (message, arg_ptr);
317   if (!msg)
318     xoutofcore ("error_object");
319
320   response = json? json : xjson_CreateObject ();
321
322   if (!(j_tmp = cJSON_GetObjectItem (response, "type")))
323     xjson_AddStringToObject (response, "type", "error");
324   else /* Replace existing "type".  */
325     {
326       j_tmp = cJSON_CreateString ("error");
327       if (!j_tmp)
328         xoutofcore ("cJSON_CreateString");
329       cJSON_ReplaceItemInObject (response, "type", j_tmp);
330      }
331   xjson_AddStringToObject (response, "msg", msg);
332   xfree (msg);
333
334   xjson_AddNumberToObject (response, "code", err);
335
336   return response;
337 }
338
339
340 /* Call cJSON_Print but terminate in case of an error.  */
341 static char *
342 xjson_Print (cjson_t object)
343 {
344   char *buf;
345   buf = cJSON_Print (object);
346   if (!buf)
347     xoutofcore ("cJSON_Print");
348   return buf;
349 }
350
351
352 static cjson_t
353 error_object (cjson_t json, const char *message, ...)
354 {
355   cjson_t response;
356   va_list arg_ptr;
357
358   va_start (arg_ptr, message);
359   response = error_object_v (json, message, arg_ptr, 0);
360   va_end (arg_ptr);
361   return response;
362 }
363
364
365 static cjson_t
366 gpg_error_object (cjson_t json, gpg_error_t err, const char *message, ...)
367 {
368   cjson_t response;
369   va_list arg_ptr;
370
371   va_start (arg_ptr, message);
372   response = error_object_v (json, message, arg_ptr, err);
373   va_end (arg_ptr);
374   return response;
375 }
376
377
378 static char *
379 error_object_string (const char *message, ...)
380 {
381   cjson_t response;
382   va_list arg_ptr;
383   char *msg;
384
385   va_start (arg_ptr, message);
386   response = error_object_v (NULL, message, arg_ptr, 0);
387   va_end (arg_ptr);
388
389   msg = xjson_Print (response);
390   cJSON_Delete (response);
391   return msg;
392 }
393
394
395 /* Get the boolean property NAME from the JSON object and store true
396  * or valse at R_VALUE.  If the name is unknown the value of DEF_VALUE
397  * is returned.  If the type of the value is not boolean,
398  * GPG_ERR_INV_VALUE is returned and R_VALUE set to DEF_VALUE.  */
399 static gpg_error_t
400 get_boolean_flag (cjson_t json, const char *name, int def_value, int *r_value)
401 {
402   cjson_t j_item;
403
404   j_item = cJSON_GetObjectItem (json, name);
405   if (!j_item)
406     *r_value = def_value;
407   else if (cjson_is_true (j_item))
408     *r_value = 1;
409   else if (cjson_is_false (j_item))
410     *r_value = 0;
411   else
412     {
413       *r_value = def_value;
414       return gpg_error (GPG_ERR_INV_VALUE);
415     }
416
417   return 0;
418 }
419
420
421 /* Get the boolean property PROTOCOL from the JSON object and store
422  * its value at R_PROTOCOL.  The default is OpenPGP.  */
423 static gpg_error_t
424 get_protocol (cjson_t json, gpgme_protocol_t *r_protocol)
425 {
426   cjson_t j_item;
427
428   *r_protocol = GPGME_PROTOCOL_OpenPGP;
429   j_item = cJSON_GetObjectItem (json, "protocol");
430   if (!j_item)
431     ;
432   else if (!cjson_is_string (j_item))
433     return gpg_error (GPG_ERR_INV_VALUE);
434   else if (!strcmp(j_item->valuestring, "openpgp"))
435     ;
436   else if (!strcmp(j_item->valuestring, "cms"))
437     *r_protocol = GPGME_PROTOCOL_CMS;
438   else
439     return gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
440
441   return 0;
442 }
443
444
445 /* Get the chunksize from JSON and store it at R_CHUNKSIZE.  */
446 static gpg_error_t
447 get_chunksize (cjson_t json, size_t *r_chunksize)
448 {
449   cjson_t j_item;
450
451   *r_chunksize = DEF_REPLY_CHUNK_SIZE;
452   j_item = cJSON_GetObjectItem (json, "chunksize");
453   if (!j_item)
454     ;
455   else if (!cjson_is_number (j_item))
456     return gpg_error (GPG_ERR_INV_VALUE);
457   else if ((size_t)j_item->valueint < MIN_REPLY_CHUNK_SIZE)
458     *r_chunksize = MIN_REPLY_CHUNK_SIZE;
459   else if ((size_t)j_item->valueint > MAX_REPLY_CHUNK_SIZE)
460     *r_chunksize = MAX_REPLY_CHUNK_SIZE;
461   else
462     *r_chunksize = (size_t)j_item->valueint;
463
464   return 0;
465 }
466
467
468 /* Extract the keys from the array or string with the name "name"
469  * in the JSON object.  On success a string with the keys identifiers
470  * is stored at R_KEYS.
471  * The keys in that string are LF delimited.  On failure an error code
472  * is returned.  */
473 static gpg_error_t
474 get_keys (cjson_t json, const char *name, char **r_keystring)
475 {
476   cjson_t j_keys, j_item;
477   int i, nkeys;
478   char *p;
479   size_t length;
480
481   *r_keystring = NULL;
482
483   j_keys = cJSON_GetObjectItem (json, name);
484   if (!j_keys)
485     return gpg_error (GPG_ERR_NO_KEY);
486   if (!cjson_is_array (j_keys) && !cjson_is_string (j_keys))
487     return gpg_error (GPG_ERR_INV_VALUE);
488
489   /* Fixme: We should better use a membuf like thing.  */
490   length = 1; /* For the EOS.  */
491   if (cjson_is_string (j_keys))
492     {
493       nkeys = 1;
494       length += strlen (j_keys->valuestring);
495       if (strchr (j_keys->valuestring, '\n'))
496         return gpg_error (GPG_ERR_INV_USER_ID);
497     }
498   else
499     {
500       nkeys = cJSON_GetArraySize (j_keys);
501       if (!nkeys)
502         return gpg_error (GPG_ERR_NO_KEY);
503       for (i=0; i < nkeys; i++)
504         {
505           j_item = cJSON_GetArrayItem (j_keys, i);
506           if (!j_item || !cjson_is_string (j_item))
507             return gpg_error (GPG_ERR_INV_VALUE);
508           if (i)
509             length++; /* Space for delimiter. */
510           length += strlen (j_item->valuestring);
511           if (strchr (j_item->valuestring, '\n'))
512             return gpg_error (GPG_ERR_INV_USER_ID);
513         }
514     }
515
516   p = *r_keystring = xtrymalloc (length);
517   if (!p)
518     return gpg_error_from_syserror ();
519
520   if (cjson_is_string (j_keys))
521     {
522       strcpy (p, j_keys->valuestring);
523     }
524   else
525     {
526       for (i=0; i < nkeys; i++)
527         {
528           j_item = cJSON_GetArrayItem (j_keys, i);
529           if (i)
530             *p++ = '\n'; /* Add delimiter.  */
531           p = stpcpy (p, j_item->valuestring);
532         }
533     }
534   return 0;
535 }
536
537
538
539 \f
540 /*
541  *  GPGME support functions.
542  */
543
544 /* Helper for get_context.  */
545 static gpgme_ctx_t
546 _create_new_context (gpgme_protocol_t proto)
547 {
548   gpg_error_t err;
549   gpgme_ctx_t ctx;
550
551   err = gpgme_new (&ctx);
552   if (err)
553     log_fatal ("error creating GPGME context: %s\n", gpg_strerror (err));
554   gpgme_set_protocol (ctx, proto);
555   gpgme_set_ctx_flag (ctx, "request-origin", "browser");
556   return ctx;
557 }
558
559
560 /* Return a context object for protocol PROTO.  This is currently a
561  * statically allocated context initialized for PROTO.  Terminates
562  * process on failure.  */
563 static gpgme_ctx_t
564 get_context (gpgme_protocol_t proto)
565 {
566   static gpgme_ctx_t ctx_openpgp, ctx_cms, ctx_conf;
567
568   if (proto == GPGME_PROTOCOL_OpenPGP)
569     {
570       if (!ctx_openpgp)
571         ctx_openpgp = _create_new_context (proto);
572       return ctx_openpgp;
573     }
574   else if (proto == GPGME_PROTOCOL_CMS)
575     {
576       if (!ctx_cms)
577         ctx_cms = _create_new_context (proto);
578       return ctx_cms;
579     }
580   else if (proto == GPGME_PROTOCOL_GPGCONF)
581     {
582       if (!ctx_conf)
583         ctx_conf = _create_new_context (proto);
584       return ctx_conf;
585     }
586   else
587     log_bug ("invalid protocol %d requested\n", proto);
588 }
589
590
591 /* Free context object retrieved by get_context.  */
592 static void
593 release_context (gpgme_ctx_t ctx)
594 {
595   /* Nothing to do right now.  */
596   (void)ctx;
597 }
598
599
600 /* Create an addition context for short operations. */
601 static gpgme_ctx_t
602 create_onetime_context (gpgme_protocol_t proto)
603 {
604   return _create_new_context (proto);
605
606 }
607
608
609 /* Release a one-time context.  */
610 static void
611 release_onetime_context (gpgme_ctx_t ctx)
612 {
613   return gpgme_release (ctx);
614
615 }
616
617
618 /* Given a Base-64 encoded string object in JSON return a gpgme data
619  * object at R_DATA.  */
620 static gpg_error_t
621 data_from_base64_string (gpgme_data_t *r_data, cjson_t json)
622 {
623 #if GPGRT_VERSION_NUMBER < 0x011d00 /* 1.29 */
624   *r_data = NULL;
625   return gpg_error (GPG_ERR_NOT_SUPPORTED);
626 #else
627   gpg_error_t err;
628   size_t len;
629   char *buf = NULL;
630   gpgrt_b64state_t state = NULL;
631   gpgme_data_t data = NULL;
632
633   *r_data = NULL;
634
635   /* A quick check on the JSON.  */
636   if (!cjson_is_string (json))
637     {
638       err = gpg_error (GPG_ERR_INV_VALUE);
639       goto leave;
640     }
641
642   state = gpgrt_b64dec_start (NULL);
643   if (!state)
644     {
645       err = gpg_err_code_from_syserror ();
646       goto leave;
647     }
648
649   /* Fixme: Data duplication - we should see how to snatch the memory
650    * from the json object.  */
651   len = strlen (json->valuestring);
652   buf = xtrystrdup (json->valuestring);
653   if (!buf)
654     {
655       err = gpg_error_from_syserror ();
656       goto leave;
657     }
658
659   err = gpgrt_b64dec_proc (state, buf, len, &len);
660   if (err)
661     goto leave;
662
663   err = gpgrt_b64dec_finish (state);
664   state = NULL;
665   if (err)
666     goto leave;
667
668   err = gpgme_data_new_from_mem (&data, buf, len, 1);
669   if (err)
670     goto leave;
671   *r_data = data;
672   data = NULL;
673
674  leave:
675   xfree (data);
676   xfree (buf);
677   gpgrt_b64dec_finish (state);
678   return err;
679 #endif
680 }
681
682
683 /* Create a keylist pattern array from a json keys object
684  * in the request. Returns either a malloced NULL terminated
685  * string array which can be used as patterns for
686  * op_keylist_ext or NULL. */
687 static char **
688 create_keylist_patterns (cjson_t request, const char *name)
689 {
690   char *keystring;
691   char *p;
692   char *tmp;
693   char **ret;
694   int cnt = 2; /* Last NULL and one is not newline delimited */
695   int i = 0;
696
697   if (get_keys (request, name, &keystring))
698     return NULL;
699
700   for (p = keystring; *p; p++)
701     if (*p == '\n')
702       cnt++;
703
704   ret = xcalloc (1, cnt * sizeof *ret);
705
706   for (p = keystring, tmp = keystring; *p; p++)
707     {
708       if (*p != '\n')
709         continue;
710       *p = '\0';
711       ret[i++] = xstrdup (tmp);
712       tmp = p + 1;
713     }
714   /* The last key is not newline delimted. */
715   ret[i] = *tmp ? xstrdup (tmp) : NULL;
716
717   xfree (keystring);
718   return ret;
719 }
720
721
722 /* Do a secret keylisting for protocol proto and add the fingerprints of
723    the secret keys for patterns to the result as "sec-fprs" array. */
724 static gpg_error_t
725 add_secret_fprs (const char **patterns, gpgme_protocol_t protocol,
726                  cjson_t result)
727 {
728   gpgme_ctx_t ctx;
729   gpg_error_t err;
730   gpgme_key_t key = NULL;
731   cjson_t j_fprs = xjson_CreateArray ();
732
733   ctx = create_onetime_context (protocol);
734
735   gpgme_set_keylist_mode (ctx, GPGME_KEYLIST_MODE_LOCAL |
736                                GPGME_KEYLIST_MODE_WITH_SECRET);
737
738   err = gpgme_op_keylist_ext_start (ctx, patterns, 1, 0);
739
740   if (err)
741     {
742       gpg_error_object (result, err, "Error listing keys: %s",
743                         gpg_strerror (err));
744       goto leave;
745     }
746
747   while (!(err = gpgme_op_keylist_next (ctx, &key)))
748     {
749       if (!key || !key->fpr)
750         continue;
751       cJSON_AddItemToArray (j_fprs, cJSON_CreateString (key->fpr));
752       gpgme_key_unref (key);
753       key = NULL;
754     }
755   err = 0;
756
757   release_onetime_context (ctx);
758   ctx = NULL;
759
760   xjson_AddItemToObject (result, "sec-fprs", j_fprs);
761
762 leave:
763   release_onetime_context (ctx);
764   gpgme_key_unref (key);
765
766   return err;
767 }
768
769
770 /* Create sigsum json array */
771 static cjson_t
772 sigsum_to_json (gpgme_sigsum_t summary)
773 {
774   cjson_t result = xjson_CreateObject ();
775   cjson_t sigsum_array = xjson_CreateArray ();
776
777   if ( (summary & GPGME_SIGSUM_VALID      ))
778     cJSON_AddItemToArray (sigsum_array,
779         cJSON_CreateString ("valid"));
780   if ( (summary & GPGME_SIGSUM_GREEN      ))
781     cJSON_AddItemToArray (sigsum_array,
782         cJSON_CreateString ("green"));
783   if ( (summary & GPGME_SIGSUM_RED        ))
784     cJSON_AddItemToArray (sigsum_array,
785         cJSON_CreateString ("red"));
786   if ( (summary & GPGME_SIGSUM_KEY_REVOKED))
787     cJSON_AddItemToArray (sigsum_array,
788         cJSON_CreateString ("revoked"));
789   if ( (summary & GPGME_SIGSUM_KEY_EXPIRED))
790     cJSON_AddItemToArray (sigsum_array,
791         cJSON_CreateString ("key-expired"));
792   if ( (summary & GPGME_SIGSUM_SIG_EXPIRED))
793     cJSON_AddItemToArray (sigsum_array,
794         cJSON_CreateString ("sig-expired"));
795   if ( (summary & GPGME_SIGSUM_KEY_MISSING))
796     cJSON_AddItemToArray (sigsum_array,
797         cJSON_CreateString ("key-missing"));
798   if ( (summary & GPGME_SIGSUM_CRL_MISSING))
799     cJSON_AddItemToArray (sigsum_array,
800         cJSON_CreateString ("crl-missing"));
801   if ( (summary & GPGME_SIGSUM_CRL_TOO_OLD))
802     cJSON_AddItemToArray (sigsum_array,
803         cJSON_CreateString ("crl-too-old"));
804   if ( (summary & GPGME_SIGSUM_BAD_POLICY ))
805     cJSON_AddItemToArray (sigsum_array,
806         cJSON_CreateString ("bad-policy"));
807   if ( (summary & GPGME_SIGSUM_SYS_ERROR  ))
808     cJSON_AddItemToArray (sigsum_array,
809         cJSON_CreateString ("sys-error"));
810   /* The signature summary as string array. */
811   xjson_AddItemToObject (result, "sigsum", sigsum_array);
812
813   /* Bools for the same. */
814   xjson_AddBoolToObject (result, "valid",
815                          (summary & GPGME_SIGSUM_VALID      ));
816   xjson_AddBoolToObject (result, "green",
817                          (summary & GPGME_SIGSUM_GREEN      ));
818   xjson_AddBoolToObject (result, "red",
819                          (summary & GPGME_SIGSUM_RED        ));
820   xjson_AddBoolToObject (result, "revoked",
821                          (summary & GPGME_SIGSUM_KEY_REVOKED));
822   xjson_AddBoolToObject (result, "key-expired",
823                          (summary & GPGME_SIGSUM_KEY_EXPIRED));
824   xjson_AddBoolToObject (result, "sig-expired",
825                          (summary & GPGME_SIGSUM_SIG_EXPIRED));
826   xjson_AddBoolToObject (result, "key-missing",
827                          (summary & GPGME_SIGSUM_KEY_MISSING));
828   xjson_AddBoolToObject (result, "crl-missing",
829                          (summary & GPGME_SIGSUM_CRL_MISSING));
830   xjson_AddBoolToObject (result, "crl-too-old",
831                          (summary & GPGME_SIGSUM_CRL_TOO_OLD));
832   xjson_AddBoolToObject (result, "bad-policy",
833                          (summary & GPGME_SIGSUM_BAD_POLICY ));
834   xjson_AddBoolToObject (result, "sys-error",
835                          (summary & GPGME_SIGSUM_SYS_ERROR  ));
836
837   return result;
838 }
839
840
841 /* Helper for summary formatting */
842 static const char *
843 validity_to_string (gpgme_validity_t val)
844 {
845   switch (val)
846     {
847     case GPGME_VALIDITY_UNDEFINED:return "undefined";
848     case GPGME_VALIDITY_NEVER:    return "never";
849     case GPGME_VALIDITY_MARGINAL: return "marginal";
850     case GPGME_VALIDITY_FULL:     return "full";
851     case GPGME_VALIDITY_ULTIMATE: return "ultimate";
852     case GPGME_VALIDITY_UNKNOWN:
853     default:                      return "unknown";
854     }
855 }
856
857 static const char *
858 protocol_to_string (gpgme_protocol_t proto)
859 {
860   switch (proto)
861     {
862     case GPGME_PROTOCOL_OpenPGP: return "OpenPGP";
863     case GPGME_PROTOCOL_CMS:     return "CMS";
864     case GPGME_PROTOCOL_GPGCONF: return "gpgconf";
865     case GPGME_PROTOCOL_ASSUAN:  return "assuan";
866     case GPGME_PROTOCOL_G13:     return "g13";
867     case GPGME_PROTOCOL_UISERVER:return "uiserver";
868     case GPGME_PROTOCOL_SPAWN:   return "spawn";
869     default:
870                                  return "unknown";
871     }
872 }
873
874 /* Create a sig_notation json object */
875 static cjson_t
876 sig_notation_to_json (gpgme_sig_notation_t not)
877 {
878   cjson_t result = xjson_CreateObject ();
879   xjson_AddBoolToObject (result, "human_readable", not->human_readable);
880   xjson_AddBoolToObject (result, "critical", not->critical);
881
882   xjson_AddStringToObject0 (result, "name", not->name);
883   xjson_AddStringToObject0 (result, "value", not->value);
884
885   xjson_AddNumberToObject (result, "flags", not->flags);
886
887   return result;
888 }
889
890 /* Create a key_sig json object */
891 static cjson_t
892 key_sig_to_json (gpgme_key_sig_t sig)
893 {
894   cjson_t result = xjson_CreateObject ();
895
896   xjson_AddBoolToObject (result, "revoked", sig->revoked);
897   xjson_AddBoolToObject (result, "expired", sig->expired);
898   xjson_AddBoolToObject (result, "invalid", sig->invalid);
899   xjson_AddBoolToObject (result, "exportable", sig->exportable);
900
901   xjson_AddStringToObject0 (result, "pubkey_algo_name",
902                             gpgme_pubkey_algo_name (sig->pubkey_algo));
903   xjson_AddStringToObject0 (result, "keyid", sig->keyid);
904   xjson_AddStringToObject0 (result, "status", gpgme_strerror (sig->status));
905   xjson_AddStringToObject0 (result, "name", sig->name);
906   xjson_AddStringToObject0 (result, "email", sig->email);
907   xjson_AddStringToObject0 (result, "comment", sig->comment);
908
909   xjson_AddNumberToObject (result, "pubkey_algo", sig->pubkey_algo);
910   xjson_AddNumberToObject (result, "timestamp", sig->timestamp);
911   xjson_AddNumberToObject (result, "expires", sig->expires);
912   xjson_AddNumberToObject (result, "status_code", sig->status);
913   xjson_AddNumberToObject (result, "sig_class", sig->sig_class);
914
915   if (sig->notations)
916     {
917       gpgme_sig_notation_t not;
918       cjson_t array = xjson_CreateArray ();
919       for (not = sig->notations; not; not = not->next)
920         cJSON_AddItemToArray (array, sig_notation_to_json (not));
921       xjson_AddItemToObject (result, "notations", array);
922     }
923
924   return result;
925 }
926
927 /* Create a tofu info object */
928 static cjson_t
929 tofu_to_json (gpgme_tofu_info_t tofu)
930 {
931   cjson_t result = xjson_CreateObject ();
932
933   xjson_AddStringToObject0 (result, "description", tofu->description);
934
935   xjson_AddNumberToObject (result, "validity", tofu->validity);
936   xjson_AddNumberToObject (result, "policy", tofu->policy);
937   xjson_AddNumberToObject (result, "signcount", tofu->signcount);
938   xjson_AddNumberToObject (result, "encrcount", tofu->encrcount);
939   xjson_AddNumberToObject (result, "signfirst", tofu->signfirst);
940   xjson_AddNumberToObject (result, "signlast", tofu->signlast);
941   xjson_AddNumberToObject (result, "encrfirst", tofu->encrfirst);
942   xjson_AddNumberToObject (result, "encrlast", tofu->encrlast);
943
944   return result;
945 }
946
947 /* Create a userid json object */
948 static cjson_t
949 uid_to_json (gpgme_user_id_t uid)
950 {
951   cjson_t result = xjson_CreateObject ();
952
953   xjson_AddBoolToObject (result, "revoked", uid->revoked);
954   xjson_AddBoolToObject (result, "invalid", uid->invalid);
955
956   xjson_AddStringToObject0 (result, "validity",
957                             validity_to_string (uid->validity));
958   xjson_AddStringToObject0 (result, "uid", uid->uid);
959   xjson_AddStringToObject0 (result, "name", uid->name);
960   xjson_AddStringToObject0 (result, "email", uid->email);
961   xjson_AddStringToObject0 (result, "comment", uid->comment);
962   xjson_AddStringToObject0 (result, "address", uid->address);
963
964   xjson_AddNumberToObject (result, "origin", uid->origin);
965   xjson_AddNumberToObject (result, "last_update", uid->last_update);
966
967   /* Key sigs */
968   if (uid->signatures)
969     {
970       cjson_t sig_array = xjson_CreateArray ();
971       gpgme_key_sig_t sig;
972
973       for (sig = uid->signatures; sig; sig = sig->next)
974         cJSON_AddItemToArray (sig_array, key_sig_to_json (sig));
975
976       xjson_AddItemToObject (result, "signatures", sig_array);
977     }
978
979   /* TOFU info */
980   if (uid->tofu)
981     {
982       gpgme_tofu_info_t tofu;
983       cjson_t array = xjson_CreateArray ();
984       for (tofu = uid->tofu; tofu; tofu = tofu->next)
985         cJSON_AddItemToArray (array, tofu_to_json (tofu));
986       xjson_AddItemToObject (result, "tofu", array);
987     }
988
989   return result;
990 }
991
992 /* Create a subkey json object */
993 static cjson_t
994 subkey_to_json (gpgme_subkey_t sub)
995 {
996   cjson_t result = xjson_CreateObject ();
997
998   xjson_AddBoolToObject (result, "revoked", sub->revoked);
999   xjson_AddBoolToObject (result, "expired", sub->expired);
1000   xjson_AddBoolToObject (result, "disabled", sub->disabled);
1001   xjson_AddBoolToObject (result, "invalid", sub->invalid);
1002   xjson_AddBoolToObject (result, "can_encrypt", sub->can_encrypt);
1003   xjson_AddBoolToObject (result, "can_sign", sub->can_sign);
1004   xjson_AddBoolToObject (result, "can_certify", sub->can_certify);
1005   xjson_AddBoolToObject (result, "can_authenticate", sub->can_authenticate);
1006   xjson_AddBoolToObject (result, "secret", sub->secret);
1007   xjson_AddBoolToObject (result, "is_qualified", sub->is_qualified);
1008   xjson_AddBoolToObject (result, "is_cardkey", sub->is_cardkey);
1009   xjson_AddBoolToObject (result, "is_de_vs", sub->is_de_vs);
1010
1011   xjson_AddStringToObject0 (result, "pubkey_algo_name",
1012                             gpgme_pubkey_algo_name (sub->pubkey_algo));
1013   xjson_AddStringToObject0 (result, "pubkey_algo_string",
1014                             gpgme_pubkey_algo_string (sub));
1015   xjson_AddStringToObject0 (result, "keyid", sub->keyid);
1016   xjson_AddStringToObject0 (result, "card_number", sub->card_number);
1017   xjson_AddStringToObject0 (result, "curve", sub->curve);
1018   xjson_AddStringToObject0 (result, "keygrip", sub->keygrip);
1019
1020   xjson_AddNumberToObject (result, "pubkey_algo", sub->pubkey_algo);
1021   xjson_AddNumberToObject (result, "length", sub->length);
1022   xjson_AddNumberToObject (result, "timestamp", sub->timestamp);
1023   xjson_AddNumberToObject (result, "expires", sub->expires);
1024
1025   return result;
1026 }
1027
1028 /* Create a key json object */
1029 static cjson_t
1030 key_to_json (gpgme_key_t key)
1031 {
1032   cjson_t result = xjson_CreateObject ();
1033
1034   xjson_AddBoolToObject (result, "revoked", key->revoked);
1035   xjson_AddBoolToObject (result, "expired", key->expired);
1036   xjson_AddBoolToObject (result, "disabled", key->disabled);
1037   xjson_AddBoolToObject (result, "invalid", key->invalid);
1038   xjson_AddBoolToObject (result, "can_encrypt", key->can_encrypt);
1039   xjson_AddBoolToObject (result, "can_sign", key->can_sign);
1040   xjson_AddBoolToObject (result, "can_certify", key->can_certify);
1041   xjson_AddBoolToObject (result, "can_authenticate", key->can_authenticate);
1042   xjson_AddBoolToObject (result, "secret", key->secret);
1043   xjson_AddBoolToObject (result, "is_qualified", key->is_qualified);
1044
1045   xjson_AddStringToObject0 (result, "protocol",
1046                             protocol_to_string (key->protocol));
1047   xjson_AddStringToObject0 (result, "issuer_serial", key->issuer_serial);
1048   xjson_AddStringToObject0 (result, "issuer_name", key->issuer_name);
1049   xjson_AddStringToObject0 (result, "fingerprint", key->fpr);
1050   xjson_AddStringToObject0 (result, "chain_id", key->chain_id);
1051   xjson_AddStringToObject0 (result, "owner_trust",
1052                             validity_to_string (key->owner_trust));
1053
1054   xjson_AddNumberToObject (result, "origin", key->origin);
1055   xjson_AddNumberToObject (result, "last_update", key->last_update);
1056
1057   /* Add subkeys */
1058   if (key->subkeys)
1059     {
1060       cjson_t subkey_array = xjson_CreateArray ();
1061       gpgme_subkey_t sub;
1062       for (sub = key->subkeys; sub; sub = sub->next)
1063         cJSON_AddItemToArray (subkey_array, subkey_to_json (sub));
1064
1065       xjson_AddItemToObject (result, "subkeys", subkey_array);
1066     }
1067
1068   /* User Ids */
1069   if (key->uids)
1070     {
1071       cjson_t uid_array = xjson_CreateArray ();
1072       gpgme_user_id_t uid;
1073       for (uid = key->uids; uid; uid = uid->next)
1074         cJSON_AddItemToArray (uid_array, uid_to_json (uid));
1075
1076       xjson_AddItemToObject (result, "userids", uid_array);
1077     }
1078
1079   return result;
1080 }
1081
1082
1083 /* Create a signature json object */
1084 static cjson_t
1085 signature_to_json (gpgme_signature_t sig)
1086 {
1087   cjson_t result = xjson_CreateObject ();
1088
1089   xjson_AddItemToObject (result, "summary", sigsum_to_json (sig->summary));
1090
1091   xjson_AddBoolToObject (result, "wrong_key_usage", sig->wrong_key_usage);
1092   xjson_AddBoolToObject (result, "chain_model", sig->chain_model);
1093   xjson_AddBoolToObject (result, "is_de_vs", sig->is_de_vs);
1094
1095   xjson_AddStringToObject0 (result, "status_string",
1096                             gpgme_strerror (sig->status));
1097   xjson_AddStringToObject0 (result, "fingerprint", sig->fpr);
1098   xjson_AddStringToObject0 (result, "validity_string",
1099                             validity_to_string (sig->validity));
1100   xjson_AddStringToObject0 (result, "pubkey_algo_name",
1101                             gpgme_pubkey_algo_name (sig->pubkey_algo));
1102   xjson_AddStringToObject0 (result, "hash_algo_name",
1103                             gpgme_hash_algo_name (sig->hash_algo));
1104   xjson_AddStringToObject0 (result, "pka_address", sig->pka_address);
1105
1106   xjson_AddNumberToObject (result, "status_code", sig->status);
1107   xjson_AddNumberToObject (result, "timestamp", sig->timestamp);
1108   xjson_AddNumberToObject (result, "exp_timestamp", sig->exp_timestamp);
1109   xjson_AddNumberToObject (result, "pka_trust", sig->pka_trust);
1110   xjson_AddNumberToObject (result, "validity", sig->validity);
1111   xjson_AddNumberToObject (result, "validity_reason", sig->validity_reason);
1112
1113   if (sig->notations)
1114     {
1115       gpgme_sig_notation_t not;
1116       cjson_t array = xjson_CreateArray ();
1117       for (not = sig->notations; not; not = not->next)
1118         cJSON_AddItemToArray (array, sig_notation_to_json (not));
1119       xjson_AddItemToObject (result, "notations", array);
1120     }
1121
1122   return result;
1123 }
1124
1125
1126 /* Create a JSON object from a gpgme_verify result */
1127 static cjson_t
1128 verify_result_to_json (gpgme_verify_result_t verify_result)
1129 {
1130   cjson_t result = xjson_CreateObject ();
1131
1132   xjson_AddStringToObject0 (result, "file_name", verify_result->file_name);
1133   xjson_AddBoolToObject (result, "is_mime", verify_result->is_mime);
1134
1135   if (verify_result->signatures)
1136     {
1137       cjson_t array = xjson_CreateArray ();
1138       gpgme_signature_t sig;
1139
1140       for (sig = verify_result->signatures; sig; sig = sig->next)
1141         cJSON_AddItemToArray (array, signature_to_json (sig));
1142       xjson_AddItemToObject (result, "signatures", array);
1143     }
1144
1145   return result;
1146 }
1147
1148
1149 /* Create a JSON object from an engine_info */
1150 static cjson_t
1151 engine_info_to_json (gpgme_engine_info_t info)
1152 {
1153   cjson_t result = xjson_CreateObject ();
1154
1155   xjson_AddStringToObject0 (result, "protocol",
1156                             protocol_to_string (info->protocol));
1157   xjson_AddStringToObject0 (result, "fname", info->file_name);
1158   xjson_AddStringToObject0 (result, "version", info->version);
1159   xjson_AddStringToObject0 (result, "req_version", info->req_version);
1160   xjson_AddStringToObject0 (result, "homedir", info->home_dir ?
1161                                                 info->home_dir :
1162                                                 "default");
1163   return result;
1164 }
1165
1166
1167 /* Create a JSON object from an import_status */
1168 static cjson_t
1169 import_status_to_json (gpgme_import_status_t sts)
1170 {
1171   cjson_t result = xjson_CreateObject ();
1172
1173   xjson_AddStringToObject0 (result, "fingerprint", sts->fpr);
1174   xjson_AddStringToObject0 (result, "error_string",
1175                             gpgme_strerror (sts->result));
1176
1177   xjson_AddNumberToObject (result, "status", sts->status);
1178
1179   return result;
1180 }
1181
1182 /* Create a JSON object from an import result */
1183 static cjson_t
1184 import_result_to_json (gpgme_import_result_t imp)
1185 {
1186   cjson_t result = xjson_CreateObject ();
1187
1188   xjson_AddNumberToObject (result, "considered", imp->considered);
1189   xjson_AddNumberToObject (result, "no_user_id", imp->no_user_id);
1190   xjson_AddNumberToObject (result, "imported", imp->imported);
1191   xjson_AddNumberToObject (result, "imported_rsa", imp->imported_rsa);
1192   xjson_AddNumberToObject (result, "unchanged", imp->unchanged);
1193   xjson_AddNumberToObject (result, "new_user_ids", imp->new_user_ids);
1194   xjson_AddNumberToObject (result, "new_sub_keys", imp->new_sub_keys);
1195   xjson_AddNumberToObject (result, "new_signatures", imp->new_signatures);
1196   xjson_AddNumberToObject (result, "new_revocations", imp->new_revocations);
1197   xjson_AddNumberToObject (result, "secret_read", imp->secret_read);
1198   xjson_AddNumberToObject (result, "secret_imported", imp->secret_imported);
1199   xjson_AddNumberToObject (result, "secret_unchanged", imp->secret_unchanged);
1200   xjson_AddNumberToObject (result, "skipped_new_keys", imp->skipped_new_keys);
1201   xjson_AddNumberToObject (result, "not_imported", imp->not_imported);
1202   xjson_AddNumberToObject (result, "skipped_v3_keys", imp->skipped_v3_keys);
1203
1204
1205   if (imp->imports)
1206     {
1207       cjson_t array = xjson_CreateArray ();
1208       gpgme_import_status_t status;
1209
1210       for (status = imp->imports; status; status = status->next)
1211         cJSON_AddItemToArray (array, import_status_to_json (status));
1212       xjson_AddItemToObject (result, "imports", array);
1213     }
1214
1215   return result;
1216 }
1217
1218
1219 /* Create a JSON object from a gpgconf arg */
1220 static cjson_t
1221 conf_arg_to_json (gpgme_conf_arg_t arg, gpgme_conf_type_t type)
1222 {
1223   cjson_t result = xjson_CreateObject ();
1224   int is_none = 0;
1225   switch (type)
1226     {
1227       case GPGME_CONF_STRING:
1228       case GPGME_CONF_PATHNAME:
1229       case GPGME_CONF_LDAP_SERVER:
1230       case GPGME_CONF_KEY_FPR:
1231       case GPGME_CONF_PUB_KEY:
1232       case GPGME_CONF_SEC_KEY:
1233       case GPGME_CONF_ALIAS_LIST:
1234         xjson_AddStringToObject0 (result, "string", arg->value.string);
1235         break;
1236
1237       case GPGME_CONF_UINT32:
1238         xjson_AddNumberToObject (result, "number", arg->value.uint32);
1239         break;
1240
1241       case GPGME_CONF_INT32:
1242         xjson_AddNumberToObject (result, "number", arg->value.int32);
1243         break;
1244
1245       case GPGME_CONF_NONE:
1246       default:
1247         is_none = 1;
1248         break;
1249     }
1250   xjson_AddBoolToObject (result, "is_none", is_none);
1251   return result;
1252 }
1253
1254
1255 /* Create a JSON object from a gpgconf option */
1256 static cjson_t
1257 conf_opt_to_json (gpgme_conf_opt_t opt)
1258 {
1259   cjson_t result = xjson_CreateObject ();
1260
1261   xjson_AddStringToObject0 (result, "name", opt->name);
1262   xjson_AddStringToObject0 (result, "description", opt->description);
1263   xjson_AddStringToObject0 (result, "argname", opt->argname);
1264   xjson_AddStringToObject0 (result, "default_description",
1265                             opt->default_description);
1266   xjson_AddStringToObject0 (result, "no_arg_description",
1267                             opt->no_arg_description);
1268
1269   xjson_AddNumberToObject (result, "flags", opt->flags);
1270   xjson_AddNumberToObject (result, "level", opt->level);
1271   xjson_AddNumberToObject (result, "type", opt->type);
1272   xjson_AddNumberToObject (result, "alt_type", opt->alt_type);
1273
1274   if (opt->default_value)
1275     {
1276       cjson_t array = xjson_CreateArray ();
1277       gpgme_conf_arg_t arg;
1278
1279       for (arg = opt->default_value; arg; arg = arg->next)
1280         cJSON_AddItemToArray (array, conf_arg_to_json (arg, opt->alt_type));
1281       xjson_AddItemToObject (result, "default_value", array);
1282     }
1283
1284   if (opt->no_arg_value)
1285     {
1286       cjson_t array = xjson_CreateArray ();
1287       gpgme_conf_arg_t arg;
1288
1289       for (arg = opt->no_arg_value; arg; arg = arg->next)
1290         cJSON_AddItemToArray (array, conf_arg_to_json (arg, opt->alt_type));
1291       xjson_AddItemToObject (result, "no_arg_value", array);
1292     }
1293
1294   if (opt->value)
1295     {
1296       cjson_t array = xjson_CreateArray ();
1297       gpgme_conf_arg_t arg;
1298
1299       for (arg = opt->value; arg; arg = arg->next)
1300         cJSON_AddItemToArray (array, conf_arg_to_json (arg, opt->alt_type));
1301       xjson_AddItemToObject (result, "value", array);
1302     }
1303   return result;
1304 }
1305
1306
1307 /* Create a JSON object from a gpgconf component*/
1308 static cjson_t
1309 conf_comp_to_json (gpgme_conf_comp_t cmp)
1310 {
1311   cjson_t result = xjson_CreateObject ();
1312
1313   xjson_AddStringToObject0 (result, "name", cmp->name);
1314   xjson_AddStringToObject0 (result, "description", cmp->description);
1315   xjson_AddStringToObject0 (result, "program_name", cmp->program_name);
1316
1317
1318   if (cmp->options)
1319     {
1320       cjson_t array = xjson_CreateArray ();
1321       gpgme_conf_opt_t opt;
1322
1323       for (opt = cmp->options; opt; opt = opt->next)
1324         cJSON_AddItemToArray (array, conf_opt_to_json (opt));
1325       xjson_AddItemToObject (result, "options", array);
1326     }
1327
1328   return result;
1329 }
1330
1331
1332 /* Create a gpgme_data from json string data named "name"
1333  * in the request. Takes the base64 option into account.
1334  *
1335  * Adds an error to the "result" on error. */
1336 static gpg_error_t
1337 get_string_data (cjson_t request, cjson_t result, const char *name,
1338                  gpgme_data_t *r_data)
1339 {
1340   gpgme_error_t err;
1341   int opt_base64;
1342   cjson_t j_data;
1343
1344   if ((err = get_boolean_flag (request, "base64", 0, &opt_base64)))
1345     return err;
1346
1347   /* Get the data.  Note that INPUT is a shallow data object with the
1348    * storage hold in REQUEST.  */
1349   j_data = cJSON_GetObjectItem (request, name);
1350   if (!j_data)
1351     {
1352       return gpg_error (GPG_ERR_NO_DATA);
1353     }
1354   if (!cjson_is_string (j_data))
1355     {
1356       return gpg_error (GPG_ERR_INV_VALUE);
1357     }
1358   if (opt_base64)
1359     {
1360       err = data_from_base64_string (r_data, j_data);
1361       if (err)
1362         {
1363           gpg_error_object (result, err,
1364                             "Error decoding Base-64 encoded '%s': %s",
1365                             name, gpg_strerror (err));
1366           return err;
1367         }
1368     }
1369   else
1370     {
1371       err = gpgme_data_new_from_mem (r_data, j_data->valuestring,
1372                                      strlen (j_data->valuestring), 0);
1373       if (err)
1374         {
1375           gpg_error_object (result, err, "Error getting '%s': %s",
1376                             name, gpg_strerror (err));
1377           return err;
1378         }
1379     }
1380   return 0;
1381 }
1382
1383
1384 /* Create a "data" object and the "type" and "base64" flags
1385  * from DATA and append them to RESULT.  Ownership of DATA is
1386  * transferred to this function.  TYPE must be a fixed string.
1387  * If BASE64 is -1 the need for base64 encoding is determined
1388  * by the content of DATA, all other values are taken as true
1389  * or false. */
1390 static gpg_error_t
1391 make_data_object (cjson_t result, gpgme_data_t data,
1392                   const char *type, int base64)
1393 {
1394   gpg_error_t err;
1395   char *buffer;
1396   const char *s;
1397   size_t buflen, n;
1398
1399   if (!base64 || base64 == -1) /* Make sure that we really have a string.  */
1400     gpgme_data_write (data, "", 1);
1401
1402   buffer = gpgme_data_release_and_get_mem (data, &buflen);
1403   data = NULL;
1404   if (!buffer)
1405     {
1406       err = gpg_error_from_syserror ();
1407       goto leave;
1408     }
1409
1410   if (base64 == -1)
1411     {
1412       base64 = 0;
1413       if (!buflen)
1414         log_fatal ("Appended Nul byte got lost\n");
1415       /* Figure out if there is any Nul octet in the buffer.  In that
1416        * case we need to Base-64 the buffer.  Due to problems with the
1417        * browser's Javascript we use Base-64 also in case an UTF-8
1418        * character is in the buffer.  This is because the chunking may
1419        * split an UTF-8 characters and JS can't handle this.  */
1420       for (s=buffer, n=0; n < buflen -1; s++, n++)
1421         if (!*s || (*s & 0x80))
1422           {
1423             buflen--; /* Adjust for the extra nul byte.  */
1424             base64 = 1;
1425             break;
1426           }
1427     }
1428
1429   xjson_AddStringToObject (result, "type", type);
1430   xjson_AddBoolToObject (result, "base64", base64);
1431
1432   if (base64)
1433     err = add_base64_to_object (result, "data", buffer, buflen);
1434   else
1435     err = cjson_AddStringToObject (result, "data", buffer);
1436
1437  leave:
1438   gpgme_free (buffer);
1439   return err;
1440 }
1441
1442
1443 /* Encode and chunk response.
1444  *
1445  * If neccessary this base64 encodes and chunks the repsonse
1446  * for getmore so that we always return valid json independent
1447  * of the chunksize.
1448  *
1449  * A chunked repsonse contains the base64 encoded chunk
1450  * as a string and a boolean if there is still more data
1451  * available for getmore like:
1452  * {
1453  *   chunk: "SGVsbG8gV29ybGQK"
1454  *   more: true
1455  * }
1456  *
1457  * Chunking is only done if the response is larger then the
1458  * chunksize.
1459  *
1460  * caller has to xfree the return value.
1461  */
1462 static char *
1463 encode_and_chunk (cjson_t request, cjson_t response)
1464 {
1465   char *data;
1466   gpg_error_t err = 0;
1467   size_t chunksize;
1468   char *getmore_request = NULL;
1469
1470   if (opt_interactive)
1471     data = cJSON_Print (response);
1472   else
1473     data = cJSON_PrintUnformatted (response);
1474
1475   if (!data)
1476     {
1477       err = GPG_ERR_NO_DATA;
1478       goto leave;
1479     }
1480
1481   if (!request)
1482     {
1483       err = GPG_ERR_INV_VALUE;
1484       goto leave;
1485     }
1486
1487   if ((err = get_chunksize (request, &chunksize)))
1488     {
1489       err = GPG_ERR_INV_VALUE;
1490       goto leave;
1491     }
1492
1493   if (!chunksize)
1494     {
1495       err = GPG_ERR_INV_VALUE;
1496       goto leave;
1497     }
1498
1499   pending_data.buffer = data;
1500   /* Data should already be encoded so that it does not
1501      contain 0.*/
1502   pending_data.length = strlen (data);
1503   pending_data.written = 0;
1504
1505   if (gpgrt_asprintf (&getmore_request,
1506                   "{ \"op\":\"getmore\", \"chunksize\": %i }",
1507                   (int) chunksize) == -1)
1508     {
1509       err = gpg_error_from_syserror ();
1510       goto leave;
1511     }
1512
1513   data = process_request (getmore_request);
1514
1515 leave:
1516   xfree (getmore_request);
1517
1518   if (!err && !data)
1519     {
1520       err = GPG_ERR_GENERAL;
1521     }
1522
1523   if (err)
1524     {
1525       cjson_t err_obj = gpg_error_object (NULL, err,
1526                                           "Encode and chunk failed: %s",
1527                                           gpgme_strerror (err));
1528       xfree (data);
1529       if (opt_interactive)
1530         data = cJSON_Print (err_obj);
1531       data = cJSON_PrintUnformatted (err_obj);
1532
1533       cJSON_Delete (err_obj);
1534     }
1535
1536   return data;
1537 }
1538
1539
1540 \f
1541 /*
1542  * Implementation of the commands.
1543  */
1544 static const char hlp_encrypt[] =
1545   "op:     \"encrypt\"\n"
1546   "keys:   Array of strings with the fingerprints or user-ids\n"
1547   "        of the keys to encrypt the data.  For a single key\n"
1548   "        a String may be used instead of an array.\n"
1549   "data:   Input data. \n"
1550   "\n"
1551   "Optional parameters:\n"
1552   "protocol:      Either \"openpgp\" (default) or \"cms\".\n"
1553   "signing_keys:  Similar to the keys parameter for added signing.\n"
1554   "               (openpgp only)"
1555   "\n"
1556   "Optional boolean flags (default is false):\n"
1557   "base64:        Input data is base64 encoded.\n"
1558   "mime:          Indicate that data is a MIME object.\n"
1559   "armor:         Request output in armored format.\n"
1560   "always-trust:  Request --always-trust option.\n"
1561   "no-encrypt-to: Do not use a default recipient.\n"
1562   "no-compress:   Do not compress the plaintext first.\n"
1563   "throw-keyids:  Request the --throw-keyids option.\n"
1564   "want-address:  Require that the keys include a mail address.\n"
1565   "wrap:          Assume the input is an OpenPGP message.\n"
1566   "\n"
1567   "Response on success:\n"
1568   "type:   \"ciphertext\"\n"
1569   "data:   Unless armor mode is used a Base64 encoded binary\n"
1570   "        ciphertext.  In armor mode a string with an armored\n"
1571   "        OpenPGP or a PEM message.\n"
1572   "base64: Boolean indicating whether data is base64 encoded.";
1573 static gpg_error_t
1574 op_encrypt (cjson_t request, cjson_t result)
1575 {
1576   gpg_error_t err;
1577   gpgme_ctx_t ctx = NULL;
1578   gpgme_protocol_t protocol;
1579   char **signing_patterns = NULL;
1580   int opt_mime;
1581   char *keystring = NULL;
1582   gpgme_data_t input = NULL;
1583   gpgme_data_t output = NULL;
1584   int abool;
1585   gpgme_encrypt_flags_t encrypt_flags = 0;
1586   gpgme_ctx_t keylist_ctx = NULL;
1587   gpgme_key_t key = NULL;
1588
1589   if ((err = get_protocol (request, &protocol)))
1590     goto leave;
1591   ctx = get_context (protocol);
1592
1593   if ((err = get_boolean_flag (request, "mime", 0, &opt_mime)))
1594     goto leave;
1595
1596   if ((err = get_boolean_flag (request, "armor", 0, &abool)))
1597     goto leave;
1598   gpgme_set_armor (ctx, abool);
1599   if ((err = get_boolean_flag (request, "always-trust", 0, &abool)))
1600     goto leave;
1601   if (abool)
1602     encrypt_flags |= GPGME_ENCRYPT_ALWAYS_TRUST;
1603   if ((err = get_boolean_flag (request, "no-encrypt-to", 0,&abool)))
1604     goto leave;
1605   if (abool)
1606     encrypt_flags |= GPGME_ENCRYPT_NO_ENCRYPT_TO;
1607   if ((err = get_boolean_flag (request, "no-compress", 0, &abool)))
1608     goto leave;
1609   if (abool)
1610     encrypt_flags |= GPGME_ENCRYPT_NO_COMPRESS;
1611   if ((err = get_boolean_flag (request, "throw-keyids", 0, &abool)))
1612     goto leave;
1613   if (abool)
1614     encrypt_flags |= GPGME_ENCRYPT_THROW_KEYIDS;
1615   if ((err = get_boolean_flag (request, "wrap", 0, &abool)))
1616     goto leave;
1617   if (abool)
1618     encrypt_flags |= GPGME_ENCRYPT_WRAP;
1619   if ((err = get_boolean_flag (request, "want-address", 0, &abool)))
1620     goto leave;
1621   if (abool)
1622     encrypt_flags |= GPGME_ENCRYPT_WANT_ADDRESS;
1623
1624
1625   /* Get the keys.  */
1626   err = get_keys (request, "keys", &keystring);
1627   if (err)
1628     {
1629       /* Provide a custom error response.  */
1630       gpg_error_object (result, err, "Error getting keys: %s",
1631                         gpg_strerror (err));
1632       goto leave;
1633     }
1634
1635   /* Do we have signing keys ? */
1636   signing_patterns = create_keylist_patterns (request, "signing_keys");
1637   if (signing_patterns)
1638     {
1639       keylist_ctx = create_onetime_context (protocol);
1640       gpgme_set_keylist_mode (keylist_ctx, GPGME_KEYLIST_MODE_LOCAL);
1641
1642       err = gpgme_op_keylist_ext_start (keylist_ctx,
1643                                         (const char **) signing_patterns,
1644                                         1, 0);
1645       if (err)
1646         {
1647           gpg_error_object (result, err, "Error listing keys: %s",
1648                             gpg_strerror (err));
1649           goto leave;
1650         }
1651       while (!(err = gpgme_op_keylist_next (keylist_ctx, &key)))
1652         {
1653           if ((err = gpgme_signers_add (ctx, key)))
1654             {
1655               gpg_error_object (result, err, "Error adding signer: %s",
1656                                 gpg_strerror (err));
1657               goto leave;
1658             }
1659           gpgme_key_unref (key);
1660           key = NULL;
1661         }
1662       release_onetime_context (keylist_ctx);
1663       keylist_ctx = NULL;
1664     }
1665
1666   if ((err = get_string_data (request, result, "data", &input)))
1667       goto leave;
1668
1669   if (opt_mime)
1670     gpgme_data_set_encoding (input, GPGME_DATA_ENCODING_MIME);
1671
1672
1673   /* Create an output data object.  */
1674   err = gpgme_data_new (&output);
1675   if (err)
1676     {
1677       gpg_error_object (result, err, "Error creating output data object: %s",
1678                         gpg_strerror (err));
1679       goto leave;
1680     }
1681
1682   /* Encrypt.  */
1683   if (!signing_patterns)
1684     {
1685       err = gpgme_op_encrypt_ext (ctx, NULL, keystring, encrypt_flags,
1686                                   input, output);
1687     }
1688   else
1689     {
1690       err = gpgme_op_encrypt_sign_ext (ctx, NULL, keystring, encrypt_flags,
1691                                        input, output);
1692
1693     }
1694   /* encrypt_result = gpgme_op_encrypt_result (ctx); */
1695   if (err)
1696     {
1697       gpg_error_object (result, err, "Encryption failed: %s",
1698                         gpg_strerror (err));
1699       goto leave;
1700     }
1701   gpgme_data_release (input);
1702   input = NULL;
1703
1704   /* We need to base64 if armoring has not been requested.  */
1705   err = make_data_object (result, output,
1706                           "ciphertext", !gpgme_get_armor (ctx));
1707   output = NULL;
1708
1709  leave:
1710   xfree_array (signing_patterns);
1711   xfree (keystring);
1712   release_onetime_context (keylist_ctx);
1713   gpgme_key_unref (key);
1714   gpgme_signers_clear (ctx);
1715   release_context (ctx);
1716   gpgme_data_release (input);
1717   gpgme_data_release (output);
1718   return err;
1719 }
1720
1721
1722 \f
1723 static const char hlp_decrypt[] =
1724   "op:     \"decrypt\"\n"
1725   "data:   The encrypted data.\n"
1726   "\n"
1727   "Optional parameters:\n"
1728   "protocol:      Either \"openpgp\" (default) or \"cms\".\n"
1729   "\n"
1730   "Optional boolean flags (default is false):\n"
1731   "base64:        Input data is base64 encoded.\n"
1732   "\n"
1733   "Response on success:\n"
1734   "type:   \"plaintext\"\n"
1735   "data:   The decrypted data.  This may be base64 encoded.\n"
1736   "base64: Boolean indicating whether data is base64 encoded.\n"
1737   "mime:   A Boolean indicating whether the data is a MIME object.\n"
1738   "info:   An object with verification information. (gpgme_verify_result_t)\n"
1739   " file_name: Optional string of the plaintext file name.\n"
1740   " is_mime:    Boolean that is true if the messages claims it is MIME.\n"
1741   " signatures: Array of signatures\n"
1742   "  summary: Object containing summary information.\n"
1743   "   Boolean values: (Check gpgme_sigsum_t doc for meaning)\n"
1744   "    valid\n"
1745   "    green\n"
1746   "    red\n"
1747   "    revoked\n"
1748   "    key-expired\n"
1749   "    sig-expired\n"
1750   "    key-missing\n"
1751   "    crl-missing\n"
1752   "    crl-too-old\n"
1753   "    bad-policy\n"
1754   "    sys-error\n"
1755   "   sigsum: Array of strings representing the sigsum.\n"
1756   "  Boolean values:\n"
1757   "   wrong_key_usage: Key should not have been used for signing.\n"
1758   "   chain_model:     Validity has been verified using the chain model.\n"
1759   "   is_de_vs:        signature is in compliance to the de-vs mode.\n"
1760   "  String values:\n"
1761   "   status_string:      The status code as localized gpg-error string\n"
1762   "   fingerprint:        The fingerprint of the signing key.\n"
1763   "   validity_string:    The validity as string.\n"
1764   "   pubkey_algo_name:   gpgme_pubkey_algo_name of used algo.\n"
1765   "   hash_algo_name:     gpgme_hash_algo_name of used hash algo\n"
1766   "   pka_address:        The mailbox from the PKA information.\n"
1767   "  Number values:\n"
1768   "   status_code:     The status as a number. (gpg_error_t)\n"
1769   "   timestamp:       Signature creation time. (secs since epoch)\n"
1770   "   exp_timestamp:   Signature expiration or 0. (secs since epoch)\n"
1771   "   pka_trust: PKA status: 0 = not available, 1 = bad, 2 = okay, 3 = RFU.\n"
1772   "   validity: validity as number (gpgme_validity_t)\n"
1773   "   validity_reason: (gpg_error_t)\n"
1774   "  Array values:\n"
1775   "   notations: Notation data and policy urls (gpgme_sig_notation_t)\n"
1776   "    Boolean values:\n"
1777   "     human_readable\n"
1778   "     critical\n"
1779   "    String values:\n"
1780   "     name\n"
1781   "     value\n"
1782   "    Number values:\n"
1783   "     flags\n";
1784 static gpg_error_t
1785 op_decrypt (cjson_t request, cjson_t result)
1786 {
1787   gpg_error_t err;
1788   gpgme_ctx_t ctx = NULL;
1789   gpgme_protocol_t protocol;
1790   gpgme_data_t input = NULL;
1791   gpgme_data_t output = NULL;
1792   gpgme_decrypt_result_t decrypt_result;
1793   gpgme_verify_result_t verify_result;
1794
1795   if ((err = get_protocol (request, &protocol)))
1796     goto leave;
1797   ctx = get_context (protocol);
1798
1799   if ((err = get_string_data (request, result, "data", &input)))
1800       goto leave;
1801
1802   /* Create an output data object.  */
1803   err = gpgme_data_new (&output);
1804   if (err)
1805     {
1806       gpg_error_object (result, err,
1807                         "Error creating output data object: %s",
1808                         gpg_strerror (err));
1809       goto leave;
1810     }
1811
1812   /* Decrypt.  */
1813   err = gpgme_op_decrypt_ext (ctx, GPGME_DECRYPT_VERIFY,
1814                               input, output);
1815   decrypt_result = gpgme_op_decrypt_result (ctx);
1816   if (err)
1817     {
1818       gpg_error_object (result, err, "Decryption failed: %s",
1819                         gpg_strerror (err));
1820       goto leave;
1821     }
1822   gpgme_data_release (input);
1823   input = NULL;
1824
1825   if (decrypt_result->is_mime)
1826     xjson_AddBoolToObject (result, "mime", 1);
1827
1828   verify_result = gpgme_op_verify_result (ctx);
1829   if (verify_result && verify_result->signatures)
1830     {
1831       xjson_AddItemToObject (result, "info",
1832                              verify_result_to_json (verify_result));
1833     }
1834
1835   err = make_data_object (result, output, "plaintext", -1);
1836   output = NULL;
1837
1838   if (err)
1839     {
1840       gpg_error_object (result, err, "Plaintext output failed: %s",
1841                         gpg_strerror (err));
1842       goto leave;
1843     }
1844
1845  leave:
1846   release_context (ctx);
1847   gpgme_data_release (input);
1848   gpgme_data_release (output);
1849   return err;
1850 }
1851
1852
1853 \f
1854 static const char hlp_sign[] =
1855   "op:     \"sign\"\n"
1856   "keys:   Array of strings with the fingerprints of the signing key.\n"
1857   "        For a single key a String may be used instead of an array.\n"
1858   "data:   Input data. \n"
1859   "\n"
1860   "Optional parameters:\n"
1861   "protocol:      Either \"openpgp\" (default) or \"cms\".\n"
1862   "sender:        The mail address of the sender.\n"
1863   "mode:          A string with the signing mode can be:\n"
1864   "               detached (default)\n"
1865   "               opaque\n"
1866   "               clearsign\n"
1867   "\n"
1868   "Optional boolean flags (default is false):\n"
1869   "base64:        Input data is base64 encoded.\n"
1870   "armor:         Request output in armored format.\n"
1871   "\n"
1872   "Response on success:\n"
1873   "type:   \"signature\"\n"
1874   "data:   Unless armor mode is used a Base64 encoded binary\n"
1875   "        signature.  In armor mode a string with an armored\n"
1876   "        OpenPGP or a PEM message.\n"
1877   "base64: Boolean indicating whether data is base64 encoded.\n";
1878 static gpg_error_t
1879 op_sign (cjson_t request, cjson_t result)
1880 {
1881   gpg_error_t err;
1882   gpgme_ctx_t ctx = NULL;
1883   gpgme_protocol_t protocol;
1884   char **patterns = NULL;
1885   gpgme_data_t input = NULL;
1886   gpgme_data_t output = NULL;
1887   int abool;
1888   cjson_t j_tmp;
1889   gpgme_sig_mode_t mode = GPGME_SIG_MODE_DETACH;
1890   gpgme_ctx_t keylist_ctx = NULL;
1891   gpgme_key_t key = NULL;
1892
1893   if ((err = get_protocol (request, &protocol)))
1894     goto leave;
1895   ctx = get_context (protocol);
1896
1897   if ((err = get_boolean_flag (request, "armor", 0, &abool)))
1898     goto leave;
1899   gpgme_set_armor (ctx, abool);
1900
1901   j_tmp = cJSON_GetObjectItem (request, "mode");
1902   if (j_tmp && cjson_is_string (j_tmp))
1903     {
1904       if (!strcmp (j_tmp->valuestring, "opaque"))
1905         {
1906           mode = GPGME_SIG_MODE_NORMAL;
1907         }
1908       else if (!strcmp (j_tmp->valuestring, "clearsign"))
1909         {
1910           mode = GPGME_SIG_MODE_CLEAR;
1911         }
1912     }
1913
1914   j_tmp = cJSON_GetObjectItem (request, "sender");
1915   if (j_tmp && cjson_is_string (j_tmp))
1916     {
1917       gpgme_set_sender (ctx, j_tmp->valuestring);
1918     }
1919
1920   patterns = create_keylist_patterns (request, "keys");
1921   if (!patterns)
1922     {
1923       gpg_error_object (result, err, "Error getting keys: %s",
1924                         gpg_strerror (gpg_error (GPG_ERR_NO_KEY)));
1925       goto leave;
1926     }
1927
1928   /* Do a keylisting and add the keys */
1929   keylist_ctx = create_onetime_context (protocol);
1930   gpgme_set_keylist_mode (keylist_ctx, GPGME_KEYLIST_MODE_LOCAL);
1931
1932   err = gpgme_op_keylist_ext_start (keylist_ctx,
1933                                     (const char **) patterns, 1, 0);
1934   if (err)
1935     {
1936       gpg_error_object (result, err, "Error listing keys: %s",
1937                         gpg_strerror (err));
1938       goto leave;
1939     }
1940   while (!(err = gpgme_op_keylist_next (keylist_ctx, &key)))
1941     {
1942       if ((err = gpgme_signers_add (ctx, key)))
1943         {
1944           gpg_error_object (result, err, "Error adding signer: %s",
1945                             gpg_strerror (err));
1946           goto leave;
1947         }
1948       gpgme_key_unref (key);
1949       key = NULL;
1950     }
1951
1952   if ((err = get_string_data (request, result, "data", &input)))
1953     goto leave;
1954
1955   /* Create an output data object.  */
1956   err = gpgme_data_new (&output);
1957   if (err)
1958     {
1959       gpg_error_object (result, err, "Error creating output data object: %s",
1960                         gpg_strerror (err));
1961       goto leave;
1962     }
1963
1964   /* Sign. */
1965   err = gpgme_op_sign (ctx, input, output, mode);
1966   if (err)
1967     {
1968       gpg_error_object (result, err, "Signing failed: %s",
1969                         gpg_strerror (err));
1970       goto leave;
1971     }
1972
1973   gpgme_data_release (input);
1974   input = NULL;
1975
1976   /* We need to base64 if armoring has not been requested.  */
1977   err = make_data_object (result, output,
1978                           "signature", !gpgme_get_armor (ctx));
1979   output = NULL;
1980
1981  leave:
1982   xfree_array (patterns);
1983   gpgme_signers_clear (ctx);
1984   gpgme_key_unref (key);
1985   release_onetime_context (keylist_ctx);
1986   release_context (ctx);
1987   gpgme_data_release (input);
1988   gpgme_data_release (output);
1989   return err;
1990 }
1991
1992
1993 \f
1994 static const char hlp_verify[] =
1995   "op:     \"verify\"\n"
1996   "data:   The data to verify.\n"
1997   "\n"
1998   "Optional parameters:\n"
1999   "protocol:      Either \"openpgp\" (default) or \"cms\".\n"
2000   "signature:     A detached signature. If missing opaque is assumed.\n"
2001   "\n"
2002   "Optional boolean flags (default is false):\n"
2003   "base64:        Input data is base64 encoded.\n"
2004   "\n"
2005   "Response on success:\n"
2006   "type:   \"plaintext\"\n"
2007   "data:   The verified data.  This may be base64 encoded.\n"
2008   "base64: Boolean indicating whether data is base64 encoded.\n"
2009   "info:   An object with verification information (gpgme_verify_result_t).\n"
2010   " file_name: Optional string of the plaintext file name.\n"
2011   " is_mime:    Boolean that is true if the messages claims it is MIME.\n"
2012   " signatures: Array of signatures\n"
2013   "  summary: Object containing summary information.\n"
2014   "   Boolean values: (Check gpgme_sigsum_t doc for meaning)\n"
2015   "    valid\n"
2016   "    green\n"
2017   "    red\n"
2018   "    revoked\n"
2019   "    key-expired\n"
2020   "    sig-expired\n"
2021   "    key-missing\n"
2022   "    crl-missing\n"
2023   "    crl-too-old\n"
2024   "    bad-policy\n"
2025   "    sys-error\n"
2026   "   sigsum: Array of strings representing the sigsum.\n"
2027   "  Boolean values:\n"
2028   "   wrong_key_usage: Key should not have been used for signing.\n"
2029   "   chain_model:     Validity has been verified using the chain model.\n"
2030   "   is_de_vs:        signature is in compliance to the de-vs mode.\n"
2031   "  String values:\n"
2032   "   status_string:      The status code as localized gpg-error string\n"
2033   "   fingerprint:        The fingerprint of the signing key.\n"
2034   "   validity_string:    The validity as string.\n"
2035   "   pubkey_algo_name:   gpgme_pubkey_algo_name of used algo.\n"
2036   "   hash_algo_name:     gpgme_hash_algo_name of used hash algo\n"
2037   "   pka_address:        The mailbox from the PKA information.\n"
2038   "  Number values:\n"
2039   "   status_code:     The status as a number. (gpg_error_t)\n"
2040   "   timestamp:       Signature creation time. (secs since epoch)\n"
2041   "   exp_timestamp:   Signature expiration or 0. (secs since epoch)\n"
2042   "   pka_trust: PKA status: 0 = not available, 1 = bad, 2 = okay, 3 = RFU.\n"
2043   "   validity: validity as number (gpgme_validity_t)\n"
2044   "   validity_reason: (gpg_error_t)\n"
2045   "  Array values:\n"
2046   "   notations: Notation data and policy urls (gpgme_sig_notation_t)\n"
2047   "    Boolean values:\n"
2048   "     human_readable\n"
2049   "     critical\n"
2050   "    String values:\n"
2051   "     name\n"
2052   "     value\n"
2053   "    Number values:\n"
2054   "     flags\n";
2055 static gpg_error_t
2056 op_verify (cjson_t request, cjson_t result)
2057 {
2058   gpg_error_t err;
2059   gpgme_ctx_t ctx = NULL;
2060   gpgme_protocol_t protocol;
2061   gpgme_data_t input = NULL;
2062   gpgme_data_t signature = NULL;
2063   gpgme_data_t output = NULL;
2064   gpgme_verify_result_t verify_result;
2065
2066   if ((err = get_protocol (request, &protocol)))
2067     goto leave;
2068   ctx = get_context (protocol);
2069
2070   if ((err = get_string_data (request, result, "data", &input)))
2071     goto leave;
2072
2073   err = get_string_data (request, result, "signature", &signature);
2074   /* Signature data is optional otherwise we expect opaque or clearsigned. */
2075   if (err && err != gpg_error (GPG_ERR_NO_DATA))
2076     goto leave;
2077
2078   /* Create an output data object.  */
2079   err = gpgme_data_new (&output);
2080   if (err)
2081     {
2082       gpg_error_object (result, err, "Error creating output data object: %s",
2083                         gpg_strerror (err));
2084       goto leave;
2085     }
2086
2087   /* Verify.  */
2088   if (signature)
2089     {
2090       err = gpgme_op_verify (ctx, signature, input, output);
2091     }
2092   else
2093     {
2094       err = gpgme_op_verify (ctx, input, 0, output);
2095     }
2096   if (err)
2097     {
2098       gpg_error_object (result, err, "Verify failed: %s", gpg_strerror (err));
2099       goto leave;
2100     }
2101   gpgme_data_release (input);
2102   input = NULL;
2103   gpgme_data_release (signature);
2104   signature = NULL;
2105
2106   verify_result = gpgme_op_verify_result (ctx);
2107   if (verify_result && verify_result->signatures)
2108     {
2109       xjson_AddItemToObject (result, "info",
2110                              verify_result_to_json (verify_result));
2111     }
2112
2113   err = make_data_object (result, output, "plaintext", -1);
2114   output = NULL;
2115
2116   if (err)
2117     {
2118       gpg_error_object (result, err, "Plaintext output failed: %s",
2119                         gpg_strerror (err));
2120       goto leave;
2121     }
2122
2123  leave:
2124   release_context (ctx);
2125   gpgme_data_release (input);
2126   gpgme_data_release (output);
2127   gpgme_data_release (signature);
2128   return err;
2129 }
2130
2131
2132 \f
2133 static const char hlp_version[] =
2134   "op:     \"version\"\n"
2135   "\n"
2136   "Response on success:\n"
2137   "gpgme:  The GPGME Version.\n"
2138   "info:   dump of engine info. containing:\n"
2139   "        protocol: The protocol.\n"
2140   "        fname:    The file name.\n"
2141   "        version:  The version.\n"
2142   "        req_ver:  The required version.\n"
2143   "        homedir:  The homedir of the engine or \"default\".\n";
2144 static gpg_error_t
2145 op_version (cjson_t request, cjson_t result)
2146 {
2147   gpg_error_t err = 0;
2148   gpgme_engine_info_t ei = NULL;
2149   cjson_t infos = xjson_CreateArray ();
2150
2151   (void)request;
2152
2153   if (!cJSON_AddStringToObject (result, "gpgme", gpgme_check_version (NULL)))
2154     {
2155       cJSON_Delete (infos);
2156       return gpg_error_from_syserror ();
2157     }
2158
2159   if ((err = gpgme_get_engine_info (&ei)))
2160     {
2161       cJSON_Delete (infos);
2162       return err;
2163     }
2164
2165   for (; ei; ei = ei->next)
2166     cJSON_AddItemToArray (infos, engine_info_to_json (ei));
2167
2168   if (!cJSON_AddItemToObject (result, "info", infos))
2169     {
2170       err = gpg_error_from_syserror ();
2171       cJSON_Delete (infos);
2172       return err;
2173     }
2174
2175   return 0;
2176 }
2177
2178
2179 \f
2180 static const char hlp_keylist[] =
2181   "op:     \"keylist\"\n"
2182   "\n"
2183   "Optional parameters:\n"
2184   "keys:          Array of strings or fingerprints to lookup\n"
2185   "               For a single key a String may be used instead of an array.\n"
2186   "               default lists all keys.\n"
2187   "protocol:      Either \"openpgp\" (default) or \"cms\".\n"
2188   "\n"
2189   "Optional boolean flags (default is false):\n"
2190   "secret:        List only secret keys.\n"
2191   "with-secret:   Add KEYLIST_MODE_WITH_SECRET.\n"
2192   "extern:        Add KEYLIST_MODE_EXTERN.\n"
2193   "local:         Add KEYLIST_MODE_LOCAL. (default mode).\n"
2194   "sigs:          Add KEYLIST_MODE_SIGS.\n"
2195   "notations:     Add KEYLIST_MODE_SIG_NOTATIONS.\n"
2196   "tofu:          Add KEYLIST_MODE_WITH_TOFU.\n"
2197   "ephemeral:     Add KEYLIST_MODE_EPHEMERAL.\n"
2198   "validate:      Add KEYLIST_MODE_VALIDATE.\n"
2199   "locate:        Add KEYLIST_MODE_LOCATE.\n"
2200   "\n"
2201   "Response on success:\n"
2202   "keys:   Array of keys.\n"
2203   "  Boolean values:\n"
2204   "   revoked\n"
2205   "   expired\n"
2206   "   disabled\n"
2207   "   invalid\n"
2208   "   can_encrypt\n"
2209   "   can_sign\n"
2210   "   can_certify\n"
2211   "   can_authenticate\n"
2212   "   secret\n"
2213   "   is_qualified\n"
2214   "  String values:\n"
2215   "   protocol\n"
2216   "   issuer_serial (CMS Only)\n"
2217   "   issuer_name (CMS Only)\n"
2218   "   chain_id (CMS Only)\n"
2219   "   owner_trust (OpenPGP only)\n"
2220   "   fingerprint\n"
2221   "  Number values:\n"
2222   "   last_update\n"
2223   "   origin\n"
2224   "  Array values:\n"
2225   "   subkeys\n"
2226   "    Boolean values:\n"
2227   "     revoked\n"
2228   "     expired\n"
2229   "     disabled\n"
2230   "     invalid\n"
2231   "     can_encrypt\n"
2232   "     can_sign\n"
2233   "     can_certify\n"
2234   "     can_authenticate\n"
2235   "     secret\n"
2236   "     is_qualified\n"
2237   "     is_cardkey\n"
2238   "     is_de_vs\n"
2239   "    String values:\n"
2240   "     pubkey_algo_name\n"
2241   "     pubkey_algo_string\n"
2242   "     keyid\n"
2243   "     card_number\n"
2244   "     curve\n"
2245   "     keygrip\n"
2246   "    Number values:\n"
2247   "     pubkey_algo\n"
2248   "     length\n"
2249   "     timestamp\n"
2250   "     expires\n"
2251   "   userids\n"
2252   "    Boolean values:\n"
2253   "     revoked\n"
2254   "     invalid\n"
2255   "    String values:\n"
2256   "     validity\n"
2257   "     uid\n"
2258   "     name\n"
2259   "     email\n"
2260   "     comment\n"
2261   "     address\n"
2262   "    Number values:\n"
2263   "     origin\n"
2264   "     last_update\n"
2265   "    Array values:\n"
2266   "     signatures\n"
2267   "      Boolean values:\n"
2268   "       revoked\n"
2269   "       expired\n"
2270   "       invalid\n"
2271   "       exportable\n"
2272   "      String values:\n"
2273   "       pubkey_algo_name\n"
2274   "       keyid\n"
2275   "       status\n"
2276   "       uid\n"
2277   "       name\n"
2278   "       email\n"
2279   "       comment\n"
2280   "      Number values:\n"
2281   "       pubkey_algo\n"
2282   "       timestamp\n"
2283   "       expires\n"
2284   "       status_code\n"
2285   "       sig_class\n"
2286   "      Array values:\n"
2287   "       notations\n"
2288   "        Boolean values:\n"
2289   "         human_readable\n"
2290   "         critical\n"
2291   "        String values:\n"
2292   "         name\n"
2293   "         value\n"
2294   "        Number values:\n"
2295   "         flags\n"
2296   "     tofu\n"
2297   "      String values:\n"
2298   "       description\n"
2299   "      Number values:\n"
2300   "       validity\n"
2301   "       policy\n"
2302   "       signcount\n"
2303   "       encrcount\n"
2304   "       signfirst\n"
2305   "       signlast\n"
2306   "       encrfirst\n"
2307   "       encrlast\n";
2308 static gpg_error_t
2309 op_keylist (cjson_t request, cjson_t result)
2310 {
2311   gpg_error_t err;
2312   gpgme_ctx_t ctx = NULL;
2313   gpgme_protocol_t protocol;
2314   char **patterns = NULL;
2315   int abool;
2316   int secret_only = 0;
2317   gpgme_keylist_mode_t mode = 0;
2318   gpgme_key_t key = NULL;
2319   cjson_t keyarray = xjson_CreateArray ();
2320
2321   if ((err = get_protocol (request, &protocol)))
2322     goto leave;
2323   ctx = get_context (protocol);
2324
2325   /* Handle the various keylist mode bools. */
2326   if ((err = get_boolean_flag (request, "secret", 0, &abool)))
2327     goto leave;
2328   if (abool)
2329     {
2330       mode |= GPGME_KEYLIST_MODE_WITH_SECRET;
2331       secret_only = 1;
2332     }
2333   if ((err = get_boolean_flag (request, "with-secret", 0, &abool)))
2334     goto leave;
2335   if (abool)
2336     mode |= GPGME_KEYLIST_MODE_WITH_SECRET;
2337   if ((err = get_boolean_flag (request, "extern", 0, &abool)))
2338     goto leave;
2339   if (abool)
2340     mode |= GPGME_KEYLIST_MODE_EXTERN;
2341
2342   if ((err = get_boolean_flag (request, "local", 0, &abool)))
2343     goto leave;
2344   if (abool)
2345     mode |= GPGME_KEYLIST_MODE_LOCAL;
2346
2347   if ((err = get_boolean_flag (request, "sigs", 0, &abool)))
2348     goto leave;
2349   if (abool)
2350     mode |= GPGME_KEYLIST_MODE_SIGS;
2351
2352   if ((err = get_boolean_flag (request, "notations", 0, &abool)))
2353     goto leave;
2354   if (abool)
2355     mode |= GPGME_KEYLIST_MODE_SIG_NOTATIONS;
2356
2357   if ((err = get_boolean_flag (request, "tofu", 0, &abool)))
2358     goto leave;
2359   if (abool)
2360     mode |= GPGME_KEYLIST_MODE_WITH_TOFU;
2361
2362   if ((err = get_boolean_flag (request, "ephemeral", 0, &abool)))
2363     goto leave;
2364   if (abool)
2365     mode |= GPGME_KEYLIST_MODE_EPHEMERAL;
2366
2367   if ((err = get_boolean_flag (request, "validate", 0, &abool)))
2368     goto leave;
2369   if (abool)
2370     mode |= GPGME_KEYLIST_MODE_VALIDATE;
2371
2372   if ((err = get_boolean_flag (request, "locate", 0, &abool)))
2373     goto leave;
2374   if (abool)
2375     mode |= GPGME_KEYLIST_MODE_LOCATE;
2376
2377   if (!mode)
2378     {
2379       /* default to local */
2380       mode = GPGME_KEYLIST_MODE_LOCAL;
2381     }
2382
2383   /* Get the keys.  */
2384   patterns = create_keylist_patterns (request, "keys");
2385
2386   /* Do a keylisting and add the keys */
2387   gpgme_set_keylist_mode (ctx, mode);
2388
2389   err = gpgme_op_keylist_ext_start (ctx, (const char **) patterns,
2390                                     secret_only, 0);
2391   if (err)
2392     {
2393       gpg_error_object (result, err, "Error listing keys: %s",
2394                         gpg_strerror (err));
2395       goto leave;
2396     }
2397
2398   while (!(err = gpgme_op_keylist_next (ctx, &key)))
2399     {
2400       cJSON_AddItemToArray (keyarray, key_to_json (key));
2401       gpgme_key_unref (key);
2402     }
2403   err = 0;
2404
2405   if (!cJSON_AddItemToObject (result, "keys", keyarray))
2406     {
2407       err = gpg_error_from_syserror ();
2408       goto leave;
2409     }
2410
2411  leave:
2412   xfree_array (patterns);
2413   if (err)
2414     {
2415       cJSON_Delete (keyarray);
2416     }
2417   return err;
2418 }
2419
2420
2421 \f
2422 static const char hlp_import[] =
2423   "op:     \"import\"\n"
2424   "data:   The data to import.\n"
2425   "\n"
2426   "Optional parameters:\n"
2427   "protocol:      Either \"openpgp\" (default) or \"cms\".\n"
2428   "\n"
2429   "Optional boolean flags (default is false):\n"
2430   "base64:        Input data is base64 encoded.\n"
2431   "\n"
2432   "Response on success:\n"
2433   "result: The import result.\n"
2434   "  Number values:\n"
2435   "   considered\n"
2436   "   no_user_id\n"
2437   "   imported\n"
2438   "   imported_rsa\n"
2439   "   unchanged\n"
2440   "   new_user_ids\n"
2441   "   new_sub_keys\n"
2442   "   new_signatures\n"
2443   "   new_revocations\n"
2444   "   secret_read\n"
2445   "   secret_imported\n"
2446   "   secret_unchanged\n"
2447   "   skipped_new_keys\n"
2448   "   not_imported\n"
2449   "   skipped_v3_keys\n"
2450   "  Array values:\n"
2451   "   imports: List of keys for which an import was attempted\n"
2452   "    String values:\n"
2453   "     fingerprint\n"
2454   "     error_string\n"
2455   "    Number values:\n"
2456   "     error_code\n"
2457   "     status\n";
2458 static gpg_error_t
2459 op_import (cjson_t request, cjson_t result)
2460 {
2461   gpg_error_t err;
2462   gpgme_ctx_t ctx = NULL;
2463   gpgme_data_t input = NULL;
2464   gpgme_import_result_t import_result;
2465   gpgme_protocol_t protocol;
2466
2467   if ((err = get_protocol (request, &protocol)))
2468     goto leave;
2469   ctx = get_context (protocol);
2470
2471   if ((err = get_string_data (request, result, "data", &input)))
2472       goto leave;
2473
2474   /* Import.  */
2475   err = gpgme_op_import (ctx, input);
2476   import_result = gpgme_op_import_result (ctx);
2477   if (err)
2478     {
2479       gpg_error_object (result, err, "Import failed: %s",
2480                         gpg_strerror (err));
2481       goto leave;
2482     }
2483   gpgme_data_release (input);
2484   input = NULL;
2485
2486   xjson_AddItemToObject (result, "result",
2487                          import_result_to_json (import_result));
2488
2489  leave:
2490   release_context (ctx);
2491   gpgme_data_release (input);
2492   return err;
2493 }
2494
2495
2496 static const char hlp_export[] =
2497   "op:     \"export\"\n"
2498   "\n"
2499   "Optional parameters:\n"
2500   "keys:          Array of strings or fingerprints to lookup\n"
2501   "               For a single key a String may be used instead of an array.\n"
2502   "               default exports all keys.\n"
2503   "protocol:      Either \"openpgp\" (default) or \"cms\".\n"
2504   "\n"
2505   "Optional boolean flags (default is false):\n"
2506   "armor:         Request output in armored format.\n"
2507   "extern:        Add EXPORT_MODE_EXTERN.\n"
2508   "minimal:       Add EXPORT_MODE_MINIMAL.\n"
2509   "raw:           Add EXPORT_MODE_RAW.\n"
2510   "pkcs12:        Add EXPORT_MODE_PKCS12.\n"
2511   "with-sec-fprs: Add the sec-fprs array to the result.\n"
2512   "\n"
2513   "Response on success:\n"
2514   "type:     \"keys\"\n"
2515   "data:     Unless armor mode is used a Base64 encoded binary.\n"
2516   "          In armor mode a string with an armored\n"
2517   "          OpenPGP or a PEM / PKCS12 key.\n"
2518   "base64:   Boolean indicating whether data is base64 encoded.\n"
2519   "sec-fprs: Optional, only if with-secret is set. An array containing\n"
2520   "          the fingerprints of the keys in the export for which a secret\n"
2521   "          key is available";
2522 static gpg_error_t
2523 op_export (cjson_t request, cjson_t result)
2524 {
2525   gpg_error_t err;
2526   gpgme_ctx_t ctx = NULL;
2527   gpgme_protocol_t protocol;
2528   char **patterns = NULL;
2529   int abool;
2530   int with_secret = 0;
2531   gpgme_export_mode_t mode = 0;
2532   gpgme_data_t output = NULL;
2533
2534   if ((err = get_protocol (request, &protocol)))
2535     goto leave;
2536   ctx = get_context (protocol);
2537
2538   if ((err = get_boolean_flag (request, "armor", 0, &abool)))
2539     goto leave;
2540   gpgme_set_armor (ctx, abool);
2541
2542   /* Handle the various export mode bools. */
2543   if ((err = get_boolean_flag (request, "secret", 0, &abool)))
2544     goto leave;
2545   if (abool)
2546     {
2547       err = gpg_error (GPG_ERR_FORBIDDEN);
2548       goto leave;
2549     }
2550
2551   if ((err = get_boolean_flag (request, "extern", 0, &abool)))
2552     goto leave;
2553   if (abool)
2554     mode |= GPGME_EXPORT_MODE_EXTERN;
2555
2556   if ((err = get_boolean_flag (request, "minimal", 0, &abool)))
2557     goto leave;
2558   if (abool)
2559     mode |= GPGME_EXPORT_MODE_MINIMAL;
2560
2561   if ((err = get_boolean_flag (request, "raw", 0, &abool)))
2562     goto leave;
2563   if (abool)
2564     mode |= GPGME_EXPORT_MODE_RAW;
2565
2566   if ((err = get_boolean_flag (request, "pkcs12", 0, &abool)))
2567     goto leave;
2568   if (abool)
2569     mode |= GPGME_EXPORT_MODE_PKCS12;
2570
2571   if ((err = get_boolean_flag (request, "with-sec-fprs", 0, &abool)))
2572     goto leave;
2573   if (abool)
2574     with_secret = 1;
2575
2576   /* Get the export patterns.  */
2577   patterns = create_keylist_patterns (request, "keys");
2578
2579   /* Create an output data object.  */
2580   err = gpgme_data_new (&output);
2581   if (err)
2582     {
2583       gpg_error_object (result, err, "Error creating output data object: %s",
2584                         gpg_strerror (err));
2585       goto leave;
2586     }
2587
2588   err = gpgme_op_export_ext (ctx, (const char **) patterns,
2589                              mode, output);
2590   if (err)
2591     {
2592       gpg_error_object (result, err, "Error exporting keys: %s",
2593                         gpg_strerror (err));
2594       goto leave;
2595     }
2596
2597   /* We need to base64 if armoring has not been requested.  */
2598   err = make_data_object (result, output,
2599                           "keys", !gpgme_get_armor (ctx));
2600   output = NULL;
2601
2602   if (!err && with_secret)
2603     {
2604       err = add_secret_fprs ((const char **) patterns, protocol, result);
2605     }
2606
2607 leave:
2608   xfree_array (patterns);
2609   release_context (ctx);
2610   gpgme_data_release (output);
2611
2612   return err;
2613 }
2614
2615
2616 static const char hlp_delete[] =
2617   "op:     \"delete\"\n"
2618   "key:    Fingerprint of the key to delete.\n"
2619   "\n"
2620   "Optional parameters:\n"
2621   "protocol:      Either \"openpgp\" (default) or \"cms\".\n"
2622   "\n"
2623   "Response on success:\n"
2624   "success:   Boolean true.\n";
2625 static gpg_error_t
2626 op_delete (cjson_t request, cjson_t result)
2627 {
2628   gpg_error_t err;
2629   gpgme_ctx_t ctx = NULL;
2630   gpgme_ctx_t keylist_ctx = NULL;
2631   gpgme_protocol_t protocol;
2632   gpgme_key_t key = NULL;
2633   int secret = 0;
2634   cjson_t j_key = NULL;
2635
2636   if ((err = get_protocol (request, &protocol)))
2637     goto leave;
2638   ctx = get_context (protocol);
2639   keylist_ctx = get_context (protocol);
2640
2641   if ((err = get_boolean_flag (request, "secret", 0, &secret)))
2642     goto leave;
2643   if (secret)
2644     {
2645       err = gpg_error (GPG_ERR_FORBIDDEN);
2646       goto leave;
2647     }
2648
2649   j_key = cJSON_GetObjectItem (request, "key");
2650   if (!j_key)
2651     {
2652       err = gpg_error (GPG_ERR_NO_KEY);
2653       goto leave;
2654     }
2655   if (!cjson_is_string (j_key))
2656     {
2657       err = gpg_error (GPG_ERR_INV_VALUE);
2658       goto leave;
2659     }
2660
2661   /* Get the key */
2662   if ((err = gpgme_get_key (keylist_ctx, j_key->valuestring, &key, 0)))
2663     {
2664       gpg_error_object (result, err, "Error fetching key for delete: %s",
2665                         gpg_strerror (err));
2666       goto leave;
2667     }
2668
2669   err = gpgme_op_delete (ctx, key, 0);
2670   if (err)
2671     {
2672       gpg_error_object (result, err, "Error deleting key: %s",
2673                         gpg_strerror (err));
2674       goto leave;
2675     }
2676
2677   xjson_AddBoolToObject (result, "success", 1);
2678
2679 leave:
2680   gpgme_key_unref (key);
2681   release_context (ctx);
2682   release_context (keylist_ctx);
2683
2684   return err;
2685 }
2686
2687
2688 static const char hlp_config_opt[] =
2689   "op:       \"config_opt\"\n"
2690   "component: The component of the option.\n"
2691   "option:    The name of the option.\n"
2692   "\n"
2693   "Response on success:\n"
2694   "\n"
2695   "option: Information about the option.\n"
2696   " String values:\n"
2697   "  name: The name of the option\n"
2698   "  description: Localized description of the opt.\n"
2699   "  argname: Thhe argument name e.g. --verbose\n"
2700   "  default_description\n"
2701   "  no_arg_description\n"
2702   " Number values:\n"
2703   "  flags: Flags for this option.\n"
2704   "  level: the level of the description. See gpgme_conf_level_t.\n"
2705   "  type: The type of the option. See gpgme_conf_type_t.\n"
2706   "  alt_type: Alternate type of the option. See gpgme_conf_type_t\n"
2707   " Arg type values: (see desc. below)\n"
2708   "  default_value: Array of the default value.\n"
2709   "  no_arg_value: Array of the value if it is not set.\n"
2710   "  value: Array for the current value if the option is set.\n"
2711   "\n"
2712   "If the response is empty the option was not found\n"
2713   "";
2714 static gpg_error_t
2715 op_config_opt (cjson_t request, cjson_t result)
2716 {
2717   gpg_error_t err;
2718   gpgme_ctx_t ctx = NULL;
2719   gpgme_conf_comp_t conf = NULL;
2720   gpgme_conf_comp_t comp = NULL;
2721   cjson_t j_tmp;
2722   char *comp_name = NULL;
2723   char *opt_name = NULL;
2724
2725   ctx = get_context (GPGME_PROTOCOL_GPGCONF);
2726
2727   j_tmp = cJSON_GetObjectItem (request, "component");
2728   if (!j_tmp || !cjson_is_string (j_tmp))
2729     {
2730       err = gpg_error (GPG_ERR_INV_VALUE);
2731       goto leave;
2732     }
2733   comp_name = j_tmp->valuestring;
2734
2735
2736   j_tmp = cJSON_GetObjectItem (request, "option");
2737   if (!j_tmp || !cjson_is_string (j_tmp))
2738     {
2739       err = gpg_error (GPG_ERR_INV_VALUE);
2740       goto leave;
2741     }
2742   opt_name = j_tmp->valuestring;
2743
2744   /* Load the config */
2745   err = gpgme_op_conf_load (ctx, &conf);
2746   if (err)
2747     {
2748       goto leave;
2749     }
2750
2751   comp = conf;
2752   for (comp = conf; comp; comp = comp->next)
2753     {
2754       gpgme_conf_opt_t opt = NULL;
2755       int found = 0;
2756       if (!comp->name || strcmp (comp->name, comp_name))
2757         {
2758           /* Skip components if a single one is specified */
2759           continue;
2760         }
2761       for (opt = comp->options; opt; opt = opt->next)
2762         {
2763           if (!opt->name || strcmp (opt->name, opt_name))
2764             {
2765               /* Skip components if a single one is specified */
2766               continue;
2767             }
2768           xjson_AddItemToObject (result, "option", conf_opt_to_json (opt));
2769           found = 1;
2770           break;
2771         }
2772       if (found)
2773         break;
2774     }
2775
2776 leave:
2777   gpgme_conf_release (conf);
2778   release_context (ctx);
2779
2780   return err;
2781 }
2782
2783
2784 static const char hlp_config[] =
2785   "op:     \"config\"\n"
2786   "\n"
2787   "Optional parameters:\n"
2788   "component:    Component of entries to list.\n"
2789   "              Default: all\n"
2790   "\n"
2791   "Response on success:\n"
2792   "   components: Array of the component program configs.\n"
2793   "     name:         The component name.\n"
2794   "     description:  Description of the component.\n"
2795   "     program_name: The absolute path to the program.\n"
2796   "     options: Array of config options\n"
2797   "      String values:\n"
2798   "       name: The name of the option\n"
2799   "       description: Localized description of the opt.\n"
2800   "       argname: Thhe argument name e.g. --verbose\n"
2801   "       default_description\n"
2802   "       no_arg_description\n"
2803   "      Number values:\n"
2804   "       flags: Flags for this option.\n"
2805   "       level: the level of the description. See gpgme_conf_level_t.\n"
2806   "       type: The type of the option. See gpgme_conf_type_t.\n"
2807   "       alt_type: Alternate type of the option. See gpgme_conf_type_t\n"
2808   "      Arg type values: (see desc. below)\n"
2809   "       default_value: Array of the default value.\n"
2810   "       no_arg_value: Array of the value if it is not set.\n"
2811   "       value: Array for the current value if the option is set.\n"
2812   "\n"
2813   "Conf type values are an array of values that are either\n"
2814   "of type number named \"number\" or of type string,\n"
2815   "named \"string\".\n"
2816   "If the type is none the bool value is_none is true.\n"
2817   "";
2818 static gpg_error_t
2819 op_config (cjson_t request, cjson_t result)
2820 {
2821   gpg_error_t err;
2822   gpgme_ctx_t ctx = NULL;
2823   gpgme_conf_comp_t conf = NULL;
2824   gpgme_conf_comp_t comp = NULL;
2825   cjson_t j_tmp;
2826   char *comp_name = NULL;
2827   cjson_t j_comps = xjson_CreateArray ();
2828
2829   ctx = get_context (GPGME_PROTOCOL_GPGCONF);
2830
2831   j_tmp = cJSON_GetObjectItem (request, "component");
2832   if (j_tmp && cjson_is_string (j_tmp))
2833     {
2834       comp_name = j_tmp->valuestring;
2835     }
2836   else if (j_tmp && !cjson_is_string (j_tmp))
2837     {
2838       err = gpg_error (GPG_ERR_INV_VALUE);
2839       goto leave;
2840     }
2841
2842   /* Load the config */
2843   err = gpgme_op_conf_load (ctx, &conf);
2844   if (err)
2845     {
2846       goto leave;
2847     }
2848
2849   comp = conf;
2850   for (comp = conf; comp; comp = comp->next)
2851     {
2852       if (comp_name && comp->name && strcmp (comp->name, comp_name))
2853         {
2854           /* Skip components if a single one is specified */
2855           continue;
2856         }
2857       cJSON_AddItemToArray (j_comps, conf_comp_to_json (comp));
2858     }
2859   xjson_AddItemToObject (result, "components", j_comps);
2860
2861 leave:
2862   gpgme_conf_release (conf);
2863   release_context (ctx);
2864
2865   return err;
2866 }
2867
2868
2869 \f
2870 static const char hlp_createkey[] =
2871   "op:      \"createkey\"\n"
2872   "userid:  The user id. E.g. \"Foo Bar <foo@bar.baz>\"\n"
2873   "\n"
2874   "Optional parameters:\n"
2875   "algo:    Algo of the key as string. See doc for gpg --quick-gen-key.\n"
2876   "expires: Seconds since epoch to expiry as Number. 0 means no expiry.\n"
2877   "\n"
2878   "Response on success:\n"
2879   "fingerprint:   The fingerprint of the created key.\n"
2880   "\n"
2881   "Note: This interface does not allow key generation if the userid\n"
2882   "of the new key already exists in the keyring.\n";
2883 static gpg_error_t
2884 op_createkey (cjson_t request, cjson_t result)
2885 {
2886   gpg_error_t err;
2887   gpgme_ctx_t ctx = NULL;
2888   unsigned int flags = 0;
2889   unsigned long expires = 0;
2890   cjson_t j_tmp;
2891   const char *algo = "default";
2892   const char *userid;
2893   gpgme_genkey_result_t res;
2894
2895 #ifdef GPG_AGENT_ALLOWS_KEYGEN_TRHOUGH_BROWSER
2896   /* GnuPG forbids keygen through the browser socket so for
2897      this we create an unrestricted context.
2898      See GnuPG-Bug-Id: T4010 for more info */
2899   ctx = get_context (GPGME_PROTOCOL_OpenPGP);
2900 #else
2901     err = gpgme_new (&ctx);
2902   if (err)
2903     log_fatal ("error creating GPGME context: %s\n", gpg_strerror (err));
2904   gpgme_set_protocol (ctx, GPGME_PROTOCOL_OpenPGP);
2905 #endif
2906
2907   j_tmp = cJSON_GetObjectItem (request, "algo");
2908   if (j_tmp && cjson_is_string (j_tmp))
2909     {
2910       algo = j_tmp->valuestring;
2911     }
2912
2913   j_tmp = cJSON_GetObjectItem (request, "userid");
2914   if (!j_tmp || !cjson_is_string (j_tmp))
2915     {
2916       err = gpg_error (GPG_ERR_INV_VALUE);
2917       goto leave;
2918     }
2919
2920   userid = j_tmp->valuestring;
2921
2922   j_tmp = cJSON_GetObjectItem (request, "expires");
2923   if (j_tmp)
2924     {
2925       if (!cjson_is_number (j_tmp))
2926         {
2927           err = gpg_error (GPG_ERR_INV_VALUE);
2928           goto leave;
2929         }
2930       expires = j_tmp->valueint;
2931
2932       if (!expires)
2933         flags |= GPGME_CREATE_NOEXPIRE;
2934     }
2935
2936
2937   if ((err = gpgme_op_createkey (ctx, userid, algo, 0, expires, NULL, flags)))
2938     goto leave;
2939
2940   res = gpgme_op_genkey_result (ctx);
2941   if (!res)
2942     {
2943       err = gpg_error (GPG_ERR_GENERAL);
2944       goto leave;
2945     }
2946
2947   xjson_AddStringToObject0 (result, "fingerprint", res->fpr);
2948
2949 leave:
2950 #ifdef GPG_AGENT_ALLOWS_KEYGEN_TRHOUGH_BROWSER
2951   release_context (ctx);
2952 #else
2953   gpgme_release (ctx);
2954 #endif
2955
2956   return err;
2957 }
2958
2959
2960 \f
2961 static const char hlp_getmore[] =
2962   "op:     \"getmore\"\n"
2963   "\n"
2964   "Response on success:\n"
2965   "response:       base64 encoded json response.\n"
2966   "more:           Another getmore is required.\n"
2967   "base64:         boolean if the response is base64 encoded.\n";
2968 static gpg_error_t
2969 op_getmore (cjson_t request, cjson_t result)
2970 {
2971   gpg_error_t err;
2972   int c;
2973   size_t n;
2974   size_t chunksize;
2975
2976   if ((err = get_chunksize (request, &chunksize)))
2977     goto leave;
2978
2979   /* For the meta data we need 41 bytes:
2980      {"more":true,"base64":true,"response":""} */
2981   chunksize -= 41;
2982
2983   /* Adjust the chunksize for the base64 conversion.  */
2984   chunksize = (chunksize / 4) * 3;
2985
2986   /* Do we have anything pending?  */
2987   if (!pending_data.buffer)
2988     {
2989       err = gpg_error (GPG_ERR_NO_DATA);
2990       gpg_error_object (result, err, "Operation not possible: %s",
2991                         gpg_strerror (err));
2992       goto leave;
2993     }
2994
2995   /* We currently always use base64 encoding for simplicity. */
2996   xjson_AddBoolToObject (result, "base64", 1);
2997
2998   if (pending_data.written >= pending_data.length)
2999     {
3000       /* EOF reached.  This should not happen but we return an empty
3001        * string once in case of client errors.  */
3002       gpgme_free (pending_data.buffer);
3003       pending_data.buffer = NULL;
3004       xjson_AddBoolToObject (result, "more", 0);
3005       err = cjson_AddStringToObject (result, "response", "");
3006     }
3007   else
3008     {
3009       n = pending_data.length - pending_data.written;
3010       if (n > chunksize)
3011         {
3012           n = chunksize;
3013           xjson_AddBoolToObject (result, "more", 1);
3014         }
3015       else
3016         xjson_AddBoolToObject (result, "more", 0);
3017
3018       c = pending_data.buffer[pending_data.written + n];
3019       pending_data.buffer[pending_data.written + n] = 0;
3020       err = add_base64_to_object (result, "response",
3021                                   (pending_data.buffer
3022                                    + pending_data.written), n);
3023       pending_data.buffer[pending_data.written + n] = c;
3024       if (!err)
3025         {
3026           pending_data.written += n;
3027           if (pending_data.written >= pending_data.length)
3028             {
3029               xfree (pending_data.buffer);
3030               pending_data.buffer = NULL;
3031             }
3032         }
3033     }
3034
3035  leave:
3036   return err;
3037 }
3038
3039
3040 \f
3041 static const char hlp_help[] =
3042   "The tool expects a JSON object with the request and responds with\n"
3043   "another JSON object.  Even on error a JSON object is returned.  The\n"
3044   "property \"op\" is mandatory and its string value selects the\n"
3045   "operation; if the property \"help\" with the value \"true\" exists, the\n"
3046   "operation is not performned but a string with the documentation\n"
3047   "returned.  To list all operations it is allowed to leave out \"op\" in\n"
3048   "help mode.  Supported values for \"op\" are:\n\n"
3049   "  config      Read configuration values.\n"
3050   "  config_opt  Read a single configuration value.\n"
3051   "  decrypt     Decrypt data.\n"
3052   "  delete      Delete a key.\n"
3053   "  encrypt     Encrypt data.\n"
3054   "  export      Export keys.\n"
3055   "  createkey   Generate a keypair (OpenPGP only).\n"
3056   "  import      Import data.\n"
3057   "  keylist     List keys.\n"
3058   "  sign        Sign data.\n"
3059   "  verify      Verify data.\n"
3060   "  version     Get engine information.\n"
3061   "  getmore     Retrieve remaining data if chunksize was used.\n"
3062   "  help        Help overview.\n"
3063   "\n"
3064   "If the data needs to be transferred in smaller chunks the\n"
3065   "property \"chunksize\" with an integer value can be added.\n"
3066   "When \"chunksize\" is set the response (including json) will\n"
3067   "not be larger then \"chunksize\" but might be smaller.\n"
3068   "The chunked result will be transferred in base64 encoded chunks\n"
3069   "using the \"getmore\" operation. See help getmore for more info.";
3070 static gpg_error_t
3071 op_help (cjson_t request, cjson_t result)
3072 {
3073   cjson_t j_tmp;
3074   char *buffer = NULL;
3075   const char *msg;
3076
3077   j_tmp = cJSON_GetObjectItem (request, "interactive_help");
3078   if (opt_interactive && j_tmp && cjson_is_string (j_tmp))
3079     msg = buffer = xstrconcat (hlp_help, "\n", j_tmp->valuestring, NULL);
3080   else
3081     msg = hlp_help;
3082
3083   xjson_AddStringToObject (result, "type", "help");
3084   xjson_AddStringToObject (result, "msg", msg);
3085
3086   xfree (buffer);
3087   return 0;
3088 }
3089
3090
3091 \f
3092 /*
3093  * Dispatcher
3094  */
3095
3096 /* Process a request and return the response.  The response is a newly
3097  * allocated string or NULL in case of an error.  */
3098 static char *
3099 process_request (const char *request)
3100 {
3101   static struct {
3102     const char *op;
3103     gpg_error_t (*handler)(cjson_t request, cjson_t result);
3104     const char * const helpstr;
3105   } optbl[] = {
3106     { "config",     op_config,     hlp_config },
3107     { "config_opt", op_config_opt, hlp_config_opt },
3108     { "encrypt",    op_encrypt,    hlp_encrypt },
3109     { "export",     op_export,     hlp_export },
3110     { "decrypt",    op_decrypt,    hlp_decrypt },
3111     { "delete",     op_delete,     hlp_delete },
3112     { "createkey",  op_createkey,  hlp_createkey },
3113     { "keylist",    op_keylist,    hlp_keylist },
3114     { "import",     op_import,     hlp_import },
3115     { "sign",       op_sign,       hlp_sign },
3116     { "verify",     op_verify,     hlp_verify },
3117     { "version",    op_version,    hlp_version },
3118     { "getmore",    op_getmore,    hlp_getmore },
3119     { "help",       op_help,       hlp_help },
3120     { NULL }
3121   };
3122   size_t erroff;
3123   cjson_t json;
3124   cjson_t j_tmp, j_op;
3125   cjson_t response;
3126   int helpmode;
3127   int is_getmore = 0;
3128   const char *op;
3129   char *res = NULL;
3130   int idx;
3131
3132   response = xjson_CreateObject ();
3133
3134   json = cJSON_Parse (request, &erroff);
3135   if (!json)
3136     {
3137       log_string (GPGRT_LOGLVL_INFO, request);
3138       log_info ("invalid JSON object at offset %zu\n", erroff);
3139       error_object (response, "invalid JSON object at offset %zu\n", erroff);
3140       goto leave;
3141     }
3142
3143   j_tmp = cJSON_GetObjectItem (json, "help");
3144   helpmode = (j_tmp && cjson_is_true (j_tmp));
3145
3146   j_op = cJSON_GetObjectItem (json, "op");
3147   if (!j_op || !cjson_is_string (j_op))
3148     {
3149       if (!helpmode)
3150         {
3151           error_object (response, "Property \"op\" missing");
3152           goto leave;
3153         }
3154       op = "help";  /* Help summary.  */
3155     }
3156   else
3157     op = j_op->valuestring;
3158
3159   for (idx=0; optbl[idx].op; idx++)
3160     if (!strcmp (op, optbl[idx].op))
3161       break;
3162   if (optbl[idx].op)
3163     {
3164       if (helpmode && strcmp (op, "help"))
3165         {
3166           xjson_AddStringToObject (response, "type", "help");
3167           xjson_AddStringToObject (response, "op", op);
3168           xjson_AddStringToObject (response, "msg", optbl[idx].helpstr);
3169         }
3170       else
3171         {
3172           gpg_error_t err;
3173           is_getmore = optbl[idx].handler == op_getmore;
3174           /* If this is not the "getmore" command and we have any
3175            * pending data release that data.  */
3176           if (pending_data.buffer && optbl[idx].handler != op_getmore)
3177             {
3178               gpgme_free (pending_data.buffer);
3179               pending_data.buffer = NULL;
3180             }
3181
3182           err = optbl[idx].handler (json, response);
3183           if (err)
3184             {
3185               if (!(j_tmp = cJSON_GetObjectItem (response, "type"))
3186                   || !cjson_is_string (j_tmp)
3187                   || strcmp (j_tmp->valuestring, "error"))
3188                 {
3189                   /* No error type response - provide a generic one.  */
3190                   gpg_error_object (response, err, "Operation failed: %s",
3191                                     gpg_strerror (err));
3192                 }
3193
3194               xjson_AddStringToObject (response, "op", op);
3195             }
3196         }
3197     }
3198   else  /* Operation not supported.  */
3199     {
3200       error_object (response, "Unknown operation '%s'", op);
3201       xjson_AddStringToObject (response, "op", op);
3202     }
3203
3204  leave:
3205   if (is_getmore)
3206     {
3207       /* For getmore we bypass the encode_and_chunk. */
3208       if (opt_interactive)
3209         res = cJSON_Print (response);
3210       else
3211         res = cJSON_PrintUnformatted (response);
3212     }
3213   else
3214     res = encode_and_chunk (json, response);
3215   if (!res)
3216     {
3217       log_error ("Printing JSON data failed\n");
3218       cjson_t err_obj = error_object (NULL, "Printing JSON data failed");
3219       if (opt_interactive)
3220         res = cJSON_Print (err_obj);
3221       res = cJSON_PrintUnformatted (err_obj);
3222       cJSON_Delete (err_obj);
3223     }
3224
3225   cJSON_Delete (json);
3226   cJSON_Delete (response);
3227
3228   if (!res)
3229     {
3230       /* Can't happen unless we created a broken error_object above */
3231       return strdup ("Bug: Fatal error in process request\n");
3232     }
3233   return res;
3234 }
3235
3236
3237 \f
3238 /*
3239  *  Driver code
3240  */
3241
3242 static char *
3243 get_file (const char *fname)
3244 {
3245   gpg_error_t err;
3246   estream_t fp;
3247   struct stat st;
3248   char *buf;
3249   size_t buflen;
3250
3251   fp = es_fopen (fname, "r");
3252   if (!fp)
3253     {
3254       err = gpg_error_from_syserror ();
3255       log_error ("can't open '%s': %s\n", fname, gpg_strerror (err));
3256       return NULL;
3257     }
3258
3259   if (fstat (es_fileno(fp), &st))
3260     {
3261       err = gpg_error_from_syserror ();
3262       log_error ("can't stat '%s': %s\n", fname, gpg_strerror (err));
3263       es_fclose (fp);
3264       return NULL;
3265     }
3266
3267   buflen = st.st_size;
3268   buf = xmalloc (buflen+1);
3269   if (es_fread (buf, buflen, 1, fp) != 1)
3270     {
3271       err = gpg_error_from_syserror ();
3272       log_error ("error reading '%s': %s\n", fname, gpg_strerror (err));
3273       es_fclose (fp);
3274       xfree (buf);
3275       return NULL;
3276     }
3277   buf[buflen] = 0;
3278   es_fclose (fp);
3279
3280   return buf;
3281 }
3282
3283
3284 /* Return a malloced line or NULL on EOF.  Terminate on read
3285  * error.  */
3286 static char *
3287 get_line (void)
3288 {
3289   char *line = NULL;
3290   size_t linesize = 0;
3291   gpg_error_t err;
3292   size_t maxlength = 2048;
3293   int n;
3294   const char *s;
3295   char *p;
3296
3297  again:
3298   n = es_read_line (es_stdin, &line, &linesize, &maxlength);
3299   if (n < 0)
3300     {
3301       err = gpg_error_from_syserror ();
3302       log_error ("error reading line: %s\n", gpg_strerror (err));
3303       exit (1);
3304     }
3305   if (!n)
3306     {
3307       xfree (line);
3308       line = NULL;
3309       return NULL;  /* EOF */
3310     }
3311   if (!maxlength)
3312     {
3313       log_info ("line too long - skipped\n");
3314       goto again;
3315     }
3316   if (memchr (line, 0, n))
3317     log_info ("warning: line shortened due to embedded Nul character\n");
3318
3319   if (line[n-1] == '\n')
3320     line[n-1] = 0;
3321
3322   /* Trim leading spaces.  */
3323   for (s=line; spacep (s); s++)
3324     ;
3325   if (s != line)
3326     {
3327       for (p=line; *s;)
3328         *p++ = *s++;
3329       *p = 0;
3330       n = p - line;
3331     }
3332
3333   return line;
3334 }
3335
3336
3337 /* Process meta commands used with the standard REPL.  */
3338 static char *
3339 process_meta_commands (const char *request)
3340 {
3341   char *result = NULL;
3342
3343   while (spacep (request))
3344     request++;
3345
3346   if (!strncmp (request, "help", 4) && (spacep (request+4) || !request[4]))
3347     {
3348       if (request[4])
3349         {
3350           char *buf = xstrconcat ("{ \"help\":true, \"op\":\"", request+5,
3351                                   "\" }", NULL);
3352           result = process_request (buf);
3353           xfree (buf);
3354         }
3355       else
3356         result = process_request ("{ \"op\": \"help\","
3357                                   " \"interactive_help\": "
3358                                   "\"\\nMeta commands:\\n"
3359                                   "  ,read FNAME Process data from FILE\\n"
3360                                   "  ,help CMD   Print help for a command\\n"
3361                                   "  ,quit       Terminate process\""
3362                                   "}");
3363     }
3364   else if (!strncmp (request, "quit", 4) && (spacep (request+4) || !request[4]))
3365     exit (0);
3366   else if (!strncmp (request, "read", 4) && (spacep (request+4) || !request[4]))
3367     {
3368       if (!request[4])
3369         log_info ("usage: ,read FILENAME\n");
3370       else
3371         {
3372           char *buffer = get_file (request + 5);
3373           if (buffer)
3374             {
3375               result = process_request (buffer);
3376               xfree (buffer);
3377             }
3378         }
3379     }
3380   else
3381     log_info ("invalid meta command\n");
3382
3383   return result;
3384 }
3385
3386
3387 /* If STRING has a help response, return the MSG property in a human
3388  * readable format.  */
3389 static char *
3390 get_help_msg (const char *string)
3391 {
3392   cjson_t json, j_type, j_msg;
3393   const char *msg;
3394   char *buffer = NULL;
3395   char *p;
3396
3397   json = cJSON_Parse (string, NULL);
3398   if (json)
3399     {
3400       j_type = cJSON_GetObjectItem (json, "type");
3401       if (j_type && cjson_is_string (j_type)
3402           && !strcmp (j_type->valuestring, "help"))
3403         {
3404           j_msg = cJSON_GetObjectItem (json, "msg");
3405           if (j_msg || cjson_is_string (j_msg))
3406             {
3407               msg = j_msg->valuestring;
3408               buffer = malloc (strlen (msg)+1);
3409               if (buffer)
3410                 {
3411                   for (p=buffer; *msg; msg++)
3412                     {
3413                       if (*msg == '\\' && msg[1] == '\n')
3414                         *p++ = '\n';
3415                       else
3416                         *p++ = *msg;
3417                     }
3418                   *p = 0;
3419                 }
3420             }
3421         }
3422       cJSON_Delete (json);
3423     }
3424   return buffer;
3425 }
3426
3427
3428 /* An interactive standard REPL.  */
3429 static void
3430 interactive_repl (void)
3431 {
3432   char *line = NULL;
3433   char *request = NULL;
3434   char *response = NULL;
3435   char *p;
3436   int first;
3437
3438   es_setvbuf (es_stdin, NULL, _IONBF, 0);
3439 #if GPGRT_VERSION_NUMBER >= 0x011d00 /* 1.29 */
3440   es_fprintf (es_stderr, "%s %s ready (enter \",help\" for help)\n",
3441               gpgrt_strusage (11), gpgrt_strusage (13));
3442 #endif
3443   do
3444     {
3445       es_fputs ("> ", es_stderr);
3446       es_fflush (es_stderr);
3447       es_fflush (es_stdout);
3448       xfree (line);
3449       line = get_line ();
3450       es_fflush (es_stderr);
3451       es_fflush (es_stdout);
3452
3453       first = !request;
3454       if (line && *line)
3455         {
3456           if (!request)
3457             request = xstrdup (line);
3458           else
3459             request = xstrconcat (request, "\n", line, NULL);
3460         }
3461
3462       if (!line)
3463         es_fputs ("\n", es_stderr);
3464
3465       if (!line || !*line || (first && *request == ','))
3466         {
3467           /* Process the input.  */
3468           xfree (response);
3469           response = NULL;
3470           if (request && *request == ',')
3471             {
3472               response = process_meta_commands (request+1);
3473             }
3474           else if (request)
3475             {
3476               response = process_request (request);
3477             }
3478           xfree (request);
3479           request = NULL;
3480
3481           if (response)
3482             {
3483               if (opt_interactive)
3484                 {
3485                   char *msg = get_help_msg (response);
3486                   if (msg)
3487                     {
3488                       xfree (response);
3489                       response = msg;
3490                     }
3491                 }
3492
3493               es_fputs ("===> ", es_stderr);
3494               es_fflush (es_stderr);
3495               for (p=response; *p; p++)
3496                 {
3497                   if (*p == '\n')
3498                     {
3499                       es_fflush (es_stdout);
3500                       es_fputs ("\n===> ", es_stderr);
3501                       es_fflush (es_stderr);
3502                     }
3503                   else
3504                     es_putc (*p, es_stdout);
3505                 }
3506               es_fflush (es_stdout);
3507               es_fputs ("\n", es_stderr);
3508             }
3509         }
3510     }
3511   while (line);
3512
3513   xfree (request);
3514   xfree (response);
3515   xfree (line);
3516 }
3517
3518
3519 /* Read and process a single request.  */
3520 static void
3521 read_and_process_single_request (void)
3522 {
3523   char *line = NULL;
3524   char *request = NULL;
3525   char *response = NULL;
3526   size_t n;
3527
3528   for (;;)
3529     {
3530       xfree (line);
3531       line = get_line ();
3532       if (line && *line)
3533         request = (request? xstrconcat (request, "\n", line, NULL)
3534                    /**/   : xstrdup (line));
3535       if (!line)
3536         {
3537           if (request)
3538             {
3539               xfree (response);
3540               response = process_request (request);
3541               if (response)
3542                 {
3543                   es_fputs (response, es_stdout);
3544                   if ((n = strlen (response)) && response[n-1] != '\n')
3545                     es_fputc ('\n', es_stdout);
3546                 }
3547               es_fflush (es_stdout);
3548             }
3549           break;
3550         }
3551     }
3552
3553   xfree (response);
3554   xfree (request);
3555   xfree (line);
3556 }
3557
3558
3559 /* The Native Messaging processing loop.  */
3560 static void
3561 native_messaging_repl (void)
3562 {
3563   gpg_error_t err;
3564   uint32_t nrequest, nresponse;
3565   char *request = NULL;
3566   char *response = NULL;
3567   size_t n;
3568
3569   /* Due to the length octets we need to switch the I/O stream into
3570    * binary mode.  */
3571   es_set_binary (es_stdin);
3572   es_set_binary (es_stdout);
3573   es_setbuf (es_stdin, NULL);  /* stdin needs to be unbuffered! */
3574
3575   for (;;)
3576     {
3577       /* Read length.  Note that the protocol uses native endianess.
3578        * Is it allowed to call such a thing a well thought out
3579        * protocol?  */
3580       if (es_read (es_stdin, &nrequest, sizeof nrequest, &n))
3581         {
3582           err = gpg_error_from_syserror ();
3583           log_error ("error reading request header: %s\n", gpg_strerror (err));
3584           break;
3585         }
3586       if (!n)
3587         break;  /* EOF */
3588       if (n != sizeof nrequest)
3589         {
3590           log_error ("error reading request header: short read\n");
3591           break;
3592         }
3593       if (nrequest > MAX_REQUEST_SIZE)
3594         {
3595           log_error ("error reading request: request too long (%zu MiB)\n",
3596                      (size_t)nrequest / (1024*1024));
3597           /* Fixme: Shall we read the request to the bit bucket and
3598            * return an error reponse or just return an error reponse
3599            * and terminate?  Needs some testing.  */
3600           break;
3601         }
3602
3603       /* Read request.  */
3604       request = xtrymalloc (nrequest + 1);
3605       if (!request)
3606         {
3607           err = gpg_error_from_syserror ();
3608           log_error ("error reading request: Not enough memory for %zu MiB)\n",
3609                      (size_t)nrequest / (1024*1024));
3610           /* FIXME: See comment above.  */
3611           break;
3612         }
3613       if (es_read (es_stdin, request, nrequest, &n))
3614         {
3615           err = gpg_error_from_syserror ();
3616           log_error ("error reading request: %s\n", gpg_strerror (err));
3617           break;
3618         }
3619       if (n != nrequest)
3620         {
3621           /* That is a protocol violation.  */
3622           xfree (response);
3623           response = error_object_string ("Invalid request:"
3624                                           " short read (%zu of %zu bytes)\n",
3625                                           n, (size_t)nrequest);
3626         }
3627       else /* Process request  */
3628         {
3629           request[n] = '\0'; /* Esnure that request has an end */
3630           if (opt_debug)
3631             log_debug ("request='%s'\n", request);
3632           xfree (response);
3633           response = process_request (request);
3634           if (opt_debug)
3635             log_debug ("response='%s'\n", response);
3636         }
3637       nresponse = strlen (response);
3638
3639       /* Write response */
3640       if (es_write (es_stdout, &nresponse, sizeof nresponse, &n))
3641         {
3642           err = gpg_error_from_syserror ();
3643           log_error ("error writing request header: %s\n", gpg_strerror (err));
3644           break;
3645         }
3646       if (n != sizeof nrequest)
3647         {
3648           log_error ("error writing request header: short write\n");
3649           break;
3650         }
3651       if (es_write (es_stdout, response, nresponse, &n))
3652         {
3653           err = gpg_error_from_syserror ();
3654           log_error ("error writing request: %s\n", gpg_strerror (err));
3655           break;
3656         }
3657       if (n != nresponse)
3658         {
3659           log_error ("error writing request: short write\n");
3660           break;
3661         }
3662       if (es_fflush (es_stdout) || es_ferror (es_stdout))
3663         {
3664           err = gpg_error_from_syserror ();
3665           log_error ("error writing request: %s\n", gpg_strerror (err));
3666           break;
3667         }
3668       xfree (response);
3669       response = NULL;
3670       xfree (request);
3671       request = NULL;
3672     }
3673
3674   xfree (response);
3675   xfree (request);
3676 }
3677
3678
3679 \f
3680 static const char *
3681 my_strusage( int level )
3682 {
3683   const char *p;
3684
3685   switch (level)
3686     {
3687     case  9: p = "LGPL-2.1-or-later"; break;
3688     case 11: p = "gpgme-json"; break;
3689     case 13: p = PACKAGE_VERSION; break;
3690     case 14: p = "Copyright (C) 2018 g10 Code GmbH"; break;
3691     case 19: p = "Please report bugs to <" PACKAGE_BUGREPORT ">.\n"; break;
3692     case 1:
3693     case 40:
3694       p = "Usage: gpgme-json [OPTIONS]";
3695       break;
3696     case 41:
3697       p = "Native messaging based GPGME operations.\n";
3698       break;
3699     case 42:
3700       p = "1"; /* Flag