Improved W32 SetForegroundWindow hacks.
authorWerner Koch <wk@gnupg.org>
Fri, 12 Jun 2009 16:58:45 +0000 (16:58 +0000)
committerWerner Koch <wk@gnupg.org>
Fri, 12 Jun 2009 16:58:45 +0000 (16:58 +0000)
16 files changed:
src/ChangeLog
src/dirinfo.c
src/engine-assuan.c
src/engine-gpg.c
src/engine-gpgconf.c
src/engine-gpgsm.c
src/gpgme-w32spawn.c
src/posix-io.c
src/posix-util.c
src/priv-io.h
src/util.h
src/version.c
src/w32-glib-io.c
src/w32-io.c
src/w32-qt-io.cpp
src/w32-util.c

index 3e03da5..db21dc4 100644 (file)
@@ -1,3 +1,26 @@
+2009-06-12  Werner Koch  <wk@g10code.com>
+
+       * gpgme-w32spawn.c (translate_get_from_file): Parse optional spawn
+       flags.  Add new arg R_FLAGS.  Fix segv on file w/o LF.
+       (translate_handles): Add new arg R_FLAGS.  Avoid possible segv.
+       (main): Pass flags for my_spawn.
+       (my_spawn): Add arg FLAGS and implement AllowSetForegroundWindow.
+
+       * priv-io.h (IOSPAWN_FLAG_ALLOW_SET_FG): New.
+       * w32-io.c (_gpgme_io_spawn): Add arg FLAGS and implement it.
+       * w32-glib-io.c (_gpgme_io_spawn): Ditto.
+       * w32-qt-io.cpp (_gpgme_io_spawn): Ditto.
+       * posix-io.c (_gpgme_io_spawn): Add dummy arg FLAGS.
+       * engine-gpg.c (start): Call spawn with new flag.
+
+       * w32-util.c (_gpgme_allow_set_foregound_window): Rename to
+       _gpgme_allow_set_foreground_window.  Change all callers.
+       * posix-util.c (_gpgme_allow_set_foreground_window): Ditto.
+
+2009-06-10  Werner Koch  <wk@g10code.com>
+
+       * w32-util.c (_gpgme_allow_set_foregound_window): Add trace support.
+
 2009-06-09  Werner Koch  <wk@g10code.com>
 
        * engine-gpg.c (gpg_io_event): Test for cmd.fd.
index 45f09c0..ab15a59 100644 (file)
@@ -102,7 +102,7 @@ read_gpgconf_dirs (void)
 
   cfd[0].fd = rp[1];
 
-  status = _gpgme_io_spawn (pgmname, argv, cfd, NULL);
+  status = _gpgme_io_spawn (pgmname, argv, 0, cfd, NULL);
   if (status < 0)
     {
       _gpgme_io_close (rp[0]);
index 12de042..08ae388 100644 (file)
@@ -377,7 +377,7 @@ inquire_cb (engine_llass_t llass, const char *keyword, const char *args)
 
   if (llass->opt.gpg_agent && !strcmp (keyword, "PINENTRY_LAUNCHED"))
     {
-      _gpgme_allow_set_foregound_window ((pid_t)strtoul (args, NULL, 10));
+      _gpgme_allow_set_foreground_window ((pid_t)strtoul (args, NULL, 10));
     }
 
   if (llass->user.inq_cb)
index 34bd613..eec3fa6 100644 (file)
@@ -1328,7 +1328,9 @@ start (engine_gpg_t gpg)
   fd_list[n].dup_to = -1;
 
   status = _gpgme_io_spawn (gpg->file_name ? gpg->file_name :
-                           _gpgme_get_gpg_path (), gpg->argv, fd_list, &pid);
+                           _gpgme_get_gpg_path (), gpg->argv,
+                            IOSPAWN_FLAG_ALLOW_SET_FG,
+                            fd_list, &pid);
   saved_errno = errno;
 
   free (fd_list);
@@ -1376,8 +1378,6 @@ start (engine_gpg_t gpg)
        }
     }
 
-  _gpgme_allow_set_foregound_window (pid);
-
   gpg_io_event (gpg, GPGME_EVENT_START, NULL);
   
   /* fixme: check what data we can release here */
index d1f27c2..cfa04ce 100644 (file)
@@ -221,7 +221,7 @@ gpgconf_read (void *engine, char *arg1, char *arg2,
 
   cfd[0].fd = rp[1];
 
-  status = _gpgme_io_spawn (gpgconf->file_name, argv, cfd, NULL);
+  status = _gpgme_io_spawn (gpgconf->file_name, argv, 0, cfd, NULL);
   if (status < 0)
     {
       _gpgme_io_close (rp[0]);
@@ -659,7 +659,7 @@ gpgconf_write (void *engine, char *arg1, char *arg2, gpgme_data_t conf)
 
   cfd[0].fd = rp[0];
 
-  status = _gpgme_io_spawn (gpgconf->file_name, argv, cfd, NULL);
+  status = _gpgme_io_spawn (gpgconf->file_name, argv, 0, cfd, NULL);
   if (status < 0)
     {
       _gpgme_io_close (rp[0]);
index 49d36c1..2d92732 100644 (file)
@@ -292,7 +292,7 @@ default_inq_cb (engine_gpgsm_t gpgsm, const char *line)
 {
   if (!strncmp (line, "PINENTRY_LAUNCHED", 17) && (line[17]==' '||!line[17]))
     {
-      _gpgme_allow_set_foregound_window ((pid_t)strtoul (line+17, NULL, 10));
+      _gpgme_allow_set_foreground_window ((pid_t)strtoul (line+17, NULL, 10));
     }
 
   return 0;
index f132a8f..6f7c609 100644 (file)
 #include <process.h>
 #include <windows.h>
 
+/* Flag values as used by gpgme.  */
+#define IOSPAWN_FLAG_ALLOW_SET_FG 1
+
+
+/* Name of this program.  */
+#define PGM "gpgme-w32spawn"
+
 
 \f
 struct spawn_fd_item_s
@@ -101,7 +108,7 @@ build_commandline (char **argv)
 
 
 int
-my_spawn (char **argv, struct spawn_fd_item_s *fd_list)
+my_spawn (char **argv, struct spawn_fd_item_s *fd_list, unsigned int flags)
 {
   SECURITY_ATTRIBUTES sec_attr;
   PROCESS_INFORMATION pi =
@@ -127,7 +134,7 @@ my_spawn (char **argv, struct spawn_fd_item_s *fd_list)
   i = 0;
   while (argv[i])
     {
-      fprintf (stderr, "argv[%2i] = %s\n", i, argv[i]);
+      fprintf (stderr, PGM": argv[%2i] = %s\n", i, argv[i]);
       i++;
     }
 
@@ -147,7 +154,7 @@ my_spawn (char **argv, struct spawn_fd_item_s *fd_list)
   si.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
   si.hStdError = GetStdHandle (STD_ERROR_HANDLE);
 
-  fprintf (stderr, "spawning: %s\n", arg_string);
+  fprintf (stderr, PGM": spawning: %s\n", arg_string);
 
   for (i = 0; fd_list[i].handle != -1; i++)
     {
@@ -156,19 +163,19 @@ my_spawn (char **argv, struct spawn_fd_item_s *fd_list)
        {
          si.hStdInput = (HANDLE) fd_list[i].peer_name;
          duped_stdin = 1;
-         fprintf (stderr, "dup 0x%x to stdin\n", fd_list[i].peer_name);
+         fprintf (stderr, PGM": dup 0x%x to stdin\n", fd_list[i].peer_name);
         }
       else if (fd_list[i].dup_to == 1)
        {
          si.hStdOutput = (HANDLE) fd_list[i].peer_name;
          duped_stdout = 1;
-         fprintf (stderr, "dup 0x%x to stdout\n", fd_list[i].peer_name);
+         fprintf (stderr, PGM": dup 0x%x to stdout\n", fd_list[i].peer_name);
         }
       else if (fd_list[i].dup_to == 2)
        {
          si.hStdError = (HANDLE) fd_list[i].peer_name;
          duped_stderr = 1;
-         fprintf (stderr, "dup 0x%x to stderr\n", fd_list[i].peer_name);
+         fprintf (stderr, PGM":dup 0x%x to stderr\n", fd_list[i].peer_name);
         }
     }
   
@@ -231,6 +238,33 @@ my_spawn (char **argv, struct spawn_fd_item_s *fd_list)
   
   for (i = 0; fd_list[i].handle != -1; i++)
     CloseHandle ((HANDLE) fd_list[i].handle);
+
+  if (flags & IOSPAWN_FLAG_ALLOW_SET_FG)
+    {
+      static int initialized;
+      static BOOL (WINAPI * func)(DWORD);
+      void *handle;
+  
+      if (!initialized)
+        {
+          /* Available since W2000; thus we dynload it.  */
+          initialized = 1;
+          handle = LoadLibrary ("user32.dll");
+          if (handle)
+            {
+              func = GetProcAddress (handle, "AllowSetForegroundWindow");
+              if (!func)
+                FreeLibrary (handle);
+            }
+        }
+      
+      if (func)
+        {
+          int rc = func (pi.dwProcessId);
+          fprintf (stderr, PGM": AllowSetForegroundWindow(%d): rc=%d\n",
+                   (int)pi.dwProcessId, rc);
+        }
+    }
   
   ResumeThread (pi.hThread);
   CloseHandle (pi.hThread);
@@ -244,12 +278,13 @@ my_spawn (char **argv, struct spawn_fd_item_s *fd_list)
 
 int
 translate_get_from_file (const char *trans_file, 
-                        struct spawn_fd_item_s *fd_list)
+                        struct spawn_fd_item_s *fd_list, 
+                         unsigned int *r_flags)
 {
   /* Hold roughly MAX_TRANS triplets of 64 bit numbers in hex
      notation: "0xFEDCBA9876543210".  10*19*4 - 1 = 759.  This plans
      ahead for a time when a HANDLE is 64 bit.  */
-#define BUFFER_MAX 800
+#define BUFFER_MAX 810
 
   char line[BUFFER_MAX + 1];
   char *linep;
@@ -257,6 +292,8 @@ translate_get_from_file (const char *trans_file,
   int res;
   int fd;
 
+  *r_flags = 0;
+
   fd = open (trans_file, O_RDONLY);
   if (fd < 0)
     return -1;
@@ -269,10 +306,12 @@ translate_get_from_file (const char *trans_file,
 
   line[BUFFER_MAX] = '\0';
   linep = strchr (line, '\n');
-  if (linep > line && linep[-1] == '\r')
-    linep--;
-  *linep = '\0';
-
+  if (linep)
+    {
+      if (linep > line && linep[-1] == '\r')
+        linep--;
+      *linep = '\0';
+    }
   linep = line;
 
   /* Now start to read mapping pairs.  */
@@ -289,6 +328,21 @@ translate_get_from_file (const char *trans_file,
        linep++;
       if (*linep == '\0')
        break;
+      if (!idx && *linep == '~')
+        {
+          /* Spawn flags have been passed.  */
+          linep++;
+          *r_flags = strtoul (linep, &tail, 0);
+          if (tail == NULL || ! (*tail == '\0' || isspace (*tail)))
+            break;
+          linep = tail;
+          
+          while (isspace (*((unsigned char *)linep)))
+            linep++;
+          if (*linep == '\0')
+            break;
+        }
+
       from = strtoul (linep, &tail, 0);
       if (tail == NULL || ! (*tail == '\0' || isspace (*tail)))
        break;
@@ -339,13 +393,14 @@ translate_get_from_file (const char *trans_file,
    FD_LIST (which must be MAX_TRANS+1 large).  */
 char **
 translate_handles (const char *trans_file, const char * const *argv,
-                  struct spawn_fd_item_s *fd_list)
+                  struct spawn_fd_item_s *fd_list, unsigned int *r_flags)
 {
   int res;
   int idx;
+  int n_args;
   char **args;
 
-  res = translate_get_from_file (trans_file, fd_list);
+  res = translate_get_from_file (trans_file, fd_list, r_flags);
   if (res < 0)
     return NULL;
 
@@ -359,6 +414,7 @@ translate_handles (const char *trans_file, const char * const *argv,
        return NULL;
     }
   args[idx] = NULL;
+  n_args = idx;
 
   for (idx = 0; fd_list[idx].handle != -1; idx++)
     {
@@ -369,6 +425,12 @@ translate_handles (const char *trans_file, const char * const *argv,
       if (aidx == 0)
        continue;
 
+      if (aidx >= n_args)
+        {
+         fprintf (stderr, PGM": translation file does not match args\n");
+          return NULL;
+        }
+
       args[aidx] = malloc (sizeof (buf));
       /* We currently disable translation for stdin/stdout/stderr.  We
         assume that the spawned program handles 0/1/2 specially
@@ -394,6 +456,7 @@ main (int argc, const char * const *argv)
   int rc = 0;
   char **argv_spawn;
   struct spawn_fd_item_s fd_list[MAX_TRANS + 1];
+  unsigned int flags;
 
   if (argc < 3)
     {
@@ -401,7 +464,7 @@ main (int argc, const char * const *argv)
       goto leave;
     }
 
-  argv_spawn = translate_handles (argv[1], &argv[2], fd_list);
+  argv_spawn = translate_handles (argv[1], &argv[2], fd_list, &flags);
   if (!argv_spawn)
     {
       rc = 2;
@@ -411,10 +474,10 @@ main (int argc, const char * const *argv)
   /* Using execv does not replace the existing program image, but
      spawns a new one and daemonizes it, confusing the command line
      interpreter.  So we have to use spawnv.  */
-  rc = my_spawn (argv_spawn, fd_list);
+  rc = my_spawn (argv_spawn, fd_list, flags);
   if (rc < 0)
     {
-      fprintf (stderr, "gpgwrap: executing `%s' failed: %s\n",
+      fprintf (stderr, PGM": executing `%s' failed: %s\n",
               argv[0], strerror (errno));
       rc = 2;
       goto leave;
@@ -422,12 +485,12 @@ main (int argc, const char * const *argv)
 
  leave:
   if (rc)
-    fprintf (stderr, "gpg-w32spawn: internal error\n");
+    fprintf (stderr, PGM": internal error\n");
   /* Always try to delete the temporary file.  */
   if (argc >= 2)
     {
       if (DeleteFile (argv[1]) == 0)
-       fprintf (stderr, "Failed to delete %s: ec=%ld\n",
+       fprintf (stderr, PGM": failed to delete %s: ec=%ld\n",
                 argv[1], GetLastError ());
     }
   return rc;
index c85255e..869d070 100644 (file)
@@ -304,13 +304,16 @@ _gpgme_io_waitpid (int pid, int hang, int *r_status, int *r_signal)
 
 /* Returns 0 on success, -1 on error.  */
 int
-_gpgme_io_spawn (const char *path, char *const argv[],
+_gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags,
                 struct spawn_fd_item_s *fd_list, pid_t *r_pid)
 {
   pid_t pid;
   int i;
   int status;
   int signo;
+
+  (void)flags;
+
   TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path,
              "path=%s", path);
   i = 0;
index 9e66949..b0d17b0 100644 (file)
@@ -67,7 +67,7 @@ _gpgme_get_conf_int (const char *key, int *value)
 }
 
 void 
-_gpgme_allow_set_foregound_window (pid_t pid)
+_gpgme_allow_set_foreground_window (pid_t pid)
 {
   (void)pid;
   /* Not needed.  */
index 4a87f65..7194a42 100644 (file)
@@ -59,11 +59,15 @@ int _gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler,
                                void *value);
 int _gpgme_io_set_nonblocking (int fd);
 
+/* A flag to tell the spawn function to allow the child process to set
+   the foreground window. */
+#define IOSPAWN_FLAG_ALLOW_SET_FG 1
+
 /* Spawn the executable PATH with ARGV as arguments.  After forking
    close all fds except for those in FD_LIST in the child, then
    optionally dup() the child fds.  Finally, all fds in the list are
    closed in the parent.  */
-int _gpgme_io_spawn (const char *path, char *const argv[],
+int _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags,
                     struct spawn_fd_item_s *fd_list, pid_t *r_pid);
 
 int _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock);
index d429d5d..a221bcc 100644 (file)
@@ -33,7 +33,7 @@ const char *_gpgme_get_gpg_path (void);
 const char *_gpgme_get_gpgsm_path (void);
 const char *_gpgme_get_gpgconf_path (void);
 int _gpgme_get_conf_int (const char *key, int *value);
-void _gpgme_allow_set_foregound_window (pid_t pid);
+void _gpgme_allow_set_foreground_window (pid_t pid);
 
 /*-- dirinfo.c --*/
 const char *_gpgme_get_default_homedir (void);
index cef49a3..f777da4 100644 (file)
@@ -310,7 +310,7 @@ _gpgme_get_program_version (const char *const file_name)
 
   cfd[0].fd = rp[1];
 
-  status = _gpgme_io_spawn (file_name, argv, cfd, NULL);
+  status = _gpgme_io_spawn (file_name, argv, 0, cfd, NULL);
   if (status < 0)
     {
       _gpgme_io_close (rp[0]);
index 5f8c886..c1542cc 100644 (file)
@@ -584,7 +584,7 @@ build_commandline (char **argv)
 
 
 int
-_gpgme_io_spawn (const char *path, char * const argv[],
+_gpgme_io_spawn (const char *path, char * const argv[], unsigned int flags,
                 struct spawn_fd_item_s *fd_list, pid_t *r_pid)
 {
   SECURITY_ATTRIBUTES sec_attr;
@@ -596,8 +596,8 @@ _gpgme_io_spawn (const char *path, char * const argv[],
       0          /* returns tid */
     };
   STARTUPINFO si;
-  int cr_flags = CREATE_DEFAULT_ERROR_MODE
-    | GetPriorityClass (GetCurrentProcess ());
+  int cr_flags = (CREATE_DEFAULT_ERROR_MODE
+                  | GetPriorityClass (GetCurrentProcess ()));
   int i;
   char **args;
   char *arg_string;
@@ -679,6 +679,9 @@ _gpgme_io_spawn (const char *path, char * const argv[],
 
   free (arg_string);
   
+  if (flags & IOSPAWN_FLAG_ALLOW_SET_FG)
+    _gpgme_allow_set_foreground_window ((pid_t)pi.dwProcessId);
+
   /* Insert the inherited handles.  */
   for (i = 0; fd_list[i].fd != -1; i++)
     {
@@ -721,8 +724,10 @@ _gpgme_io_spawn (const char *path, char * const argv[],
     int written;
     size_t len;
 
-    line[0] = '\n';
-    line[1] = '\0';
+    if ((flags & IOSPAWN_FLAG_ALLOW_SET_FG))
+      strcpy (line, "~1 \n");
+    else
+      strcpy (line, "\n");
     for (i = 0; fd_list[i].fd != -1; i++)
       {
        /* Strip the newline.  */
index 69d8a39..b6dd6fb 100644 (file)
@@ -1009,7 +1009,7 @@ build_commandline (char **argv)
 
 
 int
-_gpgme_io_spawn (const char *path, char *const argv[],
+_gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags,
                 struct spawn_fd_item_s *fd_list, pid_t *r_pid)
 {
   SECURITY_ATTRIBUTES sec_attr;
@@ -1021,8 +1021,8 @@ _gpgme_io_spawn (const char *path, char *const argv[],
       0          /* returns tid */
     };
   STARTUPINFO si;
-  int cr_flags = CREATE_DEFAULT_ERROR_MODE
-    | GetPriorityClass (GetCurrentProcess ());
+  int cr_flags = (CREATE_DEFAULT_ERROR_MODE
+                  | GetPriorityClass (GetCurrentProcess ()));
   int i;
   char **args;
   char *arg_string;
@@ -1104,6 +1104,9 @@ _gpgme_io_spawn (const char *path, char *const argv[],
 
   free (arg_string);
 
+  if (flags & IOSPAWN_FLAG_ALLOW_SET_FG)
+    _gpgme_allow_set_foreground_window ((pid_t)pi.dwProcessId);
+
   /* Insert the inherited handles.  */
   for (i = 0; fd_list[i].fd != -1; i++)
     {
@@ -1139,14 +1142,16 @@ _gpgme_io_spawn (const char *path, char *const argv[],
        notation: "0xFEDCBA9876543210" with an extra white space after
        every quadruplet.  10*(19*4 + 1) - 1 = 769.  This plans ahead
        for a time when a HANDLE is 64 bit.  */
-#define BUFFER_MAX 800
+#define BUFFER_MAX 810
     char line[BUFFER_MAX + 1];
     int res;
     int written;
     size_t len;
 
-    line[0] = '\n';
-    line[1] = '\0';
+    if ((flags & IOSPAWN_FLAG_ALLOW_SET_FG))
+      strcpy (line, "~1 \n");
+    else
+      strcpy (line, "\n");
     for (i = 0; fd_list[i].fd != -1; i++)
       {
        /* Strip the newline.  */
@@ -1181,6 +1186,7 @@ _gpgme_io_spawn (const char *path, char *const argv[],
   
   if (r_pid)
     *r_pid = (pid_t)pi.dwProcessId;
+
   
   if (ResumeThread (pi.hThread) < 0)
     TRACE_LOG1 ("ResumeThread failed: ec=%d", (int) GetLastError ());
index 08f780f..03e9ea8 100644 (file)
@@ -397,7 +397,7 @@ build_commandline (char **argv)
 
 
 int
-_gpgme_io_spawn (const char *path, char * const argv[],
+_gpgme_io_spawn (const char *path, char * const argv[], unsigned int flags,
                 struct spawn_fd_item_s *fd_list, pid_t *r_pid)
 {
   SECURITY_ATTRIBUTES sec_attr;
@@ -492,6 +492,9 @@ _gpgme_io_spawn (const char *path, char * const argv[],
 
   free (arg_string);
 
+  if (flags & IOSPAWN_FLAG_ALLOW_SET_FG)
+    _gpgme_allow_set_foreground_window ((pid_t)pi.dwProcessId);
+
   /* Insert the inherited handles.  */
   for (i = 0; fd_list[i].fd != -1; i++)
     {
@@ -533,8 +536,10 @@ _gpgme_io_spawn (const char *path, char * const argv[],
     int written;
     size_t len;
 
-    line[0] = '\n';
-    line[1] = '\0';
+    if ((flags & IOSPAWN_FLAG_ALLOW_SET_FG))
+      strcpy (line, "~1 \n");
+    else
+      strcpy (line, "\n");
     for (i = 0; fd_list[i].fd != -1; i++)
       {
        /* Strip the newline.  */
index a4a01f4..a4b713e 100644 (file)
@@ -393,7 +393,7 @@ _gpgme_get_conf_int (const char *key, int *value)
 
 
 void 
-_gpgme_allow_set_foregound_window (pid_t pid)
+_gpgme_allow_set_foreground_window (pid_t pid)
 {
   static int initialized;
   static BOOL (WINAPI * func)(DWORD);
@@ -416,9 +416,22 @@ _gpgme_allow_set_foregound_window (pid_t pid)
     }
 
   if (!pid || pid == (pid_t)(-1))
-    ;
+    {
+      TRACE1 (DEBUG_ENGINE, "gpgme:AllowSetForegroundWindow", 0,
+             "no action for pid %d", (int)pid);
+    }
   else if (func)
-    func (pid);
+    {
+      int rc = func (pid);
+      TRACE2 (DEBUG_ENGINE, "gpgme:AllowSetForegroundWindow", 0,
+             "called for pid %d; result=%d", (int)pid, rc);
+
+    }
+  else
+    {
+      TRACE0 (DEBUG_ENGINE, "gpgme:AllowSetForegroundWindow", 0,
+             "function not available");
+    }
 
 }