diff --git a/src/inspectors.cpp b/src/inspectors.cpp
index 626dc64..729a7e9 100644
--- a/src/inspectors.cpp
+++ b/src/inspectors.cpp
@@ -1,1110 +1,1113 @@
/* inspectors.cpp - Code to handle OOM Inspectors
* Copyright (C) 2009 g10 Code GmbH
*
* This file is part of GpgOL.
*
* GpgOL is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* GpgOL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, see .
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#include "common.h"
#include "oomhelp.h"
#include "myexchext.h"
#include "mapihelp.h"
#include "message.h"
#include "dialogs.h" /* IDB_xxx */
#include "cmdbarcontrols.h"
#include "eventsink.h"
#include "inspectors.h"
#include "mailitem.h"
#include "revert.h"
+#undef _
+#define _(a) utf8_gettext (a)
+
/* Event sink for an Inspectors collection object. */
BEGIN_EVENT_SINK(GpgolInspectorsEvents, IOOMInspectorsEvents)
STDMETHOD (NewInspector) (THIS_ LPOOMINSPECTOR);
EVENT_SINK_DEFAULT_CTOR(GpgolInspectorsEvents)
EVENT_SINK_DEFAULT_DTOR(GpgolInspectorsEvents)
EVENT_SINK_INVOKE(GpgolInspectorsEvents)
{
HRESULT hr;
(void)lcid; (void)riid; (void)result; (void)exepinfo; (void)argerr;
if (dispid == 0xf001 && (flags & DISPATCH_METHOD))
{
if (!parms)
hr = DISP_E_PARAMNOTOPTIONAL;
else if (parms->cArgs != 1)
hr = DISP_E_BADPARAMCOUNT;
else if (parms->rgvarg[0].vt != VT_DISPATCH)
hr = DISP_E_BADVARTYPE;
else
hr = NewInspector ((LPOOMINSPECTOR)parms->rgvarg[0].pdispVal);
}
else
hr = DISP_E_MEMBERNOTFOUND;
return hr;
}
END_EVENT_SINK(GpgolInspectorsEvents, IID_IOOMInspectorsEvents)
/* Event sink for an Inspector object. */
typedef struct GpgolInspectorEvents GpgolInspectorEvents;
typedef GpgolInspectorEvents *LPGPGOLINSPECTOREVENTS;
BEGIN_EVENT_SINK(GpgolInspectorEvents, IOOMInspectorEvents)
STDMETHOD_ (void, Activate) (THIS_);
STDMETHOD_ (void, Close) (THIS_);
STDMETHOD_ (void, Deactivate) (THIS_);
bool m_first_activate_seen;
EVENT_SINK_CTOR(GpgolInspectorEvents)
{
m_first_activate_seen = false;
}
EVENT_SINK_DEFAULT_DTOR(GpgolInspectorEvents)
EVENT_SINK_INVOKE(GpgolInspectorEvents)
{
HRESULT hr = S_OK;
(void)lcid; (void)riid; (void)result; (void)exepinfo; (void)argerr;
if ((dispid == 0xf001 || dispid == 0xf006 || dispid == 0xf008)
&& (flags & DISPATCH_METHOD))
{
if (!parms)
hr = DISP_E_PARAMNOTOPTIONAL;
else if (parms->cArgs != 0)
hr = DISP_E_BADPARAMCOUNT;
else if (dispid == 0xf001)
Activate ();
else if (dispid == 0xf006)
Deactivate ();
else if (dispid == 0xf008)
Close ();
}
else
hr = DISP_E_MEMBERNOTFOUND;
return hr;
}
END_EVENT_SINK(GpgolInspectorEvents, IID_IOOMInspectorEvents)
/* A linked list as a simple collection of button. */
struct button_list_s
{
struct button_list_s *next;
LPDISPATCH sink;
LPDISPATCH button;
int instid;
char tag[1]; /* Variable length string. */
};
typedef struct button_list_s *button_list_t;
/* To avoid messing around with the OOM (adding extra objects as user
properties and such), we keep our own information structure about
inspectors. */
struct inspector_info_s
{
/* We are pretty lame and keep all inspectors in a linked list. */
struct inspector_info_s *next;
/* The event sink object. This is used by the event methods to
locate the inspector object. */
LPGPGOLINSPECTOREVENTS eventsink;
/* The inspector object. */
LPOOMINSPECTOR inspector;
/* The Window handle of the inspector. */
HWND hwnd;
/* A list of all the buttons. */
button_list_t buttons;
};
typedef struct inspector_info_s *inspector_info_t;
/* The list of all inspectors and a lock for it. */
static inspector_info_t all_inspectors;
static HANDLE all_inspectors_lock;
static void add_inspector_controls (LPOOMINSPECTOR inspector);
static void update_crypto_info (LPDISPATCH inspector);
/* Initialize this module. Returns 0 on success. Called once by dllinit. */
int
initialize_inspectors (void)
{
SECURITY_ATTRIBUTES sa;
memset (&sa, 0, sizeof sa);
sa.bInheritHandle = FALSE;
sa.lpSecurityDescriptor = NULL;
sa.nLength = sizeof sa;
all_inspectors_lock = CreateMutex (&sa, FALSE, NULL);
return !all_inspectors_lock;
}
/* Acquire the all_inspectors_lock. No error is returned because we
can't do anything anyway. */
static void
lock_all_inspectors (void)
{
int ec = WaitForSingleObject (all_inspectors_lock, INFINITE);
if (ec != WAIT_OBJECT_0)
{
log_error ("%s:%s: waiting on mutex failed: ec=%#x\n",
SRCNAME, __func__, ec);
fatal_error ("%s:%s: waiting on mutex failed: ec=%#x\n",
SRCNAME, __func__, ec);
}
}
/* Release the all_inspectors_lock. No error is returned because this
is a fatal error anyway and there is no way to clean up. */
static void
unlock_all_inspectors (void)
{
if (!ReleaseMutex (all_inspectors_lock))
{
log_error_w32 (-1, "%s:%s: ReleaseMutex failed", SRCNAME, __func__);
fatal_error ("%s:%s: ReleaseMutex failed", SRCNAME, __func__);
}
}
/* Add SINK and BUTTON to the list at LISTADDR. The list takes
ownership of SINK and BUTTON, thus the caller may not use OBJ or
OBJ2 after this call. TAG must be given without the '#' marked
suffix. */
static void
move_to_button_list (button_list_t *listaddr,
LPDISPATCH sink, LPDISPATCH button, const char *tag)
{
button_list_t item;
int instid;
if (!tag)
tag = "";
instid = button? get_oom_int (button, "InstanceId"): 0;
log_debug ("%s:%s: sink=%p btn=%p tag=(%s) instid=%d",
SRCNAME, __func__, sink, button, tag, instid);
item = (button_list_t)xcalloc (1, sizeof *item + strlen (tag));
item->sink = sink;
item->button = button;
item->instid = instid;
strcpy (item->tag, tag);
item->next = *listaddr;
*listaddr = item;
}
static HWND
find_ole_window (LPOOMINSPECTOR inspector)
{
HRESULT hr;
LPOLEWINDOW olewndw = NULL;
HWND hwnd = NULL;
hr = inspector->QueryInterface (IID_IOleWindow, (void**)&olewndw);
if (hr != S_OK || !olewndw)
{
log_error ("%s:%s: IOleWindow not found: hr=%#lx", SRCNAME, __func__, hr);
return NULL;
}
hr = olewndw->GetWindow (&hwnd);
if (hr != S_OK || !hwnd)
{
log_error ("%s:%s: IOleWindow->GetWindow failed: hr=%#lx",
SRCNAME, __func__, hr);
hwnd = NULL;
}
olewndw->Release ();
log_debug ("%s:%s: inspector %p has hwnd=%p",
SRCNAME, __func__, inspector, hwnd);
return hwnd;
}
/* Register the inspector object INSPECTOR with its event SINK. */
static void
register_inspector (LPGPGOLINSPECTOREVENTS sink, LPOOMINSPECTOR inspector)
{
inspector_info_t item;
HWND hwnd;
log_debug ("%s:%s: Called (sink=%p, inspector=%p)",
SRCNAME, __func__, sink, inspector);
hwnd = find_ole_window (inspector);
item = (inspector_info_t)xcalloc (1, sizeof *item);
lock_all_inspectors ();
sink->AddRef ();
item->eventsink = sink;
inspector->AddRef ();
item->inspector = inspector;
item->hwnd = hwnd;
item->next = all_inspectors;
all_inspectors = item;
unlock_all_inspectors ();
}
/* Deregister the inspector with the event SINK. */
static void
deregister_inspector (LPGPGOLINSPECTOREVENTS sink)
{
inspector_info_t r, rprev;
button_list_t ol, ol2;
log_debug ("%s:%s: Called (sink=%p)", SRCNAME, __func__, sink);
if (!sink)
return;
lock_all_inspectors ();
for (r = all_inspectors, rprev = NULL; r; rprev = r, r = r->next)
if (r->eventsink == sink)
{
if (!rprev)
all_inspectors = r->next;
else
rprev->next = r->next;
r->next = NULL;
break;
}
unlock_all_inspectors ();
if (!r)
{
log_error ("%s:%s: inspector not registered", SRCNAME, __func__);
return;
}
detach_GpgolInspectorEvents_sink (r->eventsink);
for (ol = r->buttons; ol; ol = ol2)
{
ol2 = ol->next;
if (ol->sink)
{
detach_GpgolCommandBarButtonEvents_sink (ol->sink);
ol->sink->Release ();
}
if (ol->button)
{
del_oom_button (ol->button);
ol->button->Release ();
}
xfree (ol);
}
r->inspector->Release ();
r->eventsink->Release ();
xfree (r);
}
/* Return the inspector info for INSPECTOR. On success the
ALL_INSPECTORS list is locked and thus the caller should call
unlock_all_inspectors as soon as possible. On error NULL is
returned and the caller must *not* call unlock_all_inspectors. */
static inspector_info_t
get_inspector_info (LPOOMINSPECTOR inspector)
{
inspector_info_t r;
if (!inspector)
return NULL;
lock_all_inspectors ();
for (r = all_inspectors; r; r = r->next)
if (r->inspector == inspector)
return r;
unlock_all_inspectors ();
return NULL;
}
/* Return the button with TAG and assigned to INSPECTOR. TAG must be
given without the suffix. Returns NULL if not found. */
static LPDISPATCH
get_button (LPDISPATCH inspector, const char *tag)
{
LPDISPATCH result = NULL;
inspector_info_t iinfo;
button_list_t ol;
lock_all_inspectors ();
for (iinfo = all_inspectors; iinfo; iinfo = iinfo->next)
if (iinfo->inspector == inspector)
{
for (ol = iinfo->buttons; ol; ol = ol->next)
if (ol->tag && !strcmp (ol->tag, tag))
{
result = ol->button;
if (result)
result->AddRef ();
break;
}
break;
}
unlock_all_inspectors ();
return result;
}
/* Search through all objects and find the inspector which has a
button with the instance id INSTID. Returns NULL if not found. */
static LPDISPATCH
get_inspector_from_instid (int instid)
{
LPDISPATCH result = NULL;
inspector_info_t iinfo;
button_list_t ol;
lock_all_inspectors ();
for (iinfo = all_inspectors; iinfo; iinfo = iinfo->next)
for (ol = iinfo->buttons; ol; ol = ol->next)
if (ol->instid == instid)
{
result = iinfo->inspector;
if (result)
result->AddRef ();
break;
}
unlock_all_inspectors ();
return result;
}
/* Search through all objects and find the inspector which has a
the window handle HWND. Returns NULL if not found. */
LPDISPATCH
get_inspector_from_hwnd (HWND hwnd)
{
LPDISPATCH result = NULL;
inspector_info_t iinfo;
lock_all_inspectors ();
for (iinfo = all_inspectors; iinfo; iinfo = iinfo->next)
if (iinfo->hwnd == hwnd)
{
result = iinfo->inspector;
if (result)
result->AddRef ();
break;
}
unlock_all_inspectors ();
return result;
}
/* The method called by outlook for each new inspector. Note that
Outlook sometimes reuses Inspectro objects thus this event is not
an indication for a newly opened Inspector. */
STDMETHODIMP
GpgolInspectorsEvents::NewInspector (LPOOMINSPECTOR inspector)
{
LPDISPATCH obj;
log_debug ("%s:%s: Called (this=%p, inspector=%p)",
SRCNAME, __func__, this, inspector);
/* It has been said that INSPECTOR here a "weak" reference. This may
mean that the object has not been fully initialized. So better
take some care here and also take an additional reference. */
inspector->AddRef ();
obj = install_GpgolInspectorEvents_sink ((LPDISPATCH)inspector);
if (obj)
{
register_inspector ((LPGPGOLINSPECTOREVENTS)obj, inspector);
obj->Release ();
}
inspector->Release ();
return S_OK;
}
/* The method is called by an inspector before closing. */
STDMETHODIMP_(void)
GpgolInspectorEvents::Close (void)
{
log_debug ("%s:%s: Called (this=%p)", SRCNAME, __func__, this );
/* Deregister the inspector. */
deregister_inspector (this);
/* We don't release ourself because we already dropped the initial
reference after doing a register_inspector. */
}
/* The method called by an inspector on activation. */
STDMETHODIMP_(void)
GpgolInspectorEvents::Activate (void)
{
LPOOMINSPECTOR inspector;
LPDISPATCH obj;
log_debug ("%s:%s: Called (this=%p, inspector=%p)",
SRCNAME, __func__, this, m_object);
/* Note: It is easier to use the registered inspector object than to
find the inspector object in the ALL_INSPECTORS list. The
ALL_INSPECTORS list primarly useful to keep track of additional
information, not directly related to the event sink. */
if (!m_object)
{
log_error ("%s:%s: Object not set", SRCNAME, __func__);
return;
}
inspector = (LPOOMINSPECTOR)m_object;
inspector->AddRef ();
/* If this is the first activate for the inspector, we add the
controls. We do it only now to be sure that everything has been
initialized. Doing that in GpgolInspectorsEvents::NewInspector
is not suggested due to claims from some mailing lists. */
if (!m_first_activate_seen)
{
m_first_activate_seen = true;
add_inspector_controls (inspector);
obj = get_oom_object (inspector, "get_CurrentItem");
if (obj)
{
// LPDISPATCH obj2 = install_GpgolItemEvents_sink (obj);
// if (obj2)
// obj2->Release ();
obj->Release ();
}
}
update_crypto_info (inspector);
inspector->Release ();
}
/* The method called by an inspector on dectivation. */
STDMETHODIMP_(void)
GpgolInspectorEvents::Deactivate (void)
{
log_debug ("%s:%s: Called (this=%p)", SRCNAME, __func__, this);
}
/* Check whether we are in composer or read mode. */
static bool
is_inspector_in_composer_mode (LPDISPATCH inspector)
{
LPDISPATCH obj;
bool in_composer;
obj = get_oom_object (inspector, "get_CurrentItem");
if (obj)
{
/* We are in composer mode if the "Sent" property is false and
the class is 43. */
in_composer = (!get_oom_bool (obj, "Sent")
&& get_oom_int (obj, "Class") == 43);
obj->Release ();
}
else
in_composer = false;
return in_composer;
}
/* Get the flags from the inspector; i.e. whether to sign or encrypt a
message. Returns 0 on success. */
int
get_inspector_composer_flags (LPDISPATCH inspector,
bool *r_sign, bool *r_encrypt)
{
LPDISPATCH button;
int rc = 0;
button = get_button (inspector, "GpgOL_Inspector_Sign");
if (!button)
{
log_error ("%s:%s: Sign button not found", SRCNAME, __func__);
rc = -1;
}
else
{
*r_sign = get_oom_int (button, "State") == msoButtonDown;
button->Release ();
}
button = get_button (inspector, "GpgOL_Inspector_Encrypt");
if (!button)
{
log_error ("%s:%s: Encrypt button not found", SRCNAME, __func__);
rc = -1;
}
else
{
*r_encrypt = get_oom_int (button, "State") == msoButtonDown;
button->Release ();
}
if (!rc)
log_debug ("%s:%s: sign=%d encrypt=%d",
SRCNAME, __func__, *r_sign, *r_encrypt);
return rc;
}
static int
set_one_button (LPDISPATCH inspector, const char *tag, bool down)
{
LPDISPATCH button;
int rc = 0;
button = get_button (inspector, tag);
if (!button)
{
log_error ("%s:%s: `%s' not found", SRCNAME, __func__, tag);
rc = -1;
}
else
{
if (put_oom_int (button, "State", down? msoButtonDown : msoButtonUp))
rc = -1;
button->Release ();
}
return rc;
}
/* Set the flags for the inspector; i.e. whether to sign or encrypt a
message. Returns 0 on success. */
int
set_inspector_composer_flags (LPDISPATCH inspector, bool sign, bool encrypt)
{
int rc = 0;
if (set_one_button (inspector, "GpgOL_Inspector_Sign", sign))
rc = -1;
if (set_one_button (inspector, "GpgOL_Inspector_Sign@t", sign))
rc = -1;
if (set_one_button (inspector, "GpgOL_Inspector_Encrypt", encrypt))
rc = -1;
if (set_one_button (inspector, "GpgOL_Inspector_Encrypt@t", encrypt))
rc = -1;
return rc;
}
/* Helper to make the tag unique. */
static const char *
add_tag (LPDISPATCH control, const char *value)
{
int instid;
char buf[256];
instid = get_oom_int (control, "InstanceId");
snprintf (buf, sizeof buf, "%s#%d", value, instid);
put_oom_string (control, "Tag", buf);
return value;
}
/* Add all the controls. */
static void
add_inspector_controls (LPOOMINSPECTOR inspector)
{
static
LPDISPATCH obj, controls, button;
inspector_info_t inspinfo;
button_list_t buttonlist = NULL;
const char *tag;
int in_composer;
log_debug ("%s:%s: Enter", SRCNAME, __func__);
/* Check whether we are in composer or read mode. */
in_composer = is_inspector_in_composer_mode (inspector);
/* Add buttons to the Format menu but only in composer mode. */
if (in_composer)
{
controls = get_oom_object
(inspector, "CommandBars.FindControl(,30006).get_Controls");
if (!controls)
log_debug ("%s:%s: Menu Popup Format not found\n", SRCNAME, __func__);
else
{
button = opt.disable_gpgol? NULL : add_oom_button (controls);
if (button)
{
tag = add_tag (button, "GpgOL_Inspector_Encrypt");
put_oom_bool (button, "BeginGroup", true);
put_oom_int (button, "Style", msoButtonIconAndCaption );
put_oom_string (button, "Caption",
_("&encrypt message with GnuPG"));
put_oom_icon (button, IDB_ENCRYPT_16, 16);
put_oom_int (button, "State",
opt.encrypt_default? msoButtonDown: msoButtonUp);
obj = install_GpgolCommandBarButtonEvents_sink (button);
move_to_button_list (&buttonlist, obj, button, tag);
}
button = opt.disable_gpgol? NULL : add_oom_button (controls);
if (button)
{
tag = add_tag (button, "GpgOL_Inspector_Sign");
put_oom_int (button, "Style", msoButtonIconAndCaption );
put_oom_string (button, "Caption", _("&sign message with GnuPG"));
put_oom_icon (button, IDB_SIGN_16, 16);
put_oom_int (button, "State",
opt.sign_default? msoButtonDown: msoButtonUp);
obj = install_GpgolCommandBarButtonEvents_sink (button);
move_to_button_list (&buttonlist, obj, button, tag);
}
controls->Release ();
}
}
/* Add buttons to the Extra menu. */
controls = get_oom_object (inspector,
"CommandBars.FindControl(,30007).get_Controls");
if (!controls)
log_debug ("%s:%s: Menu Popup Extras not found\n", SRCNAME, __func__);
else
{
button = in_composer? NULL : add_oom_button (controls);
if (button)
{
tag = add_tag (button, "GpgOL_Inspector_Verify");
put_oom_int (button, "Style", msoButtonIconAndCaption );
put_oom_string (button, "Caption", _("GpgOL Decrypt/Verify"));
put_oom_icon (button, IDB_DECRYPT_VERIFY_16, 16);
obj = install_GpgolCommandBarButtonEvents_sink (button);
move_to_button_list (&buttonlist, obj, button, tag);
}
button = opt.enable_debug? add_oom_button (controls) : NULL;
if (button)
{
tag = add_tag (button, "GpgOL_Inspector_Debug-0");
put_oom_int (button, "Style", msoButtonCaption );
put_oom_string (button, "Caption",
"GpgOL Debug-0 (display crypto info)");
obj = install_GpgolCommandBarButtonEvents_sink (button);
move_to_button_list (&buttonlist, obj, button, tag);
}
button = opt.enable_debug? add_oom_button (controls) : NULL;
if (button)
{
tag = add_tag (button, "GpgOL_Inspector_Debug-1");
put_oom_int (button, "Style", msoButtonCaption );
put_oom_string (button, "Caption",
"GpgOL Debug-1 (not used)");
obj = install_GpgolCommandBarButtonEvents_sink (button);
move_to_button_list (&buttonlist, obj, button, tag);
}
button = opt.enable_debug? add_oom_button (controls) : NULL;
if (button)
{
tag = add_tag (button, "GpgOL_Inspector_Debug-2");
put_oom_int (button, "Style", msoButtonCaption );
put_oom_string (button, "Caption",
"GpgOL Debug-2 (change message class)");
obj = install_GpgolCommandBarButtonEvents_sink (button);
move_to_button_list (&buttonlist, obj, button, tag);
}
controls->Release ();
}
/* Create the toolbar buttons. */
controls = get_oom_object (inspector,
"CommandBars.Item(Standard).get_Controls");
if (!controls)
log_error ("%s:%s: CommandBar \"Standard\" not found\n",
SRCNAME, __func__);
else
{
button = (opt.disable_gpgol || !in_composer
? NULL : add_oom_button (controls));
if (button)
{
tag = add_tag (button, "GpgOL_Inspector_Encrypt@t");
put_oom_int (button, "Style", msoButtonIcon );
put_oom_string (button, "Caption", _("Encrypt message with GnuPG"));
put_oom_icon (button, IDB_ENCRYPT_16, 16);
put_oom_int (button, "State", msoButtonMixed );
put_oom_int (button, "State",
opt.encrypt_default? msoButtonDown: msoButtonUp);
obj = install_GpgolCommandBarButtonEvents_sink (button);
move_to_button_list (&buttonlist, obj, button, tag);
}
button = (opt.disable_gpgol || !in_composer
? NULL : add_oom_button (controls));
if (button)
{
tag = add_tag (button, "GpgOL_Inspector_Sign@t");
put_oom_int (button, "Style", msoButtonIcon);
put_oom_string (button, "Caption", _("Sign message with GnuPG"));
put_oom_icon (button, IDB_SIGN_16, 16);
put_oom_int (button, "State", msoButtonDown);
put_oom_int (button, "State",
opt.sign_default? msoButtonDown: msoButtonUp);
obj = install_GpgolCommandBarButtonEvents_sink (button);
move_to_button_list (&buttonlist, obj, button, tag);
}
button = in_composer? NULL : add_oom_button (controls);
if (button)
{
tag = add_tag (button, "GpgOL_Inspector_Crypto_Info");
put_oom_int (button, "Style", msoButtonIcon);
obj = install_GpgolCommandBarButtonEvents_sink (button);
move_to_button_list (&buttonlist, obj, button, tag);
}
controls->Release ();
}
/* Save the buttonlist. */
inspinfo = get_inspector_info (inspector);
if (inspinfo)
{
inspinfo->buttons = buttonlist;
unlock_all_inspectors ();
}
else
{
button_list_t ol, ol2;
log_error ("%s:%s: inspector not registered", SRCNAME, __func__);
for (ol = buttonlist; ol; ol = ol2)
{
ol2 = ol->next;
if (ol->sink)
ol->sink->Release ();
if (ol->button)
ol->button->Release ();
xfree (ol);
}
}
log_debug ("%s:%s: Leave", SRCNAME, __func__);
}
/* Update the crypto info icon. */
static void
update_crypto_info (LPDISPATCH inspector)
{
HRESULT hr;
LPDISPATCH button;
const char *tooltip = "";
int iconrc = -1;
button = get_button (inspector, "GpgOL_Inspector_Crypto_Info");
if (!button)
{
log_error ("%s:%s: Crypto Info button not found", SRCNAME, __func__);
return;
}
if (!is_inspector_in_composer_mode (inspector))
{
LPDISPATCH obj;
LPUNKNOWN unknown;
LPMESSAGE message = NULL;
obj = get_oom_object (inspector, "get_CurrentItem");
if (obj)
{
unknown = get_oom_iunknown (obj, "MAPIOBJECT");
if (!unknown)
log_error ("%s:%s: error getting MAPI object", SRCNAME, __func__);
else
{
hr = unknown->QueryInterface (IID_IMessage, (void**)&message);
if (hr != S_OK || !message)
{
message = NULL;
log_error ("%s:%s: error getting IMESSAGE: hr=%#lx",
SRCNAME, __func__, hr);
}
unknown->Release ();
}
obj->Release ();
}
if (message)
{
int is_encrypted = 0;
int is_signed = 0;
switch (mapi_get_message_type (message))
{
case MSGTYPE_GPGOL_MULTIPART_ENCRYPTED:
case MSGTYPE_GPGOL_OPAQUE_ENCRYPTED:
case MSGTYPE_GPGOL_PGP_MESSAGE:
is_encrypted = 1;
if ( mapi_test_sig_status (message) )
is_signed = 1;
break;
case MSGTYPE_GPGOL:
case MSGTYPE_SMIME:
case MSGTYPE_UNKNOWN:
break;
default:
is_signed = 1;
break;
}
if (is_signed && is_encrypted)
{
tooltip = _("This is a signed and encrypted message.\n"
"Click for more information. ");
iconrc = IDB_DECRYPT_VERIFY_16;
}
else if (is_signed)
{
tooltip = _("This is a signed message.\n"
"Click for more information. ");
iconrc = IDB_VERIFY_16;
}
else if (is_encrypted)
{
tooltip = _("This is an encrypted message.\n"
"Click for more information. ");
iconrc = IDB_DECRYPT_16;
}
message->Release ();
}
}
put_oom_string (button, "TooltipText", tooltip);
if (iconrc != -1)
put_oom_icon (button, iconrc, 16);
put_oom_bool (button, "Visible", (iconrc != -1));
button->Release ();
}
/* Return the MAPI message object of then inspector from a button's
instance id. */
static LPMESSAGE
get_message_from_button (unsigned long instid, LPDISPATCH *r_inspector)
{
HRESULT hr;
LPDISPATCH inspector, obj;
LPUNKNOWN unknown;
LPMESSAGE message = NULL;
if (r_inspector)
*r_inspector = NULL;
inspector = get_inspector_from_instid (instid);
if (inspector)
{
obj = get_oom_object (inspector, "get_CurrentItem");
if (!obj)
log_error ("%s:%s: error getting CurrentItem", SRCNAME, __func__);
else
{
unknown = get_oom_iunknown (obj, "MAPIOBJECT");
if (!unknown)
log_error ("%s:%s: error getting MAPI object", SRCNAME, __func__);
else
{
hr = unknown->QueryInterface (IID_IMessage, (void**)&message);
if (hr != S_OK || !message)
{
message = NULL;
log_error ("%s:%s: error getting IMESSAGE: hr=%#lx",
SRCNAME, __func__, hr);
}
unknown->Release ();
}
obj->Release ();
}
if (r_inspector)
*r_inspector = inspector;
else
inspector->Release ();
}
return message;
}
/* Toggle a button and return the new state. */
static void
toggle_button (LPDISPATCH button, const char *tag, int instid)
{
int state;
char tag2[256];
char *p;
LPDISPATCH inspector;
inspector = get_inspector_from_instid (instid);
if (!inspector)
{
log_debug ("%s:%s: inspector not found", SRCNAME, __func__);
return;
}
state = get_oom_int (button, "State");
log_debug ("%s:%s: button `%s' state is %d", SRCNAME, __func__, tag, state);
state = (state == msoButtonUp)? msoButtonDown : msoButtonUp;
put_oom_int (button, "State", state);
/* Toggle the other button. */
mem2str (tag2, tag, sizeof tag2 - 2);
p = strchr (tag2, '#');
if (p)
*p = 0; /* Strip the instance id suffix. */
if (*tag2 && tag2[1] && !strcmp (tag2+strlen(tag2)-2, "@t"))
tag2[strlen(tag2)-2] = 0; /* Remove the "@t". */
else
strcat (tag2, "@t"); /* Append a "@t". */
log_debug ("%s:%s: setting `%s' state to %d", SRCNAME, __func__, tag2, state);
set_one_button (inspector, tag2, state);
inspector->Release ();
}
/* Called for a click on an inspector button. BUTTON is the button
object and TAG is the tag value (which is guaranteed not to be
NULL). INSTID is the instance ID of the button. */
void
proc_inspector_button_click (LPDISPATCH button, const char *tag, int instid)
{
LPMESSAGE message;
HWND hwnd = NULL; /* Fixme */
if (!tagcmp (tag, "GpgOL_Inspector_Encrypt"))
{
toggle_button (button, tag, instid);
}
else if (!tagcmp (tag, "GpgOL_Inspector_Sign"))
{
toggle_button (button, tag, instid);
}
else if (!tagcmp (tag, "GpgOL_Inspector_Verify")
|| !tagcmp (tag, "GpgOL_Inspector_Crypto_Info"))
{
LPDISPATCH inspector;
message = get_message_from_button (instid, &inspector);
if (message)
{
if (message_incoming_handler (message, hwnd, true))
message_display_handler (message, inspector, hwnd);
message->Release ();
}
if (inspector)
{
update_crypto_info (inspector);
inspector->Release ();
}
}
else if (!tagcmp (tag, "GpgOL_Inspector_Debug-0"))
{
log_debug ("%s:%s: command Debug0 (showInfo) called\n",
SRCNAME, __func__);
message = get_message_from_button (instid, NULL);
if (message)
{
message_show_info (message, hwnd);
message->Release ();
}
}
else if (!tagcmp (tag, "GpgOL_Inspector_Debug-1"))
{
log_debug ("%s:%s: command Debug1 (not used) called\n",
SRCNAME, __func__);
}
else if (!tagcmp (tag, "GpgOL_Inspector_Debug-2"))
{
log_debug ("%s:%s: command Debug2 (change message class) called",
SRCNAME, __func__);
message = get_message_from_button (instid, NULL);
if (message)
{
/* We sync here. */
mapi_change_message_class (message, 1);
message->Release ();
}
}
else if (!tagcmp (tag, "GpgOL_Inspector_Debug-3"))
{
log_debug ("%s:%s: command Debug3 (revert_message_class) called",
SRCNAME, __func__);
message = get_message_from_button (instid, NULL);
if (message)
{
int rc = gpgol_message_revert (message, 1,
KEEP_OPEN_READWRITE|FORCE_SAVE);
log_debug ("%s:%s: gpgol_message_revert returns %d\n",
SRCNAME, __func__, rc);
message->Release ();
}
}
}