Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F22067870
ext-commands.cpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
27 KB
Subscribers
None
ext-commands.cpp
View Options
/* ext-commands.cpp - Subclass impl of IExchExtCommands
* Copyright (C) 2004, 2005, 2007, 2008 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 <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include
<config.h>
#endif
#define _WIN32_IE 0x400
/* Need TBIF_COMMAND et al. */
#include
<windows.h>
#include
"mymapi.h"
#include
"mymapitags.h"
#include
"myexchext.h"
#include
"common.h"
#include
"display.h"
#include
"msgcache.h"
#include
"mapihelp.h"
#include
"dialogs.h"
/* For IDB_foo. */
#include
"olflange-def.h"
#include
"olflange.h"
#include
"ol-ext-callback.h"
#include
"message.h"
#include
"engine.h"
#include
"ext-commands.h"
#include
"revert.h"
#include
"explorers.h"
#define TRACEPOINT() do { log_debug ("%s:%s:%d: tracepoint\n", \
SRCNAME, __func__, __LINE__); \
} while (0)
/* An object to store information about active (installed) toolbar
buttons. */
struct
toolbar_info_s
{
toolbar_info_t
next
;
UINT
button_id
;
/* The ID of the button as assigned by Outlook. */
UINT
bitmap
;
/* The bitmap of the button. */
UINT
cmd_id
;
/* The ID of the command to send on a click. */
const
char
*
desc
;
/* The description text. */
ULONG
context
;
/* Context under which this entry will be used. */
int
did_qbi
;
/* Has been processed by QueryButtonInfo. */
};
/* Keep copies of some bitmaps. */
static
int
bitmaps_initialized
;
static
HBITMAP
my_check_bitmap
,
my_uncheck_bitmap
;
static
void
add_menu
(
LPEXCHEXTCALLBACK
eecb
,
UINT
FAR
*
pnCommandIDBase
,
...)
#if __GNUC__ >= 4
__attribute__
((
sentinel
))
#endif
;
/* Wrapper around UlRelease with error checking. */
static
void
ul_release
(
LPVOID
punk
,
const
char
*
func
,
int
lnr
)
{
ULONG
res
;
if
(
!
punk
)
return
;
res
=
UlRelease
(
punk
);
if
(
opt
.
enable_debug
&
DBG_MEMORY
)
log_debug
(
"%s:%s:%d: UlRelease(%p) had %lu references
\n
"
,
SRCNAME
,
func
,
lnr
,
punk
,
res
);
}
/* Constructor */
GpgolExtCommands
::
GpgolExtCommands
(
GpgolExt
*
pParentInterface
)
{
m_pExchExt
=
pParentInterface
;
m_lRef
=
0
;
m_lContext
=
0
;
m_nCmdProtoAuto
=
0
;
m_nCmdProtoPgpmime
=
0
;
m_nCmdProtoSmime
=
0
;
m_nCmdEncrypt
=
0
;
m_nCmdSign
=
0
;
m_nCmdRevertFolder
=
0
;
m_nCmdDebug0
=
0
;
m_nCmdDebug1
=
0
;
m_nCmdDebug2
=
0
;
m_nCmdDebug3
=
0
;
m_toolbar_info
=
NULL
;
m_hWnd
=
NULL
;
if
(
!
bitmaps_initialized
)
{
my_uncheck_bitmap
=
get_system_check_bitmap
(
0
);
my_check_bitmap
=
get_system_check_bitmap
(
1
);
bitmaps_initialized
=
1
;
}
}
/* Destructor */
GpgolExtCommands
::~
GpgolExtCommands
(
void
)
{
while
(
m_toolbar_info
)
{
toolbar_info_t
tmp
=
m_toolbar_info
->
next
;
xfree
(
m_toolbar_info
);
m_toolbar_info
=
tmp
;
}
}
STDMETHODIMP
GpgolExtCommands
::
QueryInterface
(
REFIID
riid
,
LPVOID
FAR
*
ppvObj
)
{
*
ppvObj
=
NULL
;
if
((
riid
==
IID_IExchExtCommands
)
||
(
riid
==
IID_IUnknown
))
{
*
ppvObj
=
(
LPVOID
)
this
;
AddRef
();
return
S_OK
;
}
return
E_NOINTERFACE
;
}
/* Add a new menu. The variable entries are made up of pairs of
strings and UINT *. A NULL is used to terminate this list. An
empty string is translated to a separator menu item. One level of
submenus are supported. */
static
void
add_menu
(
LPEXCHEXTCALLBACK
eecb
,
UINT
FAR
*
pnCommandIDBase
,
...)
{
va_list
arg_ptr
;
HMENU
mainmenu
,
submenu
,
menu
;
const
char
*
string
;
UINT
*
cmdptr
;
va_start
(
arg_ptr
,
pnCommandIDBase
);
/* We put all new entries into the tools menu. To make this work we
need to pass the id of an existing item from that menu. */
eecb
->
GetMenuPos
(
EECMDID_ToolsCustomizeToolbar
,
&
mainmenu
,
NULL
,
NULL
,
0
);
menu
=
mainmenu
;
submenu
=
NULL
;
while
(
(
string
=
va_arg
(
arg_ptr
,
const
char
*
))
)
{
cmdptr
=
va_arg
(
arg_ptr
,
UINT
*
);
if
(
!*
string
)
;
/* Ignore this entry. */
else
if
(
*
string
==
'@'
&&
!
string
[
1
])
AppendMenu
(
menu
,
MF_SEPARATOR
,
0
,
NULL
);
else
if
(
*
string
==
'>'
)
{
submenu
=
CreatePopupMenu
();
AppendMenu
(
menu
,
MF_STRING
|
MF_POPUP
,
(
UINT_PTR
)
submenu
,
string
+
1
);
menu
=
submenu
;
}
else
if
(
*
string
==
'<'
)
{
menu
=
mainmenu
;
submenu
=
NULL
;
}
else
{
AppendMenu
(
menu
,
MF_STRING
,
*
pnCommandIDBase
,
string
);
if
(
menu
==
submenu
)
SetMenuItemBitmaps
(
menu
,
*
pnCommandIDBase
,
MF_BYCOMMAND
,
my_uncheck_bitmap
,
my_check_bitmap
);
if
(
cmdptr
)
*
cmdptr
=
*
pnCommandIDBase
;
(
*
pnCommandIDBase
)
++
;
}
}
va_end
(
arg_ptr
);
}
static
void
check_menu
(
LPEXCHEXTCALLBACK
eecb
,
UINT
menu_id
,
int
checked
)
{
HMENU
menu
;
eecb
->
GetMenuPos
(
EECMDID_ToolsCustomizeToolbar
,
&
menu
,
NULL
,
NULL
,
0
);
if
(
debug_commands
)
log_debug
(
"check_menu: eecb=%p menu_id=%u checked=%d -> menu=%p
\n
"
,
eecb
,
menu_id
,
checked
,
menu
);
CheckMenuItem
(
menu
,
menu_id
,
MF_BYCOMMAND
|
(
checked
?
MF_CHECKED
:
MF_UNCHECKED
));
}
void
GpgolExtCommands
::
add_toolbar
(
LPTBENTRY
tbearr
,
UINT
n_tbearr
,
...)
{
va_list
arg_ptr
;
const
char
*
desc
;
UINT
bmapid
;
UINT
cmdid
;
int
tbeidx
;
toolbar_info_t
tb_info
;
int
rc
;
for
(
tbeidx
=
n_tbearr
-1
;
tbeidx
>
-1
;
tbeidx
--
)
if
(
tbearr
[
tbeidx
].
tbid
==
EETBID_STANDARD
)
break
;
if
(
!
(
tbeidx
>
-1
))
{
log_error
(
"standard toolbar not found"
);
return
;
}
SendMessage
(
tbearr
[
tbeidx
].
hwnd
,
TB_BUTTONSTRUCTSIZE
,
(
WPARAM
)(
int
)
sizeof
(
TBBUTTON
),
0
);
va_start
(
arg_ptr
,
n_tbearr
);
while
(
(
desc
=
va_arg
(
arg_ptr
,
const
char
*
))
)
{
bmapid
=
va_arg
(
arg_ptr
,
UINT
);
cmdid
=
va_arg
(
arg_ptr
,
UINT
);
if
(
!*
desc
)
;
/* Empty description - ignore this item. */
else
if
(
*
desc
==
'|'
&&
!
desc
[
1
])
{
/* Separator. Ignore BMAPID and CMDID. */
/* Not yet implemented. */
}
else
{
TBADDBITMAP
tbab
;
tb_info
=
(
toolbar_info_t
)
xcalloc
(
1
,
sizeof
*
tb_info
);
tb_info
->
button_id
=
tbearr
[
tbeidx
].
itbbBase
++
;
tbab
.
hInst
=
glob_hinst
;
tbab
.
nID
=
bmapid
;
rc
=
SendMessage
(
tbearr
[
tbeidx
].
hwnd
,
TB_ADDBITMAP
,
1
,(
LPARAM
)
&
tbab
);
if
(
rc
==
-1
)
log_error_w32
(
-1
,
"TB_ADDBITMAP failed for `%s'"
,
desc
);
tb_info
->
bitmap
=
rc
;
tb_info
->
cmd_id
=
cmdid
;
tb_info
->
desc
=
desc
;
tb_info
->
context
=
m_lContext
;
tb_info
->
next
=
m_toolbar_info
;
m_toolbar_info
=
tb_info
;
if
(
debug_commands
)
log_debug
(
"%s:%s: ctx=%lx button_id=%d cmd_id=%d '%s'
\n
"
,
SRCNAME
,
__func__
,
m_lContext
,
tb_info
->
button_id
,
tb_info
->
cmd_id
,
tb_info
->
desc
);
}
}
va_end
(
arg_ptr
);
}
/* Called by Exchange to install commands and toolbar buttons. Returns
S_FALSE to signal Exchange to continue calling extensions. */
STDMETHODIMP
GpgolExtCommands
::
InstallCommands
(
LPEXCHEXTCALLBACK
eecb
,
// The Exchange Callback Interface.
HWND
hWnd
,
// The window handle to the main window
// of context.
HMENU
hMenu
,
// The menu handle to main menu of context.
UINT
FAR
*
pnCommandIDBase
,
// The base command id.
LPTBENTRY
pTBEArray
,
// The array of toolbar button entries.
UINT
nTBECnt
,
// The count of button entries in array.
ULONG
lFlags
)
// reserved
{
HRESULT
hr
;
m_hWnd
=
hWnd
;
LPDISPATCH
pDisp
;
DISPID
dispid
;
DISPID
dispid_put
=
DISPID_PROPERTYPUT
;
DISPPARAMS
dispparams
;
VARIANT
aVariant
;
int
force_encrypt
=
0
;
char
*
draft_info
=
NULL
;
(
void
)
hMenu
;
if
(
debug_commands
)
log_debug
(
"%s:%s: context=%s flags=0x%lx
\n
"
,
SRCNAME
,
__func__
,
ext_context_name
(
m_lContext
),
lFlags
);
show_event_object
(
eecb
,
__func__
);
/* Outlook 2003 sometimes displays the plaintext and sometimes the
original undecrypted text when doing a reply. This seems to
depend on the size of the message; my guess it that only short
messages are locally saved in the process and larger ones are
fetched again from the backend - or the other way around.
Anyway, we can't rely on that and thus me make sure to update the
Body object right here with our own copy of the plaintext. To
match the text we use the ConversationIndex property.
Unfortunately there seems to be no way of resetting the saved
property after updating the body, thus even without entering a
single byte the user will be asked when cancelling a reply
whether he really wants to do that.
Note, that we can't optimize the code here by first reading the
body because this would pop up the security window, telling the
user that someone is trying to read this data.
*/
if
(
m_lContext
==
EECONTEXT_SENDNOTEMESSAGE
)
{
LPMDB
mdb
=
NULL
;
LPMESSAGE
message
=
NULL
;
/* Note that for read and send the object returned by the
outlook extension callback is of class 43 (MailItem) so we
only need to ask for Body then. */
hr
=
eecb
->
GetObject
(
&
mdb
,
(
LPMAPIPROP
*
)
&
message
);
if
(
FAILED
(
hr
))
log_debug
(
"%s:%s: getObject failed: hr=%#lx
\n
"
,
SRCNAME
,
__func__
,
hr
);
else
if
(
!
opt
.
compat
.
no_msgcache
)
{
const
char
*
body
;
char
*
key
=
NULL
;
size_t
keylen
=
0
;
void
*
refhandle
=
NULL
;
pDisp
=
find_outlook_property
(
eecb
,
"ConversationIndex"
,
&
dispid
);
if
(
pDisp
)
{
DISPPARAMS
dispparamsNoArgs
=
{
NULL
,
NULL
,
0
,
0
};
aVariant
.
bstrVal
=
NULL
;
hr
=
pDisp
->
Invoke
(
dispid
,
IID_NULL
,
LOCALE_SYSTEM_DEFAULT
,
DISPATCH_PROPERTYGET
,
&
dispparamsNoArgs
,
&
aVariant
,
NULL
,
NULL
);
if
(
hr
!=
S_OK
)
log_debug
(
"%s:%s: retrieving ConversationIndex failed: %#lx"
,
SRCNAME
,
__func__
,
hr
);
else
if
(
aVariant
.
vt
!=
VT_BSTR
)
log_debug
(
"%s:%s: ConversationIndex is not a string (%d)"
,
SRCNAME
,
__func__
,
aVariant
.
vt
);
else
if
(
aVariant
.
bstrVal
)
{
char
*
p
;
key
=
wchar_to_utf8
(
aVariant
.
bstrVal
);
log_debug
(
"%s:%s: ConversationIndex is `%s'"
,
SRCNAME
,
__func__
,
key
);
/* The key is a hex string. Convert it to binary. */
for
(
keylen
=
0
,
p
=
key
;
hexdigitp
(
p
)
&&
hexdigitp
(
p
+
1
);
p
+=
2
)
((
unsigned
char
*
)
key
)[
keylen
++
]
=
xtoi_2
(
p
);
SysFreeString
(
aVariant
.
bstrVal
);
}
pDisp
->
Release
();
pDisp
=
NULL
;
}
if
(
key
&&
keylen
&&
(
body
=
msgcache_get
(
key
,
keylen
,
&
refhandle
))
&&
(
pDisp
=
find_outlook_property
(
eecb
,
"Body"
,
&
dispid
)))
{
dispparams
.
cNamedArgs
=
1
;
dispparams
.
rgdispidNamedArgs
=
&
dispid_put
;
dispparams
.
cArgs
=
1
;
dispparams
.
rgvarg
=
&
aVariant
;
dispparams
.
rgvarg
[
0
].
vt
=
VT_LPWSTR
;
dispparams
.
rgvarg
[
0
].
bstrVal
=
utf8_to_wchar
(
body
);
hr
=
pDisp
->
Invoke
(
dispid
,
IID_NULL
,
LOCALE_SYSTEM_DEFAULT
,
DISPATCH_PROPERTYPUT
,
&
dispparams
,
NULL
,
NULL
,
NULL
);
xfree
(
dispparams
.
rgvarg
[
0
].
bstrVal
);
log_debug
(
"%s:%s: PROPERTYPUT(body) result -> %#lx
\n
"
,
SRCNAME
,
__func__
,
hr
);
pDisp
->
Release
();
pDisp
=
NULL
;
/* Because we found the plaintext in the cache we can assume
that the orginal message has been encrypted and thus we
now set a flag to make sure that by default the reply
gets encrypted too. */
force_encrypt
=
1
;
}
msgcache_unref
(
refhandle
);
xfree
(
key
);
}
/* Because we have the message open, we use it to get the draft
info property. */
if
(
message
)
draft_info
=
mapi_get_gpgol_draft_info
(
message
);
ul_release
(
message
,
__func__
,
__LINE__
);
ul_release
(
mdb
,
__func__
,
__LINE__
);
}
/* Now install menu and toolbar items. */
if
(
m_lContext
==
EECONTEXT_READNOTEMESSAGE
)
{
add_menu
(
eecb
,
pnCommandIDBase
,
"@"
,
NULL
,
(
opt
.
enable_debug
&&
!
opt
.
disable_gpgol
)
?
"GpgOL Debug-1 (open_inspector)"
:
""
,
&
m_nCmdDebug1
,
(
opt
.
enable_debug
&&
!
opt
.
disable_gpgol
)
?
"GpgOL Debug-2 (change msg class)"
:
""
,
&
m_nCmdDebug2
,
opt
.
enable_debug
?
"GpgOL Debug-3 (revert message class)"
:
""
,
&
m_nCmdDebug3
,
NULL
);
}
else
if
(
m_lContext
==
EECONTEXT_SENDNOTEMESSAGE
&&
!
opt
.
disable_gpgol
)
{
add_menu
(
eecb
,
pnCommandIDBase
,
"@"
,
NULL
,
_
(
"&encrypt message with GnuPG"
),
&
m_nCmdEncrypt
,
_
(
"&sign message with GnuPG"
),
&
m_nCmdSign
,
NULL
);
add_toolbar
(
pTBEArray
,
nTBECnt
,
"Encrypt"
,
IDB_ENCRYPT
,
m_nCmdEncrypt
,
"Sign"
,
IDB_SIGN
,
m_nCmdSign
,
NULL
,
0
,
0
);
m_pExchExt
->
m_protoSelection
=
opt
.
default_protocol
;
if
(
draft_info
&&
draft_info
[
0
]
==
'E'
)
m_pExchExt
->
m_gpgEncrypt
=
true
;
else
if
(
draft_info
&&
draft_info
[
0
]
==
'e'
)
m_pExchExt
->
m_gpgEncrypt
=
false
;
else
m_pExchExt
->
m_gpgEncrypt
=
opt
.
encrypt_default
;
if
(
draft_info
&&
draft_info
[
0
]
&&
draft_info
[
1
]
==
'S'
)
m_pExchExt
->
m_gpgSign
=
true
;
else
if
(
draft_info
&&
draft_info
[
0
]
&&
draft_info
[
1
]
==
's'
)
m_pExchExt
->
m_gpgSign
=
false
;
else
m_pExchExt
->
m_gpgSign
=
opt
.
sign_default
;
if
(
force_encrypt
)
m_pExchExt
->
m_gpgEncrypt
=
true
;
check_menu
(
eecb
,
m_nCmdEncrypt
,
m_pExchExt
->
m_gpgEncrypt
);
check_menu
(
eecb
,
m_nCmdSign
,
m_pExchExt
->
m_gpgSign
);
}
else
if
(
m_lContext
==
EECONTEXT_VIEWER
)
{
add_menu
(
eecb
,
pnCommandIDBase
,
"@"
,
NULL
,
_
(
"Remove GpgOL flags from this folder"
),
&
m_nCmdRevertFolder
,
NULL
);
}
xfree
(
draft_info
);
return
S_FALSE
;
}
/* Called by Exchange when a user selects a command. Return value:
S_OK if command is handled, otherwise S_FALSE. */
STDMETHODIMP
GpgolExtCommands
::
DoCommand
(
LPEXCHEXTCALLBACK
eecb
,
UINT
nCommandID
)
{
HRESULT
hr
;
HWND
hwnd
=
NULL
;
LPMESSAGE
message
=
NULL
;
LPMDB
mdb
=
NULL
;
if
(
FAILED
(
eecb
->
GetWindow
(
&
hwnd
)))
hwnd
=
NULL
;
if
(
debug_commands
)
log_debug
(
"%s:%s: commandID=%u (%#x) context=%s hwnd=%p
\n
"
,
SRCNAME
,
__func__
,
nCommandID
,
nCommandID
,
ext_context_name
(
m_lContext
),
hwnd
);
show_event_object
(
eecb
,
__func__
);
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
;
if
(
debug_commands
)
log_debug
(
"%s:%s: command Close called
\n
"
,
SRCNAME
,
__func__
);
pDisp
=
find_outlook_property
(
eecb
,
"Close"
,
&
dispid
);
if
(
pDisp
)
{
/* Note that there is a report on the Net from 2005 by Amit
Joshi where he claims that in Outlook XP olDiscard does
not work but is treated like olSave. */
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"
,
SRCNAME
,
__func__
);
message_wipe_body_cruft
(
eecb
);
return
S_OK
;
/* We handled the close command. */
}
log_debug
(
"%s:%s: invoking Close failed: %#lx"
,
SRCNAME
,
__func__
,
hr
);
}
else
log_debug
(
"%s:%s: invoking Close failed: no Close method)"
,
SRCNAME
,
__func__
);
message_wipe_body_cruft
(
eecb
);
/* Closing on our own failed - pass it on. */
return
S_FALSE
;
}
else
if
(
nCommandID
==
EECMDID_ComposeReplyToSender
)
{
if
(
debug_commands
)
log_debug
(
"%s:%s: command Reply called
\n
"
,
SRCNAME
,
__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. */
return
S_FALSE
;
/* Pass it on. */
}
else
if
(
nCommandID
==
EECMDID_ComposeReplyToAll
)
{
if
(
debug_commands
)
log_debug
(
"%s:%s: command ReplyAll called
\n
"
,
SRCNAME
,
__func__
);
return
S_FALSE
;
/* Pass it on. */
}
else
if
(
nCommandID
==
EECMDID_ComposeForward
)
{
if
(
debug_commands
)
log_debug
(
"%s:%s: command Forward called
\n
"
,
SRCNAME
,
__func__
);
return
S_FALSE
;
/* Pass it on. */
}
else
if
(
nCommandID
==
m_nCmdEncrypt
&&
m_lContext
==
EECONTEXT_SENDNOTEMESSAGE
)
{
log_debug
(
"%s:%s: command Encrypt called
\n
"
,
SRCNAME
,
__func__
);
m_pExchExt
->
m_gpgEncrypt
=
!
m_pExchExt
->
m_gpgEncrypt
;
check_menu
(
eecb
,
m_nCmdEncrypt
,
m_pExchExt
->
m_gpgEncrypt
);
}
else
if
(
nCommandID
==
m_nCmdSign
&&
m_lContext
==
EECONTEXT_SENDNOTEMESSAGE
)
{
log_debug
(
"%s:%s: command Sign called
\n
"
,
SRCNAME
,
__func__
);
m_pExchExt
->
m_gpgSign
=
!
m_pExchExt
->
m_gpgSign
;
check_menu
(
eecb
,
m_nCmdSign
,
m_pExchExt
->
m_gpgSign
);
}
else
if
(
nCommandID
==
m_nCmdRevertFolder
&&
m_lContext
==
EECONTEXT_VIEWER
)
{
log_debug
(
"%s:%s: command ReverFoldert called
\n
"
,
SRCNAME
,
__func__
);
/* Notify the user that the general GpgOl fucntionaly will be
disabled when calling this function the first time. */
if
(
opt
.
disable_gpgol
||
(
MessageBox
(
hwnd
,
_
(
"You are about to start the process of reversing messages "
"created by GpgOL to prepare deinstalling of GpgOL. "
"Running this command will put GpgOL into a disabled state "
"so that messages are not anymore processed by GpgOL.
\n
"
"
\n
"
"You should convert all folders one after the other with "
"this command, close Outlook and then deinstall GpgOL.
\n
"
"
\n
"
"Note that if you start Outlook again with GpgOL still "
"being installed, GpgOL will again process messages."
),
_
(
"GpgOL"
),
MB_ICONWARNING
|
MB_OKCANCEL
)
==
IDOK
))
{
if
(
MessageBox
(
hwnd
,
_
(
"Do you want to revert this folder?"
),
_
(
"GpgOL"
),
MB_ICONQUESTION
|
MB_YESNO
)
==
IDYES
)
{
if
(
!
opt
.
disable_gpgol
)
opt
.
disable_gpgol
=
1
;
gpgol_folder_revert
(
eecb
);
}
}
}
else
if
(
opt
.
enable_debug
&&
nCommandID
==
m_nCmdDebug0
&&
m_lContext
==
EECONTEXT_READNOTEMESSAGE
)
{
log_debug
(
"%s:%s: command Debug0 (showInfo) called
\n
"
,
SRCNAME
,
__func__
);
hr
=
eecb
->
GetObject
(
&
mdb
,
(
LPMAPIPROP
*
)
&
message
);
if
(
SUCCEEDED
(
hr
))
{
message_show_info
(
message
,
hwnd
);
}
ul_release
(
message
,
__func__
,
__LINE__
);
ul_release
(
mdb
,
__func__
,
__LINE__
);
}
else
if
(
opt
.
enable_debug
&&
nCommandID
==
m_nCmdDebug1
&&
m_lContext
==
EECONTEXT_READNOTEMESSAGE
)
{
log_debug
(
"%s:%s: command Debug1 (open inspector) called
\n
"
,
SRCNAME
,
__func__
);
hr
=
eecb
->
GetObject
(
&
mdb
,
(
LPMAPIPROP
*
)
&
message
);
if
(
SUCCEEDED
(
hr
))
{
open_inspector
(
eecb
,
message
);
}
ul_release
(
message
,
__func__
,
__LINE__
);
ul_release
(
mdb
,
__func__
,
__LINE__
);
}
else
if
(
opt
.
enable_debug
&&
nCommandID
==
m_nCmdDebug2
&&
m_lContext
==
EECONTEXT_READNOTEMESSAGE
)
{
log_debug
(
"%s:%s: command Debug2 (change message class) called
\n
"
,
SRCNAME
,
__func__
);
hr
=
eecb
->
GetObject
(
&
mdb
,
(
LPMAPIPROP
*
)
&
message
);
if
(
SUCCEEDED
(
hr
))
{
/* We sync here. */
mapi_change_message_class
(
message
,
1
);
}
ul_release
(
message
,
__func__
,
__LINE__
);
ul_release
(
mdb
,
__func__
,
__LINE__
);
}
else
if
(
opt
.
enable_debug
&&
nCommandID
==
m_nCmdDebug3
&&
m_lContext
==
EECONTEXT_READNOTEMESSAGE
)
{
log_debug
(
"%s:%s: command Debug3 (revert_message_class) called
\n
"
,
SRCNAME
,
__func__
);
hr
=
eecb
->
GetObject
(
&
mdb
,
(
LPMAPIPROP
*
)
&
message
);
if
(
SUCCEEDED
(
hr
))
{
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
);
}
ul_release
(
message
,
__func__
,
__LINE__
);
ul_release
(
mdb
,
__func__
,
__LINE__
);
}
else
if
(
nCommandID
==
EECMDID_SaveMessage
&&
m_lContext
==
EECONTEXT_SENDNOTEMESSAGE
)
{
char
buf
[
4
];
log_debug
(
"%s:%s: command SaveMessage called
\n
"
,
SRCNAME
,
__func__
);
buf
[
0
]
=
m_pExchExt
->
m_gpgEncrypt
?
'E'
:
'e'
;
buf
[
1
]
=
m_pExchExt
->
m_gpgSign
?
'S'
:
's'
;
switch
(
m_pExchExt
->
m_protoSelection
)
{
case
PROTOCOL_UNKNOWN
:
buf
[
2
]
=
'A'
;
break
;
case
PROTOCOL_OPENPGP
:
buf
[
2
]
=
'P'
;
break
;
case
PROTOCOL_SMIME
:
buf
[
2
]
=
'X'
;
break
;
default
:
buf
[
2
]
=
'-'
;
break
;
}
buf
[
3
]
=
0
;
hr
=
eecb
->
GetObject
(
&
mdb
,
(
LPMAPIPROP
*
)
&
message
);
if
(
SUCCEEDED
(
hr
))
mapi_set_gpgol_draft_info
(
message
,
buf
);
else
log_debug
(
"%s:%s: getObject failed: hr=%#lx
\n
"
,
SRCNAME
,
__func__
,
hr
);
ul_release
(
message
,
__func__
,
__LINE__
);
ul_release
(
mdb
,
__func__
,
__LINE__
);
return
S_FALSE
;
/* Pass on to next handler. */
}
else
{
if
(
debug_commands
)
log_debug
(
"%s:%s: command passed on
\n
"
,
SRCNAME
,
__func__
);
return
S_FALSE
;
/* Pass on unknown command. */
}
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
)
GpgolExtCommands
::
InitMenu
(
LPEXCHEXTCALLBACK
eecb
)
{
(
void
)
eecb
;
}
/* Called by Exchange when the user requests help for a menu item.
EECB is the pointer to Exchange Callback Interface. NCOMMANDID is
the command id. Return value: S_OK when it is a menu item of this
plugin and the help was shown; otherwise S_FALSE. */
STDMETHODIMP
GpgolExtCommands
::
Help
(
LPEXCHEXTCALLBACK
eecb
,
UINT
nCommandID
)
{
(
void
)
eecb
;
show_event_object
(
eecb
,
__func__
);
if
(
nCommandID
==
m_nCmdEncrypt
&&
m_lContext
==
EECONTEXT_SENDNOTEMESSAGE
)
{
MessageBox
(
m_hWnd
,
_
(
"Select this option to encrypt the message."
),
"GpgOL"
,
MB_OK
);
}
else
if
(
nCommandID
==
m_nCmdSign
&&
m_lContext
==
EECONTEXT_SENDNOTEMESSAGE
)
{
MessageBox
(
m_hWnd
,
_
(
"Select this option to sign the message."
),
"GpgOL"
,
MB_OK
);
}
else
return
S_FALSE
;
return
S_OK
;
}
/* Called by Exchange to get the status bar text or the tooltip of a
menu item. NCOMMANDID is the command id corresponding to the menu
item activated. LFLAGS identifies either EECQHT_STATUS or
EECQHT_TOOLTIP. PSZTEXT is a pointer to buffer to received the
text to be displayed. NCHARCNT is the available space in PSZTEXT.
Returns S_OK when it is a menu item of this plugin and the text was
set; otherwise S_FALSE. */
STDMETHODIMP
GpgolExtCommands
::
QueryHelpText
(
UINT
nCommandID
,
ULONG
lFlags
,
LPTSTR
pszText
,
UINT
nCharCnt
)
{
if
(
nCommandID
==
m_nCmdEncrypt
&&
m_lContext
==
EECONTEXT_SENDNOTEMESSAGE
)
{
if
(
lFlags
==
EECQHT_STATUS
)
lstrcpyn
(
pszText
,
"."
,
nCharCnt
);
if
(
lFlags
==
EECQHT_TOOLTIP
)
lstrcpyn
(
pszText
,
_
(
"Encrypt message with GnuPG"
),
nCharCnt
);
}
else
if
(
nCommandID
==
m_nCmdSign
&&
m_lContext
==
EECONTEXT_SENDNOTEMESSAGE
)
{
if
(
lFlags
==
EECQHT_STATUS
)
lstrcpyn
(
pszText
,
"."
,
nCharCnt
);
if
(
lFlags
==
EECQHT_TOOLTIP
)
lstrcpyn
(
pszText
,
_
(
"Sign message with GnuPG"
),
nCharCnt
);
}
else
return
S_FALSE
;
return
S_OK
;
}
/* Called by Exchange to get toolbar button infos. TOOLBARID is the
toolbar identifier. BUTTONID is the toolbar button index. PTBB is
a pointer to the toolbar button structure. DESCRIPTION is a pointer to
buffer receiving the text for the button. DESCRIPTION_SIZE is the
maximum size of DESCRIPTION. FLAGS are flags which might have the
EXCHEXT_UNICODE bit set.
Returns S_OK when it is a button of this plugin and the requested
info was delivered; otherwise S_FALSE. */
STDMETHODIMP
GpgolExtCommands
::
QueryButtonInfo
(
ULONG
toolbarid
,
UINT
buttonid
,
LPTBBUTTON
pTBB
,
LPTSTR
description
,
UINT
description_size
,
ULONG
flags
)
{
toolbar_info_t
tb_info
;
size_t
n
;
(
void
)
description_size
;
(
void
)
flags
;
for
(
tb_info
=
m_toolbar_info
;
tb_info
;
tb_info
=
tb_info
->
next
)
if
(
tb_info
->
button_id
==
buttonid
&&
tb_info
->
context
==
m_lContext
)
break
;
if
(
!
tb_info
)
return
S_FALSE
;
/* Not one of our toolbar buttons. */
if
(
debug_commands
)
log_debug
(
"%s:%s: ctx=%lx tbid=%ld button_id(req)=%d got=%d"
" cmd_id=%d '%s'
\n
"
,
SRCNAME
,
__func__
,
m_lContext
,
toolbarid
,
buttonid
,
tb_info
->
button_id
,
tb_info
->
cmd_id
,
tb_info
->
desc
);
/* Mark that this button has passed this function. */
tb_info
->
did_qbi
=
1
;
pTBB
->
iBitmap
=
tb_info
->
bitmap
;
pTBB
->
idCommand
=
tb_info
->
cmd_id
;
pTBB
->
fsState
=
TBSTATE_ENABLED
;
pTBB
->
fsStyle
=
TBSTYLE_BUTTON
;
pTBB
->
dwData
=
0
;
pTBB
->
iString
=
-1
;
n
=
strlen
(
tb_info
->
desc
);
if
(
n
>
description_size
)
n
=
description_size
;
lstrcpyn
(
description
,
tb_info
->
desc
,
n
);
if
(
tb_info
->
cmd_id
==
m_nCmdEncrypt
)
{
pTBB
->
fsStyle
|=
TBSTYLE_CHECK
;
if
(
m_pExchExt
->
m_gpgEncrypt
)
pTBB
->
fsState
|=
TBSTATE_CHECKED
;
}
else
if
(
tb_info
->
cmd_id
==
m_nCmdSign
)
{
pTBB
->
fsStyle
|=
TBSTYLE_CHECK
;
if
(
m_pExchExt
->
m_gpgSign
)
pTBB
->
fsState
|=
TBSTATE_CHECKED
;
}
return
S_OK
;
}
STDMETHODIMP
GpgolExtCommands
::
ResetToolbar
(
ULONG
lToolbarID
,
ULONG
lFlags
)
{
(
void
)
lToolbarID
;
(
void
)
lFlags
;
return
S_OK
;
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Tue, Apr 22, 3:59 AM (4 h, 21 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
65/7a/1dc43cea4c848fa48b164dff6ba9
Attached To
rO GpgOL
Event Timeline
Log In to Comment