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