Yeah, that was a huge leap today.
authorWerner Koch <wk@gnupg.org>
Wed, 28 Sep 2005 19:20:00 +0000 (19:20 +0000)
committerWerner Koch <wk@gnupg.org>
Wed, 28 Sep 2005 19:20:00 +0000 (19:20 +0000)
Got rid of the Save Changes? message
and fixed the utf8 issues.  Although figured out possible ways of
overcoming the messy reply thing.

TODO
src/ChangeLog
src/common.c
src/display.cpp
src/gpgmsg.cpp
src/main.c
src/myexchext.h
src/olflange.cpp
src/passphrase-dialog.c
src/pgpmime.c
src/util.h

diff --git a/TODO b/TODO
index 80abf24..a1b8e03 100644 (file)
--- a/TODO
+++ b/TODO
@@ -7,7 +7,7 @@
 * find out why sometimes the new body cannot set to a MAPI object. In
   this case the body is empty but the W32 API said it was correctly set.
   This might be due to the length of the object.  HrGetOneProp has
-  such limitations adn thus it would be reasonable to assume that the
+  such limitations and thus it would be reasonable to assume that the
   same holds true for HrSetOneProp.  We might want to use OpenProperty
   for longer texts.
 
index e8c6d49..a0a2ccb 100644 (file)
@@ -1,3 +1,22 @@
+2005-09-28  Werner Koch  <wk@g10code.com>
+
+       * olflange.cpp (DoCommand): Catch close command and resend to
+       avoid the "save changes?".
+
+       * display.cpp (update_display): Take care of utf-8 issues.
+       * common.c (latin1_to_utf8): New.
+       * pgpmime.c (latin1_data_write): New.
+       (plaintext_handler): Use it here.
+       (message_cb): Detect utf-8 encoding.
+
+       * main.c (read_options): Make sure that compat flags are always
+       properly initialized.
+
+       * display.cpp (find_message_window): First try to find the window
+       by class name.
+
+       * common.c (wchar_to_utf8_2): New.
+
 2005-09-27  Werner Koch  <wk@g10code.com>
 
        * pgpmime.c (pgpmime_decrypt): Pass a pseduo filename to the
index b5dbf10..80ba448 100644 (file)
@@ -214,6 +214,30 @@ wchar_to_utf8 (const wchar_t *string)
   return result;
 }
 
+
+/* Same as above, but only convert the first LEN wchars.  */
+char *
+wchar_to_utf8_2 (const wchar_t *string, size_t len)
+{
+  int n;
+  char *result;
+
+  /* Note, that CP_UTF8 is not defined in Windows versions earlier
+     than NT.*/
+  n = WideCharToMultiByte (CP_UTF8, 0, string, len, NULL, 0, NULL, NULL);
+  if (n < 0)
+    return NULL;
+
+  result = xmalloc (n+1);
+  n = WideCharToMultiByte (CP_UTF8, 0, string, len, result, n, NULL, NULL);
+  if (n < 0)
+    {
+      xfree (result);
+      return NULL;
+    }
+  return result;
+}
+
 /* Return a malloced wide char string from an UTF-8 encoded input
    string STRING.  Caller must xfree this value. On failure returns
    NULL; caller may use GetLastError to get the actual error number.
@@ -264,6 +288,37 @@ utf8_to_wchar2 (const char *string, size_t len)
 }
 
 
+/* Assume STRING is a Latin-1 encoded and convert it to utf-8.
+   Returns a newly malloced UTF-8 string. */
+char *
+latin1_to_utf8 (const char *string)
+{
+  const char *s;
+  char *buffer, *p;
+  size_t n;
+
+  for (s=string, n=0; *s; s++) 
+    {
+      n++;
+      if (*s & 0x80)
+        n++;
+    }
+  buffer = xmalloc (n + 1);
+  for (s=string, p=buffer; *s; s++)
+    {
+      if (*s & 0x80)
+        {
+          *p++ = 0xc0 | ((*s >> 6) & 3);
+          *p++ = 0x80 | (*s & 0x3f);
+        }
+      else
+        *p++ = *s;
+    }
+  *p = 0;
+  return buffer;
+}
+
+
 /* Strip off trailing white spaces from STRING.  Returns STRING. */
 char *
 trim_trailing_spaces (char *string)
index 164488b..42a0256 100644 (file)
@@ -98,6 +98,18 @@ find_message_window (HWND parent)
       HWND w;
       size_t len;
       const char *s;
+
+      /* OL 2003 SP1 German uses this class name for the main
+         inspector window.  We hope that no other windows uses this
+         class name.  As a fallback we keep on testing for PGP
+         strings, but this does not work for PGP/MIME or already
+         decrypted messages. */
+      len = GetClassName (child, buf, sizeof buf - 1);
+      if (len && !strcmp (buf, "RichEdit20W"))
+        {
+          log_debug ("found class RichEdit20W");
+          return child;
+        }
       
       memset (buf, 0, sizeof (buf));
       GetWindowText (child, buf, sizeof (buf)-1);
@@ -126,14 +138,29 @@ update_display (HWND hwnd, GpgMsg *msg, void *exchange_cb)
   window = find_message_window (hwnd);
   if (window)
     {
+      const char *string, *s;
+
       log_debug ("%s:%s: window handle %p\n", __FILE__, __func__, window);
-      SetWindowText (window, msg->getDisplayText ());
+      string = msg->getDisplayText ();
+      
+      /* Decide whether we need to use the Unicode version. */
+      for (s=string; *s && !(*s & 0x80); s++)
+        ;
+      if (*s)
+        {
+          wchar_t *tmp = utf8_to_wchar (string);
+          SetWindowTextW (window, tmp);
+          xfree (tmp);
+        }
+      else
+        SetWindowTextA (window, string);
       log_debug ("%s:%s: window text is now `%s'",
-                 __FILE__, __func__, msg->getDisplayText ());
+                 __FILE__, __func__, string);
       return 0;
     }
   else if (exchange_cb && !opt.compat.no_oom_write)
     {
+      log_debug ("updating display using OOM");
       return put_outlook_property (exchange_cb, "Body",
                                    msg->getDisplayText ());
     }
@@ -156,7 +183,7 @@ set_message_body (LPMESSAGE message, const char *string)
   //  BOOL dummy_bool;
   const char *s;
   
-  /* Decide whether we ned to use the Unicode version. */
+  /* Decide whether we need to use the Unicode version. */
   for (s=string; *s && !(*s & 0x80); s++)
     ;
   if (*s)
index e892586..37854d0 100644 (file)
@@ -1013,7 +1013,7 @@ GpgMsgImpl::decrypt (HWND hwnd)
       log_debug ("decrypt isHtml=%d\n", is_html);
 
       /* Do we really need to set the body?  update_display below
-         should be sufficient.  The problem witgh this is that we have
+         should be sufficient.  The problem with this is that we did
          changes in the MAPI and OL will later ask whether to save
          them.  The original reason for this kludge was to get the
          plaintext into the reply (by setting the property without
@@ -1233,19 +1233,16 @@ GpgMsgImpl::encrypt_and_sign (HWND hwnd, bool sign_flag)
     }
 
   /* Gather the keys for the recipients. */
-      TRACEPOINT();
   recipients = getRecipients ();
-      TRACEPOINT();
   if ( op_lookup_keys (recipients, &keys, &unknown) )
     {
       log_debug ("%s.%s: leave (lookup keys failed)\n", __FILE__, __func__);
       return gpg_error (GPG_ERR_GENERAL);  
     }
-      TRACEPOINT();
   n_recp = count_strings (recipients);
   n_keys = count_keys (keys);
   n_unknown = count_strings (unknown);
-      TRACEPOINT();
+
   
   log_debug ("%s:%s: found %d recipients, need %d, unknown=%d\n",
              __FILE__, __func__, (int)n_keys, (int)n_recp, (int)n_unknown);
index be9cc3e..c4bb5d4 100644 (file)
@@ -328,6 +328,7 @@ read_options (void)
   /* Note, that on purpose these flags are only Registry changeable.
      The format of the entry is a string of of "0" and "1" digits; see
      the switch below for a description. */
+  memset (&opt.compat, 0, sizeof opt.compat);
   load_extension_value ("compatFlags", &val);
   if (val)
     {
index 8bfc19d..0339aaf 100644 (file)
@@ -72,6 +72,13 @@ extern "C" {
 #define EECMDID_ToolsOptions                   136
 
 
+/* Flag values for IExchExtAttachedFileEvents::OpenSzFile. */
+#define EEAFE_OPEN         (0x00000001)
+#define EEAFE_PRINT       (0x00000002)
+#define EEAFE_QUICKVIEW           (0x00000003)
+
+
+
 /* GUIDs */
 DEFINE_GUID(GUID_NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
 
@@ -130,6 +137,9 @@ typedef IExchExtCallback *LPEXCHEXTCALLBACK;
 typedef struct IOutlookExtCallback IOutlookExtCallback;
 typedef IOutlookExtCallback *LPOUTLOOKEXTCALLBACK;
 
+typedef struct IExchExtAttachedFileEvents IExchExtAttachedFileEvents;
+typedef IExchExtAttachedFileEvents *LPEXCHEXTATTACHEDFILEEVENTS;
+
 /* The next classes are not yet defined. but if so they should go here. */
 typedef struct IExchExtModeless IExchExtModeless; 
 typedef IExchExtModeless *LPEXCHEXTMODELESS;
@@ -330,22 +340,19 @@ DECLARE_INTERFACE_(IOutlookExtCallback, IUnknown)
   STDMETHOD(GetOfficeCharacter)(void **ppmsotfc);
 };
 
-// Flag values for IExchExtAttachedFileEvents::OpenSzFile
-#define EEAFE_OPEN         (0x00000001)
-#define EEAFE_PRINT       (0x00000002)
-#define EEAFE_QUICKVIEW           (0x00000003)
 
-#undef INTERFACE
-#define INTERFACE   IExchExtAttachedFileEvents
 
+EXTERN_C const IID IID_IExchExtAttachedFileEvents;
+#undef INTERFACE
+#define INTERFACE  IExchExtAttachedFileEvents
 DECLARE_INTERFACE_(IExchExtAttachedFileEvents, IUnknown)
 {
-  // *** IUnknown methods ***
+  /*** IUnknown methods ***/
   STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR * lppvObj) PURE;
   STDMETHOD_(ULONG,AddRef) (THIS)  PURE;
   STDMETHOD_(ULONG,Release) (THIS) PURE;
   
-  // *** IExchExtAttachedFileEvents methods ***
+  /*** IExchExtAttachedFileEvents methods ***/
   STDMETHOD(OnReadPattFromSzFile)(THIS_ LPATTACH lpatt, LPTSTR lpszFile,
                                  ULONG ulFlags) PURE;
   STDMETHOD(OnWritePattToSzFile)(THIS_ LPATTACH lpatt, LPTSTR lpszFile,
@@ -354,9 +361,7 @@ DECLARE_INTERFACE_(IExchExtAttachedFileEvents, IUnknown)
   STDMETHOD(OnOpenPatt)(THIS_ LPATTACH lpatt) PURE;
   STDMETHOD(OnOpenSzFile)(THIS_ LPTSTR lpszFile, ULONG ulFlags) PURE;
 };
-typedef IExchExtAttachedFileEvents FAR * LPEXCHEXTATTACHEDFILEEVENTS;
 
-EXTERN_C const IID IID_IExchExtAttachedFileEvents;
 
 #ifdef __cplusplus
 }
index 1126f9e..5de2d31 100644 (file)
@@ -57,6 +57,9 @@ DEFINE_GUID(CLSID_GPGOL, 0x42d30988, 0x1a3a, 0x11da,
 
 bool g_initdll = FALSE;
 
+static HWND show_window_hierarchy (HWND parent, int level);
+
+
 /* Registers this module as an Exchange extension. This basically updates
    some Registry entries. */
 STDAPI 
@@ -484,8 +487,24 @@ CGPGExchExt::CGPGExchExt (void)
 /*  Uninitializes the DLL in the session context. */
 CGPGExchExt::~CGPGExchExt (void) 
 {
-  log_debug ("%s:%s: cleaning up CGPGExchExt object\n", __FILE__, __func__);
-
+  log_debug ("%s:%s: cleaning up CGPGExchExt object; "
+             "context=0x%lx (%s)\n", __FILE__, __func__, 
+             m_lContext,
+             (m_lContext == EECONTEXT_SESSION?           "Session":
+              m_lContext == EECONTEXT_VIEWER?            "Viewer":
+              m_lContext == EECONTEXT_REMOTEVIEWER?      "RemoteViewer":
+              m_lContext == EECONTEXT_SEARCHVIEWER?      "SearchViewer":
+              m_lContext == EECONTEXT_ADDRBOOK?          "AddrBook" :
+              m_lContext == EECONTEXT_SENDNOTEMESSAGE?   "SendNoteMessage" :
+              m_lContext == EECONTEXT_READNOTEMESSAGE?   "ReadNoteMessage" :
+              m_lContext == EECONTEXT_SENDPOSTMESSAGE?   "SendPostMessage" :
+              m_lContext == EECONTEXT_READPOSTMESSAGE?   "ReadPostMessage" :
+              m_lContext == EECONTEXT_READREPORTMESSAGE? "ReadReportMessage" :
+              m_lContext == EECONTEXT_SENDRESENDMESSAGE? "SendResendMessage" :
+              m_lContext == EECONTEXT_PROPERTYSHEETS?    "PropertySheets" :
+              m_lContext == EECONTEXT_ADVANCEDCRITERIA?  "AdvancedCriteria" :
+              m_lContext == EECONTEXT_TASK?              "Task" : ""));
+  
   if (m_lContext == EECONTEXT_SESSION)
     {
       if (g_initdll)
@@ -497,6 +516,7 @@ CGPGExchExt::~CGPGExchExt (void)
           log_debug ("%s:%s: DLL closed down\n", __FILE__, __func__);
        }       
     }
+
 }
 
 
@@ -656,6 +676,7 @@ CGPGExchExtMessageEvents::OnRead (LPEXCHEXTCALLBACK pEECB)
   show_mapi_property (pMessage, PR_CONVERSATION_INDEX,"PR_CONVERSATION_INDEX");
   ul_release (pMessage);
   ul_release (pMDB);
+
   return S_FALSE;
 }
 
@@ -689,7 +710,17 @@ CGPGExchExtMessageEvents::OnReadComplete (LPEXCHEXTCALLBACK pEECB,
       ul_release (pMessage);
       ul_release (pMDB);
     }
-  
+#if 0
+  else
+    {
+      HWND hWnd = NULL;
+
+      if (FAILED (pEECB->GetWindow (&hWnd)))
+        hWnd = NULL;
+      else
+        show_window_hierarchy (hWnd, 0);
+    }
+#endif
 
   return S_FALSE;
 }
@@ -921,10 +952,19 @@ show_window_hierarchy (HWND parent, int level)
   while (child)
     {
       char buf[1024+1];
+      char name[200];
+      int nname;
+      char *pname;
       
       memset (buf, 0, sizeof (buf));
       GetWindowText (child, buf, sizeof (buf)-1);
-      log_debug ("XXX %*shwnd=%p `%s'", level*2, "", child, buf);
+      nname = GetClassName (child, name, sizeof (name)-1);
+      if (nname)
+        pname = name;
+      else
+        pname = NULL;
+      log_debug ("XXX %*shwnd=%p (%s) `%s'", level*2, "", child,
+                 pname? pname:"", buf);
       show_window_hierarchy (child, level+1);
       child = GetNextWindow (child, GW_HWNDNEXT);      
     }
@@ -977,7 +1017,7 @@ CGPGExchExtCommands::InstallCommands (
 
   /* Outlook 2003 sometimes displays the plaintext sometimes the
      orginal undecrypted text when doing a Reply.  This seems to
-     depend on the sieze of the message; my guess it that only short
+     depend on the size of the message; my guess it that only short
      messages are locally saved in the process and larger ones are
      fetyched again from the backend - or the other way around.
      Anyway, we can't rely on that and thus me make sure to update the
@@ -1232,6 +1272,63 @@ CGPGExchExtCommands::DoCommand (
 {
   HRESULT hr;
 
+  log_debug ("%s:%s: commandID=%u (%#x)\n",
+             __FILE__, __func__, nCommandID, nCommandID);
+  if (nCommandID == SC_CLOSE && m_lContext == EECONTEXT_READNOTEMESSAGE)
+    {
+      /* This is the system close command. Replace it with our own to
+         avoid the "save changes" query, apparently induced by OL
+         internal syncronisation of our SetWindowText message with its
+         own OOM (in this case Body). */
+      LPDISPATCH pDisp;
+      DISPID dispid;
+      DISPPARAMS dispparams;
+      VARIANT aVariant;
+      
+      pDisp = find_outlook_property (pEECB, "Close", &dispid);
+      if (pDisp)
+        {
+          dispparams.rgvarg = &aVariant;
+          dispparams.rgvarg[0].vt = VT_INT;
+          dispparams.rgvarg[0].intVal = 1; /* olDiscard */
+          dispparams.cArgs = 1;
+          dispparams.cNamedArgs = 0;
+          hr = pDisp->Invoke (dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT,
+                              DISPATCH_METHOD, &dispparams,
+                              NULL, NULL, NULL);
+          pDisp->Release();
+          pDisp = NULL;
+          if (hr == S_OK)
+            {
+              log_debug ("%s:%s: invoking Close succeeded", __FILE__,__func__);
+              return S_OK; /* We handled the close command. */
+            }
+
+          log_debug ("%s:%s: invoking Close failed: %#lx",
+                     __FILE__, __func__, hr);
+        }
+
+      /* We are not interested in the close command - pass it on. */
+      return S_FALSE; 
+    }
+  else if (nCommandID == 154)
+    {
+      log_debug ("%s:%s: command Reply called\n", __FILE__, __func__);
+      /* What we might want to do is to call Reply, then GetInspector
+         and then Activate - this allows us to get full control over
+         the quoted message and avoids the ugly msgcache. */
+    }
+  else if (nCommandID == 155)
+    {
+      log_debug ("%s:%s: command ReplyAll called\n", __FILE__, __func__);
+    }
+  else if (nCommandID == 156)
+    {
+      log_debug ("%s:%s: command Forward called\n", __FILE__, __func__);
+    }
+  
+
+
   if ((nCommandID != m_nCmdEncrypt) 
       && (nCommandID != m_nCmdSign))
     return S_FALSE; 
@@ -1244,6 +1341,9 @@ CGPGExchExtCommands::DoCommand (
 
       if (FAILED (pEECB->GetWindow (&hWnd)))
         hWnd = NULL;
+//       else
+//         show_window_hierarchy (hWnd, 0);
+
       hr = pEECB->GetObject (&pMDB, (LPMAPIPROP *)&pMessage);
       if (SUCCEEDED (hr))
         {
@@ -1253,8 +1353,6 @@ CGPGExchExtCommands::DoCommand (
               m->setExchangeCallback ((void*)pEECB);
               m->decrypt (hWnd);
               delete m;
-//               log_debug ("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
-//               show_window_hierarchy (hWnd, 0);
            }
        }
       ul_release (pMessage);
@@ -1277,10 +1375,31 @@ CGPGExchExtCommands::DoCommand (
   return S_OK; 
 }
 
-
+/* Called by Exchange when it receives a WM_INITMENU message, allowing
+   the extension object to enable, disable, or update its menu
+   commands before the user sees them. This method is called
+   frequently and should be written in a very efficient manner. */
 STDMETHODIMP_(VOID) 
 CGPGExchExtCommands::InitMenu(LPEXCHEXTCALLBACK pEECB) 
 {
+#if 0
+  log_debug ("%s:%s: context=0x%lx (%s)\n", __FILE__, __func__, 
+             m_lContext,
+             (m_lContext == EECONTEXT_SESSION?           "Session"          :
+              m_lContext == EECONTEXT_VIEWER?            "Viewer"           :
+              m_lContext == EECONTEXT_REMOTEVIEWER?      "RemoteViewer"     :
+              m_lContext == EECONTEXT_SEARCHVIEWER?      "SearchViewer"     :
+              m_lContext == EECONTEXT_ADDRBOOK?          "AddrBook"         :
+              m_lContext == EECONTEXT_SENDNOTEMESSAGE?   "SendNoteMessage"  :
+              m_lContext == EECONTEXT_READNOTEMESSAGE?   "ReadNoteMessage"  :
+              m_lContext == EECONTEXT_SENDPOSTMESSAGE?   "SendPostMessage"  :
+              m_lContext == EECONTEXT_READPOSTMESSAGE?   "ReadPostMessage"  :
+              m_lContext == EECONTEXT_READREPORTMESSAGE? "ReadReportMessage":
+              m_lContext == EECONTEXT_SENDRESENDMESSAGE? "SendResendMessage":
+              m_lContext == EECONTEXT_PROPERTYSHEETS?    "PropertySheets"   :
+              m_lContext == EECONTEXT_ADVANCEDCRITERIA?  "AdvancedCriteria" :
+              m_lContext == EECONTEXT_TASK?              "Task" : ""));
+#endif
 }
 
 
index ddedbfc..254d9fb 100644 (file)
@@ -52,30 +52,37 @@ static char const allhexdigits[] = "1234567890ABCDEFabcdef";
 
 
 static void
-set_key_hint (struct decrypt_key_s * dec, HWND dlg, int ctrlid)
+set_key_hint (struct decrypt_key_s *dec, HWND dlg, int ctrlid)
 {
-    const char *s = dec->user_id;
-    char *key_hint;
-    char stop_char=0;
-    size_t i=0;
-
-    if (dec->user_id != NULL) {
-       key_hint = (char *)xmalloc (17 + strlen (dec->user_id) + 32);
-       if (strchr (s, '<') && strchr (s, '>'))
-           stop_char = '<';
-       else if (strchr (s, '(') && strchr (s, ')'))
-           stop_char = '(';
-       while (s && *s != stop_char)
-           key_hint[i++] = *s++;
-       key_hint[i++] = ' ';
-       sprintf (key_hint+i, "(0x%s)", dec->keyid+8);
+  const char *s = dec->user_id;
+  char *key_hint;
+  
+  if (s && dec->keyid) 
+    {
+      char stop_char;
+      size_t i = 0;
+
+      key_hint = xmalloc (17 + strlen (s) + strlen (dec->keyid) + 32);
+      if (strchr (s, '<') && strchr (s, '>'))
+        stop_char = '<';
+      else if (strchr (s, '(') && strchr (s, ')'))
+        stop_char = '(';
+      else
+        stop_char = 0;
+      while (*s != stop_char)
+        key_hint[i++] = *s++;
+      key_hint[i++] = ' ';
+      if (dec->keyid && strlen (dec->keyid) > 8)
+        sprintf (key_hint+i, "(0x%s)", dec->keyid+8);
+      else
+        key_hint[i] = 0;
     }
-    else
-       key_hint = xstrdup ("No key hint given.");
-    SendDlgItemMessage (dlg, ctrlid, CB_ADDSTRING, 0, 
-                       (LPARAM)(const char *)key_hint);
-    SendDlgItemMessage (dlg, ctrlid, CB_SETCURSEL, 0, 0);
-    xfree (key_hint);
+  else
+    key_hint = xstrdup ("No key hint given.");
+  SendDlgItemMessage (dlg, ctrlid, CB_ADDSTRING, 0, 
+                      (LPARAM)(const char *)key_hint);
+  SendDlgItemMessage (dlg, ctrlid, CB_SETCURSEL, 0, 0);
+  xfree (key_hint);
 }
 
 /* Release the key array ARRAY as well as all COUNT keys. */
@@ -200,12 +207,10 @@ load_secbox (HWND dlg, int ctlid)
   gpgme_key_t *keyarray;
   size_t keyarray_size;
 
-  TRACEPOINT();
   err = gpgme_new (&ctx);
   if (err)
     return NULL;
 
-  TRACEPOINT();
   err = gpgme_op_keylist_start (ctx, NULL, 1);
   if (err)
     {
@@ -214,7 +219,6 @@ load_secbox (HWND dlg, int ctlid)
       return NULL;
     }
 
-  TRACEPOINT();
   keyarray_size = 20; 
   keyarray = xcalloc (keyarray_size+1, sizeof *keyarray);
   pos = 0;
@@ -224,7 +228,6 @@ load_secbox (HWND dlg, int ctlid)
       const char *name, *email, *keyid, *algo;
       char *p;
       
-  TRACEPOINT();
       if (key->revoked || key->expired || key->disabled || key->invalid)
         {
           gpgme_key_release (key);
@@ -259,16 +262,13 @@ load_secbox (HWND dlg, int ctlid)
                          (LPARAM)(const char *) p);
       xfree (p);
 
-  TRACEPOINT();
       SendDlgItemMessage (dlg, ctlid, CB_SETITEMDATA, pos, (LPARAM)pos);
-  TRACEPOINT();
 
       if (pos >= keyarray_size)
         {
           gpgme_key_t *tmparr;
           size_t i;
 
-  TRACEPOINT();
           keyarray_size += 10;
           tmparr = xcalloc (keyarray_size, sizeof *tmparr);
           for (i=0; i < pos; i++)
@@ -277,13 +277,10 @@ load_secbox (HWND dlg, int ctlid)
           keyarray = tmparr;
         }
       keyarray[pos++] = key;
-  TRACEPOINT();
     }
 
-  TRACEPOINT();
   gpgme_op_keylist_end (ctx);
   gpgme_release (ctx);
-  TRACEPOINT();
   return keyarray;
 }
 
@@ -302,7 +299,6 @@ decrypt_key_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
       context = (struct dialog_context_s *)lparam;
       context->hide_state = 1;
       dec = context->dec;
-      TRACEPOINT();
       if (dec && context->use_as_cb) 
         {
           dec->opts = 0;
@@ -315,10 +311,8 @@ decrypt_key_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
                         (dec && dec->last_was_bad)?
                         _("Invalid passphrase; please try again..."):"");
 
-      TRACEPOINT();
       if (dec && !context->use_as_cb)
         context->keyarray = load_secbox (dlg, IDC_DEC_KEYLIST);
-      TRACEPOINT();
 
       CheckDlgButton (dlg, IDC_DEC_HIDE, BST_CHECKED);
       center_window (dlg, NULL);
@@ -534,16 +528,14 @@ signer_dialog_box (gpgme_key_t *r_key, char **r_passwd)
   struct dialog_context_s context; 
   struct decrypt_key_s dec;
   
-  TRACEPOINT();
   memset (&context, 0, sizeof context);
   memset (&dec, 0, sizeof dec);
   dec.hide_pwd = 1;
   context.dec = &dec;
   
-  TRACEPOINT();
   DialogBoxParam (glob_hinst, (LPCTSTR)IDD_DEC, GetDesktopWindow (),
                   decrypt_key_dlg_proc, (LPARAM)&context);
-  TRACEPOINT();
+
   if (dec.signer) 
     {
       if (r_passwd)
@@ -558,16 +550,12 @@ signer_dialog_box (gpgme_key_t *r_key, char **r_passwd)
       *r_key = dec.signer;
       dec.signer = NULL;
     }
-  TRACEPOINT();
   if (dec.pass)
     wipestring (dec.pass);
-  TRACEPOINT();
   xfree (dec.pass);
   if (dec.signer)
     gpgme_key_release (dec.signer);
-  TRACEPOINT();
   release_keyarray (context.keyarray);
-  TRACEPOINT();
   return (dec.opts & OPT_FLAG_CANCEL)? -1 : 0;
 }
 
index f139067..420a28b 100644 (file)
@@ -98,6 +98,7 @@ struct pgpmime_context
   int collect_attachment; /* True if we are collecting an attachment. */
   int is_qp_encoded;      /* Current part is QP encoded. */
   int is_base64_encoded;  /* Current part is base 64 encoded. */
+  int is_utf8;            /* Current part has charset utf-8. */
 
   int part_counter;       /* Counts the number of processed parts. */
   char *filename;         /* Current filename (malloced) or NULL. */
@@ -125,6 +126,41 @@ struct pgpmime_context
 typedef struct pgpmime_context *pgpmime_context_t;
 
 
+/* This function is a wrapper around gpgme_data_write to convert the
+   data to utf-8 first.  We assume Latin-1 here. */
+static int
+latin1_data_write (gpgme_data_t data, const char *line, size_t len)
+{
+  const char *s;
+  char *buffer, *p;
+  size_t i, n;
+  int rc;
+
+  for (s=line, i=0, n=0 ; i < len; s++, i++ ) 
+    {
+      n++;
+      if (*s & 0x80)
+        n++;
+    }
+  buffer = xmalloc (n + 1);
+  for (s=line, i=0, p=buffer; i < len; s++, i++ )
+    {
+      if (*s & 0x80)
+        {
+          *p++ = 0xc0 | ((*s >> 6) & 3);
+          *p++ = 0x80 | (*s & 0x3f);
+        }
+      else
+        *p++ = *s;
+    }
+  assert (p-buffer == n);
+  rc = gpgme_data_write (data, buffer, n);
+  xfree (buffer);
+  return rc;
+}
+
+
+
 /* Do in-place decoding of quoted-printable data of LENGTH in BUFFER.
    Returns the new length of the buffer. */
 static size_t
@@ -262,6 +298,7 @@ message_cb (void *opaque, rfc822parse_event_t event, rfc822parse_t msg)
       char *p;
       int is_text = 0;
 
+      ctx->is_utf8 = 0;
       field = rfc822parse_parse_field (msg, "Content-Type", -1);
       if (field)
         {
@@ -291,7 +328,11 @@ message_cb (void *opaque, rfc822parse_event_t event, rfc822parse_t msg)
                 }
 
             }
-          
+
+          s1 = rfc822parse_query_parameter (field, "charset", 0);
+          if (s1 && !strcmp (s1, "utf-8"))
+            ctx->is_utf8 = 1;
+
           rfc822parse_release_field (field);
         }
       else
@@ -474,7 +515,12 @@ plaintext_handler (void *handle, const void *buffer, size_t size)
                   else
                     len = pos;
                   if (len)
-                    gpgme_data_write (ctx->body, ctx->linebuf, len);
+                    {
+                      if (ctx->is_utf8)
+                        gpgme_data_write (ctx->body, ctx->linebuf, len);
+                      else
+                        latin1_data_write (ctx->body, ctx->linebuf, len);
+                    }
                   if (!ctx->is_base64_encoded)
                     gpgme_data_write (ctx->body, "\r\n", 2);
                 }
index d0ae465..8acd6f1 100644 (file)
@@ -56,8 +56,10 @@ void  xfree (void *p);
 void out_of_core (void);
 
 char *wchar_to_utf8 (const wchar_t *string);
+char *wchar_to_utf8_2 (const wchar_t *string, size_t len);
 wchar_t *utf8_to_wchar (const char *string);
 wchar_t *utf8_to_wchar2 (const char *string, size_t len);
+char *latin1_to_utf8 (const char *string);
 
 char *trim_trailing_spaces (char *string);