2007-07-13 Marcus Brinkmann <marcus@g10code.de>
[gpgme.git] / gpgme / w32-glib-io.c
index f725a06..8f56eee 100644 (file)
 #include "sema.h"
 #include "debug.h"
 
+#ifndef O_BINARY
+#ifdef _O_BINARY
+#define O_BINARY       _O_BINARY
+#else
+#define O_BINARY       0
+#endif
+#endif
 
 \f
 /* This file is an ugly hack to get GPGME working with glib on Windows
@@ -116,10 +123,11 @@ _gpgme_io_subsystem_init (void)
 \f
 static struct
 {
-  void (*handler) (int,void*);
+  _gpgme_close_notify_handler_t handler;
   void *value;
 } notify_table[MAX_SLAFD];
 
+
 int
 _gpgme_io_read (int fd, void *buffer, size_t count)
 {
@@ -206,7 +214,7 @@ _gpgme_io_pipe (int filedes[2], int inherit_idx)
   GIOChannel *chan;
 
 #define PIPEBUF_SIZE  4096
-  if (_pipe (filedes, PIPEBUF_SIZE, O_NOINHERIT) == -1)
+  if (_pipe (filedes, PIPEBUF_SIZE, O_NOINHERIT | O_BINARY) == -1)
     return -1;
 
   /* Make one end inheritable. */
@@ -287,15 +295,16 @@ _gpgme_io_close (int fd)
       g_io_channel_unref (chan);
       giochannel_table[fd] = NULL;
     }
-
-  _close (fd);
+  else
+    _close (fd);
 
   return 0;
 }
 
 
 int
-_gpgme_io_set_close_notify (int fd, void (*handler)(int, void*), void *value)
+_gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler,
+                           void *value)
 {
   assert (fd != -1);
 
@@ -313,21 +322,25 @@ _gpgme_io_set_nonblocking (int fd)
 {
   GIOChannel *chan;
   GIOStatus status;
-
   chan = find_channel (fd, 0);
   if (!chan)
     {
+      DEBUG1 ("set nonblocking for fd %d failed: channel not found", fd);
       errno = EIO;
       return -1;
     }
 
-  status = g_io_channel_set_flags (chan,
+   status = g_io_channel_set_flags (chan,
                                   g_io_channel_get_flags (chan) |
                                   G_IO_FLAG_NONBLOCK, NULL);
   if (status != G_IO_STATUS_NORMAL)
     {
-      errno = EIO;
-      return -1;
+      /* glib 1.9.2 does not implement set_flags and returns an error. */
+      DEBUG2 ("set nonblocking for fd %d failed: status=%d - ignored",
+              fd, status);
+/*       errno = EIO; */
+/*       return -1; */
     }
 
   return 0;
@@ -335,37 +348,57 @@ _gpgme_io_set_nonblocking (int fd)
 
 
 static char *
-build_commandline ( char **argv )
+build_commandline (char **argv)
 {
-  int i, n = 0;
-  char *buf, *p;
+  int i;
+  int j;
+  int n = 0;
+  char *buf;
+  char *p;
   
-  /* FIXME: we have to quote some things because under Windows the
-   * program parses the commandline and does some unquoting.  For now
-   * we only do very basic quoting to the first argument because this
-   * one often contains a space (e.g. C:\\Program Files\GNU\GnuPG\gpg.exe) 
-   * and we would produce an invalid line in that case.  */
-  for (i=0; argv[i]; i++)
-    n += strlen (argv[i]) + 2 + 1; /* 2 extra bytes for possible quoting */
+  /* We have to quote some things because under Windows the program
+     parses the commandline and does some unquoting.  We enclose the
+     whole argument in double-quotes, and escape literal double-quotes
+     as well as backslashes with a backslash.  We end up with a
+     trailing space at the end of the line, but that is harmless.  */
+  for (i = 0; argv[i]; i++)
+    {
+      p = argv[i];
+      /* The leading double-quote.  */
+      n++;
+      while (*p)
+       {
+         /* An extra one for each literal that must be escaped.  */
+         if (*p == '\\' || *p == '"')
+           n++;
+         n++;
+         p++;
+       }
+      /* The trailing double-quote and the delimiter.  */
+      n += 2;
+    }
+  /* And a trailing zero.  */
+  n++;
+
   buf = p = malloc (n);
-  if ( !buf )
+  if (!buf)
     return NULL;
-  *buf = 0;
-  if ( argv[0] )
+  for (i = 0; argv[i]; i++)
     {
-      if (strpbrk (argv[0], " \t"))
-        p = stpcpy (stpcpy (stpcpy (p, "\""), argv[0]), "\"");
-      else
-        p = stpcpy (p, argv[0]);
-      for (i = 1; argv[i]; i++)
-        {
-          if (!*argv[i])
-            p = stpcpy (p, " \"\"");
-          else
-            p = stpcpy (stpcpy (p, " "), argv[i]);
-        }
+      char *argvp = argv[i];
+
+      *(p++) = '"';
+      while (*argvp)
+       {
+         if (*argvp == '\\' || *argvp == '"')
+           *(p++) = '\\';
+         *(p++) = *(argvp++);
+       }
+      *(p++) = '"';
+      *(p++) = ' ';
     }
-  
+  *(p++) = 0;
+
   return buf;
 }
 
@@ -594,8 +627,6 @@ _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
            DEBUG_ADD1 (dbg_help, "r%d ", fds[pollfds_map[i]].fd);
           if ((pollfds[i].revents & G_IO_OUT))
             DEBUG_ADD1 (dbg_help, "w%d ", fds[pollfds_map[i]].fd);
-         DEBUG_ADD2 (dbg_help, "x%d(%x) ", fds[pollfds_map[i]].fd,
-                     pollfds[i].revents);
         }
       DEBUG_END (dbg_help, "]");
     }