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