diff --git a/src/Makefile.am b/src/Makefile.am index 96e36c2f..21675c2a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,635 +1,636 @@ # 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-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 # 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' # Qmake still writes debug names in pkgconfig files. define gpg4win_pkg_qtbase_post_install (cd $$$${pkgbdir}; \ 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 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 # 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) -static-libgcc -I. -O2 -c -o desktopshellrun.o $(srcdir)/desktopshellrun.cpp - $(CC) -static-libgcc -I. -O2 -c -o slideshow.o $(srcdir)/slideshow.cpp - $(CC) -static-libgcc -I. -shared -O2 -o g4wihelp.dll $(srcdir)/g4wihelp.c \ - desktopshellrun.o slideshow.o -lwinmm -lgdi32 -luserenv -lshell32 \ + $(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 $(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/desktopshellrun.cpp b/src/desktopshellrun.cpp index 9af54d21..69b6420b 100644 --- a/src/desktopshellrun.cpp +++ b/src/desktopshellrun.cpp @@ -1,296 +1,296 @@ /* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik * Copyright (C) 2016 Intevation GmbH * Software engineering by Intevation GmbH * * This file is Free Software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! */ #include #include #include #include #include #include #include #include #include #include #include #include "exdll.h" #ifndef INITGUID #define INITGUID #endif /* Some declarations missing in mingw-w64 3.1.0 taken from msdn */ #if ! defined (__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 5 __CRT_UUID_DECL(IShellWindows, 0x85CB6900, 0x4D95, 0x11CF, 0x96, 0x0C, 0x00, 0x80, 0xC7, 0xF4, 0xEE, 0x85); DEFINE_GUID(IID_IShellWindows, 0x85CB6900, 0x4D95, 0x11CF, 0x96, 0x0C, 0x00, 0x80, 0xC7, 0xF4, 0xEE, 0x85); DEFINE_GUID(CLSID_ShellWindows, 0x9BA05972, 0xF6A8, 0x11CF, 0xA4, 0x42, 0x00, 0xA0, 0xC9, 0x0A, 0x8F, 0x39); __CRT_UUID_DECL(IShellDispatch2, 0xA4C6892C, 0x3BA9, 0x11d2, 0x9D, 0xEA, 0x00, 0xC0, 0x4F, 0xB1, 0x61, 0x62); __CRT_UUID_DECL(IShellFolderViewDual, 0xe7a1af80, 0x4d96, 0x11cf, 0x96, 0x0c, 0x00, 0x80, 0xc7, 0xf4, 0xee, 0x85); #endif #ifndef SWC_DESKTOP /* Will probably be addedd in future mingw */ #define SWC_DESKTOP 0x00000008 /* from http://msdn.microsoft.com/en-us/library/windows/desktop/cc836581%28v=vs.85%29.aspx */ #endif #define UNUSED(x) (void)(x) /** @brief the actual execuation call on the shell dispatcher * * @param[in] disp The shell dispatcher to use for shell execute. * @param[in] fName The file that should be exectued. * @param[in] param Optinal parameters to add. * * @returns true on success. */ static bool shellexecute(IShellDispatch2 *disp, wchar_t *fName, wchar_t *param) { BSTR bName = NULL, bParam = NULL, bDir = NULL, bOp = NULL; VARIANT vParams[4]; HRESULT hr; if (!fName || !disp) { ERRORPRINTF ("Invalid call to shellexecute."); return false; } bName = SysAllocString(fName); bParam = SysAllocString(param ? param : L""); bDir = SysAllocString(L""); bOp = SysAllocString(L""); if (!bName || !bParam || !bDir || !bOp) { /* Out of memory */ ERRORPRINTF ("Failed to allocate bstr values "); return false; } vParams[0].vt = VT_BSTR; vParams[0].bstrVal = bParam; vParams[1].vt = VT_BSTR; vParams[1].bstrVal = bDir; vParams[2].vt = VT_BSTR; vParams[2].bstrVal = bOp; vParams[3].vt = VT_INT; vParams[3].intVal = SW_SHOWNORMAL; hr = disp->ShellExecute(bName, vParams[0], vParams[1], vParams[2], vParams[3]); SysFreeString(bName); SysFreeString(bParam); SysFreeString(bOp); SysFreeString(bDir); if (FAILED(hr)) { ERRORPRINTF ("Failed to execute."); return false; } return true; } #ifdef __cplusplus extern "C" { #endif /** @brief Execute a command with the current running shell. * * This function is intended to be called when you want to * make sure that your application is not executed with higher * privileges then the normal desktop session. * * The code is based on the idea: * http://blogs.msdn.com/b/oldnewthing/archive/2013/11/18/10468726.aspx * * The function signature is explained by NSIS. */ void __declspec(dllexport) __cdecl DesktopShellRun(HWND hwndParent, int string_size, char *variables, stack_t **stacktop) { UNUSED(hwndParent); UNUSED(string_size); HRESULT hr; wchar_t *wbuf = NULL; IShellWindows *shellWindows = NULL; IShellBrowser *shellBrowser = NULL; IShellView *shellView = NULL; IShellFolderViewDual *folderView = NULL; IShellDispatch2 *shellDispatch = NULL; IServiceProvider *serviceProv = NULL; HWND hwnd; IDispatch *disp = NULL, *bgDisp = NULL, *sDisp = NULL; VARIANT vEmpty = {}; if (!stacktop || !*stacktop || !(*stacktop)->text) { ERRORPRINTF ("Invalid call to exec :"); return; } /* Initialize com ctx */ hr = CoInitialize(NULL); if(FAILED(hr)) { ERRORPRINTF ("CoInitializeEx failed. error = 0x%lx.", hr); return; } /* Get the shell interface */ hr = CoCreateInstance(CLSID_ShellWindows, NULL, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&shellWindows)); if (FAILED(hr)) { ERRORPRINTF ("Failed to get shell interface."); goto done; } /* Get the desktop shell window */ hr = shellWindows->FindWindowSW(&vEmpty, &vEmpty, SWC_DESKTOP, (long*)&hwnd, SWFO_NEEDDISPATCH, &disp); if (FAILED(hr)) { ERRORPRINTF ("Failed to find the desktop dispatcher."); goto done; } hr = disp->QueryInterface(IID_PPV_ARGS(&serviceProv)); if (FAILED(hr)) { ERRORPRINTF ("Failed to get the service provider."); goto done; } /* Get the shell browser */ hr = serviceProv->QueryService(SID_STopLevelBrowser, IID_PPV_ARGS(&shellBrowser)); if (FAILED(hr)) { ERRORPRINTF ("Failed to find the top level browser."); goto done; } hr = shellBrowser->QueryActiveShellView(&shellView); if (FAILED(hr)) { ERRORPRINTF ("Failed to find the active view."); goto done; } hr = shellView->GetItemObject(SVGIO_BACKGROUND, IID_PPV_ARGS(&bgDisp)); if (FAILED(hr)) { ERRORPRINTF ("Failed to get the views background."); goto done; } hr = bgDisp->QueryInterface(IID_PPV_ARGS(&folderView)); if (FAILED(hr)) { ERRORPRINTF ("Failed to get the folder view."); goto done; } hr = folderView->get_Application(&sDisp); if (FAILED(hr)) { ERRORPRINTF ("Failed to get the shell dispatch."); goto done; } hr = sDisp->QueryInterface(IID_PPV_ARGS(&shellDispatch)); if (FAILED(hr)) { ERRORPRINTF ("Failed to get the shell dispatch interface."); goto done; } /* For unicodensis this has to be utf8 to wchar */ - wbuf = acp_to_wchar((*stacktop)->text, strlen((*stacktop)->text)); + wbuf = wcsdup ((*stacktop)->text); if (!wbuf) { ERRORPRINTF ("Failed to convert argument to wchar. error = 0x%lx.", hr); goto done; } if (!shellexecute(shellDispatch, wbuf, NULL)) { ERRORPRINTF ("Failed to execute."); } if (wbuf) free(wbuf); done: if (folderView) { folderView->Release(); } if (disp) { disp->Release(); } if (shellBrowser) { shellBrowser->Release(); } if (shellWindows) { shellWindows->Release(); } if (shellView) { shellView->Release(); } if (sDisp) { sDisp->Release(); } if (shellDispatch) { shellDispatch->Release(); } if (serviceProv) { serviceProv->Release(); } CoUninitialize(); return; } #ifdef __cplusplus } #endif diff --git a/src/exdll.h b/src/exdll.h index 0c36f28a..91e082f9 100644 --- a/src/exdll.h +++ b/src/exdll.h @@ -1,189 +1,162 @@ -/* exdll.h for use with gpg4win - * Copyright (C) 1999-2005 Nullsoft, Inc. - * - * This license applies to everything in the NSIS package, except - * where otherwise noted. - * - * 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. - ************************************************************ - * 2005-11-14 wk Applied license text to orginal exdll.h file from - * NSIS 2.0.4 and did some formatting changes. - */ - -#ifndef _EXDLL_H_ -#define _EXDLL_H_ - -/* only include this file from one place in your DLL. (it is all - static, if you use it in two places it will fail) */ +#include +#ifndef ___NSIS_PLUGIN__H___ +#define ___NSIS_PLUGIN__H___ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef NSISCALL +# define NSISCALL __stdcall +#endif +#if !defined(_WIN32) && !defined(LPTSTR) +# define LPTSTR TCHAR* +#endif + + + +#ifndef NSISCALL +# define NSISCALL WINAPI +#endif #define EXDLL_INIT() { \ g_stringsize=string_size; \ g_stacktop=stacktop; \ g_variables=variables; } -/* For page showing plug-ins */ -#define WM_NOTIFY_OUTER_NEXT (WM_USER+0x8) -#define WM_NOTIFY_CUSTOM_READY (WM_USER+0xd) -#define NOTIFY_BYE_BYE 'x' - typedef struct _stack_t { struct _stack_t *next; - char text[1]; /* This should be the length of string_size. */ +#ifdef UNICODE + WCHAR text[1]; // this should be the length of g_stringsize when allocating +#else + char text[1]; +#endif } stack_t; - -static unsigned int g_stringsize; -static stack_t **g_stacktop; -static char *g_variables; - -static int __stdcall popstring(char *str, size_t maxlen); /* 0 on success, 1 on empty stack */ -static void __stdcall pushstring(const char *str); - -enum - { - INST_0, // $0 - INST_1, // $1 - INST_2, // $2 - INST_3, // $3 - INST_4, // $4 - INST_5, // $5 - INST_6, // $6 - INST_7, // $7 - INST_8, // $8 - INST_9, // $9 - INST_R0, // $R0 - INST_R1, // $R1 - INST_R2, // $R2 - INST_R3, // $R3 - INST_R4, // $R4 - INST_R5, // $R5 - INST_R6, // $R6 - INST_R7, // $R7 - INST_R8, // $R8 - INST_R9, // $R9 - INST_CMDLINE, // $CMDLINE - INST_INSTDIR, // $INSTDIR - INST_OUTDIR, // $OUTDIR - INST_EXEDIR, // $EXEDIR - INST_LANG, // $LANGUAGE - __INST_LAST -}; - typedef struct { int autoclose; int all_user_var; int exec_error; int abort; int exec_reboot; int reboot_called; int XXX_cur_insttype; /* deprecated */ int XXX_insttype_changed; /* deprecated */ int silent; int instdir_error; int rtl; int errlvl; } exec_flags_t; typedef struct { exec_flags_t *exec_flags; int (__stdcall *ExecuteCodeSegment)(int, HWND); } extra_parameters_t; -/* Utility functions (not required but often useful). */ -static int __stdcall -popstring(char *str, size_t maxlen) +enum { - stack_t *th; - if (!g_stacktop || !*g_stacktop) - return 1; - th=(*g_stacktop); - lstrcpyn (str, th->text, maxlen); - *g_stacktop = th->next; - GlobalFree((HGLOBAL)th); - return 0; -} +INST_0, // $0 +INST_1, // $1 +INST_2, // $2 +INST_3, // $3 +INST_4, // $4 +INST_5, // $5 +INST_6, // $6 +INST_7, // $7 +INST_8, // $8 +INST_9, // $9 +INST_R0, // $R0 +INST_R1, // $R1 +INST_R2, // $R2 +INST_R3, // $R3 +INST_R4, // $R4 +INST_R5, // $R5 +INST_R6, // $R6 +INST_R7, // $R7 +INST_R8, // $R8 +INST_R9, // $R9 +INST_CMDLINE, // $CMDLINE +INST_INSTDIR, // $INSTDIR +INST_OUTDIR, // $OUTDIR +INST_EXEDIR, // $EXEDIR +INST_LANG, // $LANGUAGE +__INST_LAST +}; -static void __stdcall -pushstring(const char *str) -{ - stack_t *th; - if (!g_stacktop) return; - th=(stack_t*)GlobalAlloc(GPTR,sizeof(stack_t)+g_stringsize); - lstrcpyn(th->text,str,g_stringsize); - th->next=*g_stacktop; - *g_stacktop=th; +extern unsigned int g_stringsize; +extern stack_t **g_stacktop; +extern LPTSTR g_variables; + +void NSISCALL pushstring(LPCTSTR str); +void NSISCALL pushintptr(INT_PTR value); +#define pushint(v) pushintptr((INT_PTR)(v)) +int NSISCALL popstring(LPTSTR str); // 0 on success, 1 on empty stack +int NSISCALL popstringn(LPTSTR str, int maxlen); // with length limit, pass 0 for g_stringsize +INT_PTR NSISCALL popintptr(); +#define popint() ( (int) popintptr() ) +int NSISCALL popint_or(); // with support for or'ing (2|4|8) +INT_PTR NSISCALL nsishelper_str_to_ptr(LPCTSTR s); +#define myatoi(s) ( (int) nsishelper_str_to_ptr(s) ) // converts a string to an integer +unsigned int NSISCALL myatou(LPCTSTR s); // converts a string to an unsigned integer, decimal only +int NSISCALL myatoi_or(LPCTSTR s); // with support for or'ing (2|4|8) +LPTSTR NSISCALL getuservariable(const int varnum); +void NSISCALL setuservariable(const int varnum, LPCTSTR var); + +#ifdef UNICODE +#define PopStringW(x) popstring(x) +#define PushStringW(x) pushstring(x) +#define SetUserVariableW(x,y) setuservariable(x,y) + +int NSISCALL PopStringA(LPSTR ansiStr); +void NSISCALL PushStringA(LPCSTR ansiStr); +void NSISCALL GetUserVariableW(const int varnum, LPWSTR wideStr); +void NSISCALL GetUserVariableA(const int varnum, LPSTR ansiStr); +void NSISCALL SetUserVariableA(const int varnum, LPCSTR ansiStr); + +#else +// ANSI defs + +#define PopStringA(x) popstring(x) +#define PushStringA(x) pushstring(x) +#define SetUserVariableA(x,y) setuservariable(x,y) + +int NSISCALL PopStringW(LPWSTR wideStr); +void NSISCALL PushStringW(LPWSTR wideStr); +void NSISCALL GetUserVariableW(const int varnum, LPWSTR wideStr); +void NSISCALL GetUserVariableA(const int varnum, LPSTR ansiStr); +void NSISCALL SetUserVariableW(const int varnum, LPCWSTR wideStr); + +#endif + +#ifdef __cplusplus } +#endif -static char * __stdcall -getuservariable(const int varnum) -{ - if (varnum < 0 || varnum >= __INST_LAST) return NULL; - return g_variables+varnum*g_stringsize; -} +#endif//!___NSIS_PLUGIN__H___ -static void __stdcall -setuservariable(const int varnum, const char *var) -{ - if (var != NULL && varnum >= 0 && varnum < __INST_LAST) - lstrcpy(g_variables + varnum*g_stringsize, var); -} +#ifndef COUNTOF +#define COUNTOF(a) (sizeof(a)/sizeof(a[0])) +#endif + +// minimal tchar.h emulation +#ifndef _T +# define _T TEXT +#endif +#if !defined(TCHAR) && !defined(_TCHAR_DEFINED) +# ifdef UNICODE +# define TCHAR WCHAR +# else +# define TCHAR char +# endif +#endif + +#define isvalidnsisvarindex(varnum) ( ((unsigned int)(varnum)) < (__INST_LAST) ) #define ERRORPRINTF(fmt, ...) \ { \ char buf[512]; \ snprintf(buf, 511, "ERROR: " fmt, ##__VA_ARGS__); \ buf[511] = '\0'; \ OutputDebugStringA(buf); \ } - -static wchar_t -*acp_to_wchar (const char *string, size_t len) -{ - int n, ilen; - wchar_t *result; - - ilen = (int) len; - if (ilen < 0) - return NULL; - - n = MultiByteToWideChar (CP_ACP, 0, string, ilen, NULL, 0); - if (n < 0 || n + 1 < 0) - return NULL; - - result = (wchar_t *) malloc ((size_t)(n+1) * sizeof *result); - if (!result) - { - ERRORPRINTF("Out of core"); - exit(1); - } - n = MultiByteToWideChar (CP_ACP, 0, string, ilen, result, n); - if (n < 0) - { - if (result) - free (result); - return NULL; - } - result[n] = 0; - return result; -} - - -#endif//_EXDLL_H_ diff --git a/src/g4wihelp.c b/src/g4wihelp.c index ddb7eb59..2a65142e 100644 --- a/src/g4wihelp.c +++ b/src/g4wihelp.c @@ -1,1029 +1,519 @@ /* g4wihelp.c - NSIS Helper DLL used with gpg4win. -*- coding: latin-1; -*- * Copyright (C) 2005 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] */ #include #include #include #include #include "exdll.h" 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. */ void slide_stop(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop); /* 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); return TRUE; } /* Dummy function for testing. */ void __declspec(dllexport) dummy (HWND hwndParent, int string_size, char *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 { char buf[1024]; sprintf(buf,"$R0=%s\r\n$R1=%s\r\n", getuservariable(INST_R0), getuservariable(INST_R1)); MessageBox(g_hwndParent,buf,0,MB_OK); sprintf (buf, "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" "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->silent, extra->exec_flags->instdir_error, extra->exec_flags->rtl, extra->exec_flags->errlvl); MessageBox(g_hwndParent,buf,0,MB_OK); } } void __declspec(dllexport) runonce (HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters_t *extra) { - const char *result; + LPCTSTR result; g_hwndParent = hwndParent; EXDLL_INIT(); - CreateMutexA (NULL, 0, getuservariable(INST_R0)); - result = GetLastError ()? "1":"0"; + CreateMutexA (NULL, 0, "gpg4win"); + result = GetLastError ()? L"1" : L"0"; + OutputDebugStringA ("Runonce returns:"); + OutputDebugStringW (result); setuservariable (INST_R0, result); } -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); -} - - -/* 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); -} - - -/* 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) - 1, "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]; - 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) - 1, - "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; -} - - #include /* 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. */ char *cmdline; char *begin = NULL; char *end = NULL; char mark; char *fname; char *ptr; FILE *conf; *keys = NULL; *values = NULL; cmdline = getuservariable (INST_CMDLINE); 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); 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, char *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 (popstring (key, sizeof (key))) + if (popstringn (key, sizeof (key))) err = 1; if (err) { setuservariable (INST_R0, ""); return; } value = config_lookup (key); setuservariable (INST_R0, value == NULL ? "" : value); return; } void __declspec(dllexport) config_fetch_bool (HWND hwndParent, int string_size, char *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 (popstring (key, sizeof (key))) + if (popstringn (key, sizeof (key))) err = 1; if (err) { setuservariable (INST_R0, ""); return; } value = config_lookup (key); if (value == NULL || *value == '\0') { setuservariable (INST_R0, ""); return; } result = 0; if (!strcasecmp (value, "true") || !strcasecmp (value, "yes") || atoi (value) != 0) result = 1; setuservariable (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) { HKEY root_key; HKEY key_handle; DWORD n1, nbytes, type; char *result = NULL; root_key = root; if (! root_key) root_key = HKEY_CURRENT_USER; if( RegOpenKeyEx( root_key, dir, 0, KEY_READ, &key_handle ) ) { if (root) return NULL; /* no need for a RegClose, so return direct */ /* It seems to be common practise to fall back to HKLM. */ if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) ) return NULL; /* still no need for a RegClose, so return direct */ } nbytes = 1; if( RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes ) ) { if (root) goto leave; /* Try to fallback to HKLM also vor a missing value. */ RegCloseKey (key_handle); if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) ) return NULL; /* Nope. */ if (RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes)) goto leave; } result = malloc( (n1=nbytes+1) ); if( !result ) goto leave; if( RegQueryValueEx( key_handle, name, 0, &type, result, &n1 ) ) { free(result); result = NULL; goto leave; } result[nbytes] = 0; /* make sure it is really a string */ leave: RegCloseKey( key_handle ); return result; } /** @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 (!strcmp ((*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 f6574087..54313c8f 100644 --- a/src/g4wihelp.nsi +++ b/src/g4wihelp.nsi @@ -1,44 +1,44 @@ # g4wihelp.nsi - Access g4wihelp.dll. -*- coding: latin-1; -*- -# Copyright (C) 2005 g10 Code GmbH +# 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 # 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 diff --git a/src/installer.nsi b/src/installer.nsi index 2f43701f..b8732980 100644 --- a/src/installer.nsi +++ b/src/installer.nsi @@ -1,784 +1,784 @@ # installer.nsi - Installer for GnuPG 4 Windows. -*- coding: latin-1; -*- # Copyright (C) 2005, 2007 g10 Code GmbH # Copyright (C) 2017 Intevation 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 # No servicable parts beyond this line. Stay clear :) !ifdef REQUIRE_W32_NSIS !ifdef PACKAGE_LIBRARY !include "Library.nsh" !endif !else !macro InstallLib libtype shared install localfile destfile tempbasedir File "${localfile}" !macroend !endif !include "FileFunc.nsh" !include "WinMessages.nsh" !include "WinVer.nsh" # We use the modern UI 2. !include "MUI2.nsh" !ifdef DEBUG !undef DEBUG !endif # Set the package name. Note that this name should not be sufficed # with the version because this would get displayed in the start menu. Name "${PRETTY_PACKAGE}" OutFile "${PACKAGE}-${VERSION}.exe" BrandingText "${PRETTY_PACKAGE}-${VERSION}" # Details button conflicts with splashscreen ShowInstDetails nevershow # Set the installation directory. !ifndef INSTALL_DIR !define INSTALL_DIR "${PACKAGE}" !endif InstallDir "$PROGRAMFILES\${INSTALL_DIR}" # Add version information to the file properties. VIProductVersion "${PROD_VERSION}" VIAddVersionKey "ProductName" "${PRETTY_PACKAGE_SHORT} (${VERSION})" !ifdef LICENSE_GPL VIAddVersionKey "Comments" \ "${PRETTY_PACKAGE_SHORT} is Free Software; you can redistribute it \ and/or modify it under the terms of the GNU General Public License. \ You should have received a copy of the GNU General Public License \ along with this software; if not, write to the Free Software \ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, \ MA 02110-1301, USA" !else VIAddVersionKey "Comments" \ "${PRETTY_PACKAGE_SHORT} is Free Software; you can redistribute it \ and/or modify it under the terms of the GNU Lesser General Public \ License. You should have received a copy of the GNU Lesser General \ Public License along with this software; if not, write to the Free \ Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, \ MA 02110-1301, USA" !endif VIAddVersionKey "CompanyName" "${COMPANY}" VIAddVersionKey "LegalTrademarks" "" VIAddVersionKey "LegalCopyright" "${COPYRIGHT}" VIAddVersionKey "FileDescription" "${DESCRIPTION}" VIAddVersionKey "FileVersion" "${PROD_VERSION}" # Set to the name of another GnuPG installation if one has been detected Var OtherGnuPGDetected # Interface Settings # !define MUI_ABORTWARNING !define MUI_FINISHPAGE_NOAUTOCLOSE !define MUI_UNFINISHPAGE_NOAUTOCLOSE !define MUI_HEADERIMAGE !define MUI_HEADERIMAGE_BITMAP \ "${TOP_SRCDIR}/doc/logo/gpg4win-nsis-header-install-150x57.bmp" !define MUI_HEADERIMAGE_UNBITMAP \ "${TOP_SRCDIR}/doc/logo/gpg4win-nsis-header-uninstall-150x57.bmp" !define MUI_WELCOMEFINISHPAGE_BITMAP \ "${TOP_SRCDIR}/doc/logo/gpg4win-nsis-wizard-install-164x314.bmp" !define MUI_UNWELCOMEFINISHPAGE_BITMAP \ "${TOP_SRCDIR}/doc/logo/gpg4win-nsis-wizard-uninstall-164x314.bmp" !define MUI_ICON "${TOP_SRCDIR}/doc/logo/gpg4win-nsis-install.ico" !define MUI_UNICON "${TOP_SRCDIR}/doc/logo/gpg4win-nsis-uninstall.ico" # Remember the installer language !define MUI_LANGDLL_REGISTRY_ROOT "SHCTX" !define MUI_LANGDLL_REGISTRY_KEY "Software\${PRETTY_PACKAGE_SHORT}" !define MUI_LANGDLL_REGISTRY_VALUENAME "Installer Language" # No Umlaute, please! !define MUI_LANGDLL_INFO "Please choose a language for the setup.$\r$\n\ Bitte die Sprache des Installations-Vorgangs angeben." # The list of wizard pages. !define MUI_WELCOMEPAGE_TITLE "${WELCOME_TITLE_STR}" !define MUI_PAGE_CUSTOMFUNCTION_SHOW WelcomeFunction !define MUI_WELCOMEPAGE_TEXT "${ABOUT_STR}" !insertmacro MUI_PAGE_WELCOME Function WelcomeFunction IfSilent leave ClearErrors ReadRegStr $0 SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\GPG4Win" "DisplayVersion" IfErrors leave 0 StrCmp $0 "" leave SendMessage $mui.WelcomePage.Text ${WM_SETTEXT} 0 "STR:${ABOUT_STR}$\r$\n$(T_UPDATE_STR) $0" leave: FunctionEnd #!define MUI_LICENSEPAGE_BUTTON "$(^NextBtn)" #!define MUI_PAGE_HEADER_SUBTEXT "$(T_GPLHeader)" #!insertmacro MUI_PAGE_LICENSE "license.blurb" !define MUI_PAGE_CUSTOMFUNCTION_SHOW PrintNonAdminWarning !insertmacro MUI_PAGE_COMPONENTS !define MUI_PAGE_CUSTOMFUNCTION_LEAVE CheckExistingVersion !insertmacro MUI_PAGE_DIRECTORY !define MUI_PAGE_CUSTOMFUNCTION_PRE BeforeInstallHooks !insertmacro MUI_PAGE_INSTFILES # Finish page !ifndef SOURCES !define MUI_PAGE_CUSTOMFUNCTION_PRE ShowFinalWarnings !define MUI_PAGE_CUSTOMFUNCTION_SHOW FinishFunction !define MUI_FINISHPAGE_RUN !define MUI_FINISHPAGE_RUN_FUNCTION RunAsUser !define MUI_FINISHPAGE_SHOWREADME "share\gpg4win\README.$(T_LangCode).txt" !define MUI_FINISHPAGE_SHOWREADME_TEXT "$(T_ShowReadme)" !define MUI_FINISHPAGE_SHOWREADME_NOTCHECKED !define MUI_FINISHPAGE_LINK "$(T_MoreInfo)" !define MUI_FINISHPAGE_LINK_LOCATION "$(T_MoreInfoURL)" !insertmacro MUI_PAGE_FINISH Function FinishFunction IfSilent leave !insertmacro SectionFlagIsSet ${SEC_kleopatra} \ ${SF_SELECTED} have_kleo have_nothing have_nothing: ShowWindow $mui.FinishPage.Run ${SW_HIDE} goto leave have_kleo: SendMessage $mui.FinishPage.Run.Text ${WM_SETTEXT} 0 "STR:$(T_RunKleopatra)" goto leave leave: FunctionEnd Function RunAsUser !insertmacro SectionFlagIsSet ${SEC_kleopatra} \ ${SF_SELECTED} do_kleo leave do_kleo: g4wihelp::DesktopShellRun "$INSTDIR\bin\kleopatra.exe" leave: FunctionEnd LangString T_RunKleopatra ${LANG_ENGLISH} \ "Run Kleopatra" # /SOURCES !endif # Uninstaller pages. !insertmacro MUI_UNPAGE_WELCOME !insertmacro MUI_UNPAGE_CONFIRM !ifndef SOURCES !define MUI_PAGE_CUSTOMFUNCTION_PRE un.CloseApps !endif !insertmacro MUI_UNPAGE_INSTFILES #!insertmacro MUI_UNPAGE_FINISH #Page license #Page components #Page directory #Page instfiles #UninstPage uninstConfirm #UninstPage instfiles # Language support. This has to be done after defining the pages, but # before defining the translation strings. Confusing. # Enable this to not filter languages for the current code page. Note # that languages which are then not filtered out may not be displayed # correctly in the Windows version the user is using. Not recommended, # but can be useful for testing. !ifdef DEBUG !define MUI_LANGDLL_ALLLANGUAGES !endif !insertmacro MUI_LANGUAGE "English" !define PO_HEADER !include "../po/catalogs.nsi" !undef PO_HEADER !insertmacro MUI_RESERVEFILE_LANGDLL ReserveFile "${BUILD_DIR}\g4wihelp.dll" !ifdef SOURCES ReserveFile "${TOP_SRCDIR}\doc\logo\gpg4win-logo-400px.bmp" ReserveFile "${TOP_SRCDIR}\src\gpg4win-splash.wav" !endif ReserveFile "${TOP_SRCDIR}\COPYING" ReserveFile "${TOP_SRCDIR}\doc\logo\gpg4win-logo-164x314.bmp" # Language support LangString T_LangCode ${LANG_ENGLISH} "en" # Startup page LangString T_GPLHeader ${LANG_ENGLISH} \ "This software is licensed under the terms of the GNU General Public \ License (GNU GPL)." LangString T_GPLShort ${LANG_ENGLISH} \ "In short: You are allowed to run this software for any purpose. \ You may distribute it as long as you give the recipients the same \ rights you have received." LangString T_MoreInfo ${LANG_ENGLISH} \ "Go to Gpg4win's webpage" LangString T_MoreInfoURL ${LANG_ENGLISH} "https://www.gpg4win.org" LangString T_ShowReadme ${LANG_ENGLISH} \ "Show the README file" LangString T_NoKeyManager ${LANG_ENGLISH} \ "No key manager has been installed, thus we can't run one now." # Used as subdirectory name in Start Menu. LangString DESC_Menu_manuals ${LANG_ENGLISH} \ "Documentation" LangString DESC_Menu_uninstall ${LANG_ENGLISH} \ "Uninstall" # Used as subdirectory name on Desktop. LangString DESC_Desktop_manuals ${LANG_ENGLISH} \ "Gpg4win Documentation" # Functions # Custom functions and macros for gpg4win. !include "g4wihelp.nsi" # Display a warning if this is a Beta version. #Function PrintBetaWarning # MessageBox MB_OK "$(T_BetaWarning)" #FunctionEnd # Display a warning if GnuPP has been detected and allow the user to abort # the installation. Function PrintGnuPPWarning MessageBox MB_YESNO "$(T_FoundOldGnuPP)" IDYES cont Abort cont: StrCpy $OtherGnuPGDetected "GnuPP" FunctionEnd # Display a warning if GnuPT has been detected and allow the user to abort # the installation. Function PrintGnuPTWarning MessageBox MB_YESNO "$(T_FoundOldGnuPT)" IDYES cont Abort cont: StrCpy $OtherGnuPGDetected "GnuPT" FunctionEnd # Display a warning if the Sourceforge WinPT has been detected and # allow the user to abort the installation. Function PrintWinPTSFWarning MessageBox MB_YESNO "$(T_FoundOldWinPTSF)" IDYES cont Abort cont: StrCpy $OtherGnuPGDetected "WinPT-SF" FunctionEnd # Display a warning if GnuPG Pack has been detected and abort the # the installation. This one clobbers our own Registry space. Function PrintGnuPackWarning MessageBox MB_OK "$(T_FoundOldGnuPack)" Abort FunctionEnd # Check whether one of the other GnuPG systems has already been # installed. We do this by looking at the registry. !ifndef SOURCES Function CheckOtherGnuPGApps StrCpy $OtherGnuPGDetected "" ClearErrors ReadRegStr $0 SHCTX "Software\GNU\GnuPP\Settings" "Path" IfErrors +2 0 Call PrintGnuPPWarning EnumRegKey $0 HKCU "Software\Microsoft\Windows\CurrentVersion\Explorer\MenuOrder\Start Menu\Programs\GnuPT" 0 StrCmp $0 "" +2 Call PrintGnuPTWarning ClearErrors ReadRegStr $0 SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\Windows Privacy Tools" "DisplayVersion" IfErrors +2 0 Call PrintWinPTSFWarning ReadRegStr $0 SHCTX "Software\GNU\GnuPG" "Install Directory" Push $0 Push "GnuPG-Pack" Call StrStr Pop $0 StrCmp $0 "" +2 Call PrintGnuPackWarning FunctionEnd !endif # Check whether gpg4win has already been installed. This is called as # a leave function from the directory page. A call to abort will get # back to the directory selection. Function CheckExistingVersion ClearErrors FileOpen $0 "$INSTDIR\VERSION" r IfErrors leave FileRead $0 $R0 FileRead $0 $R1 FileClose $0 Push $R1 Call TrimNewLines Pop $R1 # Extract major version. StrCpy $0 $R1 2 StrCmp $0 "1." 0 leave MessageBox MB_YESNO "$(T_FoundExistingOldVersion)" IDYES leave Abort leave: FunctionEnd # PrintNonAdminWarning # Check whether the current user is in the Administrator group or an # OS version without the need for an Administrator is in use. Print a # diagnostic if this is not the case and abort installation. Function PrintNonAdminWarning #Call PrintBetaWarning ClearErrors UserInfo::GetName IfErrors leave Pop $0 UserInfo::GetAccountType Pop $1 StrCmp $1 "Admin" leave +1 MessageBox MB_YESNO "$(T_AdminWanted)" IDNO exit goto leave exit: Quit leave: FunctionEnd # Check for claws mail installation which was shipped in Gpg4win # versions < 2.2.6 Function CheckClawsUninstall IfFileExists $INSTDIR\claws-mail.exe 0 leave MessageBox MB_YESNO "$(T_FoundOldClaws)" IDYES uninstall IDNO leave uninstall: !insertmacro SelectSection ${SecUninstClawsMail} leave: FunctionEnd # Check whether this is a reinstall and popup a message box to explain # that it is better to close other apps before continuing Function KillOtherAppsOrWarn g4wihelp::KillProc "kleopatra.exe" g4wihelp::KillProc "gpgme-w32spawn.exe" g4wihelp::KillProc "resolver.exe" g4wihelp::KillProc "overlayer.exe" g4wihelp::KillProc "gpg-agent.exe" g4wihelp::KillProc "gpg.exe" g4wihelp::KillProc "dirmngr.exe" g4wihelp::KillProc "gpgsm.exe" goto leave # TODO check for running outlook and offer to kill it. print_warning: MessageBox MB_OK|MB_ICONEXCLAMATION "$(T_CloseOtherApps)" leave: FunctionEnd Function un.CloseApps g4wihelp::KillProc "kleopatra.exe" g4wihelp::KillProc "gpgme-w32spawn.exe" g4wihelp::KillProc "resolver.exe" g4wihelp::KillProc "overlayer.exe" g4wihelp::KillProc "gpg-agent.exe" g4wihelp::KillProc "gpg.exe" g4wihelp::KillProc "dirmngr.exe" g4wihelp::KillProc "gpgsm.exe" FunctionEnd # Called right before installation Function BeforeInstallHooks Call CheckClawsUninstall FunctionEnd # Called right before the final page to show more warnings. Function ShowFinalWarnings StrCmp $OtherGnupgDetected "" +2 MessageBox MB_OK "$(T_FoundOldSeeManual)" leave: FunctionEnd #----------------------------------------------- # Strings pertaining to the install options page #----------------------------------------------- # Installation options title LangString T_InstallOptions ${LANG_ENGLISH} "Install Options" # Installation options subtitle 1 LangString T_InstallOptLinks ${LANG_ENGLISH} "Start links" LangString T_InstOptLabelA ${LANG_ENGLISH} \ "Please select where Gpg4win shall install links:" LangString T_InstOptLabelB ${LANG_ENGLISH} \ "(Only programs will be linked into the quick launch bar.)" LangString T_InstOptFieldA ${LANG_ENGLISH} \ "Start Menu" LangString T_InstOptFieldB ${LANG_ENGLISH} \ "Desktop" LangString T_InstOptFieldC ${LANG_ENGLISH} \ "Quick Launch Bar" #------------------------------------------------ # String pertaining to the existing version check #------------------------------------------------ LangString T_FoundExistingVersion ${LANG_ENGLISH} \ "Version $R1 has already been installed. $\r$\n\ Do you want to overwrite it with version ${VERSION}?" LangString T_FoundExistingOldVersion ${LANG_ENGLISH} \ "An old version $R1 has already been installed. It is \ strongly recommended to deinstall previous versions on \ major upgrades. $\r$\n\ Do you want to continue installing Gpg4win ${VERSION} anyway?" LangString T_UninstallingOldVersion ${LANG_ENGLISH} \ "Uninstalling Gpg4win-" #--------------------------------------------- # From the old installation checking functions #--------------------------------------------- LangString T_FoundOldSeeManual ${LANG_ENGLISH} \ "Please see the Gpg4win user manual to learn how to migrate existing \ keys from other GnuPG based installations to Gpg4win." #--------- LangString T_FoundOldGnuPP ${LANG_ENGLISH} \ "An old installation of GnuPP (GNU Privacy Project) has been \ detected. That software is not maintained anymore and thus should \ be removed. $\r$\n\ $\r$\n\ Do you want to continue installing Gpg4win and take care of the old \ installation later?" #--------- LangString T_FoundOldGnuPT ${LANG_ENGLISH} \ "An installation of GnuPT has been detected. This may cause \ problems when used along with Gpg4win. $\r$\n\ $\r$\n\ Do you want to continue installing Gpg4win?" #--------- LangString T_FoundOldWinPTSF ${LANG_ENGLISH} \ "An old installation of the Sourceforge hosted WinPT has been \ detected. That software is not maintained anymore and should \ be removed. $\r$\n\ $\r$\n\ Do you want to continue installing Gpg4win and take care of the old \ installation later?" #-------- LangString T_FoundOldGnuPack ${LANG_ENGLISH} \ "An installation of GnuPG-Pack has been detected. You need to \ uninstall it before you can continue with Gpg4win installation. $\r$\n\ $\r$\n\ The installation will be aborted now!" # From Function PrintBetaWarning LangString T_BetaWarning ${LANG_ENGLISH} \ "Note: This is a BETA version of Gpg4win. $\r$\n\ $\r$\n\ Beta versions are only intended for testing and \ shall not be used in a production environment." # From Function PrintNonAdminWarning LangString T_AdminWanted ${LANG_ENGLISH} \ "Warning: It is recommended to install Gpg4win system-wide with \ administrator rights. \ $\r$\n\ $\r$\n\ Do you want to continue installing Gpg4win without administrator rights?" # From Function KillOtherAppsOrWarn LangString T_CloseOtherApps ${LANG_ENGLISH} \ "Please make sure that other applications are not running. \ In particular you should close Outlook and all Explorer \ windows. Gpg4win will try to install anyway but a reboot \ will be required then." LangString T_ShuttingDownWinPT ${LANG_ENGLISH} \ "Trying to shutdown a possible running instance of WinPT." # From Function CheckClawsUninstall LangString T_FoundOldClaws ${LANG_ENGLISH} \ "An old version of Claws Mail was found in your Installation directory. \ $\r$\nPlease note that Claws Mail is no longer bundled with Gpg4win \ and is now available as a standalone package.$\r$\n\ You should uninstall Claws Mail now, and if you wish to \ continue to use it, install an up-to-date version from:$\r$\n\ http://www.claws-mail.org/win32 $\r$\n$\r$\n\ Uninstall Claws Mail from Gpg4win now?" # From Function CheckClawsUninstall LangString T_WinisDeprecated ${LANG_ENGLISH} \ "Windows Versions before Windows 7 are no longer maintained by Gpg4win. \ $\r$\nSupport for them may be removed in a future version.\ $\r$\n$\r$\nKleopatra is disabled." # From Function WelcomeFunction LangString T_UPDATE_STR ${LANG_ENGLISH} \ "Updating Version" # FIXME: The GetAfterChar function comes from the NSIS wiki. Function un.GetAfterChar Exch $0 ; chop char Exch Exch $1 ; input string Push $2 Push $3 StrCpy $2 0 loop: IntOp $2 $2 - 1 StrCpy $3 $1 1 $2 StrCmp $3 "" 0 +3 StrCpy $0 "" Goto exit2 StrCmp $3 $0 exit1 Goto loop exit1: IntOp $2 $2 + 1 StrCpy $0 $1 "" $2 exit2: Pop $3 Pop $2 Pop $1 Exch $0 ; output FunctionEnd Function un.SourceDelete Push "/" Call un.GetAfterChar Pop $R0 Delete "$INSTDIR\$R0" FunctionEnd # StrStr - taken from the NSIS reference # input, top of stack = string to search for # top of stack-1 = string to search in # output, top of stack (replaces with the portion of the string remaining) # modifies no other variables. # # Usage: # Push "this is a long ass string" # Push "ass" # Call StrStr # Pop $R0 # ($R0 at this point is "ass string") # !macro StrStr un Function ${un}StrStr Exch $R1 # st=haystack,old$R1, $R1=needle Exch # st=old$R1,haystack Exch $R2 # st=old$R1,old$R2, $R2=haystack Push $R3 Push $R4 Push $R5 StrLen $R3 $R1 StrCpy $R4 0 # $R1=needle # $R2=haystack # $R3=len(needle) # $R4=cnt # $R5=tmp loop: StrCpy $R5 $R2 $R3 $R4 StrCmp $R5 $R1 done StrCmp $R5 "" done IntOp $R4 $R4 + 1 Goto loop done: StrCpy $R1 $R2 "" $R4 Pop $R5 Pop $R4 Pop $R3 Pop $R2 Exch $R1 FunctionEnd !macroend # TrimNewlines - taken from the NSIS reference # input, top of stack (e.g. whatever$\r$\n) # output, top of stack (replaces, with e.g. whatever) # modifies no other variables. Function TrimNewlines Exch $R0 Push $R1 Push $R2 StrCpy $R1 0 loop: IntOp $R1 $R1 - 1 StrCpy $R2 $R0 1 $R1 StrCmp $R2 "$\r" loop StrCmp $R2 "$\n" loop IntOp $R1 $R1 + 1 IntCmp $R1 0 no_trim_needed StrCpy $R0 $R0 $R1 no_trim_needed: Pop $R2 Pop $R1 Exch $R0 FunctionEnd Function .onInit # Temporay disabled until we have fixed the DLL issue (wk 2023-04-11) - # Call G4wRunOnce + Call G4wRunOnce SetOutPath $TEMP !ifdef SOURCES File /oname=gpgspltmp.bmp "${TOP_SRCDIR}/doc/logo/gpg4win-logo-400px.bmp" # We play the tune only for the source installer File /oname=gpgspltmp.wav "${TOP_SRCDIR}/src/gpg4win-splash.wav" g4wihelp::playsound $TEMP\gpgspltmp.wav g4wihelp::showsplash 2500 $TEMP\gpgspltmp.bmp Delete $TEMP\gpgspltmp.bmp # Note that we delete gpgspltmp.wav in .onInst{Failed,Success} !else ${GetParameters} $R0 ClearErrors ${GetOptions} $R0 /MINIMAL= $is_minimal ${GetOptions} $R0 /WITH_BROWSER= $with_browser Var /GLOBAL changed_dir # Check if the install directory was modified on the command line StrCmp "$INSTDIR" "$PROGRAMFILES\${INSTALL_DIR}" unmodified 0 # It is modified. Save that value. StrCpy $changed_dir "$INSTDIR" # MULITUSER_INIT overwrites directory setting from command line !insertmacro MULTIUSER_INIT StrCpy $INSTDIR "$changed_dir" goto initDone unmodified: !insertmacro MULTIUSER_INIT !endif initDone: # Enable this to force a language selection dialog on every run (the # preferred language is the default). Otherwise, the preferred # language is stored in the registry, and the installer does not ask # on upgrades. !ifdef DEBUG !define MUI_LANGDLL_ALWAYSSHOW !endif !insertmacro MUI_LANGDLL_DISPLAY ${IfNot} ${AtLeastWin7} MessageBox MB_OK "$(T_WinisDeprecated)" ${Endif} ${MementoSectionRestore} Call CalcDefaults Call CalcDepends !ifndef SOURCES Call CheckOtherGnuPGApps !endif FunctionEnd Function un.onInit !ifndef SOURCES !insertmacro MULTIUSER_UNINIT !endif # Remove the language preference. !insertmacro MUI_UNGETLANGUAGE !ifndef SOURCES StrCpy $is_update "0" ${un.GetParameters} $R0 ClearErrors ${un.GetOptions} $R0 /UPDATE= $R1 IfErrors +2 StrCpy $is_update "1" !endif FunctionEnd # This must be in a central place. Urgs. !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN !ifdef HAVE_PKG_GNUPG_W32 !insertmacro MUI_DESCRIPTION_TEXT ${SEC_gnupg_w32} $(DESC_SEC_gnupg_w32) !endif !ifdef HAVE_PKG_GPGOL !insertmacro MUI_DESCRIPTION_TEXT ${SEC_gpgol} $(DESC_SEC_gpgol) !endif !ifdef HAVE_PKG_GPGEX !insertmacro MUI_DESCRIPTION_TEXT ${SEC_gpgex} $(DESC_SEC_gpgex) !endif !ifdef HAVE_PKG_PAPERKEY !insertmacro MUI_DESCRIPTION_TEXT ${SEC_paperkey} $(DESC_SEC_paperkey) !endif !ifdef HAVE_PKG_KLEOPATRA !insertmacro MUI_DESCRIPTION_TEXT ${SEC_kleopatra} $(DESC_SEC_kleopatra) !endif !ifdef HAVE_PKG_MAN_NOVICE_EN !insertmacro MUI_DESCRIPTION_TEXT ${SEC_man_novice_en} $(DESC_SEC_man_novice_en) !endif !ifdef HAVE_PKG_MAN_ADVANCED_EN !insertmacro MUI_DESCRIPTION_TEXT ${SEC_man_advanced_en} $(DESC_SEC_man_advanced_en) !endif !ifdef HAVE_PKG_COMPENDIUM !insertmacro MUI_DESCRIPTION_TEXT ${SEC_compendium} $(DESC_SEC_compendium) !endif !ifdef HAVE_PKG_MAN_NOVICE_DE !insertmacro MUI_DESCRIPTION_TEXT ${SEC_man_novice_de} $(DESC_SEC_man_novice_de) !endif !ifdef HAVE_PKG_MAN_ADVANCED_DE !insertmacro MUI_DESCRIPTION_TEXT ${SEC_man_advanced_de} $(DESC_SEC_man_advanced_de) !endif !insertmacro MUI_DESCRIPTION_TEXT ${SEC_gpgme_browser} $(DESC_SEC_gpgme_browser) !insertmacro MUI_FUNCTION_DESCRIPTION_END diff --git a/src/slideshow.cpp b/src/slideshow.cpp index 932097e0..812f1742 100644 --- a/src/slideshow.cpp +++ b/src/slideshow.cpp @@ -1,461 +1,461 @@ /* slideshow.cpp - NSIS Helper DLL for a slideshow. -*- coding: latin-1; -*- * Copyright (C) 2016 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 is heavily based on the Slideshow * plugin from http://wiz0u.free.fr/prog/nsisSlideshow * * It was slightly modified and adapted by: * 2016 Andre Heinecke * * Version 1.7 was Licensed at the time of copying (28.6.2016) as: * Copyright (c) 2009-2011 Olivier Marcoux * * 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. ************************************************************ */ #include #include #include #include #include "exdll.h" #include static unsigned int timerid = 0xBEEF; #ifndef _countof #define _countof(A) (sizeof(A)/sizeof((A)[0])) #endif #ifndef INITGUID #define INITGUID #endif __CRT_UUID_DECL(IImgCtx, 0x3050f3d7, 0x98b5, 0x11cf, 0xbb, 0x82, 0x00, 0xaa, 0x00, 0xbd, 0xce, 0x0b); DEFINE_GUID(IID_IImgCtx, 0x3050f3d7, 0x98b5, 0x11cf, 0xbb, 0x82, 0x00, 0xaa, 0x00, 0xbd, 0xce, 0x0b); DEFINE_GUID(CLSID_IImgCtx, 0x3050f3d6, 0x98b5, 0x11cf, 0xbb, 0x82, 0x00, 0xaa, 0x00, 0xbd, 0xce, 0x0b); #undef INITGUID /* array of precalculated alpha values for a linear crossfade in 15 steps */ const BYTE SCA_Steps[15] = { 17, 18, 20, 21, 23, 26, 28, 32, 36, 43, 51, 64, 85, 127, 255 }; int g_step = 0; HWND g_hWnd = NULL; HDC g_hdcMem = NULL; HBITMAP g_hbmMem = NULL; TCHAR g_autoPath[MAX_PATH]; LPTSTR g_autoBuffer = NULL; LPTSTR g_autoNext = NULL; int g_autoDelay = 0; RECT rDest; int wDest, hDest; WNDPROC lpPrevWndFunc = NULL; enum HAlign { HALIGN_CENTER = 0, HALIGN_LEFT, HALIGN_RIGHT } iHAlign; enum VAlign { VALIGN_CENTER = 0, VALIGN_TOP, VALIGN_BOTTOM } iVAlign; enum Fit { FIT_STRETCH = 0, FIT_WIDTH, FIT_HEIGHT, FIT_BOTH } iFit; COLORREF captionColor; static LRESULT CALLBACK slide_WndProc(HWND, UINT, WPARAM, LPARAM); /***************************************************** * Abort: stops current processing, detach from slide_WndProc and release resources *****************************************************/ static void slide_abort(bool stayAuto = false) { KillTimer(g_hWnd, timerid); if (!stayAuto) { if (lpPrevWndFunc != NULL && IsWindow(g_hWnd)) { if ((WNDPROC) GetWindowLong(g_hWnd, GWL_WNDPROC) == slide_WndProc) SetWindowLongPtr(g_hWnd, GWL_WNDPROC, (long)lpPrevWndFunc); } lpPrevWndFunc = NULL; GlobalFree(g_autoBuffer); g_autoBuffer = NULL; g_autoNext = NULL; g_autoDelay = false; } DeleteDC(g_hdcMem); g_hdcMem = NULL; DeleteObject(g_hbmMem); g_hbmMem = NULL; } static void slide_NewImage(LPCTSTR imgPath, LPCTSTR caption, int duration) { -#ifdef _UNICODE +#ifdef UNICODE LPCWSTR imgPathW = imgPath; #else WCHAR imgPathW[MAX_PATH]; MultiByteToWideChar(CP_ACP, 0, imgPath, -1, imgPathW, _countof(imgPathW)); #endif IImgCtx *pImage = NULL; SIZE imgSize = {0, 0}; if (SUCCEEDED(CoCreateInstance(CLSID_IImgCtx, NULL, CLSCTX_ALL, IID_IImgCtx, (void**)&pImage))) { if (SUCCEEDED(pImage->Load(imgPathW, 0))) { DWORD dwState; while (SUCCEEDED(pImage->GetStateInfo(&dwState, NULL, true)) && (dwState & (IMGLOAD_COMPLETE|IMGLOAD_ERROR)) == 0) Sleep(20); pImage->GetStateInfo(&dwState, &imgSize, true); } if (imgSize.cx == 0 || imgSize.cy == 0) // error path or format (IMGLOAD_ERROR) { pImage->Release(); pImage = NULL; } } if (pImage == NULL) return; // fit image wDest = rDest.right - rDest.left; hDest = rDest.bottom - rDest.top; if (iFit == FIT_BOTH) iFit = (wDest*imgSize.cy > imgSize.cx*hDest) ? FIT_HEIGHT : FIT_WIDTH; if (iFit == FIT_HEIGHT) wDest = (imgSize.cx * hDest) / imgSize.cy; else if (iFit == FIT_WIDTH) hDest = (imgSize.cy * wDest) / imgSize.cx; // align image if (iHAlign == HALIGN_CENTER) rDest.left = (rDest.left + rDest.right - wDest) / 2; else if (iHAlign == HALIGN_RIGHT) rDest.left = rDest.right - wDest; if (iVAlign == VALIGN_CENTER) rDest.top = (rDest.top + rDest.bottom - hDest) / 2; else if (iVAlign == VALIGN_BOTTOM) rDest.top = rDest.bottom - hDest; rDest.right = rDest.left + wDest; rDest.bottom = rDest.top + hDest; // create memory DC & Bitmap compatible with window's DC HDC hWndDC = GetDC(g_hWnd); g_hdcMem = CreateCompatibleDC(hWndDC); g_hbmMem = CreateCompatibleBitmap(hWndDC, wDest, hDest); ReleaseDC(g_hWnd, hWndDC); SelectObject(g_hdcMem, g_hbmMem); // paint image in memory DC RECT bounds = { 0, 0, wDest, hDest }; pImage->Draw(g_hdcMem, &bounds); pImage->Release(); // we don't need the image anymore if (caption[0] != '\0') { LOGFONT lf; GetObject((HFONT) ::SendMessage(g_hWnd, WM_GETFONT, 0, 0), sizeof(lf), &lf); lf.lfHeight += lf.lfHeight/2; HFONT hFont = CreateFontIndirect(&lf); HGDIOBJ hOldFont = SelectObject(g_hdcMem, hFont); SetTextColor(g_hdcMem, captionColor); SetBkMode(g_hdcMem, TRANSPARENT); SetTextAlign(g_hdcMem, TA_BOTTOM|TA_CENTER|TA_NOUPDATECP); TextOut(g_hdcMem, wDest/2, hDest-10, caption, lstrlen(caption)); DeleteObject(SelectObject(g_hdcMem, hOldFont)); } // replace windows procedure, start time and initiate first step if (lpPrevWndFunc == NULL) lpPrevWndFunc = (WNDPROC) SetWindowLongPtr(g_hWnd, GWL_WNDPROC, (long) slide_WndProc); if (duration == 0) { g_step = _countof(SCA_Steps); InvalidateRect(g_hWnd, NULL, FALSE); // no duration => force a WM_PAINT for immediate draw of picture if (g_autoNext && g_autoDelay) SetTimer(g_hWnd, timerid, g_autoDelay, NULL); } else { g_step = 0; slide_WndProc(g_hWnd, WM_TIMER, timerid, 0); // first iteration right now SetTimer(g_hWnd, timerid, duration/_countof(SCA_Steps), NULL); } } static bool slide_NextAuto() { LPTSTR scan; if (g_autoNext == NULL) return false; if (*g_autoNext == '.') { g_autoNext = g_autoBuffer; return false; } bool result = false; if (*g_autoNext == '=') g_autoNext++; for (scan = g_autoNext; *scan; scan++) if (*scan == ',') break; if (*scan) { TCHAR imgPath[MAX_PATH]; *scan = '\0'; PathCombine(imgPath, g_autoPath, g_autoNext); *scan = ','; g_autoNext = scan+1; int duration = StrToInt(g_autoNext); for (scan = g_autoNext; *scan; scan++) if (*scan == ',') break; if (*scan) { g_autoNext = scan+1; g_autoDelay = StrToInt(g_autoNext); for (scan = g_autoNext; *scan; scan++) if (*scan == ',') break; if (*scan && (scan[1] == '"')) { g_autoNext = scan+2; for (scan = g_autoNext; *scan; scan++) if (*scan == '"') break; if (*scan) { TCHAR caption[MAX_PATH]; lstrcpyn(caption, g_autoNext, scan-g_autoNext+1); g_autoNext = scan+1; slide_NewImage(imgPath, caption, duration); result = true; } } } } g_autoNext += lstrlen(g_autoNext); g_autoNext++; if (*g_autoNext == '\0') g_autoNext = g_autoBuffer; return result; } /***************************************************** * overriden WndProc for NSIS wizard pane *****************************************************/ static LRESULT CALLBACK slide_WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_TIMER: if (wParam == timerid) { if (g_step == _countof(SCA_Steps)) { slide_abort(true); if (!slide_NextAuto()) { slide_abort(); } return 0; } HDC hDC = GetDC(hWnd); const BLENDFUNCTION ftn = { AC_SRC_OVER, 0, SCA_Steps[g_step++], 0 }; AlphaBlend(hDC, rDest.left, rDest.top, wDest, hDest, g_hdcMem, 0, 0, wDest, hDest, ftn); ReleaseDC(hWnd, hDC); if (g_step == _countof(SCA_Steps)) { if (g_autoNext && g_autoDelay) SetTimer(hWnd, timerid, g_autoDelay, NULL); else KillTimer(hWnd, timerid); } return 0; } case WM_PAINT: if (g_hdcMem) { PAINTSTRUCT ps; HDC hDC = BeginPaint(hWnd, &ps); CallWindowProc(lpPrevWndFunc, hWnd, uMsg, wParam, lParam); BitBlt(hDC, rDest.left, rDest.top, wDest, hDest, g_hdcMem, 0, 0, SRCCOPY); EndPaint(hWnd, &ps); return 0; } break; case WM_CLOSE: slide_abort(); break; case WM_COMMAND: if(LOWORD(wParam) == IDCANCEL || LOWORD(wParam) == IDOK || LOWORD(wParam) == IDABORT) slide_abort(); break; default: break; } return CallWindowProc(lpPrevWndFunc, hWnd, uMsg, wParam, lParam); } /***************************************************** * NSIS Plugin "stop" entrypoint *****************************************************/ #ifdef __cplusplus extern "C" { #endif void __declspec(dllexport) slide_stop(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop) { slide_abort(); } /***************************************************** * NSIS Plugin "show" entrypoint *****************************************************/ void __declspec(dllexport) slide_show(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop) { EXDLL_INIT(); slide_abort(); // argument default values iHAlign = HALIGN_CENTER; iVAlign = VALIGN_CENTER; iFit = FIT_BOTH; g_hWnd = NULL; captionColor = RGB(255,255,255); int duration = 1000; // transition duration in ms (default = 1s) TCHAR caption[MAX_PATH]; caption[0] = '\0'; // parse arguments TCHAR arg[MAX_PATH]; LPTSTR argValue; - while(!popstring(arg, sizeof arg) && *arg == '/' && (argValue = StrChr(arg, '=')) != NULL) + while(!popstringn(arg, sizeof arg) && *arg == '/' && (argValue = StrChr(arg, '=')) != NULL) { *argValue++ = '\0'; // replace '=' by '\0' if(lstrcmpi(arg, TEXT("/hwnd")) == 0) StrToIntEx(argValue, STIF_SUPPORT_HEX, (int*) &g_hWnd); else if(lstrcmpi(arg, TEXT("/fit")) == 0) { if(lstrcmpi(argValue, TEXT("height")) == 0) iFit = FIT_HEIGHT; else if(lstrcmpi(argValue, TEXT("width")) == 0) iFit = FIT_WIDTH; else if(lstrcmpi(argValue, TEXT("stretch")) == 0) iFit = FIT_STRETCH; } else if(lstrcmpi(arg, TEXT("/halign")) == 0) { if(lstrcmpi(argValue, TEXT("left")) == 0) iHAlign = HALIGN_LEFT; else if(lstrcmpi(argValue, TEXT("right")) == 0) iHAlign = HALIGN_RIGHT; } else if(lstrcmpi(arg, TEXT("/valign")) == 0) { if(lstrcmpi(argValue, TEXT("top")) == 0) iVAlign = VALIGN_TOP; else if(lstrcmpi(argValue, TEXT("bottom")) == 0) iVAlign = VALIGN_BOTTOM; } else if(lstrcmpi(arg, TEXT("/duration")) == 0) StrToIntEx(argValue, STIF_SUPPORT_HEX, &duration); else if(lstrcmpi(arg, TEXT("/caption")) == 0) lstrcpy(caption, argValue); else if(lstrcmpi(arg, TEXT("/ccolor")) == 0) StrToIntEx(argValue, STIF_SUPPORT_HEX, (int*) &captionColor); else if(lstrcmpi(arg, TEXT("/auto")) == 0) { lstrcpy(g_autoPath, argValue); PathRemoveFileSpec(g_autoPath); HGLOBAL hMem = GlobalAlloc(GMEM_FIXED, 32767*sizeof(TCHAR)); DWORD count = GetPrivateProfileSection(getuservariable(INST_LANG), LPTSTR(hMem), 32767, argValue); if (count == 0) { count = GetPrivateProfileSection(TEXT("1033"), LPTSTR(hMem), 32767, argValue); if (count == 0) count = GetPrivateProfileSection(TEXT("0"), LPTSTR(hMem), 32767, argValue); } if (count) { g_autoBuffer = LPTSTR(GlobalReAlloc(hMem, (count+1)*sizeof(TCHAR), 0)); g_autoNext = g_autoBuffer; } else GlobalFree(hMem); } } // if target window not defined we'll search for default (the details listview) if (g_hWnd == NULL) { g_hWnd = FindWindowEx(hwndParent, NULL, TEXT("#32770"), NULL); if (g_hWnd == NULL) return; hwndParent = FindWindowEx(hwndParent, g_hWnd, TEXT("#32770"), NULL); if (hwndParent != NULL && !IsWindowVisible(hwndParent)) g_hWnd = hwndParent; if (g_hWnd == NULL) return; HWND hWnd = GetDlgItem(g_hWnd, 1016); GetWindowRect(hWnd, &rDest); ScreenToClient(g_hWnd, (LPPOINT) &rDest.left); ScreenToClient(g_hWnd, (LPPOINT) &rDest.right); } else GetClientRect(g_hWnd, &rDest); // load new image if (arg[0] == '\0') return; // stop here if no filename if (g_autoNext != NULL) slide_NextAuto(); else slide_NewImage(arg, caption, duration); } #ifdef __cplusplus } #endif