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