diff --git a/src/Makefile.am b/src/Makefile.am
index 500e286..d3d8b19 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,118 +1,117 @@
# Makefile.am - makefile for GPGol
# Copyright (C) 2005 g10 Code GmbH
# Copyright (C) 2016 Bundesamt für Sicherheit in der Informationstechnik
# Software engineering by Intevation GmbH
# Copyright (C) 2018 Intevation GmbH
#
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
## Process this file with automake to produce Makefile.in
SUBDIRS = icons
bin_PROGRAMS = gpgol
EXTRA_DIST = \
versioninfo.rc.in mapi32.def Outlook.gpl \
dialogs.rc
EXEEXT = .dll
AM_CFLAGS = $(GPGME_CFLAGS) -shared
AM_CXXFLAGS = $(GPGME_CFLAGS) $(LIBASSUAN_CFLAGS) -shared -std=c++11
AM_CXXFLAGS += $(GPGMEPP_CXXFLAGS) -D_FILE_OFFSET_BITS=64
gpgol_SOURCES = \
addin-options.cpp addin-options.h \
application-events.cpp \
attachment.h attachment.cpp \
- common.h common.c \
+ common.h common.cpp \
common_indep.h common_indep.c \
- config-dialog.c \
cpphelp.cpp cpphelp.h \
cryptcontroller.cpp cryptcontroller.h \
dialogs.h \
eventsink.h \
eventsinks.h \
exechelp.c exechelp.h \
explorer-events.cpp \
explorers-events.cpp \
filetype.c filetype.h \
folder-events.cpp \
gmime-table-private.h \
gpgoladdin.cpp gpgoladdin.h \
gpgol.def \
gpgol-ids.h \
keycache.cpp keycache.h \
mail.h mail.cpp \
mailitem-events.cpp \
main.c \
mapihelp.cpp mapihelp.h \
mimedataprovider.cpp mimedataprovider.h \
mimemaker.cpp mimemaker.h \
mlang-charset.cpp mlang-charset.h \
mymapi.h \
mymapitags.h \
olflange.cpp olflange.h \
oomhelp.cpp oomhelp.h \
overlay.cpp overlay.h \
parsecontroller.cpp parsecontroller.h \
parsetlv.h parsetlv.c \
resource.rc \
revert.cpp revert.h \
rfc2047parse.h rfc2047parse.c \
rfc822parse.c rfc822parse.h \
ribbon-callbacks.cpp ribbon-callbacks.h \
w32-gettext.cpp w32-gettext.h \
windowmessages.h windowmessages.cpp \
wks-helper.cpp wks-helper.h \
xmalloc.h
#treeview_SOURCES = treeview.c
# W32API 3.2 comes with an unusable libmapi32.a. We build our own
# version. Note the omission of -k (--kill-at) from the DLLTOOL
# command line. We also create our own virtual copies to the _static_
# versions of GPGME and gpg-error, because we want to link to them
# statically, and not dynamically (otherwise Outlook would not find
# them).
gpgol_DEPENDENCIES = libmapi32.a libgpg-error.a libgpgme.a libassuan.a libgpgmepp.a
if BUILD_W64
DLLTOOLFLAGS64=--as-flags=--64 -m i386:x86-64
endif
libmapi32.a: mapi32.def
$(DLLTOOL) $(DLLTOOLFLAGS64) --output-lib $@ --def $<
libgpg-error.a:
ln -s $$($(GPG_ERROR_CONFIG) --prefix)/lib/libgpg-error.a .
libgpgme.a:
ln -s $$($(GPGME_CONFIG) --prefix)/lib/libgpgme.a .
libassuan.a:
ln -s $$($(LIBASSUAN_CONFIG) --prefix)/lib/libassuan.a .
libgpgmepp.a:
ln -s $$($(GPGME_CONFIG) --prefix)/lib/libgpgmepp.a .
clean-local:
rm -f libmapi32.a libgpg-error.a libgpgme.a libassuan.a libgpgmepp.a
gpgol_LDFLAGS = -static-libgcc -static-libstdc++
gpgol_LDADD = $(srcdir)/gpgol.def \
-L . -lgpgmepp -lgpgme -lassuan -lgpg-error \
-lmapi32 -lshell32 -lgdi32 -lcomdlg32 \
-lole32 -loleaut32 -lws2_32 -ladvapi32 \
-luuid -lgdiplus -lrpcrt4
resource.o: resource.rc versioninfo.rc dialogs.rc dialogs.h
.rc.o:
$(WINDRES) -I $(srcdir) -I . -I .. `test -f '$<' || echo '$(srcdir)/'`$< $@
diff --git a/src/common.c b/src/common.cpp
similarity index 61%
rename from src/common.c
rename to src/common.cpp
index a9ac04b..629690d 100644
--- a/src/common.c
+++ b/src/common.cpp
@@ -1,1207 +1,851 @@
/* common.c - Common routines used by GpgOL
* Copyright (C) 2005, 2007, 2008 g10 Code GmbH
* 2015, 2016, 2017 Bundesamt für Sicherheit in der Informationstechnik
* Software engineering by Intevation 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
* 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 .
*/
#include
#define OEMRESOURCE /* Required for OBM_CHECKBOXES. */
#include
#include
#ifndef CSIDL_APPDATA
#define CSIDL_APPDATA 0x001a
#endif
#ifndef CSIDL_LOCAL_APPDATA
#define CSIDL_LOCAL_APPDATA 0x001c
#endif
#ifndef CSIDL_FLAG_CREATE
#define CSIDL_FLAG_CREATE 0x8000
#endif
#include
#include
#include
#include "common.h"
-
#include "dialogs.h"
+#include
+
HINSTANCE glob_hinst = NULL;
void
set_global_hinstance (HINSTANCE hinst)
{
glob_hinst = hinst;
}
-/* Center the given window with the desktop window as the
- parent window. */
-void
-center_window (HWND childwnd, HWND style)
-{
- HWND parwnd;
- RECT rchild, rparent;
- HDC hdc;
- int wchild, hchild, wparent, hparent;
- int wscreen, hscreen, xnew, ynew;
- int flags = SWP_NOSIZE | SWP_NOZORDER;
-
- parwnd = GetDesktopWindow ();
- GetWindowRect (childwnd, &rchild);
- wchild = rchild.right - rchild.left;
- hchild = rchild.bottom - rchild.top;
-
- GetWindowRect (parwnd, &rparent);
- wparent = rparent.right - rparent.left;
- hparent = rparent.bottom - rparent.top;
-
- hdc = GetDC (childwnd);
- wscreen = GetDeviceCaps (hdc, HORZRES);
- hscreen = GetDeviceCaps (hdc, VERTRES);
- ReleaseDC (childwnd, hdc);
- xnew = rparent.left + ((wparent - wchild) / 2);
- if (xnew < 0)
- xnew = 0;
- else if ((xnew+wchild) > wscreen)
- xnew = wscreen - wchild;
- ynew = rparent.top + ((hparent - hchild) / 2);
- if (ynew < 0)
- ynew = 0;
- else if ((ynew+hchild) > hscreen)
- ynew = hscreen - hchild;
- if (style == HWND_TOPMOST || style == HWND_NOTOPMOST)
- flags = SWP_NOMOVE | SWP_NOSIZE;
- SetWindowPos (childwnd, style? style : NULL, xnew, ynew, 0, 0, flags);
-}
-
-
-/* Return the system's bitmap of the check bar used which check boxes.
- If CHECKED is set, this check mark is returned; if it is not set,
- the one used for not-checked is returned. May return NULL on
- error. Taken from an example in the platform reference.
-
- Not used as of now. */
-HBITMAP
-get_system_check_bitmap (int checked)
-{
- COLORREF bg_color;
- HBRUSH bg_brush, saved_dst_brush;
- HDC src_dc, dst_dc;
- WORD xsize, ysize;
- HBITMAP result, saved_dst_bitmap, saved_src_bitmap, checkboxes;
- BITMAP bitmap;
- RECT rect;
-
- bg_color = GetSysColor (COLOR_MENU);
- bg_brush = CreateSolidBrush (bg_color);
-
- src_dc = CreateCompatibleDC (NULL);
- dst_dc = CreateCompatibleDC (src_dc);
-
- xsize = GetSystemMetrics (SM_CXMENUCHECK);
- ysize = GetSystemMetrics (SM_CYMENUCHECK);
- result = CreateCompatibleBitmap(src_dc, xsize, ysize);
-
- saved_dst_brush = SelectObject (dst_dc, bg_brush);
- saved_dst_bitmap = SelectObject (dst_dc, result);
-
- PatBlt (dst_dc, 0, 0, xsize, ysize, PATCOPY);
-
- checkboxes = LoadBitmap (NULL, (LPTSTR)OBM_CHECKBOXES);
-
- saved_src_bitmap = SelectObject (src_dc, checkboxes);
-
- GetObject (checkboxes, sizeof (BITMAP), &bitmap);
- rect.top = 0;
- rect.bottom = (bitmap.bmHeight / 3);
- if (checked)
- {
- /* Select row 1, column 1. */
- rect.left = 0;
- rect.right = (bitmap.bmWidth / 4);
- }
- else
- {
- /* Select row 1, column 2. */
- rect.left = (bitmap.bmWidth / 4);
- rect.right = (bitmap.bmWidth / 4) * 2;
- }
-
- if ( ((rect.right - rect.left) > (int)xsize)
- || ((rect.bottom - rect.top) > (int)ysize) )
- StretchBlt (dst_dc, 0, 0, xsize, ysize, src_dc, rect.left, rect.top,
- rect.right - rect.left, rect.bottom - rect.top, SRCCOPY);
- else
- BitBlt (dst_dc, 0, 0, rect.right - rect.left, rect.bottom - rect.top,
- src_dc, rect.left, rect.top, SRCCOPY);
-
- SelectObject (src_dc, saved_src_bitmap);
- SelectObject (dst_dc, saved_dst_brush);
- result = SelectObject (dst_dc, saved_dst_bitmap);
-
- DeleteObject (bg_brush);
- DeleteObject (src_dc);
- DeleteObject (dst_dc);
- return result;
-}
-
-/* Return the path to a file that should be worked with.
- Returns a malloced string (UTF-8) on success.
- HWND is the current Window.
- Title is a UTF-8 encoded string containing the
- dialog title and may be NULL.
- On error (i.e. cancel) NULL is returned. */
-char *
-get_open_filename (HWND root, const char *title)
-{
- OPENFILENAMEW ofn;
- wchar_t fname[MAX_PATH+1];
- wchar_t *wTitle = NULL;
-
- if (title)
- {
- wTitle = utf8_to_wchar2 (title, strlen(title));
- }
- memset (fname, 0, sizeof (fname));
-
- /* Set up the ofn structure */
- memset (&ofn, 0, sizeof (ofn));
- ofn.lStructSize = sizeof (ofn);
- ofn.hwndOwner = root;
- ofn.lpstrFile = fname;
- ofn.nMaxFile = MAX_PATH;
- ofn.lpstrTitle = wTitle;
- ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
-
- if (GetOpenFileNameW (&ofn))
- {
- xfree (wTitle);
- return wchar_to_utf8_2 (fname, MAX_PATH);
- }
- xfree (wTitle);
- return NULL;
-}
-
-
-/* Return a filename to be used for saving an attachment. Returns a
- malloced string on success. HWND is the current Window and SRCNAME
- the filename to be used as suggestion. On error (i.e. cancel) NULL
- is returned. */
-char *
-get_save_filename (HWND root, const char *srcname)
-{
- char filter[21] = "All Files (*.*)\0*.*\0\0";
- char fname[MAX_PATH+1];
- char filterBuf[32];
- char* extSep;
- OPENFILENAME ofn;
-
- memset (fname, 0, sizeof (fname));
- memset (filterBuf, 0, sizeof (filterBuf));
- strncpy (fname, srcname, MAX_PATH-1);
- fname[MAX_PATH] = 0;
-
- if ((extSep = strrchr (srcname, '.')) && strlen (extSep) <= 4)
- {
- /* Windows removes the file extension by default so we
- need to set the first filter to the file extension.
- */
- strcpy (filterBuf, extSep);
- strcpy (filterBuf + strlen (filterBuf) + 1, extSep);
- memcpy (filterBuf + strlen (extSep) * 2 + 2, filter, 21);
- }
- else
- memcpy (filterBuf, filter, 21);
-
-
- memset (&ofn, 0, sizeof (ofn));
- ofn.lStructSize = sizeof (ofn);
- ofn.hwndOwner = root;
- ofn.lpstrFile = fname;
- ofn.nMaxFile = MAX_PATH;
- ofn.lpstrFileTitle = NULL;
- ofn.nMaxFileTitle = 0;
- ofn.Flags |= OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
- ofn.lpstrTitle = _("GpgOL - Save attachment");
- ofn.lpstrFilter = filterBuf;
-
- if (GetSaveFileName (&ofn))
- return xstrdup (fname);
- return NULL;
-}
-
void
bring_to_front (HWND wid)
{
if (wid)
{
if (!SetForegroundWindow (wid))
{
log_debug ("%s:%s: SetForegroundWindow failed", SRCNAME, __func__);
/* Yet another fallback which will not work on some
* versions and is not recommended by msdn */
if (!ShowWindow (wid, SW_SHOWNORMAL))
{
log_debug ("%s:%s: ShowWindow failed.", SRCNAME, __func__);
}
}
}
log_debug ("%s:%s: done", SRCNAME, __func__);
}
void
fatal_error (const char *format, ...)
{
va_list arg_ptr;
char buf[512];
va_start (arg_ptr, format);
vsnprintf (buf, sizeof buf -1, format, arg_ptr);
buf[sizeof buf - 1] = 0;
va_end (arg_ptr);
MessageBox (NULL, buf, "Fatal Error", MB_OK);
abort ();
}
-/* This is a helper function to load a Windows function from either of
- one DLLs. */
-static HRESULT
-w32_shgetfolderpath (HWND a, int b, HANDLE c, DWORD d, LPSTR e)
-{
- static int initialized;
- static HRESULT (WINAPI * func)(HWND,int,HANDLE,DWORD,LPSTR);
-
- if (!initialized)
- {
- static char *dllnames[] = { "shell32.dll", "shfolder.dll", NULL };
- void *handle;
- int i;
-
- initialized = 1;
-
- for (i=0, handle = NULL; !handle && dllnames[i]; i++)
- {
- handle = LoadLibrary (dllnames[i]);
- if (handle)
- {
- func = (HRESULT (WINAPI *)(HWND,int,HANDLE,DWORD,LPSTR))
- GetProcAddress (handle, "SHGetFolderPathA");
- if (!func)
- {
- FreeLibrary (handle);
- handle = NULL;
- }
- }
- }
- }
-
- if (func)
- return func (a,b,c,d,e);
- else
- return -1;
-}
-
-
-
-/* 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;
-}
-
-
-/* Same as above but convert only the first LEN characters. STRING
- must be at least LEN characters long. */
-wchar_t *
-utf8_to_wchar2 (const char *string, size_t len)
-{
- int n;
- wchar_t *result;
-
- n = MultiByteToWideChar (CP_UTF8, 0, string, len, NULL, 0);
- if (n < 0)
- return NULL;
-
- result = xmalloc ((n+1) * sizeof *result);
- n = MultiByteToWideChar (CP_UTF8, 0, string, len, result, n);
- if (n < 0)
- {
- xfree (result);
- return NULL;
- }
- result[n] = 0;
- return result;
-}
-
-
-
-
-
/* Helper for read_w32_registry_string(). */
static HKEY
get_root_key(const char *root)
{
HKEY root_key;
if( !root )
root_key = HKEY_CURRENT_USER;
else if( !strcmp( root, "HKEY_CLASSES_ROOT" ) )
root_key = HKEY_CLASSES_ROOT;
else if( !strcmp( root, "HKEY_CURRENT_USER" ) )
root_key = HKEY_CURRENT_USER;
else if( !strcmp( root, "HKEY_LOCAL_MACHINE" ) )
root_key = HKEY_LOCAL_MACHINE;
else if( !strcmp( root, "HKEY_USERS" ) )
root_key = HKEY_USERS;
else if( !strcmp( root, "HKEY_PERFORMANCE_DATA" ) )
root_key = HKEY_PERFORMANCE_DATA;
else if( !strcmp( root, "HKEY_CURRENT_CONFIG" ) )
root_key = HKEY_CURRENT_CONFIG;
else
return NULL;
return root_key;
}
-/* Return a string from the Win32 Registry or NULL in case of error.
- Caller must release the return value. A NULL for root is an alias
- for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn. NOTE: The value
- is allocated with a plain malloc() - use free() and not the usual
- xfree(). */
-char *
-read_w32_registry_string (const char *root, const char *dir, const char *name)
+static std::string
+readRegStr (const char *root, const char *dir, const char *name)
{
- HKEY root_key, key_handle;
- DWORD n1, nbytes, type;
- char *result = NULL;
+#ifndef _WIN32
+ (void)root; (void)dir; (void)name;
+ return std::string();
+#else
- if ( !(root_key = get_root_key(root) ) )
- return NULL;
-
- if( RegOpenKeyEx( root_key, dir, 0, KEY_READ, &key_handle ) )
- {
- if (root)
- return NULL; /* no need for a RegClose, so return direct */
- /* It seems to be common practise to fall back to HKLM. */
- if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) )
- return NULL; /* still no need for a RegClose, so return direct */
- }
+ HKEY root_key, key_handle;
+ DWORD n1, nbytes, type;
+ std::string ret;
- nbytes = 1;
- if( RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes ) ) {
- if (root)
- goto leave;
- /* Try to fallback to HKLM also vor a missing value. */
- RegCloseKey (key_handle);
- if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) )
- return NULL; /* Nope. */
- if (RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes))
- goto leave;
- }
- result = malloc( (n1=nbytes+1) );
- if( !result )
- goto leave;
- if( RegQueryValueEx( key_handle, name, 0, &type, result, &n1 ) ) {
- free(result); result = NULL;
- goto leave;
- }
- result[nbytes] = 0; /* make sure it is really a string */
- if (type == REG_EXPAND_SZ && strchr (result, '%')) {
- char *tmp;
-
- n1 += 1000;
- tmp = malloc (n1+1);
- if (!tmp)
- goto leave;
- nbytes = ExpandEnvironmentStrings (result, tmp, n1);
- if (nbytes && nbytes > n1) {
- free (tmp);
- n1 = nbytes;
- tmp = malloc (n1 + 1);
- if (!tmp)
- goto leave;
- nbytes = ExpandEnvironmentStrings (result, tmp, n1);
- if (nbytes && nbytes > n1) {
- free (tmp); /* oops - truncated, better don't expand at all */
- goto leave;
- }
- tmp[nbytes] = 0;
- free (result);
- result = tmp;
- }
- else if (nbytes) { /* okay, reduce the length */
- tmp[nbytes] = 0;
- free (result);
- result = malloc (strlen (tmp)+1);
- if (!result)
- result = tmp;
- else {
- strcpy (result, tmp);
- free (tmp);
- }
- }
- else { /* error - don't expand */
- free (tmp);
+ if (!(root_key = get_root_key(root))) {
+ return ret;
}
- }
-
- leave:
- RegCloseKey( key_handle );
- return result;
-}
-
-
-/* Get the standard home directory. In general this function should
- not be used as it does not consider a registry value or the
- GNUPGHOME environment variable. Please use default_homedir(). */
-static const char *
-standard_homedir (void)
-{
- static char *dir;
-
- if (!dir)
- {
- char path[MAX_PATH];
-
- /* It might be better to use LOCAL_APPDATA because this is
- defined as "non roaming" and thus more likely to be kept
- locally. For private keys this is desired. However, given
- that many users copy private keys anyway forth and back,
- using a system roaming services might be better than to let
- them do it manually. A security conscious user will anyway
- use the registry entry to have better control. */
- if (w32_shgetfolderpath (NULL, CSIDL_APPDATA|CSIDL_FLAG_CREATE,
- NULL, 0, path) >= 0)
- {
- char *tmp = malloc (strlen (path) + 6 + 1);
- strcpy (tmp, path);
- strcat (tmp, "\\gnupg");
+ if (RegOpenKeyExA(root_key, dir, 0, KEY_READ, &key_handle)) {
+ if (root) {
+ /* no need for a RegClose, so return direct */
+ return ret;
+ }
+ /* Fallback to HKLM */
- dir = tmp;
+ if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle)) {
+ return ret;
+ }
+ }
- /* Try to create the directory if it does not yet exists. */
- if (access (dir, F_OK))
- CreateDirectory (dir, NULL);
+ nbytes = 1;
+ if (RegQueryValueExA(key_handle, name, 0, nullptr, nullptr, &nbytes)) {
+ if (root) {
+ RegCloseKey (key_handle);
+ return ret;
+ }
+ /* Try to fallback to HKLM also vor a missing value. */
+ RegCloseKey (key_handle);
+ if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle)) {
+ return ret;
+ }
+ if (RegQueryValueExA(key_handle, name, 0, nullptr, nullptr, &nbytes)) {
+ RegCloseKey(key_handle);
+ return ret;
}
- else
- dir = xstrdup ("C:\\gnupg");
}
- return dir;
+ n1 = nbytes+1;
+ char result[n1];
+ if (RegQueryValueExA(key_handle, name, 0, &type, (LPBYTE)result, &n1)) {
+ RegCloseKey(key_handle);
+ return ret;
+ }
+ RegCloseKey(key_handle);
+ result[nbytes] = 0; /* make sure it is really a string */
+ ret = result;
+ if (type == REG_EXPAND_SZ && strchr (result, '%')) {
+ n1 += 1000;
+ char tmp[n1 +1];
+
+ nbytes = ExpandEnvironmentStringsA(ret.c_str(), tmp, n1);
+ if (nbytes && nbytes > n1) {
+ n1 = nbytes;
+ char tmp2[n1 +1];
+ nbytes = ExpandEnvironmentStringsA(result, tmp2, n1);
+ if (nbytes && nbytes > n1) {
+ /* oops - truncated, better don't expand at all */
+ return ret;
+ }
+ tmp2[nbytes] = 0;
+ ret = tmp2;
+ } else if (nbytes) { /* okay, reduce the length */
+ tmp[nbytes] = 0;
+ ret = tmp;
+ }
+ }
+ return ret;
+#endif
}
-
-/* Retrieve the default home directory. */
-const char *
-default_homedir (void)
+/* Return a string from the Win32 Registry or NULL in case of error.
+ Caller must release the return value. A NULL for root is an alias
+ for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn. NOTE: The value
+ is allocated with a plain malloc() - use free() and not the usual
+ xfree(). */
+char *
+read_w32_registry_string (const char *root, const char *dir, const char *name)
{
- static char *dir;
-
- if (!dir)
+ const auto ret = readRegStr (root, dir, name);
+ if (ret.empty())
{
- dir = getenv ("GNUPGHOME");
- if (!dir || !*dir)
- {
- char *tmp;
-
- tmp = read_w32_registry_string (NULL, GPG4WIN_REGKEY_3, "HomeDir");
- if (!tmp)
- {
- tmp = read_w32_registry_string (NULL, GPG4WIN_REGKEY_2, "HomeDir");
- }
- if (tmp && !*tmp)
- {
- free (tmp);
- tmp = NULL;
- }
- if (tmp)
- dir = tmp;
- else
- dir = xstrdup (standard_homedir ());
- }
- else
- dir = xstrdup (dir);
+ return nullptr;
}
-
- return dir;
+ return strdup (ret.c_str ());
}
/* Return the data dir used for forms etc. Returns NULL on error. */
char *
get_data_dir (void)
{
char *instdir;
char *p;
char *dname;
instdir = get_gpg4win_dir();
if (!instdir)
return NULL;
-
+
/* Build the key: "/share/gpgol". */
#define SDDIR "\\share\\gpgol"
- dname = malloc (strlen (instdir) + strlen (SDDIR) + 1);
+ dname = (char*) malloc (strlen (instdir) + strlen (SDDIR) + 1);
if (!dname)
{
free (instdir);
return NULL;
}
p = dname;
strcpy (p, instdir);
p += strlen (instdir);
strcpy (p, SDDIR);
-
+
free (instdir);
-
+
#undef SDDIR
return dname;
}
/* Percent-escape the string STR by replacing colons with '%3a'. If
EXTRA is not NULL all characters in it are also escaped. */
char *
percent_escape (const char *str, const char *extra)
{
int i, j;
char *ptr;
if (!str)
return NULL;
for (i=j=0; str[i]; i++)
if (str[i] == ':' || str[i] == '%' || (extra && strchr (extra, str[i])))
j++;
ptr = (char *) malloc (i + 2 * j + 1);
i = 0;
while (*str)
{
/* FIXME: Work around a bug in Kleo. */
if (*str == ':')
{
ptr[i++] = '%';
ptr[i++] = '3';
ptr[i++] = 'a';
}
else
{
if (*str == '%')
{
ptr[i++] = '%';
ptr[i++] = '2';
ptr[i++] = '5';
}
else if (extra && strchr (extra, *str))
{
ptr[i++] = '%';
ptr[i++] = tohex_lower ((*str >> 4) & 15);
ptr[i++] = tohex_lower (*str & 15);
}
else
ptr[i++] = *str;
}
str++;
}
ptr[i] = '\0';
return ptr;
}
/* Fix linebreaks.
This replaces all consecutive \r or \n characters
by a single \n.
There can be extremly weird combinations of linebreaks
like \r\r\n\r\r\n at the end of each line when
getting the body of a mail message.
*/
void
fix_linebreaks (char *str, int *len)
{
char *src;
char *dst;
src = str;
dst = str;
while (*src)
{
if (*src == '\r' || *src == '\n')
{
do
src++;
while (*src == '\r' || *src == '\n');
*(dst++) = '\n';
}
else
{
*(dst++) = *(src++);
}
}
*dst = '\0';
*len = dst - str;
}
/* Get a pretty name for the file at path path. File extension
will be set to work for the protocol as provided in protocol and
depends on the signature setting. Set signature to 0 if the
extension should not be a signature extension.
Returns NULL on success.
Caller must free result. */
wchar_t *
get_pretty_attachment_name (wchar_t *path, protocol_t protocol,
int signature)
{
wchar_t* pretty;
wchar_t* buf;
if (!path || !wcslen (path))
{
log_error("%s:%s: No path given", SRCNAME, __func__);
return NULL;
}
pretty = (wchar_t*) xmalloc ((MAX_PATH + 1) * sizeof (wchar_t));
memset (pretty, 0, (MAX_PATH + 1) * sizeof (wchar_t));
buf = wcsrchr (path, '\\') + 1;
if (!buf || !*buf)
{
log_error("%s:%s: No filename found in path", SRCNAME, __func__);
xfree (pretty);
return NULL;
}
wcscpy (pretty, buf);
buf = pretty + wcslen(pretty);
if (signature)
{
if (protocol == PROTOCOL_SMIME)
{
*(buf++) = '.';
*(buf++) = 'p';
*(buf++) = '7';
*(buf++) = 's';
}
else
{
*(buf++) = '.';
*(buf++) = 's';
*(buf++) = 'i';
*(buf++) = 'g';
}
}
else
{
if (protocol == PROTOCOL_SMIME)
{
*(buf++) = '.';
*(buf++) = 'p';
*(buf++) = '7';
*(buf++) = 'm';
}
else
{
*(buf++) = '.';
*(buf++) = 'g';
*(buf++) = 'p';
*(buf++) = 'g';
}
}
return pretty;
}
/* Open a file in a temporary directory, take name as a
suggestion and put the open Handle in outHandle.
Returns the actually used file name in case there
were other files with that name. */
wchar_t*
get_tmp_outfile (wchar_t *name, HANDLE *outHandle)
{
wchar_t tmpPath[MAX_PATH];
wchar_t *outName;
wchar_t *fileExt = NULL;
int tries = 1;
if (!name || !wcslen(name))
{
log_error ("%s:%s: Needs a name.",
SRCNAME, __func__);
return NULL;
}
/* We should probably use the unicode variants here
but this would mean adding OpenStreamOnFileW to
out mapi */
if (!GetTempPathW (MAX_PATH, tmpPath))
{
log_error ("%s:%s: Could not get tmp path.",
SRCNAME, __func__);
return NULL;
}
outName = (wchar_t*) xmalloc ((MAX_PATH + 1) * sizeof(wchar_t));
memset (outName, 0, (MAX_PATH + 1) * sizeof (wchar_t));
snwprintf (outName, MAX_PATH, L"%s%s", tmpPath, name);
while ((*outHandle = CreateFileW (outName,
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_DELETE,
NULL,
CREATE_NEW,
FILE_ATTRIBUTE_TEMPORARY,
NULL)) == INVALID_HANDLE_VALUE)
{
wchar_t fnameBuf[MAX_PATH + 1];
wchar_t origName[MAX_PATH + 1];
memset (fnameBuf, 0, MAX_PATH + 1);
memset (origName, 0, MAX_PATH + 1);
snwprintf (origName, MAX_PATH, L"%s%s", tmpPath, name);
fileExt = wcschr (wcsrchr(origName, '\\'), '.');
if (fileExt)
{
wcsncpy (fnameBuf, origName, fileExt - origName);
}
else
{
wcsncpy (fnameBuf, origName, wcslen (origName));
}
snwprintf (outName, MAX_PATH, L"%s%i%s", fnameBuf, tries++,
fileExt ? fileExt : L"");
if (tries > 100)
{
/* You have to know when to give up,.. */
log_error ("%s:%s: Could not get a name out of 100 tries",
SRCNAME, __func__);
xfree (outName);
return NULL;
}
}
return outName;
}
/** Get the Gpg4win Install directory.
*
* Looks first for the Gpg4win 3.x registry key. Then for the Gpg4win
* 2.x registry key. And checks that the directory can be read.
*
* @returns NULL if no dir could be found. Otherwise a malloced string.
*/
char *
get_gpg4win_dir()
{
const char *g4win_keys[] = {GPG4WIN_REGKEY_3,
GPG4WIN_REGKEY_2,
NULL};
const char **key;
for (key = g4win_keys; *key; key++)
{
char *tmp = read_w32_registry_string (NULL, *key, "Install Directory");
if (!tmp)
{
continue;
}
if (!access(tmp, R_OK))
{
return tmp;
}
else
{
log_debug ("Failed to access: %s\n", tmp);
xfree (tmp);
}
}
return NULL;
}
static void
epoch_to_file_time (unsigned long time, LPFILETIME pft)
{
LONGLONG ll;
ll = Int32x32To64(time, 10000000) + 116444736000000000;
pft->dwLowDateTime = (DWORD)ll;
pft->dwHighDateTime = ll >> 32;
}
char *
format_date_from_gpgme (unsigned long time)
{
wchar_t buf[256];
FILETIME ft;
SYSTEMTIME st;
epoch_to_file_time (time, &ft);
FileTimeToSystemTime(&ft, &st);
int ret = GetDateFormatEx (NULL,
DATE_SHORTDATE,
&st,
NULL,
buf,
256,
NULL);
if (ret == 0)
{
return NULL;
}
return wchar_to_utf8 (buf);
}
/* Return the name of the default UI server. This name is used to
auto start an UI server if an initial connect failed. */
char *
get_uiserver_name (void)
{
char *name = NULL;
char *dir, *uiserver, *p;
int extra_arglen = 9;
const char * server_names[] = {"kleopatra.exe",
"bin\\kleopatra.exe",
"gpa.exe",
"bin\\gpa.exe",
NULL};
const char **tmp = NULL;
dir = get_gpg4win_dir ();
if (!dir)
{
log_error ("Failed to find gpg4win dir");
return NULL;
}
uiserver = read_w32_registry_string (NULL, GPG4WIN_REGKEY_3,
"UI Server");
if (!uiserver)
{
uiserver = read_w32_registry_string (NULL, GPG4WIN_REGKEY_2,
"UI Server");
}
if (uiserver)
{
- name = xmalloc (strlen (dir) + strlen (uiserver) + extra_arglen + 2);
+ name = (char*) xmalloc (strlen (dir) + strlen (uiserver) + extra_arglen + 2);
strcpy (stpcpy (stpcpy (name, dir), "\\"), uiserver);
for (p = name; *p; p++)
if (*p == '/')
*p = '\\';
xfree (uiserver);
}
if (name && !access (name, F_OK))
{
/* Set through registry and is accessible */
xfree(dir);
return name;
}
/* Fallbacks */
for (tmp = server_names; *tmp; tmp++)
{
if (name)
{
xfree (name);
}
- name = xmalloc (strlen (dir) + strlen (*tmp) + extra_arglen + 2);
+ name = (char *) xmalloc (strlen (dir) + strlen (*tmp) + extra_arglen + 2);
strcpy (stpcpy (stpcpy (name, dir), "\\"), *tmp);
for (p = name; *p; p++)
if (*p == '/')
*p = '\\';
if (!access (name, F_OK))
{
/* Found a viable candidate */
if (strstr (name, "kleopatra.exe"))
{
strcat (name, " --daemon");
}
xfree (dir);
return name;
}
}
xfree (dir);
log_error ("Failed to find a viable UIServer");
return NULL;
}
int
has_high_integrity(HANDLE hToken)
{
PTOKEN_MANDATORY_LABEL integrity_label = NULL;
DWORD integrity_level = 0,
size = 0;
if (hToken == NULL || hToken == INVALID_HANDLE_VALUE)
{
log_debug ("Invalid parameters.");
return 0;
}
/* Get the required size */
if (!GetTokenInformation (hToken, TokenIntegrityLevel,
NULL, 0, &size))
{
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
log_debug ("Failed to get required size.\n");
return 0;
}
}
integrity_label = (PTOKEN_MANDATORY_LABEL) LocalAlloc(0, size);
if (integrity_label == NULL)
{
log_debug ("Failed to allocate label. \n");
return 0;
}
if (!GetTokenInformation (hToken, TokenIntegrityLevel,
integrity_label, size, &size))
{
log_debug ("Failed to get integrity level.\n");
LocalFree(integrity_label);
return 0;
}
/* Get the last integrity level */
integrity_level = *GetSidSubAuthority(integrity_label->Label.Sid,
(DWORD)(UCHAR)(*GetSidSubAuthorityCount(
integrity_label->Label.Sid) - 1));
LocalFree (integrity_label);
return integrity_level >= SECURITY_MANDATORY_HIGH_RID;
}
int
is_elevated()
{
int ret = 0;
HANDLE hToken = NULL;
if (OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &hToken))
{
DWORD elevation;
DWORD cbSize = sizeof (DWORD);
if (GetTokenInformation (hToken, TokenElevation, &elevation,
sizeof (TokenElevation), &cbSize))
{
ret = elevation;
}
}
/* Elevation will be true and ElevationType TokenElevationTypeFull even
if the token is a user token created by SAFER so we additionally
check the integrity level of the token which will only be high in
the real elevated process and medium otherwise. */
ret = ret && has_high_integrity (hToken);
if (hToken)
CloseHandle (hToken);
return ret;
}
int
gpgol_message_box (HWND parent, const char *utf8_text,
const char *utf8_caption, UINT type)
{
wchar_t *w_text = utf8_to_wchar (utf8_text);
wchar_t *w_caption = utf8_to_wchar (utf8_caption);
int ret = 0;
MSGBOXPARAMSW mbp;
mbp.cbSize = sizeof (MSGBOXPARAMS);
mbp.hwndOwner = parent;
mbp.hInstance = glob_hinst;
mbp.lpszText = w_text;
mbp.lpszCaption = w_caption;
mbp.dwStyle = type | MB_USERICON;
mbp.dwLanguageId = MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT);
mbp.lpfnMsgBoxCallback = NULL;
mbp.dwContextHelpId = 0;
mbp.lpszIcon = (LPCWSTR) MAKEINTRESOURCE (IDI_GPGOL_LOCK_ICON);
ret = MessageBoxIndirectW (&mbp);
xfree (w_text);
xfree (w_caption);
return ret;
}
void
gpgol_bug (HWND parent, int code)
{
const char *bugmsg = utf8_gettext ("Operation failed.\n\n"
"This is usually caused by a bug in GpgOL or an error in your setup.\n"
"Please see https://www.gpg4win.org/reporting-bugs.html "
"or ask your Administrator for support.");
char *with_code;
gpgrt_asprintf (&with_code, "%s\nCode: %i", bugmsg, code);
gpgol_message_box (parent,
with_code,
_("GpgOL Error"), MB_OK);
xfree (with_code);
return;
}
static char*
expand_path (const char *path)
{
DWORD len;
char *p;
len = ExpandEnvironmentStrings (path, NULL, 0);
if (!len)
{
return NULL;
}
len += 1;
- p = xcalloc (1, len+1);
+ p = (char *) xcalloc (1, len+1);
if (!p)
{
return NULL;
}
len = ExpandEnvironmentStrings (path, p, len);
if (!len)
{
xfree (p);
return NULL;
}
return p;
}
static int
load_config_value (HKEY hk, const char *path, const char *key, char **val)
{
HKEY h;
DWORD size=0, type;
int ec;
*val = NULL;
if (hk == NULL)
{
hk = HKEY_CURRENT_USER;
}
ec = RegOpenKeyEx (hk, path, 0, KEY_READ, &h);
if (ec != ERROR_SUCCESS)
{
return -1;
}
ec = RegQueryValueEx(h, key, NULL, &type, NULL, &size);
if (ec != ERROR_SUCCESS)
{
RegCloseKey (h);
return -1;
}
if (type == REG_EXPAND_SZ)
{
char tmp[256];
RegQueryValueEx (h, key, NULL, NULL, (BYTE*)tmp, &size);
*val = expand_path (tmp);
}
else
{
- *val = xcalloc(1, size+1);
+ *val = (char *) xcalloc(1, size+1);
ec = RegQueryValueEx (h, key, NULL, &type, (BYTE*)*val, &size);
if (ec != ERROR_SUCCESS)
{
xfree (*val);
*val = NULL;
RegCloseKey (h);
return -1;
}
}
RegCloseKey (h);
return 0;
}
static int
store_config_value (HKEY hk, const char *path, const char *key, const char *val)
{
HKEY h;
int type;
int ec;
if (hk == NULL)
{
hk = HKEY_CURRENT_USER;
}
ec = RegCreateKeyEx (hk, path, 0, NULL, REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS, NULL, &h, NULL);
if (ec != ERROR_SUCCESS)
{
log_debug_w32 (ec, "creating/opening registry key `%s' failed", path);
return -1;
}
type = strchr (val, '%')? REG_EXPAND_SZ : REG_SZ;
ec = RegSetValueEx (h, key, 0, type, (const BYTE*)val, strlen (val));
if (ec != ERROR_SUCCESS)
{
log_debug_w32 (ec, "saving registry key `%s'->`%s' failed", path, key);
RegCloseKey(h);
return -1;
}
RegCloseKey(h);
return 0;
}
/* Store a key in the registry with the key given by @key and the
value @value. */
int
store_extension_value (const char *key, const char *val)
{
return store_config_value (HKEY_CURRENT_USER, GPGOL_REGPATH, key, val);
}
/* Load a key from the registry with the key given by @key. The value is
returned in @val and needs to freed by the caller. */
int
load_extension_value (const char *key, char **val)
{
return load_config_value (HKEY_CURRENT_USER, GPGOL_REGPATH, key, val);
}
int
store_extension_subkey_value (const char *subkey,
const char *key,
const char *val)
{
int ret;
char *path;
gpgrt_asprintf (&path, "%s\\%s", GPGOL_REGPATH, subkey);
ret = store_config_value (HKEY_CURRENT_USER, path, key, val);
xfree (path);
return ret;
}
diff --git a/src/common.h b/src/common.h
index 265955c..52099fd 100644
--- a/src/common.h
+++ b/src/common.h
@@ -1,160 +1,129 @@
/* common.h - Common declarations for GpgOL
* Copyright (C) 2004 Timo Schulz
* Copyright (C) 2005, 2006, 2007, 2008 g10 Code GmbH
* Copyright (C) 2015, 2016 by Bundesamt für Sicherheit in der Informationstechnik
* Software engineering by Intevation 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
* 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 .
*/
#ifndef GPGOL_COMMON_H
#define GPGOL_COMMON_H
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include "common_indep.h"
#include
+/* i18n stuff */
+#include "w32-gettext.h"
+#define _(a) gettext (a)
+#define N_(a) gettext_noop (a)
+
+
/* Registry path to store plugin settings */
#define GPGOL_REGPATH "Software\\GNU\\GpgOL"
#ifdef __cplusplus
extern "C" {
#if 0
}
#endif
#endif
extern HINSTANCE glob_hinst;
extern UINT this_dll;
/*-- common.c --*/
void set_global_hinstance (HINSTANCE hinst);
-void center_window (HWND childwnd, HWND style);
-HBITMAP get_system_check_bitmap (int checked);
-char *get_save_filename (HWND root, const char *srcname);
-char *get_open_filename (HWND root, const char *title);
-char *utf8_to_wincp (const char *string);
-const char *default_homedir (void);
char *get_data_dir (void);
char *get_gpg4win_dir (void);
int store_extension_value (const char *key, const char *val);
int store_extension_subkey_value (const char *subkey, const char *key,
const char *val);
int load_extension_value (const char *key, char **val);
/* Get a temporary filename with and its name */
wchar_t *get_tmp_outfile (wchar_t *name, HANDLE *outHandle);
wchar_t *get_pretty_attachment_name (wchar_t *path, protocol_t protocol,
int signature);
-/*-- recipient-dialog.c --*/
-unsigned int recipient_dialog_box (gpgme_key_t **ret_rset);
-unsigned int recipient_dialog_box2 (gpgme_key_t *fnd, char **unknown,
- gpgme_key_t **ret_rset);
-
-/*-- passphrase-dialog.c --*/
-int signer_dialog_box (gpgme_key_t *r_key, char **r_passwd, int encrypting);
-gpgme_error_t passphrase_callback_box (void *opaque, const char *uid_hint,
- const char *pass_info,
- int prev_was_bad, int fd);
-void free_decrypt_key (struct passphrase_cb_s *ctx);
-const char *get_pubkey_algo_str (gpgme_pubkey_algo_t id);
-
-/*-- config-dialog.c --*/
-void config_dialog_box (HWND parent);
-
/*-- verify-dialog.c --*/
int verify_dialog_box (gpgme_protocol_t protocol,
gpgme_verify_result_t res,
const char *filename);
/*-- inspectors.cpp --*/
int initialize_inspectors (void);
#if __GNUC__ >= 4
# define GPGOL_GCC_A_SENTINEL(a) __attribute__ ((sentinel(a)))
#else
# define GPGOL_GCC_A_SENTINEL(a)
#endif
-/* i18n stuff */
-#include "w32-gettext.h"
-#define _(a) gettext (a)
-#define N_(a) gettext_noop (a)
-
-
/*-- common.c --*/
void fatal_error (const char *format, ...);
-char *wchar_to_utf8_2 (const wchar_t *string, size_t len);
-wchar_t *utf8_to_wchar2 (const char *string, size_t len);
char *read_w32_registry_string (const char *root, const char *dir,
const char *name);
char *percent_escape (const char *str, const char *extra);
void fix_linebreaks (char *str, int *len);
/* Format a date from gpgme (seconds since epoch)
with windows system locale. */
char *format_date_from_gpgme (unsigned long time);
/* Get the name of the uiserver */
char *get_uiserver_name (void);
int is_elevated (void);
/*-- main.c --*/
-const void *get_128bit_session_key (void);
-const void *get_64bit_session_marker (void);
-void *create_initialization_vector (size_t nbytes);
-
void read_options (void);
int write_options (void);
extern int g_ol_version_major;
-void log_window_hierarchy (HWND window, const char *fmt,
- ...) __attribute__ ((format (printf,2,3)));
-
void bring_to_front (HWND wid);
int gpgol_message_box (HWND parent, const char *utf8_text,
const char *utf8_caption, UINT type);
/* Show a bug message with the code. */
void gpgol_bug (HWND parent, int code);
void i18n_init (void);
#define ERR_CRYPT_RESOLVER_FAILED 1
#define ERR_WANTS_SEND_MIME_BODY 2
#define ERR_WANTS_SEND_INLINE_BODY 3
#define ERR_INLINE_BODY_TO_BODY 4
#define ERR_INLINE_BODY_INV_STATE 5
#ifdef __cplusplus
}
#endif
#endif /*GPGOL_COMMON_H*/
diff --git a/src/config-dialog.c b/src/config-dialog.c
deleted file mode 100644
index b2663f7..0000000
--- a/src/config-dialog.c
+++ /dev/null
@@ -1,96 +0,0 @@
-/* config-dialog.c
- * Copyright (C) 2005, 2008 g10 Code GmbH
- * Copyright (C) 2003 Timo Schulz
- *
- * 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 .
- */
-
-#include
-
-#include
-#include
-#include
-
-#include "common.h"
-#include "gpgol-ids.h"
-#include "dialogs.h"
-
-/* To avoid writing a dialog template for each language we use gettext
- for the labels and hope that there is enough space in the dialog to
- fit teh longest translation. */
-static void
-config_dlg_set_labels (HWND dlg)
-{
- static struct { int itemid; const char *label; } labels[] = {
- { IDC_T_DEBUG_LOGFILE, N_("Debug output (for analysing problems)")},
- { 0, NULL}
- };
- int i;
-
- for (i=0; labels[i].itemid; i++)
- SetDlgItemText (dlg, labels[i].itemid, _(labels[i].label));
-
-}
-
-static BOOL CALLBACK
-config_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
-{
- char name[MAX_PATH+1];
- int n;
- const char *s;
-
- (void)lparam;
-
- switch (msg)
- {
- case WM_INITDIALOG:
- center_window (dlg, 0);
- s = get_log_file ();
- SetDlgItemText (dlg, IDC_DEBUG_LOGFILE, s? s:"");
- config_dlg_set_labels (dlg);
- break;
-
- case WM_COMMAND:
- switch (LOWORD (wparam))
- {
- case IDOK:
- n = GetDlgItemText (dlg, IDC_DEBUG_LOGFILE, name, MAX_PATH-1);
- set_log_file (n>0?name:NULL);
- EndDialog (dlg, TRUE);
- break;
- }
- break;
- }
- return FALSE;
-}
-
-/* Display GPG configuration dialog. */
-void
-config_dialog_box (HWND parent)
-{
-#ifndef _WIN64
- int resid;
-
- resid = IDD_EXT_OPTIONS;
-
- if (!parent)
- parent = GetDesktopWindow ();
- DialogBoxParam (glob_hinst, (LPCTSTR)resid, parent, config_dlg_proc, 0);
-#else
- (void)parent;
- (void)config_dlg_proc;
-#endif
-}
diff --git a/src/gpgoladdin.cpp b/src/gpgoladdin.cpp
index b43ef6f..15fb475 100644
--- a/src/gpgoladdin.cpp
+++ b/src/gpgoladdin.cpp
@@ -1,1113 +1,1113 @@
/* gpgoladdin.cpp - Connect GpgOL to Outlook as an addin
* Copyright (C) 2013 Intevation GmbH
* 2015 by Bundesamt für Sicherheit in der Informationstechnik
* Software engineering by Intevation 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
#include "common.h"
#include "gpgoladdin.h"
#include "mymapi.h"
#include "mymapitags.h"
#include "mapihelp.h"
#include "oomhelp.h"
#include "olflange.h"
#include "gpgol-ids.h"
#include "ribbon-callbacks.h"
#include "eventsinks.h"
#include "eventsink.h"
#include "windowmessages.h"
#include "mail.h"
#include "addin-options.h"
#include
#include
#define ICON_SIZE_LARGE 32
#define ICON_SIZE_NORMAL 16
/* We use UTF-8 internally. */
#undef _
#define _(a) utf8_gettext (a)
ULONG addinLocks = 0;
bool can_unload = false;
static std::list g_ribbon_uis;
static GpgolAddin * addin_instance = NULL;
/* This is the main entry point for the addin
Outlook uses this function to query for an Object implementing
the IClassFactory interface.
*/
STDAPI DllGetClassObject (REFCLSID rclsid, REFIID riid, LPVOID* ppvObj)
{
if (!ppvObj)
return E_POINTER;
*ppvObj = NULL;
if (rclsid != CLSID_GPGOL)
return CLASS_E_CLASSNOTAVAILABLE;
/* Let the factory give the requested interface. */
GpgolAddinFactory* factory = new GpgolAddinFactory();
if (!factory)
return E_OUTOFMEMORY;
HRESULT hr = factory->QueryInterface (riid, ppvObj);
if(FAILED(hr))
{
*ppvObj = NULL;
delete factory;
}
return hr;
}
STDAPI DllCanUnloadNow()
{
/* This is called regularly to check if memory can be freed
by unloading the dll. The following unload will not call
any addin methods like disconnect etc. It will just
unload the Library. Any callbacks will become invalid.
So we _only_ say it's ok to unload if we were disconnected.
For the epic story behind the next line see GnuPG-Bug-Id 1837 */
return can_unload ? S_OK : S_FALSE;
}
/* Class factory */
STDMETHODIMP GpgolAddinFactory::QueryInterface (REFIID riid, LPVOID* ppvObj)
{
HRESULT hr = S_OK;
*ppvObj = NULL;
if ((IID_IUnknown == riid) || (IID_IClassFactory == riid))
*ppvObj = static_cast(this);
else
{
hr = E_NOINTERFACE;
LPOLESTR sRiid = NULL;
StringFromIID (riid, &sRiid);
/* Should not happen */
log_debug ("GpgolAddinFactory queried for unknown interface: %S \n", sRiid);
}
if (*ppvObj)
((LPUNKNOWN)*ppvObj)->AddRef();
return hr;
}
/* This actually creates the instance of our COM object */
STDMETHODIMP GpgolAddinFactory::CreateInstance (LPUNKNOWN punk, REFIID riid,
LPVOID* ppvObj)
{
(void)punk;
*ppvObj = NULL;
GpgolAddin* obj = GpgolAddin::get_instance();
if (NULL == obj)
return E_OUTOFMEMORY;
HRESULT hr = obj->QueryInterface (riid, ppvObj);
if (FAILED(hr))
{
LPOLESTR sRiid = NULL;
StringFromIID (riid, &sRiid);
fprintf(stderr, "failed to create instance for: %S", sRiid);
}
return hr;
}
/* GpgolAddin definition */
/* Constructor of GpgolAddin
Initializes members and creates the interface objects for the new
context. Does the DLL initialization if it has not been done
before.
The ref count is set by the factory after creation.
*/
GpgolAddin::GpgolAddin (void) : m_lRef(0),
m_application(nullptr),
m_addin(nullptr),
m_applicationEventSink(nullptr),
m_explorersEventSink(nullptr),
m_disabled(false),
m_hook(nullptr)
{
read_options ();
/* RibbonExtender is it's own object to avoid the pitfalls of
multiple inheritance
*/
m_ribbonExtender = new GpgolRibbonExtender();
}
GpgolAddin::~GpgolAddin (void)
{
if (m_disabled)
{
return;
}
log_debug ("%s:%s: Releasing Application Event Sink;",
SRCNAME, __func__);
gpgol_release (m_explorersEventSink);
gpgol_release (m_applicationEventSink);
write_options ();
UnhookWindowsHookEx (m_hook);
addin_instance = NULL;
log_debug ("%s:%s: Object deleted\n", SRCNAME, __func__);
}
STDMETHODIMP
GpgolAddin::QueryInterface (REFIID riid, LPVOID* ppvObj)
{
HRESULT hr = S_OK;
*ppvObj = NULL;
if (m_disabled)
return E_NOINTERFACE;
if ((riid == IID_IUnknown) || (riid == IID_IDTExtensibility2) ||
(riid == IID_IDispatch))
{
*ppvObj = (LPUNKNOWN) this;
}
else if (riid == IID_IRibbonExtensibility)
{
return m_ribbonExtender->QueryInterface (riid, ppvObj);
}
else
{
hr = E_NOINTERFACE;
#if 0
LPOLESTR sRiid = NULL;
StringFromIID(riid, &sRiid);
log_debug ("%s:%s: queried for unimplmented interface: %S",
SRCNAME, __func__, sRiid);
#endif
}
if (*ppvObj)
((LPUNKNOWN)*ppvObj)->AddRef();
return hr;
}
static void
addGpgOLToReg (const std::string &path)
{
HKEY h;
int err = RegOpenKeyEx (HKEY_CURRENT_USER, path.c_str(), 0,
KEY_ALL_ACCESS, &h);
if (err != ERROR_SUCCESS)
{
log_debug ("%s:%s: no DoNotDisableAddinList entry '%s' creating it",
SRCNAME, __func__, path.c_str ());
err = RegCreateKeyEx (HKEY_CURRENT_USER, path.c_str (), 0, NULL,
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
&h, NULL);
}
if (err != ERROR_SUCCESS)
{
log_error ("%s:%s: failed to create key.",
SRCNAME, __func__);
return;
}
DWORD type;
err = RegQueryValueEx (h, GPGOL_PROGID, NULL, &type, NULL, NULL);
if (err == ERROR_SUCCESS)
{
log_debug ("%s:%s: Found gpgol reg key. Leaving it unchanged.",
SRCNAME, __func__);
RegCloseKey (h);
return;
}
// No key exists. Create one.
DWORD dwTemp = 1;
err = RegSetValueEx (h, GPGOL_PROGID, 0, REG_DWORD, (BYTE*)&dwTemp, 4);
RegCloseKey (h);
if (err != ERROR_SUCCESS)
{
log_error ("%s:%s: failed to set registry value.",
SRCNAME, __func__);
}
else
{
log_debug ("%s:%s: added gpgol to %s",
SRCNAME, __func__, path.c_str ());
}
}
/* This is a bit evil as we basically disable outlooks resiliency
for us. But users are still able to manually disable the addon
or change the donotdisable setting to zero and we won't change
it.
It has been much requested by users that we do this automatically.
*/
static void
setupDoNotDisable ()
{
std::string path = "Software\\Microsoft\\Office\\";
path += std::to_string (g_ol_version_major);
path += ".0\\Outlook\\Resiliency\\DoNotDisableAddinList";
addGpgOLToReg (path);
path = "Software\\Microsoft\\Office\\";
path += std::to_string (g_ol_version_major);
path += ".0\\Outlook\\Resiliency\\AddinList";
addGpgOLToReg (path);
}
STDMETHODIMP
GpgolAddin::OnConnection (LPDISPATCH Application, ext_ConnectMode ConnectMode,
LPDISPATCH AddInInst, SAFEARRAY ** custom)
{
(void)custom;
char* version;
log_debug ("%s:%s: this is GpgOL %s\n",
SRCNAME, __func__, PACKAGE_VERSION);
can_unload = false;
m_application = Application;
m_application->AddRef();
m_addin = AddInInst;
version = get_oom_string (Application, "Version");
log_debug ("%s:%s: using GPGME %s\n",
SRCNAME, __func__, gpgme_check_version (NULL));
log_debug ("%s:%s: in Outlook %s\n",
SRCNAME, __func__, version);
g_ol_version_major = atoi (version);
if (!version || !strlen (version) ||
(strncmp (version, "14", 2) &&
strncmp (version, "15", 2) &&
strncmp (version, "16", 2)))
{
m_disabled = true;
log_debug ("%s:%s: Disabled addin for unsupported version.",
SRCNAME, __func__);
xfree (version);
return S_OK;
}
setupDoNotDisable ();
if (ConnectMode != ext_cm_Startup)
{
OnStartupComplete (custom);
}
return S_OK;
}
STDMETHODIMP
GpgolAddin::OnDisconnection (ext_DisconnectMode RemoveMode,
SAFEARRAY** custom)
{
(void)custom;
(void)RemoveMode;
log_debug ("%s:%s: cleaning up GpgolAddin object;",
SRCNAME, __func__);
/* Doing the wipe in the dtor is too late. Outlook
does not allow us any OOM calls then and only returns
"Unexpected error" in that case. Weird. */
if (Mail::closeAllMails_o ())
{
MessageBox (NULL,
"Failed to remove plaintext from at least one message.\n\n"
"Until GpgOL is activated again it is possible that the "
"plaintext of messages decrypted in this Session is saved "
"or transfered back to your mailserver.",
_("GpgOL"),
MB_ICONINFORMATION|MB_OK);
}
write_options();
can_unload = true;
return S_OK;
}
STDMETHODIMP
GpgolAddin::OnAddInsUpdate (SAFEARRAY** custom)
{
(void)custom;
return S_OK;
}
static void
check_html_preferred()
{
/* Check if HTML Mail should be enabled. */
HKEY h;
std::string path = "Software\\Microsoft\\Office\\";
path += std::to_string (g_ol_version_major);
path += ".0\\Outlook\\Options\\Mail";
opt.prefer_html = 1;
int err = RegOpenKeyEx (HKEY_CURRENT_USER, path.c_str() , 0, KEY_READ, &h);
if (err != ERROR_SUCCESS)
{
log_debug ("%s:%s: no mail options under %s",
SRCNAME, __func__, path.c_str());
return;
}
else
{
DWORD type;
err = RegQueryValueEx (h, "ReadAsPlain", NULL, &type, NULL, NULL);
if (err != ERROR_SUCCESS || type != REG_DWORD)
{
log_debug ("%s:%s: No type or key for ReadAsPlain",
SRCNAME, __func__);
return;
}
else
{
DWORD data;
DWORD size = sizeof (DWORD);
err = RegQueryValueEx (h, "ReadAsPlain", NULL, NULL, (LPBYTE)&data,
&size);
if (err != ERROR_SUCCESS)
{
log_debug ("%s:%s: Failed to find out ReadAsPlain",
SRCNAME, __func__);
return;
}
opt.prefer_html = data ? 0 : 1;
return;
}
}
}
static LPDISPATCH
install_explorer_sinks (LPDISPATCH application)
{
LPDISPATCH explorers = get_oom_object (application, "Explorers");
if (!explorers)
{
log_error ("%s:%s: No explorers object",
SRCNAME, __func__);
return nullptr;
}
int count = get_oom_int (explorers, "Count");
for (int i = 1; i <= count; i++)
{
std::string item = "Item(";
item += std::to_string (i) + ")";
LPDISPATCH explorer = get_oom_object (explorers, item.c_str());
if (!explorer)
{
log_error ("%s:%s: failed to get explorer %i",
SRCNAME, __func__, i);
continue;
}
/* Explorers delete themself in the close event of the explorer. */
LPDISPATCH sink = install_ExplorerEvents_sink (explorer);
if (!sink)
{
log_error ("%s:%s: failed to create eventsink for explorer %i",
SRCNAME, __func__, i);
}
else
{
log_oom_extra ("%s:%s: created sink %p for explorer %i",
SRCNAME, __func__, sink, i);
}
add_explorer (explorer);
gpgol_release (explorer);
}
/* Now install the event sink to handle new explorers */
return install_ExplorersEvents_sink (explorers);
}
STDMETHODIMP
GpgolAddin::OnStartupComplete (SAFEARRAY** custom)
{
(void)custom;
TRACEPOINT;
i18n_init ();
if (!create_responder_window())
{
log_error ("%s:%s: Failed to create the responder window;",
SRCNAME, __func__);
}
if (!m_application)
{
/* Should not happen as OnConnection should be called before */
log_error ("%s:%s: no application set;",
SRCNAME, __func__);
return E_NOINTERFACE;
}
if (!(m_hook = create_message_hook ()))
{
log_error ("%s:%s: Failed to create messagehook. ",
SRCNAME, __func__);
}
/* Set up categories */
const char *decCategory = _("GpgOL: Encrypted Message");
const char *verifyCategory = _("GpgOL: Trusted Sender Address");
ensure_category_exists (m_application, decCategory, 8);
ensure_category_exists (m_application, verifyCategory, 5);
install_forms ();
m_applicationEventSink = install_ApplicationEvents_sink (m_application);
m_explorersEventSink = install_explorer_sinks (m_application);
check_html_preferred ();
return S_OK;
}
STDMETHODIMP
GpgolAddin::OnBeginShutdown (SAFEARRAY * * custom)
{
(void)custom;
TRACEPOINT;
return S_OK;
}
STDMETHODIMP
GpgolAddin::GetTypeInfoCount (UINT *r_count)
{
*r_count = 0;
TRACEPOINT; /* Should not happen */
return S_OK;
}
STDMETHODIMP
GpgolAddin::GetTypeInfo (UINT iTypeInfo, LCID lcid,
LPTYPEINFO *r_typeinfo)
{
(void)iTypeInfo;
(void)lcid;
(void)r_typeinfo;
TRACEPOINT; /* Should not happen */
return S_OK;
}
STDMETHODIMP
GpgolAddin::GetIDsOfNames (REFIID riid, LPOLESTR *rgszNames,
UINT cNames, LCID lcid,
DISPID *rgDispId)
{
(void)riid;
(void)rgszNames;
(void)cNames;
(void)lcid;
(void)rgDispId;
TRACEPOINT; /* Should not happen */
return E_NOINTERFACE;
}
STDMETHODIMP
GpgolAddin::Invoke (DISPID dispid, REFIID riid, LCID lcid,
WORD flags, DISPPARAMS *parms, VARIANT *result,
EXCEPINFO *exepinfo, UINT *argerr)
{
USE_INVOKE_ARGS
TRACEPOINT; /* Should not happen */
return DISP_E_MEMBERNOTFOUND;
}
/* Definition of GpgolRibbonExtender */
GpgolRibbonExtender::GpgolRibbonExtender (void) : m_lRef(0)
{
}
GpgolRibbonExtender::~GpgolRibbonExtender (void)
{
log_debug ("%s:%s: cleaning up GpgolRibbonExtender object;",
SRCNAME, __func__);
log_debug ("%s:%s: Object deleted\n", SRCNAME, __func__);
}
STDMETHODIMP
GpgolRibbonExtender::QueryInterface(REFIID riid, LPVOID* ppvObj)
{
HRESULT hr = S_OK;
*ppvObj = NULL;
if ((riid == IID_IUnknown) || (riid == IID_IRibbonExtensibility) ||
(riid == IID_IDispatch))
{
*ppvObj = (LPUNKNOWN) this;
}
else
{
LPOLESTR sRiid = NULL;
StringFromIID (riid, &sRiid);
log_debug ("%s:%s: queried for unknown interface: %S",
SRCNAME, __func__, sRiid);
}
if (*ppvObj)
((LPUNKNOWN)*ppvObj)->AddRef();
return hr;
}
STDMETHODIMP
GpgolRibbonExtender::GetTypeInfoCount (UINT *r_count)
{
*r_count = 0;
TRACEPOINT; /* Should not happen */
return S_OK;
}
STDMETHODIMP
GpgolRibbonExtender::GetTypeInfo (UINT iTypeInfo, LCID lcid,
LPTYPEINFO *r_typeinfo)
{
(void)iTypeInfo;
(void)lcid;
(void)r_typeinfo;
TRACEPOINT; /* Should not happen */
return S_OK;
}
/* Good documentation of what this function is supposed to do can
be found at: http://msdn.microsoft.com/en-us/library/cc237568.aspx
There is also a very good blog explaining how Ribbon Extensibility
is supposed to work.
http://blogs.msdn.com/b/andreww/archive/2007/03/09/
why-is-it-so-hard-to-shim-iribbonextensibility.aspx
*/
#define ID_MAPPER(name,id) \
if (!wcscmp (rgszNames[i], name)) \
{ \
found = true; \
rgDispId[i] = id; \
break; \
} \
STDMETHODIMP
GpgolRibbonExtender::GetIDsOfNames (REFIID riid, LPOLESTR *rgszNames,
UINT cNames, LCID lcid,
DISPID *rgDispId)
{
(void)riid;
(void)lcid;
bool found = false;
if (!rgszNames || !cNames || !rgDispId)
{
return E_POINTER;
}
for (unsigned int i = 0; i < cNames; i++)
{
log_debug ("%s:%s: GetIDsOfNames for: %S",
SRCNAME, __func__, rgszNames[i]);
/* How this is supposed to work with cNames > 1 is unknown,
but we can just say that we won't support callbacks with
different parameters and just match the name (the first element)
and we give it one of our own dispIds's that are later handled in
the invoke part */
ID_MAPPER (L"btnDecrypt", ID_BTN_DECRYPT)
ID_MAPPER (L"btnDecryptLarge", ID_BTN_DECRYPT_LARGE)
ID_MAPPER (L"btnEncrypt", ID_BTN_ENCRYPT)
ID_MAPPER (L"btnEncryptLarge", ID_BTN_ENCRYPT_LARGE)
ID_MAPPER (L"btnEncryptSmall", IDI_ENCRYPT_20_PNG)
ID_MAPPER (L"btnSignSmall", IDI_SIGN_20_PNG)
ID_MAPPER (L"btnSignEncryptLarge", IDI_SIGN_ENCRYPT_40_PNG)
ID_MAPPER (L"btnEncryptFileLarge", ID_BTN_ENCSIGN_LARGE)
ID_MAPPER (L"btnSignLarge", ID_BTN_SIGN_LARGE)
ID_MAPPER (L"btnVerifyLarge", ID_BTN_VERIFY_LARGE)
ID_MAPPER (L"btnSigstateLarge", ID_BTN_SIGSTATE_LARGE)
/* MIME support: */
ID_MAPPER (L"encryptMime", ID_CMD_MIME_ENCRYPT)
ID_MAPPER (L"encryptMimeEx", ID_CMD_MIME_ENCRYPT_EX)
ID_MAPPER (L"signMime", ID_CMD_MIME_SIGN)
ID_MAPPER (L"signMimeEx", ID_CMD_MIME_SIGN_EX)
ID_MAPPER (L"encryptSignMime", ID_CMD_SIGN_ENCRYPT_MIME)
ID_MAPPER (L"encryptSignMimeEx", ID_CMD_SIGN_ENCRYPT_MIME_EX)
ID_MAPPER (L"getEncryptPressed", ID_GET_ENCRYPT_PRESSED)
ID_MAPPER (L"getEncryptPressedEx", ID_GET_ENCRYPT_PRESSED_EX)
ID_MAPPER (L"getSignPressed", ID_GET_SIGN_PRESSED)
ID_MAPPER (L"getSignPressedEx", ID_GET_SIGN_PRESSED_EX)
ID_MAPPER (L"getSignEncryptPressed", ID_GET_SIGN_ENCRYPT_PRESSED)
ID_MAPPER (L"getSignEncryptPressedEx", ID_GET_SIGN_ENCRYPT_PRESSED_EX)
ID_MAPPER (L"ribbonLoaded", ID_ON_LOAD)
ID_MAPPER (L"openOptions", ID_CMD_OPEN_OPTIONS)
ID_MAPPER (L"getSigLabel", ID_GET_SIG_LABEL)
ID_MAPPER (L"getSigSTip", ID_GET_SIG_STIP)
ID_MAPPER (L"getSigTip", ID_GET_SIG_TTIP)
ID_MAPPER (L"launchDetails", ID_LAUNCH_CERT_DETAILS)
ID_MAPPER (L"getIsDetailsEnabled", ID_GET_IS_DETAILS_ENABLED)
ID_MAPPER (L"getIsCrypto", ID_GET_IS_CRYPTO_MAIL)
ID_MAPPER (L"printDecrypted", ID_CMD_PRINT_DECRYPTED)
}
if (cNames > 1)
{
log_debug ("More then one name provided. Should not happen");
}
return found ? S_OK : E_NOINTERFACE;
}
STDMETHODIMP
GpgolRibbonExtender::Invoke (DISPID dispid, REFIID riid, LCID lcid,
WORD flags, DISPPARAMS *parms, VARIANT *result,
EXCEPINFO *exepinfo, UINT *argerr)
{
USE_INVOKE_ARGS
log_debug ("%s:%s: enter with dispid: %x",
SRCNAME, __func__, (int)dispid);
if (!(flags & DISPATCH_METHOD))
{
log_debug ("%s:%s: not called in method mode. Bailing out.",
SRCNAME, __func__);
return DISP_E_MEMBERNOTFOUND;
}
switch (dispid)
{
case ID_CMD_SIGN_ENCRYPT_MIME:
return mark_mime_action (parms->rgvarg[1].pdispVal,
OP_SIGN|OP_ENCRYPT, false);
case ID_CMD_SIGN_ENCRYPT_MIME_EX:
return mark_mime_action (parms->rgvarg[1].pdispVal,
OP_SIGN|OP_ENCRYPT, true);
case ID_CMD_MIME_ENCRYPT:
return mark_mime_action (parms->rgvarg[1].pdispVal, OP_ENCRYPT,
false);
case ID_CMD_MIME_SIGN:
return mark_mime_action (parms->rgvarg[1].pdispVal, OP_SIGN,
false);
case ID_GET_ENCRYPT_PRESSED:
return get_crypt_pressed (parms->rgvarg[0].pdispVal, OP_ENCRYPT,
result, false);
case ID_GET_SIGN_PRESSED:
return get_crypt_pressed (parms->rgvarg[0].pdispVal, OP_SIGN,
result, false);
case ID_GET_SIGN_ENCRYPT_PRESSED:
return get_crypt_pressed (parms->rgvarg[0].pdispVal,
OP_SIGN | OP_ENCRYPT,
result, false);
case ID_CMD_MIME_SIGN_EX:
return mark_mime_action (parms->rgvarg[1].pdispVal, OP_SIGN, true);
case ID_CMD_MIME_ENCRYPT_EX:
return mark_mime_action (parms->rgvarg[1].pdispVal, OP_ENCRYPT, true);
case ID_GET_ENCRYPT_PRESSED_EX:
return get_crypt_pressed (parms->rgvarg[0].pdispVal, OP_ENCRYPT,
result, true);
case ID_GET_SIGN_PRESSED_EX:
return get_crypt_pressed (parms->rgvarg[0].pdispVal, OP_SIGN,
result, true);
case ID_GET_SIGN_ENCRYPT_PRESSED_EX:
return get_crypt_pressed (parms->rgvarg[0].pdispVal, OP_SIGN | OP_ENCRYPT,
result, true);
case ID_GET_SIG_STIP:
return get_sig_stip (parms->rgvarg[0].pdispVal, result);
case ID_GET_SIG_TTIP:
return get_sig_ttip (parms->rgvarg[0].pdispVal, result);
case ID_GET_SIG_LABEL:
return get_sig_label (parms->rgvarg[0].pdispVal, result);
case ID_LAUNCH_CERT_DETAILS:
return launch_cert_details (parms->rgvarg[0].pdispVal);
case ID_GET_IS_DETAILS_ENABLED:
return get_is_details_enabled (parms->rgvarg[0].pdispVal, result);
case ID_ON_LOAD:
{
g_ribbon_uis.push_back (parms->rgvarg[0].pdispVal);
return S_OK;
}
case ID_CMD_OPEN_OPTIONS:
{
options_dialog_box (NULL);
return S_OK;
}
case ID_CMD_PRINT_DECRYPTED:
return print_decrypted (parms->rgvarg[0].pdispVal);
case ID_GET_IS_CRYPTO_MAIL:
return get_is_crypto_mail (parms->rgvarg[0].pdispVal, result);
case ID_BTN_ENCRYPT:
case ID_BTN_DECRYPT:
case ID_BTN_DECRYPT_LARGE:
case ID_BTN_ENCRYPT_LARGE:
case ID_BTN_ENCSIGN_LARGE:
case ID_BTN_SIGN_LARGE:
case ID_BTN_VERIFY_LARGE:
case IDI_SIGN_ENCRYPT_40_PNG:
case IDI_ENCRYPT_20_PNG:
case IDI_SIGN_20_PNG:
return getIcon (dispid, result);
case ID_BTN_SIGSTATE_LARGE:
return get_crypto_icon (parms->rgvarg[0].pdispVal, result);
}
log_debug ("%s:%s: leave", SRCNAME, __func__);
return DISP_E_MEMBERNOTFOUND;
}
/* Returns the XML markup for the various RibbonID's
The custom ui syntax is documented at:
http://msdn.microsoft.com/en-us/library/dd926139%28v=office.12%29.aspx
The outlook specific elements are documented at:
http://msdn.microsoft.com/en-us/library/office/ee692172%28v=office.14%29.aspx
*/
static STDMETHODIMP
GetCustomUI_MIME (BSTR RibbonID, BSTR * RibbonXml)
{
char * buffer = NULL;
/* const char *certManagerTTip =
_("Start the Certificate Management Software");
const char *certManagerSTip =
_("Open GPA or Kleopatra to manage your certificates. "
"You can use this you to generate your "
"own certificates. ");*/
const char *encryptTTip =
_("Encrypt the message");
const char *encryptSTip =
_("Encrypts the message and all attachments before sending");
const char *signTTip =
_("Sign the message");
const char *signSTip =
_("Sign the message and all attachments before sending");
const char *secureTTip =
_("Sign and encrypt the message");
const char *secureSTip =
_("Encrypting and cryptographically signing a message means that the "
"recipients can be sure that no one modified the message and only the "
"recipients can read it");
const char *optsSTip =
_("Open the settings dialog for GpgOL");
log_debug ("%s:%s: GetCustomUI_MIME for id: %ls", SRCNAME, __func__, RibbonID);
if (!RibbonXml || !RibbonID)
return E_POINTER;
if (!wcscmp (RibbonID, L"Microsoft.Outlook.Mail.Compose"))
{
gpgrt_asprintf (&buffer,
""
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
"", _("GpgOL"),
_("Secure"), secureTTip, secureSTip,
_("Sign"), signTTip, signSTip,
_("Encrypt"), encryptTTip, encryptSTip,
optsSTip
);
}
else if (!wcscmp (RibbonID, L"Microsoft.Outlook.Mail.Read"))
{
gpgrt_asprintf (&buffer,
""
" "
" "
" "
" "
" "
" "
" "
" "
"",
_("GpgOL"),
optsSTip
);
}
/* We don't use this code currently because calling the send
event for Inline Response mailitems fails. */
else if (!wcscmp (RibbonID, L"Microsoft.Outlook.Explorer") && g_ol_version_major > 14)
{
gpgrt_asprintf (&buffer,
""
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
"",
_("GpgOL"),
optsSTip,
_("GpgOL"),
_("Secure"), secureTTip, secureSTip,
_("Sign"), signTTip, signSTip,
_("Encrypt"), encryptTTip, encryptSTip,
optsSTip,
_("&Print decrypted")
);
}
else if (!wcscmp (RibbonID, L"Microsoft.Outlook.Explorer"))
{
// No TabComposeTools in Outlook 2010
gpgrt_asprintf (&buffer,
""
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
" "
"",
_("GpgOL"),
optsSTip
);
}
if (buffer)
{
- wchar_t *wbuf = utf8_to_wchar2 (buffer, strlen(buffer));
+ wchar_t *wbuf = utf8_to_wchar (buffer);
xfree (buffer);
*RibbonXml = SysAllocString (wbuf);
xfree (wbuf);
}
else
*RibbonXml = NULL;
return S_OK;
}
STDMETHODIMP
GpgolRibbonExtender::GetCustomUI (BSTR RibbonID, BSTR * RibbonXml)
{
return GetCustomUI_MIME (RibbonID, RibbonXml);
}
/* RibbonUi elements are created on demand but they are reused
in different inspectors. So far and from all documentation
I could find RibbonUi elments are never
deleted. When they are created the onLoad callback is called
to register them.
The callbacks registered in the XML description are only
executed on Load. So to have different information depending
on the available mails we have to invalidate the UI ourself.
This means that the callbacks will be reevaluated and the UI
Updated. Sadly we don't know which ribbon_ui needs updates
so we have to invalidate everything.
*/
void gpgoladdin_invalidate_ui ()
{
std::list::iterator it;
for (it = g_ribbon_uis.begin(); it != g_ribbon_uis.end(); ++it)
{
log_debug ("%s:%s: Invalidating ribbon: %p",
SRCNAME, __func__, *it);
invoke_oom_method (*it, "Invalidate", NULL);
}
}
GpgolAddin *
GpgolAddin::get_instance ()
{
if (!addin_instance)
{
addin_instance = new GpgolAddin ();
}
return addin_instance;
}