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