diff --git a/configure.ac b/configure.ac index 2d1fab6..c94f968 100644 --- a/configure.ac +++ b/configure.ac @@ -1,323 +1,311 @@ # configure.ac - for GpgOL # Copyright (C) 2005, 2006, 2007, 2008, 2011 g10 Code 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 autoconf to produce a configure script. AC_PREREQ(2.59) min_automake_version="1.14" # To build a release you need to create a tag with the version number # (git tag -s gpgol-k.n.m) and run "./autogen.sh --force". Please # bump the version number immediately *after* the release and do # another commit and push so that the git magic is able to work. m4_define([mym4_version], [2.1.2]) # Below is m4 magic to extract and compute the git revision number, # the decimalized short revision number, a beta version string and a # flag indicating a development version (mym4_isgit). Note that the # m4 processing is done by autoconf and not during the configure run. m4_define([mym4_revision], m4_esyscmd([git rev-parse --short HEAD | tr -d '\n\r'])) m4_define([mym4_revision_dec], m4_esyscmd_s([echo $((0x$(echo ]mym4_revision[|head -c 4)))])) m4_define([mym4_betastring], m4_esyscmd_s([git describe --match 'gpgol-[0-9].[0-9].*[0-9]' \ --long | awk -F- '$3!=0{print"-beta"$3}'])) m4_define([mym4_isgit],m4_if(mym4_betastring,[],[no],[yes])) m4_define([mym4_full_version],[mym4_version[]mym4_betastring]) AC_INIT([gpgol],[mym4_full_version], [http://bugs.gnupg.org]) # Bump up this value if you changed any form. GPGOL_FORMS_REVISION=335 NEED_GPG_ERROR_VERSION=1.9 NEED_GPGME_API=1 NEED_GPGME_VERSION=1.11.0 NEED_LIBASSUAN_API=2 NEED_LIBASSUAN_VERSION=2.0.0 GIT_COMMIT=0x[]mym4_revision GIT_COMMIT_DECIMAL=0x[]mym4_revision_dec PACKAGE=$PACKAGE_NAME PACKAGE_GT=${PACKAGE_NAME} VERSION=$PACKAGE_VERSION AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_SRCDIR(src/gpgol.def) AM_CONFIG_HEADER(config.h) AC_CANONICAL_TARGET() AM_INIT_AUTOMAKE AC_GNU_SOURCE have_gpg_error=no have_libassuan=no AC_SUBST(PACKAGE) AC_SUBST(PACKAGE_GT) AC_SUBST(VERSION) AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of this package]) AC_DEFINE_UNQUOTED(PACKAGE_GT, "$PACKAGE_GT", [Name of this package for gettext]) AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version of this package]) AC_DEFINE_UNQUOTED(PACKAGE_BUGREPORT, "$PACKAGE_BUGREPORT", [Bug report address]) AC_DEFINE_UNQUOTED(NEED_GPGME_VERSION, "$NEED_GPGME_VERSION", [Required version of GPGME]) AC_DEFINE_UNQUOTED(GIT_COMMIT, ${GIT_COMMIT}, [Current GIT commit]) AC_DEFINE_UNQUOTED(GPGOL_FORMS_REVISION, ${GPGOL_FORMS_REVISION}, [Current Forms revision]) BUILD_TIMESTAMP=`date --iso-8601=minutes` AC_SUBST(BUILD_TIMESTAMP) changequote(,)dnl BUILD_FILEVERSION=`echo "$VERSION" | sed 's/\([0-9.]*\).*/\1./;s/\./,/g'` changequote([,])dnl BUILD_FILEVERSION="${BUILD_FILEVERSION}${GIT_COMMIT_DECIMAL}" AC_SUBST(BUILD_FILEVERSION) AH_BOTTOM([ /* Some global constants. */ /* Force using of NLS for W32 even if no libintl has been found. This is okay because we have our own gettext implementation for W32. */ #if defined(HAVE_W32_SYSTEM) && !defined(ENABLE_NLS) #define ENABLE_NLS 1 #endif ]) AM_MAINTAINER_MODE # Checks for programs. AC_PROG_MAKE_SET AM_SANITY_CHECK missing_dir=`cd $ac_aux_dir && pwd` AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir) AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir) AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir) AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir) AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir) AC_PROG_AWK AC_PROG_CC AC_PROG_CPP AC_PROG_CXX AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_MAKE_SET AC_PROG_RANLIB AC_CHECK_TOOL(AR, ar, :) AC_CHECK_TOOL(DLLTOOL, dlltool, :) AC_CHECK_TOOL(WINDRES, windres, :) have_dosish_system=no have_w32_system=no case "${host}" in *-mingw32*) # special stuff for Windoze NT ac_cv_have_dev_random=no AC_DEFINE(USE_ONLY_8DOT3,1, [set this to limit filenames to the 8.3 format]) AC_DEFINE(HAVE_DRIVE_LETTERS,1, [defined if we must run on a stupid file system]) have_dosish_system=yes have_w32_system=yes ;; *) AC_MSG_NOTICE([[ *** *** This software is only useful for W32 systems. Use *** ./autogen.sh --build-w32 *** to prepare it for such a build. *** *** For your current host only tests will be built! ***]]) ;; esac if test "$have_dosish_system" = yes; then AC_DEFINE(HAVE_DOSISH_SYSTEM,1, [Defined if we run on some of the PCDOS like systems (DOS, Windoze. OS/2) with special properties like no file modes]) fi AM_CONDITIONAL(HAVE_DOSISH_SYSTEM, test "$have_dosish_system" = yes) if test "$have_w32_system" = yes; then AC_DEFINE(HAVE_W32_SYSTEM,1, [Defined if we run on a W32 API based system]) fi AM_CONDITIONAL(HAVE_W32_SYSTEM, test "$have_w32_system" = yes) AM_CONDITIONAL(BUILD_W64, test "$host" = "x86_64-w64-mingw32") # # Checks for libraries. # AM_PATH_GPGME("$NEED_GPGME_API:$NEED_GPGME_VERSION", have_gpgme=yes,have_gpgme=no) AM_PATH_GPGMEPP(have_gpgmepp=yes,have_gpgmepp=no) AM_PATH_GPG_ERROR("$NEED_GPG_ERROR_VERSION", have_gpg_error=yes,have_gpg_error=no) AC_DEFINE(GPG_ERR_SOURCE_DEFAULT, GPG_ERR_SOURCE_USER_2, [The default error source for GpgOL.]) AM_PATH_LIBASSUAN("$NEED_LIBASSUAN_API:$NEED_LIBASSUAN_VERSION", have_libassuan=yes,have_libassuan=no) # Note, that autogen.sh greps for the next line. AM_GNU_GETTEXT_VERSION([0.12.1]) AM_GNU_GETTEXT([external]) # We always want NLs, despite what the above macro figures out. USE_NLS=yes # Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS(string.h unistd.h langinfo.h termio.h locale.h) # Check for functions AC_REPLACE_FUNCS(stpcpy) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_C_INLINE AC_TYPE_SIZE_T AC_TYPE_SIGNAL AM_CONDITIONAL(CROSS_COMPILING, test x$cross_compiling = xyes) # Add some extra libs here so that previous tests don't fail for # mysterious reasons - the final link step should bail out. if test "$have_w32_system" = yes; then W32LIBS="-lwsock32" fi if test "$GCC" = yes; then CFLAGS="$CFLAGS -Wall -mms-bitfields -fno-strict-aliasing" CXXFLAGS="$CXXFLAGS -Wall -mms-bitfields -fno-strict-aliasing" # Hardening flags # Stack protection # -fstack-protector-all -Wstack-protector --param ssp-buffer-size=4 # causes gpgol not to be loaded by Outlook due to a runtime error. # This needs to be analysed but could be an incompatibility between # gcc's stack protection and COM / Outlook system calls. if test "$have_w32_system" = yes; then HARDENING="-Wl,--dynamicbase -Wl,--nxcompat -fno-exceptions -D_FORTIFY_SOURCE=2 -O0" else HARDENING="-fPIC" fi CFLAGS="$CFLAGS $HARDENING" CXXFLAGS="$CXXFLAGS $HARDENING" if test "$USE_MAINTAINER_MODE" = "yes"; then CFLAGS="$CFLAGS -Werror -Wcast-align -Wshadow -Wstrict-prototypes" CFLAGS="$CFLAGS -Wformat-security" CFLAGS="$CFLAGS -W -Wno-sign-compare" CXXFLAGS="$CXXFLAGS -Werror -Wcast-align -Wshadow" CXXFLAGS="$CXXFLAGS -Wformat-security" CXXFLAGS="$CXXFLAGS -W -Wno-sign-compare" fi AC_MSG_CHECKING([if gcc supports -Wno-pointer-sign]) _gcc_cflags_save=$CFLAGS CFLAGS="-Wno-pointer-sign" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[])],_gcc_psign=yes,_gcc_psign=no) AC_MSG_RESULT($_gcc_psign) CFLAGS=$_gcc_cflags_save; if test x"$_gcc_psign" = xyes ; then CFLAGS="$CFLAGS -Wno-pointer-sign" fi fi AC_SUBST(W32LIBS) -# -# This should be a temporary option that will eventually become the -# default. -# -AC_ARG_ENABLE(mime-send, - AC_HELP_STRING([--enable-mime-send], [Enable experimental send support for mime messages]), - mime_send=$enableval, mime_send=no) -if test "$mime_send" != "no"; then - AC_DEFINE(MIME_SEND, 1, - [Sending Mime messages will be supported.]) -fi - # # Print errors here so that they are visible all # together and the user can acquire them all together. # die=no if test "$have_gpg_error" = "no"; then die=yes AC_MSG_NOTICE([[ *** *** You need libgpg-error to build this program. ** This library is for example available at *** ftp://ftp.gnupg.org/pub/gcrypt/libgpg-error *** (at least version $NEED_GPG_ERROR_VERSION is required.) ***]]) fi if test "$have_gpgme" = "no"; then die=yes AC_MSG_NOTICE([[ *** *** You need gpgme to build this program. ** This library is for example available at *** ftp://ftp.gnupg.org/gcrypt/gpgme/ *** (at least version $NEED_GPGME_VERSION is required.) ***]]) fi if test "$have_gpgmepp" = "no"; then die=yes AC_MSG_NOTICE([[ *** *** You need the C++ language binding for gpgme to build this program. ** Ensure that GPGME was compiled with --enabled-languages=cpp ***]]) fi if test "$have_libassuan" = "no"; then die=yes AC_MSG_NOTICE([[ *** *** You need libassuan to build this program. *** This library is for example available at *** ftp://ftp.gnupg.org/pub/gcrypt/libassuan/ *** (at least version $NEED_LIBASSUAN_VERSION is required). ***]]) fi if test "$die" = "yes"; then AC_MSG_ERROR([[ *** *** Required libraries not found. Please consult the above messages *** and install them before running configure again. ***]]) fi AC_CONFIG_FILES([ Makefile src/Makefile src/icons/Makefile src/versioninfo.rc forms/Makefile doc/Makefile po/Makefile.in m4/Makefile tests/Makefile ]) AC_OUTPUT diff --git a/src/addin-options.cpp b/src/addin-options.cpp index 6677a30..8384efc 100644 --- a/src/addin-options.cpp +++ b/src/addin-options.cpp @@ -1,243 +1,207 @@ /* addin-options.cpp - Options for the Ol >= 2010 Addin * Copyright (C) 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 "config.h" #endif #include #include "dialogs.h" #include "common.h" #include "engine.h" #include #include #include /* 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 the longest translation.. */ static void set_labels (HWND dlg) { static struct { int itemid; const char *label; } labels[] = { { IDC_G_GENERAL, N_("General")}, { IDC_ENABLE_SMIME, N_("Enable the S/MIME support")}, -#ifndef MIME_SEND - { IDC_MIME_UI, N_("Enable simplified interface (experimental)")}, -#endif { IDC_G_SEND, N_("Message sending")}, { IDC_ENCRYPT_DEFAULT, N_("&Encrypt new messages by default")}, { IDC_SIGN_DEFAULT, N_("&Sign new messages by default")}, { IDC_INLINE_PGP, N_("&Send OpenPGP mails without " "attachments as PGP/Inline")}, { IDC_REPLYCRYPT, N_("S&elect crypto settings automatically " "for reply and forward")}, { IDC_AUTORRESOLVE, N_("&Resolve recipient keys automatically")}, { IDC_GPG_OPTIONS, N_("Debug...")}, { IDC_GPG_CONF, N_("Configure GnuPG")}, { IDC_VERSION_INFO, N_("Version ")VERSION}, { 0, NULL} }; int i; for (i=0; labels[i].itemid; i++) SetDlgItemText (dlg, labels[i].itemid, _(labels[i].label)); } - -/** Enable or disable options that are only relvant for mime ui */ -static void -enable_disable_opts (HWND hDlg) -{ - BOOL enable = opt.mime_ui ? TRUE : FALSE; - EnableWindow (GetDlgItem (hDlg, IDC_ENCRYPT_DEFAULT), enable); - EnableWindow (GetDlgItem (hDlg, IDC_SIGN_DEFAULT), enable); - char *uiserver = get_uiserver_name (); - if (!uiserver && !opt.enable_smime) - { - EnableWindow (GetDlgItem (hDlg, IDC_AUTORRESOLVE), FALSE); - } - xfree (uiserver); -} - static void launch_kleo_config (HWND hDlg) { char *uiserver = get_uiserver_name (); bool showError = false; if (uiserver) { std::string path (uiserver); xfree (uiserver); if (path.find("kleopatra.exe") != std::string::npos) { size_t dpos; if ((dpos = path.find(" --daemon")) != std::string::npos) { path.erase(dpos, strlen(" --daemon")); } auto ctx = GpgME::Context::createForEngine(GpgME::SpawnEngine); if (!ctx) { log_error ("%s:%s: No spawn engine.", SRCNAME, __func__); } std::string parentWid = std::to_string ((int) (intptr_t) hDlg); const char *argv[] = {path.c_str(), "--config", "--parent-windowid", parentWid.c_str(), NULL }; log_debug ("%s:%s: Starting %s %s %s", SRCNAME, __func__, path.c_str(), argv[1], argv[2]); GpgME::Data d(GpgME::Data::null); ctx->spawnAsync(path.c_str(), argv, d, d, d, (GpgME::Context::SpawnFlags) ( GpgME::Context::SpawnAllowSetFg | GpgME::Context::SpawnShowWindow)); } else { showError = true; } } else { showError = true; } if (showError) { MessageBox (NULL, _("Could not find Kleopatra.\n" "Please reinstall Gpg4win with the Kleopatra component enabled."), _("GpgOL"), MB_ICONINFORMATION|MB_OK); } } static INT_PTR CALLBACK options_window_proc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { (void)lParam; switch (uMsg) { case WM_INITDIALOG: { SendDlgItemMessage (hDlg, IDC_ENABLE_SMIME, BM_SETCHECK, !!opt.enable_smime, 0L); SendDlgItemMessage (hDlg, IDC_ENCRYPT_DEFAULT, BM_SETCHECK, !!opt.encrypt_default, 0L); SendDlgItemMessage (hDlg, IDC_SIGN_DEFAULT, BM_SETCHECK, !!opt.sign_default, 0L); -#ifndef MIME_SEND - SendDlgItemMessage (hDlg, IDC_MIME_UI, BM_SETCHECK, - !!opt.mime_ui, 0L); -#endif SendDlgItemMessage (hDlg, IDC_INLINE_PGP, BM_SETCHECK, !!opt.inline_pgp, 0L); SendDlgItemMessage (hDlg, IDC_REPLYCRYPT, BM_SETCHECK, !!opt.reply_crypt, 0L); SendDlgItemMessage (hDlg, IDC_AUTORRESOLVE, BM_SETCHECK, !!opt.autoresolve, 0L); - enable_disable_opts (hDlg); set_labels (hDlg); ShowWindow (GetDlgItem (hDlg, IDC_GPG_OPTIONS), opt.enable_debug ? SW_SHOW : SW_HIDE); } return 1; case WM_LBUTTONDOWN: { return 1; } case WM_COMMAND: switch (LOWORD (wParam)) { case IDOK: { opt.enable_smime = !!SendDlgItemMessage (hDlg, IDC_ENABLE_SMIME, BM_GETCHECK, 0, 0L); opt.encrypt_default = !!SendDlgItemMessage (hDlg, IDC_ENCRYPT_DEFAULT, BM_GETCHECK, 0, 0L); opt.sign_default = !!SendDlgItemMessage (hDlg, IDC_SIGN_DEFAULT, BM_GETCHECK, 0, 0L); -#ifndef MIME_SEND - int mime_ui_old = opt.mime_ui; - opt.mime_ui = !!SendDlgItemMessage - (hDlg, IDC_MIME_UI, BM_GETCHECK, 0, 0L); - if (opt.mime_ui != mime_ui_old) - { - MessageBox (NULL, - _("Changing the interface requires a restart of Outlook."), - _("GpgOL"), - MB_ICONINFORMATION|MB_OK); - } -#endif opt.inline_pgp = !!SendDlgItemMessage (hDlg, IDC_INLINE_PGP, BM_GETCHECK, 0, 0L); opt.reply_crypt = !!SendDlgItemMessage (hDlg, IDC_REPLYCRYPT, BM_GETCHECK, 0, 0L); opt.autoresolve = !!SendDlgItemMessage (hDlg, IDC_AUTORRESOLVE, BM_GETCHECK, 0, 0L); write_options (); EndDialog (hDlg, TRUE); break; } case IDC_GPG_CONF: launch_kleo_config (hDlg); break; case IDC_GPG_OPTIONS: config_dialog_box (hDlg); break; } case WM_SYSCOMMAND: switch (LOWORD (wParam)) { case SC_CLOSE: EndDialog (hDlg, TRUE); } break; } return 0; } void options_dialog_box (HWND parent) { int resid; resid = IDD_ADDIN_OPTIONS; if (!parent) parent = GetDesktopWindow (); DialogBoxParam (glob_hinst, MAKEINTRESOURCE (resid), parent, options_window_proc, 0); } diff --git a/src/common.h b/src/common.h index bd55a13..177bf6a 100644 --- a/src/common.h +++ b/src/common.h @@ -1,165 +1,159 @@ /* 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 -#ifdef MIME_SEND -# define MIME_UI_DEFAULT 1 -#else -# define MIME_UI_DEFAULT 0 -#endif - /* 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); #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/common_indep.h b/src/common_indep.h index adfc8bf..7332dbd 100644 --- a/src/common_indep.h +++ b/src/common_indep.h @@ -1,408 +1,407 @@ #ifndef COMMON_INDEP_H #define COMMON_INDEP_H /* common_indep.h - Common, platform indepentent routines used by GpgOL * Copyright (C) 2005, 2007, 2008 g10 Code GmbH * Copyright (C) 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 . */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include "xmalloc.h" #ifdef HAVE_W32_SYSTEM /* Not so independenent ;-) need this for logging HANDLE */ # include #endif /* The Registry key used by Gpg4win. */ #ifdef _WIN64 # define GPG4WIN_REGKEY_2 "Software\\Wow6432Node\\GNU\\GnuPG" #else # define GPG4WIN_REGKEY_2 "Software\\GNU\\GnuPG" #endif #ifdef _WIN64 # define GPG4WIN_REGKEY_3 "Software\\Wow6432Node\\Gpg4win" #else # define GPG4WIN_REGKEY_3 "Software\\Gpg4win" #endif /* Identifiers for the protocol. We use different one than those use by gpgme. FIXME: We might want to define an unknown protocol to non-null and define such a value also in gpgme. */ typedef enum { PROTOCOL_UNKNOWN = 0, PROTOCOL_OPENPGP = 1000, PROTOCOL_SMIME = 1001 } protocol_t; /* Possible options for the recipient dialog. */ enum { OPT_FLAG_TEXT = 2, OPT_FLAG_FORCE = 4, OPT_FLAG_CANCEL = 8 }; typedef enum { GPG_FMT_NONE = 0, /* do not encrypt attachments */ GPG_FMT_CLASSIC = 1, /* encrypt attachments without any encoding */ GPG_FMT_PGP_PEF = 2 /* use the PGP partioned encoding format (PEF) */ } gpgol_format_t; /* Type of a message. */ typedef enum { OPENPGP_NONE = 0, OPENPGP_MSG, OPENPGP_SIG, OPENPGP_CLEARSIG, OPENPGP_PUBKEY, /* Note, that this type is only partly supported */ OPENPGP_SECKEY /* Note, that this type is only partly supported */ } openpgp_t; /* The list of message types we support in GpgOL. */ typedef enum { MSGTYPE_UNKNOWN = 0, MSGTYPE_SMIME, /* Original SMIME class. */ MSGTYPE_GPGOL, MSGTYPE_GPGOL_MULTIPART_SIGNED, MSGTYPE_GPGOL_MULTIPART_ENCRYPTED, MSGTYPE_GPGOL_OPAQUE_SIGNED, MSGTYPE_GPGOL_OPAQUE_ENCRYPTED, MSGTYPE_GPGOL_CLEAR_SIGNED, MSGTYPE_GPGOL_PGP_MESSAGE, MSGTYPE_GPGOL_WKS_CONFIRMATION } msgtype_t; typedef enum { ATTACHTYPE_UNKNOWN = 0, ATTACHTYPE_MOSS = 1, /* The original MOSS message (ie. a S/MIME or PGP/MIME message. */ ATTACHTYPE_FROMMOSS = 2, /* Attachment created from MOSS. */ ATTACHTYPE_MOSSTEMPL = 3, /* Attachment has been created in the course of sending a message */ ATTACHTYPE_PGPBODY = 4, /* Attachment contains the original PGP message body of PGP inline encrypted messages. */ ATTACHTYPE_FROMMOSS_DEC = 5 /* A FROMMOSS attachment that has been temporarily decrypted and needs to be encrypted before it is written back into storage. */ } attachtype_t; /* An object to collect information about one MAPI attachment. */ struct mapi_attach_item_s { int end_of_table; /* True if this is the last plus one entry of the table. */ void *private_mapitable; /* Only for use by mapi_release_attach_table. */ int mapipos; /* The position which needs to be passed to MAPI to open the attachment. -1 means that there is no valid attachment. */ int method; /* MAPI attachment method. */ char *filename; /* Malloced filename of this attachment or NULL. */ /* Malloced string with the MIME attrib or NULL. Parameters are stripped off thus a compare against "type/subtype" is sufficient. */ char *content_type; /* If not NULL the parameters of the content_type. */ const char *content_type_parms; /* If not NULL the content_id */ char *content_id; /* The attachment type from Property GpgOL Attach Type. */ attachtype_t attach_type; }; typedef struct mapi_attach_item_s mapi_attach_item_t; /* Passphrase callback structure. */ struct passphrase_cb_s { gpgme_key_t signer; gpgme_ctx_t ctx; char keyid[16+1]; char *user_id; char *pass; int opts; int ttl; /* TTL of the passphrase. */ unsigned int decrypt_cmd:1; /* 1 = show decrypt dialog, otherwise secret key selection. */ unsigned int hide_pwd:1; unsigned int last_was_bad:1; }; /* Global options - initialized to default by main.c. */ #ifdef __cplusplus extern "C" { #if 0 } #endif #endif #ifdef __cplusplus extern #endif struct { int enable_debug; /* Enable extra debug options. Values larger than 1 increases the debug log verbosity. */ int enable_smime; /* Enable S/MIME support. */ int passwd_ttl; /* Time in seconds the passphrase is stored. */ protocol_t default_protocol;/* The default protocol. */ int encrypt_default; /* Encrypt by default. */ int sign_default; /* Sign by default. */ int enc_format; /* Encryption format for attachments. */ char *default_key; /* The key we want to always encrypt to. */ int enable_default_key; /* Enable the use of DEFAULT_KEY. */ int preview_decrypt; /* Decrypt in preview window. */ int prefer_html; /* Prefer html in html/text alternatives. */ int body_as_attachment; /* Present encrypted message as attachment. */ - int mime_ui; /* Only for Addin. Use the PGP/MIME ui */ int inline_pgp; /* Only for Addin. Use Inline PGP by default. */ int autoresolve; /* Autresolve keys with --locate-keys. */ int reply_crypt; /* Only for Addin. Encrypt / Sign based on cryptostatus. */ int deprecation_shown; /* Flag to save if deprecation warning was shown */ /* The compatibility flags. */ struct { unsigned int no_msgcache:1; unsigned int no_pgpmime:1; unsigned int no_oom_write:1; /* Don't write using Outlooks object model. */ unsigned int no_preview_info:1; /* No preview info about PGP/MIME. */ unsigned int old_reply_hack: 1; /* See gpgmsg.cpp:decrypt. */ unsigned int auto_decrypt: 1; /* Try to decrypt when clicked. */ unsigned int no_attestation: 1; /* Don't create an attestation. */ unsigned int use_mwfmo: 1; /* Use MsgWaitForMultipleObjects. */ } compat; /* The current git commit id. */ unsigned int git_commit; /* The forms revision number of the binary. */ int forms_revision; /* The stored number of the binary which showed the last announcement. */ int announce_number; /* Disable message processing until restart. This is required to implement message reverting as a perparation to remove GpgOL. */ int disable_gpgol; } opt; /* The state object used by b64_decode. */ struct b64_state_s { int idx; unsigned char val; int stop_seen; int invalid_encoding; }; typedef struct b64_state_s b64_state_t; /* Bit values used for extra log file verbosity. Value 1 is reserved to enable debug menu options. */ #define DBG_IOWORKER (1<<1) #define DBG_IOWORKER_EXTRA (1<<2) #define DBG_FILTER (1<<3) #define DBG_FILTER_EXTRA (1<<4) #define DBG_MEMORY (1<<5) #define DBG_COMMANDS (1<<6) #define DBG_MIME_PARSER (1<<7) #define DBG_MIME_DATA (1<<8) #define DBG_OOM (1<<9) #define DBG_OOM_EXTRA (1<<10) /* Macros to used in conditionals to enable debug output. */ #define debug_commands (opt.enable_debug & DBG_COMMANDS) size_t qp_decode (char *buffer, size_t length, int *r_slbrk); char *qp_encode (const char *input, size_t length, size_t* outlen); void b64_init (b64_state_t *state); size_t b64_decode (b64_state_t *state, char *buffer, size_t length); char * b64_encode (const char *input, size_t length); char *latin1_to_utf8 (const char *string); char *mem2str (char *dest, const void *src, size_t n); char *trim_spaces (char *string); char *trim_trailing_spaces (char *string); /* To avoid that a compiler optimizes certain memset calls away, these macros may be used instead. */ #define wipememory2(_ptr,_set,_len) do { \ volatile char *_vptr=(volatile char *)(_ptr); \ size_t _vlen=(_len); \ while(_vlen) { *_vptr=(_set); _vptr++; _vlen--; } \ } while(0) #define wipememory(_ptr,_len) wipememory2(_ptr,0,_len) #define wipestring(_ptr) do { \ volatile char *_vptr=(volatile char *)(_ptr); \ while(*_vptr) { *_vptr=0; _vptr++; } \ } while(0) #define debug_oom (opt.enable_debug & DBG_OOM) #define debug_oom_extra (opt.enable_debug & DBG_OOM_EXTRA) void log_debug (const char *fmt, ...) __attribute__ ((format (printf,1,2))); void log_error (const char *fmt, ...) __attribute__ ((format (printf,1,2))); void log_vdebug (const char *fmt, va_list a); void log_debug_w32 (int w32err, const char *fmt, ...) __attribute__ ((format (printf,2,3))); void log_error_w32 (int w32err, const char *fmt, ...) __attribute__ ((format (printf,2,3))); void log_hexdump (const void *buf, size_t buflen, const char *fmt, ...) __attribute__ ((format (printf,3,4))); #define log_oom if (opt.enable_debug & DBG_OOM) log_debug #define log_oom_extra if (opt.enable_debug & DBG_OOM_EXTRA) log_debug #define log_mime_parser if (opt.enable_debug & DBG_MIME_PARSER) log_debug #define log_mime_data if (opt.enable_debug & DBG_MIME_DATA) log_debug #define gpgol_release(X) \ { \ if (X && opt.enable_debug & DBG_OOM_EXTRA) \ { \ log_debug ("%s:%s: Object: %p released ref: %lu \n", \ SRCNAME, __func__, X, X->Release()); \ } \ else if (X) \ { \ X->Release(); \ } \ } const char *log_srcname (const char *s); #define SRCNAME log_srcname (__FILE__) #define TRACEPOINT log_debug ("%s:%s:%d: tracepoint\n", \ SRCNAME, __func__, __LINE__); const char *get_log_file (void); void set_log_file (const char *name); void set_default_key (const char *name); /*-- Convenience macros. -- */ #define DIM(v) (sizeof(v)/sizeof((v)[0])) #define DIMof(type,member) DIM(((type *)0)->member) /*-- Macros to replace ctype ones to avoid locale problems. --*/ #define spacep(p) (*(p) == ' ' || *(p) == '\t') #define digitp(p) (*(p) >= '0' && *(p) <= '9') #define hexdigitp(a) (digitp (a) \ || (*(a) >= 'A' && *(a) <= 'F') \ || (*(a) >= 'a' && *(a) <= 'f')) /* Note this isn't identical to a C locale isspace() without \f and \v, but works for the purposes used here. */ #define ascii_isspace(a) ((a)==' ' || (a)=='\n' || (a)=='\r' || (a)=='\t') /* The atoi macros assume that the buffer has only valid digits. */ #define atoi_1(p) (*(p) - '0' ) #define atoi_2(p) ((atoi_1(p) * 10) + atoi_1((p)+1)) #define atoi_4(p) ((atoi_2(p) * 100) + atoi_2((p)+2)) #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \ *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10)) #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1)) #define xtoi_4(p) ((xtoi_2(p) * 256) + xtoi_2((p)+2)) #define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A')) #define tohex_lower(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'a')) /***** Inline functions. ****/ /* Return true if LINE consists only of white space (up to and including the LF). */ static inline int trailing_ws_p (const char *line) { for ( ; *line && *line != '\n'; line++) if (*line != ' ' && *line != '\t' && *line != '\r') return 0; return 1; } /* An strcmp variant with the compare ending at the end of B. */ static inline int tagcmp (const char *a, const char *b) { return strncmp (a, b, strlen (b)); } #ifdef HAVE_W32_SYSTEM extern HANDLE log_mutex; #endif /***** Missing functions. ****/ #ifndef HAVE_STPCPY static inline char * _gpgol_stpcpy (char *a, const char *b) { while (*b) *a++ = *b++; *a = 0; return a; } #define stpcpy(a,b) _gpgol_stpcpy ((a), (b)) #endif /*!HAVE_STPCPY*/ #ifdef _WIN64 #define SIZE_T_FORMAT "%I64u" #else # ifdef HAVE_W32_SYSTEM # define SIZE_T_FORMAT "%u" # else # define SIZE_T_FORMAT "%lu" # endif #endif /* The length of the boundary - the buffer needs to be allocated one byte larger. */ #define BOUNDARYSIZE 20 char *generate_boundary (char *buffer); #ifdef __cplusplus } #endif #endif // COMMON_INDEP_H diff --git a/src/dialogs.h b/src/dialogs.h index be662ca..217b0d0 100644 --- a/src/dialogs.h +++ b/src/dialogs.h @@ -1,140 +1,78 @@ /* dialogs.h Resouces IDs for the dialogs. */ #ifndef DIALOGS_H #define DIALOGS_H -/* Ids used for bitmaps. There is some magic in the identifiers: In - the code we only use the first ID value and add 1 to find the mask. - */ -#define IDB_ENCRYPT_16 0x1000 -#define IDB_ENCRYPT_16M 0x1001 - -#define IDB_SIGN_16 0x1010 -#define IDB_SIGN_16M 0x1011 - -#define IDB_KEY_MANAGER_16 0x1020 -#define IDB_KEY_MANAGER_16M 0x1021 - -#define IDB_DECRYPT_16 0x1030 -#define IDB_DECRYPT_16M 0x1031 - -#define IDB_VERIFY_16 0x1040 -#define IDB_VERIFY_16M 0x1041 - -#define IDB_DECRYPT_VERIFY_16 0x1050 -#define IDB_DECRYPT_VERIFY_16M 0x1051 - #define IDB_LOGO 0x1060 /* Ids for the extended options dialog. */ #define IDD_EXT_OPTIONS 0x4110 #define IDC_T_DEBUG_LOGFILE 0x4120 #define IDC_DEBUG_LOGFILE 0x4130 -/* Ids for the recipient selection dialog. */ -#define IDD_ENC 0x4210 -#define IDC_ENC_RSET1 0x4220 -#define IDC_ENC_RSET2_T 0x4230 -#define IDC_ENC_RSET2 0x4240 -#define IDC_ENC_NOTFOUND_T 0x4250 -#define IDC_ENC_NOTFOUND 0x4260 - - -/* Ids for the two decryption dialogs. */ -#define IDD_DEC 0x4310 -#define IDD_DECEXT 0x4320 -#define IDC_DEC_KEYLIST 0x4330 -#define IDC_DEC_HINT 0x4340 -#define IDC_DEC_PASSINF 0x4350 -#define IDC_DEC_PASS 0x4360 -#define IDC_DEC_HIDE 0x4370 -#define IDC_DECEXT_RSET_T 0x4380 -#define IDC_DECEXT_RSET 0x4390 -#define IDC_DECEXT_KEYLIST 0x43A0 -#define IDC_DECEXT_HINT 0x43B0 -#define IDC_DECEXT_PASSINF 0x43C0 -#define IDC_DECEXT_PASS 0x43D0 -#define IDC_DECEXT_HIDE 0x43E0 - - -/* Ids for the verification dialog. */ -#define IDD_VRY 0x4410 -#define IDC_VRY_TIME_T 0x4420 -#define IDC_VRY_TIME 0x4430 -#define IDC_VRY_PKALGO_T 0x4440 -#define IDC_VRY_PKALGO 0x4450 -#define IDC_VRY_KEYID_T 0x4460 -#define IDC_VRY_KEYID 0x4470 -#define IDC_VRY_STATUS 0x4480 -#define IDC_VRY_ISSUER_T 0x4490 -#define IDC_VRY_ISSUER 0x44A0 -#define IDC_VRY_AKALIST_T 0x44B0 -#define IDC_VRY_AKALIST 0x44C0 -#define IDC_VRY_HINT 0x44D0 - /* Ids used for the main config dialog. */ #define IDD_GPG_OPTIONS 0x5000 #define IDD_ADDIN_OPTIONS 0x5001 #define IDC_TIME_PHRASES 0x5010 #define IDC_ENCRYPT_DEFAULT 0x5020 #define IDC_SIGN_DEFAULT 0x5030 #define IDC_ENCRYPT_WITH_STANDARD_KEY 0x5040 #define IDC_OPENPGP_DEFAULT 0x5050 #define IDC_SMIME_DEFAULT 0x5060 #define IDC_GPG_OPTIONS 0x5070 #define IDC_ADDIN_OPTIONS 0x5071 #define IDC_BITMAP 0x5080 #define IDC_VERSION_INFO 0x5090 #define IDC_ENCRYPT_TO 0x50A0 #define IDC_ENABLE_SMIME 0x50B0 #define IDC_PREVIEW_DECRYPT 0x50C0 #define IDC_PREFER_HTML 0x50D0 #define IDC_G_GENERAL 0x50E0 #define IDC_G_SEND 0x50F0 #define IDC_G_RECV 0x5100 #define IDC_BODY_AS_ATTACHMENT 0x5110 #define IDC_GPG_CONF 0x5120 #define IDC_G10CODE_STRING 0x5130 #define IDC_GPG4WIN_STRING 0x5131 #define IDC_START_CERTMAN 0x5132 #define IDC_MIME_UI 0x5133 #define IDC_INLINE_PGP 0x5134 #define IDC_AUTORRESOLVE 0x5135 #define IDC_REPLYCRYPT 0x5136 /* Ids for PNG Images */ #define IDI_ENCRYPT_16_PNG 0x6000 #define IDI_ENCRYPT_48_PNG 0x6010 #define IDI_DECRYPT_16_PNG 0x6020 #define IDI_DECRYPT_48_PNG 0x6030 #define IDI_ENCSIGN_FILE_48_PNG 0x6050 #define IDI_SIGN_48_PNG 0x6060 #define IDI_VERIFY_48_PNG 0x6070 #define IDI_EMBLEM_WARNING_64_PNG 0x6071 #define IDI_EMBLEM_QUESTION_64_PNG 0x6074 #define IDI_SIGN_ENCRYPT_40_PNG 0x6075 #define IDI_ENCRYPT_20_PNG 0x6076 #define IDI_SIGN_20_PNG 0x6077 #define IDI_GPGOL_LOCK_ICON 0x6078 /* Status icons */ #define ENCRYPT_ICON_OFFSET 0x10 #define IDI_LEVEL_0 0x6080 #define IDI_LEVEL_1 0x6081 #define IDI_LEVEL_2 0x6082 #define IDI_LEVEL_3 0x6083 #define IDI_LEVEL_4 0x6084 #define IDI_LEVEL_0_ENC (IDI_LEVEL_0 + ENCRYPT_ICON_OFFSET) #define IDI_LEVEL_1_ENC (IDI_LEVEL_1 + ENCRYPT_ICON_OFFSET) #define IDI_LEVEL_2_ENC (IDI_LEVEL_2 + ENCRYPT_ICON_OFFSET) #define IDI_LEVEL_3_ENC (IDI_LEVEL_3 + ENCRYPT_ICON_OFFSET) #define IDI_LEVEL_4_ENC (IDI_LEVEL_4 + ENCRYPT_ICON_OFFSET) #endif /*DIALOGS_H*/ diff --git a/src/dialogs.rc b/src/dialogs.rc index 4ee8f3b..5687041 100644 --- a/src/dialogs.rc +++ b/src/dialogs.rc @@ -1,362 +1,194 @@ /* dialogs.rc - GpgOL dialog resources. -*- c -*- * Copyright (C) 2004, 2005, 2006, 2007 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 . */ #include "dialogs.h" #include "config.h" #include "afxres.h" IDI_ENCRYPT_16_PNG RCDATA "icons/encrypt-16.png" IDI_ENCRYPT_48_PNG RCDATA "icons/encrypt-48.png" IDI_SIGN_48_PNG RCDATA "icons/sign-48.png" IDI_DECRYPT_16_PNG RCDATA "icons/decrypt-16.png" IDI_DECRYPT_48_PNG RCDATA "icons/decrypt-48.png" IDI_VERIFY_48_PNG RCDATA "icons/verify-48.png" IDI_ENCSIGN_FILE_48_PNG RCDATA "icons/encrypt-sign-file-48.png" IDI_LEVEL_0_ENC RCDATA "icons/level-0-enc.png" IDI_LEVEL_1_ENC RCDATA "icons/level-1-enc.png" /* We use the same icon for level 2 and 3 */ IDI_LEVEL_2_ENC RCDATA "icons/level-3-enc.png" IDI_LEVEL_3_ENC RCDATA "icons/level-3-enc.png" IDI_LEVEL_4_ENC RCDATA "icons/level-4-enc.png" IDI_LEVEL_0 RCDATA "icons/level-0.png" IDI_LEVEL_1 RCDATA "icons/level-1.png" IDI_LEVEL_2 RCDATA "icons/level-3.png" IDI_LEVEL_3 RCDATA "icons/level-3.png" IDI_LEVEL_4 RCDATA "icons/level-4.png" IDI_SIGN_ENCRYPT_40_PNG RCDATA "icons/sign-enc-40.png" IDI_ENCRYPT_20_PNG RCDATA "icons/encrypt-20.png" IDI_SIGN_20_PNG RCDATA "icons/sign-20.png" IDI_GPGOL_LOCK_ICON ICON DISCARDABLE "icons/lock.ico" IDB_LOGO BITMAP DISCARDABLE "icons/logo.bmp" IDD_GPG_OPTIONS DIALOG DISCARDABLE 0, 0, 266, 274 STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU CAPTION "GpgOL" FONT 8, "MS Sans Serif" BEGIN /* General options box. */ GROUPBOX "general-options", IDC_G_GENERAL, 9, 9, 250, 25 CONTROL "enable-smime", IDC_ENABLE_SMIME, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 24, 19, 215, 10 /* Send options box. */ GROUPBOX "send-options", IDC_G_SEND, 9, 40, 250, 38 CONTROL "encrypt-by-default", IDC_ENCRYPT_DEFAULT, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 24, 50, 215, 10 CONTROL "sign-by-default", IDC_SIGN_DEFAULT, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 24, 61, 215, 10 /* Receive options box. */ GROUPBOX "recv-options", IDC_G_RECV, 9, 82, 250, 36 /* We have no reliable way to detect the preview window, thus we don't show this option. */ /* CONTROL "preview-decrypt", IDC_PREVIEW_DECRYPT, */ /* "Button", BS_AUTOCHECKBOX | WS_TABSTOP, */ /* 24, 114, 215, 10 */ CONTROL "prefer-html", IDC_PREFER_HTML, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 24, 94, 215, 10 CONTROL "body-as-attachment", IDC_BODY_AS_ATTACHMENT, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 24, 103, 215, 10 /* Stuff at the lower left corner. */ LTEXT "GpgOL by g10 Code GmbH", IDC_G10CODE_STRING, 8, 229, 100, 8 LTEXT "Version x ", IDC_VERSION_INFO, 8, 240, 100, 9 /* No more logo due to problems with the background colour. */ /* CONTROL IDB_BANNER, IDC_BITMAP, */ /* "Static", SS_BITMAP | SS_REALSIZEIMAGE, */ /* 8, 212, 150, 64 */ PUSHBUTTON "advanced", IDC_GPG_OPTIONS, 130, 240, 50, 14 PUSHBUTTON "gpgconf", IDC_GPG_CONF, 190, 240, 70, 14 END IDD_EXT_OPTIONS DIALOG DISCARDABLE 0, 0, 155, 70 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION CAPTION "GpgOL - Debug Options" FONT 8, "MS Sans Serif" BEGIN LTEXT "debug-logfile", IDC_T_DEBUG_LOGFILE, 8, 10, 122, 8 EDITTEXT IDC_DEBUG_LOGFILE, 8, 20, 138, 12, ES_AUTOHSCROLL DEFPUSHBUTTON "&OK", IDOK, 90, 50, 50, 14 END -/* - The dialog to select recipient keys - */ -IDD_ENC DIALOG DISCARDABLE 0, 0, 332, 215 -STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "GpgOL - Select Recipients" -FONT 8, "MS Sans Serif" -BEGIN - CONTROL "List1", IDC_ENC_RSET1, - "SysListView32", LVS_REPORT | LVS_NOSORTHEADER | - WS_BORDER | WS_TABSTOP, - 8, 4, 314, 92 - - LTEXT "Ausgewählte Empfänger:", IDC_ENC_RSET2_T, - 8, 98, 130, 8 - - CONTROL "List2", IDC_ENC_RSET2, - "SysListView32", LVS_REPORT | LVS_NOSORTHEADER | - WS_BORDER | WS_TABSTOP, - 8, 110, 313, 49 - - LTEXT "Recipient which were NOT found", IDC_ENC_NOTFOUND_T, - 8, 161, 128, 8 - - LISTBOX IDC_ENC_NOTFOUND, - 8, 170, 313, 22, LBS_SORT | LBS_NOINTEGRALHEIGHT | - WS_VSCROLL | WS_TABSTOP - - DEFPUSHBUTTON "&OK", IDOK, - 221, 196, 50, 14 - - PUSHBUTTON "&Cancel-btn", IDCANCEL, - 273, 196, 50, 14 -END - - -/* - The decryption dialog used to select the secret key. -*/ -IDD_DEC DIALOG DISCARDABLE 0, 0, 225, 101 -STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Secret Key Selection" -FONT 8, "MS Sans Serif" -BEGIN - COMBOBOX IDC_DEC_KEYLIST, - 9, 7, 209, 58, CBS_DROPDOWNLIST | WS_VSCROLL | - WS_TABSTOP - - LTEXT "", IDC_DEC_HINT, - 9, 25, 201, 10 - - LTEXT "enter-passphrase", IDC_DEC_PASSINF, - 9, 37, 158, 8 - - EDITTEXT IDC_DEC_PASS, - 9, 51, 207, 12, ES_PASSWORD | ES_AUTOHSCROLL - - CONTROL "&Hide Typing", IDC_DEC_HIDE, - "Button", BS_AUTOCHECKBOX | WS_TABSTOP, - 138, 64, 81, 10 - - DEFPUSHBUTTON "&OK", IDOK, - 115, 83, 50, 14 - - PUSHBUTTON "&Cancel-btn", IDCANCEL, - 167, 83, 50, 14 -END - - -/* - The extended decryption dialog used to select the secret key. -*/ -IDD_DECEXT DIALOG DISCARDABLE 0, 0, 207, 134 -STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "GpgOL - Secret Key Selection" -FONT 8, "MS Sans Serif" -BEGIN - LTEXT "encrypted-to",IDC_DECEXT_RSET_T, - 7, 4, 128, 8 - - LISTBOX IDC_DECEXT_RSET, - 7, 16, 193, 25, LBS_NOINTEGRALHEIGHT | - WS_VSCROLL | WS_TABSTOP - - COMBOBOX IDC_DECEXT_KEYLIST, - 8, 54, 191, 14, CBS_DROPDOWN | CBS_SORT | - WS_DISABLED | WS_VSCROLL | WS_TABSTOP - - LTEXT "", IDC_DECEXT_HINT, - 7, 73, 193, 8 - - LTEXT "enter-passphrase", IDC_DECEXT_PASSINF, - 7, 85, 158, 8 - - EDITTEXT IDC_DECEXT_PASS, - 7, 96, 192, 12, ES_PASSWORD | ES_AUTOHSCROLL - - CONTROL "hide-typing", IDC_DECEXT_HIDE, - "Button", BS_AUTOCHECKBOX | WS_TABSTOP, - 122, 108, 81, 10 - - DEFPUSHBUTTON "OK", IDOK, - 98, 125, 50, 14 - - PUSHBUTTON "&Cancel-btn", IDCANCEL, - 149, 125, 50, 14 -END - - -/* - The dialog to display verification results. -*/ -IDD_VRY DIALOG DISCARDABLE 0, 0, 253, 116 -STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION -CAPTION "GpgOL - Signature Verification Result" -FONT 8, "MS Sans Serif" -BEGIN - LTEXT "made-at", IDC_VRY_TIME_T, - 3, 6, 50, 8 - - EDITTEXT IDC_VRY_TIME, - 55, 4, 76, 12, ES_AUTOHSCROLL | ES_READONLY - - LTEXT "using", IDC_VRY_PKALGO_T, - 132, 6, 18, 8 - - EDITTEXT IDC_VRY_PKALGO, - 152, 4, 20, 12, ES_AUTOHSCROLL | ES_READONLY - - LTEXT "key-id", IDC_VRY_KEYID_T, - 174, 7, 50, 8 - - EDITTEXT IDC_VRY_KEYID, - 196, 4, 51, 12, ES_AUTOHSCROLL | ES_READONLY - - EDITTEXT IDC_VRY_STATUS, - 3, 29, 92, 12, ES_AUTOHSCROLL | ES_READONLY - - LTEXT "from", IDC_VRY_ISSUER_T, - 98, 31, 14, 8 - - EDITTEXT IDC_VRY_ISSUER, - 117, 29, 131, 13, ES_AUTOHSCROLL | ES_READONLY - - LTEXT "aka", IDC_VRY_AKALIST_T, - 3, 47, 56, 8 - - LISTBOX IDC_VRY_AKALIST, - 3, 56, 245, 25, LBS_SORT | LBS_NOINTEGRALHEIGHT | - WS_VSCROLL | WS_TABSTOP - - LTEXT "", IDC_VRY_HINT, - 3, 83, 245, 10 - - DEFPUSHBUTTON "&OK", IDOK, - 198, 96, 50, 14 -END - IDD_ADDIN_OPTIONS DIALOGEX DISCARDABLE 300, 300, 286, 190 STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | DS_SHELLFONT | DS_SETFONT CAPTION "GpgOL" FONT 8, "MS Shell Dlg" BEGIN /* General options box. */ -#ifdef MIME_SEND GROUPBOX "general-options", IDC_G_GENERAL, 9, 9, 270, 25 -#else - GROUPBOX "general-options", IDC_G_GENERAL, - 9, 9, 270, 35 -#endif CONTROL "enable-smime", IDC_ENABLE_SMIME, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 24, 19, 235, 10 -#ifndef MIME_SEND - CONTROL "enable-mime-ui", IDC_MIME_UI, - "Button", BS_AUTOCHECKBOX | WS_TABSTOP, - 24, 29, 235, 10 -#endif /* Send options box. */ GROUPBOX "send-options", IDC_G_SEND, 9, 50, 270, 67 CONTROL "encrypt-by-default", IDC_ENCRYPT_DEFAULT, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 24, 60, 235, 10 CONTROL "sign-by-default", IDC_SIGN_DEFAULT, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 24, 71, 235, 10 CONTROL "inline-pgp", IDC_INLINE_PGP, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 24, 82, 235, 10 CONTROL "replycrypt", IDC_REPLYCRYPT, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 24, 93, 235, 10 CONTROL "autoresolve", IDC_AUTORRESOLVE, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 24, 104, 235, 10 /* Stuff at the lower left corner. */ CONTROL IDB_LOGO, IDC_BITMAP, "Static", SS_BITMAP | SS_REALSIZEIMAGE, 10, 125, 128, 80 LTEXT "Version x ", IDC_VERSION_INFO, 10, 175, 100, 9 PUSHBUTTON "advanced", IDC_GPG_OPTIONS, 180, 140, 90, 14 PUSHBUTTON "gpgconf", IDC_GPG_CONF, 180, 155, 90, 14 DEFPUSHBUTTON "&OK", IDOK, 180, 170, 90, 14 END diff --git a/src/gpgoladdin.cpp b/src/gpgoladdin.cpp index c163647..0cadbc8 100644 --- a/src/gpgoladdin.cpp +++ b/src/gpgoladdin.cpp @@ -1,1489 +1,1129 @@ /* 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 "engine.h" #include "engine-assuan.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; -/* Invalidating the interface does not take a nice effect so we store - this option in a global variable. */ -bool use_mime_ui = 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 (); - use_mime_ui = opt.mime_ui; /* 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); engine_deinit (); 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; } engine_init (); 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::close_all_mails ()) { 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; 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"attachmentDecryptCallback", ID_CMD_DECRYPT) - ID_MAPPER (L"encryptSelection", ID_CMD_ENCRYPT_SELECTION) - ID_MAPPER (L"decryptSelection", ID_CMD_DECRYPT_SELECTION) - ID_MAPPER (L"startCertManager", ID_CMD_CERT_MANAGER) - ID_MAPPER (L"btnCertManager", ID_BTN_CERTMANAGER) 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) - ID_MAPPER (L"encryptBody", ID_CMD_ENCRYPT_BODY) - ID_MAPPER (L"decryptBody", ID_CMD_DECRYPT_BODY) - ID_MAPPER (L"addEncSignedAttachment", ID_CMD_ATT_ENCSIGN_FILE) - ID_MAPPER (L"addEncAttachment", ID_CMD_ATT_ENC_FILE) - ID_MAPPER (L"signBody", ID_CMD_SIGN_BODY) - ID_MAPPER (L"verifyBody", ID_CMD_VERIFY_BODY) /* 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_DECRYPT: /* We can assume that this points to an implementation of IRibbonControl as we know the callback dispid. */ return decryptAttachments (parms->rgvarg[0].pdispVal); - case ID_CMD_ENCRYPT_SELECTION: - return encryptSelection (parms->rgvarg[0].pdispVal); - case ID_CMD_DECRYPT_SELECTION: - return decryptSelection (parms->rgvarg[0].pdispVal); - case ID_CMD_CERT_MANAGER: - return startCertManager (parms->rgvarg[0].pdispVal); - case ID_CMD_ENCRYPT_BODY: - return encryptBody (parms->rgvarg[0].pdispVal); - case ID_CMD_DECRYPT_BODY: - return decryptBody (parms->rgvarg[0].pdispVal); - case ID_CMD_ATT_ENCSIGN_FILE: - return addEncSignedAttachment (parms->rgvarg[0].pdispVal); - case ID_CMD_ATT_ENC_FILE: - return addEncAttachment (parms->rgvarg[0].pdispVal); - case ID_CMD_SIGN_BODY: - return signBody (parms->rgvarg[0].pdispVal); - case ID_CMD_VERIFY_BODY: - return verifyBody (parms->rgvarg[0].pdispVal); 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_CERTMANAGER: 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, "" " " " " " " " " " " " " " " " " " " " " " " "