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