json: Make native messaging work.
authorWerner Koch <wk@gnupg.org>
Wed, 28 Mar 2018 18:50:54 +0000 (20:50 +0200)
committerWerner Koch <wk@gnupg.org>
Wed, 28 Mar 2018 18:53:21 +0000 (20:53 +0200)
* src/gpgme-json.c (opt_debug): New.
(process_request): Add optional arg nm_mode.  In this mode take the
request from a "message" object.
(native_messaging_repl): Add debug output and call process_request
in NM_MODE.
(main): Add option --debug.  Parse envvar GPGME_JSON_DEBUG as an
alternative way to enable this.  Use a default log file.
--

Note that the default log file is ~/.gnupg/S.gpgme-json.log .
Thus to debug a javascript application you should start

  watchgnupg --time-only --force ~/.gnupg/S.gpgme-json.log

in a separate tty and then use

 GPGME_JSON_DEBUG=1 firefox &

to run firefox.

Signed-off-by: Werner Koch <wk@gnupg.org>
src/gpgme-json.c

index e38f9d8..e5c84bb 100644 (file)
@@ -56,7 +56,8 @@ static char *error_object_string (const char *message,
 
 /* True if interactive mode is active.  */
 static int opt_interactive;
-
+/* True is debug mode is active.  */
+static int opt_debug;
 
 
 /*
@@ -754,9 +755,10 @@ op_help (cjson_t request, cjson_t result)
 
 
 /* Process a request and return the response.  The response is a newly
- * allocated staring or NULL in case of an error.  */
+ * allocated staring or NULL in case of an error.  With NM_MODE set
+ * the actual request is taken from a "message" object.  */
 static char *
-process_request (const char *request)
+process_request (const char *request, int nm_mode)
 {
   static struct {
     const char *op;
@@ -770,6 +772,7 @@ process_request (const char *request)
     { NULL }
   };
   size_t erroff;
+  cjson_t json_orig;
   cjson_t json;
   cjson_t j_tmp, j_op;
   cjson_t response;
@@ -780,7 +783,7 @@ process_request (const char *request)
 
   response = xjson_CreateObject ();
 
-  json = cJSON_Parse (request, &erroff);
+  json = json_orig = cJSON_Parse (request, &erroff);
   if (!json)
     {
       log_string (GPGRT_LOGLVL_INFO, request);
@@ -788,6 +791,16 @@ process_request (const char *request)
       error_object (response, "invalid JSON object at offset %zu\n", erroff);
       goto leave;
     }
+  if (nm_mode)
+    {
+      json = cJSON_GetObjectItem (json, "message");
+      if (!json)
+        {
+          log_info ("no \"message\" object in request\n");
+          error_object (response, "no \"message\" object in request\n");
+          goto leave;
+        }
+    }
 
   j_tmp = cJSON_GetObjectItem (json, "help");
   helpmode = (j_tmp && cjson_is_true (j_tmp));
@@ -844,8 +857,7 @@ process_request (const char *request)
     }
 
  leave:
-  cJSON_Delete (json);
-  json = NULL;
+  cJSON_Delete (json_orig);
   if (opt_interactive)
     res = cJSON_Print (response);
   else
@@ -930,7 +942,7 @@ process_meta_commands (const char *request)
                               "\"\\nMeta commands:\\n"
                               "  ,help       This help\\n"
                               "  ,quit       Terminate process\""
-                              "}");
+                              "}", 0);
   else if (!strncmp (request, "quit", 4) && (spacep (request+4) || !request[4]))
     exit (0);
   else
@@ -1029,7 +1041,7 @@ interactive_repl (void)
             }
           else if (request)
             {
-              response = process_request (request);
+              response = process_request (request, 0);
             }
           xfree (request);
           request = NULL;
@@ -1072,7 +1084,7 @@ interactive_repl (void)
 }
 
 
-/* Read and process  asingle request.  */
+/* Read and process single request.  */
 static void
 read_and_process_single_request (void)
 {
@@ -1093,7 +1105,7 @@ read_and_process_single_request (void)
           if (request)
             {
               xfree (response);
-              response = process_request (request);
+              response = process_request (request, 0);
               if (response)
                 {
                   es_fputs (response, es_stdout);
@@ -1126,6 +1138,7 @@ native_messaging_repl (void)
    * binary mode.  */
   es_set_binary (es_stdin);
   es_set_binary (es_stdout);
+  es_setbuf (es_stdin, NULL);
 
   for (;;)
     {
@@ -1149,7 +1162,7 @@ native_messaging_repl (void)
         {
           log_error ("error reading request: request too long (%zu MiB)\n",
                      (size_t)nrequest / (1024*1024));
-          /* Fixme: Shall we read the request t the bit bucket and
+          /* Fixme: Shall we read the request to the bit bucket and
            * return an error reponse or just return an error reponse
            * and terminate?  Needs some testing.  */
           break;
@@ -1181,8 +1194,12 @@ native_messaging_repl (void)
         }
       else /* Process request  */
         {
+          if (opt_debug)
+            log_debug ("request='%s'\n", request);
           xfree (response);
-          response = process_request (request);
+          response = process_request (request, 1);
+          if (opt_debug)
+            log_debug ("response='%s'\n", response);
         }
       nresponse = strlen (response);
 
@@ -1263,12 +1280,18 @@ main (int argc, char *argv[])
   enum { CMD_DEFAULT     = 0,
          CMD_INTERACTIVE = 'i',
          CMD_SINGLE      = 's',
-         CMD_LIBVERSION  = 501
+         CMD_LIBVERSION  = 501,
   } cmd = CMD_DEFAULT;
+  enum {
+    OPT_DEBUG = 600
+  };
+
   static gpgrt_opt_t opts[] = {
     ARGPARSE_c  (CMD_INTERACTIVE, "interactive", "Interactive REPL"),
     ARGPARSE_c  (CMD_SINGLE,      "single",      "Single request mode"),
     ARGPARSE_c  (CMD_LIBVERSION,  "lib-version", "Show library version"),
+    ARGPARSE_s_n(OPT_DEBUG,       "debug",       "Flyswatter"),
+
     ARGPARSE_end()
   };
   gpgrt_argparse_t pargs = { &argc, &argv};
@@ -1298,6 +1321,8 @@ main (int argc, char *argv[])
           cmd = pargs.r_opt;
           break;
 
+        case OPT_DEBUG: opt_debug = 1; break;
+
         default:
           pargs.err = ARGPARSE_PRINT_WARNING;
          break;
@@ -1305,6 +1330,29 @@ main (int argc, char *argv[])
     }
   gpgrt_argparse (NULL, &pargs, NULL);
 
+  if (!opt_debug)
+    {
+      const char *s = getenv ("GPGME_JSON_DEBUG");
+      if (s && atoi (s) > 0)
+        opt_debug = 1;
+    }
+
+  if (opt_debug)
+    {
+      const char *home = getenv ("HOME");
+      char *file = xstrconcat ("socket://",
+                               home? home:"/tmp",
+                               "/.gnupg/S.gpgme-json.log", NULL);
+      log_set_file (file);
+      xfree (file);
+    }
+
+  if (opt_debug)
+    { int i;
+      for (i=0; argv[i]; i++)
+        log_debug ("argv[%d]='%s'\n", i, argv[i]);
+    }
+
   switch (cmd)
     {
     case CMD_DEFAULT:
@@ -1327,6 +1375,9 @@ main (int argc, char *argv[])
       break;
     }
 
+  if (opt_debug)
+    log_debug ("ready");
+
 #endif /* This is a modern libgp-error.  */
   return 0;
 }