diff --git a/src/Makefile.am b/src/Makefile.am
index 418f5ae8..a187e4eb 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,655 +1,660 @@
# Makefile.am - Installer for GnuPG 4 Windows Makefile.
# Copyright (C) 2005, 2006, 2007, 2008, 2009 g10 Code GmbH
#
# This file is part of Gpg4win.
#
# Gpg4win is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# Gpg4win 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 General Public License
# along with this program; if not, see .
EXTRA_DIST = pkg-config gpg4win.nsi gpg4win-src.nsi \
config.site config.nsi.in \
libiconv.def libintl.def loreley.mid \
gpg4win-splash.wav exdll.h g4wihelp.c desktopshellrun.cpp \
g4wihelp.nsi slideshow.cpp gpgwrap.c \
inst-sections.nsi installer.nsi installer-finish.nsi \
zlib.pc sha1sum.c \
potomo Memento.nsh \
inst-gpg4win.nsi uninst-gpg4win.nsi \
inst-gettext.nsi uninst-gettext.nsi \
inst-gnupg-w32.nsi uninst-gnupg-w32.nsi \
inst-gpgme.nsi uninst-gpgme.nsi \
inst-paperkey.nsi uninst-paperkey.nsi \
inst-gpgol.nsi uninst-gpgol.nsi \
inst-gpgex.nsi uninst-gpgex.nsi \
inst-libassuan.nsi uninst-libassuan.nsi \
inst-libgpg-error.nsi uninst-libgpg-error.nsi \
inst-libiconv.nsi uninst-libiconv.nsi \
inst-compendium.nsi uninst-compendium.nsi \
inst-man_advanced_de.nsi uninst-man_advanced_de.nsi \
inst-man_advanced_en.nsi uninst-man_advanced_en.nsi \
inst-man_novice_de.nsi uninst-man_novice_de.nsi \
inst-man_novice_en.nsi uninst-man_novice_en.nsi \
inst-pinentry.nsi uninst-pinentry.nsi \
inst-pkgconfig.nsi uninst-pkgconfig.nsi \
inst-zlib.nsi uninst-zlib.nsi \
inst-kconfig.nsi uninst-kconfig.nsi \
inst-kleopatra.nsi uninst-kleopatra.nsi \
inst-bzip2.nsi uninst-bzip2.nsi \
inst-qtbase.nsi uninst-qtbase.nsi \
inst-ki18n.nsi uninst-ki18n.nsi \
inst-kio.nsi uninst-kio.nsi \
inst-kbookmarks.nsi uninst-kbookmarks.nsi \
inst-kservice.nsi uninst-kservice.nsi \
inst-solid.nsi uninst-solid.nsi \
inst-kjobwidgets.nsi uninst-kjobwidgets.nsi \
inst-kwidgetsaddons.nsi uninst-kwidgetsaddons.nsi \
inst-kcompletion.nsi uninst-kcompletion.nsi \
inst-kwindowsystem.nsi uninst-kwindowsystem.nsi \
inst-libkleo.nsi uninst-libkleo.nsi \
inst-kcoreaddons.nsi uninst-kcoreaddons.nsi \
inst-kcodecs.nsi uninst-kcodecs.nsi \
inst-kconfigwidgets.nsi uninst-kconfigwidgets.nsi \
inst-kxmlgui.nsi uninst-kxmlgui.nsi \
inst-kiconthemes.nsi uninst-kiconthemes.nsi \
inst-breeze-icons.nsi uninst-breeze-icons.nsi \
inst-karchive.nsi uninst-karchive.nsi \
inst-kcrash.nsi uninst-kcrash.nsi \
inst-kitemviews.nsi uninst-kitemviews.nsi \
inst-kitemmodels.nsi uninst-kitemmodels.nsi \
inst-kguiaddons.nsi uninst-kguiaddons.nsi \
inst-kmime.nsi uninst-kmime.nsi \
inst-kde-l10n.nsi uninst-kde-l10n.nsi \
inst-qtsvg.nsi uninst-qtsvg.nsi \
inst-qttools.nsi uninst-qttools.nsi \
inst-qttranslations.nsi uninst-qttranslations.nsi \
inst-qtwinextras.nsi uninst-qtwinextras.nsi \
inst-scute.nsi uninst-scute.nsi \
inst-extra-cmake-modules.nsi uninst-extra-cmake-modules.nsi \
inst-gpg4win-tools.nsi uninst-gpg4win-tools.nsi \
inst-gpgme-browser.nsi \
inst-poppler.nsi uninst-poppler.nsi \
inst-freetype.nsi uninst-freetype.nsi \
inst-threadweaver.nsi uninst-threadweaver.nsi \
inst-kparts.nsi uninst-kparts.nsi \
inst-okular.nsi uninst-okular.nsi \
inst-final.nsi index.theme \
slideshow/slides.dat \
slideshow/slide1-gpgol.png \
slideshow/slide2-gpgex.png \
slideshow/slide3-kleopatra.png \
slideshow/slide4-summary.png \
icons/file-ext.ico \
kdeglobals qtlogging.ini \
make-msi.pl make-msi.guids \
build-gpg4win.sh \
WixUI_Gpg4win.wxs icons/shield.ico
if BUILD_APPIMAGE
appimage = appimage
else
appimage =
endif
SUBDIRS = ${appimage}
# These paths must be absolute, as we switch directories pretty often.
root := $(shell pwd)/playground
stampdir := $(shell pwd)/stamps
gpg4win_readme_ll = en de ar es fr ru pt zh
README_files = $(addsuffix .txt,$(addprefix README.,$(gpg4win_readme_ll)))
gpg4win_howto_smime_ll = en de
HOWTO_files = $(addsuffix .txt, \
$(addprefix HOWTO-SMIME.,$(gpg4win_howto_smime_ll)))
foosum_exe = sha1sum.exe md5sum.exe sha256sum.exe
# Need to clean the dll because we bypassed automake.
CLEANFILES = g4wihelp.dll desktopshellrun.o versioninfo.txt $(README_files) \
$(HOWTO_files) NEWS.tmp COMPONENTS-list.tmp \
license.blurb cdversioninfo.tmp slideshow.o \
$(foosum_exe) gpgwrap.exe
# Supported source packages. (see also ../appimage/Makefile.am)
gpg4win_spkgs = glib libffi gdk-pixbuf gtk+ \
libgpg-error gpgme gpgol gpgex libpng \
gpa opencdk \
pinentry libassuan ntbtls pcre \
paperkey regex libiconv gettext scute
gpg4win_qtpkgs = qtbase qttools qtwinextras qtsvg qttranslations
# Source packages following the KDE pattern
gpg4win_kdepkgs = kconfig kwidgetsaddons ki18n extra-cmake-modules \
kcompletion kwindowsystem kcoreaddons libkleo kcodecs \
kmime kconfigwidgets kxmlgui kguiaddons kitemviews \
kiconthemes kleopatra breeze-icons kitemmodels karchive \
gpg4win-tools kcrash kio kbookmarks kservice solid \
kjobwidgets poppler okular freetype threadweaver \
kparts
# Supported source packages to build in an additional architecture
gpg4win_expkgs = libgpg-error libassuan libiconv gettext gpgex gpgol \
gpgme
# Some variables
WINE = wine
WINHOST = win10
WINLIGHT = c:/wix/light.exe
# Extra options to configure for individual packages.
# We can use $(idir) here for the installation prefix.
gpg4win_pkg_libiconv_ex_configure = \
--enable-shared=no --enable-static=yes
gpg4win_pkg_gettext_configure = \
--with-lib-prefix=$(idir) --with-libiconv-prefix=$(idir) \
CPPFLAGS=-I$(idir)/include CFLAGS=-O2 LDFLAGS=-L$(idir)/lib
gpg4win_pkg_scute_configure = \
LDFLAGS=-lws2_32
gpg4win_pkg_gettext_ex_configure = \
--with-lib-prefix=$(ex_idir) --with-libiconv-prefix=$(ex_idir) \
CPPFLAGS=-I$(ex_idir)/include CFLAGS=-O2 LDFLAGS=-L$(ex_idir)/lib
# We only need gettext-runtime and there is sadly no top level
# configure option for this
gpg4win_pkg_gettext_make_dir = gettext-runtime
gpg4win_pkg_gettext_make_dir_inst = gettext-runtime
gpg4win_pkg_gettext_ex_make_dir = gettext-runtime
gpg4win_pkg_gettext_ex_make_dir_inst = gettext-runtime
# Paperkey comes with a man pages which we have to convert.
define gpg4win_pkg_paperkey_post_install
(for i in paperkey ; \
do man -Tlatin1 -l $$$${pkgidir}/share/man/man1/$$$${i}.1 | \
sed `printf "s/_\b//g;s/\b.//g"` | \
sed -e 's/$$$$/\r/' > $$$${pkgidir}/share/man/man1/$$$${i}.man ; \
done)
endef
# Build the reference manual.
define gpg4win_pkg_gpgol_post_install
( cd $$$${pkgbdir}/doc; make pdf )
endef
# We would like to use --with-libiconv-prefix and
# --with-libintl-prefix, but these don't work with the cheesy
# non-"libfoo.la" versions of iconv and gettext that we are using.
#gpg4win_pkg_libgpg_error_configure = \
# --with-libiconv-prefix=$(idir) --with-libintl-prefix=$(idir)
gpg4win_pkg_libgpg_error_configure = --silent \
CPPFLAGS=-I$(idir)/include LDFLAGS=-L$(idir)/lib \
--enable-static --enable-install-gpg-error-config
gpg4win_pkg_libgpg_error_ex_configure = --silent \
--enable-static --enable-install-gpg-error-config
# We convert the PO files to UTF-8. FIXME: This should be done in
# libgpg-error proper.
define gpg4win_pkg_libgpg_error_post_install
(for i in `$(tsdir)/src/potomo --get-linguas $$$${pkgsdir}/po` ; do \
rm $$$${pkgidir}/share/locale/$$$${i}/LC_MESSAGES/libgpg-error.mo \
2>/dev/null|| true; \
$(tsdir)/src/potomo $$$${pkgsdir}/po/$$$${i}.po \
$$$${pkgidir}/share/locale/$$$${i}/LC_MESSAGES/libgpg-error.mo; \
done)
endef
gpg4win_pkg_libassuan_configure = --silent --enable-static
gpg4win_pkg_libassuan_ex_configure = --with-gpg-error-prefix=$(ex_idir) --silent --enable-static
gpg4win_pkg_libpng_configure = HAVE_SOLARIS_LD_FALSE=yes CPPFLAGS=\"-I$(idir)/include -DPNG_BUILD_DLL\" LDFLAGS=\"-L$(idir)/lib\" LIBPNG_DEFINES=\"-DPNG_BUILD_DLL\"
# We would like to use --with-libiconv-prefix and
# --with-libintl-prefix, but these don't work with the cheesy
# non-"libfoo.la" versions of iconv and gettext that we are using.
gpg4win_pkg_pinentry_configure = \
--enable-pinentry-qt \
$(pinentry_enable_disable) \
--disable-pinentry-fltk \
--disable-pinentry-curses \
--disable-fallback-curses \
CPPFLAGS=-I$(idir)/include LDFLAGS=-L$(idir)/lib
# --with-libiconv-prefix=$(idir) --with-libintl-prefix=$(idir)
# The LDFLAGS is needed for -lintl for glib. The QT4 variables work
# around the lack of cross compilation support in qt-dev.
gpg4win_pkg_gpgme_configure = --silent \
--with-gpg-error-prefix=$(idir) --enable-static \
LDFLAGS=-L$(idir)/lib \
--enable-languages=qt,cpp \
--disable-gpg-test \
--disable-gpgsm-test
gpg4win_pkg_gpgme_ex_configure = --silent \
--with-gpg-error-prefix=$(ex_idir) --enable-static \
--with-libassuan-prefix=$(ex_idir) \
LDFLAGS=-L$(ex_idir)/lib \
--enable-languages=cpp \
--disable-gpg-test \
--disable-gpgsm-test
gpg4win_pkg_gpgol_configure = --silent \
--with-gpgme-prefix=$(idir) --with-gpg-error-prefix=$(idir) \
--with-libassuan-prefix=$(idir)
gpg4win_pkg_gpgol_ex_configure = --silent \
--with-gpgme-prefix=$(ex_idir) --with-gpg-error-prefix=$(ex_idir) \
--with-libassuan-prefix=$(ex_idir)
gpg4win_pkg_gpgex_configure = --silent \
--with-gpg-error-prefix=$(idir) \
--with-libassuan-prefix=$(idir)
gpg4win_pkg_gpgex_ex_configure = --silent \
--with-gpg-error-prefix=$(ex_idir) \
--with-libassuan-prefix=$(ex_idir)
gpg4win_pkg_paperkey_configure = --silent
gpg4win_pkg_ki18n_configure = -DBUILD_WITH_QML=OFF
gpg4win_pkg_kconfig_configure = -DKCONFIG_USE_DBUS=OFF -DKCONFIG_USE_QML=OFF
gpg4win_pkg_qtbase_configure = ../$$$${pkg_version}/configure -opensource \
-confirm-license \
-xplatform win32-g++ \
-device-option CROSS_COMPILE=$(host)- \
-device-option PKG_CONFIG='$(host)-pkg-config' \
-no-use-gold-linker \
-release \
-shared \
-prefix $$$${pkgidir} \
-I '$(idir)/include' \
-L '$(idir)/lib' \
-no-icu \
-opengl desktop \
-no-glib \
-accessibility \
-nomake examples \
-nomake tests \
-no-sql-mysql \
-no-sql-sqlite \
-no-sql-odbc \
-no-sql-psql \
-no-sql-tds \
-qt-zlib \
-qt-libpng \
-qt-libjpeg \
-qt-freetype \
-qt-pcre \
-no-openssl \
-no-dbus \
-v
# qtbase
# invoke qmake with removed debug options as a workaround for
# https://bugreports.qt-project.org/browse/QTBUG-30898
gpg4win_pkg_qtbase_make_args = \
QMAKE='$$$${pkgbdir}/bin/qmake'
# Make install step. Somehow qtprintsupport is now installed automatically.
define gpg4win_pkg_qtbase_post_install
(cd $$$${pkgbdir}; \
make install; \
cd $$$${pkgbdir}/src/printsupport; \
make install;)
endef
gpg4win_pkg_qttools_configure = \
"$(idir)/bin/qmake" ../$$$${pkg_version}
define gpg4win_pkg_qttools_post_install
(cd $$$${pkgbdir}; \
mkdir -p $$$${pkgidir}; \
cp -r bin lib include $$$${pkgidir})
endef
# Qmake does not support setting the installation path.
# really https://bugreports.qt.io/browse/QTBUG-12341
gpg4win_pkg_qtwinextras_configure = \
"$(idir)/bin/qmake" ../$$$${pkg_version}
define gpg4win_pkg_qtwinextras_post_install
(cd $$$${pkgbdir}; \
mkdir -p $$$${pkgidir}/bin; \
cp -r lib include $$$${pkgidir}; \
mv $$$${pkgidir}/lib/*.dll $$$${pkgidir}/bin;)
endef
gpg4win_pkg_qtsvg_configure = \
"$(idir)/bin/qmake" ../$$$${pkg_version}
# XXX Adding the qtconf after qtsvg is a weird hack
# because somhow (yay qmake) zlib is not linked if
# the qt conf exists before that. The qt conf is
# needed for qttranslations to find the correct path
# of the translation tools.
define gpg4win_pkg_qtsvg_post_install
(cd $$$${pkgbdir}; \
mkdir -p $$$${pkgidir}; \
cp -r lib include plugins $$$${pkgidir}; \
mkdir -p $$$${pkgidir}/bin; \
mv $$$${pkgidir}/lib/*.dll $$$${pkgidir}/bin; \
echo "[Paths]" > $$$${pkgidir}/bin/qt.conf; \
echo "Prefix = .." >> $$$${pkgidir}/bin/qt.conf)
endef
gpg4win_pkg_qttranslations_configure = \
"$(idir)/bin/qmake" ../$$$${pkg_version}
define gpg4win_pkg_qttranslations_post_install
( rm -fR $$$${pkgidir}/qttranslations; \
mkdir -p $$$${pkgidir}; \
cp -r $$$${pkgbdir}/translations $$$${pkgidir}/qttranslations;)
endef
define gpg4win_pkg_okular_post_install
( rm $$$${pkgidir}/share/icons/hicolor/icon-theme.cache; )
endef
gpg4win_pkg_kleopatra_configure = \
-DFORCE_DISABLE_KCMUTILS=ON \
-DDISABLE_KWATCHGNUPG=ON \
-DRELEASE_SERVICE_VERSION=Gpg4win-$(VERSION) \
-DKLEOPATRA_DISTRIBUTION_TEXT="$(DISTRIBUTION_TEXT)"
gpg4win_pkg_kxmlgui_configure = \
-DFORCE_DISABLE_KGLOBALACCEL=ON \
-DFORCE_DISABLE_DBUS=ON \
-DXMLGUI_COMPILER_VERSION="i686-w64-mingw32-gcc" \
-DXMLGUI_DISTRIBUTION_TEXT="$(DISTRIBUTION_TEXT)"
gpg4win_pkg_breeze_icons_configure = \
-DBINARY_ICONS_RESOURCE=OFF
gpg4win_pkg_kbookmarks_configure = \
-DANDROID=ON
gpg4win_pkg_kservice_configure = \
-DANDROID=ON
gpg4win_pkg_kjobwidgets_configure = \
-DANDROID=ON
gpg4win_pkg_poppler_configure = \
-DENABLE_DCTDECODER=none \
-DENABLE_LIBOPENJPEG=none
gpg4win_pkg_okular_configure = \
-DFORCE_NOT_REQUIRED_DEPENDENCIES="KF5Purpose\;KF5TextWidgets\;Qt5TextToSpeech\;LibZip\;KF5Wallet\;KF5DocTools\;KF5JS\;Phonon4Qt5\;TIFF\;JPEG\;LibSpectre\;KF5KExiv2\;CHM\;KF5KHtml\;DjVuLibre\;EPub\;QMobipocket\;Discount"
# Supported make-only source packages.
gpg4win_mpkgs = bzip2 zlib
# Extra options for the make invocations for individual packages.
# make_flags is used for building, make_args_inst is used for installing.
gpg4win_pkg_bzip2_make_args = \
CC=$(CC) AR=$(AR) RANLIB=$(RANLIB)
gpg4win_pkg_bzip2_make_args_inst = \
PREFIX=$$$${pkgidir} CC=$(CC) AR=$(AR) RANLIB=$(RANLIB)
gpg4win_pkg_zlib_make_args = \
-fwin32/Makefile.gcc PREFIX=$(host)- IMPLIB=libz.dll.a
gpg4win_pkg_zlib_make_args_inst = -fwin32/Makefile.gcc install \
BINARY_PATH=$$$${pkgidir}/bin INCLUDE_PATH=$$$${pkgidir}/include \
LIBRARY_PATH=$$$${pkgidir}/lib SHARED_MODE=1 IMPLIB=libz.dll.a
# Supported binary packages.
gpg4win_bpkgs = pkgconfig gnupg-w32 kde-l10n
# libiconv needs some special magic to generate a usable import
# library.
# define gpg4win_pkg_libiconv_post_install
# (cp $(srcdir)/libiconv.def $$$${pkgidir}/lib; \
# cd $$$${pkgidir}/lib; \
# $(DLLTOOL) --output-lib libiconv.dll.a --def libiconv.def)
# endef
# libiconv needs some special magic to generate a usable import
# library. Note that we include some internal symbols that are not
# actually part of the DLL. They are needed by the AM_GNU_GETTEXT
# configure test, but not used otherwise.
# define gpg4win_pkg_gettext_post_install
# (cp $(srcdir)/libintl.def $$$${pkgidir}/lib; \
# cd $$$${pkgidir}/lib; \
# $(DLLTOOL) --output-lib libintl.dll.a --def libintl.def)
# endef
# Zlib needs some special magic to generate a libtool file.
# We also install the pc file here.
define gpg4win_pkg_zlib_post_install
(mkdir $$$${pkgidir}/lib/pkgconfig || true; \
cp $(abs_srcdir)/zlib.pc $$$${pkgidir}/lib/pkgconfig/; \
cd $$$${pkgidir}; \
echo "# Generated by libtool" > lib/libz.la \
echo "dlname='../bin/zlib1.dll'" >> lib/libz.la; \
echo "library_names='libz.dll.a'" >> lib/libz.la; \
echo "old_library='libz.a'" >> lib/libz.la; \
echo "dependency_libs=''" >> lib/libz.la; \
echo "current=1" >> lib/libz.la; \
echo "age=2" >> lib/libz.la; \
echo "revision=5" >> lib/libz.la; \
echo "installed=yes" >> lib/libz.la; \
echo "shouldnotlink=no" >> lib/libz.la; \
echo "dlopen=''" >> lib/libz.la; \
echo "dlpreopen=''" >> lib/libz.la; \
echo "libdir=\"$$$${pkgidir}/lib\"" >> lib/libz.la)
endef
# We don't use khelpcenter in kleopatra so remove the help links and
# point to the correct common folder
# TODO Needs to be fixed with current doc
#define gpg4win_pkg_kleopatra_post_install
# (for i in de en ; do \
# (cd $$$${pkgidir}/share/doc/HTML/$$$${i}; \
# perl -pi -e 's/help:\///g' `find . -name \*.html`; \
# perl -pi -e 's@common/@../../common/@g' `find . -name \*.html`); \
# done)
#endef
#define gpg4win_pkg_libiconv_post_install
#(cp $(srcdir)/libiconv.def $$$${pkgidir}/lib; \
#cd $$$${pkgidir}/lib; \
#$(DLLTOOL) --output-lib libiconv.dll.a --def libiconv.def)
#endef
# Supported internal packages. Internal packages do not require any
# special support. Thus, this variable is actually unused, and no
# rules are added in gpg4win.mk.
gpg4win_ipkgs = man_novice_de man_advanced_de man_novice_en man_advanced_en \
compendium
# Default to same version.
VSD_VERSION=$(VERSION)
# Include installer targets for customized packages
-include gnupg-vsd/custom.mk
# Signging host/key setup for codesigning
-include gnupg-vsd/sign.mk
$(stampdir)/stamp-msi-base: icons/shield.ico Makefile.am \
$(top_srcdir)/doc/logo/gpg4win-msi*.bmp \
$(top_srcdir)/po/gpg4win-de.wxl \
$(top_srcdir)/po/gpg4win-en.wxl
ssh $(WINHOST) "mkdir AppData\\Local\\Temp\\gpg4win-$(VERSION)" || true
scp $(top_srcdir)/packages/gnupg-msi-$(gpg4win_pkg_gnupg_msi_version)-bin.wixlib \
$(WINHOST):AppData/Local/Temp/gpg4win-$(VERSION);
scp $(top_srcdir)/src/icons/shield.ico $(WINHOST):AppData/Local/Temp/gpg4win-$(VERSION)
scp $(top_srcdir)/doc/logo/gpg4win-msi-header_install-493x58.bmp \
$(WINHOST):AppData/Local/Temp/gpg4win-$(VERSION)/header.bmp
scp $(top_srcdir)/doc/logo/gpg4win-msi-wizard_install-493x312.bmp \
$(WINHOST):AppData/Local/Temp/gpg4win-$(VERSION)/dialog.bmp
scp $(top_srcdir)/doc/logo/gpg4win-msi-wizard_install-493x312.bmp \
$(WINHOST):AppData/Local/Temp/gpg4win-$(VERSION)/dialog.bmp
scp $(top_srcdir)/doc/logo/gpg4win-msi-wizard_install-info-32x32.bmp \
$(WINHOST):AppData/Local/Temp/gpg4win-$(VERSION)/info.bmp
scp $(top_srcdir)/doc/logo/gpg4win-msi-wizard_install-exclamation-32x32.bmp \
$(WINHOST):AppData/Local/Temp/gpg4win-$(VERSION)/exclamation.bmp
scp $(top_srcdir)/po/gpg4win-en.wxl $(WINHOST):AppData/Local/Temp/gpg4win-$(VERSION)
scp $(top_srcdir)/po/gpg4win-de.wxl $(WINHOST):AppData/Local/Temp/gpg4win-$(VERSION)
scp WixUI_Gpg4win.wxs $(WINHOST):AppData/Local/Temp/gpg4win-$(VERSION)
touch $(stampdir)/stamp-msi-base
# Now do the bunch of the work. This is a bunch of dirty magic to
# integrate our special makefile into automake, while not actually
# including it (make should include it). This is in turn necessary
# because automake can't deal with the elegant magic in the actual
# Makefile.
define INCLUDE_BY_MAKE
include $(1)
endef
if BUILD_GPG4WIN
$(eval $(call INCLUDE_BY_MAKE,gpg4win.mk))
gpg4win_clean = clean-gpg4win
endif
clean-local: $(gpg4win_clean)
common_nsi = inst-sections.nsi installer.nsi installer-finish.nsi \
$(addsuffix .nsi,$(addprefix inst-,$(gpg4win_build_list))) \
$(addsuffix .nsi,$(addprefix uninst-,$(gpg4win_build_list)))
# Sign additional files as per signing setup
# This is a bit of a hack.
$(stampdir)/stamp-additional-signedfiles: $(stampdir)/stamp-binaries
(set -e;\
cd "$(idir)"; \
for f in $(AUTHENTICODE_FILES); do \
if [ -f "$$f" ]; then \
$(call AUTHENTICODE_sign,"$$f","$$f");\
else \
echo "speedo: WARNING: file '$$f' not available for signing";\
fi;\
done \
)
touch $(stampdir)/stamp-additional-signedfiles
# Prepare the versioninfo file. The pipeline extracts the last
# occurrence of a package with the same name, sorts the entries and
# writes the file with DOS line endings. This helps to avoid
# duplicate entries in case one package has been rebuild (which is
# common when developing a new version).
versioninfo.txt:
$(SHA1SUM) $(pkg_files) versioninfo.tmp
set -e; \
( while read a b; do echo "$$a $$(basename $$b)"; \
done < versioninfo.tmp \
| sort -k2 -sf | tac | uniq -f1 ; \
echo '=========== SHA-1 checksum ============= == package ==' \
) | tac | awk '{printf "%s\r\n", $$0}' > versioninfo.txt
-rm versioninfo.tmp
NEWS.tmp : $(top_srcdir)/NEWS
awk '/^#/ {next} /^\(de\)/ {skip=1;next} /^[^[:space:]]/ {skip=0} \
!skip { sub(/^\(en\)/," *"); print }' \
<$(top_srcdir)/NEWS >NEWS.tmp
NEWS.de : $(top_srcdir)/NEWS
awk '/^#/ {next} /^\(en\)/ {skip=1;next} /^[^[:space:]]/ {skip=0} \
!skip { sub(/^\(de\)/,"-"); print }' \
<$(top_srcdir)/NEWS >NEWS.de; \
sed -i 's/^ / /' NEWS.de
NEWS.en : $(top_srcdir)/NEWS
awk '/^#/ {next} /^\(de\)/ {skip=1;next} /^[^[:space:]]/ {skip=0} \
!skip { sub(/^\(en\)/,"-"); print }' \
<$(top_srcdir)/NEWS >NEWS.en; \
sed -i 's/^ / /' NEWS.en
COMPONENTS-list.tmp : $(top_srcdir)/NEWS
awk '/^~~~~~~~~~~~/ { ok++; next} ok==1 {print " "$$0}' \
< $(top_srcdir)/NEWS > COMPONENTS-list.tmp
# For some nut-crazy reason someone thought it would be a great idea
# if makensis changed to the directory of the source file at startup.
# So we have to pull a couple of strings to correct this.
installers/gpg4win-$(VERSION).exe: gpg4win.nsi $(common_nsi) $(stampdir)/stamp-final \
g4wihelp.dll gpgwrap.exe \
$(foosum_exe) \
$(README_files) $(HOWTO_files) \
license.blurb versioninfo.txt
$(MAKENSIS) -V3 -DBUILD_DIR=`pwd` -DTOP_SRCDIR=$(top_srcdir) \
-DSRCDIR=$(srcdir) $(EXTRA_MAKENSIS_FLAGS) $(srcdir)/gpg4win.nsi && \
mv gpg4win-$(VERSION).exe installers/gpg4win-$(VERSION).exe
$(stampdir)/stamp-dist-self: versioninfo.txt
(set -e; cd ..; make dist-xz)
touch $(stampdir)/stamp-dist-self
installers/gpg4win-src-$(VERSION).exe: gpg4win-src.nsi $(common_nsii) \
$(stampdir)/stamp-final \
$(stampdir)/stamp-dist-self \
license.blurb
$(MAKENSIS) -V3 -DBUILD_DIR=`pwd` -DTOP_SRCDIR=$(top_srcdir) \
-DSRCDIR=$(srcdir) $(EXTRA_MAKENSIS_FLAGS) $(srcdir)/gpg4win-src.nsi && \
mv gpg4win-src-$(VERSION).exe installers/gpg4win-src-$(VERSION).exe
license.blurb: $(top_srcdir)/doc/license-page $(top_srcdir)/doc/GPLv3
cat $(top_srcdir)/doc/license-page $(top_srcdir)/doc/GPLv3 >$@
g4wihelp.dll: slideshow.cpp desktopshellrun.cpp g4wihelp.c exdll.h
- $(CC) -DUNICODE -static-libgcc -I. -O2 -c -o exdll.o $(srcdir)/exdll.c
- $(CC) -DUNICODE -static-libgcc -I. -O2 -c -o desktopshellrun.o $(srcdir)/desktopshellrun.cpp
- $(CC) -DUNICODE -static-libgcc -I. -O2 -c -o slideshow.o $(srcdir)/slideshow.cpp
- $(CC) -DUNICODE -static-libgcc -I. -shared -O2 -o g4wihelp.dll $(srcdir)/g4wihelp.c \
- desktopshellrun.o slideshow.o exdll.o -lwinmm -lgdi32 -luserenv -lshell32 \
- -lole32 -loleaut32 -lshlwapi -lmsimg32
+ $(CC) -DUNICODE -static-libgcc -I. -O2 -c \
+ -o exdll.o $(srcdir)/exdll.c
+ $(CC) -DUNICODE -static-libgcc -I. -O2 -c \
+ -o desktopshellrun.o $(srcdir)/desktopshellrun.cpp
+ $(CC) -DUNICODE -static-libgcc -I. -O2 -c \
+ -o slideshow.o $(srcdir)/slideshow.cpp
+ $(CC) -DUNICODE -DENABLE_SLIDE_SHOW -static-libgcc -I. -shared -O2 \
+ -o g4wihelp.dll $(srcdir)/g4wihelp.c \
+ desktopshellrun.o slideshow.o exdll.o \
+ -lwinmm -lgdi32 -luserenv -lshell32 \
+ -lole32 -loleaut32 -lshlwapi -lmsimg32
$(STRIP) g4wihelp.dll
gpgwrap.exe: gpgwrap.c
$(CC) -I. -I.. -DHAVE_CONFIG_H -O2 -Wl,-subsystem,windows -o $@ $^
$(STRIP) $@
sha1sum.exe: sha1sum.c
$(CC) -O2 -o $@ $^
$(STRIP) $@
md5sum.exe: sha1sum.c
$(CC) -DBUILD_MD5SUM -O2 -o $@ $^
$(STRIP) $@
sha256sum.exe: sha1sum.c
$(CC) -DBUILD_SHA256SUM -O2 -o $@ $^
$(STRIP) $@
if BUILD_GPG4WIN
all_full = installers/gpg4win-$(VERSION).exe
endif
all-local: $(all_full)
if BUILD_GPG4WIN
@echo "###################################################"
@echo " Gpg4win $(VERSION) successfully build!"
@echo " Installers can be found under src/installers"
@echo "###################################################"
endif
clean-local:
rm -f installers/gpg4win-$(VERSION).exe \
installers/GnuPG-VS-Desktop-$(VERSION).msi
diff --git a/src/g4wihelp.c b/src/g4wihelp.c
index 54a872e2..b83ab4a2 100644
--- a/src/g4wihelp.c
+++ b/src/g4wihelp.c
@@ -1,534 +1,1284 @@
/* g4wihelp.c - NSIS Helper DLL used with gpg4win. -*- coding: latin-1; -*-
- * Copyright (C) 2005 g10 Code GmbH
+ * Copyright (C) 2005, 2023 g10 Code GmbH
* Copyright (C) 2001 Justin Frankel
* Copyright (C) 2016, 2017 Intevation GmbH
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must
* not claim that you wrote the original software. If you use this
* software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must
* not be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
************************************************************
* The code for the splash screen has been taken from the Splash
* plugin of the NSIS 2.04 distribution. That code comes without
* explicit copyright notices in tyhe source files or author names, it
* seems that it has been written by Justin Frankel; not sure about
* the year, though. [wk 2005-11-28]
+ *
+ * Fixed some compiler warnings. [wk 2014-02-24].
+ * Merged code from GnuPG version. [wk 2023-04-24].
+ *
+ * Compile time macros:
+ * ENABLE_SLIDE_SHOW :: Define for Gpg4win.
*/
#include
#include
#include
#include
+#include
+#include
#include "exdll.h"
+/* We keep some code here for documentation reasons. That code has not
+ * yet been converted to the Unicode NSIS plugin API. */
+/* #define ENABLE_SOUND_GADGET 1 */
+/* #define ENABLE_SPLASH_GADGET 1 */
+/* #define ENABLE_SERVICE_MANAGEMENT 1 */
+
+
static HINSTANCE g_hInstance; /* Our Instance. */
static HWND g_hwndParent; /* Handle of parent window or NULL. */
static HBITMAP g_hbm; /* Handle of the splash image. */
static int sleepint; /* Milliseconds to show the spals image. */
+#ifdef ENABLE_SLIDE_SHOW
void
slide_stop(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop);
+#endif
/* Standard entry point for DLLs. */
int WINAPI
DllMain (HANDLE hinst, DWORD reason, LPVOID reserved)
{
if (reason == DLL_PROCESS_ATTACH)
g_hInstance = hinst;
else if (reason == DLL_PROCESS_DETACH)
- slide_stop(NULL, 0, NULL, NULL);
+ {
+#ifdef ENABLE_SLIDE_SHOW
+ slide_stop (NULL, 0, NULL, NULL);
+#endif
+ }
return TRUE;
}
/* Dummy function for testing. */
void __declspec(dllexport)
dummy (HWND hwndParent, int string_size, LPTSTR variables,
stack_t **stacktop, extra_parameters_t *extra)
{
g_hwndParent = hwndParent;
EXDLL_INIT();
// note if you want parameters from the stack, pop them off in order.
// i.e. if you are called via exdll::myFunction file.dat poop.dat
// calling popstring() the first time would give you file.dat,
// and the second time would give you poop.dat.
// you should empty the stack of your parameters, and ONLY your
// parameters.
// do your stuff here
{
wchar_t buf[1024];
swprintf(buf, 1024,
L"stringsize=%d\r\n$0=%s\r\n$1=%s\r\n$R0=%s\r\n$R1=%s\r\n",
string_size,
getuservariable(INST_0),
getuservariable(INST_1),
getuservariable(INST_R0),
getuservariable(INST_R1));
MessageBoxW(g_hwndParent,buf,0,MB_OK);
swprintf (buf, 1024,
L"autoclose =%d\r\n"
"all_user_var =%d\r\n"
"exec_error =%d\r\n"
"abort =%d\r\n"
"exec_reboot =%d\r\n"
"reboot_called=%d\r\n"
"api_version =%d\r\n"
"silent =%d\r\n"
"instdir_error=%d\r\n"
"rtl =%d\r\n"
"errlvl =%d\r\n",
extra->exec_flags->autoclose,
extra->exec_flags->all_user_var,
extra->exec_flags->exec_error,
extra->exec_flags->abort,
extra->exec_flags->exec_reboot,
extra->exec_flags->reboot_called,
extra->exec_flags->plugin_api_version,
extra->exec_flags->silent,
extra->exec_flags->instdir_error,
extra->exec_flags->rtl,
extra->exec_flags->errlvl);
MessageBoxW(g_hwndParent,buf,0,MB_OK);
}
}
void __declspec(dllexport)
runonce (HWND hwndParent, int string_size, LPTSTR variables,
stack_t **stacktop, extra_parameters_t *extra)
{
LPCWSTR result;
g_hwndParent = hwndParent;
EXDLL_INIT();
CreateMutexW (NULL, 0, getuservariable(INST_R0));
result = GetLastError ()? L"1" : L"0";
setuservariable (INST_R0, result);
}
-#include
+
+#ifdef ENABLE_SOUND_GADGET
+void __declspec(dllexport)
+playsound (HWND hwndParent, int string_size, char *variables,
+ stack_t **stacktop, extra_parameters_t *extra)
+{
+ char fname[MAX_PATH];
+
+ g_hwndParent = hwndParent;
+ EXDLL_INIT();
+
+ if (popstring(fname, sizeof fname))
+ return;
+ PlaySound (fname, NULL, SND_ASYNC|SND_FILENAME|SND_NODEFAULT);
+}
+
+
+void __declspec(dllexport)
+stopsound (HWND hwndParent, int string_size, char *variables,
+ stack_t **stacktop, extra_parameters_t *extra)
+{
+ g_hwndParent = hwndParent;
+ EXDLL_INIT();
+ PlaySound (NULL, NULL, 0);
+}
+#endif /*ENABLE_SOUND_GADGET*/
+
+
+#ifdef ENABLE_SPLASH_GADGET
+/* Windows procedure to control the splashimage. This one pauses the
+ execution until the sleep time is over or the user closes this
+ windows. */
+static LRESULT CALLBACK
+splash_wndproc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ LRESULT result = 0;
+
+ switch (uMsg)
+ {
+ case WM_CREATE:
+ {
+ BITMAP bm;
+ RECT vp;
+
+ GetObject(g_hbm, sizeof(bm), (LPSTR)&bm);
+ SystemParametersInfo(SPI_GETWORKAREA, 0, &vp, 0);
+ SetWindowLong(hwnd,GWL_STYLE,0);
+ SetWindowPos(hwnd,NULL,
+ vp.left+(vp.right-vp.left-bm.bmWidth)/2,
+ vp.top+(vp.bottom-vp.top-bm.bmHeight)/2,
+ bm.bmWidth,bm.bmHeight,
+ SWP_NOZORDER);
+ ShowWindow(hwnd,SW_SHOW);
+ SetTimer(hwnd,1,sleepint,NULL);
+ }
+ break;
+
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+ RECT r;
+ HDC curdc=BeginPaint(hwnd,&ps);
+ HDC hdc=CreateCompatibleDC(curdc);
+ HBITMAP oldbm;
+ GetClientRect(hwnd,&r);
+ oldbm=(HBITMAP)SelectObject(hdc,g_hbm);
+ BitBlt(curdc,r.left,r.top,r.right-r.left,r.bottom-r.top,
+ hdc,0,0,SRCCOPY);
+ SelectObject(hdc,oldbm);
+ DeleteDC(hdc);
+ EndPaint(hwnd,&ps);
+ }
+ break;
+
+ case WM_CLOSE:
+ break;
+
+ case WM_TIMER:
+ case WM_LBUTTONDOWN:
+ DestroyWindow(hwnd);
+ /*(fall through)*/
+ default:
+ result = DefWindowProc (hwnd, uMsg, wParam, lParam);
+ }
+
+ return result;
+}
+
+
+/* Display a splash screen. Call as
+
+ g4wihelp::showsplash SLEEP FNAME
+
+ With SLEEP being the time in milliseconds to show the splashscreen
+ and FNAME the complete filename of the image. As of now only BMP
+ is supported.
+*/
+void __declspec(dllexport)
+showsplash (HWND hwndParent, int string_size, char *variables,
+ stack_t **stacktop, extra_parameters_t *extra)
+{
+ static WNDCLASS wc;
+ char sleepstr[30];
+ char fname[MAX_PATH];
+ int err = 0;
+ char *p;
+ char classname[] = "_sp";
+
+ g_hwndParent = hwndParent;
+ EXDLL_INIT();
+ if (popstring(sleepstr, sizeof sleepstr))
+ err = 1;
+ if (popstring(fname, sizeof fname))
+ err = 1;
+ if (err)
+ return;
+
+ if (!*fname)
+ return; /* Nothing to do. */
+
+ for (sleepint=0, p=sleepstr; *p >= '0' && *p <= '9'; p++)
+ {
+ sleepint *= 10;
+ sleepint += *p - '0';
+ }
+ if (sleepint <= 0)
+ return; /* Nothing to do. */
+
+ wc.lpfnWndProc = splash_wndproc;
+ wc.hInstance = g_hInstance;
+ wc.hCursor = LoadCursor(NULL,IDC_ARROW);
+ wc.lpszClassName = classname;
+ if (!RegisterClass(&wc))
+ return; /* Error. */
+
+ g_hbm = LoadImage (NULL, fname, IMAGE_BITMAP,
+ 0, 0 , LR_CREATEDIBSECTION|LR_LOADFROMFILE);
+ if (g_hbm)
+ {
+ MSG msg;
+ HWND hwnd;
+
+ hwnd = CreateWindowEx (WS_EX_TOOLWINDOW, classname, classname,
+ 0, 0, 0, 0, 0, (HWND)hwndParent, NULL,
+ g_hInstance, NULL);
+
+ while (IsWindow(hwnd) && GetMessage ( &msg, hwnd, 0, 0))
+ {
+ DispatchMessage (&msg);
+ }
+
+ DeleteObject (g_hbm);
+ g_hbm = NULL;
+ }
+ UnregisterClass (classname, g_hInstance);
+}
+#endif /*ENABLE_SPLASH_GADGET*/
+
+
+#ifdef ENABLE_SERVICE_MANAGEMENT
+/* Use this to report unexpected errors. FIXME: This is really not
+ very descriptive. */
+void
+service_error (const char *str)
+{
+ char buf[1024];
+ snprintf (buf, sizeof (buf), "error: %s: ec=%d\r\n", str,
+ GetLastError ());
+ MessageBox(g_hwndParent, buf, 0, MB_OK);
+
+ setuservariable (INST_R0, "1");
+}
+
+
+void __declspec(dllexport)
+service_create (HWND hwndParent, int string_size, char *variables,
+ stack_t **stacktop, extra_parameters_t *extra)
+{
+ SC_HANDLE sc;
+ SC_HANDLE service;
+ const char *result = NULL;
+ char service_name[256];
+ char display_name[256];
+ char program[256];
+ int err = 0;
+
+ g_hwndParent = hwndParent;
+ EXDLL_INIT();
+
+ /* The expected stack layout: service_name, display_name, program. */
+ if (popstring (service_name, sizeof (service_name)))
+ err = 1;
+ if (!err && popstring (display_name, sizeof (display_name)))
+ err = 1;
+ if (!err && popstring (program, sizeof (program)))
+ err = 1;
+ if (err)
+ {
+ setuservariable (INST_R0, "1");
+ return;
+ }
+
+ sc = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);
+ if (sc == NULL)
+ {
+ service_error ("OpenSCManager");
+ return;
+ }
+
+ service = CreateService (sc, service_name, display_name,
+ SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
+ /* Use SERVICE_DEMAND_START for testing.
+ FIXME: Currently not configurable by caller. */
+ SERVICE_AUTO_START,
+ SERVICE_ERROR_NORMAL, program,
+ NULL, NULL, NULL,
+ /* FIXME: Currently not configurable by caller. */
+ /* FIXME: LocalService or NetworkService
+ don't work for dirmngr right now. NOTE!
+ If you change it here, you also should
+ adjust make-msi.pl for the msi
+ installer. In the future, this should
+ be an argument to the function and then
+ the make-msi.pl script can extract it
+ from the invocation. */
+ NULL /* "NT AUTHORITY\\LocalService" */,
+ NULL);
+ if (service == NULL)
+ {
+ service_error ("CreateService");
+ CloseServiceHandle (sc);
+ return;
+ }
+ CloseServiceHandle (service);
+
+ result = GetLastError () ? "1":"0";
+ setuservariable (INST_R0, result);
+ return;
+}
+
+
+/* Requires g_hwndParent to be set! */
+SC_HANDLE
+service_lookup (char *service_name)
+{
+ SC_HANDLE sc;
+ SC_HANDLE service;
+
+ sc = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);
+ if (sc == NULL)
+ {
+ service_error ("OpenSCManager");
+ return NULL;
+ }
+ service = OpenService (sc, service_name, SC_MANAGER_ALL_ACCESS);
+ if (service == NULL)
+ {
+ /* Fail silently here. */
+ CloseServiceHandle (sc);
+ return NULL;
+ }
+ CloseServiceHandle (sc);
+ return service;
+}
+
+
+/* Returns status. */
+void __declspec(dllexport)
+service_query (HWND hwndParent, int string_size, char *variables,
+ stack_t **stacktop, extra_parameters_t *extra)
+{
+ SC_HANDLE service;
+ const char *result = NULL;
+ char service_name[256];
+ int err = 0;
+ SERVICE_STATUS status;
+
+ g_hwndParent = hwndParent;
+ EXDLL_INIT();
+
+ /* The expected stack layout: service_name argc [argv]. */
+ if (popstring (service_name, sizeof (service_name)))
+ err = 1;
+ if (err)
+ {
+ setuservariable (INST_R0, "ERROR");
+ return;
+ }
+
+ service = service_lookup (service_name);
+ if (service == NULL)
+ if (err == 0)
+ {
+ setuservariable (INST_R0, "MISSING");
+ return;
+ }
+
+ err = QueryServiceStatus (service, &status);
+ if (err == 0)
+ {
+ setuservariable (INST_R0, "ERROR");
+ CloseServiceHandle (service);
+ return;
+ }
+ CloseServiceHandle (service);
+
+ switch (status.dwCurrentState)
+ {
+ case SERVICE_START_PENDING:
+ result = "START_PENDING";
+ break;
+ case SERVICE_RUNNING:
+ result = "RUNNING";
+ break;
+ case SERVICE_PAUSE_PENDING:
+ result = "PAUSE_PENDING";
+ break;
+ case SERVICE_PAUSED:
+ result = "PAUSED";
+ break;
+ case SERVICE_CONTINUE_PENDING:
+ result = "CONTINUE_PENDING";
+ break;
+ case SERVICE_STOP_PENDING:
+ result = "STOP_PENDING";
+ break;
+ case SERVICE_STOPPED:
+ result = "STOPPED";
+ break;
+ default:
+ result = "UNKNOWN";
+ }
+ setuservariable (INST_R0, result);
+ return;
+}
+
+
+void __declspec(dllexport)
+service_start (HWND hwndParent, int string_size, char *variables,
+ stack_t **stacktop, extra_parameters_t *extra)
+{
+ SC_HANDLE service;
+ const char *result = NULL;
+ char service_name[256];
+ char argc_str[256];
+#define NR_ARGS 10
+#define ARG_MAX 256
+ char argv_str[NR_ARGS][ARG_MAX];
+ const char *argv[NR_ARGS + 1];
+ int argc;
+ int i;
+ int err = 0;
+
+ g_hwndParent = hwndParent;
+ EXDLL_INIT();
+
+ /* The expected stack layout: service_name argc [argv]. */
+ if (popstring (service_name, sizeof (service_name)))
+ err = 1;
+ if (!err && popstring (argc_str, sizeof (argc_str)))
+ err = 1;
+ if (!err)
+ {
+ argc = atoi (argc_str);
+ for (i = 0; i < argc; i++)
+ {
+ if (popstring (argv_str[i], ARG_MAX))
+ {
+ err = 1;
+ break;
+ }
+ argv[i] = argv_str[i];
+ }
+ argv[i] = NULL;
+ }
+ if (err)
+ {
+ setuservariable (INST_R0, "1");
+ return;
+ }
+
+ service = service_lookup (service_name);
+ if (service == NULL)
+ return;
+
+ err = StartService (service, argc, argc == 0 ? NULL : argv);
+ if (err == 0)
+ {
+ service_error ("StartService");
+ CloseServiceHandle (service);
+ return;
+ }
+ CloseServiceHandle (service);
+
+ setuservariable (INST_R0, "0");
+ return;
+}
+
+
+void __declspec(dllexport)
+service_stop (HWND hwndParent, int string_size, char *variables,
+ stack_t **stacktop, extra_parameters_t *extra)
+{
+ SC_HANDLE service;
+ const char *result = NULL;
+ char service_name[256];
+ int err = 0;
+ SERVICE_STATUS status;
+ DWORD timeout = 10000; /* 10 seconds. */
+ DWORD start_time;
+
+ g_hwndParent = hwndParent;
+ EXDLL_INIT();
+
+ /* The expected stack layout: service_name argc [argv]. */
+ if (popstring (service_name, sizeof (service_name)))
+ err = 1;
+ if (err)
+ {
+ setuservariable (INST_R0, "1");
+ return;
+ }
+
+ service = service_lookup (service_name);
+ if (service == NULL)
+ return;
+
+ err = QueryServiceStatus (service, &status);
+ if (err == 0)
+ {
+ service_error ("QueryService");
+ CloseServiceHandle (service);
+ return;
+ }
+
+ if (status.dwCurrentState != SERVICE_STOPPED
+ && status.dwCurrentState != SERVICE_STOP_PENDING)
+ {
+ err = ControlService (service, SERVICE_CONTROL_STOP, &status);
+ if (err == 0)
+ {
+ service_error ("ControlService");
+ CloseServiceHandle (service);
+ return;
+ }
+ }
+
+ start_time = GetTickCount ();
+ while (status.dwCurrentState != SERVICE_STOPPED)
+ {
+ Sleep (1000); /* One second. */
+ if (!QueryServiceStatus (service, &status))
+ {
+ service_error ("QueryService");
+ CloseServiceHandle (service);
+ return;
+ }
+ if (status.dwCurrentState == SERVICE_STOPPED)
+ break;
+
+ if (GetTickCount () - start_time > timeout)
+ {
+ char buf[1024];
+ snprintf (buf, sizeof (buf),
+ "time out waiting for service %s to stop\r\n",
+ service_name);
+ MessageBox (g_hwndParent, buf, 0, MB_OK);
+ setuservariable (INST_R0, "1");
+ return;
+ }
+ }
+ CloseServiceHandle (service);
+ setuservariable (INST_R0, "0");
+ return;
+}
+
+
+void __declspec(dllexport)
+service_delete (HWND hwndParent, int string_size, char *variables,
+ stack_t **stacktop, extra_parameters_t *extra)
+{
+ SC_HANDLE service;
+ const char *result = NULL;
+ char service_name[256];
+ int err = 0;
+
+ g_hwndParent = hwndParent;
+ EXDLL_INIT();
+
+ /* The expected stack layout: service_name argc [argv]. */
+ if (popstring (service_name, sizeof (service_name)))
+ err = 1;
+ if (err)
+ {
+ setuservariable (INST_R0, "1");
+ return;
+ }
+
+ service = service_lookup (service_name);
+ if (service == NULL)
+ return;
+
+ err = DeleteService (service);
+ if (err == 0)
+ {
+ service_error ("DeleteService");
+ CloseServiceHandle (service);
+ return;
+ }
+ CloseServiceHandle (service);
+
+ setuservariable (INST_R0, "0");
+ return;
+}
+#endif /*ENABLE_SERVICE_MANAGEMENT*/
+
/* Extract config file parameters. FIXME: Not particularly robust.
We expect some reasonable formatting. The parser below is very
limited. It expects a command line option /c=FILE or /C=FILE,
where FILE must be enclosed in double-quotes if it contains spaces.
That file should contain a single section [gpg4win] and KEY=VALUE
pairs for each additional configuration file to install. Comments
are supported only on lines by themselves. VALUE can be quoted in
double-quotes, but does not need to be, unless it has whitespace at
the beginning or end. KEY can, for example, be "gpg.conf" (without
the quotes). */
void
config_init (char **keys, char **values, int max)
{
/* First, parse the command line. */
LPCWSTR wcmdline;
char *cmdline;
char *begin = NULL;
char *end = NULL;
char mark;
char *fname;
char *ptr;
FILE *conf;
*keys = NULL;
*values = NULL;
cmdline = malloc (4096);
if (!cmdline)
return;
wcmdline = getuservariable (INST_CMDLINE);
*cmdline = 0;
WideCharToMultiByte(CP_ACP, 0, wcmdline, -1, cmdline, 4095, NULL, NULL);
if (!*cmdline)
return;
mark = (*cmdline == '"') ? (cmdline++, '"') : ' ';
while (*cmdline && *cmdline != mark)
cmdline++;
if (mark == '"' && *cmdline)
cmdline++;
while (*cmdline && *cmdline == ' ')
cmdline++;
while (*cmdline)
{
/* We are at the beginning of a new argument. */
if (cmdline[0] == '/' && (cmdline[1] == 'C' || cmdline[1] == 'c')
&& cmdline[2] == '=')
{
cmdline += 3;
begin = cmdline;
}
while (*cmdline && *cmdline != ' ')
{
/* Skip over quoted parts. */
if (*cmdline == '"')
{
cmdline++;
while (*cmdline && *cmdline != '"')
cmdline++;
if (*cmdline)
cmdline++;
}
else
cmdline++;
}
if (begin && !end)
{
end = cmdline - 1;
break;
}
while (*cmdline && *cmdline == ' ')
cmdline++;
}
if (!begin || begin > end)
return;
/* Strip quotes. */
if (*begin == '"' && *end == '"')
{
begin++;
end--;
}
if (begin > end)
return;
fname = malloc (end - begin + 2);
if (!fname)
return;
ptr = fname;
while (begin <= end)
*(ptr++) = *(begin++);
*ptr = '\0';
conf = fopen (fname, "r");
free (fname);
free (cmdline);
if (!conf)
return;
while (max - 1 > 0)
{
char line[256];
char *ptr2;
if (fgets (line, sizeof (line), conf) == NULL)
break;
ptr = &line[strlen (line)];
while (ptr > line && (ptr[-1] == '\n' || ptr[-1] == '\r'
|| ptr[-1] == ' ' || ptr[-1] == '\t'))
ptr--;
*ptr = '\0';
ptr = line;
while (*ptr && (*ptr == ' ' || *ptr == '\t'))
ptr++;
/* Ignore comment lines. */
/* FIXME: Ignore section markers. */
if (*ptr == '\0' || *ptr == ';' || *ptr == '[')
continue;
begin = ptr;
while (*ptr && *ptr != '=' && *ptr != ' ' && *ptr != '\t')
ptr++;
end = ptr - 1;
while (*ptr && (*ptr == ' ' || *ptr == '\t'))
ptr++;
if (*ptr != '=')
continue;
ptr++;
if (begin > end)
continue;
/* We found a key. */
*keys = malloc (end - begin + 2);
if (!keys)
return;
ptr2 = *keys;
while (begin <= end)
*(ptr2++) = *(begin++);
*ptr2 = '\0';
*values = NULL;
while (*ptr && (*ptr == ' ' || *ptr == '\t'))
ptr++;
begin = ptr;
/* In this case, end points to the byte after the value, which
is OK because that is '\0'. */
end = &line[strlen (line)];
if (begin > end)
begin = end;
/* Strip quotes. */
if (*begin == '"' && end[-1] == '"')
{
begin++;
end--;
*end = '\0';
}
if (begin > end)
return;
*values = malloc (end - begin + 1);
ptr2 = *values;
while (begin <= end)
*(ptr2++) = *(begin++);
keys++;
values++;
max--;
}
fclose (conf);
*keys = NULL;
*values = NULL;
}
char *
config_lookup (char *key)
{
#define MAX_KEYS 128
static int initialised = 0;
static char *keys[MAX_KEYS];
static char *values[MAX_KEYS];
int i;
if (initialised == 0)
{
initialised = 1;
config_init (keys, values, MAX_KEYS);
#if 0
MessageBox(g_hwndParent, "Configuration File:", 0, MB_OK);
i = 0;
while (keys[i])
{
char buf[256];
sprintf (buf, "%s=%s\r\n", keys[i], values[i]);
MessageBox (g_hwndParent, buf, 0, MB_OK);
i++;
}
#endif
}
i = 0;
while (keys[i])
{
if (!strcmp (keys[i], key))
return values[i];
i++;
}
return NULL;
}
void __declspec(dllexport)
config_fetch (HWND hwndParent, int string_size, LPTSTR variables,
stack_t **stacktop, extra_parameters_t *extra)
{
char key[256];
int err = 0;
char *value;
g_hwndParent = hwndParent;
EXDLL_INIT();
/* The expected stack layout: key. */
if (PopStringNA (key, sizeof (key)))
err = 1;
if (err)
{
setuservariable (INST_R0, L"");
return;
}
value = config_lookup (key);
SetUserVariableA (INST_R0, value == NULL ? "" : value);
return;
}
void __declspec(dllexport)
config_fetch_bool (HWND hwndParent, int string_size, LPTSTR variables,
stack_t **stacktop, extra_parameters_t *extra)
{
char key[256];
int err = 0;
char *value;
int result;
g_hwndParent = hwndParent;
EXDLL_INIT();
/* The expected stack layout: key. */
if (PopStringNA (key, sizeof (key)))
err = 1;
if (err)
{
setuservariable (INST_R0, L"");
return;
}
value = config_lookup (key);
if (value == NULL || *value == '\0')
{
setuservariable (INST_R0, L"");
return;
}
result = 0;
if (!strcasecmp (value, "true")
|| !strcasecmp (value, "yes")
|| atoi (value) != 0)
result = 1;
SetUserVariableA (INST_R0, result == 0 ? "0" : "1");
return;
}
/* 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. */
-char *
-read_w32_registry_string (HKEY root, const char *dir, const char *name)
+static wchar_t *
+read_w32_registry_string (HKEY root, const wchar_t *dir, const wchar_t *name)
{
HKEY root_key;
HKEY key_handle;
DWORD n1, nbytes, type;
- char *result = NULL;
+ wchar_t *result = NULL;
root_key = root;
- if (! root_key)
+ if (!root_key)
root_key = HKEY_CURRENT_USER;
- if( RegOpenKeyExA( root_key, dir, 0, KEY_READ, &key_handle ) )
+ if (RegOpenKeyExW (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 (RegOpenKeyExA (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) )
+ if (RegOpenKeyExW (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle))
return NULL; /* still no need for a RegClose, so return direct */
}
nbytes = 1;
- if( RegQueryValueExA ( 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 (RegOpenKeyExA (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) )
- return NULL; /* Nope. */
- if (RegQueryValueExA ( key_handle, name, 0, NULL, NULL, &nbytes))
- goto leave;
+ if (RegQueryValueExW (key_handle, name, 0, NULL, NULL, &nbytes))
+ {
+ if (root)
+ goto leave;
+ /* Try to fallback to HKLM also for a missing value. */
+ RegCloseKey (key_handle);
+ if (RegOpenKeyExW (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle))
+ return NULL; /* Nope. */
+ if (RegQueryValueExW (key_handle, name, 0, NULL, NULL, &nbytes))
+ goto leave;
}
- result = malloc( (n1=nbytes+1) );
-
- if( !result )
- goto leave;
- if( RegQueryValueExA ( key_handle, name, 0, &type, result, &n1 ) ) {
- free(result); result = NULL;
+ result = calloc ((n1=nbytes+1), sizeof *result);
+ if (!result)
goto leave;
- }
- result[nbytes] = 0; /* make sure it is really a string */
+
+ if (RegQueryValueExW (key_handle, name, 0, &type,
+ (unsigned char *)result, &n1))
+ {
+ free (result);
+ result = NULL;
+ goto leave;
+ }
+ result[nbytes] = 0; /* Make sure it is really a string */
leave:
- RegCloseKey( key_handle );
+ RegCloseKey (key_handle);
return result;
}
+/* Registry keys for PATH for HKLM and HKCU. */
+#define ENV_HK HKEY_LOCAL_MACHINE
+#define ENV_REG L"SYSTEM\\CurrentControlSet\\Control\\" \
+ "Session Manager\\Environment"
+#define ENV_HK_USER HKEY_CURRENT_USER
+#define ENV_REG_USER L"Environment"
+
+/* Due to a bug in Windows7 (kb 2685893) we better put a lower limit
+ * than 8191 on the maximum length of the PATH variable. Note, that
+ * depending on the used toolchain we used to had a 259 byte limit in
+ * the past.
+ * [wk 2023-04-24]: Can this be lifted now that we use the wchar_t API?
+ */
+#define PATH_LENGTH_LIMIT 2047
+
+void __declspec(dllexport)
+path_add (HWND hwndParent, int string_size, LPTSTR variables,
+ stack_t **stacktop, extra_parameters_t *extra)
+{
+ wchar_t dir[PATH_LENGTH_LIMIT];
+ wchar_t is_user_install[2];
+ wchar_t *path;
+ wchar_t *path_new;
+ size_t path_new_size;
+ wchar_t *comp;
+ const wchar_t delims[] = L";";
+ int is_user;
+ HKEY key_handle = 0;
+ HKEY root_key;
+ const wchar_t *env_reg;
+ /* wchar_t *tokctx; Context var for wcstok - not yet needed. */
+
+ g_hwndParent = hwndParent;
+ EXDLL_INIT();
+
+ setuservariable (INST_R0, L"0"); /* Default return value. */
+
+ /* The expected stack layout: path component. */
+ if (popstringn (dir, COUNTOF (dir)))
+ return;
+ dir[COUNTOF(dir)-1] = 0;
+
+ /* The expected stack layout: HKEY component. */
+ if (popstringn (is_user_install, COUNTOF (is_user_install)))
+ return;
+ is_user_install[COUNTOF(is_user_install)-1] = 0;
+
+ if (!wcscmp (is_user_install, L"1"))
+ {
+ root_key = ENV_HK_USER;
+ env_reg = ENV_REG_USER;
+ }
+ else
+ {
+ root_key = ENV_HK;
+ env_reg = ENV_REG;
+ }
+
+ path = read_w32_registry_string (root_key, env_reg, L"Path");
+ if (!path)
+ {
+ path = wcsdup (L"");
+ }
+
+ /* Old path plus semicolon plus dir plus terminating nul. */
+ path_new_size = wcslen (path) + 1 + wcslen (dir) + 1;
+ if (path_new_size > PATH_LENGTH_LIMIT)
+ {
+ MessageBox (g_hwndParent, L"PATH env variable too big", 0, MB_OK);
+ free (path);
+ return;
+ }
+
+ path_new = calloc (path_new_size, sizeof *path_new);
+ if (!path_new)
+ {
+ free (path);
+ return;
+ }
+
+ wcscpy (path_new, path);
+ wcscat (path_new, L";");
+ wcscat (path_new, dir);
+
+ /* Check if the directory already exists in the path. */
+ comp = wcstok (path, delims/*, &tokctx*/);
+ do
+ {
+ /* MessageBox (g_hwndParent, comp, 0, MB_OK); */
+ if (!comp)
+ break;
+
+ if (!wcscmp (comp, dir))
+ {
+ free (path);
+ free (path_new);
+ return;
+ }
+ comp = wcstok (NULL, delims/*, &tokctx*/);
+ }
+ while (comp);
+ free (path);
+
+ /* Update the path key. */
+ RegCreateKeyW (root_key, env_reg, &key_handle);
+ RegSetValueEx (key_handle, L"Path", 0, REG_EXPAND_SZ,
+ (unsigned char*)path_new,
+ wcslen (path_new) * sizeof *path_new);
+ RegCloseKey (key_handle);
+ SetEnvironmentVariableW(L"PATH", path_new);
+ free (path_new);
+
+/* MessageBox (g_hwndParent, "XXX 9", 0, MB_OK); */
+
+ setuservariable (INST_R0, L"1"); /* success. */
+}
+
+
+void __declspec(dllexport)
+path_remove (HWND hwndParent, int string_size, LPTSTR variables,
+ stack_t **stacktop, extra_parameters_t *extra)
+{
+ wchar_t dir[PATH_LENGTH_LIMIT];
+ wchar_t is_user_install[2];
+ wchar_t *path;
+ wchar_t *path_new;
+ size_t path_new_size;
+ wchar_t *comp;
+ const wchar_t delims[] = L";";
+ HKEY key_handle = 0;
+ int changed = 0;
+ int count = 0;
+ HKEY root_key;
+ const wchar_t *env_reg;
+ /* wchar_t *tokctx; Context var for wcstok - not yet needed. */
+
+ g_hwndParent = hwndParent;
+ EXDLL_INIT();
+
+ setuservariable (INST_R0, L"0");
+
+ /* The expected stack layout: path component. */
+ if (popstringn (dir, COUNTOF (dir)))
+ return;
+ dir[COUNTOF(dir)-1] = 0;
+
+ /* The expected stack layout: HKEY component. */
+ if (popstringn (is_user_install, COUNTOF (is_user_install)))
+ return;
+ is_user_install[COUNTOF(is_user_install)-1] = 0;
+
+ if (!wcscmp (is_user_install, L"1"))
+ {
+ root_key = ENV_HK_USER;
+ env_reg = ENV_REG_USER;
+ }
+ else
+ {
+ root_key = ENV_HK;
+ env_reg = ENV_REG;
+ }
+
+ path = read_w32_registry_string (root_key, env_reg, L"Path");
+ if (!path)
+ return;
+
+ /* Old path plus semicolon plus dir plus terminating nul. */
+ path_new_size = wcslen (path) + 1;
+ path_new = calloc (path_new_size, sizeof *path_new);
+ if (!path_new)
+ {
+ free (path);
+ return;
+ }
+
+ /* Compose the new path. */
+ comp = wcstok (path, delims/*, &tokctx*/);
+ do
+ {
+ if (wcscmp (comp, dir))
+ {
+ if (count)
+ wcscat (path_new, L";");
+ wcscat (path_new, comp);
+ count++;
+ }
+ else
+ changed = 1;
+ }
+ while ((comp = wcstok (NULL, delims/*, &tokctx*/)));
+ free (path);
+
+ if (!changed)
+ {
+ free (path_new);
+ return;
+ }
+
+ /* Set a key for our CLSID. */
+ RegCreateKeyW (root_key, env_reg, &key_handle);
+ RegSetValueEx (key_handle, L"Path", 0, REG_EXPAND_SZ,
+ (unsigned char*)path_new,
+ wcslen (path_new) * sizeof *path_new);
+ RegCloseKey (key_handle);
+ free (path_new);
+
+ setuservariable (INST_R0, L"1"); /* success */
+}
+
+
/** @brief Kill processes with the name name.
*
* This function tries to kill a process using ExitProcess.
*
* If it does not work it does not work. No return values.
* The intention is to make an effort to kill something during
* installation / uninstallation.
*
* The function signature is explained by NSIS.
*/
void __declspec(dllexport) __cdecl KillProc(HWND hwndParent,
int string_size,
char *variables,
stack_t **stacktop)
{
HANDLE h;
PROCESSENTRY32 pe32;
if (!stacktop || !*stacktop || !(*stacktop)->text)
{
ERRORPRINTF ("Invalid call to KillProc.");
return;
}
h = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0);
if (h == INVALID_HANDLE_VALUE)
{
ERRORPRINTF ("Failed to create Toolhelp snapshot");
return;
}
pe32.dwSize = sizeof (PROCESSENTRY32);
if (!Process32First (h, &pe32))
{
ERRORPRINTF ("Failed to get first process");
CloseHandle (h);
return;
}
do
{
if (!wcscmp ((*stacktop)->text, pe32.szExeFile))
{
HANDLE hProc = OpenProcess (PROCESS_ALL_ACCESS, FALSE,
pe32.th32ProcessID);
if (!hProc)
{
ERRORPRINTF ("Failed to open process handle.");
continue;
}
if (!TerminateProcess (hProc, 1))
{
ERRORPRINTF ("Failed to terminate process.");
}
CloseHandle (hProc);
}
}
while (Process32Next (h, &pe32));
CloseHandle (h);
}
diff --git a/src/g4wihelp.nsi b/src/g4wihelp.nsi
index 54313c8f..fb23f9e9 100644
--- a/src/g4wihelp.nsi
+++ b/src/g4wihelp.nsi
@@ -1,44 +1,98 @@
# g4wihelp.nsi - Access g4wihelp.dll. -*- coding: latin-1; -*-
# Copyright (C) 2005, 2023 g10 Code GmbH
-#
+#
# This file is part of GPG4Win.
-#
+#
# GPG4Win is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-#
+#
# GPG4Win 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 General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
LangString T_AlreadyRunning ${LANG_ENGLISH} \
"An instance of this installer is already running."
#Function G4wTest
# Push $R0
# Push $R1
# StrCpy $R0 "mein argument 0"
# StrCpy $R1 "mein argument 1"
-# g4wihelp::dummy
+# g4wihelp::dummy
# Pop $R1
# Pop $R0
#FunctionEnd
Function G4wRunOnce
Push $R0
StrCpy $R0 "gpg4win"
g4wihelp::runonce
StrCmp $R0 0 +3
MessageBox MB_OK $(T_AlreadyRunning)
Abort
Pop $R0
FunctionEnd
+# AddToPath - Adds the given dir to the search path.
+# Input - head of the stack
+Function G4wAddToPath
+ ClearErrors
+ UserInfo::GetName
+ IfErrors add_admin
+ Pop $0
+ UserInfo::GetAccountType
+ Pop $1
+ StrCmp $1 "Admin" add_admin add_user
+
+add_admin:
+ Exch $0
+ g4wihelp::path_add "$0" "0"
+ goto add_done
+add_user:
+ Exch $0
+ g4wihelp::path_add "$0" "1"
+ goto add_done
+
+add_done:
+ StrCmp $R5 "0" add_to_path_done
+ SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
+ add_to_path_done:
+ Pop $0
+FunctionEnd
+
+
+# RemoveFromPath - Remove a given dir from the path
+# Input: head of the stack
+Function G4wRemoveFromPath
+ ClearErrors
+ UserInfo::GetName
+ IfErrors remove_admin
+ Pop $0
+ UserInfo::GetAccountType
+ Pop $1
+ StrCmp $1 "Admin" remove_admin remove_user
+
+remove_admin:
+ Exch $0
+ g4wihelp::path_remove "$0" "0"
+ goto remove_done
+remove_user:
+ Exch $0
+ g4wihelp::path_remove "$0" "1"
+ goto remove_done
+
+remove_done:
+ StrCmp $R5 "0" remove_from_path_done
+ SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
+ remove_from_path_done:
+ Pop $0
+FunctionEnd