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