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