json: Delete primary key if subkey gen fails
[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   /* Create an output data object.  */
2177   err = gpgme_data_new (&output);
2178   if (err)
2179     {
2180       gpg_error_object (result, err, "Error creating output data object: %s",
2181                         gpg_strerror (err));
2182       goto leave;
2183     }
2184
2185   /* Verify.  */
2186   if (signature)
2187     {
2188       err = gpgme_op_verify (ctx, signature, input, output);
2189     }
2190   else
2191     {
2192       err = gpgme_op_verify (ctx, input, 0, output);
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   err = make_data_object (result, output, "plaintext", -1);
2212   output = NULL;
2213
2214   if (err)
2215     {
2216       gpg_error_object (result, err, "Plaintext output failed: %s",
2217                         gpg_strerror (err));
2218       goto leave;
2219     }
2220
2221  leave:
2222   release_context (ctx);
2223   gpgme_data_release (input);
2224   gpgme_data_release (output);
2225   gpgme_data_release (signature);
2226   return err;
2227 }
2228
2229
2230 \f
2231 static const char hlp_version[] =
2232   "op:     \"version\"\n"
2233   "\n"
2234   "Response on success:\n"
2235   "gpgme:  The GPGME Version.\n"
2236   "info:   dump of engine info. containing:\n"
2237   "        protocol: The protocol.\n"
2238   "        fname:    The file name.\n"
2239   "        version:  The version.\n"
2240   "        req_ver:  The required version.\n"
2241   "        homedir:  The homedir of the engine or \"default\".\n";
2242 static gpg_error_t
2243 op_version (cjson_t request, cjson_t result)
2244 {
2245   gpg_error_t err = 0;
2246   gpgme_engine_info_t ei = NULL;
2247   cjson_t infos = xjson_CreateArray ();
2248
2249   (void)request;
2250
2251   if (!cJSON_AddStringToObject (result, "gpgme", gpgme_check_version (NULL)))
2252     {
2253       cJSON_Delete (infos);
2254       return gpg_error_from_syserror ();
2255     }
2256
2257   if ((err = gpgme_get_engine_info (&ei)))
2258     {
2259       cJSON_Delete (infos);
2260       return err;
2261     }
2262
2263   for (; ei; ei = ei->next)
2264     cJSON_AddItemToArray (infos, engine_info_to_json (ei));
2265
2266   if (!cJSON_AddItemToObject (result, "info", infos))
2267     {
2268       err = gpg_error_from_syserror ();
2269       cJSON_Delete (infos);
2270       return err;
2271     }
2272
2273   return 0;
2274 }
2275
2276
2277 \f
2278 static const char hlp_keylist[] =
2279   "op:     \"keylist\"\n"
2280   "\n"
2281   "Optional parameters:\n"
2282   "keys:          Array of strings or fingerprints to lookup\n"
2283   "               For a single key a String may be used instead of an array.\n"
2284   "               default lists all keys.\n"
2285   "protocol:      Either \"openpgp\" (default) or \"cms\".\n"
2286   "\n"
2287   "Optional boolean flags (default is false):\n"
2288   "secret:        List only secret keys.\n"
2289   "with-secret:   Add KEYLIST_MODE_WITH_SECRET.\n"
2290   "extern:        Add KEYLIST_MODE_EXTERN.\n"
2291   "local:         Add KEYLIST_MODE_LOCAL. (default mode).\n"
2292   "sigs:          Add KEYLIST_MODE_SIGS.\n"
2293   "notations:     Add KEYLIST_MODE_SIG_NOTATIONS.\n"
2294   "tofu:          Add KEYLIST_MODE_WITH_TOFU.\n"
2295   "ephemeral:     Add KEYLIST_MODE_EPHEMERAL.\n"
2296   "validate:      Add KEYLIST_MODE_VALIDATE.\n"
2297   "locate:        Add KEYLIST_MODE_LOCATE.\n"
2298   "\n"
2299   "Response on success:\n"
2300   "keys:   Array of keys.\n"
2301   "  Boolean values:\n"
2302   "   revoked\n"
2303   "   expired\n"
2304   "   disabled\n"
2305   "   invalid\n"
2306   "   can_encrypt\n"
2307   "   can_sign\n"
2308   "   can_certify\n"
2309   "   can_authenticate\n"
2310   "   secret\n"
2311   "   is_qualified\n"
2312   "  String values:\n"
2313   "   protocol\n"
2314   "   issuer_serial (CMS Only)\n"
2315   "   issuer_name (CMS Only)\n"
2316   "   chain_id (CMS Only)\n"
2317   "   owner_trust (OpenPGP only)\n"
2318   "   fingerprint\n"
2319   "  Number values:\n"
2320   "   last_update\n"
2321   "   origin\n"
2322   "  Array values:\n"
2323   "   subkeys\n"
2324   "    Boolean values:\n"
2325   "     revoked\n"
2326   "     expired\n"
2327   "     disabled\n"
2328   "     invalid\n"
2329   "     can_encrypt\n"
2330   "     can_sign\n"
2331   "     can_certify\n"
2332   "     can_authenticate\n"
2333   "     secret\n"
2334   "     is_qualified\n"
2335   "     is_cardkey\n"
2336   "     is_de_vs\n"
2337   "    String values:\n"
2338   "     pubkey_algo_name\n"
2339   "     pubkey_algo_string\n"
2340   "     keyid\n"
2341   "     card_number\n"
2342   "     curve\n"
2343   "     keygrip\n"
2344   "    Number values:\n"
2345   "     pubkey_algo\n"
2346   "     length\n"
2347   "     timestamp\n"
2348   "     expires\n"
2349   "   userids\n"
2350   "    Boolean values:\n"
2351   "     revoked\n"
2352   "     invalid\n"
2353   "    String values:\n"
2354   "     validity\n"
2355   "     uid\n"
2356   "     name\n"
2357   "     email\n"
2358   "     comment\n"
2359   "     address\n"
2360   "    Number values:\n"
2361   "     origin\n"
2362   "     last_update\n"
2363   "    Array values:\n"
2364   "     signatures\n"
2365   "      Boolean values:\n"
2366   "       revoked\n"
2367   "       expired\n"
2368   "       invalid\n"
2369   "       exportable\n"
2370   "      String values:\n"
2371   "       pubkey_algo_name\n"
2372   "       keyid\n"
2373   "       status\n"
2374   "       uid\n"
2375   "       name\n"
2376   "       email\n"
2377   "       comment\n"
2378   "      Number values:\n"
2379   "       pubkey_algo\n"
2380   "       timestamp\n"
2381   "       expires\n"
2382   "       status_code\n"
2383   "       sig_class\n"
2384   "      Array values:\n"
2385   "       notations\n"
2386   "        Boolean values:\n"
2387   "         human_readable\n"
2388   "         critical\n"
2389   "        String values:\n"
2390   "         name\n"
2391   "         value\n"
2392   "        Number values:\n"
2393   "         flags\n"
2394   "     tofu\n"
2395   "      String values:\n"
2396   "       description\n"
2397   "      Number values:\n"
2398   "       validity\n"
2399   "       policy\n"
2400   "       signcount\n"
2401   "       encrcount\n"
2402   "       signfirst\n"
2403   "       signlast\n"
2404   "       encrfirst\n"
2405   "       encrlast\n";
2406 static gpg_error_t
2407 op_keylist (cjson_t request, cjson_t result)
2408 {
2409   gpg_error_t err;
2410   gpgme_ctx_t ctx = NULL;
2411   gpgme_protocol_t protocol;
2412   char **patterns = NULL;
2413   int abool;
2414   int secret_only = 0;
2415   gpgme_keylist_mode_t mode = 0;
2416   gpgme_key_t key = NULL;
2417   cjson_t keyarray = xjson_CreateArray ();
2418
2419   if ((err = get_protocol (request, &protocol)))
2420     goto leave;
2421   ctx = get_context (protocol);
2422
2423   /* Handle the various keylist mode bools. */
2424   if ((err = get_boolean_flag (request, "secret", 0, &abool)))
2425     goto leave;
2426   if (abool)
2427     {
2428       mode |= GPGME_KEYLIST_MODE_WITH_SECRET;
2429       secret_only = 1;
2430     }
2431   if ((err = get_boolean_flag (request, "with-secret", 0, &abool)))
2432     goto leave;
2433   if (abool)
2434     mode |= GPGME_KEYLIST_MODE_WITH_SECRET;
2435   if ((err = get_boolean_flag (request, "extern", 0, &abool)))
2436     goto leave;
2437   if (abool)
2438     mode |= GPGME_KEYLIST_MODE_EXTERN;
2439
2440   if ((err = get_boolean_flag (request, "local", 0, &abool)))
2441     goto leave;
2442   if (abool)
2443     mode |= GPGME_KEYLIST_MODE_LOCAL;
2444
2445   if ((err = get_boolean_flag (request, "sigs", 0, &abool)))
2446     goto leave;
2447   if (abool)
2448     mode |= GPGME_KEYLIST_MODE_SIGS;
2449
2450   if ((err = get_boolean_flag (request, "notations", 0, &abool)))
2451     goto leave;
2452   if (abool)
2453     mode |= GPGME_KEYLIST_MODE_SIG_NOTATIONS;
2454
2455   if ((err = get_boolean_flag (request, "tofu", 0, &abool)))
2456     goto leave;
2457   if (abool)
2458     mode |= GPGME_KEYLIST_MODE_WITH_TOFU;
2459
2460   if ((err = get_boolean_flag (request, "ephemeral", 0, &abool)))
2461     goto leave;
2462   if (abool)
2463     mode |= GPGME_KEYLIST_MODE_EPHEMERAL;
2464
2465   if ((err = get_boolean_flag (request, "validate", 0, &abool)))
2466     goto leave;
2467   if (abool)
2468     mode |= GPGME_KEYLIST_MODE_VALIDATE;
2469
2470   if ((err = get_boolean_flag (request, "locate", 0, &abool)))
2471     goto leave;
2472   if (abool)
2473     mode |= GPGME_KEYLIST_MODE_LOCATE;
2474
2475   if (!mode)
2476     {
2477       /* default to local */
2478       mode = GPGME_KEYLIST_MODE_LOCAL;
2479     }
2480
2481   /* Get the keys.  */
2482   patterns = create_keylist_patterns (request, "keys");
2483
2484   /* Do a keylisting and add the keys */
2485   gpgme_set_keylist_mode (ctx, mode);
2486
2487   err = gpgme_op_keylist_ext_start (ctx, (const char **) patterns,
2488                                     secret_only, 0);
2489   if (err)
2490     {
2491       gpg_error_object (result, err, "Error listing keys: %s",
2492                         gpg_strerror (err));
2493       goto leave;
2494     }
2495
2496   while (!(err = gpgme_op_keylist_next (ctx, &key)))
2497     {
2498       cJSON_AddItemToArray (keyarray, key_to_json (key));
2499       gpgme_key_unref (key);
2500     }
2501   err = 0;
2502
2503   if (!cJSON_AddItemToObject (result, "keys", keyarray))
2504     {
2505       err = gpg_error_from_syserror ();
2506       goto leave;
2507     }
2508
2509  leave:
2510   xfree_array (patterns);
2511   if (err)
2512     {
2513       cJSON_Delete (keyarray);
2514     }
2515   return err;
2516 }
2517
2518
2519 \f
2520 static const char hlp_import[] =
2521   "op:     \"import\"\n"
2522   "data:   The data to import.\n"
2523   "\n"
2524   "Optional parameters:\n"
2525   "protocol:      Either \"openpgp\" (default) or \"cms\".\n"
2526   "\n"
2527   "Optional boolean flags (default is false):\n"
2528   "base64:        Input data is base64 encoded.\n"
2529   "\n"
2530   "Response on success:\n"
2531   "result: The import result.\n"
2532   "  Number values:\n"
2533   "   considered\n"
2534   "   no_user_id\n"
2535   "   imported\n"
2536   "   imported_rsa\n"
2537   "   unchanged\n"
2538   "   new_user_ids\n"
2539   "   new_sub_keys\n"
2540   "   new_signatures\n"
2541   "   new_revocations\n"
2542   "   secret_read\n"
2543   "   secret_imported\n"
2544   "   secret_unchanged\n"
2545   "   skipped_new_keys\n"
2546   "   not_imported\n"
2547   "   skipped_v3_keys\n"
2548   "  Array values:\n"
2549   "   imports: List of keys for which an import was attempted\n"
2550   "    String values:\n"
2551   "     fingerprint\n"
2552   "     error_string\n"
2553   "    Number values:\n"
2554   "     error_code\n"
2555   "     status\n";
2556 static gpg_error_t
2557 op_import (cjson_t request, cjson_t result)
2558 {
2559   gpg_error_t err;
2560   gpgme_ctx_t ctx = NULL;
2561   gpgme_data_t input = NULL;
2562   gpgme_import_result_t import_result;
2563   gpgme_protocol_t protocol;
2564
2565   if ((err = get_protocol (request, &protocol)))
2566     goto leave;
2567   ctx = get_context (protocol);
2568
2569   if ((err = get_string_data (request, result, "data", &input)))
2570       goto leave;
2571
2572   /* Import.  */
2573   err = gpgme_op_import (ctx, input);
2574   import_result = gpgme_op_import_result (ctx);
2575   if (err)
2576     {
2577       gpg_error_object (result, err, "Import failed: %s",
2578                         gpg_strerror (err));
2579       goto leave;
2580     }
2581   gpgme_data_release (input);
2582   input = NULL;
2583
2584   xjson_AddItemToObject (result, "result",
2585                          import_result_to_json (import_result));
2586
2587  leave:
2588   release_context (ctx);
2589   gpgme_data_release (input);
2590   return err;
2591 }
2592
2593
2594 static const char hlp_export[] =
2595   "op:     \"export\"\n"
2596   "\n"
2597   "Optional parameters:\n"
2598   "keys:          Array of strings or fingerprints to lookup\n"
2599   "               For a single key a String may be used instead of an array.\n"
2600   "               default exports all keys.\n"
2601   "protocol:      Either \"openpgp\" (default) or \"cms\".\n"
2602   "\n"
2603   "Optional boolean flags (default is false):\n"
2604   "armor:         Request output in armored format.\n"
2605   "extern:        Add EXPORT_MODE_EXTERN.\n"
2606   "minimal:       Add EXPORT_MODE_MINIMAL.\n"
2607   "raw:           Add EXPORT_MODE_RAW.\n"
2608   "pkcs12:        Add EXPORT_MODE_PKCS12.\n"
2609   "with-sec-fprs: Add the sec-fprs array to the result.\n"
2610   "\n"
2611   "Response on success:\n"
2612   "type:     \"keys\"\n"
2613   "data:     Unless armor mode is used a Base64 encoded binary.\n"
2614   "          In armor mode a string with an armored\n"
2615   "          OpenPGP or a PEM / PKCS12 key.\n"
2616   "base64:   Boolean indicating whether data is base64 encoded.\n"
2617   "sec-fprs: Optional, only if with-secret is set. An array containing\n"
2618   "          the fingerprints of the keys in the export for which a secret\n"
2619   "          key is available";
2620 static gpg_error_t
2621 op_export (cjson_t request, cjson_t result)
2622 {
2623   gpg_error_t err;
2624   gpgme_ctx_t ctx = NULL;
2625   gpgme_protocol_t protocol;
2626   char **patterns = NULL;
2627   int abool;
2628   int with_secret = 0;
2629   gpgme_export_mode_t mode = 0;
2630   gpgme_data_t output = NULL;
2631
2632   if ((err = get_protocol (request, &protocol)))
2633     goto leave;
2634   ctx = get_context (protocol);
2635
2636   if ((err = get_boolean_flag (request, "armor", 0, &abool)))
2637     goto leave;
2638   gpgme_set_armor (ctx, abool);
2639
2640   /* Handle the various export mode bools. */
2641   if ((err = get_boolean_flag (request, "secret", 0, &abool)))
2642     goto leave;
2643   if (abool)
2644     {
2645       err = gpg_error (GPG_ERR_FORBIDDEN);
2646       goto leave;
2647     }
2648
2649   if ((err = get_boolean_flag (request, "extern", 0, &abool)))
2650     goto leave;
2651   if (abool)
2652     mode |= GPGME_EXPORT_MODE_EXTERN;
2653
2654   if ((err = get_boolean_flag (request, "minimal", 0, &abool)))
2655     goto leave;
2656   if (abool)
2657     mode |= GPGME_EXPORT_MODE_MINIMAL;
2658
2659   if ((err = get_boolean_flag (request, "raw", 0, &abool)))
2660     goto leave;
2661   if (abool)
2662     mode |= GPGME_EXPORT_MODE_RAW;
2663
2664   if ((err = get_boolean_flag (request, "pkcs12", 0, &abool)))
2665     goto leave;
2666   if (abool)
2667     mode |= GPGME_EXPORT_MODE_PKCS12;
2668
2669   if ((err = get_boolean_flag (request, "with-sec-fprs", 0, &abool)))
2670     goto leave;
2671   if (abool)
2672     with_secret = 1;
2673
2674   /* Get the export patterns.  */
2675   patterns = create_keylist_patterns (request, "keys");
2676
2677   /* Create an output data object.  */
2678   err = gpgme_data_new (&output);
2679   if (err)
2680     {
2681       gpg_error_object (result, err, "Error creating output data object: %s",
2682                         gpg_strerror (err));
2683       goto leave;
2684     }
2685
2686   err = gpgme_op_export_ext (ctx, (const char **) patterns,
2687                              mode, output);
2688   if (err)
2689     {
2690       gpg_error_object (result, err, "Error exporting keys: %s",
2691                         gpg_strerror (err));
2692       goto leave;
2693     }
2694
2695   /* We need to base64 if armoring has not been requested.  */
2696   err = make_data_object (result, output,
2697                           "keys", !gpgme_get_armor (ctx));
2698   output = NULL;
2699
2700   if (!err && with_secret)
2701     {
2702       err = add_secret_fprs ((const char **) patterns, protocol, result);
2703     }
2704
2705 leave:
2706   xfree_array (patterns);
2707   release_context (ctx);
2708   gpgme_data_release (output);
2709
2710   return err;
2711 }
2712
2713
2714 static const char hlp_delete[] =
2715   "op:     \"delete\"\n"
2716   "key:    Fingerprint of the key to delete.\n"
2717   "\n"
2718   "Optional parameters:\n"
2719   "protocol:      Either \"openpgp\" (default) or \"cms\".\n"
2720   "\n"
2721   "Response on success:\n"
2722   "success:   Boolean true.\n";
2723 static gpg_error_t
2724 op_delete (cjson_t request, cjson_t result)
2725 {
2726   gpg_error_t err;
2727   gpgme_ctx_t ctx = NULL;
2728   gpgme_ctx_t keylist_ctx = NULL;
2729   gpgme_protocol_t protocol;
2730   gpgme_key_t key = NULL;
2731   int secret = 0;
2732   cjson_t j_key = NULL;
2733
2734   if ((err = get_protocol (request, &protocol)))
2735     goto leave;
2736   ctx = get_context (protocol);
2737   keylist_ctx = get_context (protocol);
2738
2739   if ((err = get_boolean_flag (request, "secret", 0, &secret)))
2740     goto leave;
2741   if (secret)
2742     {
2743       err = gpg_error (GPG_ERR_FORBIDDEN);
2744       goto leave;
2745     }
2746
2747   j_key = cJSON_GetObjectItem (request, "key");
2748   if (!j_key)
2749     {
2750       err = gpg_error (GPG_ERR_NO_KEY);
2751       goto leave;
2752     }
2753   if (!cjson_is_string (j_key))
2754     {
2755       err = gpg_error (GPG_ERR_INV_VALUE);
2756       goto leave;
2757     }
2758
2759   /* Get the key */
2760   if ((err = gpgme_get_key (keylist_ctx, j_key->valuestring, &key, 0)))
2761     {
2762       gpg_error_object (result, err, "Error fetching key for delete: %s",
2763                         gpg_strerror (err));
2764       goto leave;
2765     }
2766
2767   err = gpgme_op_delete (ctx, key, 0);
2768   if (err)
2769     {
2770       gpg_error_object (result, err, "Error deleting key: %s",
2771                         gpg_strerror (err));
2772       goto leave;
2773     }
2774
2775   xjson_AddBoolToObject (result, "success", 1);
2776
2777 leave:
2778   gpgme_key_unref (key);
2779   release_context (ctx);
2780   release_context (keylist_ctx);
2781
2782   return err;
2783 }
2784
2785
2786 static const char hlp_config_opt[] =
2787   "op:       \"config_opt\"\n"
2788   "component: The component of the option.\n"
2789   "option:    The name of the option.\n"
2790   "\n"
2791   "Response on success:\n"
2792   "\n"
2793   "option: Information about the option.\n"
2794   " String values:\n"
2795   "  name: The name of the option\n"
2796   "  description: Localized description of the opt.\n"
2797   "  argname: Thhe argument name e.g. --verbose\n"
2798   "  default_description\n"
2799   "  no_arg_description\n"
2800   " Number values:\n"
2801   "  flags: Flags for this option.\n"
2802   "  level: the level of the description. See gpgme_conf_level_t.\n"
2803   "  type: The type of the option. See gpgme_conf_type_t.\n"
2804   "  alt_type: Alternate type of the option. See gpgme_conf_type_t\n"
2805   " Arg type values: (see desc. below)\n"
2806   "  default_value: Array of the default value.\n"
2807   "  no_arg_value: Array of the value if it is not set.\n"
2808   "  value: Array for the current value if the option is set.\n"
2809   "\n"
2810   "If the response is empty the option was not found\n"
2811   "";
2812 static gpg_error_t
2813 op_config_opt (cjson_t request, cjson_t result)
2814 {
2815   gpg_error_t err;
2816   gpgme_ctx_t ctx = NULL;
2817   gpgme_conf_comp_t conf = NULL;
2818   gpgme_conf_comp_t comp = NULL;
2819   cjson_t j_tmp;
2820   char *comp_name = NULL;
2821   char *opt_name = NULL;
2822
2823   ctx = get_context (GPGME_PROTOCOL_GPGCONF);
2824
2825   j_tmp = cJSON_GetObjectItem (request, "component");
2826   if (!j_tmp || !cjson_is_string (j_tmp))
2827     {
2828       err = gpg_error (GPG_ERR_INV_VALUE);
2829       goto leave;
2830     }
2831   comp_name = j_tmp->valuestring;
2832
2833
2834   j_tmp = cJSON_GetObjectItem (request, "option");
2835   if (!j_tmp || !cjson_is_string (j_tmp))
2836     {
2837       err = gpg_error (GPG_ERR_INV_VALUE);
2838       goto leave;
2839     }
2840   opt_name = j_tmp->valuestring;
2841
2842   /* Load the config */
2843   err = gpgme_op_conf_load (ctx, &conf);
2844   if (err)
2845     {
2846       goto leave;
2847     }
2848
2849   comp = conf;
2850   for (comp = conf; comp; comp = comp->next)
2851     {
2852       gpgme_conf_opt_t opt = NULL;
2853       int found = 0;
2854       if (!comp->name || strcmp (comp->name, comp_name))
2855         {
2856           /* Skip components if a single one is specified */
2857           continue;
2858         }
2859       for (opt = comp->options; opt; opt = opt->next)
2860         {
2861           if (!opt->name || strcmp (opt->name, opt_name))
2862             {
2863               /* Skip components if a single one is specified */
2864               continue;
2865             }
2866           xjson_AddItemToObject (result, "option", conf_opt_to_json (opt));
2867           found = 1;
2868           break;
2869         }
2870       if (found)
2871         break;
2872     }
2873
2874 leave:
2875   gpgme_conf_release (conf);
2876   release_context (ctx);
2877
2878   return err;
2879 }
2880
2881
2882 static const char hlp_config[] =
2883   "op:     \"config\"\n"
2884   "\n"
2885   "Optional parameters:\n"
2886   "component:    Component of entries to list.\n"
2887   "              Default: all\n"
2888   "\n"
2889   "Response on success:\n"
2890   "   components: Array of the component program configs.\n"
2891   "     name:         The component name.\n"
2892   "     description:  Description of the component.\n"
2893   "     program_name: The absolute path to the program.\n"
2894   "     options: Array of config options\n"
2895   "      String values:\n"
2896   "       name: The name of the option\n"
2897   "       description: Localized description of the opt.\n"
2898   "       argname: Thhe argument name e.g. --verbose\n"
2899   "       default_description\n"
2900   "       no_arg_description\n"
2901   "      Number values:\n"
2902   "       flags: Flags for this option.\n"
2903   "       level: the level of the description. See gpgme_conf_level_t.\n"
2904   "       type: The type of the option. See gpgme_conf_type_t.\n"
2905   "       alt_type: Alternate type of the option. See gpgme_conf_type_t\n"
2906   "      Arg type values: (see desc. below)\n"
2907   "       default_value: Array of the default value.\n"
2908   "       no_arg_value: Array of the value if it is not set.\n"
2909   "       value: Array for the current value if the option is set.\n"
2910   "\n"
2911   "Conf type values are an array of values that are either\n"
2912   "of type number named \"number\" or of type string,\n"
2913   "named \"string\".\n"
2914   "If the type is none the bool value is_none is true.\n"
2915   "";
2916 static gpg_error_t
2917 op_config (cjson_t request, cjson_t result)
2918 {
2919   gpg_error_t err;
2920   gpgme_ctx_t ctx = NULL;
2921   gpgme_conf_comp_t conf = NULL;
2922   gpgme_conf_comp_t comp = NULL;
2923   cjson_t j_tmp;
2924   char *comp_name = NULL;
2925   cjson_t j_comps = xjson_CreateArray ();
2926
2927   ctx = get_context (GPGME_PROTOCOL_GPGCONF);
2928
2929   j_tmp = cJSON_GetObjectItem (request, "component");
2930   if (j_tmp && cjson_is_string (j_tmp))
2931     {
2932       comp_name = j_tmp->valuestring;
2933     }
2934   else if (j_tmp && !cjson_is_string (j_tmp))
2935     {
2936       err = gpg_error (GPG_ERR_INV_VALUE);
2937       goto leave;
2938     }
2939
2940   /* Load the config */
2941   err = gpgme_op_conf_load (ctx, &conf);
2942   if (err)
2943     {
2944       goto leave;
2945     }
2946
2947   comp = conf;
2948   for (comp = conf; comp; comp = comp->next)
2949     {
2950       if (comp_name && comp->name && strcmp (comp->name, comp_name))
2951         {
2952           /* Skip components if a single one is specified */
2953           continue;
2954         }
2955       cJSON_AddItemToArray (j_comps, conf_comp_to_json (comp));
2956     }
2957   xjson_AddItemToObject (result, "components", j_comps);
2958
2959 leave:
2960   gpgme_conf_release (conf);
2961   release_context (ctx);
2962
2963   return err;
2964 }
2965
2966
2967 \f
2968 static const char hlp_createkey[] =
2969   "op:      \"createkey\"\n"
2970   "userid:  The user id. E.g. \"Foo Bar <foo@bar.baz>\"\n"
2971   "\n"
2972   "Optional parameters:\n"
2973   "algo:        Algo of the key as string. See doc for gpg --quick-gen-key.\n"
2974   "subkey-algo: Algo of the encryption subkey. If ommited the same as algo\n"
2975   "             is used.\n"
2976   "             Except for dsa and ed25519 where the according\n"
2977   "             elg / cv25519 algo will be used as subkey-algo.\n"
2978   "\n"
2979   "             If algo is omitted or default or future-default subkey-algo\n"
2980   "             is ignored.\n"
2981   "expires:     Seconds from now to expiry as Number. 0 means no expiry.\n"
2982   "\n"
2983   "Response on success:\n"
2984   "fingerprint:   The fingerprint of the created key.\n"
2985   "\n"
2986   "Note: This interface does not allow key generation if the userid\n"
2987   "of the new key already exists in the keyring.\n";
2988 static gpg_error_t
2989 op_createkey (cjson_t request, cjson_t result)
2990 {
2991   gpg_error_t err;
2992   gpgme_ctx_t ctx = NULL;
2993   unsigned int flags = GPGME_CREATE_FORCE; /* Always force as the GUI should
2994                                               handle checks, if required. */
2995   unsigned long expires = 0;
2996   cjson_t j_tmp;
2997   const char *algo = "default";
2998   const char *userid;
2999   gpgme_genkey_result_t res;
3000   char *new_fpr = NULL;
3001
3002 #ifdef GPG_AGENT_ALLOWS_KEYGEN_TRHOUGH_BROWSER
3003   /* GnuPG forbids keygen through the browser socket so for
3004      this we create an unrestricted context.
3005      See GnuPG-Bug-Id: T4010 for more info */
3006   ctx = get_context (GPGME_PROTOCOL_OpenPGP);
3007 #else
3008     err = gpgme_new (&ctx);
3009   if (err)
3010     log_fatal ("error creating GPGME context: %s\n", gpg_strerror (err));
3011   gpgme_set_protocol (ctx, GPGME_PROTOCOL_OpenPGP);
3012 #endif
3013
3014   j_tmp = cJSON_GetObjectItem (request, "algo");
3015   if (j_tmp && cjson_is_string (j_tmp))
3016     {
3017       algo = j_tmp->valuestring;
3018     }
3019
3020   j_tmp = cJSON_GetObjectItem (request, "userid");
3021   if (!j_tmp || !cjson_is_string (j_tmp))
3022     {
3023       err = gpg_error (GPG_ERR_INV_VALUE);
3024       goto leave;
3025     }
3026
3027   userid = j_tmp->valuestring;
3028
3029   j_tmp = cJSON_GetObjectItem (request, "expires");
3030   if (j_tmp)
3031     {
3032       if (!cjson_is_number (j_tmp))
3033         {
3034           err = gpg_error (GPG_ERR_INV_VALUE);
3035           goto leave;
3036         }
3037       expires = j_tmp->valueint;
3038
3039       if (!expires)
3040         flags |= GPGME_CREATE_NOEXPIRE;
3041     }
3042
3043
3044   if ((err = gpgme_op_createkey (ctx, userid, algo, 0, expires, NULL, flags)))
3045     goto leave;
3046
3047   res = gpgme_op_genkey_result (ctx);
3048   if (!res)
3049     {
3050       err = gpg_error (GPG_ERR_GENERAL);
3051       goto leave;
3052     }
3053
3054   /* Dup the fpr as the result might become invalid after context reuse. */
3055   new_fpr = xstrdup (res->fpr);
3056
3057   if (algo && strcmp ("default", algo) && strcmp ("future-default", algo))
3058     {
3059       /* We need to add the encryption subkey manually */
3060       gpgme_ctx_t keylistctx = create_onetime_context (GPGME_PROTOCOL_OpenPGP);
3061       gpgme_key_t new_key = NULL;
3062       char *subkey_algo = NULL;
3063
3064       j_tmp = cJSON_GetObjectItem (request, "subkey_algo");
3065       if (j_tmp && cjson_is_string (j_tmp))
3066         {
3067           subkey_algo = xstrdup (j_tmp->valuestring);
3068         }
3069
3070       if (!subkey_algo)
3071         {
3072           subkey_algo = strdup (algo);
3073           if (!strncmp ("dsa", subkey_algo, 3))
3074             {
3075               subkey_algo[0] = 'e';
3076               subkey_algo[1] = 'l';
3077               subkey_algo[2] = 'g';
3078             }
3079           if (!strcmp ("ed25519", subkey_algo))
3080             {
3081               strcpy (subkey_algo, "cv25519");
3082             }
3083         }
3084
3085       err = gpgme_get_key (keylistctx, new_fpr, &new_key, 1);
3086       release_onetime_context (keylistctx);
3087       if (err || !new_key)
3088         {
3089           gpg_error_object (result, err, "Error finding created key: %s",
3090                             gpg_strerror (err));
3091           xfree (subkey_algo);
3092           goto leave;
3093         }
3094
3095       err = gpgme_op_createsubkey (ctx, new_key, subkey_algo,
3096                                    0, expires, flags |= GPGME_CREATE_ENCR);
3097       xfree (subkey_algo);
3098       if (err)
3099         {
3100           /* This can happen for example if the user cancels the
3101            * pinentry to unlock the primary key when adding the
3102            * subkey.  To avoid an artifact of a pimary key without
3103            * an encryption capable subkey we delete the created
3104            * key and treat the whole operation as failed. */
3105           gpgme_error_t err2;
3106           gpg_error_object (result, err, "Error creating subkey: %s",
3107                             gpg_strerror (err));
3108           log_info ("Deleting primary key after keygen failure.\n");
3109           err2 = gpgme_op_delete_ext (ctx, new_key, GPGME_DELETE_FORCE |
3110                                       GPGME_DELETE_ALLOW_SECRET);
3111           if (err2)
3112             {
3113               log_error ("Error deleting primary key: %s",
3114                          gpg_strerror (err));
3115             }
3116           gpgme_key_unref (new_key);
3117           goto leave;
3118         }
3119       gpgme_key_unref (new_key);
3120     }
3121
3122   xjson_AddStringToObject0 (result, "fingerprint", new_fpr);
3123
3124 leave:
3125   xfree (new_fpr);
3126 #ifdef GPG_AGENT_ALLOWS_KEYGEN_TRHOUGH_BROWSER
3127   release_context (ctx);
3128 #else
3129   gpgme_release (ctx);
3130 #endif
3131
3132   return err;
3133 }
3134
3135
3136 \f
3137 static const char hlp_getmore[] =
3138   "op:     \"getmore\"\n"
3139   "\n"
3140   "Response on success:\n"
3141   "response:       base64 encoded json response.\n"
3142   "more:           Another getmore is required.\n"
3143   "base64:         boolean if the response is base64 encoded.\n";
3144 static gpg_error_t
3145 op_getmore (cjson_t request, cjson_t result)
3146 {
3147   gpg_error_t err;
3148   int c;
3149   size_t n;
3150   size_t chunksize;
3151
3152   if ((err = get_chunksize (request, &chunksize)))
3153     goto leave;
3154
3155   /* For the meta data we need 41 bytes:
3156      {"more":true,"base64":true,"response":""} */
3157   chunksize -= 41;
3158
3159   /* Adjust the chunksize for the base64 conversion.  */
3160   chunksize = (chunksize / 4) * 3;
3161
3162   /* Do we have anything pending?  */
3163   if (!pending_data.buffer)
3164     {
3165       err = gpg_error (GPG_ERR_NO_DATA);
3166       gpg_error_object (result, err, "Operation not possible: %s",
3167                         gpg_strerror (err));
3168       goto leave;
3169     }
3170
3171   /* We currently always use base64 encoding for simplicity. */
3172   xjson_AddBoolToObject (result, "base64", 1);
3173
3174   if (pending_data.written >= pending_data.length)
3175     {
3176       /* EOF reached.  This should not happen but we return an empty
3177        * string once in case of client errors.  */
3178       gpgme_free (pending_data.buffer);
3179       pending_data.buffer = NULL;
3180       xjson_AddBoolToObject (result, "more", 0);
3181       err = cjson_AddStringToObject (result, "response", "");
3182     }
3183   else
3184     {
3185       n = pending_data.length - pending_data.written;
3186       if (n > chunksize)
3187         {
3188           n = chunksize;
3189           xjson_AddBoolToObject (result, "more", 1);
3190         }
3191       else
3192         xjson_AddBoolToObject (result, "more", 0);
3193
3194       c = pending_data.buffer[pending_data.written + n];
3195       pending_data.buffer[pending_data.written + n] = 0;
3196       err = add_base64_to_object (result, "response",
3197                                   (pending_data.buffer
3198                                    + pending_data.written), n);
3199       pending_data.buffer[pending_data.written + n] = c;
3200       if (!err)
3201         {
3202           pending_data.written += n;
3203           if (pending_data.written >= pending_data.length)
3204             {
3205               xfree (pending_data.buffer);
3206               pending_data.buffer = NULL;
3207             }
3208         }
3209     }
3210
3211  leave:
3212   return err;
3213 }
3214
3215
3216 \f
3217 static const char hlp_help[] =
3218   "The tool expects a JSON object with the request and responds with\n"
3219   "another JSON object.  Even on error a JSON object is returned.  The\n"
3220   "property \"op\" is mandatory and its string value selects the\n"
3221   "operation; if the property \"help\" with the value \"true\" exists, the\n"
3222   "operation is not performned but a string with the documentation\n"
3223   "returned.  To list all operations it is allowed to leave out \"op\" in\n"
3224   "help mode.  Supported values for \"op\" are:\n\n"
3225   "  config      Read configuration values.\n"
3226   "  config_opt  Read a single configuration value.\n"
3227   "  decrypt     Decrypt data.\n"
3228   "  delete      Delete a key.\n"
3229   "  encrypt     Encrypt data.\n"
3230   "  export      Export keys.\n"
3231   "  createkey   Generate a keypair (OpenPGP only).\n"
3232   "  import      Import data.\n"
3233   "  keylist     List keys.\n"
3234   "  sign        Sign data.\n"
3235   "  verify      Verify data.\n"
3236   "  version     Get engine information.\n"
3237   "  getmore     Retrieve remaining data if chunksize was used.\n"
3238   "  help        Help overview.\n"
3239   "\n"
3240   "If the data needs to be transferred in smaller chunks the\n"
3241   "property \"chunksize\" with an integer value can be added.\n"
3242   "When \"chunksize\" is set the response (including json) will\n"
3243   "not be larger then \"chunksize\" but might be smaller.\n"
3244   "The chunked result will be transferred in base64 encoded chunks\n"
3245   "using the \"getmore\" operation. See help getmore for more info.";
3246 static gpg_error_t
3247 op_help (cjson_t request, cjson_t result)
3248 {
3249   cjson_t j_tmp;
3250   char *buffer = NULL;
3251   const char *msg;
3252
3253   j_tmp = cJSON_GetObjectItem (request, "interactive_help");
3254   if (opt_interactive && j_tmp && cjson_is_string (j_tmp))
3255     msg = buffer = xstrconcat (hlp_help, "\n", j_tmp->valuestring, NULL);
3256   else
3257     msg = hlp_help;
3258
3259   xjson_AddStringToObject (result, "type", "help");
3260   xjson_AddStringToObject (result, "msg", msg);
3261
3262   xfree (buffer);
3263   return 0;
3264 }
3265
3266
3267 \f
3268 /*
3269  * Dispatcher
3270  */
3271
3272 /* Process a request and return the response.  The response is a newly
3273  * allocated string or NULL in case of an error.  */
3274 static char *
3275 process_request (const char *request)
3276 {
3277   static struct {
3278     const char *op;
3279     gpg_error_t (*handler)(cjson_t request, cjson_t result);
3280     const char * const helpstr;
3281   } optbl[] = {
3282     { "config",     op_config,     hlp_config },
3283     { "config_opt", op_config_opt, hlp_config_opt },
3284     { "encrypt",    op_encrypt,    hlp_encrypt },
3285     { "export",     op_export,     hlp_export },
3286     { "decrypt",    op_decrypt,    hlp_decrypt },
3287     { "delete",     op_delete,     hlp_delete },
3288     { "createkey",  op_createkey,  hlp_createkey },
3289     { "keylist",    op_keylist,    hlp_keylist },
3290     { "import",     op_import,     hlp_import },
3291     { "sign",       op_sign,       hlp_sign },
3292     { "verify",     op_verify,     hlp_verify },
3293     { "version",    op_version,    hlp_version },
3294     { "getmore",    op_getmore,    hlp_getmore },
3295     { "help",       op_help,       hlp_help },
3296     { NULL }
3297   };
3298   size_t erroff;
3299   cjson_t json;
3300   cjson_t j_tmp, j_op;
3301   cjson_t response;
3302   int helpmode;
3303   int is_getmore = 0;
3304   const char *op;
3305   char *res = NULL;
3306   int idx;
3307
3308   response = xjson_CreateObject ();
3309
3310   json = cJSON_Parse (request, &erroff);
3311   if (!json)
3312     {
3313       log_string (GPGRT_LOGLVL_INFO, request);
3314       log_info ("invalid JSON object at offset %zu\n", erroff);
3315       error_object (response, "invalid JSON object at offset %zu\n", erroff);
3316       goto leave;
3317     }
3318
3319   j_tmp = cJSON_GetObjectItem (json, "help");
3320   helpmode = (j_tmp && cjson_is_true (j_tmp));
3321
3322   j_op = cJSON_GetObjectItem (json, "op");
3323   if (!j_op || !cjson_is_string (j_op))
3324     {
3325       if (!helpmode)
3326         {
3327           error_object (response, "Property \"op\" missing");
3328           goto leave;
3329         }
3330       op = "help";  /* Help summary.  */
3331     }
3332   else
3333     op = j_op->valuestring;
3334
3335   for (idx=0; optbl[idx].op; idx++)
3336     if (!strcmp (op, optbl[idx].op))
3337       break;
3338   if (optbl[idx].op)
3339     {
3340       if (helpmode && strcmp (op, "help"))
3341         {
3342           xjson_AddStringToObject (response, "type", "help");
3343           xjson_AddStringToObject (response, "op", op);
3344           xjson_AddStringToObject (response, "msg", optbl[idx].helpstr);
3345         }
3346       else
3347         {
3348           gpg_error_t err;
3349           is_getmore = optbl[idx].handler == op_getmore;
3350           /* If this is not the "getmore" command and we have any
3351            * pending data release that data.  */
3352           if (pending_data.buffer && optbl[idx].handler != op_getmore)
3353             {
3354               gpgme_free (pending_data.buffer);
3355               pending_data.buffer = NULL;
3356             }
3357
3358           err = optbl[idx].handler (json, response);
3359           if (err)
3360             {
3361               if (!(j_tmp = cJSON_GetObjectItem (response, "type"))
3362                   || !cjson_is_string (j_tmp)
3363                   || strcmp (j_tmp->valuestring, "error"))
3364                 {
3365                   /* No error type response - provide a generic one.  */
3366                   gpg_error_object (response, err, "Operation failed: %s",
3367                                     gpg_strerror (err));
3368                 }
3369
3370               xjson_AddStringToObject (response, "op", op);
3371             }
3372         }
3373     }
3374   else  /* Operation not supported.  */
3375     {
3376       error_object (response, "Unknown operation '%s'", op);
3377       xjson_AddStringToObject (response, "op", op);
3378     }
3379
3380  leave:
3381   if (is_getmore)
3382     {
3383       /* For getmore we bypass the encode_and_chunk. */
3384       if (opt_interactive)
3385         res = cJSON_Print (response);
3386       else
3387         res = cJSON_PrintUnformatted (response);
3388     }
3389   else
3390     res = encode_and_chunk (json, response);
3391   if (!res)
3392     {
3393       cjson_t err_obj;
3394
3395       log_error ("printing JSON data failed\n");
3396
3397       err_obj = error_object (NULL, "Printing JSON data failed");
3398       if (opt_interactive)
3399         res = cJSON_Print (err_obj);
3400       res = cJSON_PrintUnformatted (err_obj);
3401       cJSON_Delete (err_obj);
3402     }
3403
3404   cJSON_Delete (json);
3405   cJSON_Delete (response);
3406
3407   if (!res)
3408     {
3409       /* Can't happen unless we created a broken error_object above */
3410       return xtrystrdup ("Bug: Fatal error in process request\n");
3411     }
3412   return res;
3413 }
3414
3415
3416 \f
3417 /*
3418  *  Driver code
3419  */
3420
3421 static char *
3422 get_file (const char *fname)
3423 {
3424   gpg_error_t err;
3425   estream_t fp;
3426   struct stat st;
3427   char *buf;
3428   size_t buflen;
3429
3430   fp = es_fopen (fname, "r");
3431   if (!fp)
3432     {
3433       err = gpg_error_from_syserror ();
3434       log_error ("can't open '%s': %s\n", fname, gpg_strerror (err));
3435       return NULL;
3436     }
3437
3438   if (fstat (es_fileno(fp), &st))
3439     {
3440       err = gpg_error_from_syserror ();
3441       log_error ("can't stat '%s': %s\n", fname, gpg_strerror (err));
3442       es_fclose (fp);
3443       return NULL;
3444     }
3445
3446   buflen = st.st_size;
3447   buf = xmalloc (buflen+1);
3448   if (es_fread (buf, buflen, 1, fp) != 1)
3449     {
3450       err = gpg_error_from_syserror ();
3451       log_error ("error reading '%s': %s\n", fname, gpg_strerror (err));
3452       es_fclose (fp);
3453       xfree (buf);
3454       return NULL;
3455     }
3456   buf[buflen] = 0;
3457   es_fclose (fp);
3458
3459   return buf;
3460 }
3461
3462
3463 /* Return a malloced line or NULL on EOF.  Terminate on read
3464  * error.  */
3465 static char *
3466 get_line (void)
3467 {
3468   char *line = NULL;
3469   size_t linesize = 0;
3470   gpg_error_t err;
3471   size_t maxlength = 2048;
3472   int n;
3473   const char *s;
3474   char *p;
3475
3476  again:
3477   n = es_read_line (es_stdin, &line, &linesize, &maxlength);
3478   if (n < 0)
3479     {
3480       err = gpg_error_from_syserror ();
3481       log_error ("error reading line: %s\n", gpg_strerror (err));
3482       exit (1);
3483     }
3484   if (!n)
3485     {
3486       xfree (line);
3487       line = NULL;
3488       return NULL;  /* EOF */
3489     }
3490   if (!maxlength)
3491     {
3492       log_info ("line too long - skipped\n");
3493       goto again;
3494     }
3495   if (memchr (line, 0, n))
3496     log_info ("warning: line shortened due to embedded Nul character\n");
3497
3498   if (line[n-1] == '\n')
3499     line[n-1] = 0;
3500
3501   /* Trim leading spaces.  */
3502   for (s=line; spacep (s); s++)
3503     ;
3504   if (s != line)
3505     {
3506       for (p=line; *s;)
3507         *p++ = *s++;
3508       *p = 0;
3509       n = p - line;
3510     }
3511
3512   return line;
3513 }
3514
3515
3516 /* Process meta commands used with the standard REPL.  */
3517 static char *
3518 process_meta_commands (const char *request)
3519 {
3520   char *result = NULL;
3521
3522   while (spacep (request))
3523     request++;
3524
3525   if (!strncmp (request, "help", 4) && (spacep (request+4) || !request[4]))
3526     {
3527       if (request[4])
3528         {
3529           char *buf = xstrconcat ("{ \"help\":true, \"op\":\"", request+5,
3530                                   "\" }", NULL);
3531           result = process_request (buf);
3532           xfree (buf);
3533         }
3534       else
3535         result = process_request ("{ \"op\": \"help\","
3536                                   " \"interactive_help\": "
3537                                   "\"\\nMeta commands:\\n"
3538                                   "  ,read FNAME Process data from FILE\\n"
3539                                   "  ,help CMD   Print help for a command\\n"
3540                                   "  ,quit       Terminate process\""
3541                                   "}");
3542     }
3543   else if (!strncmp (request, "quit", 4) && (spacep (request+4) || !request[4]))
3544     exit (0);
3545   else if (!strncmp (request, "read", 4) && (spacep (request+4) || !request[4]))
3546     {
3547       if (!request[4])
3548         log_info ("usage: ,read FILENAME\n");
3549       else
3550         {
3551           char *buffer = get_file (request + 5);
3552           if (buffer)
3553             {
3554               result = process_request (buffer);
3555               xfree (buffer);
3556             }
3557         }
3558     }
3559   else
3560     log_info ("invalid meta command\n");
3561
3562   return result;
3563 }
3564
3565
3566 /* If STRING has a help response, return the MSG property in a human
3567  * readable format.  */
3568 static char *
3569 get_help_msg (const char *string)
3570 {
3571   cjson_t json, j_type, j_msg;
3572   const char *msg;
3573   char *buffer = NULL;
3574   char *p;
3575
3576   json = cJSON_Parse (string, NULL);
3577   if (json)
3578     {
3579       j_type = cJSON_GetObjectItem (json, "type");
3580       if (j_type && cjson_is_string (j_type)
3581           && !strcmp (j_type->valuestring, "help"))
3582         {
3583           j_msg = cJSON_GetObjectItem (json, "msg");
3584           if (j_msg || cjson_is_string (j_msg))
3585             {
3586               msg = j_msg->valuestring;
3587               buffer = malloc (strlen (msg)+1);
3588               if (buffer)
3589                 {
3590                   for (p=buffer; *msg; msg++)
3591                     {
3592                       if (*msg == '\\' && msg[1] == '\n')
3593                         *p++ = '\n';
3594                       else
3595                         *p++ = *msg;
3596                     }
3597                   *p = 0;
3598                 }
3599             }
3600         }
3601       cJSON_Delete (json);
3602     }
3603   return buffer;
3604 }
3605
3606
3607 /* An interactive standard REPL.  */
3608 static void
3609 interactive_repl (void)
3610 {
3611   char *line = NULL;
3612   char *request = NULL;
3613   char *response = NULL;
3614   char *p;
3615   int first;
3616
3617   es_setvbuf (es_stdin, NULL, _IONBF, 0);
3618 #if GPGRT_VERSION_NUMBER >= 0x011d00 /* 1.29 */
3619   es_fprintf (es_stderr, "%s %s ready (enter \",help\" for help)\n",
3620               gpgrt_strusage (11), gpgrt_strusage (13));
3621 #endif
3622   do
3623     {
3624       es_fputs ("> ", es_stderr);
3625       es_fflush (es_stderr);
3626       es_fflush (es_stdout);
3627       xfree (line);
3628       line = get_line ();
3629       es_fflush (es_stderr);
3630       es_fflush (es_stdout);
3631
3632       first = !request;
3633       if (line && *line)
3634         {
3635           if (!request)
3636             request = xstrdup (line);
3637           else
3638             request = xstrconcat (request, "\n", line, NULL);
3639         }
3640
3641       if (!line)
3642         es_fputs ("\n", es_stderr);
3643
3644       if (!line || !*line || (first && *request == ','))
3645         {
3646           /* Process the input.  */
3647           xfree (response);
3648           response = NULL;
3649           if (request && *request == ',')
3650             {
3651               response = process_meta_commands (request+1);
3652             }
3653           else if (request)
3654             {
3655               response = process_request (request);
3656             }
3657           xfree (request);
3658           request = NULL;
3659
3660           if (response)
3661             {
3662               if (opt_interactive)
3663                 {
3664                   char *msg = get_help_msg (response);
3665                   if (msg)
3666                     {
3667                       xfree (response);
3668                       response = msg;
3669                     }
3670                 }
3671
3672               es_fputs ("===> ", es_stderr);
3673               es_fflush (es_stderr);
3674               for (p=response; *p; p++)
3675                 {
3676                   if (*p == '\n')
3677                     {
3678                       es_fflush (es_stdout);
3679                       es_fputs ("\n===> ", es_stderr);
3680                       es_fflush (es_stderr);
3681                     }
3682                   else
3683                     es_putc (*p, es_stdout);
3684                 }
3685               es_fflush (es_stdout);
3686               es_fputs ("\n", es_stderr);
3687             }
3688         }
3689     }
3690   while (line);