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