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