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