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