json: Better use gpgme_free
[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 <https://gnu.org/licenses/>.
18  * SPDX-License-Identifier: LGPL-2.1-or-later
19  */
20
21 /* This 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 being
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 delimited. */
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   char *tmp;
1007
1008   xjson_AddBoolToObject (result, "revoked", sub->revoked);
1009   xjson_AddBoolToObject (result, "expired", sub->expired);
1010   xjson_AddBoolToObject (result, "disabled", sub->disabled);
1011   xjson_AddBoolToObject (result, "invalid", sub->invalid);
1012   xjson_AddBoolToObject (result, "can_encrypt", sub->can_encrypt);
1013   xjson_AddBoolToObject (result, "can_sign", sub->can_sign);
1014   xjson_AddBoolToObject (result, "can_certify", sub->can_certify);
1015   xjson_AddBoolToObject (result, "can_authenticate", sub->can_authenticate);
1016   xjson_AddBoolToObject (result, "secret", sub->secret);
1017   xjson_AddBoolToObject (result, "is_qualified", sub->is_qualified);
1018   xjson_AddBoolToObject (result, "is_cardkey", sub->is_cardkey);
1019   xjson_AddBoolToObject (result, "is_de_vs", sub->is_de_vs);
1020   xjson_AddStringToObject0 (result, "pubkey_algo_name",
1021                             gpgme_pubkey_algo_name (sub->pubkey_algo));
1022
1023   tmp = gpgme_pubkey_algo_string (sub);
1024   xjson_AddStringToObject0 (result, "pubkey_algo_string", tmp);
1025   gpgme_free (tmp);
1026
1027   xjson_AddStringToObject0 (result, "keyid", sub->keyid);
1028   xjson_AddStringToObject0 (result, "card_number", sub->card_number);
1029   xjson_AddStringToObject0 (result, "curve", sub->curve);
1030   xjson_AddStringToObject0 (result, "keygrip", sub->keygrip);
1031
1032   xjson_AddNumberToObject (result, "pubkey_algo", sub->pubkey_algo);
1033   xjson_AddNumberToObject (result, "length", sub->length);
1034   xjson_AddNumberToObject (result, "timestamp", sub->timestamp);
1035   xjson_AddNumberToObject (result, "expires", sub->expires);
1036
1037   return result;
1038 }
1039
1040 /* Create a key json object */
1041 static cjson_t
1042 key_to_json (gpgme_key_t key)
1043 {
1044   cjson_t result = xjson_CreateObject ();
1045
1046   xjson_AddBoolToObject (result, "revoked", key->revoked);
1047   xjson_AddBoolToObject (result, "expired", key->expired);
1048   xjson_AddBoolToObject (result, "disabled", key->disabled);
1049   xjson_AddBoolToObject (result, "invalid", key->invalid);
1050   xjson_AddBoolToObject (result, "can_encrypt", key->can_encrypt);
1051   xjson_AddBoolToObject (result, "can_sign", key->can_sign);
1052   xjson_AddBoolToObject (result, "can_certify", key->can_certify);
1053   xjson_AddBoolToObject (result, "can_authenticate", key->can_authenticate);
1054   xjson_AddBoolToObject (result, "secret", key->secret);
1055   xjson_AddBoolToObject (result, "is_qualified", key->is_qualified);
1056
1057   xjson_AddStringToObject0 (result, "protocol",
1058                             protocol_to_string (key->protocol));
1059   xjson_AddStringToObject0 (result, "issuer_serial", key->issuer_serial);
1060   xjson_AddStringToObject0 (result, "issuer_name", key->issuer_name);
1061   xjson_AddStringToObject0 (result, "fingerprint", key->fpr);
1062   xjson_AddStringToObject0 (result, "chain_id", key->chain_id);
1063   xjson_AddStringToObject0 (result, "owner_trust",
1064                             validity_to_string (key->owner_trust));
1065
1066   xjson_AddNumberToObject (result, "origin", key->origin);
1067   xjson_AddNumberToObject (result, "last_update", key->last_update);
1068
1069   /* Add subkeys */
1070   if (key->subkeys)
1071     {
1072       cjson_t subkey_array = xjson_CreateArray ();
1073       gpgme_subkey_t sub;
1074       for (sub = key->subkeys; sub; sub = sub->next)
1075         cJSON_AddItemToArray (subkey_array, subkey_to_json (sub));
1076
1077       xjson_AddItemToObject (result, "subkeys", subkey_array);
1078     }
1079
1080   /* User Ids */
1081   if (key->uids)
1082     {
1083       cjson_t uid_array = xjson_CreateArray ();
1084       gpgme_user_id_t uid;
1085       for (uid = key->uids; uid; uid = uid->next)
1086         cJSON_AddItemToArray (uid_array, uid_to_json (uid));
1087
1088       xjson_AddItemToObject (result, "userids", uid_array);
1089     }
1090
1091   return result;
1092 }
1093
1094
1095 /* Create a signature json object */
1096 static cjson_t
1097 signature_to_json (gpgme_signature_t sig)
1098 {
1099   cjson_t result = xjson_CreateObject ();
1100
1101   xjson_AddItemToObject (result, "summary", sigsum_to_json (sig->summary));
1102
1103   xjson_AddBoolToObject (result, "wrong_key_usage", sig->wrong_key_usage);
1104   xjson_AddBoolToObject (result, "chain_model", sig->chain_model);
1105   xjson_AddBoolToObject (result, "is_de_vs", sig->is_de_vs);
1106
1107   xjson_AddStringToObject0 (result, "status_string",
1108                             gpgme_strerror (sig->status));
1109   xjson_AddStringToObject0 (result, "fingerprint", sig->fpr);
1110   xjson_AddStringToObject0 (result, "validity_string",
1111                             validity_to_string (sig->validity));
1112   xjson_AddStringToObject0 (result, "pubkey_algo_name",
1113                             gpgme_pubkey_algo_name (sig->pubkey_algo));
1114   xjson_AddStringToObject0 (result, "hash_algo_name",
1115                             gpgme_hash_algo_name (sig->hash_algo));
1116   xjson_AddStringToObject0 (result, "pka_address", sig->pka_address);
1117
1118   xjson_AddNumberToObject (result, "status_code", sig->status);
1119   xjson_AddNumberToObject (result, "timestamp", sig->timestamp);
1120   xjson_AddNumberToObject (result, "exp_timestamp", sig->exp_timestamp);
1121   xjson_AddNumberToObject (result, "pka_trust", sig->pka_trust);
1122   xjson_AddNumberToObject (result, "validity", sig->validity);
1123   xjson_AddNumberToObject (result, "validity_reason", sig->validity_reason);
1124
1125   if (sig->notations)
1126     {
1127       gpgme_sig_notation_t not;
1128       cjson_t array = xjson_CreateArray ();
1129       for (not = sig->notations; not; not = not->next)
1130         cJSON_AddItemToArray (array, sig_notation_to_json (not));
1131       xjson_AddItemToObject (result, "notations", array);
1132     }
1133
1134   return result;
1135 }
1136
1137
1138 /* Create a JSON object from a gpgme_verify result */
1139 static cjson_t
1140 verify_result_to_json (gpgme_verify_result_t verify_result)
1141 {
1142   cjson_t result = xjson_CreateObject ();
1143
1144   xjson_AddBoolToObject (result, "is_mime", verify_result->is_mime);
1145
1146   if (verify_result->signatures)
1147     {
1148       cjson_t array = xjson_CreateArray ();
1149       gpgme_signature_t sig;
1150
1151       for (sig = verify_result->signatures; sig; sig = sig->next)
1152         cJSON_AddItemToArray (array, signature_to_json (sig));
1153       xjson_AddItemToObject (result, "signatures", array);
1154     }
1155
1156   return result;
1157 }
1158
1159 /* Create a recipient json object */
1160 static cjson_t
1161 recipient_to_json (gpgme_recipient_t recp)
1162 {
1163   cjson_t result = xjson_CreateObject ();
1164
1165   xjson_AddStringToObject0 (result, "keyid", recp->keyid);
1166   xjson_AddStringToObject0 (result, "pubkey_algo_name",
1167                             gpgme_pubkey_algo_name (recp->pubkey_algo));
1168   xjson_AddStringToObject0 (result, "status_string",
1169                             gpgme_strerror (recp->status));
1170
1171   xjson_AddNumberToObject (result, "status_code", recp->status);
1172
1173   return result;
1174 }
1175
1176
1177 /* Create a JSON object from a gpgme_decrypt result */
1178 static cjson_t
1179 decrypt_result_to_json (gpgme_decrypt_result_t decrypt_result)
1180 {
1181   cjson_t result = xjson_CreateObject ();
1182
1183   xjson_AddStringToObject0 (result, "file_name", decrypt_result->file_name);
1184   xjson_AddStringToObject0 (result, "symkey_algo",
1185                             decrypt_result->symkey_algo);
1186
1187   xjson_AddBoolToObject (result, "wrong_key_usage",
1188                          decrypt_result->wrong_key_usage);
1189   xjson_AddBoolToObject (result, "is_de_vs",
1190                          decrypt_result->is_de_vs);
1191   xjson_AddBoolToObject (result, "is_mime", decrypt_result->is_mime);
1192   xjson_AddBoolToObject (result, "legacy_cipher_nomdc",
1193                          decrypt_result->legacy_cipher_nomdc);
1194
1195   if (decrypt_result->recipients)
1196     {
1197       cjson_t array = xjson_CreateArray ();
1198       gpgme_recipient_t recp;
1199
1200       for (recp = decrypt_result->recipients; recp; recp = recp->next)
1201         cJSON_AddItemToArray (array, recipient_to_json (recp));
1202       xjson_AddItemToObject (result, "recipients", array);
1203     }
1204
1205   return result;
1206 }
1207
1208
1209 /* Create a JSON object from an engine_info */
1210 static cjson_t
1211 engine_info_to_json (gpgme_engine_info_t info)
1212 {
1213   cjson_t result = xjson_CreateObject ();
1214
1215   xjson_AddStringToObject0 (result, "protocol",
1216                             protocol_to_string (info->protocol));
1217   xjson_AddStringToObject0 (result, "fname", info->file_name);
1218   xjson_AddStringToObject0 (result, "version", info->version);
1219   xjson_AddStringToObject0 (result, "req_version", info->req_version);
1220   xjson_AddStringToObject0 (result, "homedir", info->home_dir ?
1221                                                 info->home_dir :
1222                                                 "default");
1223   return result;
1224 }
1225
1226
1227 /* Create a JSON object from an import_status */
1228 static cjson_t
1229 import_status_to_json (gpgme_import_status_t sts)
1230 {
1231   cjson_t result = xjson_CreateObject ();
1232
1233   xjson_AddStringToObject0 (result, "fingerprint", sts->fpr);
1234   xjson_AddStringToObject0 (result, "error_string",
1235                             gpgme_strerror (sts->result));
1236
1237   xjson_AddNumberToObject (result, "status", sts->status);
1238
1239   return result;
1240 }
1241
1242 /* Create a JSON object from an import result */
1243 static cjson_t
1244 import_result_to_json (gpgme_import_result_t imp)
1245 {
1246   cjson_t result = xjson_CreateObject ();
1247
1248   xjson_AddNumberToObject (result, "considered", imp->considered);
1249   xjson_AddNumberToObject (result, "no_user_id", imp->no_user_id);
1250   xjson_AddNumberToObject (result, "imported", imp->imported);
1251   xjson_AddNumberToObject (result, "imported_rsa", imp->imported_rsa);
1252   xjson_AddNumberToObject (result, "unchanged", imp->unchanged);
1253   xjson_AddNumberToObject (result, "new_user_ids", imp->new_user_ids);
1254   xjson_AddNumberToObject (result, "new_sub_keys", imp->new_sub_keys);
1255   xjson_AddNumberToObject (result, "new_signatures", imp->new_signatures);
1256   xjson_AddNumberToObject (result, "new_revocations", imp->new_revocations);
1257   xjson_AddNumberToObject (result, "secret_read", imp->secret_read);
1258   xjson_AddNumberToObject (result, "secret_imported", imp->secret_imported);
1259   xjson_AddNumberToObject (result, "secret_unchanged", imp->secret_unchanged);
1260   xjson_AddNumberToObject (result, "skipped_new_keys", imp->skipped_new_keys);
1261   xjson_AddNumberToObject (result, "not_imported", imp->not_imported);
1262   xjson_AddNumberToObject (result, "skipped_v3_keys", imp->skipped_v3_keys);
1263
1264
1265   if (imp->imports)
1266     {
1267       cjson_t array = xjson_CreateArray ();
1268       gpgme_import_status_t status;
1269
1270       for (status = imp->imports; status; status = status->next)
1271         cJSON_AddItemToArray (array, import_status_to_json (status));
1272       xjson_AddItemToObject (result, "imports", array);
1273     }
1274
1275   return result;
1276 }
1277
1278
1279 /* Create a JSON object from a gpgconf arg */
1280 static cjson_t
1281 conf_arg_to_json (gpgme_conf_arg_t arg, gpgme_conf_type_t type)
1282 {
1283   cjson_t result = xjson_CreateObject ();
1284   int is_none = 0;
1285   switch (type)
1286     {
1287       case GPGME_CONF_STRING:
1288       case GPGME_CONF_PATHNAME:
1289       case GPGME_CONF_LDAP_SERVER:
1290       case GPGME_CONF_KEY_FPR:
1291       case GPGME_CONF_PUB_KEY:
1292       case GPGME_CONF_SEC_KEY:
1293       case GPGME_CONF_ALIAS_LIST:
1294         xjson_AddStringToObject0 (result, "string", arg->value.string);
1295         break;
1296
1297       case GPGME_CONF_UINT32:
1298         xjson_AddNumberToObject (result, "number", arg->value.uint32);
1299         break;
1300
1301       case GPGME_CONF_INT32:
1302         xjson_AddNumberToObject (result, "number", arg->value.int32);
1303         break;
1304
1305       case GPGME_CONF_NONE:
1306       default:
1307         is_none = 1;
1308         break;
1309     }
1310   xjson_AddBoolToObject (result, "is_none", is_none);
1311   return result;
1312 }
1313
1314
1315 /* Create a JSON object from a gpgconf option */
1316 static cjson_t
1317 conf_opt_to_json (gpgme_conf_opt_t opt)
1318 {
1319   cjson_t result = xjson_CreateObject ();
1320
1321   xjson_AddStringToObject0 (result, "name", opt->name);
1322   xjson_AddStringToObject0 (result, "description", opt->description);
1323   xjson_AddStringToObject0 (result, "argname", opt->argname);
1324   xjson_AddStringToObject0 (result, "default_description",
1325                             opt->default_description);
1326   xjson_AddStringToObject0 (result, "no_arg_description",
1327                             opt->no_arg_description);
1328
1329   xjson_AddNumberToObject (result, "flags", opt->flags);
1330   xjson_AddNumberToObject (result, "level", opt->level);
1331   xjson_AddNumberToObject (result, "type", opt->type);
1332   xjson_AddNumberToObject (result, "alt_type", opt->alt_type);
1333
1334   if (opt->default_value)
1335     {
1336       cjson_t array = xjson_CreateArray ();
1337       gpgme_conf_arg_t arg;
1338
1339       for (arg = opt->default_value; arg; arg = arg->next)
1340         cJSON_AddItemToArray (array, conf_arg_to_json (arg, opt->alt_type));
1341       xjson_AddItemToObject (result, "default_value", array);
1342     }
1343
1344   if (opt->no_arg_value)
1345     {
1346       cjson_t array = xjson_CreateArray ();
1347       gpgme_conf_arg_t arg;
1348
1349       for (arg = opt->no_arg_value; arg; arg = arg->next)
1350         cJSON_AddItemToArray (array, conf_arg_to_json (arg, opt->alt_type));
1351       xjson_AddItemToObject (result, "no_arg_value", array);
1352     }
1353
1354   if (opt->value)
1355     {
1356       cjson_t array = xjson_CreateArray ();
1357       gpgme_conf_arg_t arg;
1358
1359       for (arg = opt->value; arg; arg = arg->next)
1360         cJSON_AddItemToArray (array, conf_arg_to_json (arg, opt->alt_type));
1361       xjson_AddItemToObject (result, "value", array);
1362     }
1363   return result;
1364 }
1365
1366
1367 /* Create a JSON object from a gpgconf component*/
1368 static cjson_t
1369 conf_comp_to_json (gpgme_conf_comp_t cmp)
1370 {
1371   cjson_t result = xjson_CreateObject ();
1372
1373   xjson_AddStringToObject0 (result, "name", cmp->name);
1374   xjson_AddStringToObject0 (result, "description", cmp->description);
1375   xjson_AddStringToObject0 (result, "program_name", cmp->program_name);
1376
1377
1378   if (cmp->options)
1379     {
1380       cjson_t array = xjson_CreateArray ();
1381       gpgme_conf_opt_t opt;
1382
1383       for (opt = cmp->options; opt; opt = opt->next)
1384         cJSON_AddItemToArray (array, conf_opt_to_json (opt));
1385       xjson_AddItemToObject (result, "options", array);
1386     }
1387
1388   return result;
1389 }
1390
1391
1392 /* Create a gpgme_data from json string data named "name"
1393  * in the request. Takes the base64 option into account.
1394  *
1395  * Adds an error to the "result" on error. */
1396 static gpg_error_t
1397 get_string_data (cjson_t request, cjson_t result, const char *name,
1398                  gpgme_data_t *r_data)
1399 {
1400   gpgme_error_t err;
1401   int opt_base64;
1402   cjson_t j_data;
1403
1404   if ((err = get_boolean_flag (request, "base64", 0, &opt_base64)))
1405     return err;
1406
1407   /* Get the data.  Note that INPUT is a shallow data object with the
1408    * storage hold in REQUEST.  */
1409   j_data = cJSON_GetObjectItem (request, name);
1410   if (!j_data)
1411     {
1412       return gpg_error (GPG_ERR_NO_DATA);
1413     }
1414   if (!cjson_is_string (j_data))
1415     {
1416       return gpg_error (GPG_ERR_INV_VALUE);
1417     }
1418   if (opt_base64)
1419     {
1420       err = data_from_base64_string (r_data, j_data);
1421       if (err)
1422         {
1423           gpg_error_object (result, err,
1424                             "Error decoding Base-64 encoded '%s': %s",
1425                             name, gpg_strerror (err));
1426           return err;
1427         }
1428     }
1429   else
1430     {
1431       err = gpgme_data_new_from_mem (r_data, j_data->valuestring,
1432                                      strlen (j_data->valuestring), 0);
1433       if (err)
1434         {
1435           gpg_error_object (result, err, "Error getting '%s': %s",
1436                             name, gpg_strerror (err));
1437           return err;
1438         }
1439     }
1440   return 0;
1441 }
1442
1443
1444 /* Create a "data" object and the "type" and "base64" flags
1445  * from DATA and append them to RESULT.  Ownership of DATA is
1446  * transferred to this function.  TYPE must be a fixed string.
1447  * If BASE64 is -1 the need for base64 encoding is determined
1448  * by the content of DATA, all other values are taken as true
1449  * or false. */
1450 static gpg_error_t
1451 make_data_object (cjson_t result, gpgme_data_t data,
1452                   const char *type, int base64)
1453 {
1454   gpg_error_t err;
1455   char *buffer;
1456   const char *s;
1457   size_t buflen, n;
1458
1459   if (!base64 || base64 == -1) /* Make sure that we really have a string.  */
1460     gpgme_data_write (data, "", 1);
1461
1462   buffer = gpgme_data_release_and_get_mem (data, &buflen);
1463   data = NULL;
1464   if (!buffer)
1465     {
1466       err = gpg_error_from_syserror ();
1467       goto leave;
1468     }
1469
1470   if (base64 == -1)
1471     {
1472       base64 = 0;
1473       if (!buflen)
1474         log_fatal ("Appended Nul byte got lost\n");
1475       /* Figure out if there is any Nul octet in the buffer.  In that
1476        * case we need to Base-64 the buffer.  Due to problems with the
1477        * browser's Javascript we use Base-64 also in case an UTF-8
1478        * character is in the buffer.  This is because the chunking may
1479        * split an UTF-8 characters and JS can't handle this.  */
1480       for (s=buffer, n=0; n < buflen -1; s++, n++)
1481         if (!*s || (*s & 0x80))
1482           {
1483             buflen--; /* Adjust for the extra nul byte.  */
1484             base64 = 1;
1485             break;
1486           }
1487     }
1488
1489   xjson_AddStringToObject (result, "type", type);
1490   xjson_AddBoolToObject (result, "base64", base64);
1491
1492   if (base64)
1493     err = add_base64_to_object (result, "data", buffer, buflen);
1494   else
1495     err = cjson_AddStringToObject (result, "data", buffer);
1496
1497  leave:
1498   gpgme_free (buffer);
1499   return err;
1500 }
1501
1502
1503 /* Encode and chunk response.
1504  *
1505  * If necessary this base64 encodes and chunks the response
1506  * for getmore so that we always return valid json independent
1507  * of the chunksize.
1508  *
1509  * A chunked response contains the base64 encoded chunk
1510  * as a string and a boolean if there is still more data
1511  * available for getmore like:
1512  * {
1513  *   chunk: "SGVsbG8gV29ybGQK"
1514  *   more: true
1515  * }
1516  *
1517  * Chunking is only done if the response is larger then the
1518  * chunksize.
1519  *
1520  * caller has to xfree the return value.
1521  */
1522 static char *
1523 encode_and_chunk (cjson_t request, cjson_t response)
1524 {
1525   char *data;
1526   gpg_error_t err = 0;
1527   size_t chunksize = 0;
1528   char *getmore_request = NULL;
1529
1530   if (opt_interactive)
1531     data = cJSON_Print (response);
1532   else
1533     data = cJSON_PrintUnformatted (response);
1534
1535   if (!data)
1536     {
1537       err = GPG_ERR_NO_DATA;
1538       goto leave;
1539     }
1540
1541   if (!request)
1542     {
1543       goto leave;
1544     }
1545
1546   if ((err = get_chunksize (request, &chunksize)))
1547     {
1548       err = GPG_ERR_INV_VALUE;
1549       goto leave;
1550     }
1551
1552   if (!chunksize)
1553     goto leave;
1554
1555   pending_data.buffer = data;
1556   /* Data should already be encoded so that it does not
1557      contain 0.*/
1558   pending_data.length = strlen (data);
1559   pending_data.written = 0;
1560
1561   if (gpgrt_asprintf (&getmore_request,
1562                   "{ \"op\":\"getmore\", \"chunksize\": %i }",
1563                   (int) chunksize) == -1)
1564     {
1565       err = gpg_error_from_syserror ();
1566       goto leave;
1567     }
1568
1569   data = process_request (getmore_request);
1570
1571 leave:
1572   xfree (getmore_request);
1573
1574   if (!err && !data)
1575     {
1576       err = GPG_ERR_GENERAL;
1577     }
1578
1579   if (err)
1580     {
1581       cjson_t err_obj = gpg_error_object (NULL, err,
1582                                           "Encode and chunk failed: %s",
1583                                           gpgme_strerror (err));
1584       xfree (data);
1585       if (opt_interactive)
1586         data = cJSON_Print (err_obj);
1587       data = cJSON_PrintUnformatted (err_obj);
1588
1589       cJSON_Delete (err_obj);
1590     }
1591
1592   return data;
1593 }
1594
1595
1596 \f
1597 /*
1598  * Implementation of the commands.
1599  */
1600 static const char hlp_encrypt[] =
1601   "op:     \"encrypt\"\n"
1602   "keys:   Array of strings with the fingerprints or user-ids\n"
1603   "        of the keys to encrypt the data.  For a single key\n"
1604   "        a String may be used instead of an array.\n"
1605   "data:   Input data. \n"
1606   "\n"
1607   "Optional parameters:\n"
1608   "protocol:      Either \"openpgp\" (default) or \"cms\".\n"
1609   "signing_keys:  Similar to the keys parameter for added signing.\n"
1610   "               (openpgp only)"
1611   "file_name:     The file name associated with the data.\n"
1612   "sender:        Sender info to embed in a signature.\n"
1613   "\n"
1614   "Optional boolean flags (default is false):\n"
1615   "base64:        Input data is base64 encoded.\n"
1616   "mime:          Indicate that data is a MIME object.\n"
1617   "armor:         Request output in armored format.\n"
1618   "always-trust:  Request --always-trust option.\n"
1619   "no-encrypt-to: Do not use a default recipient.\n"
1620   "no-compress:   Do not compress the plaintext first.\n"
1621   "throw-keyids:  Request the --throw-keyids option.\n"
1622   "want-address:  Require that the keys include a mail address.\n"
1623   "wrap:          Assume the input is an OpenPGP message.\n"
1624   "\n"
1625   "Response on success:\n"
1626   "type:   \"ciphertext\"\n"
1627   "data:   Unless armor mode is used a Base64 encoded binary\n"
1628   "        ciphertext.  In armor mode a string with an armored\n"
1629   "        OpenPGP or a PEM message.\n"
1630   "base64: Boolean indicating whether data is base64 encoded.";
1631 static gpg_error_t
1632 op_encrypt (cjson_t request, cjson_t result)
1633 {
1634   gpg_error_t err;
1635   gpgme_ctx_t ctx = NULL;
1636   gpgme_protocol_t protocol;
1637   char **signing_patterns = NULL;
1638   int opt_mime;
1639   char *keystring = NULL;
1640   char *file_name = NULL;
1641   gpgme_data_t input = NULL;
1642   gpgme_data_t output = NULL;
1643   int abool;
1644   gpgme_encrypt_flags_t encrypt_flags = 0;
1645   gpgme_ctx_t keylist_ctx = NULL;
1646   gpgme_key_t key = NULL;
1647   cjson_t j_tmp = NULL;
1648
1649   if ((err = get_protocol (request, &protocol)))
1650     goto leave;
1651   ctx = get_context (protocol);
1652
1653   if ((err = get_boolean_flag (request, "mime", 0, &opt_mime)))
1654     goto leave;
1655
1656   if ((err = get_boolean_flag (request, "armor", 0, &abool)))
1657     goto leave;
1658   gpgme_set_armor (ctx, abool);
1659   if ((err = get_boolean_flag (request, "always-trust", 0, &abool)))
1660     goto leave;
1661   if (abool)
1662     encrypt_flags |= GPGME_ENCRYPT_ALWAYS_TRUST;
1663   if ((err = get_boolean_flag (request, "no-encrypt-to", 0,&abool)))
1664     goto leave;
1665   if (abool)
1666     encrypt_flags |= GPGME_ENCRYPT_NO_ENCRYPT_TO;
1667   if ((err = get_boolean_flag (request, "no-compress", 0, &abool)))
1668     goto leave;
1669   if (abool)
1670     encrypt_flags |= GPGME_ENCRYPT_NO_COMPRESS;
1671   if ((err = get_boolean_flag (request, "throw-keyids", 0, &abool)))
1672     goto leave;
1673   if (abool)
1674     encrypt_flags |= GPGME_ENCRYPT_THROW_KEYIDS;
1675   if ((err = get_boolean_flag (request, "wrap", 0, &abool)))
1676     goto leave;
1677   if (abool)
1678     encrypt_flags |= GPGME_ENCRYPT_WRAP;
1679   if ((err = get_boolean_flag (request, "want-address", 0, &abool)))
1680     goto leave;
1681   if (abool)
1682     encrypt_flags |= GPGME_ENCRYPT_WANT_ADDRESS;
1683
1684   j_tmp = cJSON_GetObjectItem (request, "file_name");
1685   if (j_tmp && cjson_is_string (j_tmp))
1686     {
1687       file_name = j_tmp->valuestring;
1688     }
1689
1690   j_tmp = cJSON_GetObjectItem (request, "sender");
1691   if (j_tmp && cjson_is_string (j_tmp))
1692     {
1693       gpgme_set_sender (ctx, j_tmp->valuestring);
1694     }
1695
1696   /* Get the keys.  */
1697   err = get_keys (request, "keys", &keystring);
1698   if (err)
1699     {
1700       /* Provide a custom error response.  */
1701       gpg_error_object (result, err, "Error getting keys: %s",
1702                         gpg_strerror (err));
1703       goto leave;
1704     }
1705
1706   /* Do we have signing keys ? */
1707   signing_patterns = create_keylist_patterns (request, "signing_keys");
1708   if (signing_patterns)
1709     {
1710       keylist_ctx = create_onetime_context (protocol);
1711       gpgme_set_keylist_mode (keylist_ctx, GPGME_KEYLIST_MODE_LOCAL);
1712
1713       err = gpgme_op_keylist_ext_start (keylist_ctx,
1714                                         (const char **) signing_patterns,
1715                                         1, 0);
1716       if (err)
1717         {
1718           gpg_error_object (result, err, "Error listing keys: %s",
1719                             gpg_strerror (err));
1720           goto leave;
1721         }
1722       while (!(err = gpgme_op_keylist_next (keylist_ctx, &key)))
1723         {
1724           if ((err = gpgme_signers_add (ctx, key)))
1725             {
1726               gpg_error_object (result, err, "Error adding signer: %s",
1727                                 gpg_strerror (err));
1728               goto leave;
1729             }
1730           gpgme_key_unref (key);
1731           key = NULL;
1732         }
1733       release_onetime_context (keylist_ctx);
1734       keylist_ctx = NULL;
1735     }
1736
1737   if ((err = get_string_data (request, result, "data", &input)))
1738       goto leave;
1739
1740   if (opt_mime)
1741     gpgme_data_set_encoding (input, GPGME_DATA_ENCODING_MIME);
1742
1743   if (file_name)
1744     {
1745       gpgme_data_set_file_name (input, file_name);
1746     }
1747
1748   /* Create an output data object.  */
1749   err = gpgme_data_new (&output);
1750   if (err)
1751     {
1752       gpg_error_object (result, err, "Error creating output data object: %s",
1753                         gpg_strerror (err));
1754       goto leave;
1755     }
1756
1757   /* Encrypt.  */
1758   if (!signing_patterns)
1759     {
1760       err = gpgme_op_encrypt_ext (ctx, NULL, keystring, encrypt_flags,
1761                                   input, output);
1762     }
1763   else
1764     {
1765       err = gpgme_op_encrypt_sign_ext (ctx, NULL, keystring, encrypt_flags,
1766                                        input, output);
1767
1768     }
1769   /* encrypt_result = gpgme_op_encrypt_result (ctx); */
1770   if (err)
1771     {
1772       gpg_error_object (result, err, "Encryption failed: %s",
1773                         gpg_strerror (err));
1774       goto leave;
1775     }
1776   gpgme_data_release (input);
1777   input = NULL;
1778
1779   /* We need to base64 if armoring has not been requested.  */
1780   err = make_data_object (result, output,
1781                           "ciphertext", !gpgme_get_armor (ctx));
1782   output = NULL;
1783
1784  leave:
1785   xfree_array (signing_patterns);
1786   xfree (keystring);
1787   release_onetime_context (keylist_ctx);
1788   /* Reset sender in case the context is reused */
1789   gpgme_set_sender (ctx, NULL);
1790   gpgme_key_unref (key);
1791   gpgme_signers_clear (ctx);
1792   release_context (ctx);
1793   gpgme_data_release (input);
1794   gpgme_data_release (output);
1795   return err;
1796 }
1797
1798
1799 \f
1800 static const char hlp_decrypt[] =
1801   "op:     \"decrypt\"\n"
1802   "data:   The encrypted data.\n"
1803   "\n"
1804   "Optional parameters:\n"
1805   "protocol:      Either \"openpgp\" (default) or \"cms\".\n"
1806   "\n"
1807   "Optional boolean flags (default is false):\n"
1808   "base64:        Input data is base64 encoded.\n"
1809   "\n"
1810   "Response on success:\n"
1811   "type:     \"plaintext\"\n"
1812   "data:     The decrypted data.  This may be base64 encoded.\n"
1813   "base64:   Boolean indicating whether data is base64 encoded.\n"
1814   "mime:     deprecated - use dec_info is_mime instead\n"
1815   "dec_info: An object with decryption information. (gpgme_decrypt_result_t)\n"
1816   " Boolean values:\n"
1817   "  wrong_key_usage:     Key should not have been used for encryption.\n"
1818   "  is_de_vs:            Message was encrypted in compliance to the de-vs\n"
1819   "                       mode.\n"
1820   "  is_mime:             Message claims that the content is a MIME Message.\n"
1821   "  legacy_cipher_nomdc: The message was made by a legacy algorithm\n"
1822   "                       without integrity protection.\n"
1823   " String values:\n"
1824   "  file_name:   The filename contained in the decrypt result.\n"
1825   "  symkey_algo: A string with the symmetric encryption algorithm and\n"
1826   "               mode using the format \"<algo>.<mode>\".\n"
1827   " Array values:\n"
1828   "  recipients:  The list of recipients (gpgme_recipient_t).\n"
1829   "   String values:\n"
1830   "    keyid:            The keyid of the recipient.\n"
1831   "    pubkey_algo_name: gpgme_pubkey_algo_name of used algo.\n"
1832   "    status_string:    The status code as localized gpg-error string\n"
1833   "   Number values:\n"
1834   "    status_code:      The status as a number. (gpg_error_t)\n"
1835   "info:     Optional an object with verification information.\n"
1836   "          (gpgme_verify_result_t)\n"
1837   " file_name: The filename contained in the verify result.\n"
1838   " is_mime:   The is_mime info contained in the verify result.\n"
1839   " signatures: Array of signatures\n"
1840   "  summary: Object containing summary information.\n"
1841   "   Boolean values: (Check gpgme_sigsum_t doc for meaning)\n"
1842   "    valid\n"
1843   "    green\n"
1844   "    red\n"
1845   "    revoked\n"
1846   "    key-expired\n"
1847   "    sig-expired\n"
1848   "    key-missing\n"
1849   "    crl-missing\n"
1850   "    crl-too-old\n"
1851   "    bad-policy\n"
1852   "    sys-error\n"
1853   "   sigsum: Array of strings representing the sigsum.\n"
1854   "  Boolean values:\n"
1855   "   wrong_key_usage: Key should not have been used for signing.\n"
1856   "   chain_model:     Validity has been verified using the chain model.\n"
1857   "   is_de_vs:        signature is in compliance to the de-vs mode.\n"
1858   "  String values:\n"
1859   "   status_string:      The status code as localized gpg-error string\n"
1860   "   fingerprint:        The fingerprint of the signing key.\n"
1861   "   validity_string:    The validity as string.\n"
1862   "   pubkey_algo_name:   gpgme_pubkey_algo_name of used algo.\n"
1863   "   hash_algo_name:     gpgme_hash_algo_name of used hash algo\n"
1864   "   pka_address:        The mailbox from the PKA information.\n"
1865   "  Number values:\n"
1866   "   status_code:     The status as a number. (gpg_error_t)\n"
1867   "   timestamp:       Signature creation time. (secs since epoch)\n"
1868   "   exp_timestamp:   Signature expiration or 0. (secs since epoch)\n"
1869   "   pka_trust: PKA status: 0 = not available, 1 = bad, 2 = okay, 3 = RFU.\n"
1870   "   validity: validity as number (gpgme_validity_t)\n"
1871   "   validity_reason: (gpg_error_t)\n"
1872   "  Array values:\n"
1873   "   notations: Notation data and policy urls (gpgme_sig_notation_t)\n"
1874   "    Boolean values:\n"
1875   "     human_readable\n"
1876   "     critical\n"
1877   "    String values:\n"
1878   "     name\n"
1879   "     value\n"
1880   "    Number values:\n"
1881   "     flags\n";
1882 static gpg_error_t
1883 op_decrypt (cjson_t request, cjson_t result)
1884 {
1885   gpg_error_t err;
1886   gpgme_ctx_t ctx = NULL;
1887   gpgme_protocol_t protocol;
1888   gpgme_data_t input = NULL;
1889   gpgme_data_t output = NULL;
1890   gpgme_decrypt_result_t decrypt_result;
1891   gpgme_verify_result_t verify_result;
1892
1893   if ((err = get_protocol (request, &protocol)))
1894     goto leave;
1895   ctx = get_context (protocol);
1896
1897   if ((err = get_string_data (request, result, "data", &input)))
1898       goto leave;
1899
1900   /* Create an output data object.  */
1901   err = gpgme_data_new (&output);
1902   if (err)
1903     {
1904       gpg_error_object (result, err,
1905                         "Error creating output data object: %s",
1906                         gpg_strerror (err));
1907       goto leave;
1908     }
1909
1910   /* Decrypt.  */
1911   err = gpgme_op_decrypt_ext (ctx, GPGME_DECRYPT_VERIFY,
1912                               input, output);
1913   decrypt_result = gpgme_op_decrypt_result (ctx);
1914   if (err)
1915     {
1916       gpg_error_object (result, err, "Decryption failed: %s",
1917                         gpg_strerror (err));
1918       goto leave;
1919     }
1920   gpgme_data_release (input);
1921   input = NULL;
1922
1923   if (decrypt_result->is_mime)
1924     xjson_AddBoolToObject (result, "mime", 1);
1925
1926   xjson_AddItemToObject (result, "dec_info",
1927                          decrypt_result_to_json (decrypt_result));
1928
1929   verify_result = gpgme_op_verify_result (ctx);
1930   if (verify_result && verify_result->signatures)
1931     {
1932       xjson_AddItemToObject (result, "info",
1933                              verify_result_to_json (verify_result));
1934     }
1935
1936   err = make_data_object (result, output, "plaintext", -1);
1937   output = NULL;
1938
1939   if (err)
1940     {
1941       gpg_error_object (result, err, "Plaintext output failed: %s",
1942                         gpg_strerror (err));
1943       goto leave;
1944     }
1945
1946  leave:
1947   release_context (ctx);
1948   gpgme_data_release (input);
1949   gpgme_data_release (output);
1950   return err;
1951 }
1952
1953
1954 \f
1955 static const char hlp_sign[] =
1956   "op:     \"sign\"\n"
1957   "keys:   Array of strings with the fingerprints of the signing key.\n"
1958   "        For a single key a String may be used instead of an array.\n"
1959   "data:   Input data. \n"
1960   "\n"
1961   "Optional parameters:\n"
1962   "protocol:      Either \"openpgp\" (default) or \"cms\".\n"
1963   "sender:        The mail address of the sender.\n"
1964   "mode:          A string with the signing mode can be:\n"
1965   "               detached (default)\n"
1966   "               opaque\n"
1967   "               clearsign\n"
1968   "\n"
1969   "Optional boolean flags (default is false):\n"
1970   "base64:        Input data is base64 encoded.\n"
1971   "armor:         Request output in armored format.\n"
1972   "\n"
1973   "Response on success:\n"
1974   "type:   \"signature\"\n"
1975   "data:   Unless armor mode is used a Base64 encoded binary\n"
1976   "        signature.  In armor mode a string with an armored\n"
1977   "        OpenPGP or a PEM message.\n"
1978   "base64: Boolean indicating whether data is base64 encoded.\n";
1979 static gpg_error_t
1980 op_sign (cjson_t request, cjson_t result)
1981 {
1982   gpg_error_t err;
1983   gpgme_ctx_t ctx = NULL;
1984   gpgme_protocol_t protocol;
1985   char **patterns = NULL;
1986   gpgme_data_t input = NULL;
1987   gpgme_data_t output = NULL;
1988   int abool;
1989   cjson_t j_tmp;
1990   gpgme_sig_mode_t mode = GPGME_SIG_MODE_DETACH;
1991   gpgme_ctx_t keylist_ctx = NULL;
1992   gpgme_key_t key = NULL;
1993
1994   if ((err = get_protocol (request, &protocol)))
1995     goto leave;
1996   ctx = get_context (protocol);
1997
1998   if ((err = get_boolean_flag (request, "armor", 0, &abool)))
1999     goto leave;
2000   gpgme_set_armor (ctx, abool);
2001
2002   j_tmp = cJSON_GetObjectItem (request, "mode");
2003   if (j_tmp && cjson_is_string (j_tmp))
2004     {
2005       if (!strcmp (j_tmp->valuestring, "opaque"))
2006         {
2007           mode = GPGME_SIG_MODE_NORMAL;
2008         }
2009       else if (!strcmp (j_tmp->valuestring, "clearsign"))
2010         {
2011           mode = GPGME_SIG_MODE_CLEAR;
2012         }
2013     }
2014
2015   j_tmp = cJSON_GetObjectItem (request, "sender");
2016   if (j_tmp && cjson_is_string (j_tmp))
2017     {
2018       gpgme_set_sender (ctx, j_tmp->valuestring);
2019     }
2020
2021   patterns = create_keylist_patterns (request, "keys");
2022   if (!patterns)
2023     {
2024       gpg_error_object (result, err, "Error getting keys: %s",
2025                         gpg_strerror (gpg_error (GPG_ERR_NO_KEY)));
2026       goto leave;
2027     }
2028
2029   /* Do a keylisting and add the keys */
2030   keylist_ctx = create_onetime_context (protocol);
2031   gpgme_set_keylist_mode (keylist_ctx, GPGME_KEYLIST_MODE_LOCAL);
2032
2033   err = gpgme_op_keylist_ext_start (keylist_ctx,
2034                                     (const char **) patterns, 1, 0);
2035   if (err)
2036     {
2037       gpg_error_object (result, err, "Error listing keys: %s",
2038                         gpg_strerror (err));
2039       goto leave;
2040     }
2041   while (!(err = gpgme_op_keylist_next (keylist_ctx, &key)))
2042     {
2043       if ((err = gpgme_signers_add (ctx, key)))
2044         {
2045           gpg_error_object (result, err, "Error adding signer: %s",
2046                             gpg_strerror (err));
2047           goto leave;
2048         }
2049       gpgme_key_unref (key);
2050       key = NULL;
2051     }
2052
2053   if ((err = get_string_data (request, result, "data", &input)))
2054     goto leave;
2055
2056   /* Create an output data object.  */
2057   err = gpgme_data_new (&output);
2058   if (err)
2059     {
2060       gpg_error_object (result, err, "Error creating output data object: %s",
2061                         gpg_strerror (err));
2062       goto leave;
2063     }
2064
2065   /* Sign. */
2066   err = gpgme_op_sign (ctx, input, output, mode);
2067   if (err)
2068     {
2069       gpg_error_object (result, err, "Signing failed: %s",
2070                         gpg_strerror (err));
2071       goto leave;
2072     }
2073
2074   gpgme_data_release (input);
2075   input = NULL;
2076
2077   /* We need to base64 if armoring has not been requested.  */
2078   err = make_data_object (result, output,
2079                           "signature", !gpgme_get_armor (ctx));
2080   output = NULL;
2081
2082  leave:
2083   xfree_array (patterns);
2084   gpgme_signers_clear (ctx);
2085   gpgme_key_unref (key);
2086   release_onetime_context (keylist_ctx);
2087   release_context (ctx);
2088   gpgme_data_release (input);
2089   gpgme_data_release (output);
2090   return err;
2091 }
2092
2093
2094 \f
2095 static const char hlp_verify[] =
2096   "op:     \"verify\"\n"
2097   "data:   The data to verify.\n"
2098   "\n"
2099   "Optional parameters:\n"
2100   "protocol:      Either \"openpgp\" (default) or \"cms\".\n"
2101   "signature:     A detached signature. If missing opaque is assumed.\n"
2102   "\n"
2103   "Optional boolean flags (default is false):\n"
2104   "base64:        Input data is base64 encoded.\n"
2105   "\n"
2106   "Response on success:\n"
2107   "type:   \"plaintext\"\n"
2108   "data:   The verified data.  This may be base64 encoded.\n"
2109   "base64: Boolean indicating whether data is base64 encoded.\n"
2110   "info:   An object with verification information (gpgme_verify_result_t).\n"
2111   " is_mime:    Boolean that is true if the messages claims it is MIME.\n"
2112   "             Note that this flag is not covered by the signature.)\n"
2113   " signatures: Array of signatures\n"
2114   "  summary: Object containing summary information.\n"
2115   "   Boolean values: (Check gpgme_sigsum_t doc for meaning)\n"
2116   "    valid\n"
2117   "    green\n"
2118   "    red\n"
2119   "    revoked\n"
2120   "    key-expired\n"
2121   "    sig-expired\n"
2122   "    key-missing\n"
2123   "    crl-missing\n"
2124   "    crl-too-old\n"
2125   "    bad-policy\n"
2126   "    sys-error\n"
2127   "   sigsum: Array of strings representing the sigsum.\n"
2128   "  Boolean values:\n"
2129   "   wrong_key_usage: Key should not have been used for signing.\n"
2130   "   chain_model:     Validity has been verified using the chain model.\n"
2131   "   is_de_vs:        signature is in compliance to the de-vs mode.\n"
2132   "  String values:\n"
2133   "   status_string:      The status code as localized gpg-error string\n"
2134   "   fingerprint:        The fingerprint of the signing key.\n"
2135   "   validity_string:    The validity as string.\n"
2136   "   pubkey_algo_name:   gpgme_pubkey_algo_name of used algo.\n"
2137   "   hash_algo_name:     gpgme_hash_algo_name of used hash algo\n"
2138   "   pka_address:        The mailbox from the PKA information.\n"
2139   "  Number values:\n"
2140   "   status_code:     The status as a number. (gpg_error_t)\n"
2141   "   timestamp:       Signature creation time. (secs since epoch)\n"
2142   "   exp_timestamp:   Signature expiration or 0. (secs since epoch)\n"
2143   "   pka_trust: PKA status: 0 = not available, 1 = bad, 2 = okay, 3 = RFU.\n"
2144   "   validity: validity as number (gpgme_validity_t)\n"
2145   "   validity_reason: (gpg_error_t)\n"
2146   "  Array values:\n"
2147   "   notations: Notation data and policy urls (gpgme_sig_notation_t)\n"
2148   "    Boolean values:\n"
2149   "     human_readable\n"
2150   "     critical\n"
2151   "    String values:\n"
2152   "     name\n"
2153   "     value\n"
2154   "    Number values:\n"
2155   "     flags\n";
2156 static gpg_error_t
2157 op_verify (cjson_t request, cjson_t result)
2158 {
2159   gpg_error_t err;
2160   gpgme_ctx_t ctx = NULL;
2161   gpgme_protocol_t protocol;
2162   gpgme_data_t input = NULL;
2163   gpgme_data_t signature = NULL;
2164   gpgme_data_t output = NULL;
2165   gpgme_verify_result_t verify_result;
2166
2167   if ((err = get_protocol (request, &protocol)))
2168     goto leave;
2169   ctx = get_context (protocol);
2170
2171   if ((err = get_string_data (request, result, "data", &input)))
2172     goto leave;
2173
2174   err = get_string_data (request, result, "signature", &signature);
2175   /* Signature data is optional otherwise we expect opaque or clearsigned. */
2176   if (err && err != gpg_error (GPG_ERR_NO_DATA))
2177     goto leave;
2178
2179   if (!signature)
2180     {
2181       /* Verify opaque or clearsigned we need an output data object.  */
2182       err = gpgme_data_new (&output);
2183       if (err)
2184         {
2185           gpg_error_object (result, err,
2186                             "Error creating output data object: %s",
2187                             gpg_strerror (err));
2188           goto leave;
2189         }
2190       err = gpgme_op_verify (ctx, input, 0, output);
2191     }
2192   else
2193     {
2194       err = gpgme_op_verify (ctx, signature, input, NULL);
2195     }
2196
2197   if (err)
2198     {
2199       gpg_error_object (result, err, "Verify failed: %s", gpg_strerror (err));
2200       goto leave;
2201     }
2202   gpgme_data_release (input);
2203   input = NULL;
2204   gpgme_data_release (signature);
2205   signature = NULL;
2206
2207   verify_result = gpgme_op_verify_result (ctx);
2208   if (verify_result && verify_result->signatures)
2209     {
2210       xjson_AddItemToObject (result, "info",
2211                              verify_result_to_json (verify_result));
2212     }
2213
2214   if (output)
2215     {
2216       err = make_data_object (result, output, "plaintext", -1);
2217       output = NULL;
2218
2219       if (err)
2220         {
2221           gpg_error_object (result, err, "Plaintext output failed: %s",
2222                             gpg_strerror (err));
2223           goto leave;
2224         }
2225     }
2226
2227  leave:
2228   release_context (ctx);
2229   gpgme_data_release (input);
2230   gpgme_data_release (output);
2231   gpgme_data_release (signature);
2232   return err;
2233 }
2234
2235
2236 \f
2237 static const char hlp_version[] =
2238   "op:     \"version\"\n"
2239   "\n"
2240   "Response on success:\n"
2241   "gpgme:  The GPGME Version.\n"
2242   "info:   dump of engine info. containing:\n"
2243   "        protocol: The protocol.\n"
2244   "        fname:    The file name.\n"
2245   "        version:  The version.\n"
2246   "        req_ver:  The required version.\n"
2247   "        homedir:  The homedir of the engine or \"default\".\n";
2248 static gpg_error_t
2249 op_version (cjson_t request, cjson_t result)
2250 {
2251   gpg_error_t err = 0;
2252   gpgme_engine_info_t ei = NULL;
2253   cjson_t infos = xjson_CreateArray ();
2254
2255   (void)request;
2256
2257   if (!cJSON_AddStringToObject (result, "gpgme", gpgme_check_version (NULL)))
2258     {
2259       cJSON_Delete (infos);
2260       return gpg_error_from_syserror ();
2261     }
2262
2263   if ((err = gpgme_get_engine_info (&ei)))
2264     {
2265       cJSON_Delete (infos);
2266       return err;
2267     }
2268
2269   for (; ei; ei = ei->next)
2270     cJSON_AddItemToArray (infos, engine_info_to_json (ei));
2271
2272   if (!cJSON_AddItemToObject (result, "info", infos))
2273     {
2274       err = gpg_error_from_syserror ();
2275       cJSON_Delete (infos);
2276       return err;
2277     }
2278
2279   return 0;
2280 }
2281
2282
2283 \f
2284 static const char hlp_keylist[] =
2285   "op:     \"keylist\"\n"
2286   "\n"
2287   "Optional parameters:\n"
2288   "keys:          Array of strings or fingerprints to lookup\n"
2289   "               For a single key a String may be used instead of an array.\n"
2290   "               default lists all keys.\n"
2291   "protocol:      Either \"openpgp\" (default) or \"cms\".\n"
2292   "\n"
2293   "Optional boolean flags (default is false):\n"
2294   "secret:        List only secret keys.\n"
2295   "with-secret:   Add KEYLIST_MODE_WITH_SECRET.\n"
2296   "extern:        Add KEYLIST_MODE_EXTERN.\n"
2297   "local:         Add KEYLIST_MODE_LOCAL. (default mode).\n"
2298   "sigs:          Add KEYLIST_MODE_SIGS.\n"
2299   "notations:     Add KEYLIST_MODE_SIG_NOTATIONS.\n"
2300   "tofu:          Add KEYLIST_MODE_WITH_TOFU.\n"
2301   "ephemeral:     Add KEYLIST_MODE_EPHEMERAL.\n"
2302   "validate:      Add KEYLIST_MODE_VALIDATE.\n"
2303   "locate:        Add KEYLIST_MODE_LOCATE.\n"
2304   "\n"
2305   "Response on success:\n"
2306   "keys:   Array of keys.\n"
2307   "  Boolean values:\n"
2308   "   revoked\n"
2309   "   expired\n"
2310   "   disabled\n"
2311   "   invalid\n"
2312   "   can_encrypt\n"
2313   "   can_sign\n"
2314   "   can_certify\n"
2315   "   can_authenticate\n"
2316   "   secret\n"
2317   "   is_qualified\n"
2318   "  String values:\n"
2319   "   protocol\n"
2320   "   issuer_serial (CMS Only)\n"
2321   "   issuer_name (CMS Only)\n"
2322   "   chain_id (CMS Only)\n"
2323   "   owner_trust (OpenPGP only)\n"
2324   "   fingerprint\n"
2325   "  Number values:\n"
2326   "   last_update\n"
2327   "   origin\n"
2328   "  Array values:\n"
2329   "   subkeys\n"
2330   "    Boolean values:\n"
2331   "     revoked\n"
2332   "     expired\n"
2333   "     disabled\n"
2334   "     invalid\n"
2335   "     can_encrypt\n"
2336   "     can_sign\n"
2337   "     can_certify\n"
2338   "     can_authenticate\n"
2339   "     secret\n"
2340   "     is_qualified\n"
2341   "     is_cardkey\n"
2342   "     is_de_vs\n"
2343   "    String values:\n"
2344   "     pubkey_algo_name\n"
2345   "     pubkey_algo_string\n"
2346   "     keyid\n"
2347   "     card_number\n"
2348   "     curve\n"
2349   "     keygrip\n"
2350   "    Number values:\n"
2351   "     pubkey_algo\n"
2352   "     length\n"
2353   "     timestamp\n"
2354   "     expires\n"
2355   "   userids\n"
2356   "    Boolean values:\n"
2357   "     revoked\n"
2358   "     invalid\n"
2359   "    String values:\n"
2360   "     validity\n"
2361   "     uid\n"
2362   "     name\n"
2363   "     email\n"
2364   "     comment\n"
2365   "     address\n"
2366   "    Number values:\n"
2367   "     origin\n"
2368   "     last_update\n"
2369   "    Array values:\n"
2370   "     signatures\n"
2371   "      Boolean values:\n"
2372   "       revoked\n"
2373   "       expired\n"
2374   "       invalid\n"
2375   "       exportable\n"
2376   "      String values:\n"
2377   "       pubkey_algo_name\n"
2378   "       keyid\n"
2379   "       status\n"
2380   "       uid\n"
2381   "       name\n"
2382   "       email\n"
2383   "       comment\n"
2384   "      Number values:\n"
2385   "       pubkey_algo\n"
2386   "       timestamp\n"
2387   "       expires\n"
2388   "       status_code\n"
2389   "       sig_class\n"
2390   "      Array values:\n"
2391   "       notations\n"
2392   "        Boolean values:\n"
2393   "         human_readable\n"
2394   "         critical\n"
2395   "        String values:\n"
2396   "         name\n"
2397   "         value\n"
2398   "        Number values:\n"
2399   "         flags\n"
2400   "     tofu\n"
2401   "      String values:\n"
2402   "       description\n"
2403   "      Number values:\n"
2404   "       validity\n"
2405   "       policy\n"
2406   "       signcount\n"
2407   "       encrcount\n"
2408   "       signfirst\n"
2409   "       signlast\n"
2410   "       encrfirst\n"
2411   "       encrlast\n";
2412 static gpg_error_t
2413 op_keylist (cjson_t request, cjson_t result)
2414 {
2415   gpg_error_t err;
2416   gpgme_ctx_t ctx = NULL;
2417   gpgme_protocol_t protocol;
2418   char **patterns = NULL;
2419   int abool;
2420   int secret_only = 0;
2421   gpgme_keylist_mode_t mode = 0;
2422   gpgme_key_t key = NULL;
2423   cjson_t keyarray = xjson_CreateArray ();
2424
2425   if ((err = get_protocol (request, &protocol)))
2426     goto leave;
2427   ctx = get_context (protocol);
2428
2429   /* Handle the various keylist mode bools. */
2430   if ((err = get_boolean_flag (request, "secret", 0, &abool)))
2431     goto leave;
2432   if (abool)
2433     {
2434       mode |= GPGME_KEYLIST_MODE_WITH_SECRET;
2435       secret_only = 1;
2436     }
2437   if ((err = get_boolean_flag (request, "with-secret", 0, &abool)))
2438     goto leave;
2439   if (abool)
2440     mode |= GPGME_KEYLIST_MODE_WITH_SECRET;
2441   if ((err = get_boolean_flag (request, "extern", 0, &abool)))
2442     goto leave;
2443   if (abool)
2444     mode |= GPGME_KEYLIST_MODE_EXTERN;
2445
2446   if ((err = get_boolean_flag (request, "local", 0, &abool)))
2447     goto leave;
2448   if (abool)
2449     mode |= GPGME_KEYLIST_MODE_LOCAL;
2450
2451   if ((err = get_boolean_flag (request, "sigs", 0, &abool)))
2452     goto leave;
2453   if (abool)
2454     mode |= GPGME_KEYLIST_MODE_SIGS;
2455
2456   if ((err = get_boolean_flag (request, "notations", 0, &abool)))
2457     goto leave;
2458   if (abool)
2459     mode |= GPGME_KEYLIST_MODE_SIG_NOTATIONS;
2460
2461   if ((err = get_boolean_flag (request, "tofu", 0, &abool)))
2462     goto leave;
2463   if (abool)
2464     mode |= GPGME_KEYLIST_MODE_WITH_TOFU;
2465
2466   if ((err = get_boolean_flag (request, "ephemeral", 0, &abool)))
2467     goto leave;
2468   if (abool)
2469     mode |= GPGME_KEYLIST_MODE_EPHEMERAL;
2470
2471   if ((err = get_boolean_flag (request, "validate", 0, &abool)))
2472     goto leave;
2473   if (abool)
2474     mode |= GPGME_KEYLIST_MODE_VALIDATE;
2475
2476   if ((err = get_boolean_flag (request, "locate", 0, &abool)))
2477     goto leave;
2478   if (abool)
2479     mode |= GPGME_KEYLIST_MODE_LOCATE;
2480
2481   if (!mode)
2482     {
2483       /* default to local */
2484       mode = GPGME_KEYLIST_MODE_LOCAL;
2485     }
2486
2487   /* Get the keys.  */
2488   patterns = create_keylist_patterns (request, "keys");
2489
2490   /* Do a keylisting and add the keys */
2491   gpgme_set_keylist_mode (ctx, mode);
2492
2493   err = gpgme_op_keylist_ext_start (ctx, (const char **) patterns,
2494                                     secret_only, 0);
2495   if (err)
2496     {
2497       gpg_error_object (result, err, "Error listing keys: %s",
2498                         gpg_strerror (err));
2499       goto leave;
2500     }
2501
2502   while (!(err = gpgme_op_keylist_next (ctx, &key)))
2503     {
2504       cJSON_AddItemToArray (keyarray, key_to_json (key));
2505       gpgme_key_unref (key);
2506     }
2507   err = 0;
2508
2509   if (!cJSON_AddItemToObject (result, "keys", keyarray))
2510     {
2511       err = gpg_error_from_syserror ();
2512       goto leave;
2513     }
2514
2515  leave:
2516   xfree_array (patterns);
2517   if (err)
2518     {
2519       cJSON_Delete (keyarray);
2520     }
2521   return err;
2522 }
2523
2524
2525 \f
2526 static const char hlp_import[] =
2527   "op:     \"import\"\n"
2528   "data:   The data to import.\n"
2529   "\n"
2530   "Optional parameters:\n"
2531   "protocol:      Either \"openpgp\" (default) or \"cms\".\n"
2532   "\n"
2533   "Optional boolean flags (default is false):\n"
2534   "base64:        Input data is base64 encoded.\n"
2535   "\n"
2536   "Response on success:\n"
2537   "result: The import result.\n"
2538   "  Number values:\n"
2539   "   considered\n"
2540   "   no_user_id\n"
2541   "   imported\n"
2542   "   imported_rsa\n"
2543   "   unchanged\n"
2544   "   new_user_ids\n"
2545   "   new_sub_keys\n"
2546   "   new_signatures\n"
2547   "   new_revocations\n"
2548   "   secret_read\n"
2549   "   secret_imported\n"
2550   "   secret_unchanged\n"
2551   "   skipped_new_keys\n"
2552   "   not_imported\n"
2553   "   skipped_v3_keys\n"
2554   "  Array values:\n"
2555   "   imports: List of keys for which an import was attempted\n"
2556   "    String values:\n"
2557   "     fingerprint\n"
2558   "     error_string\n"
2559   "    Number values:\n"
2560   "     error_code\n"
2561   "     status\n";
2562 static gpg_error_t
2563 op_import (cjson_t request, cjson_t result)
2564 {
2565   gpg_error_t err;
2566   gpgme_ctx_t ctx = NULL;
2567   gpgme_data_t input = NULL;
2568   gpgme_import_result_t import_result;
2569   gpgme_protocol_t protocol;
2570
2571   if ((err = get_protocol (request, &protocol)))
2572     goto leave;
2573   ctx = get_context (protocol);
2574
2575   if ((err = get_string_data (request, result, "data", &input)))
2576       goto leave;
2577
2578   /* Import.  */
2579   err = gpgme_op_import (ctx, input);
2580   import_result = gpgme_op_import_result (ctx);
2581   if (err)
2582     {
2583       gpg_error_object (result, err, "Import failed: %s",
2584                         gpg_strerror (err));
2585       goto leave;
2586     }
2587   gpgme_data_release (input);
2588   input = NULL;
2589
2590   xjson_AddItemToObject (result, "result",
2591                          import_result_to_json (import_result));
2592
2593  leave:
2594   release_context (ctx);
2595   gpgme_data_release (input);
2596   return err;
2597 }
2598
2599
2600 static const char hlp_export[] =
2601   "op:     \"export\"\n"
2602   "\n"
2603   "Optional parameters:\n"
2604   "keys:          Array of strings or fingerprints to lookup\n"
2605   "               For a single key a String may be used instead of an array.\n"
2606   "               default exports all keys.\n"
2607   "protocol:      Either \"openpgp\" (default) or \"cms\".\n"
2608   "\n"
2609   "Optional boolean flags (default is false):\n"
2610   "armor:         Request output in armored format.\n"
2611   "extern:        Add EXPORT_MODE_EXTERN.\n"
2612   "minimal:       Add EXPORT_MODE_MINIMAL.\n"
2613   "raw:           Add EXPORT_MODE_RAW.\n"
2614   "pkcs12:        Add EXPORT_MODE_PKCS12.\n"
2615   "with-sec-fprs: Add the sec-fprs array to the result.\n"
2616   "\n"
2617   "Response on success:\n"
2618   "type:     \"keys\"\n"
2619   "data:     Unless armor mode is used a Base64 encoded binary.\n"
2620   "          In armor mode a string with an armored\n"
2621   "          OpenPGP or a PEM / PKCS12 key.\n"
2622   "base64:   Boolean indicating whether data is base64 encoded.\n"
2623   "sec-fprs: Optional, only if with-secret is set. An array containing\n"
2624   "          the fingerprints of the keys in the export for which a secret\n"
2625   "          key is available";
2626 static gpg_error_t
2627 op_export (cjson_t request, cjson_t result)
2628 {
2629   gpg_error_t err;
2630   gpgme_ctx_t ctx = NULL;
2631   gpgme_protocol_t protocol;
2632   char **patterns = NULL;
2633   int abool;
2634   int with_secret = 0;
2635   gpgme_export_mode_t mode = 0;
2636   gpgme_data_t output = NULL;
2637
2638   if ((err = get_protocol (request, &protocol)))
2639     goto leave;
2640   ctx = get_context (protocol);
2641
2642   if ((err = get_boolean_flag (request, "armor", 0, &abool)))
2643     goto leave;
2644   gpgme_set_armor (ctx, abool);
2645
2646   /* Handle the various export mode bools. */
2647   if ((err = get_boolean_flag (request, "secret", 0, &abool)))
2648     goto leave;
2649   if (abool)
2650     {
2651       err = gpg_error (GPG_ERR_FORBIDDEN);
2652       goto leave;
2653     }
2654
2655   if ((err = get_boolean_flag (request, "extern", 0, &abool)))
2656     goto leave;
2657   if (abool)
2658     mode |= GPGME_EXPORT_MODE_EXTERN;
2659
2660   if ((err = get_boolean_flag (request, "minimal", 0, &abool)))
2661     goto leave;
2662   if (abool)
2663     mode |= GPGME_EXPORT_MODE_MINIMAL;
2664
2665   if ((err = get_boolean_flag (request, "raw", 0, &abool)))
2666     goto leave;
2667   if (abool)
2668     mode |= GPGME_EXPORT_MODE_RAW;
2669
2670   if ((err = get_boolean_flag (request, "pkcs12", 0, &abool)))
2671     goto leave;
2672   if (abool)
2673     mode |= GPGME_EXPORT_MODE_PKCS12;
2674
2675   if ((err = get_boolean_flag (request, "with-sec-fprs", 0, &abool)))
2676     goto leave;
2677   if (abool)
2678     with_secret = 1;
2679
2680   /* Get the export patterns.  */
2681   patterns = create_keylist_patterns (request, "keys");
2682
2683   /* Create an output data object.  */
2684   err = gpgme_data_new (&output);
2685   if (err)
2686     {
2687       gpg_error_object (result, err, "Error creating output data object: %s",
2688                         gpg_strerror (err));
2689       goto leave;
2690     }
2691
2692   err = gpgme_op_export_ext (ctx, (const char **) patterns,
2693                              mode, output);
2694   if (err)
2695     {
2696       gpg_error_object (result, err, "Error exporting keys: %s",
2697                         gpg_strerror (err));
2698       goto leave;
2699     }
2700
2701   /* We need to base64 if armoring has not been requested.  */
2702   err = make_data_object (result, output,
2703                           "keys", !gpgme_get_armor (ctx));
2704   output = NULL;
2705
2706   if (!err && with_secret)
2707     {
2708       err = add_secret_fprs ((const char **) patterns, protocol, result);
2709     }
2710
2711 leave:
2712   xfree_array (patterns);
2713   release_context (ctx);
2714   gpgme_data_release (output);
2715
2716   return err;
2717 }
2718
2719
2720 static const char hlp_delete[] =
2721   "op:     \"delete\"\n"
2722   "key:    Fingerprint of the key to delete.\n"
2723   "\n"
2724   "Optional parameters:\n"
2725   "protocol:      Either \"openpgp\" (default) or \"cms\".\n"
2726   "\n"
2727   "Response on success:\n"
2728   "success:   Boolean true.\n";
2729 static gpg_error_t
2730 op_delete (cjson_t request, cjson_t result)
2731 {
2732   gpg_error_t err;
2733   gpgme_ctx_t ctx = NULL;
2734   gpgme_ctx_t keylist_ctx = NULL;
2735   gpgme_protocol_t protocol;
2736   gpgme_key_t key = NULL;
2737   int secret = 0;
2738   cjson_t j_key = NULL;
2739
2740   if ((err = get_protocol (request, &protocol)))
2741     goto leave;
2742   ctx = get_context (protocol);
2743   keylist_ctx = get_context (protocol);
2744
2745   if ((err = get_boolean_flag (request, "secret", 0, &secret)))
2746     goto leave;
2747   if (secret)
2748     {
2749       err = gpg_error (GPG_ERR_FORBIDDEN);
2750       goto leave;
2751     }
2752
2753   j_key = cJSON_GetObjectItem (request, "key");
2754   if (!j_key)
2755     {
2756       err = gpg_error (GPG_ERR_NO_KEY);
2757       goto leave;
2758     }
2759   if (!cjson_is_string (j_key))
2760     {
2761       err = gpg_error (GPG_ERR_INV_VALUE);
2762       goto leave;
2763     }
2764
2765   /* Get the key */
2766   if ((err = gpgme_get_key (keylist_ctx, j_key->valuestring, &key, 0)))
2767     {
2768       gpg_error_object (result, err, "Error fetching key for delete: %s",
2769                         gpg_strerror (err));
2770       goto leave;
2771     }
2772
2773   err = gpgme_op_delete (ctx, key, 0);
2774   if (err)
2775     {
2776       gpg_error_object (result, err, "Error deleting key: %s",
2777                         gpg_strerror (err));
2778       goto leave;
2779     }
2780
2781   xjson_AddBoolToObject (result, "success", 1);
2782
2783 leave:
2784   gpgme_key_unref (key);
2785   release_context (ctx);
2786   release_context (keylist_ctx);
2787
2788   return err;
2789 }
2790
2791
2792 static const char hlp_config_opt[] =
2793   "op:       \"config_opt\"\n"
2794   "component: The component of the option.\n"
2795   "option:    The name of the option.\n"
2796   "\n"
2797   "Response on success:\n"
2798   "\n"
2799   "option: Information about the option.\n"
2800   " String values:\n"
2801   "  name: The name of the option\n"
2802   "  description: Localized description of the opt.\n"
2803   "  argname: Thhe argument name e.g. --verbose\n"
2804   "  default_description\n"
2805   "  no_arg_description\n"
2806   " Number values:\n"
2807   "  flags: Flags for this option.\n"
2808   "  level: the level of the description. See gpgme_conf_level_t.\n"
2809   "  type: The type of the option. See gpgme_conf_type_t.\n"
2810   "  alt_type: Alternate type of the option. See gpgme_conf_type_t\n"
2811   " Arg type values: (see desc. below)\n"
2812   "  default_value: Array of the default value.\n"
2813   "  no_arg_value: Array of the value if it is not set.\n"
2814   "  value: Array for the current value if the option is set.\n"
2815   "\n"
2816   "If the response is empty the option was not found\n"
2817   "";
2818 static gpg_error_t
2819 op_config_opt (cjson_t request, cjson_t result)
2820 {
2821   gpg_error_t err;
2822   gpgme_ctx_t ctx = NULL;
2823   gpgme_conf_comp_t conf = NULL;
2824   gpgme_conf_comp_t comp = NULL;
2825   cjson_t j_tmp;
2826   char *comp_name = NULL;
2827   char *opt_name = NULL;
2828
2829   ctx = get_context (GPGME_PROTOCOL_GPGCONF);
2830
2831   j_tmp = cJSON_GetObjectItem (request, "component");
2832   if (!j_tmp || !cjson_is_string (j_tmp))
2833     {
2834       err = gpg_error (GPG_ERR_INV_VALUE);
2835       goto leave;
2836     }
2837   comp_name = j_tmp->valuestring;
2838
2839
2840   j_tmp = cJSON_GetObjectItem (request, "option");
2841   if (!j_tmp || !cjson_is_string (j_tmp))
2842     {
2843       err = gpg_error (GPG_ERR_INV_VALUE);
2844       goto leave;
2845     }
2846   opt_name = j_tmp->valuestring;
2847
2848   /* Load the config */
2849   err = gpgme_op_conf_load (ctx, &conf);
2850   if (err)
2851     {
2852       goto leave;
2853     }
2854
2855   comp = conf;
2856   for (comp = conf; comp; comp = comp->next)
2857     {
2858       gpgme_conf_opt_t opt = NULL;
2859       int found = 0;
2860       if (!comp->name || strcmp (comp->name, comp_name))
2861         {
2862           /* Skip components if a single one is specified */
2863           continue;
2864         }
2865       for (opt = comp->options; opt; opt = opt->next)
2866         {
2867           if (!opt->name || strcmp (opt->name, opt_name))
2868             {
2869               /* Skip components if a single one is specified */
2870               continue;
2871             }
2872           xjson_AddItemToObject (result, "option", conf_opt_to_json (opt));
2873           found = 1;
2874           break;
2875         }
2876       if (found)
2877         break;
2878     }
2879
2880 leave:
2881   gpgme_conf_release (conf);
2882   release_context (ctx);
2883
2884   return err;
2885 }
2886
2887
2888 static const char hlp_config[] =
2889   "op:     \"config\"\n"
2890   "\n"
2891   "Optional parameters:\n"
2892   "component:    Component of entries to list.\n"
2893   "              Default: all\n"
2894   "\n"
2895   "Response on success:\n"
2896   "   components: Array of the component program configs.\n"
2897   "     name:         The component name.\n"
2898   "     description:  Description of the component.\n"
2899   "     program_name: The absolute path to the program.\n"
2900   "     options: Array of config options\n"
2901   "      String values:\n"
2902   "       name: The name of the option\n"
2903   "       description: Localized description of the opt.\n"
2904   "       argname: Thhe argument name e.g. --verbose\n"
2905   "       default_description\n"
2906   "       no_arg_description\n"
2907   "      Number values:\n"
2908   "       flags: Flags for this option.\n"
2909   "       level: the level of the description. See gpgme_conf_level_t.\n"
2910   "       type: The type of the option. See gpgme_conf_type_t.\n"
2911   "       alt_type: Alternate type of the option. See gpgme_conf_type_t\n"
2912   "      Arg type values: (see desc. below)\n"
2913   "       default_value: Array of the default value.\n"
2914   "       no_arg_value: Array of the value if it is not set.\n"
2915   "       value: Array for the current value if the option is set.\n"
2916   "\n"
2917   "Conf type values are an array of values that are either\n"
2918   "of type number named \"number\" or of type string,\n"
2919   "named \"string\".\n"
2920   "If the type is none the bool value is_none is true.\n"
2921   "";
2922 static gpg_error_t
2923 op_config (cjson_t request, cjson_t result)
2924 {
2925   gpg_error_t err;
2926   gpgme_ctx_t ctx = NULL;
2927   gpgme_conf_comp_t conf = NULL;
2928   gpgme_conf_comp_t comp = NULL;
2929   cjson_t j_tmp;
2930   char *comp_name = NULL;
2931   cjson_t j_comps;
2932
2933   ctx = get_context (GPGME_PROTOCOL_GPGCONF);
2934
2935   j_tmp = cJSON_GetObjectItem (request, "component");
2936   if (j_tmp && cjson_is_string (j_tmp))
2937     {
2938       comp_name = j_tmp->valuestring;
2939     }
2940   else if (j_tmp && !cjson_is_string (j_tmp))
2941     {
2942       err = gpg_error (GPG_ERR_INV_VALUE);
2943       goto leave;
2944     }
2945
2946   /* Load the config */
2947   err = gpgme_op_conf_load (ctx, &conf);
2948   if (err)
2949     {
2950       goto leave;
2951     }
2952
2953   j_comps = xjson_CreateArray ();
2954   comp = conf;
2955   for (comp = conf; comp; comp = comp->next)
2956     {
2957       if (comp_name && comp->name && strcmp (comp->name, comp_name))
2958         {
2959           /* Skip components if a single one is specified */
2960           continue;
2961         }
2962       cJSON_AddItemToArray (j_comps, conf_comp_to_json (comp));
2963     }
2964   xjson_AddItemToObject (result, "components", j_comps);
2965
2966  leave:
2967   gpgme_conf_release (conf);
2968   release_context (ctx);
2969
2970   return err;
2971 }
2972
2973
2974 \f
2975 static const char hlp_createkey[] =
2976   "op:      \"createkey\"\n"
2977   "userid:  The user id. E.g. \"Foo Bar <foo@bar.baz>\"\n"
2978   "\n"
2979   "Optional parameters:\n"
2980   "algo:        Algo of the key as string.  See doc for gpg --quick-gen-key.\n"
2981   "             Supported values are \"default\" and \"future-default\".\n"
2982   "expires:     Seconds from now to expiry as Number.  0 means no expiry.\n"
2983   "             The default is to use a standard expiration interval.\n"
2984   "\n"
2985   "Response on success:\n"
2986   "fingerprint:   The fingerprint of the created key.\n"
2987   "\n"
2988   "Note: This interface does not allow key generation if the userid\n"
2989   "of the new key already exists in the keyring.\n";
2990 static gpg_error_t
2991 op_createkey (cjson_t request, cjson_t result)
2992 {
2993   gpg_error_t err;
2994   gpgme_ctx_t ctx = NULL;
2995   unsigned int flags = GPGME_CREATE_FORCE; /* Always force as the GUI should
2996                                               handle checks, if required. */
2997   unsigned long expires = 0;
2998   cjson_t j_tmp;
2999   const char *algo = "default";
3000   const char *userid;
3001   gpgme_genkey_result_t res;
3002
3003 #ifdef GPG_AGENT_ALLOWS_KEYGEN_THROUGH_BROWSER
3004   /* GnuPG forbids keygen through the browser socket so for
3005      this we create an unrestricted context.
3006      See GnuPG-Bug-Id: T4010 for more info */
3007   ctx = get_context (GPGME_PROTOCOL_OpenPGP);
3008 #else
3009     err = gpgme_new (&ctx);
3010   if (err)
3011     log_fatal ("error creating GPGME context: %s\n", gpg_strerror (err));
3012   gpgme_set_protocol (ctx, GPGME_PROTOCOL_OpenPGP);
3013 #endif
3014
3015   j_tmp = cJSON_GetObjectItem (request, "algo");
3016   if (j_tmp && cjson_is_string (j_tmp))
3017     {
3018       algo = j_tmp->valuestring;
3019     }
3020
3021   j_tmp = cJSON_GetObjectItem (request, "userid");
3022   if (!j_tmp || !cjson_is_string (j_tmp))
3023     {
3024       err = gpg_error (GPG_ERR_INV_VALUE);
3025       goto leave;
3026     }
3027
3028   userid = j_tmp->valuestring;
3029
3030   j_tmp = cJSON_GetObjectItem (request, "expires");
3031   if (j_tmp)
3032     {
3033       if (!cjson_is_number (j_tmp))
3034         {
3035           err = gpg_error (GPG_ERR_INV_VALUE);
3036           goto leave;
3037         }
3038       expires = j_tmp->valueint;
3039
3040       if (!expires)
3041         flags |= GPGME_CREATE_NOEXPIRE;
3042     }
3043
3044
3045   if ((err = gpgme_op_createkey (ctx, userid, algo, 0, expires, NULL, flags)))
3046     goto leave;
3047
3048   res = gpgme_op_genkey_result (ctx);
3049   if (!res)
3050     {
3051       err = gpg_error (GPG_ERR_GENERAL);
3052       goto leave;
3053     }
3054
3055   xjson_AddStringToObject0 (result, "fingerprint", res->fpr);
3056
3057 leave:
3058 #ifdef GPG_AGENT_ALLOWS_KEYGEN_THROUGH_BROWSER
3059   release_context (ctx);
3060 #else
3061   gpgme_release (ctx);
3062 #endif
3063
3064   return err;
3065 }
3066
3067
3068 \f
3069 static const char hlp_getmore[] =
3070   "op:     \"getmore\"\n"
3071   "\n"
3072   "Response on success:\n"
3073   "response:       base64 encoded json response.\n"
3074   "more:           Another getmore is required.\n"
3075   "base64:         boolean if the response is base64 encoded.\n";
3076 static gpg_error_t
3077 op_getmore (cjson_t request, cjson_t result)
3078 {
3079   gpg_error_t err;
3080   int c;
3081   size_t n;
3082   size_t chunksize;
3083
3084   if ((err = get_chunksize (request, &chunksize)))
3085     goto leave;
3086
3087   /* For the meta data we need 41 bytes:
3088      {"more":true,"base64":true,"response":""} */
3089   chunksize -= 41;
3090
3091   /* Adjust the chunksize for the base64 conversion.  */
3092   chunksize = (chunksize / 4) * 3;
3093
3094   /* Do we have anything pending?  */
3095   if (!pending_data.buffer)
3096     {
3097       err = gpg_error (GPG_ERR_NO_DATA);
3098       gpg_error_object (result, err, "Operation not possible: %s",
3099                         gpg_strerror (err));
3100       goto leave;
3101     }
3102
3103   /* We currently always use base64 encoding for simplicity. */
3104   xjson_AddBoolToObject (result, "base64", 1);
3105
3106   if (pending_data.written >= pending_data.length)
3107     {
3108       /* EOF reached.  This should not happen but we return an empty
3109        * string once in case of client errors.  */
3110       gpgme_free (pending_data.buffer);
3111       pending_data.buffer = NULL;
3112       xjson_AddBoolToObject (result, "more", 0);
3113       err = cjson_AddStringToObject (result, "response", "");
3114     }
3115   else
3116     {
3117       n = pending_data.length - pending_data.written;
3118       if (n > chunksize)
3119         {
3120           n = chunksize;
3121           xjson_AddBoolToObject (result, "more", 1);
3122         }
3123       else
3124         xjson_AddBoolToObject (result, "more", 0);
3125
3126       c = pending_data.buffer[pending_data.written + n];
3127       pending_data.buffer[pending_data.written + n] = 0;
3128       err = add_base64_to_object (result, "response",
3129                                   (pending_data.buffer
3130                                    + pending_data.written), n);
3131       pending_data.buffer[pending_data.written + n] = c;
3132       if (!err)
3133         {
3134           pending_data.written += n;
3135           if (pending_data.written >= pending_data.length)
3136             {
3137               xfree (pending_data.buffer);
3138               pending_data.buffer = NULL;
3139             }
3140         }
3141     }
3142
3143  leave:
3144   return err;
3145 }
3146
3147
3148 \f
3149 static const char hlp_help[] =
3150   "The tool expects a JSON object with the request and responds with\n"
3151   "another JSON object.  Even on error a JSON object is returned.  The\n"
3152   "property \"op\" is mandatory and its string value selects the\n"
3153   "operation; if the property \"help\" with the value \"true\" exists, the\n"
3154   "operation is not performned but a string with the documentation\n"
3155   "returned.  To list all operations it is allowed to leave out \"op\" in\n"
3156   "help mode.  Supported values for \"op\" are:\n\n"
3157   "  config      Read configuration values.\n"
3158   "  config_opt  Read a single configuration value.\n"
3159   "  decrypt     Decrypt data.\n"
3160   "  delete      Delete a key.\n"
3161   "  encrypt     Encrypt data.\n"
3162   "  export      Export keys.\n"
3163   "  createkey   Generate a keypair (OpenPGP only).\n"
3164   "  import      Import data.\n"
3165   "  keylist     List keys.\n"
3166   "  sign        Sign data.\n"
3167   "  verify      Verify data.\n"
3168   "  version     Get engine information.\n"
3169   "  getmore     Retrieve remaining data if chunksize was used.\n"
3170   "  help        Help overview.\n"
3171   "\n"
3172   "If the data needs to be transferred in smaller chunks the\n"
3173   "property \"chunksize\" with an integer value can be added.\n"
3174   "When \"chunksize\" is set the response (including json) will\n"
3175   "not be larger then \"chunksize\" but might be smaller.\n"
3176   "The chunked result will be transferred in base64 encoded chunks\n"
3177   "using the \"getmore\" operation. See help getmore for more info.";
3178 static gpg_error_t
3179 op_help (cjson_t request, cjson_t result)
3180 {
3181   cjson_t j_tmp;
3182   char *buffer = NULL;
3183   const char *msg;
3184
3185   j_tmp = cJSON_GetObjectItem (request, "interactive_help");
3186   if (opt_interactive && j_tmp && cjson_is_string (j_tmp))
3187     msg = buffer = xstrconcat (hlp_help, "\n", j_tmp->valuestring, NULL);
3188   else
3189     msg = hlp_help;
3190
3191   xjson_AddStringToObject (result, "type", "help");
3192   xjson_AddStringToObject (result, "msg", msg);
3193
3194   xfree (buffer);
3195   return 0;
3196 }
3197
3198
3199 \f
3200 /*
3201  * Dispatcher
3202  */
3203
3204 /* Process a request and return the response.  The response is a newly
3205  * allocated string or NULL in case of an error.  */
3206 static char *
3207 process_request (const char *request)
3208 {
3209   static struct {
3210     const char *op;
3211     gpg_error_t (*handler)(cjson_t request, cjson_t result);
3212     const char * const helpstr;
3213   } optbl[] = {
3214     { "config",     op_config,     hlp_config },
3215     { "config_opt", op_config_opt, hlp_config_opt },
3216     { "encrypt",    op_encrypt,    hlp_encrypt },
3217     { "export",     op_export,     hlp_export },
3218     { "decrypt",    op_decrypt,    hlp_decrypt },
3219     { "delete",     op_delete,     hlp_delete },
3220     { "createkey",  op_createkey,  hlp_createkey },
3221     { "keylist",    op_keylist,    hlp_keylist },
3222     { "import",     op_import,     hlp_import },
3223     { "sign",       op_sign,       hlp_sign },
3224     { "verify",     op_verify,     hlp_verify },
3225     { "version",    op_version,    hlp_version },
3226     { "getmore",    op_getmore,    hlp_getmore },
3227     { "help",       op_help,       hlp_help },
3228     { NULL }
3229   };
3230   size_t erroff;
3231   cjson_t json;
3232   cjson_t j_tmp, j_op;
3233   cjson_t response;
3234   int helpmode;
3235   int is_getmore = 0;
3236   const char *op;
3237   char *res = NULL;
3238   int idx;
3239
3240   response = xjson_CreateObject ();
3241
3242   json = cJSON_Parse (request, &erroff);
3243   if (!json)
3244     {
3245       log_string (GPGRT_LOGLVL_INFO, request);
3246       log_info ("invalid JSON object at offset %zu\n", erroff);
3247       error_object (response, "invalid JSON object at offset %zu\n", erroff);
3248       goto leave;
3249     }
3250
3251   j_tmp = cJSON_GetObjectItem (json, "help");
3252   helpmode = (j_tmp && cjson_is_true (j_tmp));
3253
3254   j_op = cJSON_GetObjectItem (json, "op");
3255   if (!j_op || !cjson_is_string (j_op))
3256     {
3257       if (!helpmode)
3258         {
3259           error_object (response, "Property \"op\" missing");
3260           goto leave;
3261         }
3262       op = "help";  /* Help summary.  */
3263     }
3264   else
3265     op = j_op->valuestring;
3266
3267   for (idx=0; optbl[idx].op; idx++)
3268     if (!strcmp (op, optbl[idx].op))
3269       break;
3270   if (optbl[idx].op)
3271     {
3272       if (helpmode && strcmp (op, "help"))
3273         {
3274           xjson_AddStringToObject (response, "type", "help");
3275           xjson_AddStringToObject (response, "op", op);
3276           xjson_AddStringToObject (response, "msg", optbl[idx].helpstr);
3277         }
3278       else
3279         {
3280           gpg_error_t err;
3281           is_getmore = optbl[idx].handler == op_getmore;
3282           /* If this is not the "getmore" command and we have any
3283            * pending data release that data.  */
3284           if (pending_data.buffer && optbl[idx].handler != op_getmore)
3285             {
3286               gpgme_free (pending_data.buffer);
3287               pending_data.buffer = NULL;
3288             }
3289
3290           err = optbl[idx].handler (json, response);
3291           if (err)
3292             {
3293               if (!(j_tmp = cJSON_GetObjectItem (response, "type"))
3294                   || !cjson_is_string (j_tmp)
3295                   || strcmp (j_tmp->valuestring, "error"))
3296                 {
3297                   /* No error type response - provide a generic one.  */
3298                   gpg_error_object (response, err, "Operation failed: %s",
3299                                     gpg_strerror (err));
3300                 }
3301
3302               xjson_AddStringToObject (response, "op", op);
3303             }
3304         }
3305     }
3306   else  /* Operation not supported.  */
3307     {
3308       error_object (response, "Unknown operation '%s'", op);
3309       xjson_AddStringToObject (response, "op", op);
3310     }
3311
3312  leave:
3313   if (is_getmore)
3314     {
3315       /* For getmore we bypass the encode_and_chunk. */
3316       if (opt_interactive)
3317         res = cJSON_Print (response);
3318       else
3319         res = cJSON_PrintUnformatted (response);
3320     }
3321   else
3322     res = encode_and_chunk (json, response);
3323   if (!res)
3324     {
3325       cjson_t err_obj;
3326
3327       log_error ("printing JSON data failed\n");
3328
3329       err_obj = error_object (NULL, "Printing JSON data failed");
3330       if (opt_interactive)
3331         res = cJSON_Print (err_obj);
3332       res = cJSON_PrintUnformatted (err_obj);
3333       cJSON_Delete (err_obj);
3334     }
3335
3336   cJSON_Delete (json);
3337   cJSON_Delete (response);
3338
3339   if (!res)
3340     {
3341       /* Can't happen unless we created a broken error_object above */
3342       return xtrystrdup ("Bug: Fatal error in process request\n");
3343     }
3344   return res;
3345 }
3346
3347
3348 \f
3349 /*
3350  *  Driver code
3351  */
3352
3353 static char *
3354 get_file (const char *fname)
3355 {
3356   gpg_error_t err;
3357   estream_t fp;
3358   struct stat st;
3359   char *buf;
3360   size_t buflen;
3361
3362   fp = es_fopen (fname, "r");
3363   if (!fp)
3364     {
3365       err = gpg_error_from_syserror ();
3366       log_error ("can't open '%s': %s\n", fname, gpg_strerror (err));
3367       return NULL;
3368     }
3369
3370   if (fstat (es_fileno(fp), &st))
3371     {
3372       err = gpg_error_from_syserror ();
3373       log_error ("can't stat '%s': %s\n", fname, gpg_strerror (err));
3374       es_fclose (fp);
3375       return NULL;
3376     }
3377
3378   buflen = st.st_size;
3379   buf = xmalloc (buflen+1);
3380   if (es_fread (buf, buflen, 1, fp) != 1)
3381     {
3382       err = gpg_error_from_syserror ();
3383       log_error ("error reading '%s': %s\n", fname, gpg_strerror (err));
3384       es_fclose (fp);
3385       xfree (buf);
3386       return NULL;
3387     }
3388   buf[buflen] = 0;
3389   es_fclose (fp);
3390
3391   return buf;
3392 }
3393
3394
3395 /* Return a malloced line or NULL on EOF.  Terminate on read
3396  * error.  */
3397 static char *
3398 get_line (void)
3399 {
3400   char *line = NULL;
3401   size_t linesize = 0;
3402   gpg_error_t err;
3403   size_t maxlength = 2048;
3404   int n;
3405   const char *s;
3406   char *p;
3407
3408  again:
3409   n = es_read_line (es_stdin, &line, &linesize, &maxlength);
3410   if (n < 0)
3411     {
3412       err = gpg_error_from_syserror ();
3413       log_error ("error reading line: %s\n", gpg_strerror (err));
3414       exit (1);
3415     }
3416   if (!n)
3417     {
3418       xfree (line);
3419       line = NULL;
3420       return NULL;  /* EOF */
3421     }
3422   if (!maxlength)
3423     {
3424       log_info ("line too long - skipped\n");
3425       goto again;
3426     }
3427   if (memchr (line, 0, n))
3428     log_info ("warning: line shortened due to embedded Nul character\n");
3429
3430   if (line[n-1] == '\n')
3431     line[n-1] = 0;
3432
3433   /* Trim leading spaces.  */
3434   for (s=line; spacep (s); s++)
3435     ;
3436   if (s != line)
3437     {
3438       for (p=line; *s;)
3439         *p++ = *s++;
3440       *p = 0;
3441       n = p - line;
3442     }
3443
3444   return line;
3445 }
3446
3447
3448 /* Process meta commands used with the standard REPL.  */
3449 static char *
3450 process_meta_commands (const char *request)
3451 {
3452   char *result = NULL;
3453
3454   while (spacep (request))
3455     request++;
3456
3457   if (!strncmp (request, "help", 4) && (spacep (request+4) || !request[4]))
3458     {
3459       if (request[4])
3460         {
3461           char *buf = xstrconcat ("{ \"help\":true, \"op\":\"", request+5,
3462                                   "\" }", NULL);
3463           result = process_request (buf);
3464           xfree (buf);
3465         }
3466       else
3467         result = process_request ("{ \"op\": \"help\","
3468                                   " \"interactive_help\": "
3469                                   "\"\\nMeta commands:\\n"
3470                                   "  ,read FNAME Process data from FILE\\n"
3471                                   "  ,help CMD   Print help for a command\\n"
3472                                   "  ,quit       Terminate process\""
3473                                   "}");
3474     }
3475   else if (!strncmp (request, "quit", 4) && (spacep (request+4) || !request[4]))
3476     exit (0);
3477   else if (!strncmp (request, "read", 4) && (spacep (request+4) || !request[4]))
3478     {
3479       if (!request[4])
3480         log_info ("usage: ,read FILENAME\n");
3481       else
3482         {
3483           char *buffer = get_file (request + 5);
3484           if (buffer)
3485             {
3486               result = process_request (buffer);
3487               xfree (buffer);
3488             }
3489         }
3490     }
3491   else
3492     log_info ("invalid meta command\n");
3493
3494   return result;
3495 }
3496
3497
3498 /* If STRING has a help response, return the MSG property in a human
3499  * readable format.  */
3500 static char *
3501 get_help_msg (const char *string)
3502 {
3503   cjson_t json, j_type, j_msg;
3504   const char *msg;
3505   char *buffer = NULL;
3506   char *p;
3507
3508   json = cJSON_Parse (string, NULL);
3509   if (json)
3510     {
3511       j_type = cJSON_GetObjectItem (json, "type");
3512       if (j_type && cjson_is_string (j_type)
3513           && !strcmp (j_type->valuestring, "help"))
3514         {
3515           j_msg = cJSON_GetObjectItem (json, "msg");
3516           if (j_msg || cjson_is_string (j_msg))
3517             {
3518               msg = j_msg->valuestring;
3519               buffer = malloc (strlen (msg)+1);
3520               if (buffer)
3521                 {
3522                   for (p=buffer; *msg; msg++)
3523                     {
3524                       if (*msg == '\\' && msg[1] == '\n')
3525                         *p++ = '\n';
3526                       else
3527                         *p++ = *msg;
3528                     }
3529                   *p = 0;
3530                 }
3531             }
3532         }
3533       cJSON_Delete (json);
3534     }
3535   return buffer;
3536 }
3537
3538
3539 /* An interactive standard REPL.  */
3540 static void
3541 interactive_repl (void)
3542 {
3543   char *line = NULL;
3544   char *request = NULL;
3545   char *response = NULL;
3546   char *p;
3547   int first;
3548
3549   es_setvbuf (es_stdin, NULL, _IONBF, 0);
3550 #if GPGRT_VERSION_NUMBER >= 0x011d00 /* 1.29 */
3551   es_fprintf (es_stderr, "%s %s ready (enter \",help\" for help)\n",
3552               gpgrt_strusage (11), gpgrt_strusage (13));
3553 #endif
3554   do
3555     {
3556       es_fputs ("> ", es_stderr);
3557       es_fflush (es_stderr);
3558       es_fflush (es_stdout);
3559       xfree (line);
3560       line = get_line ();
3561       es_fflush (es_stderr);
3562       es_fflush (es_stdout);
3563
3564       first = !request;
3565       if (line && *line)
3566         {
3567           if (!request)
3568             request = xstrdup (line);
3569           else
3570             {
3571               char *tmp = xstrconcat (request, "\n", line, NULL);
3572               xfree (request);
3573               request = tmp;
3574             }
3575         }
3576
3577       if (!line)
3578         es_fputs ("\n", es_stderr);
3579
3580       if (!line || !*line || (first && *request == ','))
3581         {
3582           /* Process the input.  */
3583           xfree (response);
3584           response = NULL;
3585           if (request && *request == ',')
3586             {
3587               response = process_meta_commands (request+1);
3588             }
3589           else if (request)
3590             {
3591               response = process_request (request);
3592             }
3593           xfree (request);
3594           request = NULL;
3595
3596           if (response)
3597             {
3598               if (opt_interactive)
3599                 {
3600                   char *msg = get_help_msg (response);
3601                   if (msg)
3602                     {
3603                       xfree (response);
3604                       response = msg;
3605                     }
3606                 }
3607
3608               es_fputs ("===> ", es_stderr);
3609               es_fflush (es_stderr);
3610               for (p=response; *p; p++)
3611                 {
3612                   if (*p == '\n')
3613                     {
3614                       es_fflush (es_stdout);
3615                       es_fputs ("\n===> ", es_stderr);
3616                       es_fflush (es_stderr);
3617                     }
3618                   else
3619                     es_putc (*p, es_stdout);
3620                 }
3621               es_fflush (es_stdout);
3622               es_fputs ("\n", es_stderr);
3623             }
3624         }
3625     }
3626   while (line);
3627
3628   xfree (request);
3629   xfree (response);
3630   xfree (line);
3631 }
3632
3633
3634 /* Read and process a single request.  */
3635 static void
3636 read_and_process_single_request (void)
3637 {
3638   char *line = NULL;
3639   char *request = NULL;
3640   char *response = NULL;
3641   size_t n;
3642
3643   for (;;)
3644     {
3645       xfree (line);
3646       line = get_line ();
3647       if (line && *line)
3648         request = (request? xstrconcat (request, "\n", line, NULL)
3649                    /**/   : xstrdup (line));
3650       if (!line)
3651         {
3652           if (request)
3653             {
3654               xfree (response);
3655               response = process_request (request);
3656               if (response)
3657                 {
3658                   es_fputs (response, es_stdout);
3659                   if ((n = strlen (response)) && response[n-1] != '\n')
3660                     es_fputc ('\n', es_stdout);
3661                 }
3662               es_fflush (es_stdout);
3663             }
3664           break;
3665         }
3666     }
3667
3668   xfree (response);
3669   xfree (request);
3670   xfree (line);
3671 }
3672
3673
3674 /* The Native Messaging processing loop.  */
3675 static void
3676 native_messaging_repl (void)
3677 {
3678   gpg_error_t err;
3679   uint32_t nrequest, nresponse;
3680   char *request = NULL;
3681   char *response = NULL;
3682   size_t n;
3683
3684   /* Due to the length octets we need to switch the I/O stream into
3685    * binary mode.  */
3686   es_set_binary (es_stdin);
3687   es_set_binary (es_stdout);
3688   es_setbuf (es_stdin, NULL);  /* stdin needs to be unbuffered! */
3689
3690   for (;;)
3691     {
3692       /* Read length.  Note that the protocol uses native endianness.
3693        * Is it allowed to call such a thing a well thought out
3694        * protocol?  */
3695       if (es_read (es_stdin, &nrequest, sizeof nrequest, &n))
3696         {
3697           err = gpg_error_from_syserror ();
3698           log_error ("error reading request header: %s\n", gpg_strerror (err));
3699           break;