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