Preparing a release gpgol-0.10.10
authorWerner Koch <wk@gnupg.org>
Wed, 2 Apr 2008 16:09:58 +0000 (16:09 +0000)
committerWerner Koch <wk@gnupg.org>
Wed, 2 Apr 2008 16:09:58 +0000 (16:09 +0000)
14 files changed:
ChangeLog
NEWS
configure.ac
doc/gpgol.texi
po/de.po
po/sv.po
src/ChangeLog
src/Makefile.am
src/common.c
src/engine-assuan.c
src/engine.c
src/main.c
src/mimeparser.c
src/util.h

index 6d43a57..a0c3833 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2008-04-01  Werner Koch  <wk@g10code.com>
+
+       * configure.ac (AC_INIT): Fix quoting.
+
 2008-03-19  Werner Koch  <wk@g10code.com>
 
        * Release 0.10.9.
diff --git a/NEWS b/NEWS
index 3910563..2a1fb9f 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,13 @@
+Noteworthy changes for version 0.10.10 (2008-04-02)
+===================================================
+
+ * Visual cleanups.
+
+ * Changes to the I/O dispatcher.
+
+
 Noteworthy changes for version 0.10.9 (2008-03-19)
-=================================================
+==================================================
 
  * Decrypt opaque signed and encrypted S/MIME mails.
 
@@ -8,7 +16,7 @@ Noteworthy changes for version 0.10.9 (2008-03-19)
 
 
 Noteworthy changes for version 0.10.8 (2008-03-18)
-=================================================
+==================================================
 
  * Fixed a segv introduced with 0.10.6.
 
index 5929693..fe94fb3 100644 (file)
@@ -16,12 +16,13 @@ min_automake_version="1.9.4"
 # Remember to change the version number immediately *after* a release.
 # Set my_issvn to "yes" for non-released code.  Remember to run an
 # "svn up" and "autogen.sh" right before creating a distribution.
-m4_define([my_version], [0.10.9])
+m4_define([my_version], [0.10.10])
 m4_define([my_issvn], [no])
 
 m4_define([svn_revision], m4_esyscmd([echo -n $( (svn info 2>/dev/null \
             || echo 'Revision: 0')|sed -n '/^Revision:/ {s/[^0-9]//gp;q;}')]))
-AC_INIT([gpgol], my_version[]m4_if(my_issvn,[yes],[-svn[]svn_revision]),
+AC_INIT([gpgol], 
+        [my_version[]m4_if(my_issvn,[yes],[-svn[]svn_revision])],
         [bug-gpgol@g10code.com])
 
 NEED_GPG_ERROR_VERSION=1.4
index 0107358..4092272 100644 (file)
@@ -661,24 +661,26 @@ the UI, useful only for debugging.  Setting it to values larger than 1
 make the log file output more verbose; these are actually bit flags
 according to the following table (which may change with any release):
 @table @code
-@item 2  (0x0002)
+@item 2 (0x0002) (ioworker)
 Tell what the Assuan I/O scheduler is doing.
-@item 4  (0x0004)
+@item 4 (0x0004) (ioworker-extra)
 Even more verbose Assuan I/O scheduler reporting. 
-@item 8  (0x0008)
+@item 8  (0x0008) (filter)
 Tell what the filter I/O system is doing.
-@item 16 (0x0010)
+@item 16 (0x0010) (filter-extra)
 Tell how the filter I/O locks the resources.
-@item 32 (0x0020)
+@item 32 (0x0020) (memory)
 Tell about resource allocation.
-@item 64 (0x0040)
+@item 64 (0x0040) (commands)
 Tell about command events.
-@item 128 (0x0080)
+@item 128 (0x0080) (mime-parser)
 Tell what the MIME parser is doing
-@item 256 (0x0100)
+@item 256 (0x0100) (mime-data)
 Print data lines while parsing MIME.
 @end table
-You may use the regular C-syntax for entering the value.
+You may use the regular C-syntax for entering the value.  As an
+alternative you may use the names ofthe flags, separated by space or
+comma.
 
 
 @itemx HKCU\Software\GNU\GpgOL:logFile
index 1b0b559..9de3738 100644 (file)
--- a/po/de.po
+++ b/po/de.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: GpgOL 0.10.0\n"
 "Report-Msgid-Bugs-To: bug-gpgol@g10code.com\n"
-"POT-Creation-Date: 2008-03-31 18:00+0200\n"
+"POT-Creation-Date: 2008-04-02 17:45+0200\n"
 "PO-Revision-Date: 2008-03-31 18:06+0200\n"
 "Last-Translator: Werner Koch <wk@gnupg.org>\n"
 "Language-Team: de\n"
@@ -48,7 +48,7 @@ msgstr "GpgOL - Sichern der entschlüsselten Anlage"
 msgid "Debug output (for analysing problems)"
 msgstr "Debugausgabe (zur Problemanalyse)"
 
-#: src/engine.c:372
+#: src/engine.c:405
 msgid ""
 "The user interface server is not available or does not work.  Using an "
 "internal user interface.\n"
@@ -68,7 +68,7 @@ msgstr ""
 "   (unter \"GnuPG für Windows\") oder auf einem anderen Weg starten.\n"
 "   Sobald \"Kleopatra\" läuft, erneut Outlook starten."
 
-#: src/engine.c:376 src/ext-commands.cpp:703 src/main.c:614 src/main.c:620
+#: src/engine.c:409 src/ext-commands.cpp:703 src/main.c:665 src/main.c:671
 #: src/message.cpp:326
 msgid "GpgOL"
 msgstr "GpgOL"
@@ -281,7 +281,10 @@ msgid ""
 msgstr ""
 "Unterstützung für S/MIME ist nicht eingeschaltet.\n"
 "\n"
-"Um die S/MIME Unterstützung einzuschalten, öffnen Sie bitte das Fenster mit den Einstellungen um dort die Option \"S/MIME Unterstützung einschalten\" zu aktivieren.  Sie finden die Einstellungen im Hauptmenu unter:  Extras->Optionen->GpgOL.\n"
+"Um die S/MIME Unterstützung einzuschalten, öffnen Sie bitte das Fenster mit "
+"den Einstellungen um dort die Option \"S/MIME Unterstützung einschalten\" zu "
+"aktivieren.  Sie finden die Einstellungen im Hauptmenu unter:  Extras-"
+">Optionen->GpgOL.\n"
 
 #: src/ext-commands.cpp:702
 msgid "Could not start certificate manager"
@@ -329,12 +332,12 @@ msgstr "S/MIME zum signieren/verschlüsseln verwenden"
 msgid "Open the GpgOL certificate manager"
 msgstr "Zertifikatsverwaltung von GpgOL öffnen"
 
-#: src/main.c:613
+#: src/main.c:664
 #, c-format
 msgid "Note: Using compatibility flags: %s"
 msgstr "Notiz: Diese Kompatibilitätsflags werden verwendet: %s"
 
-#: src/main.c:619
+#: src/main.c:670
 #, c-format
 msgid ""
 "Note: Writing debug logs to\n"
@@ -557,7 +560,9 @@ msgid ""
 msgstr ""
 "Eine neue Version von GpgOL ist installiert worden.\n"
 "\n"
-"Bitte öffnen Sie das Fenster mit den Einstellungen und bestätigen Sie, daß die die Einstellungen für Sie noch stimmen.  Sie finden die Einstellungen im Hauptmenu unter:  Extras->Optionen->GpgOL.\n"
+"Bitte öffnen Sie das Fenster mit den Einstellungen und bestätigen Sie, daß "
+"die die Einstellungen für Sie noch stimmen.  Sie finden die Einstellungen im "
+"Hauptmenu unter:  Extras->Optionen->GpgOL.\n"
 
 #: src/olflange.cpp:506
 msgid ""
index 8160aa1..33d3bbf 100644 (file)
--- a/po/sv.po
+++ b/po/sv.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: GPGol\n"
 "Report-Msgid-Bugs-To: bug-gpgol@g10code.com\n"
-"POT-Creation-Date: 2008-03-31 18:00+0200\n"
+"POT-Creation-Date: 2008-04-02 17:45+0200\n"
 "PO-Revision-Date: 2006-12-12 23:52+0100\n"
 "Last-Translator: Daniel Nylander <po@danielnylander.se>\n"
 "Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n"
@@ -48,7 +48,7 @@ msgstr "GPG - Spara dekrypterad bilaga"
 msgid "Debug output (for analysing problems)"
 msgstr ""
 
-#: src/engine.c:372
+#: src/engine.c:405
 msgid ""
 "The user interface server is not available or does not work.  Using an "
 "internal user interface.\n"
@@ -57,7 +57,7 @@ msgid ""
 "are not readable."
 msgstr ""
 
-#: src/engine.c:376 src/ext-commands.cpp:703 src/main.c:614 src/main.c:620
+#: src/engine.c:409 src/ext-commands.cpp:703 src/main.c:665 src/main.c:671
 #: src/message.cpp:326
 msgid "GpgOL"
 msgstr ""
@@ -325,12 +325,12 @@ msgstr ""
 msgid "Open the GpgOL certificate manager"
 msgstr ""
 
-#: src/main.c:613
+#: src/main.c:664
 #, c-format
 msgid "Note: Using compatibility flags: %s"
 msgstr ""
 
-#: src/main.c:619
+#: src/main.c:670
 #, c-format
 msgid ""
 "Note: Writing debug logs to\n"
index 0a04cad..75db15b 100644 (file)
@@ -1,5 +1,23 @@
+2008-04-02  Werner Koch  <wk@g10code.com>
+
+       * engine-assuan.c (destroy_command): Add arg FORCE.
+       (op_assuan_encrypt_bottom): Call destroy_command.
+
+       * mimeparser.c (struct mime_context): Use parser_error to return
+       gpg error codes.
+
+       * main.c (read_options): Allow names for debug flags.
+       * common.c (trim_spaces): New.
+
 2008-03-31  Werner Koch  <wk@g10code.com>
 
+       * engine-assuan.c (struct work_item_s): Add SWITCH_COUNTER.
+       (switch_threads, clear_switch_threads): New.
+       (worker_start_write): Use it.
+       * engine.c (struct engine_filter_s): Add SWITCH_COUNTER.
+       (switch_threads, clear_switch_threads): New.
+       (filter_gpgme_read_cb): Use it.
+
        * ext-commands.h (class GpgolExtCommands): Add m_nCmdCryptoState.
        * ext-commands.cpp (InstallCommands): Add a toolbar crypto state
        button.
index af004ad..c40842b 100644 (file)
@@ -74,13 +74,13 @@ libmapi32.a: mapi32.def
        $(DLLTOOL) --output-lib $@ --def $<
 
 libgpg-error.a:
-       ln -s $(shell $(GPG_ERROR_CONFIG) --prefix)/lib/libgpg-error.a
+       ln -s $$($(GPG_ERROR_CONFIG) --prefix)/lib/libgpg-error.a .
 
 libgpgme.a:
-       ln -s $(shell $(GPGME_CONFIG) --prefix)/lib/libgpgme.a
+       ln -s $$($(GPGME_CONFIG) --prefix)/lib/libgpgme.a .
 
 libassuan.a:
-       ln -s $(shell $(LIBASSUAN_CONFIG) --prefix)/lib/libassuan.a
+       ln -s $$($(LIBASSUAN_CONFIG) --prefix)/lib/libassuan.a .
 
 clean-local:
        rm -f libmapi32.a libgpg-error.a libgpgme.a libassuan.a
index b2f81cf..ad195a8 100644 (file)
@@ -413,6 +413,36 @@ trim_trailing_spaces (char *string)
 }
 
 
+/* Strip off leading and trailing white spaces from STRING.  Returns
+   STRING. */
+char *
+trim_spaces (char *arg_string)
+{
+  char *string = arg_string;
+  char *p, *mark;
+
+  /* Find first non space character. */
+  for (p = string; *p && isascii (*p) && isspace (*p) ; p++ )
+    ;
+  /* Move characters. */
+  for (mark = NULL; (*string = *p); string++, p++ )
+    {
+      if (isascii (*p) && isspace (*p))
+        {
+          if (!mark)
+          mark = string;
+        }
+      else
+        mark = NULL ;
+    }
+  if (mark)
+    *mark = 0;
+  
+  return arg_string;
+}
+
+
+
 /* Helper for read_w32_registry_string(). */
 static HKEY
 get_root_key(const char *root)
index 6e9a36b..cdd9e5f 100644 (file)
@@ -111,6 +111,8 @@ struct work_item_s
                                     queue.  */
   OVERLAPPED ov;     /* The overlapped info structure.  */
   char buffer[1024]; /* The buffer used by ReadFile or WriteFile.  */
+
+  ULONG switch_counter; /* Used by switch_threads.  */
 };
 
 
@@ -636,6 +638,39 @@ attach_thread_input (DWORD other_tid)
 #endif /* not used.  */
 
 
+/* This is a wraper around SwitchToThread, a syscall we unfortunately
+   need due to the lack of an sophisticated event system.  The wrapper
+   calls SwitchToThread but after a couple of immediate folliwing
+   switches, it introduces a short delays.  */
+static void
+switch_threads (work_item_t item)
+{
+  ULONG count;
+
+  count = InterlockedExchangeAdd (&item->switch_counter, 1);
+  if (count > 5)
+    {
+      /* Tried too often without success.  Use Sleep until
+         clear_switch_threads has been called.  */
+      InterlockedExchange (&item->switch_counter, 5);
+      SleepEx (60, TRUE); 
+    }
+  else if (!SwitchToThread ())
+    {
+      /* No runable other thread: Fall asleep. */
+      SleepEx (8, TRUE);
+    }
+}
+
+/* Call this fucntion if some action has been done.  */
+static void
+clear_switch_threads (work_item_t item)
+{
+  InterlockedExchange (&item->switch_counter, 0);
+}
+
+
+
 \f
 /* Helper for async_worker_thread.  Returns true if the item's handle
    needs to be put on the wait list.  This is called with the worker
@@ -763,13 +798,16 @@ worker_start_write (work_item_t item)
   /* Read from the callback and the write to the handle.  The gpgme
      callback is expected to never block.  */
   nread = gpgme_data_read (item->data, item->buffer, sizeof item->buffer);
+  if (nread < 0 && errno == EAGAIN)
+    switch_threads (item);
+  else
+    clear_switch_threads (item);
   if (nread < 0)
     {
       if (errno == EAGAIN)
         {
 /*           log_debug ("%s:%s: [%s:%p] ignoring EAGAIN from callback", */
 /*                      SRCNAME, __func__, item->name, item->hd); */
-          SwitchToThread ();
           retval = 1;
         }
       else
@@ -955,7 +993,21 @@ async_worker_thread (void *dummy)
 /*                                          INFINITE, QS_ALLEVENTS); */
           if (n == WAIT_FAILED)
             {
+              int i;
+              DWORD hdinfo;
+                  
               log_error_w32 (-1, "%s:%s: WFMO failed", SRCNAME, __func__);
+              for (i=0; i < hdarraylen; i++)
+                {
+                  hdinfo = 0;
+                  if (!GetHandleInformation (hdarray[i], &hdinfo))
+                    log_debug_w32 (-1, "%s:%s: WFMO GetHandleInfo(%p) failed", 
+                                   SRCNAME, __func__, hdarray[i]);
+                  else
+                    log_debug ("%s:%s: WFMO GetHandleInfo(%p)=0x%lu", 
+                               SRCNAME, __func__, hdarray[i],
+                               (unsigned long)hdinfo);
+                }
               Sleep (1000);
             }
           else if (n >= 0 && n < hdarraylen)
@@ -1060,33 +1112,60 @@ async_worker_thread (void *dummy)
             {
               if (item->cld)
                 {
+                  work_item_t itm2;
+
                   if (!item->cld->final_err && item->got_error)
                     item->cld->final_err = gpg_error (GPG_ERR_EIO);
 
-                  if (!item->cld->final_err)
+                  /* Check whether there are other work items in this
+                     group we need to wait for before invoking the
+                     closure. */
+                  for (itm2=work_queue; itm2; itm2 = itm2->next)
+                    if (itm2->used && itm2 != item 
+                        && itm2->cmdid == item->cmdid
+                        && itm2->wait_on_success
+                        && !(itm2->got_ready || itm2->got_error))
+                      break;
+                  if (itm2)
                     {
-                      /* Check whether there are other work items in
-                         this group we need to wait for before
-                         invoking the closure. */
-                      work_item_t itm2;
-                      
-                      for (itm2=work_queue; itm2; itm2 = itm2->next)
-                        if (itm2->used && itm2 != item 
-                            && itm2->cmdid == item->cmdid
-                            && itm2->wait_on_success
-                            && !(itm2->got_ready || itm2->got_error))
-                          break;
-                      if (itm2)
+                      if (debug_ioworker)
+                        log_debug ("%s:%s: [%s:%p] delaying closure "
+                                   "due to [%s:%p]", SRCNAME, __func__,
+                                   item->name, item->hd, 
+                                   itm2->name, itm2->hd);
+                      item->delayed_ready = 1;
+                      if (item->cld->final_err)
                         {
-                          if (debug_ioworker)
-                            log_debug ("%s:%s: [%s:%p] delaying closure "
-                                       "due to [%s/%p]", SRCNAME, __func__,
-                                       item->name, item->hd, 
-                                       itm2->name, itm2->hd);
-                          item->delayed_ready = 1;
-                          break; 
+                          /* If we received an error we better do not
+                             assume that the server has properly
+                             closed all I/O channels.  Send a cancel
+                             to the work item we are waiting for. */
+                          if (!itm2->aborting)
+                            {
+                              if (debug_ioworker)
+                                log_debug ("%s:%s: [%s:%p] calling CancelIO",
+                                           SRCNAME, __func__,
+                                           itm2->name, itm2->hd);
+                              itm2->aborting = 1;
+                              if (!CancelIo (itm2->hd))
+                                log_error_w32 (-1, "%s:%s: [%s:%p] "
+                                               "CancelIo failed",
+                                               SRCNAME,__func__, 
+                                               itm2->name, itm2->hd);
+                            }
+                          else
+                            {
+                              if (debug_ioworker)
+                                log_debug ("%s:%s: [%s:%p] clearing "
+                                           "wait on success flag",
+                                           SRCNAME, __func__,
+                                           itm2->name, itm2->hd);
+                              itm2->wait_on_success = 0;
+                            }
                         }
+                      break; 
                     }
+
                   item->delayed_ready = 0;
                   if (debug_ioworker)
                     log_debug ("%s:%s: [%s:%p] invoking closure",
@@ -1189,18 +1268,19 @@ enqueue_callback (const char *name, assuan_context_t ctx,
 /* Remove all items from the work queue belonging to the command with
    the id CMDID.  */
 static void
-destroy_command (ULONG cmdid)
+destroy_command (ULONG cmdid, int force)
 {
   work_item_t item;
 
   EnterCriticalSection (&work_queue_lock);
   for (item = work_queue; item; item = item->next)
-    if (item->used && item->cmdid == cmdid && !item->wait_on_success)
+    if (item->used && item->cmdid == cmdid 
+        && (!item->wait_on_success || force))
       {
         if (debug_ioworker)
           log_debug ("%s:%s: [%s:%p] cmdid=%lu registered for destroy",
                      SRCNAME, __func__, item->name, item->hd, item->cmdid);
-        /* First send an I/O cancel in case the the last
+        /* First send an I/O cancel in case the last
            GetOverlappedResult returned only a partial result.  This
            works because we are always running within the
            async_worker_thread.  */
@@ -1315,7 +1395,7 @@ status_in_cb (void *opaque, const void *buffer, size_t size)
               break;
             case 1: /* Ready. */
               cld->status_ready = 1;
-              destroy_command (cld->cmdid);
+              destroy_command (cld->cmdid, 0);
               break;
             default:
               log_error ("%s:%s: invalid line from server", SRCNAME, __func__);
@@ -1432,7 +1512,7 @@ encrypt_closure (closure_data_t cld)
    correct relationship between a popups and the active window.  If
    this function returns success, the data objects may only be
    destroyed after an engine_wait or engine_cancel.  On success the
-   fucntion returns a pojunter to the encryption state and thus
+   function returns a poiunter to the encryption state and thus
    requires that op_assuan_encrypt_bottom will be run later. */
 int
 op_assuan_encrypt (protocol_t protocol, 
@@ -1579,11 +1659,15 @@ op_assuan_encrypt_bottom (struct engine_assuan_encstate_s *encstate,
 
   if (err)
     {
-      /* Fixme: Cancel stuff in the work_queue. */
+      xfree (encstate->cld);
+      encstate->cld = NULL;
+      engine_private_set_cancel (encstate->filter, NULL);
       close_pipe (encstate->inpipe);
       close_pipe (encstate->outpipe);
-      xfree (encstate->cld);
+      if (cancel)
+        destroy_command (encstate->cmdid, 1);
       assuan_disconnect (encstate->ctx);
+      encstate->ctx = NULL;
     }
   else
     engine_private_set_cancel (encstate->filter, encstate->ctx);
index 373a906..ffcc5fd 100644 (file)
@@ -105,6 +105,9 @@ struct engine_filter_s
   /* A pointer used convey information from engine_encrypt_prepare to
      engine_encrypt_start.  */
   struct engine_assuan_encstate_s *encstate;
+
+  /* Counter used to optimize voluntary thread switching. */
+  ULONG switch_counter;
 };
 
 
@@ -198,6 +201,34 @@ release_filter (engine_filter_t filter)
 }
 
 
+/* This is a wraper around SwitchToThread, a syscall we unfortunately
+   need due to the lack of an sophisticated event system.  The wrapper
+   calls SwitchToThread but after a couple of immediate folliwing
+   switches, it introduces a short delays.  */
+static void
+switch_threads (engine_filter_t filter)
+{
+  ULONG count;
+
+  count = InterlockedExchangeAdd (&filter->switch_counter, 1);
+  if (count > 5)
+    {
+      InterlockedExchange (&filter->switch_counter, 5);
+      SleepEx (50, TRUE); 
+    }
+  else if (!SwitchToThread ())
+    {
+      /* No runable other thread: Fall asleep. */
+      SleepEx (5, TRUE);
+    }
+}
+
+/* Call this fucntion if some action has been done.  */
+static void
+clear_switch_threads (engine_filter_t filter)
+{
+  InterlockedExchange (&filter->switch_counter, 0);
+}
 
 
 /* This read callback is used by GPGME to read data from a filter
@@ -234,9 +265,11 @@ filter_gpgme_read_cb (void *handle, void *buffer, size_t size)
           errno = EAGAIN;
           if (debug_filter_extra)
             log_debug ("%s:%s: leave; result=EAGAIN\n", SRCNAME, __func__);
-          SwitchToThread ();
+          switch_threads (filter);
           return -1;
         }
+      else
+        clear_switch_threads (filter);
       if (debug_filter)
         log_debug ("%s:%s: waiting for in.condvar\n", SRCNAME, __func__);
       WaitForSingleObject (filter->in.condvar, 500);
@@ -425,8 +458,11 @@ engine_filter (engine_filter_t filter, const void *indata, size_t indatalen)
                SRCNAME, __func__, indata, (int)indatalen, filter->outfnc); 
   for (;;)
     {
+      int any;
+
       /* If there is something to write out, do this now to make space
          for more data.  */
+      any = 0;
       take_out_lock (filter, __func__);
       while (filter->out.length)
         {
@@ -447,13 +483,19 @@ engine_filter (engine_filter_t filter, const void *indata, size_t indatalen)
             memmove (filter->out.buffer, filter->out.buffer + nbytes,
                      filter->out.length - nbytes); 
           filter->out.length -= nbytes;
+          any = 1;
         }
       if (!PulseEvent (filter->out.condvar))
         log_error_w32 (-1, "%s:%s: PulseEvent(out) failed", SRCNAME, __func__);
       release_out_lock (filter, __func__);
-      
-      take_in_lock (filter, __func__);
 
+      if (any)
+        clear_switch_threads (filter);
+      else
+        switch_threads (filter);
+
+      any = 0;
+      take_in_lock (filter, __func__);
       if (!indata && !indatalen)
         {
           filter->in.got_eof = 1;
@@ -480,17 +522,23 @@ engine_filter (engine_filter_t filter, const void *indata, size_t indatalen)
           memcpy (filter->in.buffer, indata, filter->in.length);
           indata    += filter->in.length;
           indatalen -= filter->in.length;
+          any = 1;
         }
+      /* Terminate the loop if the filter queue is empty OR the filter
+         is ready and there is nothing left for output.  */
       if (!filter->in.length || (filter->in.ready && !filter->out.length))
         {
           release_in_lock (filter, __func__);
-          err = 0;
+          err = filter->in.status;
           break;  /* the loop.  */
         }
       if (!PulseEvent (filter->in.condvar))
         log_error_w32 (-1, "%s:%s: PulseEvent(in) failed", SRCNAME, __func__);
       release_in_lock (filter, __func__);
-      SwitchToThread ();
+      if (any)
+        clear_switch_threads (filter);
+      else
+        switch_threads (filter);
     }
 
   if (debug_filter)
index c8354ae..a34e334 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <windows.h>
 #include <wincrypt.h>
+#include <ctype.h>
 
 #include "mymapi.h"
 #include "mymapitags.h"
@@ -507,10 +508,52 @@ read_options (void)
 {
   static int warnings_shown;
   char *val = NULL;
+
+  /* Set the log file first so that output from this function is
+     logged too.  */
+  load_extension_value ("logFile", &val);
+  set_log_file (val);
+  xfree (val); val = NULL;
+  
+  /* Parse the debug flags.  */
   load_extension_value ("enableDebug", &val);
-  opt.enable_debug = val? strtoul (val, NULL, 0) : 0;
-  if (!val)
+  opt.enable_debug = 0;
+  if (val)
+    {
+      char *p, *pend;
+
+      trim_spaces (val);
+      for (p = val; p; p = pend)
+        {
+          pend = strpbrk (p, ", \t\n\r\f");
+          if (pend)
+            {
+              *pend++ = 0;
+              pend += strspn (pend, ", \t\n\r\f");
+            }
+          if (isascii (*p) && isdigit (*p))
+            opt.enable_debug |= strtoul (p, NULL, 0);
+          else if (!strcmp (p, "ioworker"))
+            opt.enable_debug |= DBG_IOWORKER;
+          else if (!strcmp (p, "ioworker-extra"))
+            opt.enable_debug |= DBG_IOWORKER_EXTRA;
+          else if (!strcmp (p, "filter"))
+            opt.enable_debug |= DBG_FILTER;
+          else if (!strcmp (p, "filter-extra"))
+            opt.enable_debug |= DBG_FILTER_EXTRA;
+          else if (!strcmp (p, "memory"))
+            opt.enable_debug |= DBG_MEMORY;
+          else if (!strcmp (p, "commands"))
+            opt.enable_debug |= DBG_COMMANDS;
+          else if (!strcmp (p, "mime-parser"))
+            opt.enable_debug |= DBG_MIME_PARSER;
+          else if (!strcmp (p, "mime-data"))
+            opt.enable_debug |= DBG_MIME_DATA;
+          else
+            log_debug ("invalid debug flag `%s' ignored", p);
+        }
+    }
+  else
     {
       /* To help the user enable debugging make sure that the registry
          key exists.  Note that the other registry keys are stored
@@ -518,6 +561,18 @@ read_options (void)
       store_extension_value ("enableDebug", "0");
     }
   xfree (val); val = NULL;
+  if (opt.enable_debug)
+    log_debug ("enabled debug flags:%s%s%s%s%s%s%s%s\n",
+               (opt.enable_debug & DBG_IOWORKER)? " ioworker":"",
+               (opt.enable_debug & DBG_IOWORKER_EXTRA)? " ioworker-extra":"",
+               (opt.enable_debug & DBG_FILTER)? " filter":"",
+               (opt.enable_debug & DBG_FILTER_EXTRA)? " filter-extra":"",
+               (opt.enable_debug & DBG_MEMORY)? " memory":"",
+               (opt.enable_debug & DBG_COMMANDS)? " commands":"",
+               (opt.enable_debug & DBG_MIME_PARSER)? " mime-parser":"",
+               (opt.enable_debug & DBG_MIME_DATA)? " mime-data":""
+               );
+
 
   load_extension_value ("enableSmime", &val);
   opt.enable_smime = val == NULL || *val != '1' ? 0 : 1;
@@ -559,10 +614,6 @@ read_options (void)
   opt.enc_format = val == NULL? GPG_FMT_CLASSIC  : atol (val);
   xfree (val); val = NULL;
 
-  load_extension_value ("logFile", &val);
-  set_log_file (val);
-  xfree (val); val = NULL;
-  
   load_extension_value ("defaultKey", &val);
   set_default_key (val);
   xfree (val); val = NULL;
index 6cda93d..3ada4ae 100644 (file)
@@ -123,7 +123,7 @@ struct mime_context
                              working on a MIME message and not just on
                              plain rfc822 message.  */
   
-  engine_filter_t outfilter; /* Fiter as used by ciphertext_handler.  */
+  engine_filter_t outfilter; /* Filter as used by ciphertext_handler.  */
 
   /* A linked list describing the structure of the mime message.  This
      list gets build up while parsing the message.  */
@@ -148,8 +148,8 @@ struct mime_context
   b64_state_t base64;     /* The state of the Base-64 decoder.  */
 
   int line_too_long;  /* Indicates that a received line was too long. */
-  int parser_error;   /* Indicates that we encountered a error from
-                         the parser. */
+  gpg_error_t parser_error;   /* Indicates that we encountered a error from
+                                 the parser. */
 
   /* Buffer used to constructed complete files. */
   size_t linebufsize;   /* The allocated size of the buffer. */
@@ -1000,7 +1000,7 @@ message_cb (void *opaque, rfc822parse_event_t event, rfc822parse_t msg)
         {
           log_error ("%s: ctx=%p, invalid structure: bad nesting level\n",
                      SRCNAME, ctx);
-          ctx->parser_error = 1;
+          ctx->parser_error = gpg_error (GPG_ERR_GENERAL);
         }
       break;
     
@@ -1067,7 +1067,7 @@ plaintext_handler (void *handle, const void *buffer, size_t size)
             {
               log_error ("%s: ctx=%p, rfc822 parser failed: %s\n",
                          SRCNAME, ctx, strerror (errno));
-              ctx->parser_error = 1;
+              ctx->parser_error = gpg_error (GPG_ERR_GENERAL);
               return -1; /* Error. */
             }
 
@@ -1122,7 +1122,7 @@ plaintext_handler (void *handle, const void *buffer, size_t size)
                       if (!ctx->preview)
                         MessageBox (ctx->hwnd, _("Error writing to stream"),
                                     _("I/O-Error"), MB_ICONERROR|MB_OK);
-                      ctx->parser_error = 1;
+                      ctx->parser_error = gpg_error (GPG_ERR_EIO);
                       return -1; /* Error. */
                     }
                 }
@@ -1206,7 +1206,12 @@ mime_verify (protocol_t protocol, const char *message, size_t messagelen,
         log_debug ("%s:%s: passing '%.*s'\n", 
                    SRCNAME, __func__, (int)len, message);
       plaintext_handler (ctx, message, len);
-      if (ctx->parser_error || ctx->line_too_long)
+      if (ctx->parser_error)
+        {
+          err = ctx->parser_error;
+          break;
+        }
+      else if (ctx->line_too_long)
         {
           err = gpg_error (GPG_ERR_GENERAL);
           break;
@@ -1385,7 +1390,9 @@ mime_verify_opaque (protocol_t protocol, LPSTREAM instream,
     goto leave;
   filter = NULL;
 
-  if (ctx->parser_error || ctx->line_too_long)
+  if (ctx->parser_error)
+    err = ctx->parser_error;
+  else if (ctx->line_too_long)
     err = gpg_error (GPG_ERR_GENERAL);
 
  leave:
@@ -1511,7 +1518,7 @@ ciphermessage_cb (void *opaque, rfc822parse_event_t event, rfc822parse_t msg)
         {
           log_error ("%s: decctx=%p, invalid structure: bad nesting level\n",
                      SRCNAME, decctx);
-          decctx->parser_error = 1;
+          decctx->parser_error = gpg_error (GPG_ERR_GENERAL);
         }
       break;
     
@@ -1569,7 +1576,7 @@ ciphertext_handler (void *handle, const void *buffer, size_t size)
             {
               log_error ("%s:%s: ctx=%p, rfc822 parser failed: %s\n",
                          SRCNAME, __func__, ctx, strerror (errno));
-              ctx->parser_error = 1;
+              ctx->parser_error = gpg_error (GPG_ERR_GENERAL);
               return -1; /* Error. */
             }
 
@@ -1599,7 +1606,7 @@ ciphertext_handler (void *handle, const void *buffer, size_t size)
                 {
                   log_debug ("%s:%s: sending ciphertext to engine failed: %s",
                              SRCNAME, __func__, gpg_strerror (err));
-                  ctx->parser_error = 1;
+                  ctx->parser_error = err;
                   return -1; /* Error. */
                 }
             }
@@ -1714,7 +1721,12 @@ mime_decrypt (protocol_t protocol, LPSTREAM instream, LPMESSAGE mapi_message,
           if (decctx)
             {
                ciphertext_handler (decctx, buffer, nread);
-               if (ctx->parser_error || ctx->line_too_long)
+               if (decctx->parser_error)
+                 {
+                   err = decctx->parser_error;
+                   break;
+                 }
+               else if (decctx->line_too_long)
                  {
                    err = gpg_error (GPG_ERR_GENERAL);
                    break;
@@ -1737,7 +1749,9 @@ mime_decrypt (protocol_t protocol, LPSTREAM instream, LPMESSAGE mapi_message,
     goto leave;
   filter = NULL;
 
-  if (ctx->parser_error || ctx->line_too_long)
+  if (ctx->parser_error)
+    err = ctx->parser_error;
+  else if (ctx->line_too_long)
     err = gpg_error (GPG_ERR_GENERAL);
 
  leave:
index 387a354..cb38ff1 100644 (file)
@@ -62,6 +62,7 @@ char *wchar_to_utf8_2 (const wchar_t *string, size_t len);
 wchar_t *utf8_to_wchar2 (const char *string, size_t len);
 char *latin1_to_utf8 (const char *string);
 
+char *trim_spaces (char *string);
 char *trim_trailing_spaces (char *string);
 char *read_w32_registry_string (const char *root, const char *dir,
                                 const char *name);