diff --git a/CMakeLists.txt b/CMakeLists.txt index 533ea591d9..3c8e58eed0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,354 +1,355 @@ project(kdepim) # where to look first for cmake modules. This line must be the first one or cmake will use the system's FindFoo.cmake set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules") ############### Build Options ############### option(KDEPIM_BUILD_EXAMPLES "Build the kdepim example applications." FALSE) option(KDEPIM_BUILD_MOBILE "Build the mobile applications. Note that you have to enable KDEPIM_MOBILE_UI if you want to run these applications on a mobile device." TRUE) option(KDEPIM_ENTERPRISE_BUILD "Enable features specific to the enterprise branch, which are normally disabled. Also, it disables many components not needed for Kontact such as the Kolab client." FALSE) option(KDEPIM_MOBILE_UI "Build UI for mobile devices instead of for desktops" FALSE) option(KDEPIM_ONLY_KLEO "Only build Kleopatra. This option will build only libkleo and kleopatra" FALSE) option(KDEPIM_BUILD_STATIC "Build KDEPIM static." FALSE) option(KDEPIM_BUILD_DESKTOP "Build Desktop Applications. Can be deactivated for mobile" TRUE) option(KDEPIM_NO_WEBKIT "Do not use WebKit in the kdepim applications" FALSE) if(KDEPIM_BUILD_STATIC) set(LIBRARY_TYPE STATIC) else() set(LIBRARY_TYPE SHARED) endif() add_definitions(-DQT_USE_QSTRINGBUILDER) if(KDEPIM_NO_WEBKIT) add_definitions(-DKDEPIM_NO_WEBKIT) endif() if(KDEPIM_ENTERPRISE_BUILD) message(STATUS "Enterprise build is enabled.") endif() # if KDEPIM_ONLY_KLEO is defined, KDEPIM_BUILD_MOBILE and KDEPIM_MOBILE_UI are disabled. if(KDEPIM_ONLY_KLEO) set(KDEPIM_BUILD_MOBILE FALSE) set(KDEPIM_MOBILE_UI FALSE) set(KDEPIM_DEFINITIONS "-DHAVE_CONFIG_H=1") message(STATUS "Only libkleo and Kleopatra will be built.") endif() if(KDEPIM_MOBILE_UI) # Build the mobile applications set(KDEPIM_BUILD_MOBILE TRUE) endif() # config-enterprise.h is needed for both ENTERPRISE_BUILD and BUILD_EVERYTHING configure_file(config-enterprise.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-enterprise.h ) ############### generate kdepim-version.h ############### # Support for the GIT revision number in kdepim-version.h if(EXISTS "${kdepim_SOURCE_DIR}/.git") find_package(Git) if(GIT_FOUND) message(STATUS "Found git: ${GIT_EXECUTABLE}") execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD WORKING_DIRECTORY ${kdepim_SOURCE_DIR} OUTPUT_VARIABLE kdepim_git_revision) string(REGEX REPLACE "\n" "" kdepim_git_revision "${kdepim_git_revision}") set(kdepim_git_revision "git-${kdepim_git_revision}") execute_process(COMMAND ${GIT_EXECUTABLE} log -1 --oneline --format=%ci WORKING_DIRECTORY ${kdepim_SOURCE_DIR} OUTPUT_VARIABLE kdepim_git_last_change) string(REGEX REPLACE " [-0-9:+ ]*\n" "" kdepim_git_last_change "${kdepim_git_last_change}") endif() endif() # KDEPIM_VERSION # Version scheme: "x.y.z build". # # x is the version number. # y is the major release number. # z is the minor release number. # # "x.y.z" follow the kdelibs version kdepim is released with. # # If "z" is 0, the version is "x.y" # # KDEPIM_DEV_VERSION is empty for final versions. # For development versions "build" is something like "pre", "alpha1", "alpha2", "beta1", "beta2", "rc1", "rc2". # # Examples in chronological order: # 3.0, 3.0.1, 3.1 alpha1, 3.1 beta1, 3.1 beta2, 3.1 rc1, 3.1, 3.1.1, 3.2 pre, 3.2 alpha1 set(KDEPIM_VERSION_MAJOR 4) set(KDEPIM_VERSION_MINOR 13) set(KDEPIM_VERSION_PATCH 0) set(KDEPIM_VERSION_KOLAB 24) set(KDEPIM_VERSION ${KDEPIM_VERSION_MAJOR}.${KDEPIM_VERSION_MINOR}.${KDEPIM_VERSION_PATCH}.${KDEPIM_VERSION_KOLAB}) configure_file(kdepim-version.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/kdepim-version.h @ONLY) set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTOMOC_MOC_OPTIONS -DBOOST_TT_HAS_OPERATOR_HPP_INCLUDED) # This is a hack to get the right include path to moc via automoc # See https://git.kolab.org/T953 set(CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES} "${CMAKE_INSTALL_PREFIX}/include" ) ############### search packages used by KDE ############### find_package(KDE4 4.11.3 REQUIRED) include(KDE4Defaults) find_package(KdepimLibs 4.13.0) set_package_properties(KdepimLibs PROPERTIES DESCRIPTION "The KDEPIM libraries" URL "http://www.kde.org" TYPE REQUIRED) ############### Load the CTest options ############### # CMake is irritating and doesn't allow setting the tests timeout globally. # Let's work around this. The global timeout is now 2 minutes. set(_DartConfigFile "${CMAKE_BINARY_DIR}/DartConfiguration.tcl") if(EXISTS ${_DartConfigFile}) set(DartTestingTimeout "120") file(READ ${_DartConfigFile} _DartConfigFile_content) string(REGEX REPLACE "TimeOut: 1500" "TimeOut: ${DartTestingTimeout}" _DartConfigFile_content ${_DartConfigFile_content}) file(WRITE ${_DartConfigFile} ${_DartConfigFile_content}) endif() # CTestCustom.cmake has to be in the CTEST_BINARY_DIR. # in the KDE build system, this is the same as CMAKE_BINARY_DIR. configure_file(${CMAKE_SOURCE_DIR}/CTestCustom.cmake ${CMAKE_BINARY_DIR}/CTestCustom.cmake) ############### search Boost ############### find_package(Boost 1.34.0) set_package_properties(Boost PROPERTIES DESCRIPTION "Boost C++ Libraries" URL "http://www.boost.org" TYPE REQUIRED PURPOSE "Boost is required for building most KDEPIM applications") # Kleopatra needs to know if the topological.hpp header exists (part of Boost_graph). find_path(Boost_TOPOLOGICAL_SORT_DIR NAMES boost/graph/topological_sort.hpp PATHS ${Boost_INCLUDE_DIRS}) if(Boost_TOPOLOGICAL_SORT_DIR) message(STATUS "The Boost Topological_sort header was found. Building Kleopatra") else() message(STATUS "The Boost Topological_sort header was NOT found. Kleopatra will not be built") endif() ############### Windows specific ############### if(WIN32) # detect oxygen icon dir at configure time based on KDEDIRS - there may be different package installation locations execute_process(COMMAND "${KDE4_KDECONFIG_EXECUTABLE}" --path icon OUTPUT_VARIABLE _dir ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) file(TO_CMAKE_PATH "${_dir}" __dir) find_path(KDE4_ICON_DIR oxygen PATHS ${__dir} ) message(STATUS "using oxygen application icons from ${KDE4_ICON_DIR}") else() set (KDE4_ICON_DIR ${CMAKE_INSTALL_PREFIX}/share/icons) endif() ############### ONLY_KLEO ############### # If the KDEPIM_ONLY_KLEO option is true if(KDEPIM_ONLY_KLEO) find_package(QGpgme) set_package_properties(QGpgme PROPERTIES DESCRIPTION "The QGpgME library" URL "http://www.kde.org" TYPE REQUIRED PURPOSE "QGpgME is required to build Kleopatra.") add_definitions(${QT_DEFINITIONS} ${KDE4_DEFINITIONS} ${KDEPIM_DEFINITIONS}) include_directories (${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${KDE4_INCLUDES} ${KDEPIMLIBS_INCLUDE_DIRS} ${QT_QTDBUS_INCLUDE_DIR}) include(kleopatra/ConfigureChecks.cmake) add_subdirectory(libkleo) if(Boost_TOPOLOGICAL_SORT_DIR) add_subdirectory(kleopatra) endif() else() # Otherwise... ############### Find the stuff we need ############### # Akonadi find_package(Akonadi 1.12.0 QUIET CONFIG) set_package_properties(Akonadi PROPERTIES DESCRIPTION "Akonadi server libraries" URL "http://pim.kde.org/akonadi" TYPE REQUIRED PURPOSE "Akonadi is required to build KDEPIM") find_package(ZLIB) set_package_properties(ZLIB PROPERTIES DESCRIPTION "The Zlib compression library" URL "http://www.zlib.net" TYPE REQUIRED) find_package(QGpgme) set_package_properties(QGpgme PROPERTIES DESCRIPTION "The QGpgMe library" URL "http://www.kde.org" TYPE RECOMMENDED PURPOSE "QGpgME is required to build KMail, KOrganizer and Kleopatra") find_package(Grantlee 0.3.0 QUIET CONFIG) set_package_properties(Grantlee PROPERTIES DESCRIPTION "The Grantlee Template System" URL "http://www.gitorious.org/grantlee/pages/Home" TYPE REQUIRED PURPOSE "Grantlee is requires for kmail and templating, theming for KJots, KaddressBook, KNotes and MessageViewer(KMail)." ) find_package(Baloo 4.13.0 QUIET CONFIG) set_package_properties(Baloo PROPERTIES DESCRIPTION "The Baloo libraries" URL "http://www.kde.org" TYPE REQUIRED PURPOSE "Baloo provides search capabilities in KMail and Akonadi") # Xsltproc find_package(Xsltproc) set_package_properties(Xsltproc PROPERTIES DESCRIPTION "XSLT processor from libxslt" TYPE REQUIRED PURPOSE "Required to generate D-Bus interfaces.") find_package(QJSON) set_package_properties(QJSON PROPERTIES DESCRIPTION "QJSON" URL "http://qjson.sourceforge.net/" TYPE REQUIRED PURPOSE "Qt library for handling JSON data") find_package(Prison QUIET CONFIG) set_package_properties(Prison PROPERTIES DESCRIPTION "The Prison library" URL "http://projects.kde.org/prison" TYPE OPTIONAL PURPOSE "Needed to show mobile barcodes of your contacts") # Libkgapi2 find_package(LibKGAPI2 2.1.0 QUIET CONFIG) set_package_properties(LibKGAPI2 PROPERTIES DESCRIPTION "KDE-based library for accessing various Google services" URL "https://projects.kde.org/libkgapi" TYPE OPTIONAL PURPOSE "LibKGAPI is required to build Google Drive Storage Service") # shared-mime-info find_package(SharedMimeInfo 0.30) set_package_properties(SharedMimeInfo PROPERTIES DESCRIPTION "The shared-mime-info utility" URL "http://freedesktop.org/wiki/Software/shared-mime-info" TYPE REQUIRED PURPOSE "Information about filetypes") if( LibKGAPI2_FOUND ) add_definitions( -DKDEPIM_STORAGESERVICE_GDRIVE ) endif() ############### Desktop vs. Mobile options ############## if(KDEPIM_MOBILE_UI) add_definitions( -DKDEPIM_MOBILE_UI ) if(NOT QT_QTDECLARATIVE_FOUND) message(FATAL_ERROR "The QtDeclarative (QML) module is required for building the mobile UI") endif() else() if(NOT QT_QTDECLARATIVE_FOUND) message(STATUS "The Qt Declarative (QML) module was not found. The mobile applications will not be built.") set(KDEPIM_BUILD_MOBILE FALSE) endif() endif() ############### Needed commands before building anything ############### add_definitions (${QT_DEFINITIONS} ${KDE4_DEFINITIONS} ${KDEPIM_DEFINITIONS} ${AKONADI_DEFINITIONS}) include_directories (${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${KDEPIMLIBS_INCLUDE_DIRS} ${KDE4_INCLUDES} ${QT_QTDBUS_INCLUDE_DIR} ${Boost_INCLUDE_DIR}) if(NOT KDEPIMLIBS_KRESOURCES_LIBRARY) add_definitions( -DKDEPIM_NO_KRESOURCES ) endif() ############### Now, we add the PIM components ############### include (kleopatra/ConfigureChecks.cmake) # These targets will always be built before anything else. add_subdirectory(accountwizard) add_subdirectory(noteshared) add_subdirectory(akonadi_next) add_subdirectory(libkdepim) add_subdirectory(calendarsupport) add_subdirectory(calendarviews) add_subdirectory(incidenceeditor-ng) add_subdirectory(libkdepimdbusinterfaces) add_subdirectory(libkleo) add_subdirectory(libkpgp) add_subdirectory(libksieve) add_subdirectory(kdgantt2) add_subdirectory(icons) add_subdirectory(composereditor-ng) add_subdirectory(grammar) add_subdirectory(messagecore) add_subdirectory(grantleetheme) add_subdirectory(messagelist) add_subdirectory(templateparser) if(QGPGME_FOUND) if(Boost_TOPOLOGICAL_SORT_DIR) macro_optional_add_subdirectory(kleopatra) endif() endif() # The following components depend on QGpgME. add_subdirectory(messageviewer) macro_optional_add_subdirectory(messagecomposer) add_subdirectory(pimcommon) add_subdirectory(mailcommon) # TODO: does this make sense?!? macro_optional_add_subdirectory(kmail) macro_optional_add_subdirectory(headerthemeeditor) macro_optional_add_subdirectory(contactthemeeditor) add_subdirectory(grantleethemeeditor) if(KDEPIM_BUILD_MOBILE) add_subdirectory(mobile) endif() if(KDEPIM_BUILD_EXAMPLES) add_subdirectory(examples) endif() # If kmail is compiled, KMAIL_SUPPORTED is true (used in several places) if(BUILD_kmail) set(KMAIL_SUPPORTED TRUE) add_definitions(-DKMAIL_SUPPORTED) endif() macro_optional_add_subdirectory(pimactivity) macro_optional_add_subdirectory(korganizer) macro_optional_add_subdirectory(korgac) macro_optional_add_subdirectory(sieveeditor) macro_optional_add_subdirectory(storageservicemanager) add_subdirectory(kaddressbookgrantlee) if(KDEPIM_BUILD_DESKTOP) macro_optional_add_subdirectory(agents) macro_optional_add_subdirectory(akregator) macro_optional_add_subdirectory(importwizard) macro_optional_add_subdirectory(kaddressbook) macro_optional_add_subdirectory(kmailcvt) macro_optional_add_subdirectory(mboximporter) if (NOT WIN32) macro_optional_add_subdirectory(knotes) endif() macro_optional_add_subdirectory(ksendemail) macro_optional_add_subdirectory(ktnef) macro_optional_add_subdirectory(mailimporter) macro_optional_add_subdirectory(pimsettingexporter) macro_optional_add_subdirectory(kalarm) if(KDEPIMLIBS_KCAL_LIBRARY) macro_optional_add_subdirectory(blogilo) endif() macro_optional_add_subdirectory(kjots) if(KDEPIMLIBS_KRESOURCES_LIBRARY) if(QT_QT3SUPPORT_FOUND) macro_optional_add_subdirectory(knode) endif() if(Q_WS_X11) macro_optional_add_subdirectory(ktimetracker) endif() endif() macro_optional_add_subdirectory(kontact) # must be the last one. endif() macro_optional_add_subdirectory(akonadiconsole) macro_optional_add_subdirectory(console) # These targets depend on optional applications if(KDEPIMLIBS_KRESOURCES_LIBRARY) add_subdirectory(kresources) # Must be after KAddressbook endif() add_subdirectory(plugins) # Must be after KMail endif() # doc must be a subdir of kdepim or packagers will kill us macro_optional_add_subdirectory(doc) # All done, let's display what we found... feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES ) diff --git a/kleopatra/commands/certifycertificatecommand.cpp b/kleopatra/commands/certifycertificatecommand.cpp index 3b59fe65e2..0386ef45ad 100644 --- a/kleopatra/commands/certifycertificatecommand.cpp +++ b/kleopatra/commands/certifycertificatecommand.cpp @@ -1,281 +1,283 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/signcertificatecommand.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2008 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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 Softwarls Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "certifycertificatecommand.h" #include "command_p.h" #include "exportopenpgpcertstoservercommand.h" #include #include #include #include #include #include #include #include #include +#ifndef Q_MOC_RUN #include +#endif #include using namespace Kleo; using namespace Kleo::Commands; using namespace Kleo::Dialogs; using namespace GpgME; class CertifyCertificateCommand::Private : public Command::Private { friend class ::Kleo::Commands::CertifyCertificateCommand; CertifyCertificateCommand * q_func() const { return static_cast( q ); } public: explicit Private( CertifyCertificateCommand * qq, KeyListController * c ); ~Private(); void init(); private: void slotDialogRejected(); void slotResult( const Error & err ); void slotCertificationPrepared(); private: void ensureDialogCreated(); void createJob(); private: std::vector uids; QPointer dialog; QPointer job; }; CertifyCertificateCommand::Private * CertifyCertificateCommand::d_func() { return static_cast( d.get() ); } const CertifyCertificateCommand::Private * CertifyCertificateCommand::d_func() const { return static_cast( d.get() ); } #define d d_func() #define q q_func() CertifyCertificateCommand::Private::Private( CertifyCertificateCommand * qq, KeyListController * c ) : Command::Private( qq, c ), uids(), dialog(), job() { } CertifyCertificateCommand::Private::~Private() { kDebug(); } CertifyCertificateCommand::CertifyCertificateCommand( KeyListController * c ) : Command( new Private( this, c ) ) { d->init(); } CertifyCertificateCommand::CertifyCertificateCommand( QAbstractItemView * v, KeyListController * c ) : Command( v, new Private( this, c ) ) { d->init(); } CertifyCertificateCommand::CertifyCertificateCommand( const Key & key ) : Command( key, new Private( this, 0 ) ) { d->init(); } CertifyCertificateCommand::CertifyCertificateCommand( const UserID & uid ) : Command( uid.parent(), new Private( this, 0 ) ) { std::vector( 1, uid ).swap( d->uids ); d->init(); } CertifyCertificateCommand::CertifyCertificateCommand( const std::vector & uids ) : Command( uids.empty() ? Key() : uids.front().parent(), new Private( this, 0 ) ) { d->uids = uids; d->init(); } void CertifyCertificateCommand::Private::init() { } CertifyCertificateCommand::~CertifyCertificateCommand() { kDebug(); } void CertifyCertificateCommand::setCertificationExportable( bool on ) { Q_UNUSED( on ); } void CertifyCertificateCommand::setCertificationRevocable( bool on ) { Q_UNUSED( on ); } void CertifyCertificateCommand::setCertifyingKey( const Key & signer ) { Q_UNUSED( signer ); } void CertifyCertificateCommand::setUserIDs( const std::vector & uids ) { d->uids = uids; if ( !uids.empty() && d->key().isNull() ) setKey( uids.front().parent() ); } void CertifyCertificateCommand::setUserID( const UserID & uid ) { setUserIDs( std::vector( 1, uid ) ); } void CertifyCertificateCommand::doStart() { const std::vector keys = d->keys(); if ( keys.size() != 1 || keys.front().protocol() != GpgME::OpenPGP ) { d->finished(); return; } std::vector secKeys = KeyCache::instance()->secretKeys(); std::vector::iterator it = std::remove_if( secKeys.begin(), secKeys.end(), !boost::bind( &Key::canCertify, _1 ) ); it = std::remove_if( it, secKeys.end(), boost::bind( &Key::protocol, _1 ) != OpenPGP ); secKeys.erase( it, secKeys.end() ); if ( secKeys.empty() ) { d->error( i18nc( "@info", "To certify other certificates, you first need to create an OpenPGP certificate for yourself. Choose File->New Certificate... to create one." ), i18n( "Certification Not Possible" ) ); d->finished(); return; } const Key & key = keys.front(); Q_FOREACH( const UserID & uid, d->uids ) if ( qstricmp( uid.parent().primaryFingerprint(), key.primaryFingerprint() ) != 0 ) { kWarning() << "User-ID <-> Key mismatch!"; d->finished(); return; } d->ensureDialogCreated(); assert( d->dialog ); d->dialog->setCertificateToCertify( d->key() ); d->dialog->setSelectedUserIDs( d->uids ); d->dialog->setCertificatesWithSecretKeys( secKeys ); d->dialog->show(); } void CertifyCertificateCommand::Private::slotDialogRejected() { emit q->canceled(); finished(); } void CertifyCertificateCommand::Private::slotResult( const Error & err ) { if ( !err && !err.isCanceled() && dialog && dialog->exportableCertificationSelected() && dialog->sendToServer() ) { ExportOpenPGPCertsToServerCommand * const cmd = new ExportOpenPGPCertsToServerCommand( key() ); cmd->start(); } finished(); } void CertifyCertificateCommand::Private::slotCertificationPrepared() { assert( dialog ); createJob(); assert( job ); job->setExportable( dialog->exportableCertificationSelected() ); job->setNonRevocable( dialog->nonRevocableCertificationSelected() ); job->setUserIDsToSign( dialog->selectedUserIDs() ); job->setSigningKey( dialog->selectedSecretKey() ); job->setCheckLevel( dialog->selectedCheckLevel() ); dialog->connectJob( job ); if ( const Error err = job->start( key() ) ) { dialog->setError( err ); finished(); } } void CertifyCertificateCommand::doCancel() { kDebug(); if ( d->job ) d->job->slotCancel(); } void CertifyCertificateCommand::Private::ensureDialogCreated() { if ( dialog ) return; dialog = new CertifyCertificateDialog; applyWindowID( dialog ); dialog->setAttribute( Qt::WA_DeleteOnClose ); connect( dialog, SIGNAL(rejected()), q, SLOT(slotDialogRejected()) ); connect( dialog, SIGNAL(certificationPrepared()), q, SLOT(slotCertificationPrepared()) ); } void CertifyCertificateCommand::Private::createJob() { if ( dialog ) disconnect( dialog, SIGNAL(certificationPrepared()), q, SLOT(slotCertificationPrepared()) ); assert( !job ); assert( key().protocol() == OpenPGP ); const CryptoBackend::Protocol * const backend = CryptoBackendFactory::instance()->protocol( key().protocol() ); if ( !backend ) return; SignKeyJob * const j = backend->signKeyJob(); if ( !j ) return; connect( j, SIGNAL(progress(QString,int,int)), q, SIGNAL(progress(QString,int,int)) ); connect( j, SIGNAL(result(GpgME::Error)), q, SLOT(slotResult(GpgME::Error)) ); job = j; } #undef d #undef q #include "moc_certifycertificatecommand.cpp" diff --git a/kleopatra/commands/deletecertificatescommand.cpp b/kleopatra/commands/deletecertificatescommand.cpp index ba3956a7b5..10e4d6a4f9 100644 --- a/kleopatra/commands/deletecertificatescommand.cpp +++ b/kleopatra/commands/deletecertificatescommand.cpp @@ -1,387 +1,389 @@ /* -*- mode: c++; c-basic-offset:4 -*- deleteCertificatescommand.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2007 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "deletecertificatescommand.h" #include "command_p.h" #include #include #include #include #include #include #include #include #include #include #include #include +#ifndef Q_MOC_RUN #include +#endif #include #include #include using namespace boost; using namespace GpgME; using namespace Kleo; using namespace Kleo::Dialogs; class DeleteCertificatesCommand::Private : public Command::Private { friend class ::Kleo::DeleteCertificatesCommand; DeleteCertificatesCommand * q_func() const { return static_cast(q); } public: explicit Private( DeleteCertificatesCommand * qq, KeyListController * c ); ~Private(); void startDeleteJob( GpgME::Protocol protocol ); void cancelJobs(); void pgpDeleteResult( const GpgME::Error & ); void cmsDeleteResult( const GpgME::Error & ); void showErrorsAndFinish(); bool canDelete( GpgME::Protocol proto ) const { if ( const CryptoBackend::Protocol * const cbp = CryptoBackendFactory::instance()->protocol( proto ) ) if ( DeleteJob * const job = cbp->deleteJob() ) { job->slotCancel(); return true; } return false; } void ensureDialogCreated() { if ( dialog ) return; dialog = new DeleteCertificatesDialog; applyWindowID( dialog ); dialog->setAttribute( Qt::WA_DeleteOnClose ); dialog->setWindowTitle( i18nc("@title:window", "Delete Certificates") ); connect( dialog, SIGNAL(accepted()), q_func(), SLOT(slotDialogAccepted()) ); connect( dialog, SIGNAL(rejected()), q_func(), SLOT(slotDialogRejected()) ); } void ensureDialogShown() { if ( dialog ) dialog->show(); } void slotDialogAccepted(); void slotDialogRejected() { canceled(); } private: QPointer dialog; QPointer cmsJob, pgpJob; GpgME::Error cmsError, pgpError; std::vector cmsKeys, pgpKeys; }; DeleteCertificatesCommand::Private * DeleteCertificatesCommand::d_func() { return static_cast(d.get()); } const DeleteCertificatesCommand::Private * DeleteCertificatesCommand::d_func() const { return static_cast(d.get()); } #define d d_func() #define q q_func() DeleteCertificatesCommand::Private::Private( DeleteCertificatesCommand * qq, KeyListController * c ) : Command::Private( qq, c ) { } DeleteCertificatesCommand::Private::~Private() {} DeleteCertificatesCommand::DeleteCertificatesCommand( KeyListController * p ) : Command( new Private( this, p ) ) { } DeleteCertificatesCommand::DeleteCertificatesCommand( QAbstractItemView * v, KeyListController * p ) : Command( v, new Private( this, p ) ) { } DeleteCertificatesCommand::~DeleteCertificatesCommand() {} namespace { enum Action { Nothing = 0, Failure = 1, ClearCMS = 2, ClearPGP = 4 }; // const unsigned int errorCase = // openpgp.empty() << 3U | d->canDelete( OpenPGP ) << 2U | // cms.empty() << 1U | d->canDelete( CMS ) << 0U ; static const struct { const char * text; Action actions; } deletionErrorCases[16] = { // if havePGP // if cantPGP // if haveCMS { I18N_NOOP( "Neither the OpenPGP nor the CMS " "backends support certificate deletion.\n" "Check your installation." ), Failure }, // cantCMS { I18N_NOOP( "The OpenPGP backend does not support " "certificate deletion.\n" "Check your installation.\n" "Only the selected CMS certificates " "will be deleted." ), ClearPGP }, // canCMS // if !haveCMS { I18N_NOOP( "The OpenPGP backend does not support " "certificate deletion.\n" "Check your installation." ), Failure }, { I18N_NOOP( "The OpenPGP backend does not support " "certificate deletion.\n" "Check your installation." ), Failure }, // if canPGP // if haveCMS { I18N_NOOP( "The CMS backend does not support " "certificate deletion.\n" "Check your installation.\n" "Only the selected OpenPGP certificates " "will be deleted." ), ClearCMS }, // cantCMS { 0, Nothing }, // canCMS // if !haveCMS { 0, Nothing }, // cantCMS { 0, Nothing }, // canCMS // if !havePGP // if cantPGP // if haveCMS { I18N_NOOP( "The CMS backend does not support " "certificate deletion.\n" "Check your installation." ), Failure }, // cantCMS { 0, Nothing }, // canCMS // if !haveCMS { 0, Nothing }, // cantCMS { 0, Nothing }, // canCMS // if canPGP // if haveCMS { I18N_NOOP( "The CMS backend does not support " "certificate deletion.\n" "Check your installation." ), Failure }, // cantCMS { 0, Nothing }, // canCMS // if !haveCMS { 0, Nothing }, // cantCMS { 0, Nothing }, // canCMS }; } // anon namespace void DeleteCertificatesCommand::doStart() { std::vector selected = d->keys(); if ( selected.empty() ) { d->finished(); return; } kdtools::sort( selected, _detail::ByFingerprint() ); // Calculate the closure of the selected keys (those that need to // be deleted with them, though not selected themselves): std::vector toBeDeleted = KeyCache::instance()->findSubjects( selected ); kdtools::sort( toBeDeleted, _detail::ByFingerprint() ); std::vector unselected; unselected.reserve( toBeDeleted.size() ); std::set_difference( toBeDeleted.begin(), toBeDeleted.end(), selected.begin(), selected.end(), std::back_inserter( unselected ), _detail::ByFingerprint() ); d->ensureDialogCreated(); d->dialog->setSelectedKeys( selected ); d->dialog->setUnselectedKeys( unselected ); d->ensureDialogShown(); } void DeleteCertificatesCommand::Private::slotDialogAccepted() { std::vector keys = dialog->keys(); assert( !keys.empty() ); std::vector::iterator pgpBegin = keys.begin(), pgpEnd = std::stable_partition( pgpBegin, keys.end(), boost::bind( &GpgME::Key::protocol, _1 ) != CMS ), cmsBegin = pgpEnd, cmsEnd = keys.end() ; std::vector openpgp( pgpBegin, pgpEnd ); std::vector cms( cmsBegin, cmsEnd ); const unsigned int errorCase = openpgp.empty() << 3U | canDelete( OpenPGP ) << 2U | cms.empty() << 1U | canDelete( CMS ) << 0U ; if ( const unsigned int actions = deletionErrorCases[errorCase].actions ) { information( i18n( deletionErrorCases[errorCase].text ), (actions & Failure) ? i18n( "Certificate Deletion Failed" ) : i18n( "Certificate Deletion Problem" ) ); if ( actions & ClearCMS ) cms.clear(); if ( actions & ClearPGP ) openpgp.clear(); if ( actions & Failure ) { canceled(); return; } } assert( !openpgp.empty() || !cms.empty() ); pgpKeys.swap( openpgp ); cmsKeys.swap( cms ); if ( !pgpKeys.empty() ) startDeleteJob( GpgME::OpenPGP ); if ( !cmsKeys.empty() ) startDeleteJob( GpgME::CMS ); if ( ( pgpKeys.empty() || pgpError.code() ) && ( cmsKeys.empty() || cmsError.code() ) ) showErrorsAndFinish(); } void DeleteCertificatesCommand::Private::startDeleteJob( GpgME::Protocol protocol ) { assert( protocol != GpgME::UnknownProtocol ); const std::vector & keys = protocol == CMS ? cmsKeys : pgpKeys ; const CryptoBackend::Protocol * const backend = CryptoBackendFactory::instance()->protocol( protocol ); assert( backend ); std::auto_ptr job( new MultiDeleteJob( backend ) ); if ( protocol == CMS ) connect( job.get(), SIGNAL(result(GpgME::Error,GpgME::Key)), q_func(), SLOT(cmsDeleteResult(GpgME::Error)) ); else connect( job.get(), SIGNAL(result(GpgME::Error,GpgME::Key)), q_func(), SLOT(pgpDeleteResult(GpgME::Error)) ); connect( job.get(), SIGNAL(progress(QString,int,int)), q, SIGNAL(progress(QString,int,int)) ); if ( const Error err = job->start( keys, true /*allowSecretKeyDeletion*/ ) ) ( protocol == CMS ? cmsError : pgpError ) = err; else ( protocol == CMS ? cmsJob : pgpJob ) = job.release(); } void DeleteCertificatesCommand::Private::showErrorsAndFinish() { assert( !pgpJob ); assert( !cmsJob ); if ( pgpError || cmsError ) { QString pgpErrorString; if ( pgpError ) pgpErrorString = i18n( "OpenPGP backend: %1", QString::fromLocal8Bit( pgpError.asString() ) ); QString cmsErrorString; if ( cmsError ) cmsErrorString = i18n( "CMS backend: %1", QString::fromLocal8Bit( cmsError.asString() ) ); const QString msg = i18n("

An error occurred while trying to delete " "the certificate:

" "

%1

", pgpError ? cmsError ? pgpErrorString + QLatin1String("
") + cmsErrorString : pgpErrorString : cmsErrorString ); error( msg, i18n("Certificate Deletion Failed") ); } else { std::vector keys = pgpKeys; keys.insert( keys.end(), cmsKeys.begin(), cmsKeys.end() ); KeyCache::mutableInstance()->remove( keys ); } finished(); } void DeleteCertificatesCommand::doCancel() { d->cancelJobs(); } void DeleteCertificatesCommand::Private::pgpDeleteResult( const Error & err ) { pgpError = err; pgpJob = 0; if ( !cmsJob ) showErrorsAndFinish(); } void DeleteCertificatesCommand::Private::cmsDeleteResult( const Error & err ) { cmsError = err; cmsJob = 0; if ( !pgpJob ) showErrorsAndFinish(); } void DeleteCertificatesCommand::Private::cancelJobs() { if ( cmsJob ) cmsJob->slotCancel(); if ( pgpJob ) pgpJob->slotCancel(); } #undef d #undef q #include "moc_deletecertificatescommand.cpp" diff --git a/kleopatra/commands/exportcertificatecommand.cpp b/kleopatra/commands/exportcertificatecommand.cpp index 330d8acc1c..8c7493f845 100644 --- a/kleopatra/commands/exportcertificatecommand.cpp +++ b/kleopatra/commands/exportcertificatecommand.cpp @@ -1,331 +1,333 @@ /* -*- mode: c++; c-basic-offset:4 -*- exportcertificatecommand.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2007 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "exportcertificatecommand.h" #include "command_p.h" #include #include #include #include #include #include #include #include #include #include #include +#ifndef Q_MOC_RUN #include +#endif #include #include #include using namespace Kleo; using namespace Kleo::Dialogs; using namespace GpgME; using namespace boost; class ExportCertificateCommand::Private : public Command::Private { friend class ::ExportCertificateCommand; ExportCertificateCommand * q_func() const { return static_cast(q); } public: explicit Private( ExportCertificateCommand * qq, KeyListController * c ); ~Private(); void startExportJob( GpgME::Protocol protocol, const std::vector& keys ); void cancelJobs(); void exportResult( const GpgME::Error&, const QByteArray& ); void showError( const GpgME::Error& error ); bool requestFileNames( Protocol prot ); void finishedIfLastJob(); private: QMap fileNames; uint jobsPending; QMap outFileForSender; QPointer cmsJob; QPointer pgpJob; }; ExportCertificateCommand::Private * ExportCertificateCommand::d_func() { return static_cast(d.get()); } const ExportCertificateCommand::Private * ExportCertificateCommand::d_func() const { return static_cast(d.get()); } #define d d_func() #define q q_func() ExportCertificateCommand::Private::Private( ExportCertificateCommand * qq, KeyListController * c ) : Command::Private( qq, c ), jobsPending( 0 ) { } ExportCertificateCommand::Private::~Private() {} ExportCertificateCommand::ExportCertificateCommand( KeyListController * p ) : Command( new Private( this, p ) ) { } ExportCertificateCommand::ExportCertificateCommand( QAbstractItemView * v, KeyListController * p ) : Command( v, new Private( this, p ) ) { } ExportCertificateCommand::ExportCertificateCommand( const Key & key ) : Command( key, new Private( this, 0 ) ) { } ExportCertificateCommand::~ExportCertificateCommand() {} void ExportCertificateCommand::setOpenPGPFileName( const QString & fileName ) { if ( !d->jobsPending ) d->fileNames[OpenPGP] = fileName; } QString ExportCertificateCommand::openPGPFileName() const { return d->fileNames[OpenPGP]; } void ExportCertificateCommand::setX509FileName( const QString & fileName ) { if ( !d->jobsPending ) d->fileNames[CMS] = fileName; } QString ExportCertificateCommand::x509FileName() const { return d->fileNames[CMS]; } void ExportCertificateCommand::doStart() { std::vector keys = d->keys(); if ( keys.empty() ) return; const std::vector::iterator firstCms = std::partition( keys.begin(), keys.end(), boost::bind( &GpgME::Key::protocol, _1 ) != CMS ); std::vector openpgp, cms; std::copy( keys.begin(), firstCms, std::back_inserter( openpgp ) ); std::copy( firstCms, keys.end(), std::back_inserter( cms ) ); assert( !openpgp.empty() || !cms.empty() ); const bool haveBoth = !cms.empty() && !openpgp.empty(); const GpgME::Protocol prot = haveBoth ? UnknownProtocol : ( !cms.empty() ? CMS : OpenPGP ); if ( !d->requestFileNames( prot ) ) { emit canceled(); d->finished(); } else { if ( !openpgp.empty() ) d->startExportJob( GpgME::OpenPGP, openpgp ); if ( !cms.empty() ) d->startExportJob( GpgME::CMS, cms ); } } bool ExportCertificateCommand::Private::requestFileNames( GpgME::Protocol protocol ) { if ( protocol == UnknownProtocol ) { if ( !fileNames[OpenPGP].isEmpty() && !fileNames[CMS].isEmpty() ) return true; const QPointer dlg( new ExportCertificatesDialog ); applyWindowID( dlg ); dlg->setOpenPgpExportFileName( fileNames[OpenPGP] ); dlg->setCmsExportFileName( fileNames[CMS] ); const bool accepted = dlg->exec() == QDialog::Accepted && dlg ; if ( accepted ) { fileNames[OpenPGP] = dlg->openPgpExportFileName(); fileNames[CMS] = dlg->cmsExportFileName(); } else { fileNames.clear(); } delete dlg; return accepted; } if ( !fileNames[protocol].isEmpty() ) return true; QString proposedFileName; if ( keys().size() == 1 ) proposedFileName = QString::fromLatin1( keys().front().primaryFingerprint() ) + QLatin1Char( '.' ) + QString::fromLatin1( outputFileExtension( protocol == OpenPGP ? Class::OpenPGP|Class::Ascii|Class::Certificate : Class::CMS|Class::Ascii|Class::Certificate ) ) ; const QString fname = FileDialog::getSaveFileNameEx( parentWidgetOrView(), i18n( "Export Certificates" ), QLatin1String("imp"), proposedFileName, protocol == GpgME::OpenPGP ? i18n( "OpenPGP Certificates" ) + QLatin1String(" (*.asc *.gpg *.pgp)") : i18n( "S/MIME Certificates" ) + QLatin1String(" (*.pem *.der)" )); fileNames[protocol] = fname; return !fname.isEmpty(); } void ExportCertificateCommand::Private::startExportJob( GpgME::Protocol protocol, const std::vector& keys ) { assert( protocol != GpgME::UnknownProtocol ); const CryptoBackend::Protocol* const backend = CryptoBackendFactory::instance()->protocol( protocol ); assert( backend ); const QString fileName = fileNames[protocol]; const bool binary = protocol == GpgME::OpenPGP ? fileName.endsWith( QLatin1String( ".gpg" ), Qt::CaseInsensitive ) || fileName.endsWith( QLatin1String( ".pgp" ), Qt::CaseInsensitive ) : fileName.endsWith( QLatin1String( ".der" ), Qt::CaseInsensitive ) ; std::auto_ptr job( backend->publicKeyExportJob( !binary ) ); assert( job.get() ); connect( job.get(), SIGNAL(result(GpgME::Error,QByteArray)), q, SLOT(exportResult(GpgME::Error,QByteArray)) ); connect( job.get(), SIGNAL(progress(QString,int,int)), q, SIGNAL(progress(QString,int,int)) ); QStringList fingerprints; Q_FOREACH ( const Key& i, keys ) fingerprints << QLatin1String(i.primaryFingerprint()); const GpgME::Error err = job->start( fingerprints ); if ( err ) { showError( err ); finished(); return; } emit q->info( i18n( "Exporting certificates..." ) ); ++jobsPending; const QPointer exportJob( job.release() ); outFileForSender[exportJob.data()] = fileName; ( protocol == CMS ? cmsJob : pgpJob ) = exportJob; } void ExportCertificateCommand::Private::showError( const GpgME::Error& err ) { assert( err ); const QString msg = i18n("

An error occurred while trying to export " "the certificate:

" "

%1

", QString::fromLocal8Bit( err.asString() ) ); error( msg, i18n("Certificate Export Failed") ); } void ExportCertificateCommand::doCancel() { d->cancelJobs(); } void ExportCertificateCommand::Private::finishedIfLastJob() { if ( jobsPending <= 0 ) finished(); } static bool write_complete( QIODevice & iod, const QByteArray & data ) { qint64 total = 0; qint64 toWrite = data.size(); while ( total < toWrite ) { const qint64 written = iod.write( data.data() + total, toWrite ); if ( written < 0 ) return false; total += written; toWrite -= written; } return true; } void ExportCertificateCommand::Private::exportResult( const GpgME::Error& err, const QByteArray& data ) { assert( jobsPending > 0 ); --jobsPending; assert( outFileForSender.contains( q->sender() ) ); const QString outFile = outFileForSender[q->sender()]; if ( err ) { showError( err ); finishedIfLastJob(); return; } KSaveFile savefile( outFile ); //TODO: use KIO const QString writeErrorMsg = i18n( "Could not write to file %1.", outFile ); const QString errorCaption = i18n( "Certificate Export Failed" ); if ( !savefile.open() ) { error( writeErrorMsg, errorCaption ); finishedIfLastJob(); return; } if ( !write_complete( savefile, data ) || !savefile.finalize() ) error( writeErrorMsg, errorCaption ); finishedIfLastJob(); } void ExportCertificateCommand::Private::cancelJobs() { if ( cmsJob ) cmsJob->slotCancel(); if ( pgpJob ) pgpJob->slotCancel(); } #undef d #undef q #include "moc_exportcertificatecommand.cpp" diff --git a/kleopatra/commands/importcertificatescommand.cpp b/kleopatra/commands/importcertificatescommand.cpp index 4c109954fb..c5f6c5029c 100644 --- a/kleopatra/commands/importcertificatescommand.cpp +++ b/kleopatra/commands/importcertificatescommand.cpp @@ -1,463 +1,465 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/importcertificatescommand.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2007, 2008 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "importcertificatescommand.h" #include "importcertificatescommand_p.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // for Qt::escape +#ifndef Q_MOC_RUN #include #include +#endif #include #include #include #include #include using namespace GpgME; using namespace Kleo; using namespace boost; namespace { make_comparator_str( ByImportFingerprint, .fingerprint() ); class ImportResultProxyModel : public AbstractKeyListSortFilterProxyModel { Q_OBJECT public: ImportResultProxyModel( const std::vector & results, const QStringList & ids, QObject * parent=0 ) : AbstractKeyListSortFilterProxyModel( parent ) { updateFindCache( results, ids ); } ~ImportResultProxyModel() {} /* reimp */ ImportResultProxyModel * clone() const { // compiler-generated copy ctor is fine! return new ImportResultProxyModel( *this ); } void setImportResults( const std::vector & results, const QStringList & ids ) { updateFindCache( results, ids ); invalidateFilter(); } protected: /* reimp */ QVariant data( const QModelIndex & index, int role ) const { if ( !index.isValid() || role != Qt::ToolTipRole ) return AbstractKeyListSortFilterProxyModel::data( index, role ); const QString fpr = index.data( FingerprintRole ).toString(); // find information: const std::vector::const_iterator it = qBinaryFind( m_importsByFingerprint.begin(), m_importsByFingerprint.end(), fpr.toLatin1().constData(), ByImportFingerprint() ); if ( it == m_importsByFingerprint.end() ) return AbstractKeyListSortFilterProxyModel::data( index, role ); else return Formatting::importMetaData( *it, kdtools::copy( m_idsByFingerprint[it->fingerprint()] ) ); } /* reimp */ bool filterAcceptsRow( int source_row, const QModelIndex & source_parent ) const { // // 0. Keep parents of matching children: // const QModelIndex index = sourceModel()->index( source_row, 0, source_parent ); assert( index.isValid() ); for ( int i = 0, end = sourceModel()->rowCount( index ) ; i != end ; ++i ) if ( filterAcceptsRow( i, index ) ) return true; // // 1. Check that this is an imported key: // const QString fpr = index.data( FingerprintRole ).toString(); return std::binary_search( m_importsByFingerprint.begin(), m_importsByFingerprint.end(), fpr.toLatin1().constData(), ByImportFingerprint() ); } private: void updateFindCache( const std::vector & results, const QStringList & ids ) { assert( results.size() == static_cast( ids.size() ) ); m_importsByFingerprint.clear(); m_idsByFingerprint.clear(); m_results = results; for ( unsigned int i = 0, end = results.size() ; i != end ; ++i ) { const std::vector imports = results[i].imports(); m_importsByFingerprint.insert( m_importsByFingerprint.end(), imports.begin(), imports.end() ); const QString & id = ids[i]; for ( std::vector::const_iterator it = imports.begin(), end = imports.end() ; it != end ; ++it ) { m_idsByFingerprint[it->fingerprint()].insert( id ); } } std::sort( m_importsByFingerprint.begin(), m_importsByFingerprint.end(), ByImportFingerprint() ); } private: mutable std::vector m_importsByFingerprint; mutable std::map< const char*, std::set, ByImportFingerprint > m_idsByFingerprint; std::vector m_results; }; } ImportCertificatesCommand::Private::Private( ImportCertificatesCommand * qq, KeyListController * c ) : Command::Private( qq, c ), waitForMoreJobs( false ), nonWorkingProtocols(), idsByJob(), jobs(), results(), ids() { } ImportCertificatesCommand::Private::~Private() {} #define d d_func() #define q q_func() ImportCertificatesCommand::ImportCertificatesCommand( KeyListController * p ) : Command( new Private( this, p ) ) { } ImportCertificatesCommand::ImportCertificatesCommand( QAbstractItemView * v, KeyListController * p ) : Command( v, new Private( this, p ) ) { } ImportCertificatesCommand::~ImportCertificatesCommand() {} static QString format_ids( const QStringList & ids ) { return kdtools::transform_if( ids, Qt::escape, !boost::bind( &QString::isEmpty, _1 ) ).join( QLatin1String("
") ); } static QString make_tooltip( const QStringList & ids ) { if ( ids.empty() ) return QString(); if ( ids.size() == 1 ) if ( ids.front().isEmpty() ) return QString(); else return i18nc( "@info:tooltip", "Imported Certificates from %1", Qt::escape( ids.front() ) ); else return i18nc( "@info:tooltip", "Imported certificates from these sources:
%1", format_ids( ids ) ); } void ImportCertificatesCommand::Private::setImportResultProxyModel( const std::vector & results, const QStringList & ids ) { if ( kdtools::none_of( results, mem_fn( &ImportResult::numConsidered ) ) ) return; q->addTemporaryView( i18nc("@title:tab", "Imported Certificates"), new ImportResultProxyModel( results, ids ), make_tooltip( ids ) ); if ( QTreeView * const tv = qobject_cast( parentWidgetOrView() ) ) tv->expandAll(); } int sum( const std::vector & res, int (ImportResult::*fun)() const ) { return kdtools::accumulate_transform( res.begin(), res.end(), mem_fn( fun ), 0 ); } static QString make_report( const std::vector & res, const QString & id=QString() ) { const KLocalizedString normalLine = ki18n("%1%2"); const KLocalizedString boldLine = ki18n("%1%2"); const KLocalizedString headerLine = ki18n("%1"); #define SUM( x ) sum( res, &ImportResult::x ) QStringList lines; if ( !id.isEmpty() ) lines.push_back( headerLine.subs( id ).toString() ); lines.push_back( normalLine.subs( i18n("Total number processed:") ) .subs( SUM(numConsidered) ).toString() ); lines.push_back( normalLine.subs( i18n("Imported:") ) .subs( SUM(numImported) ).toString() ); if ( const int n = SUM(newSignatures) ) lines.push_back( normalLine.subs( i18n("New signatures:") ) .subs( n ).toString() ); if ( const int n = SUM(newUserIDs) ) lines.push_back( normalLine.subs( i18n("New user IDs:") ) .subs( n ).toString() ); if ( const int n = SUM(numKeysWithoutUserID) ) lines.push_back( normalLine.subs( i18n("Certificates without user IDs:") ) .subs( n ).toString() ); if ( const int n = SUM(newSubkeys) ) lines.push_back( normalLine.subs( i18n("New subkeys:") ) .subs( n ).toString() ); if ( const int n = SUM(newRevocations) ) lines.push_back( boldLine.subs( i18n("Newly revoked:") ) .subs( n ).toString() ); if ( const int n = SUM(notImported) ) lines.push_back( boldLine.subs( i18n("Not imported:") ) .subs( n ).toString() ); if ( const int n = SUM(numUnchanged) ) lines.push_back( normalLine.subs( i18n("Unchanged:") ) .subs( n ).toString() ); if ( const int n = SUM(numSecretKeysConsidered) ) lines.push_back( normalLine.subs( i18n("Secret keys processed:") ) .subs( n ).toString() ); if ( const int n = SUM(numSecretKeysImported) ) lines.push_back( normalLine.subs( i18n("Secret keys imported:") ) .subs( n ).toString() ); if ( const int n = SUM(numSecretKeysConsidered) - SUM(numSecretKeysImported) - SUM(numSecretKeysUnchanged) ) if ( n > 0 ) lines.push_back( boldLine.subs( i18n("Secret keys not imported:") ) .subs( n ).toString() ); if ( const int n = SUM(numSecretKeysUnchanged) ) lines.push_back( normalLine.subs( i18n("Secret keys unchanged:") ) .subs( n ).toString() ); #undef sum return lines.join( QString() ); } static QString make_message_report( const std::vector & res, const QStringList & ids ) { assert( res.size() == static_cast( ids.size() ) ); if ( res.empty() ) return i18n( "No imports (should not happen, please report a bug)." ); if ( res.size() == 1 ) return ids.front().isEmpty() ? i18n( "

Detailed results of certificate import:

" "%1
", make_report( res ) ) : i18n( "

Detailed results of importing %1:

" "%2
", ids.front(), make_report( res ) ); return i18n( "

Detailed results of certificate import:

" "%1
", make_report( res, i18n("Totals") ) ); } void ImportCertificatesCommand::Private::showDetails( QWidget * parent, const std::vector & res, const QStringList & ids ) { if ( parent ) { setImportResultProxyModel( res, ids ); KMessageBox::information( parent, make_message_report( res, ids ), i18n( "Certificate Import Result" ) ); } else { showDetails( res, ids ); } } void ImportCertificatesCommand::Private::showDetails( const std::vector & res, const QStringList & ids ) { setImportResultProxyModel( res, ids ); information( make_message_report( res, ids ), i18n( "Certificate Import Result" ) ); } static QString make_error_message( const Error & err, const QString & id ) { assert( err ); assert( !err.isCanceled() ); return id.isEmpty() ? i18n( "

An error occurred while trying " "to import the certificate:

" "

%1

", QString::fromLocal8Bit( err.asString() ) ) : i18n( "

An error occurred while trying " "to import the certificate %1:

" "

%2

", id, QString::fromLocal8Bit( err.asString() ) ); } void ImportCertificatesCommand::Private::showError( QWidget * parent, const Error & err, const QString & id ) { if ( parent ) KMessageBox::error( parent, make_error_message( err, id ), i18n( "Certificate Import Failed" ) ); else showError( err, id ); } void ImportCertificatesCommand::Private::showError( const Error & err, const QString & id ) { error( make_error_message( err, id ), i18n( "Certificate Import Failed" ) ); } void ImportCertificatesCommand::Private::setWaitForMoreJobs( bool wait ) { if ( wait == waitForMoreJobs ) return; waitForMoreJobs = wait; tryToFinish(); } void ImportCertificatesCommand::Private::importResult( const ImportResult & result ) { jobs.erase( std::remove( jobs.begin(), jobs.end(), q->sender() ), jobs.end() ); importResult( result, idsByJob[q->sender()] ); } void ImportCertificatesCommand::Private::importResult( const ImportResult & result, const QString & id ) { results.push_back( result ); ids.push_back( id ); tryToFinish(); } void ImportCertificatesCommand::Private::tryToFinish() { if ( waitForMoreJobs || !jobs.empty() ) return; if ( kdtools::any( results, boost::bind( &Error::code, boost::bind( &ImportResult::error, _1 ) ) ) ) { setImportResultProxyModel( results, ids ); if ( kdtools::all( results, boost::bind( &Error::isCanceled, boost::bind( &ImportResult::error, _1 ) ) ) ) emit q->canceled(); else for ( unsigned int i = 0, end = results.size() ; i != end ; ++i ) if ( const Error err = results[i].error() ) showError( err, ids[i] ); } else showDetails( results, ids ); finished(); } static std::auto_ptr get_import_job( GpgME::Protocol protocol ) { assert( protocol != UnknownProtocol ); if ( const Kleo::CryptoBackend::Protocol * const backend = CryptoBackendFactory::instance()->protocol( protocol ) ) return std::auto_ptr( backend->importJob() ); else return std::auto_ptr(); } void ImportCertificatesCommand::Private::startImport( GpgME::Protocol protocol, const QByteArray & data, const QString & id ) { assert( protocol != UnknownProtocol ); if ( kdtools::contains( nonWorkingProtocols, protocol ) ) return; std::auto_ptr job = get_import_job( protocol ); if ( !job.get() ) { nonWorkingProtocols.push_back( protocol ); error( i18n( "The type of this certificate (%1) is not supported by this Kleopatra installation.", Formatting::displayName( protocol ) ), i18n( "Certificate Import Failed" ) ); importResult( ImportResult(), id ); return; } connect( job.get(), SIGNAL(result(GpgME::ImportResult)), q, SLOT(importResult(GpgME::ImportResult)) ); connect( job.get(), SIGNAL(progress(QString,int,int)), q, SIGNAL(progress(QString,int,int)) ); const GpgME::Error err = job->start( data ); if ( err.code() ) { importResult( ImportResult( err ), id ); } else { jobs.push_back( job.release() ); idsByJob[jobs.back()] = id; } } static std::auto_ptr get_import_from_keyserver_job( GpgME::Protocol protocol ) { assert( protocol != UnknownProtocol ); if ( const Kleo::CryptoBackend::Protocol * const backend = CryptoBackendFactory::instance()->protocol( protocol ) ) return std::auto_ptr( backend->importFromKeyserverJob() ); else return std::auto_ptr(); } void ImportCertificatesCommand::Private::startImport( GpgME::Protocol protocol, const std::vector & keys, const QString & id ) { assert( protocol != UnknownProtocol ); if ( kdtools::contains( nonWorkingProtocols, protocol ) ) return; std::auto_ptr job = get_import_from_keyserver_job( protocol ); if ( !job.get() ) { nonWorkingProtocols.push_back( protocol ); error( i18n( "The type of this certificate (%1) is not supported by this Kleopatra installation.", Formatting::displayName( protocol ) ), i18n( "Certificate Import Failed" ) ); importResult( ImportResult(), id ); return; } connect( job.get(), SIGNAL(result(GpgME::ImportResult)), q, SLOT(importResult(GpgME::ImportResult)) ); connect( job.get(), SIGNAL(progress(QString,int,int)), q, SIGNAL(progress(QString,int,int)) ); const GpgME::Error err = job->start( keys ); if ( err.code() ) { importResult( ImportResult( err ), id ); } else { jobs.push_back( job.release() ); idsByJob[jobs.back()] = id; } } void ImportCertificatesCommand::doCancel() { kdtools::for_each( d->jobs, mem_fn( &Job::slotCancel ) ); } #undef d #undef q #include "moc_importcertificatescommand.cpp" #include "importcertificatescommand.moc" diff --git a/kleopatra/commands/lookupcertificatescommand.cpp b/kleopatra/commands/lookupcertificatescommand.cpp index 83308d64f9..b54cd45d8f 100644 --- a/kleopatra/commands/lookupcertificatescommand.cpp +++ b/kleopatra/commands/lookupcertificatescommand.cpp @@ -1,399 +1,401 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/lookupcertificatescommand.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2008, 2009 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "lookupcertificatescommand.h" #include "importcertificatescommand_p.h" #include "detailscommand.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#ifndef Q_MOC_RUN #include #include +#endif #include #include #include #include using namespace Kleo; using namespace Kleo::Commands; using namespace Kleo::Dialogs; using namespace GpgME; using namespace boost; class LookupCertificatesCommand::Private : public ImportCertificatesCommand::Private { friend class ::Kleo::Commands::LookupCertificatesCommand; LookupCertificatesCommand * q_func() const { return static_cast( q ); } public: explicit Private( LookupCertificatesCommand * qq, KeyListController * c ); ~Private(); QString fingerPrint; void init(); private: void slotSearchTextChanged( const QString & str ); void slotNextKey( const Key & key ) { keyListing.keys.push_back( key ); } void slotKeyListResult( const KeyListResult & result ); void slotImportRequested( const std::vector & keys ); void slotDetailsRequested( const Key & key ); void slotSaveAsRequested( const std::vector & keys ); void slotDialogRejected() { canceled(); } private: using ImportCertificatesCommand::Private::showError; void showError( QWidget * parent, const KeyListResult & result ); void showResult( QWidget * parent, const KeyListResult & result ); void createDialog(); KeyListJob * createKeyListJob( GpgME::Protocol proto ) const { const CryptoBackend::Protocol * const cbp = CryptoBackendFactory::instance()->protocol( proto ); return cbp ? cbp->keyListJob( true ) : 0 ; } ImportFromKeyserverJob * createImportJob( GpgME::Protocol proto ) const { const CryptoBackend::Protocol * const cbp = CryptoBackendFactory::instance()->protocol( proto ); return cbp ? cbp->importFromKeyserverJob() : 0 ; } void startKeyListJob( GpgME::Protocol proto, const QString & str ); bool checkConfig() const; QWidget * dialogOrParentWidgetOrView() const { if ( dialog ) return dialog; else return parentWidgetOrView(); } private: QPointer dialog; struct KeyListingVariables { QPointer cms, openpgp; KeyListResult result; std::vector keys; void reset() { *this = KeyListingVariables(); } } keyListing; }; LookupCertificatesCommand::Private * LookupCertificatesCommand::d_func() { return static_cast( d.get() ); } const LookupCertificatesCommand::Private * LookupCertificatesCommand::d_func() const { return static_cast( d.get() ); } #define d d_func() #define q q_func() LookupCertificatesCommand::Private::Private( LookupCertificatesCommand * qq, KeyListController * c ) : ImportCertificatesCommand::Private( qq, c ), dialog() { } LookupCertificatesCommand::Private::~Private() { kDebug(); delete dialog; } LookupCertificatesCommand::LookupCertificatesCommand( KeyListController * c ) : ImportCertificatesCommand( new Private( this, c ) ) { d->init(); } LookupCertificatesCommand::LookupCertificatesCommand( const QString & fingerPrint, KeyListController * c ) : ImportCertificatesCommand( new Private( this, c ) ) { d->init(); d->fingerPrint = fingerPrint; } LookupCertificatesCommand::LookupCertificatesCommand( QAbstractItemView * v, KeyListController * c ) : ImportCertificatesCommand( v, new Private( this, c ) ) { d->init(); } void LookupCertificatesCommand::Private::init() { } LookupCertificatesCommand::~LookupCertificatesCommand() { kDebug(); } void LookupCertificatesCommand::doStart() { if ( !d->checkConfig() ) { d->finished(); return; } d->createDialog(); assert( d->dialog ); // if have prespecified fingerPrint, load into find field // and start search if ( ! d->fingerPrint.isEmpty() ) { if ( !d->fingerPrint.startsWith( QLatin1String("0x") ) ) d->fingerPrint = QLatin1String("0x") + d->fingerPrint; d->dialog->setSearchText( d->fingerPrint ); // Start Search d->slotSearchTextChanged( d->fingerPrint ); } d->dialog->setPassive( false ); d->dialog->show(); } void LookupCertificatesCommand::Private::createDialog() { if ( dialog ) return; dialog = new LookupCertificatesDialog; applyWindowID( dialog ); dialog->setAttribute( Qt::WA_DeleteOnClose ); connect( dialog, SIGNAL(searchTextChanged(QString)), q, SLOT(slotSearchTextChanged(QString)) ); connect( dialog, SIGNAL(saveAsRequested(std::vector)), q, SLOT(slotSaveAsRequested(std::vector)) ); connect( dialog, SIGNAL(importRequested(std::vector)), q, SLOT(slotImportRequested(std::vector)) ); connect( dialog, SIGNAL(detailsRequested(GpgME::Key)), q, SLOT(slotDetailsRequested(GpgME::Key)) ); connect( dialog, SIGNAL(rejected()), q, SLOT(slotDialogRejected()) ); } void LookupCertificatesCommand::Private::slotSearchTextChanged( const QString & str ) { // pressing return might trigger both search and dialog destruction (search focused and default key set) // On Windows, the dialog is then destroyed before this slot is called if ( dialog ) { //thus test dialog->setPassive( true ); dialog->setCertificates( std::vector() ); } const QRegExp rx( QLatin1String( "(?:0x|0X)?[0-9a-fA-F]{6,}" ) ); if ( rx.exactMatch( str ) ) information( str.startsWith( QLatin1String( "0x" ), Qt::CaseInsensitive ) ? i18n("

You seem to be searching for a fingerPrint or a key-id.

" "

Different keyservers expect different ways to search for these. " "Some require a \"0x\" prefix, while others require there be no such prefix.

" "

If your search does not yield any results, try removing the 0x prefix from your search.

") : i18n("

You seem to be searching for a fingerPrint or a key-id.

" "

Different keyservers expect different ways to search for these. " "Some require a \"0x\" prefix, while others require there be no such prefix.

" "

If your search does not yield any results, try adding the 0x prefix to your search.

"), i18n("Hex-String Search"), QLatin1String( "lookup-certificates-warn-0x-prefix" ) ); startKeyListJob( CMS, str ); startKeyListJob( OpenPGP, str ); } void LookupCertificatesCommand::Private::startKeyListJob( GpgME::Protocol proto, const QString & str ) { KeyListJob * const klj = createKeyListJob( proto ); if ( !klj ) return; connect( klj, SIGNAL(result(GpgME::KeyListResult)), q, SLOT(slotKeyListResult(GpgME::KeyListResult)) ); connect( klj, SIGNAL(nextKey(GpgME::Key)), q, SLOT(slotNextKey(GpgME::Key)) ); if ( const Error err = klj->start( QStringList( str ) ) ) keyListing.result.mergeWith( KeyListResult( err ) ); else if ( proto == CMS ) keyListing.cms = klj; else keyListing.openpgp = klj; } void LookupCertificatesCommand::Private::slotKeyListResult( const KeyListResult & r ) { if ( q->sender() == keyListing.cms ) keyListing.cms = 0; else if ( q->sender() == keyListing.openpgp ) keyListing.openpgp = 0; else kDebug() << "unknown sender()" << q->sender(); keyListing.result.mergeWith( r ); if ( keyListing.cms || keyListing.openpgp ) // still waiting for jobs to complete return; if ( keyListing.result.error() && !keyListing.result.error().isCanceled() ) showError( dialog, keyListing.result ); if ( keyListing.result.isTruncated() ) showResult( dialog, keyListing.result ); if ( dialog ) { dialog->setPassive( false ); dialog->setCertificates( keyListing.keys ); } else { finished(); } keyListing.reset(); } void LookupCertificatesCommand::Private::slotImportRequested( const std::vector & keys ) { dialog = 0; assert( !keys.empty() ); assert( kdtools::none_of( keys, mem_fn( &Key::isNull ) ) ); std::vector pgp, cms; pgp.reserve( keys.size() ); cms.reserve( keys.size() ); kdtools::separate_if( keys.begin(), keys.end(), std::back_inserter( pgp ), std::back_inserter( cms ), boost::bind( &Key::protocol, _1 ) == OpenPGP ); setWaitForMoreJobs( true ); if ( !pgp.empty() ) startImport( OpenPGP, pgp, i18nc("@title %1:\"OpenPGP\" or \"CMS\"", "%1 Certificate Server", Formatting::displayName( OpenPGP ) ) ); if ( !cms.empty() ) startImport( CMS, cms, i18nc("@title %1:\"OpenPGP\" or \"CMS\"", "%1 Certificate Server", Formatting::displayName( CMS ) ) ); setWaitForMoreJobs( false ); } void LookupCertificatesCommand::Private::slotSaveAsRequested( const std::vector & keys ) { Q_UNUSED( keys ); kDebug() << "not implemented"; } void LookupCertificatesCommand::Private::slotDetailsRequested( const Key & key ) { Command * const cmd = new DetailsCommand( key, view(), controller() ); cmd->setParentWidget( dialogOrParentWidgetOrView() ); cmd->start(); } void LookupCertificatesCommand::doCancel() { ImportCertificatesCommand::doCancel(); if ( QDialog * const dlg = d->dialog ) { d->dialog = 0; dlg->close(); } } void LookupCertificatesCommand::Private::showError( QWidget * parent, const KeyListResult & result ) { if ( !result.error() ) return; KMessageBox::information( parent, i18nc( "@info", "Failed to search on certificate server. The error returned was:\n%1", QString::fromLocal8Bit( result.error().asString() ) ) ); } void LookupCertificatesCommand::Private::showResult( QWidget * parent, const KeyListResult & result ) { if ( result.isTruncated() ) KMessageBox::information( parent, i18nc("@info", "The query result has been truncated." "Either the local or a remote limit on " "the maximum number of returned hits has " "been exceeded." "You can try to increase the local limit " "in the configuration dialog, but if one " "of the configured servers is the limiting " "factor, you have to refine your search."), i18nc("@title", "Result Truncated"), QLatin1String("lookup-certificates-truncated-result") ); } static bool haveOpenPGPKeyserverConfigured() { const Kleo::CryptoConfig * const config = Kleo::CryptoBackendFactory::instance()->config(); if ( !config ) return false; const Kleo::CryptoConfigEntry * const entry = config->entry( QLatin1String("gpg"), QLatin1String("Keyserver"), QLatin1String("keyserver") ); return entry && !entry->stringValue().isEmpty(); } static bool haveX509DirectoryServerConfigured() { const Kleo::CryptoConfig * const config = Kleo::CryptoBackendFactory::instance()->config(); if ( !config ) return false; const Kleo::CryptoConfigEntry * entry = config->entry( QLatin1String("dirmngr"), QLatin1String("LDAP"), QLatin1String("LDAP Server") ); bool entriesExist = entry && !entry->urlValueList().empty(); entry = config->entry( QLatin1String("gpgsm"), QLatin1String("Configuration"), QLatin1String("keyserver") ); entriesExist |= entry && !entry->stringValueList().empty(); return entriesExist; } bool LookupCertificatesCommand::Private::checkConfig() const { const bool ok = haveOpenPGPKeyserverConfigured() || haveX509DirectoryServerConfigured(); if ( !ok ) information( i18nc("@info", "You do not have any directory servers configured." "You need to configure at least one directory server to " "search on one." "You can configure directory servers here: " "Settings->Configure Kleopatra."), i18nc("@title", "No Directory Servers Configured") ); return ok; } #undef d #undef q #include "moc_lookupcertificatescommand.cpp" diff --git a/kleopatra/commands/reloadkeyscommand.cpp b/kleopatra/commands/reloadkeyscommand.cpp index a405d165f2..4427b785ad 100644 --- a/kleopatra/commands/reloadkeyscommand.cpp +++ b/kleopatra/commands/reloadkeyscommand.cpp @@ -1,104 +1,106 @@ /* -*- mode: c++; c-basic-offset:4 -*- reloadkeyscommand.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2007 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "reloadkeyscommand.h" #include "command_p.h" #include #include #include +#ifndef Q_MOC_RUN #include +#endif using namespace Kleo; using namespace boost; using namespace GpgME; class ReloadKeysCommand::Private : public Command::Private { friend class ::Kleo::ReloadKeysCommand; public: Private( ReloadKeysCommand * qq, KeyListController* controller ); ~Private(); void keyListingDone( const KeyListResult & result ); }; ReloadKeysCommand::Private * ReloadKeysCommand::d_func() { return static_cast( d.get() ); } const ReloadKeysCommand::Private * ReloadKeysCommand::d_func() const { return static_cast( d.get() ); } ReloadKeysCommand::ReloadKeysCommand( KeyListController * p ) : Command( new Private( this, p ) ) { } ReloadKeysCommand::ReloadKeysCommand( QAbstractItemView * v, KeyListController * p ) : Command( v, new Private( this, p ) ) { } ReloadKeysCommand::~ReloadKeysCommand() {} ReloadKeysCommand::Private::Private( ReloadKeysCommand * qq, KeyListController * controller ) : Command::Private( qq, controller ) { } ReloadKeysCommand::Private::~Private() {} void ReloadKeysCommand::Private::keyListingDone( const KeyListResult & result ) { if ( result.error() ) // ### Show error message here? kError() << "Error occurred during key listing: " << result.error().asString(); finished(); } #define d d_func() void ReloadKeysCommand::doStart() { connect( KeyCache::mutableInstance().get(), SIGNAL(keyListingDone(GpgME::KeyListResult)), this, SLOT(keyListingDone(GpgME::KeyListResult)) ); KeyCache::mutableInstance()->startKeyListing(); } void ReloadKeysCommand::doCancel() { KeyCache::mutableInstance()->cancelKeyListing(); } #undef d #include "moc_reloadkeyscommand.cpp" diff --git a/kleopatra/commands/selftestcommand.cpp b/kleopatra/commands/selftestcommand.cpp index bd1e4dfe0a..f7f49627b7 100644 --- a/kleopatra/commands/selftestcommand.cpp +++ b/kleopatra/commands/selftestcommand.cpp @@ -1,278 +1,280 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/selftestcommand.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2008 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "selftestcommand.h" #include "command_p.h" #include #ifdef Q_OS_WIN # include #endif #include #include #ifdef HAVE_KLEOPATRACLIENT_LIBRARY # include #endif #include #include #include #include #include #include #include #include +#ifndef Q_MOC_RUN #include #include +#endif #include using namespace Kleo; using namespace Kleo::Commands; using namespace Kleo::Dialogs; using namespace boost; static const char * const components[] = { 0, // gpgconf "gpg", "gpg-agent", "scdaemon", "gpgsm", "dirmngr", }; static const unsigned int numComponents = sizeof components / sizeof *components; class SelfTestCommand::Private : Command::Private { friend class ::Kleo::Commands::SelfTestCommand; SelfTestCommand * q_func() const { return static_cast( q ); } public: explicit Private( SelfTestCommand * qq, KeyListController * c ); ~Private(); private: void init(); void ensureDialogCreated() { if ( dialog ) return; dialog = new SelfTestDialog; applyWindowID( dialog ); dialog->setAttribute( Qt::WA_DeleteOnClose ); connect( dialog, SIGNAL(updateRequested()), q_func(), SLOT(slotUpdateRequested()) ); connect( dialog, SIGNAL(accepted()), q_func(), SLOT(slotDialogAccepted()) ); connect( dialog, SIGNAL(rejected()), q_func(), SLOT(slotDialogRejected()) ); dialog->setRunAtStartUp( runAtStartUp() ); dialog->setAutomaticMode( automatic ); } void ensureDialogShown() { ensureDialogCreated(); if ( dialog->isVisible() ) dialog->raise(); else dialog->show(); #ifndef QT_NO_SPLASHSCREEN if ( splash ) splash->finish( dialog ); #endif // QT_NO_SPLASHSCREEN } bool runAtStartUp() const { const KConfigGroup config( KGlobal::config(), "Self-Test" ); return config.readEntry( "run-at-startup", true ); } void setRunAtStartUp( bool on ) { KConfigGroup config( KGlobal::config(), "Self-Test" ); config.writeEntry( "run-at-startup", on ); } void runTests() { std::vector< shared_ptr > tests; #if defined(Q_OS_WIN) //emit q->info( i18n("Checking Windows Registry...") ); tests.push_back( makeGpgProgramRegistryCheckSelfTest() ); #endif //emit q->info( i18n("Checking gpg installation...") ); tests.push_back( makeGpgEngineCheckSelfTest() ); //emit q->info( i18n("Checking gpgsm installation...") ); tests.push_back( makeGpgSmEngineCheckSelfTest() ); //emit q->info( i18n("Checking gpgconf installation...") ); tests.push_back( makeGpgConfEngineCheckSelfTest() ); for ( unsigned int i = 0 ; i < numComponents ; ++i ) { //emit q->info( i18n("Checking %1 configuration...", components[i]) ); tests.push_back( makeGpgConfCheckConfigurationSelfTest( components[i] ) ); } #if defined( HAVE_KLEOPATRACLIENT_LIBRARY ) //emit q->info( i18n("Checking Ui Server connectivity...") ); tests.push_back( makeUiServerConnectivitySelfTest() ); #endif #ifndef Q_OS_WIN tests.push_back( makeGpgAgentConnectivitySelfTest() ); #endif tests.push_back( makeLibKleopatraRcSelfTest() ); if ( !dialog && kdtools::none_of( tests, mem_fn( &Kleo::SelfTest::failed ) ) ) { finished(); return; } ensureDialogCreated(); dialog->clear(); dialog->addSelfTests( tests ); ensureDialogShown(); } private: void slotDialogAccepted() { setRunAtStartUp( dialog->runAtStartUp() ); finished(); } void slotDialogRejected() { if ( automatic ) { canceled = true; Command::Private::canceled(); } else { slotDialogAccepted(); } } void slotUpdateRequested() { runTests(); } private: #ifndef QT_NO_SPLASHSCREEN QPointer splash; #endif // QT_NO_SPLASHSCREEN QPointer dialog; bool canceled; bool automatic; }; SelfTestCommand::Private * SelfTestCommand::d_func() { return static_cast( d.get() ); } const SelfTestCommand::Private * SelfTestCommand::d_func() const { return static_cast( d.get() ); } #define d d_func() #define q q_func() SelfTestCommand::Private::Private( SelfTestCommand * qq, KeyListController * c ) : Command::Private( qq, c ), #ifndef QT_NO_SPLASHSCREEN splash(), #endif // QT_NO_SPLASHSCREEN dialog(), canceled( false ), automatic( false ) { } SelfTestCommand::Private::~Private() { } SelfTestCommand::SelfTestCommand( KeyListController * c ) : Command( new Private( this, c ) ) { d->init(); } SelfTestCommand::SelfTestCommand( QAbstractItemView * v, KeyListController * c ) : Command( v, new Private( this, c ) ) { d->init(); } void SelfTestCommand::Private::init() { } SelfTestCommand::~SelfTestCommand() {} void SelfTestCommand::setAutomaticMode( bool on ) { d->automatic = on; if ( d->dialog ) d->dialog->setAutomaticMode( on ); } void SelfTestCommand::setSplashScreen( KSplashScreen * splash ) { #ifndef QT_NO_SPLASHSCREEN d->splash = splash; #else Q_UNUSED( splash ); #endif // QT_NO_SPLASHSCREEN } bool SelfTestCommand::isCanceled() const { return d->canceled; } void SelfTestCommand::doStart() { if ( d->automatic ) { if ( !d->runAtStartUp() ) { d->finished(); return; } } else { d->ensureDialogCreated(); } d->runTests(); } void SelfTestCommand::doCancel() { d->canceled = true; if ( d->dialog ) d->dialog->close(); d->dialog = 0; } #undef d #undef q #include "moc_selftestcommand.cpp" diff --git a/kleopatra/conf/appearanceconfigwidget.cpp b/kleopatra/conf/appearanceconfigwidget.cpp index 0b3012d17c..123f63f732 100644 --- a/kleopatra/conf/appearanceconfigwidget.cpp +++ b/kleopatra/conf/appearanceconfigwidget.cpp @@ -1,593 +1,595 @@ /* appearanceconfigwidget.cpp This file is part of kleopatra, the KDE key manager Copyright (c) 2002,2004,2008 Klarälvdalens Datakonsult AB Copyright (c) 2002,2003 Marc Mutz Libkleopatra 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. Libkleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "appearanceconfigwidget.h" #include "ui_appearanceconfigwidget.h" #include "tooltippreferences.h" #include "libkleo/kleo/cryptobackendfactory.h" #include "libkleo/kleo/keyfiltermanager.h" #include "libkleo/kleo/dn.h" #include "libkleo/ui/dnattributeorderconfigwidget.h" #ifdef KDEPIM_ONLY_KLEO # include #else # include #endif #include #include #include #include #include #include #include #include #include #include +#ifndef Q_MOC_RUN #include #include +#endif #include #include using namespace Kleo; using namespace Kleo::Config; using namespace boost; #ifdef KDEPIM_ONLY_KLEO using namespace Kleo::KioAvoidance; #endif enum { HasNameRole = Qt::UserRole + 0x1234, /*!< Records that the user has assigned a name (to avoid comparing with i18n-strings) */ HasFontRole, /*!< Records that the user has chosen completely different font (as opposed to italic/bold/strikeout) */ IconNameRole, /*!< Records the name of the icon (since QIcon won't give it out again, once set) */ MayChangeNameRole, MayChangeForegroundRole, MayChangeBackgroundRole, MayChangeFontRole, MayChangeItalicRole, MayChangeBoldRole, MayChangeStrikeOutRole, MayChangeIconRole, EndDummy }; static QFont tryToFindFontFor( const QListWidgetItem * item ) { if ( item ) if ( const QListWidget * const lw = item->listWidget() ) return lw->font(); return QApplication::font( "QListWidget" ); } static bool is( const QListWidgetItem * item, bool (QFont::*func)() const ) { if ( !item ) return false; const QVariant v = item->data( Qt::FontRole ); if ( !v.isValid() || v.type() != QVariant::Font ) return false; return (v.value().*func)(); } static bool is_italic( const QListWidgetItem * item ) { return is( item, &QFont::italic ); } static bool is_bold( const QListWidgetItem * item ) { return is( item, &QFont::bold ); } static bool is_strikeout( const QListWidgetItem * item ) { return is( item, &QFont::strikeOut ); } static void set( QListWidgetItem * item, bool on, void (QFont::*func)(bool) ) { if ( !item ) return; const QVariant v = item->data( Qt::FontRole ); QFont font = v.isValid() && v.type() == QVariant::Font ? v.value() : tryToFindFontFor( item ) ; (font.*func)( on ); item->setData( Qt::FontRole, font ); } static void set_italic( QListWidgetItem * item, bool on ) { set( item, on, &QFont::setItalic ); } static void set_bold( QListWidgetItem * item, bool on ) { set( item, on, &QFont::setBold ); } static void set_strikeout( QListWidgetItem * item, bool on ) { set( item, on, &QFont::setStrikeOut ); } static void apply_config( const KConfigGroup & group, QListWidgetItem * item ) { if ( !item ) return; const QString name = group.readEntry( "Name" ); item->setText( name.isEmpty() ? i18nc("Key filter without user-assigned name", "") : name ); item->setData( HasNameRole, !name.isEmpty() ); item->setData( MayChangeNameRole, !group.isEntryImmutable( "Name" ) ); const QColor fg = group.readEntry( "foreground-color", QColor() ); item->setData( Qt::ForegroundRole, fg.isValid() ? QBrush( fg ) : QVariant() ); item->setData( MayChangeForegroundRole, !group.isEntryImmutable( "foreground-color" ) ); const QColor bg = group.readEntry( "background-color", QColor() ); item->setData( Qt::BackgroundRole, bg.isValid() ? QBrush( bg ) : QVariant() ); item->setData( MayChangeBackgroundRole, !group.isEntryImmutable( "background-color" ) ); const QFont defaultFont = tryToFindFontFor( item ); if ( group.hasKey( "font" ) ) { const QFont font = group.readEntry( "font", defaultFont ); item->setData( Qt::FontRole, font != defaultFont ? font : QVariant() ); item->setData( HasFontRole, font != defaultFont ); } else { QFont font = defaultFont; font.setStrikeOut( group.readEntry( "font-strikeout", false ) ); font.setItalic( group.readEntry( "font-italic", false ) ); font.setBold( group.readEntry( "font-bold", false ) ); item->setData( Qt::FontRole, font ); item->setData( HasFontRole, false ); } item->setData( MayChangeFontRole, !group.isEntryImmutable( "font" ) ); item->setData( MayChangeItalicRole, !group.isEntryImmutable( "font-italic" ) ); item->setData( MayChangeBoldRole, !group.isEntryImmutable( "font-bold" ) ); item->setData( MayChangeStrikeOutRole, !group.isEntryImmutable( "font-strikeout" ) ); const QString iconName = group.readEntry( "icon" ); item->setData( Qt::DecorationRole, iconName.isEmpty() ? QVariant() : KIcon( iconName ) ); item->setData( IconNameRole, iconName.isEmpty() ? QVariant() : iconName ); item->setData( MayChangeIconRole, !group.isEntryImmutable( "icon" ) ); } static void erase_if_allowed( QListWidgetItem * item, int role, int allowRole ) { if ( item && item->data( allowRole ).toBool() ) item->setData( role, QVariant() ); } #if 0 static void erase_if_allowed( QListWidgetItem * item, const int role[], size_t numRoles, int allowRole ) { if ( item && item->data( allowRole ).toBool() ) for ( unsigned int i = 0 ; i < numRoles ; ++i ) item->setData( role[i], QVariant() ); } static void erase_if_allowed( QListWidgetItem * item, int role, const int allowRole[], size_t numAllowRoles ) { if ( !item ) return; for ( unsigned int i = 0 ; i < numAllowRoles ; ++i ) if ( !item->data( allowRole[i] ).toBool() ) return; item->setData( role, QVariant() ); } #endif static void erase_if_allowed( QListWidgetItem * item, const int role[], size_t numRoles, const int allowRole[], size_t numAllowRoles ) { if ( !item ) return; for ( unsigned int i = 0 ; i < numAllowRoles ; ++i ) if ( !item->data( allowRole[i] ).toBool() ) return; for ( unsigned int i = 0 ; i < numRoles ; ++i ) item->setData( role[i], QVariant() ); } static void set_default_appearance( QListWidgetItem * item ) { if ( !item ) return; erase_if_allowed( item, Qt::ForegroundRole, MayChangeForegroundRole ); erase_if_allowed( item, Qt::BackgroundRole, MayChangeBackgroundRole ); erase_if_allowed( item, Qt::DecorationRole, MayChangeIconRole ); static const int fontRoles[] = { Qt::FontRole, HasFontRole }; static const int fontAllowRoles[] = { MayChangeFontRole, MayChangeItalicRole, MayChangeBoldRole, MayChangeStrikeOutRole, }; erase_if_allowed( item, fontRoles, size( fontRoles ), fontAllowRoles, size( fontAllowRoles ) ); } static void writeOrDelete( KConfigGroup & group, const char * key, const QVariant & value ) { if ( value.isValid() ) group.writeEntry( key, value ); else group.deleteEntry( key ); } static QVariant brush2color( const QVariant & v ) { if ( v.isValid() ) { if ( v.type() == QVariant::Color ) return v; else if ( v.type() == QVariant::Brush ) return v.value().color(); } return QVariant(); } static void save_to_config( const QListWidgetItem * item, KConfigGroup & group ) { if ( !item ) return; writeOrDelete( group, "Name", item->data( HasNameRole ).toBool() ? item->text() : QVariant() ); writeOrDelete( group, "foreground-color", brush2color( item->data( Qt::ForegroundRole ) ) ); writeOrDelete( group, "background-color", brush2color( item->data( Qt::BackgroundRole ) ) ); writeOrDelete( group, "icon", item->data( IconNameRole ) ); group.deleteEntry( "font" ); group.deleteEntry( "font-strikeout" ); group.deleteEntry( "font-italic" ); group.deleteEntry( "font-bold" ); if ( item->data( HasFontRole ).toBool() ) { writeOrDelete( group, "font", item->data( Qt::FontRole ) ); return; } if ( is_strikeout( item ) ) group.writeEntry( "font-strikeout", true ); if ( is_italic( item ) ) group.writeEntry( "font-italic", true ); if ( is_bold( item ) ) group.writeEntry( "font-bold", true ); } static void kiosk_enable( QWidget * w, const QListWidgetItem * item, int allowRole ) { if ( !w ) return; if ( item && !item->data( allowRole ).toBool() ) { w->setEnabled( false ); w->setToolTip( i18n( "This parameter has been locked down by the system administrator." ) ); } else { w->setEnabled( item ); w->setToolTip( QString() ); } } class AppearanceConfigWidget::Private : public Ui_AppearanceConfigWidget { friend class ::Kleo::Config::AppearanceConfigWidget; AppearanceConfigWidget * const q; public: explicit Private( AppearanceConfigWidget * qq ) : Ui_AppearanceConfigWidget(), q( qq ), dnOrderWidget( 0 ) { setupUi( q ); if ( QLayout * const l = q->layout() ) l->setMargin( 0 ); QWidget * w = new QWidget; dnOrderWidget = Kleo::DNAttributeMapper::instance()->configWidget( w ); dnOrderWidget->setObjectName( QLatin1String( "dnOrderWidget" ) ); ( new QVBoxLayout( w ) )->addWidget( dnOrderWidget ); tabWidget->addTab( w, i18n("DN-Attribute Order") ); connect( dnOrderWidget, SIGNAL(changed()), q, SIGNAL(changed()) ); connect( iconButton, SIGNAL(clicked()), q, SLOT(slotIconClicked()) ); #ifndef QT_NO_COLORDIALOG connect( foregroundButton, SIGNAL(clicked()), q, SLOT(slotForegroundClicked()) ); connect( backgroundButton, SIGNAL(clicked()), q, SLOT(slotBackgroundClicked()) ); #else foregroundButton->hide(); backgroundButton->hide(); #endif #ifndef QT_NO_FONTDIALOG connect( fontButton, SIGNAL(clicked()), q, SLOT(slotFontClicked()) ); #else fontButton->hide(); #endif connect( categoriesLV, SIGNAL(itemSelectionChanged()), q, SLOT(slotSelectionChanged()) ); connect( defaultLookPB, SIGNAL(clicked()), q, SLOT(slotDefaultClicked()) ); connect( italicCB, SIGNAL(toggled(bool)), q, SLOT(slotItalicToggled(bool)) ); connect( boldCB, SIGNAL(toggled(bool)), q, SLOT(slotBoldToggled(bool)) ); connect( strikeoutCB, SIGNAL(toggled(bool)), q, SLOT(slotStrikeOutToggled(bool)) ); connect( tooltipValidityCheckBox, SIGNAL(toggled(bool)), q, SLOT(slotTooltipValidityChanged(bool)) ); connect( tooltipOwnerCheckBox, SIGNAL(toggled(bool)), q, SLOT(slotTooltipOwnerChanged(bool)) ); connect( tooltipDetailsCheckBox, SIGNAL(toggled(bool)), q, SLOT(slotTooltipDetailsChanged(bool)) ); } private: void enableDisableActions( QListWidgetItem * item ); QListWidgetItem * selectedItem() const; private: void slotIconClicked(); #ifndef QT_NO_COLORDIALOG void slotForegroundClicked(); void slotBackgroundClicked(); #endif #ifndef QT_NO_FONTDIALOG void slotFontClicked(); #endif void slotSelectionChanged(); void slotDefaultClicked(); void slotItalicToggled(bool); void slotBoldToggled(bool); void slotStrikeOutToggled(bool); void slotTooltipValidityChanged(bool); void slotTooltipOwnerChanged(bool); void slotTooltipDetailsChanged(bool); private: Kleo::DNAttributeOrderConfigWidget * dnOrderWidget; }; AppearanceConfigWidget::AppearanceConfigWidget( QWidget * p, Qt::WindowFlags f ) : QWidget( p, f ), d( new Private( this ) ) { // load(); } AppearanceConfigWidget::~AppearanceConfigWidget() {} void AppearanceConfigWidget::Private::slotSelectionChanged() { enableDisableActions( selectedItem() ); } QListWidgetItem * AppearanceConfigWidget::Private::selectedItem() const { const QList items = categoriesLV->selectedItems(); return items.empty() ? 0 : items.front() ; } void AppearanceConfigWidget::Private::enableDisableActions( QListWidgetItem * item ) { kiosk_enable( iconButton, item, MayChangeIconRole ); #ifndef QT_NO_COLORDIALOG kiosk_enable( foregroundButton, item, MayChangeForegroundRole ); kiosk_enable( backgroundButton, item, MayChangeBackgroundRole ); #endif #ifndef QT_NO_FONTDIALOG kiosk_enable( fontButton, item, MayChangeFontRole ); #endif kiosk_enable( italicCB, item, MayChangeItalicRole ); kiosk_enable( boldCB, item, MayChangeBoldRole ); kiosk_enable( strikeoutCB, item, MayChangeStrikeOutRole ); defaultLookPB->setEnabled( item ); italicCB->setChecked( is_italic( item ) ); boldCB->setChecked( is_bold( item ) ); strikeoutCB->setChecked( is_strikeout( item ) ); } void AppearanceConfigWidget::Private::slotDefaultClicked() { QListWidgetItem * const item = selectedItem(); if ( !item ) return; set_default_appearance( item ); enableDisableActions( item ); emit q->changed(); } void AppearanceConfigWidget::defaults() { // This simply means "default look for every category" for ( int i = 0, end = d->categoriesLV->count() ; i != end ; ++i ) set_default_appearance( d->categoriesLV->item( i ) ); d->tooltipValidityCheckBox->setChecked( true ); d->tooltipOwnerCheckBox->setChecked( false ); d->tooltipDetailsCheckBox->setChecked( false ); d->dnOrderWidget->defaults(); emit changed(); } void AppearanceConfigWidget::load() { d->dnOrderWidget->load(); d->categoriesLV->clear(); KConfig * const config = CryptoBackendFactory::instance()->configObject(); if ( !config ) return; const QStringList groups = config->groupList().filter( QRegExp( QLatin1String("^Key Filter #\\d+$") ) ); Q_FOREACH( const QString & group, groups ) { //QListWidgetItem * item = new QListWidgetItem( d->categoriesLV ); apply_config( KConfigGroup( config, group ), new QListWidgetItem( d->categoriesLV ) ); } const TooltipPreferences prefs; d->tooltipValidityCheckBox->setChecked( prefs.showValidity() ); d->tooltipOwnerCheckBox->setChecked( prefs.showOwnerInformation() ); d->tooltipDetailsCheckBox->setChecked( prefs.showCertificateDetails() ); } void AppearanceConfigWidget::save() { d->dnOrderWidget->save(); TooltipPreferences prefs; prefs.setShowValidity( d->tooltipValidityCheckBox->isChecked() ); prefs.setShowOwnerInformation( d->tooltipOwnerCheckBox->isChecked() ); prefs.setShowCertificateDetails( d->tooltipDetailsCheckBox->isChecked() ); prefs.writeConfig(); KConfig * const config = CryptoBackendFactory::instance()->configObject(); if ( !config ) return; // We know (assume) that the groups in the config object haven't changed, // so we just iterate over them and over the listviewitems, and map one-to-one. const QStringList groups = config->groupList().filter( QRegExp( QLatin1String("^Key Filter #\\d+$") ) ); #if 0 if ( groups.isEmpty() ) { // If we created the default categories ourselves just now, then we need to make up their list Q3ListViewItemIterator lvit( categoriesLV ); for ( ; lvit.current() ; ++lvit ) groups << lvit.current()->text( 0 ); } #endif for ( int i = 0, end = std::min( groups.size(), d->categoriesLV->count() ) ; i != end ; ++i ) { const QListWidgetItem * const item = d->categoriesLV->item( i ); assert( item ); KConfigGroup group( config, groups[i] ); save_to_config( item, group ); } config->sync(); KeyFilterManager::instance()->reload(); } void AppearanceConfigWidget::Private::slotIconClicked() { QListWidgetItem * const item = selectedItem(); if ( !item ) return; const QString iconName = KIconDialog::getIcon( /* repeating default arguments begin */ KIconLoader::Desktop, KIconLoader::Application, false, 0, false, /* repeating default arguments end */ q ); if ( iconName.isEmpty() ) return; item->setIcon( KIcon( iconName ) ); item->setData( IconNameRole, iconName ); emit q->changed(); } #ifndef QT_NO_COLORDIALOG void AppearanceConfigWidget::Private::slotForegroundClicked() { QListWidgetItem * const item = selectedItem(); if ( !item ) return; const QVariant v = brush2color( item->data( Qt::ForegroundRole ) ); const QColor initial = v.isValid() ? v.value() : categoriesLV->palette().color( QPalette::Normal, QPalette::Text ); const QColor c = QColorDialog::getColor( initial, q ); if ( c.isValid() ) { item->setData( Qt::ForegroundRole, QBrush( c ) ); emit q->changed(); } } void AppearanceConfigWidget::Private::slotBackgroundClicked() { QListWidgetItem * const item = selectedItem(); if ( !item ) return; const QVariant v = brush2color( item->data( Qt::BackgroundRole ) ); const QColor initial = v.isValid() ? v.value() : categoriesLV->palette().color( QPalette::Normal, QPalette::Base ); const QColor c = QColorDialog::getColor( initial, q ); if ( c.isValid() ) { item->setData( Qt::BackgroundRole, QBrush( c ) ); emit q->changed(); } } #endif // QT_NO_COLORDIALOG #ifndef QT_NO_FONTDIALOG void AppearanceConfigWidget::Private::slotFontClicked() { QListWidgetItem * const item = selectedItem(); if ( !item ) return; const QVariant v = item->data( Qt::FontRole ); bool ok = false; const QFont defaultFont = tryToFindFontFor( item ); const QFont initial = v.isValid() && v.type() == QVariant::Font ? v.value() : defaultFont ; QFont f = QFontDialog::getFont( &ok, initial, q ); if ( !ok ) return; // disallow circumventing KIOSK: if ( !item->data( MayChangeItalicRole ).toBool() ) f.setItalic( initial.italic() ); if ( !item->data( MayChangeBoldRole ).toBool() ) f.setBold( initial.bold() ); if ( !item->data( MayChangeStrikeOutRole ).toBool() ) f.setStrikeOut( initial.strikeOut() ); item->setData( Qt::FontRole, f != defaultFont ? f : QVariant() ); item->setData( HasFontRole, true ); emit q->changed(); } #endif // QT_NO_FONTDIALOG void AppearanceConfigWidget::Private::slotItalicToggled( bool on ) { set_italic( selectedItem(), on ); emit q->changed(); } void AppearanceConfigWidget::Private::slotBoldToggled( bool on ) { set_bold( selectedItem(), on ); emit q->changed(); } void AppearanceConfigWidget::Private::slotStrikeOutToggled( bool on ) { set_strikeout( selectedItem(), on ); emit q->changed(); } void AppearanceConfigWidget::Private::slotTooltipValidityChanged( bool ) { emit q->changed(); } void AppearanceConfigWidget::Private::slotTooltipOwnerChanged( bool ) { emit q->changed(); } void AppearanceConfigWidget::Private::slotTooltipDetailsChanged( bool ) { emit q->changed(); } #include "moc_appearanceconfigwidget.cpp" diff --git a/kleopatra/conf/cryptooperationsconfigwidget.cpp b/kleopatra/conf/cryptooperationsconfigwidget.cpp index c6132c1180..b9ce4f5979 100644 --- a/kleopatra/conf/cryptooperationsconfigwidget.cpp +++ b/kleopatra/conf/cryptooperationsconfigwidget.cpp @@ -1,148 +1,150 @@ /* cryptooperationsconfigwidget.cpp This file is part of kleopatra, the KDE key manager Copyright (c) 2010 Klarälvdalens Datakonsult AB Libkleopatra 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. Libkleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "cryptooperationsconfigwidget.h" #include "ui_cryptooperationsconfigwidget.h" #include "emailoperationspreferences.h" #include "fileoperationspreferences.h" #include #include #include #include #include #include +#ifndef Q_MOC_RUN #include +#endif using namespace Kleo; using namespace Kleo::Config; using namespace boost; class CryptoOperationsConfigWidget::Private { friend class ::Kleo::Config::CryptoOperationsConfigWidget; CryptoOperationsConfigWidget * const q; public: explicit Private( CryptoOperationsConfigWidget * qq ) : q( qq ), ui( q ) {} private: struct UI : Ui_CryptoOperationsConfigWidget { explicit UI( CryptoOperationsConfigWidget * q ) : Ui_CryptoOperationsConfigWidget() { setupUi( q ); if ( QLayout * const l = q->layout() ) l->setMargin( 0 ); connect( quickSignCB, SIGNAL(toggled(bool)), q, SIGNAL(changed()) ); connect( quickEncryptCB, SIGNAL(toggled(bool)), q, SIGNAL(changed()) ); connect( checksumDefinitionCB, SIGNAL(currentIndexChanged(int)), q, SIGNAL(changed()) ); connect( pgpFileExtCB, SIGNAL(toggled(bool)), q, SIGNAL(changed()) ); } } ui; }; CryptoOperationsConfigWidget::CryptoOperationsConfigWidget( QWidget * p, Qt::WindowFlags f ) : QWidget( p, f ), d( new Private( this ) ) { // load(); } CryptoOperationsConfigWidget::~CryptoOperationsConfigWidget() {} void CryptoOperationsConfigWidget::defaults() { EMailOperationsPreferences emailPrefs; emailPrefs.setDefaults(); d->ui.quickSignCB->setChecked( emailPrefs.quickSignEMail() ); d->ui.quickEncryptCB->setChecked( emailPrefs.quickEncryptEMail() ); FileOperationsPreferences filePrefs; filePrefs.setDefaults(); d->ui.pgpFileExtCB->setChecked( filePrefs.usePGPFileExt() ); if ( d->ui.checksumDefinitionCB->count() ) d->ui.checksumDefinitionCB->setCurrentIndex( 0 ); } Q_DECLARE_METATYPE( boost::shared_ptr ) void CryptoOperationsConfigWidget::load() { const EMailOperationsPreferences emailPrefs; d->ui.quickSignCB ->setChecked( emailPrefs.quickSignEMail() ); d->ui.quickEncryptCB->setChecked( emailPrefs.quickEncryptEMail() ); const FileOperationsPreferences filePrefs; d->ui.pgpFileExtCB->setChecked( filePrefs.usePGPFileExt() ); const std::vector< shared_ptr > cds = ChecksumDefinition::getChecksumDefinitions(); const shared_ptr default_cd = ChecksumDefinition::getDefaultChecksumDefinition( cds ); d->ui.checksumDefinitionCB->clear(); Q_FOREACH( const shared_ptr & cd, cds ) { d->ui.checksumDefinitionCB->addItem( cd->label(), qVariantFromValue( cd ) ); if ( cd == default_cd ) d->ui.checksumDefinitionCB->setCurrentIndex( d->ui.checksumDefinitionCB->count() - 1 ); } } void CryptoOperationsConfigWidget::save() { EMailOperationsPreferences emailPrefs; emailPrefs.setQuickSignEMail ( d->ui.quickSignCB ->isChecked() ); emailPrefs.setQuickEncryptEMail( d->ui.quickEncryptCB->isChecked() ); emailPrefs.writeConfig(); FileOperationsPreferences filePrefs; filePrefs.setUsePGPFileExt( d->ui.pgpFileExtCB->isChecked() ); filePrefs.writeConfig(); const int idx = d->ui.checksumDefinitionCB->currentIndex(); if ( idx < 0 ) return; // ### pick first? const shared_ptr cd = qvariant_cast< shared_ptr >( d->ui.checksumDefinitionCB->itemData( idx ) ); ChecksumDefinition::setDefaultChecksumDefinition( cd ); } diff --git a/kleopatra/crypto/certificateresolver.cpp b/kleopatra/crypto/certificateresolver.cpp index 5f7b4e1ee0..7d78d502fe 100644 --- a/kleopatra/crypto/certificateresolver.cpp +++ b/kleopatra/crypto/certificateresolver.cpp @@ -1,273 +1,275 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/certificateresolver.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2007 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "certificateresolver.h" #include #include #include #include #include #include #include +#ifndef Q_MOC_RUN #include +#endif #include #include using namespace Kleo; using namespace Kleo::Crypto; using namespace boost; using namespace GpgME; using namespace KMime::Types; using namespace KMime::HeaderParsing; std::vector< std::vector > CertificateResolver::resolveRecipients( const std::vector & recipients, Protocol proto ) { std::vector< std::vector > result; std::transform( recipients.begin(), recipients.end(), std::back_inserter( result ), boost::bind( &resolveRecipient, _1, proto ) ); return result; } std::vector CertificateResolver::resolveRecipient( const Mailbox & recipient, Protocol proto ) { std::vector result = KeyCache::instance()->findByEMailAddress( recipient.address() ); std::vector::iterator end = std::remove_if( result.begin(), result.end(), !boost::bind( &Key::canEncrypt, _1 ) ); if ( proto != UnknownProtocol ) end = std::remove_if( result.begin(), end, boost::bind( &Key::protocol, _1 ) != proto ); result.erase( end, result.end() ); return result; } std::vector< std::vector > CertificateResolver::resolveSigners( const std::vector & signers, Protocol proto ) { std::vector< std::vector > result; std::transform( signers.begin(), signers.end(), std::back_inserter( result ), boost::bind( &resolveSigner, _1, proto ) ); return result; } std::vector CertificateResolver::resolveSigner( const Mailbox & signer, Protocol proto ) { std::vector result = KeyCache::instance()->findByEMailAddress( signer.address() ); std::vector::iterator end = std::remove_if( result.begin(), result.end(), !boost::bind( &Key::hasSecret, _1 ) ); end = std::remove_if( result.begin(), end, !boost::bind( &Key::canReallySign, _1 ) ); if ( proto != UnknownProtocol ) end = std::remove_if( result.begin(), end, boost::bind( &Key::protocol, _1 ) != proto ); result.erase( end, result.end() ); return result; } class KConfigBasedRecipientPreferences::Private { friend class ::Kleo::Crypto::KConfigBasedRecipientPreferences; KConfigBasedRecipientPreferences* const q; public: explicit Private( KSharedConfigPtr config, KConfigBasedRecipientPreferences* qq ); ~Private(); private: void ensurePrefsParsed() const; void writePrefs(); private: KSharedConfigPtr m_config; mutable QHash pgpPrefs; mutable QHash cmsPrefs; mutable bool m_parsed; mutable bool m_dirty; }; KConfigBasedRecipientPreferences::Private::Private( KSharedConfigPtr config , KConfigBasedRecipientPreferences* qq ) : q( qq ), m_config( config ), m_parsed( false ), m_dirty( false ) { assert( m_config ); } KConfigBasedRecipientPreferences::Private::~Private() { writePrefs(); } void KConfigBasedRecipientPreferences::Private::writePrefs() { if ( !m_dirty ) return; const QSet keys = pgpPrefs.keys().toSet() + cmsPrefs.keys().toSet(); int n = 0; Q_FOREACH ( const QByteArray& i, keys ) { KConfigGroup group( m_config, QString::fromLatin1( "EncryptionPreference_%1" ).arg( n++ ) ); group.writeEntry( "email", i ); const QByteArray pgp = pgpPrefs.value( i ); if ( !pgp.isEmpty() ) group.writeEntry( "pgpCertificate", pgp ); const QByteArray cms = cmsPrefs.value( i ); if ( !cms.isEmpty() ) group.writeEntry( "cmsCertificate", cms ); } m_config->sync(); m_dirty = false; } void KConfigBasedRecipientPreferences::Private::ensurePrefsParsed() const { if ( m_parsed ) return; const QStringList groups = m_config->groupList().filter( QRegExp( QLatin1String("^EncryptionPreference_\\d+$") ) ); Q_FOREACH ( const QString& i, groups ) { const KConfigGroup group( m_config, i ); const QByteArray id = group.readEntry( "email", QByteArray() ); if ( id.isEmpty() ) continue; pgpPrefs.insert( id, group.readEntry( "pgpCertificate", QByteArray() ) ); cmsPrefs.insert( id, group.readEntry( "cmsCertificate", QByteArray() ) ); } m_parsed = true; } KConfigBasedRecipientPreferences::KConfigBasedRecipientPreferences( KSharedConfigPtr config ) : d( new Private( config, this ) ) { } KConfigBasedRecipientPreferences::~KConfigBasedRecipientPreferences() { d->writePrefs(); } Key KConfigBasedRecipientPreferences::preferredCertificate( const Mailbox& recipient, Protocol protocol ) { d->ensurePrefsParsed(); const QByteArray keyId = ( protocol == CMS ? d->cmsPrefs : d->pgpPrefs ).value( recipient.address() ); return KeyCache::instance()->findByKeyIDOrFingerprint( keyId ); } void KConfigBasedRecipientPreferences::setPreferredCertificate( const Mailbox& recipient, Protocol protocol, const Key& certificate ) { d->ensurePrefsParsed(); if ( !recipient.hasAddress() ) return; ( protocol == CMS ? d->cmsPrefs : d->pgpPrefs ).insert( recipient.address(), certificate.keyID() ); d->m_dirty = true; } class KConfigBasedSigningPreferences::Private { friend class ::Kleo::Crypto::KConfigBasedSigningPreferences; KConfigBasedSigningPreferences* const q; public: explicit Private( KSharedConfigPtr config, KConfigBasedSigningPreferences* qq ); ~Private(); private: void ensurePrefsParsed() const; void writePrefs(); private: KSharedConfigPtr m_config; mutable QByteArray pgpSigningCertificate; mutable QByteArray cmsSigningCertificate; mutable bool m_parsed; mutable bool m_dirty; }; KConfigBasedSigningPreferences::Private::Private( KSharedConfigPtr config , KConfigBasedSigningPreferences* qq ) : q( qq ), m_config( config ), m_parsed( false ), m_dirty( false ) { assert( m_config ); } void KConfigBasedSigningPreferences::Private::ensurePrefsParsed() const { if ( m_parsed ) return; const KConfigGroup group( m_config, "SigningPreferences" ); pgpSigningCertificate = group.readEntry( "pgpSigningCertificate", QByteArray() ); cmsSigningCertificate = group.readEntry( "cmsSigningCertificate", QByteArray() ); m_parsed = true; } void KConfigBasedSigningPreferences::Private::writePrefs() { if ( !m_dirty ) return; KConfigGroup group( m_config, "SigningPreferences" ); group.writeEntry( "pgpSigningCertificate", pgpSigningCertificate ); group.writeEntry( "cmsSigningCertificate", cmsSigningCertificate ); m_config->sync(); m_dirty = false; } KConfigBasedSigningPreferences::Private::~Private() { writePrefs(); } KConfigBasedSigningPreferences::KConfigBasedSigningPreferences( KSharedConfigPtr config ) : d( new Private( config, this ) ) { } KConfigBasedSigningPreferences::~KConfigBasedSigningPreferences() { d->writePrefs(); } Key KConfigBasedSigningPreferences::preferredCertificate( Protocol protocol ) { d->ensurePrefsParsed(); const QByteArray keyId = ( protocol == CMS ? d->cmsSigningCertificate : d->pgpSigningCertificate ); const Key key = KeyCache::instance()->findByKeyIDOrFingerprint( keyId ); return key.hasSecret() ? key : Key::null; } void KConfigBasedSigningPreferences::setPreferredCertificate( Protocol protocol, const Key& certificate ) { d->ensurePrefsParsed(); ( protocol == CMS ? d->cmsSigningCertificate : d->pgpSigningCertificate ) = certificate.keyID(); d->m_dirty = true; } diff --git a/kleopatra/crypto/controller.h b/kleopatra/crypto/controller.h index 12fa73fb81..e7f8846e68 100644 --- a/kleopatra/crypto/controller.h +++ b/kleopatra/crypto/controller.h @@ -1,90 +1,92 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/controller.h This file is part of Kleopatra, the KDE keymanager Copyright (c) 2008 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #ifndef __KLEOPATRA_CRYPTO_CONTROLLER_H__ #define __KLEOPATRA_CRYPTO_CONTROLLER_H__ #include #include #include #include +#ifndef Q_MOC_RUN #include +#endif class QDialog; namespace Kleo { namespace Crypto { class Controller : public QObject, protected ExecutionContextUser { Q_OBJECT public: explicit Controller( QObject * parent=0 ); explicit Controller( const boost::shared_ptr & cmd, QObject * parent=0 ); ~Controller(); using ExecutionContextUser::setExecutionContext; Q_SIGNALS: void progress( int current, int total, const QString & what ); protected: void emitDoneOrError(); void setLastError( int err, const QString & details ); void connectTask( const boost::shared_ptr & task ); virtual void doTaskDone( const Task* task, const boost::shared_ptr & result ); protected Q_SLOTS: void taskDone( const boost::shared_ptr & ); Q_SIGNALS: #ifndef Q_MOC_RUN # ifndef DOXYGEN_SHOULD_SKIP_THIS private: // don't tell moc or doxygen, but those signals are in fact private # endif #endif void error( int err, const QString & details ); void done(); private: class Private; kdtools::pimpl_ptr d; }; } } #endif /* __KLEOPATRA_CRYPTO_CONTROLLER_H__ */ diff --git a/kleopatra/crypto/createchecksumscontroller.cpp b/kleopatra/crypto/createchecksumscontroller.cpp index 92c835642c..f68f0a1889 100644 --- a/kleopatra/crypto/createchecksumscontroller.cpp +++ b/kleopatra/crypto/createchecksumscontroller.cpp @@ -1,656 +1,658 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/createchecksumscontroller.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2010 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "createchecksumscontroller.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#ifndef Q_MOC_RUN #include #include +#endif #include #include #include #include using namespace Kleo; using namespace Kleo::Crypto; using namespace boost; namespace { class ResultDialog : public QDialog { Q_OBJECT public: ResultDialog( const QStringList & created, const QStringList & errors, QWidget * parent=0, Qt::WindowFlags f=0 ) : QDialog( parent, f ), createdLB( created.empty() ? i18nc("@info","No checksum files have been created.") : i18nc("@info","These checksum files have been successfully created:"), this ), createdLW( this ), errorsLB( errors.empty() ? i18nc("@info","There were no errors.") : i18nc("@info","The following errors were encountered:"), this ), errorsLW( this ), buttonBox( QDialogButtonBox::Ok, Qt::Horizontal, this ), vlay( this ) { KDAB_SET_OBJECT_NAME( createdLB ); KDAB_SET_OBJECT_NAME( createdLW ); KDAB_SET_OBJECT_NAME( errorsLB ); KDAB_SET_OBJECT_NAME( errorsLW ); KDAB_SET_OBJECT_NAME( buttonBox ); KDAB_SET_OBJECT_NAME( vlay ); createdLW.addItems( created ); QRect r; for( int i = 0; i < created.size(); ++i ) r = r.united( createdLW.visualRect( createdLW.model()->index( 0, i ) ) ); createdLW.setMinimumWidth( qMin( 1024, r.width() + 4 * createdLW.frameWidth() ) ); errorsLW.addItems( errors ); vlay.addWidget( &createdLB ); vlay.addWidget( &createdLW, 1 ); vlay.addWidget( &errorsLB ); vlay.addWidget( &errorsLW, 1 ); vlay.addWidget( &buttonBox ); if ( created.empty() ) createdLW.hide(); if ( errors.empty() ) errorsLW.hide(); connect( &buttonBox, SIGNAL(accepted()), this, SLOT(accept()) ); connect( &buttonBox, SIGNAL(rejected()), this, SLOT(reject()) ); } private: QLabel createdLB; QListWidget createdLW; QLabel errorsLB; QListWidget errorsLW; QDialogButtonBox buttonBox; QVBoxLayout vlay; }; } #ifdef Q_OS_UNIX static const bool HAVE_UNIX = true; #else static const bool HAVE_UNIX = false; #endif static const Qt::CaseSensitivity fs_cs = HAVE_UNIX ? Qt::CaseSensitive : Qt::CaseInsensitive ; // can we use QAbstractFileEngine::caseSensitive()? static QStringList fs_sort( QStringList l ) { int (*QString_compare)(const QString&,const QString&,Qt::CaseSensitivity) = &QString::compare; kdtools::sort( l, boost::bind( QString_compare, _1, _2, fs_cs ) < 0 ); return l; } static QStringList fs_intersect( QStringList l1, QStringList l2 ) { int (*QString_compare)(const QString&,const QString&,Qt::CaseSensitivity) = &QString::compare; fs_sort( l1 ); fs_sort( l2 ); QStringList result; std::set_intersection( l1.begin(), l1.end(), l2.begin(), l2.end(), std::back_inserter( result ), boost::bind( QString_compare, _1, _2, fs_cs ) < 0 ); return result; } static QList get_patterns( const std::vector< shared_ptr > & checksumDefinitions ) { QList result; Q_FOREACH( const shared_ptr & cd, checksumDefinitions ) if ( cd ) Q_FOREACH( const QString & pattern, cd->patterns() ) result.push_back( QRegExp( pattern, fs_cs ) ); return result; } namespace { struct matches_any : std::unary_function { const QList m_regexps; explicit matches_any( const QList & regexps ) : m_regexps( regexps ) {} bool operator()( const QString & s ) const { return kdtools::any( m_regexps, boost::bind( &QRegExp::exactMatch, _1, s ) ); } }; } class CreateChecksumsController::Private : public QThread { Q_OBJECT friend class ::Kleo::Crypto::CreateChecksumsController; CreateChecksumsController * const q; public: explicit Private( CreateChecksumsController * qq ); ~Private(); Q_SIGNALS: void progress( int, int, const QString & ); private: void slotOperationFinished() { #ifndef QT_NO_PROGRESSDIALOG if ( progressDialog ) { progressDialog->setValue( progressDialog->maximum() ); progressDialog->close(); } #endif // QT_NO_PROGRESSDIALOG ResultDialog * const dlg = new ResultDialog( created, errors ); q->bringToForeground( dlg ); if ( !errors.empty() ) q->setLastError( gpg_error( GPG_ERR_GENERAL ), errors.join( QLatin1String("\n") ) ); q->emitDoneOrError(); } void slotProgress( int current, int total, const QString & what ) { kDebug() << "progress: " << current << "/" << total << ": " << qPrintable( what ); #ifndef QT_NO_PROGRESSDIALOG if ( !progressDialog ) return; progressDialog->setMaximum( total ); progressDialog->setValue( current ); progressDialog->setLabelText( what ); #endif // QT_NO_PROGRESSDIALOG } private: /* reimp */ void run(); private: #ifndef QT_NO_PROGRESSDIALOG QPointer progressDialog; #endif mutable QMutex mutex; const std::vector< shared_ptr > checksumDefinitions; shared_ptr checksumDefinition; QStringList files; QStringList errors, created; bool allowAddition; volatile bool canceled; }; CreateChecksumsController::Private::Private( CreateChecksumsController * qq ) : q( qq ), #ifndef QT_NO_PROGRESSDIALOG progressDialog(), #endif mutex(), checksumDefinitions( ChecksumDefinition::getChecksumDefinitions() ), checksumDefinition( ChecksumDefinition::getDefaultChecksumDefinition( checksumDefinitions ) ), files(), errors(), created(), allowAddition( false ), canceled( false ) { connect( this, SIGNAL(progress(int,int,QString)), q, SLOT(slotProgress(int,int,QString)) ); connect( this, SIGNAL(progress(int,int,QString)), q, SIGNAL(progress(int,int,QString)) ); connect( this, SIGNAL(finished()), q, SLOT(slotOperationFinished()) ); } CreateChecksumsController::Private::~Private() { kDebug(); } CreateChecksumsController::CreateChecksumsController( QObject * p ) : Controller( p ), d( new Private( this ) ) { } CreateChecksumsController::CreateChecksumsController( const shared_ptr & ctx, QObject * p ) : Controller( ctx, p ), d( new Private( this ) ) { } CreateChecksumsController::~CreateChecksumsController() { kDebug(); } void CreateChecksumsController::setFiles( const QStringList & files ) { kleo_assert( !d->isRunning() ); kleo_assert( !files.empty() ); const QList patterns = get_patterns( d->checksumDefinitions ); if ( !kdtools::all( files, matches_any( patterns ) ) && !kdtools::none_of( files, matches_any( patterns ) ) ) throw Exception( gpg_error( GPG_ERR_INV_ARG ), i18n("Create Checksums: input files must be either all checksum files or all files to be checksummed, not a mixture of both.") ); const QMutexLocker locker( &d->mutex ); d->files = files; } void CreateChecksumsController::setAllowAddition( bool allow ) { kleo_assert( !d->isRunning() ); const QMutexLocker locker( &d->mutex ); d->allowAddition = allow; } bool CreateChecksumsController::allowAddition() const { const QMutexLocker locker( &d->mutex ); return d->allowAddition; } void CreateChecksumsController::start() { { const QMutexLocker locker( &d->mutex ); #ifndef QT_NO_PROGRESSDIALOG d->progressDialog = new QProgressDialog( i18n("Initializing..."), i18n("Cancel"), 0, 0 ); applyWindowID( d->progressDialog ); d->progressDialog->setAttribute( Qt::WA_DeleteOnClose ); d->progressDialog->setMinimumDuration( 1000 ); d->progressDialog->setWindowTitle( i18nc("@title:window","Create Checksum Progress") ); connect( d->progressDialog, SIGNAL(canceled()), this, SLOT(cancel()) ); #endif // QT_NO_PROGRESSDIALOG d->canceled = false; d->errors.clear(); d->created.clear(); } d->start(); } void CreateChecksumsController::cancel() { kDebug(); const QMutexLocker locker( &d->mutex ); d->canceled = true; } namespace { struct Dir { QDir dir; QString sumFile; QStringList inputFiles; quint64 totalSize; shared_ptr checksumDefinition; }; } static QStringList remove_checksum_files( QStringList l, const QList & rxs ) { QStringList::iterator end = l.end(); Q_FOREACH( const QRegExp & rx, rxs ) end = std::remove_if( l.begin(), end, boost::bind( &QRegExp::exactMatch, rx, _1 ) ); l.erase( end, l.end() ); return l; } namespace { struct File { QString name; QByteArray checksum; bool binary; }; } static QString decode( const QString & encoded ) { QString decoded; decoded.reserve( encoded.size() ); bool shift = false; Q_FOREACH( const QChar ch, encoded ) if ( shift ) { switch ( ch.toLatin1() ) { case '\\': decoded += QLatin1Char( '\\' ); break; case 'n': decoded += QLatin1Char( '\n' ); break; default: kDebug() << "invalid escape sequence" << '\\' << ch << "(interpreted as '" << ch << "')"; decoded += ch; break; } shift = false; } else { if ( ch == QLatin1Char( '\\' ) ) shift = true; else decoded += ch; } return decoded; } static std::vector parse_sum_file( const QString & fileName ) { std::vector files; QFile f( fileName ); if ( f.open( QIODevice::ReadOnly ) ) { QTextStream s( &f ); QRegExp rx( QLatin1String("(\\?)([a-f0-9A-F]+) ([ *])([^\n]+)\n*") ); while ( !s.atEnd() ) { const QString line = s.readLine(); if ( rx.exactMatch( line ) ) { assert( !rx.cap(4).endsWith( QLatin1Char('\n') ) ); const File file = { rx.cap( 1 ) == QLatin1String("\\") ? decode( rx.cap( 4 ) ) : rx.cap( 4 ), rx.cap( 2 ).toLatin1(), rx.cap( 3 ) == QLatin1String("*"), }; files.push_back( file ); } } } return files; } static quint64 aggregate_size( const QDir & dir, const QStringList & files ) { quint64 n = 0; Q_FOREACH( const QString & file, files ) n += QFileInfo( dir.absoluteFilePath( file ) ).size(); return n; } static shared_ptr filename2definition( const QString & fileName, const std::vector< shared_ptr > & checksumDefinitions ) { Q_FOREACH( const shared_ptr & cd, checksumDefinitions ) if ( cd ) Q_FOREACH( const QString & pattern, cd->patterns() ) if ( QRegExp( pattern, fs_cs ).exactMatch( fileName ) ) return cd; return shared_ptr(); } static std::vector find_dirs_by_sum_files( const QStringList & files, bool allowAddition, const function & progress, const std::vector< shared_ptr > & checksumDefinitions ) { const QList patterns = get_patterns( checksumDefinitions ); std::vector dirs; dirs.reserve( files.size() ); int i = 0; Q_FOREACH( const QString & file, files ) { const QFileInfo fi( file ); const QDir dir = fi.dir(); const QStringList entries = remove_checksum_files( dir.entryList( QDir::Files ), patterns ); QStringList inputFiles; if ( allowAddition ) { inputFiles = entries; } else { const std::vector parsed = parse_sum_file( fi.absoluteFilePath() ); const QStringList oldInputFiles = kdtools::transform( parsed, mem_fn( &File::name ) ); inputFiles = fs_intersect( oldInputFiles, entries ); } const Dir item = { dir, fi.fileName(), inputFiles, aggregate_size( dir, inputFiles ), filename2definition( fi.fileName(), checksumDefinitions ) }; dirs.push_back( item ); if ( !progress.empty() ) progress( ++i ); } return dirs; } namespace { struct less_dir : std::binary_function { bool operator()( const QDir & lhs, const QDir & rhs ) const { return QString::compare( lhs.absolutePath(), rhs.absolutePath(), fs_cs ) < 0 ; } }; } static std::vector find_dirs_by_input_files( const QStringList & files, const shared_ptr & checksumDefinition, bool allowAddition, const function & progress, const std::vector< shared_ptr > & checksumDefinitions ) { Q_UNUSED( allowAddition ); if ( !checksumDefinition ) return std::vector(); const QList patterns = get_patterns( checksumDefinitions ); std::map dirs2files; // Step 1: sort files by the dir they're contained in: std::deque inputs( files.begin(), files.end() ); int i = 0; while ( !inputs.empty() ) { const QString file = inputs.front(); inputs.pop_front(); const QFileInfo fi( file ); if ( fi.isDir() ) { QDir dir( file ); dirs2files[ dir ] = remove_checksum_files( dir.entryList( QDir::Files ), patterns ); kdtools::transform( dir.entryList( QDir::Dirs|QDir::NoDotAndDotDot ), std::inserter( inputs, inputs.begin() ), boost::bind( &QDir::absoluteFilePath, cref(dir), _1 ) ); } else { dirs2files[fi.dir()].push_back( file ); } if ( !progress.empty() ) progress( ++i ); } // Step 2: convert into vector: std::vector dirs; dirs.reserve( dirs2files.size() ); for ( std::map::const_iterator it = dirs2files.begin(), end = dirs2files.end() ; it != end ; ++it ) { const QStringList inputFiles = remove_checksum_files( it->second, patterns ); if ( inputFiles.empty() ) continue; const Dir dir = { it->first, checksumDefinition->outputFileName(), inputFiles, aggregate_size( it->first, inputFiles ), checksumDefinition }; dirs.push_back( dir ); if ( !progress.empty() ) progress( ++i ); } return dirs; } static QString process( const Dir & dir, bool * fatal ) { const QString absFilePath = dir.dir.absoluteFilePath( dir.sumFile ); KSaveFile file( absFilePath ); if ( !file.open() ) return i18n( "Failed to open file \"%1\" for reading and writing: %2", dir.dir.absoluteFilePath( file.fileName() ), file.errorString() ); QProcess p; p.setWorkingDirectory( dir.dir.absolutePath() ); p.setStandardOutputFile( dir.dir.absoluteFilePath( file.QFile::fileName() /*!sic*/ ) ); const QString program = dir.checksumDefinition->createCommand(); dir.checksumDefinition->startCreateCommand( &p, dir.inputFiles ); p.waitForFinished(); kDebug() << "[" << &p << "] Exit code " << p.exitCode(); if ( p.exitStatus() != QProcess::NormalExit || p.exitCode() != 0 ) { file.abort(); if ( fatal && p.error() == QProcess::FailedToStart ) *fatal = true; if ( p.error() == QProcess::UnknownError ) return i18n( "Error while running %1: %2", program, QString::fromLocal8Bit( p.readAllStandardError().trimmed().constData() ) ); else return i18n( "Failed to execute %1: %2", program, p.errorString() ); } if ( !file.finalize() ) return i18n( "Failed to move file %1 to its final destination, %2: %3", file.fileName(), dir.sumFile, file.errorString() ); return QString(); } namespace { static QDebug operator<<( QDebug s, const Dir & dir ) { return s << "Dir(" << dir.dir << "->" << dir.sumFile << "<-(" << dir.totalSize << ')' << dir.inputFiles << ")\n"; } } void CreateChecksumsController::Private::run() { QMutexLocker locker( &mutex ); const QStringList files = this->files; const std::vector< shared_ptr > checksumDefinitions = this->checksumDefinitions; const shared_ptr checksumDefinition = this->checksumDefinition; const bool allowAddition = this->allowAddition; locker.unlock(); QStringList errors; QStringList created; if ( !checksumDefinition ) { errors.push_back( i18n("No checksum programs defined.") ); locker.relock(); this->errors = errors; return; } else { kDebug() << "using checksum-definition" << checksumDefinition->id(); } // // Step 1: build a list of work to do (no progress): // const QString scanning = i18n("Scanning directories..."); emit progress( 0, 0, scanning ); const bool haveSumFiles = kdtools::all( files, matches_any( get_patterns( checksumDefinitions ) ) ); const function progressCb = boost::bind( &Private::progress, this, _1, 0, scanning ); const std::vector dirs = haveSumFiles ? find_dirs_by_sum_files( files, allowAddition, progressCb, checksumDefinitions ) : find_dirs_by_input_files( files, checksumDefinition, allowAddition, progressCb, checksumDefinitions ) ; Q_FOREACH( const Dir & dir, dirs ) kDebug() << dir; if ( !canceled ) { emit progress( 0, 0, i18n("Calculating total size...") ); const quint64 total = kdtools::accumulate_transform( dirs, mem_fn( &Dir::totalSize ), Q_UINT64_C(0) ); if ( !canceled ) { // // Step 2: perform work (with progress reporting): // // re-scale 'total' to fit into ints (wish QProgressDialog would use quint64...) const quint64 factor = total / std::numeric_limits::max() + 1 ; quint64 done = 0; Q_FOREACH( const Dir & dir, dirs ) { emit progress( done/factor, total/factor, i18n("Checksumming (%2) in %1", dir.checksumDefinition->label(), dir.dir.path() ) ); bool fatal = false; const QString error = process( dir, &fatal ); if ( !error.isEmpty() ) errors.push_back( error ); else created.push_back( dir.dir.absoluteFilePath( dir.sumFile ) ); done += dir.totalSize; if ( fatal || canceled ) break; } emit progress( done/factor, total/factor, i18n("Done.") ); } } locker.relock(); this->errors = errors; this->created = created; // mutex unlocked by QMutexLocker } #include "moc_createchecksumscontroller.cpp" #include "createchecksumscontroller.moc" diff --git a/kleopatra/crypto/createchecksumscontroller.h b/kleopatra/crypto/createchecksumscontroller.h index 77c2672e6a..8664ff2d02 100644 --- a/kleopatra/crypto/createchecksumscontroller.h +++ b/kleopatra/crypto/createchecksumscontroller.h @@ -1,78 +1,80 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/createchecksumscontroller.h This file is part of Kleopatra, the KDE keymanager Copyright (c) 2010 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #ifndef __KLEOPATRA_CRYPTO_CREATECHECKSUMSCONTROLLER_H__ #define __KLEOPATRA_CRYPTO_CREATECHECKSUMSCONTROLLER_H__ #include #include #include #include +#ifndef Q_MOC_RUN #include +#endif #include namespace Kleo { namespace Crypto { class CreateChecksumsController : public Controller { Q_OBJECT public: explicit CreateChecksumsController( QObject * parent=0 ); explicit CreateChecksumsController( const boost::shared_ptr & ctx, QObject * parent=0 ); ~CreateChecksumsController(); void setAllowAddition( bool allow ); bool allowAddition() const; void setFiles( const QStringList & files ); void start(); public Q_SLOTS: void cancel(); private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT( d, void slotOperationFinished() ) Q_PRIVATE_SLOT( d, void slotProgress(int,int,QString) ) }; } } #endif /* __KLEOPATRA_UISERVER_CREATECHECKSUMSCONTROLLER_H__ */ diff --git a/kleopatra/crypto/decryptverifyemailcontroller.cpp b/kleopatra/crypto/decryptverifyemailcontroller.cpp index 11366659a1..8aa2c806d0 100644 --- a/kleopatra/crypto/decryptverifyemailcontroller.cpp +++ b/kleopatra/crypto/decryptverifyemailcontroller.cpp @@ -1,489 +1,491 @@ /* -*- mode: c++; c-basic-offset:4 -*- decryptverifyemailcontroller.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2008 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "decryptverifyemailcontroller.h" #include "emailoperationspreferences.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#ifndef Q_MOC_RUN #include +#endif #include #include using namespace boost; using namespace GpgME; using namespace Kleo; using namespace Kleo::Crypto; using namespace Kleo::Crypto::Gui; using namespace KMime::Types; namespace { class DecryptVerifyEMailWizard : public QWizard { Q_OBJECT public: explicit DecryptVerifyEMailWizard( QWidget * parent=0, Qt::WindowFlags f=0 ) : QWizard( parent, f ), m_resultPage( this ) { KDAB_SET_OBJECT_NAME( m_resultPage ); m_resultPage.setSubTitle( i18n("Status and progress of the crypto operations is shown here.") ); // there's no way we're letting users fast-forward over the decryption/verification results... m_resultPage.setKeepOpenWhenDoneShown( false ); addPage( &m_resultPage ); } void addTaskCollection( const shared_ptr & coll ) { m_resultPage.addTaskCollection( coll ); } public Q_SLOTS: void accept() { EMailOperationsPreferences prefs; prefs.setDecryptVerifyPopupGeometry( geometry() ); prefs.writeConfig(); QWizard::accept(); } private: NewResultPage m_resultPage; }; } class DecryptVerifyEMailController::Private { DecryptVerifyEMailController* const q; public: explicit Private( DecryptVerifyEMailController* qq ); void slotWizardCanceled(); void schedule(); std::vector > buildTasks(); static DecryptVerifyEMailWizard * findOrCreateWizard( unsigned int id ); void ensureWizardCreated(); void ensureWizardVisible(); void reportError( int err, const QString & details ) { q->setLastError( err, details ); q->emitDoneOrError(); } void cancelAllTasks(); std::vector > m_inputs, m_signedDatas; std::vector > m_outputs; unsigned int m_sessionId; QPointer m_wizard; std::vector > m_results; std::vector > m_runnableTasks, m_completedTasks; shared_ptr m_runningTask; bool m_silent; bool m_operationCompleted; DecryptVerifyOperation m_operation; Protocol m_protocol; VerificationMode m_verificationMode; std::vector m_informativeSenders; }; DecryptVerifyEMailController::Private::Private( DecryptVerifyEMailController* qq ) : q( qq ), m_sessionId( 0 ), m_silent( false ), m_operationCompleted( false ), m_operation( DecryptVerify ), m_protocol( UnknownProtocol ), m_verificationMode( Detached ) { qRegisterMetaType(); } void DecryptVerifyEMailController::Private::slotWizardCanceled() { kDebug(); if ( !m_operationCompleted ) reportError( gpg_error( GPG_ERR_CANCELED ), i18n("User canceled") ); } void DecryptVerifyEMailController::doTaskDone( const Task* task, const shared_ptr & result ) { assert( task ); // We could just delete the tasks here, but we can't use // Qt::QueuedConnection here (we need sender()) and other slots // might not yet have executed. Therefore, we push completed tasks // into a burial container if ( task == d->m_runningTask.get() ) { d->m_completedTasks.push_back( d->m_runningTask ); const shared_ptr & dvr = boost::dynamic_pointer_cast( result ); assert( dvr ); d->m_results.push_back( dvr ); d->m_runningTask.reset(); } QTimer::singleShot( 0, this, SLOT(schedule()) ); } void DecryptVerifyEMailController::Private::schedule() { if ( !m_runningTask && !m_runnableTasks.empty() ) { const shared_ptr t = m_runnableTasks.back(); m_runnableTasks.pop_back(); t->start(); m_runningTask = t; } if ( !m_runningTask ) { kleo_assert( m_runnableTasks.empty() ); Q_FOREACH ( const shared_ptr & i, m_results ) emit q->verificationResult( i->verificationResult() ); // if there is a popup, wait for either the client cancel or the user closing the popup. // Otherwise (silent case), finish immediately m_operationCompleted = true; q->emitDoneOrError(); } } void DecryptVerifyEMailController::Private::ensureWizardCreated() { if ( m_wizard ) return; DecryptVerifyEMailWizard * w = findOrCreateWizard( m_sessionId ); connect( w, SIGNAL(destroyed()), q, SLOT(slotWizardCanceled()), Qt::QueuedConnection ); m_wizard = w; } namespace { template void collectGarbage( C & c ) { typename C::iterator it = c.begin(); while ( it != c.end() /*sic!*/ ) if ( it->second ) ++it; else c.erase( it++ /*sic!*/ ); } } // static DecryptVerifyEMailWizard * DecryptVerifyEMailController::Private::findOrCreateWizard( unsigned int id ) { static std::map > s_wizards; collectGarbage( s_wizards ); kDebug() << "id = " << id; if ( id != 0 ) { const std::map >::const_iterator it = s_wizards.find( id ); if ( it != s_wizards.end() ) { assert( it->second && "This should have been garbage-collected" ); return it->second; } } DecryptVerifyEMailWizard * w = new DecryptVerifyEMailWizard; w->setWindowTitle( i18n( "Decrypt/Verify E-Mail" ) ); w->setAttribute( Qt::WA_DeleteOnClose ); const QRect preferredGeometry = EMailOperationsPreferences().decryptVerifyPopupGeometry(); if ( preferredGeometry.isValid() ) w->setGeometry( preferredGeometry ); s_wizards[id] = w; return w; } std::vector< shared_ptr > DecryptVerifyEMailController::Private::buildTasks() { const uint numInputs = m_inputs.size(); const uint numMessages = m_signedDatas.size(); const uint numOutputs = m_outputs.size(); const uint numInformativeSenders = m_informativeSenders.size(); // these are duplicated from DecryptVerifyCommandEMailBase::Private::checkForErrors with slightly modified error codes/messages if ( !numInputs ) throw Kleo::Exception( makeGnuPGError( GPG_ERR_CONFLICT ), i18n("At least one input needs to be provided") ); if ( numInformativeSenders > 0 && numInformativeSenders != numInputs ) throw Kleo::Exception( makeGnuPGError( GPG_ERR_CONFLICT ), //TODO use better error code if possible i18n("Informative sender/signed data count mismatch") ); if ( numMessages ) { if ( numMessages != numInputs ) throw Kleo::Exception( makeGnuPGError( GPG_ERR_CONFLICT ), //TODO use better error code if possible i18n("Signature/signed data count mismatch") ); else if ( m_operation != Verify || m_verificationMode != Detached ) throw Kleo::Exception( makeGnuPGError( GPG_ERR_CONFLICT ), i18n("Signed data can only be given for detached signature verification") ); } if ( numOutputs ) { if ( numOutputs != numInputs ) throw Kleo::Exception( makeGnuPGError( GPG_ERR_CONFLICT ), //TODO use better error code if possible i18n("Input/Output count mismatch") ); else if ( numMessages ) throw Kleo::Exception( makeGnuPGError( GPG_ERR_CONFLICT ), i18n("Cannot use output and signed data simultaneously") ); } kleo_assert( m_protocol != UnknownProtocol ); const CryptoBackend::Protocol * const backend = CryptoBackendFactory::instance()->protocol( m_protocol ); if ( !backend ) throw Kleo::Exception( makeGnuPGError( GPG_ERR_UNSUPPORTED_PROTOCOL ), i18n("No backend support for %1", Formatting::displayName( m_protocol ) ) ); if ( m_operation != Decrypt && !m_silent ) ensureWizardVisible(); std::vector< shared_ptr > tasks; for ( unsigned int i = 0 ; i < numInputs ; ++i ) { shared_ptr task; switch ( m_operation ) { case Decrypt: { shared_ptr t( new DecryptTask ); t->setInput( m_inputs.at( i ) ); assert( numOutputs ); t->setOutput( m_outputs.at( i ) ); t->setProtocol( m_protocol ); task = t; } break; case Verify: { if ( m_verificationMode == Detached ) { shared_ptr t( new VerifyDetachedTask ); t->setInput( m_inputs.at( i ) ); t->setSignedData( m_signedDatas.at( i ) ); if ( numInformativeSenders > 0 ) t->setInformativeSender( m_informativeSenders.at( i ) ); t->setProtocol( m_protocol ); task = t; } else { shared_ptr t( new VerifyOpaqueTask ); t->setInput( m_inputs.at( i ) ); if ( numOutputs ) t->setOutput( m_outputs.at( i ) ); if ( numInformativeSenders > 0 ) t->setInformativeSender( m_informativeSenders.at( i ) ); t->setProtocol( m_protocol ); task = t; } } break; case DecryptVerify: { shared_ptr t( new DecryptVerifyTask ); t->setInput( m_inputs.at( i ) ); assert( numOutputs ); t->setOutput( m_outputs.at( i ) ); if ( numInformativeSenders > 0 ) t->setInformativeSender( m_informativeSenders.at( i ) ); t->setProtocol( m_protocol ); task = t; } } assert( task ); tasks.push_back( task ); } return tasks; } void DecryptVerifyEMailController::Private::ensureWizardVisible() { ensureWizardCreated(); q->bringToForeground( m_wizard ); } DecryptVerifyEMailController::DecryptVerifyEMailController( QObject* parent ) : Controller( parent ), d( new Private( this ) ) { } DecryptVerifyEMailController::DecryptVerifyEMailController( const shared_ptr & ctx, QObject* parent ) : Controller( ctx, parent ), d( new Private( this ) ) { } DecryptVerifyEMailController::~DecryptVerifyEMailController() { kDebug(); } void DecryptVerifyEMailController::start() { d->m_runnableTasks = d->buildTasks(); const shared_ptr coll( new TaskCollection ); std::vector > tsks; Q_FOREACH( const shared_ptr & i, d->m_runnableTasks ) { connectTask( i ); tsks.push_back( i ); } coll->setTasks( tsks ); d->ensureWizardCreated(); d->m_wizard->addTaskCollection( coll ); d->ensureWizardVisible(); QTimer::singleShot( 0, this, SLOT(schedule()) ); } void DecryptVerifyEMailController::setInput( const shared_ptr & input ) { d->m_inputs.resize( 1, input ); } void DecryptVerifyEMailController::setInputs( const std::vector > & inputs ) { d->m_inputs = inputs; } void DecryptVerifyEMailController::setSignedData( const shared_ptr & data ) { d->m_signedDatas.resize( 1, data ); } void DecryptVerifyEMailController::setSignedData( const std::vector > & data ) { d->m_signedDatas = data; } void DecryptVerifyEMailController::setOutput( const shared_ptr & output ) { d->m_outputs.resize( 1, output ); } void DecryptVerifyEMailController::setOutputs( const std::vector > & outputs ) { d->m_outputs = outputs; } void DecryptVerifyEMailController::setInformativeSenders( const std::vector & senders ) { d->m_informativeSenders = senders; } void DecryptVerifyEMailController::setWizardShown( bool shown ) { d->m_silent = !shown; if ( d->m_wizard ) d->m_wizard->setVisible( shown ); } void DecryptVerifyEMailController::setOperation( DecryptVerifyOperation operation ) { d->m_operation = operation; } void DecryptVerifyEMailController::setVerificationMode( VerificationMode vm ) { d->m_verificationMode = vm; } void DecryptVerifyEMailController::setProtocol( Protocol prot ) { d->m_protocol = prot; } void DecryptVerifyEMailController::setSessionId( unsigned int id ) { kDebug() << "id = " << id; d->m_sessionId = id; } void DecryptVerifyEMailController::cancel() { kDebug(); try { if ( d->m_wizard ) { disconnect( d->m_wizard ); d->m_wizard->close(); } d->cancelAllTasks(); } catch ( const std::exception & e ) { kDebug() << "Caught exception: " << e.what(); } } void DecryptVerifyEMailController::Private::cancelAllTasks() { // we just kill all runnable tasks - this will not result in // signal emissions. m_runnableTasks.clear(); // a cancel() will result in a call to if ( m_runningTask ) m_runningTask->cancel(); } #include "decryptverifyemailcontroller.moc" #include "moc_decryptverifyemailcontroller.cpp" diff --git a/kleopatra/crypto/decryptverifyemailcontroller.h b/kleopatra/crypto/decryptverifyemailcontroller.h index 747188cb16..6eee3bb7f6 100644 --- a/kleopatra/crypto/decryptverifyemailcontroller.h +++ b/kleopatra/crypto/decryptverifyemailcontroller.h @@ -1,118 +1,120 @@ /* -*- mode: c++; c-basic-offset:4 -*- decryptverifyemailcontroller.h This file is part of Kleopatra, the KDE keymanager Copyright (c) 2008 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #ifndef __KLEOPATRA_CRYPTO_DECRYPTVERIFYEMAILCONTROLLER_H__ #define __KLEOPATRA_CRYPTO_DECRYPTVERIFYEMAILCONTROLLER_H__ #include #include #include #include +#ifndef Q_MOC_RUN #include +#endif #include class QFile; namespace KMime { namespace Types { class Mailbox; } } namespace GpgME { class VerificationResult; } namespace Kleo { class AssuanCommand; class Input; class Output; namespace Crypto { class DecryptVerifyResult; class DecryptVerifyEMailController : public Controller { Q_OBJECT public: explicit DecryptVerifyEMailController( QObject * parent=0 ); explicit DecryptVerifyEMailController( const boost::shared_ptr & cmd, QObject * parent=0 ); ~DecryptVerifyEMailController(); void setInput( const boost::shared_ptr & input ); void setInputs( const std::vector > & inputs ); void setSignedData( const boost::shared_ptr & data ); void setSignedData( const std::vector > & data ); void setOutput( const boost::shared_ptr & output ); void setOutputs( const std::vector > & outputs ); void setInformativeSenders( const std::vector & senders ); void setWizardShown( bool shown ); void setOperation( DecryptVerifyOperation operation ); void setVerificationMode( VerificationMode vm ); void setProtocol( GpgME::Protocol protocol ); void setSessionId( unsigned int id ); void start(); public Q_SLOTS: void cancel(); Q_SIGNALS: void verificationResult( const GpgME::VerificationResult & ); private: /* reimp */ void doTaskDone( const Task* task, const boost::shared_ptr & result ); class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT( d, void slotWizardCanceled() ) Q_PRIVATE_SLOT( d, void schedule() ) }; } //namespace Crypto } //namespace Kleo Q_DECLARE_METATYPE( GpgME::VerificationResult ) #endif // __KLEOPATRA_CTYPTO_DECRYPTVERIFYEMAILCONTROLLER_H__ diff --git a/kleopatra/crypto/decryptverifyfilescontroller.cpp b/kleopatra/crypto/decryptverifyfilescontroller.cpp index f6cd0cbb1a..5b99b15686 100644 --- a/kleopatra/crypto/decryptverifyfilescontroller.cpp +++ b/kleopatra/crypto/decryptverifyfilescontroller.cpp @@ -1,472 +1,474 @@ /* -*- mode: c++; c-basic-offset:4 -*- decryptverifyfilescontroller.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2008 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "decryptverifyfilescontroller.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#ifndef Q_MOC_RUN #include +#endif #include #include using namespace boost; using namespace GpgME; using namespace Kleo; using namespace Kleo::Crypto; using namespace Kleo::Crypto::Gui; class DecryptVerifyFilesController::Private { DecryptVerifyFilesController* const q; public: static shared_ptr taskFromOperationWidget( const DecryptVerifyOperationWidget * w, const QString & fileName, const QDir & outDir, const shared_ptr & overwritePolicy ); explicit Private( DecryptVerifyFilesController* qq ); void slotWizardOperationPrepared(); void slotWizardCanceled(); void schedule(); QStringList prepareWizardFromPassedFiles(); std::vector > buildTasks( const QStringList &, const shared_ptr & ); void ensureWizardCreated(); void ensureWizardVisible(); void reportError( int err, const QString & details ) { q->setLastError( err, details ); q->emitDoneOrError(); } void cancelAllTasks(); QStringList m_passedFiles, m_filesAfterPreparation; QPointer m_wizard; std::vector > m_results; std::vector > m_runnableTasks, m_completedTasks; shared_ptr m_runningTask; bool m_errorDetected; DecryptVerifyOperation m_operation; }; // static shared_ptr DecryptVerifyFilesController::Private::taskFromOperationWidget( const DecryptVerifyOperationWidget * w, const QString & fileName, const QDir & outDir, const shared_ptr & overwritePolicy ) { kleo_assert( w ); shared_ptr task; switch ( w->mode() ) { case DecryptVerifyOperationWidget::VerifyDetachedWithSignature: { shared_ptr t( new VerifyDetachedTask ); t->setInput( Input::createFromFile( fileName ) ); t->setSignedData( Input::createFromFile( w->signedDataFileName() ) ); task = t; kleo_assert( fileName == w->inputFileName() ); } break; case DecryptVerifyOperationWidget::VerifyDetachedWithSignedData: { shared_ptr t( new VerifyDetachedTask ); t->setInput( Input::createFromFile( w->inputFileName() ) ); t->setSignedData( Input::createFromFile( fileName ) ); task = t; kleo_assert( fileName == w->signedDataFileName() ); } break; case DecryptVerifyOperationWidget::DecryptVerifyOpaque: { const unsigned int classification = classify( fileName ); kDebug() << "classified" << fileName << "as" << printableClassification( classification ); const shared_ptr ad = w->selectedArchiveDefinition(); const Protocol proto = isOpenPGP( classification ) ? OpenPGP : isCMS( classification ) ? CMS : ad /* _needs_ the info */ ? throw Exception( gpg_error( GPG_ERR_CONFLICT ), i18n("Cannot determine whether input data is OpenPGP or CMS") ) : /* else we don't care */ UnknownProtocol ; const shared_ptr input = Input::createFromFile( fileName ); const shared_ptr output = ad ? ad->createOutputFromUnpackCommand( proto, fileName, outDir ) : /*else*/ Output::createFromFile( outDir.absoluteFilePath( outputFileName( QFileInfo( fileName ).fileName() ) ), overwritePolicy ); if ( mayBeCipherText( classification ) ) { kDebug() << "creating a DecryptVerifyTask"; shared_ptr t( new DecryptVerifyTask ); t->setInput( input ); t->setOutput( output ); task = t; } else { kDebug() << "creating a VerifyOpaqueTask"; shared_ptr t( new VerifyOpaqueTask ); t->setInput( input ); t->setOutput( output ); task = t; } kleo_assert( fileName == w->inputFileName() ); } break; } task->autodetectProtocolFromInput(); return task; } DecryptVerifyFilesController::Private::Private( DecryptVerifyFilesController* qq ) : q( qq ), m_errorDetected( false ), m_operation( DecryptVerify ) { qRegisterMetaType(); } void DecryptVerifyFilesController::Private::slotWizardOperationPrepared() { try { ensureWizardCreated(); std::vector > tasks = buildTasks( m_filesAfterPreparation, shared_ptr( new OverwritePolicy( m_wizard ) ) ); kleo_assert( m_runnableTasks.empty() ); m_runnableTasks.swap( tasks ); shared_ptr coll( new TaskCollection ); Q_FOREACH( const shared_ptr & i, m_runnableTasks ) q->connectTask( i ); coll->setTasks( m_runnableTasks ); m_wizard->setTaskCollection( coll ); QTimer::singleShot( 0, q, SLOT(schedule()) ); } catch ( const Kleo::Exception & e ) { reportError( e.error().encodedError(), e.message() ); } catch ( const std::exception & e ) { reportError( gpg_error( GPG_ERR_UNEXPECTED ), i18n("Caught unexpected exception in DecryptVerifyFilesController::Private::slotWizardOperationPrepared: %1", QString::fromLocal8Bit( e.what() ) ) ); } catch ( ... ) { reportError( gpg_error( GPG_ERR_UNEXPECTED ), i18n("Caught unknown exception in DecryptVerifyFilesController::Private::slotWizardOperationPrepared") ); } } void DecryptVerifyFilesController::Private::slotWizardCanceled() { kDebug(); reportError( gpg_error( GPG_ERR_CANCELED ), i18n("User canceled") ); } void DecryptVerifyFilesController::doTaskDone( const Task* task, const shared_ptr & result ) { assert( task ); assert( task == d->m_runningTask.get() ); Q_UNUSED( task ); // We could just delete the tasks here, but we can't use // Qt::QueuedConnection here (we need sender()) and other slots // might not yet have executed. Therefore, we push completed tasks // into a burial container d->m_completedTasks.push_back( d->m_runningTask ); d->m_runningTask.reset(); if ( const shared_ptr & dvr = boost::dynamic_pointer_cast( result ) ) d->m_results.push_back( dvr ); QTimer::singleShot( 0, this, SLOT(schedule()) ); } void DecryptVerifyFilesController::Private::schedule() { if ( !m_runningTask && !m_runnableTasks.empty() ) { const shared_ptr t = m_runnableTasks.back(); m_runnableTasks.pop_back(); t->start(); m_runningTask = t; } if ( !m_runningTask ) { kleo_assert( m_runnableTasks.empty() ); Q_FOREACH ( const shared_ptr & i, m_results ) emit q->verificationResult( i->verificationResult() ); q->emitDoneOrError(); } } void DecryptVerifyFilesController::Private::ensureWizardCreated() { if ( m_wizard ) return; std::auto_ptr w( new DecryptVerifyFilesWizard ); w->setWindowTitle( i18n( "Decrypt/Verify Files" ) ); w->setAttribute( Qt::WA_DeleteOnClose ); connect( w.get(), SIGNAL(operationPrepared()), q, SLOT(slotWizardOperationPrepared()), Qt::QueuedConnection ); connect( w.get(), SIGNAL(canceled()), q, SLOT(slotWizardCanceled()), Qt::QueuedConnection ); m_wizard = w.release(); } namespace { struct FindExtension : std::unary_function,bool> { const QString ext; const Protocol proto; FindExtension( const QString & ext, Protocol proto ) : ext( ext ), proto( proto ) {} bool operator()( const shared_ptr & ad ) const { kDebug() << " considering" << ( ad ? ad->label() : QLatin1String( "" ) ) << "for" << ext; bool result; if ( proto == UnknownProtocol ) result = ad && ( ad->extensions( OpenPGP ).contains( ext, Qt::CaseInsensitive ) || ad->extensions( CMS ).contains( ext, Qt::CaseInsensitive ) ); else result = ad && ad->extensions( proto ).contains( ext, Qt::CaseInsensitive ); kDebug() << ( result ? " -> matches" : " -> doesn't match" ); return result; } }; } shared_ptr pick_archive_definition( GpgME::Protocol proto, const std::vector< shared_ptr > & ads, const QString & filename ) { const QFileInfo fi( outputFileName( filename ) ); QString extension = fi.completeSuffix(); if ( extension == QLatin1String("out") ) // added by outputFileName() -> useless return shared_ptr(); if ( extension.endsWith( QLatin1String( ".out" ) ) ) // added by outputFileName() -> remove extension.chop(4); for ( ;; ) { const std::vector >::const_iterator it = std::find_if( ads.begin(), ads.end(), FindExtension( extension, proto ) ); if ( it != ads.end() ) return *it; const int idx = extension.indexOf( QLatin1Char('.') ); if ( idx < 0 ) return shared_ptr(); extension = extension.mid( idx + 1 ); } } QStringList DecryptVerifyFilesController::Private::prepareWizardFromPassedFiles() { ensureWizardCreated(); const std::vector< shared_ptr > archiveDefinitions = ArchiveDefinition::getArchiveDefinitions(); QStringList fileNames; unsigned int counter = 0; Q_FOREACH( const QString & fname, m_passedFiles ) { kleo_assert( !fname.isEmpty() ); const unsigned int classification = classify( fname ); const Protocol proto = findProtocol( classification ); if ( mayBeOpaqueSignature( classification ) || mayBeCipherText( classification ) || mayBeDetachedSignature( classification ) ) { DecryptVerifyOperationWidget * const op = m_wizard->operationWidget( counter++ ); kleo_assert( op != 0 ); op->setArchiveDefinitions( archiveDefinitions ); const QString signedDataFileName = findSignedData( fname ); // this breaks opaque signatures whose source files still // happen to exist in the same directory. Until we have // content-based classification, this is the most unlikely // case, so that's the case we break. ### FIXME remove when content-classify is done if ( mayBeDetachedSignature( classification ) && !signedDataFileName.isEmpty() ) op->setMode( DecryptVerifyOperationWidget::VerifyDetachedWithSignature ); // ### end FIXME else if ( mayBeOpaqueSignature( classification ) || mayBeCipherText( classification ) ) op->setMode( DecryptVerifyOperationWidget::DecryptVerifyOpaque, pick_archive_definition( proto, archiveDefinitions, fname ) ); else op->setMode( DecryptVerifyOperationWidget::VerifyDetachedWithSignature ); op->setInputFileName( fname ); op->setSignedDataFileName( signedDataFileName ); fileNames.push_back( fname ); } else { // probably the signed data file was selected: const QStringList signatures = findSignatures( fname ); if ( signatures.empty() ) { // We are assuming this is a detached signature file, but // there were no signature files for it. Let's guess it's encrypted after all. // ### FIXME once we have a proper heuristic for this, this should move into // classify() and/or classifyContent() DecryptVerifyOperationWidget * const op = m_wizard->operationWidget( counter++ ); kleo_assert( op != 0 ); op->setArchiveDefinitions( archiveDefinitions ); op->setMode( DecryptVerifyOperationWidget::DecryptVerifyOpaque, pick_archive_definition( proto, archiveDefinitions, fname ) ); op->setInputFileName( fname ); fileNames.push_back( fname ); } else { Q_FOREACH( const QString & s, signatures ) { DecryptVerifyOperationWidget * op = m_wizard->operationWidget( counter++ ); kleo_assert( op != 0 ); op->setArchiveDefinitions( archiveDefinitions ); op->setMode( DecryptVerifyOperationWidget::VerifyDetachedWithSignedData ); op->setInputFileName( s ); op->setSignedDataFileName( fname ); fileNames.push_back( fname ); } } } } kleo_assert( counter == static_cast( fileNames.size() ) ); if ( !counter ) throw Kleo::Exception( makeGnuPGError( GPG_ERR_ASS_NO_INPUT ), i18n("No usable inputs found") ); m_wizard->setOutputDirectory( heuristicBaseDirectory( m_passedFiles ) ); return fileNames; } std::vector< shared_ptr > DecryptVerifyFilesController::Private::buildTasks( const QStringList & fileNames, const shared_ptr & overwritePolicy ) { const bool useOutDir = m_wizard->useOutputDirectory(); const QFileInfo outDirInfo( m_wizard->outputDirectory() ); kleo_assert( !useOutDir || outDirInfo.isDir() ); const QDir outDir( outDirInfo.absoluteFilePath() ); kleo_assert( !useOutDir || outDir.exists() ); std::vector > tasks; for ( unsigned int i = 0, end = fileNames.size() ; i != end ; ++i ) try { const QDir fileDir = QFileInfo( fileNames[i] ).absoluteDir(); kleo_assert( fileDir.exists() ); tasks.push_back( taskFromOperationWidget( m_wizard->operationWidget( i ), fileNames[i], useOutDir ? outDir : fileDir, overwritePolicy ) ); } catch ( const GpgME::Exception & e ) { tasks.push_back( Task::makeErrorTask( e.error().code(), QString::fromLocal8Bit( e.what() ), fileNames[i] ) ); } return tasks; } void DecryptVerifyFilesController::setFiles( const QStringList & files ) { d->m_passedFiles = files; } void DecryptVerifyFilesController::Private::ensureWizardVisible() { ensureWizardCreated(); q->bringToForeground( m_wizard ); } DecryptVerifyFilesController::DecryptVerifyFilesController( QObject* parent ) : Controller( parent ), d( new Private( this ) ) { } DecryptVerifyFilesController::DecryptVerifyFilesController( const shared_ptr & ctx, QObject* parent ) : Controller( ctx, parent ), d( new Private( this ) ) { } DecryptVerifyFilesController::~DecryptVerifyFilesController() { kDebug(); } void DecryptVerifyFilesController::start() { d->m_filesAfterPreparation = d->prepareWizardFromPassedFiles(); d->ensureWizardVisible(); } void DecryptVerifyFilesController::setOperation( DecryptVerifyOperation op ) { d->m_operation = op; } DecryptVerifyOperation DecryptVerifyFilesController::operation() const { return d->m_operation; } void DecryptVerifyFilesController::Private::cancelAllTasks() { // we just kill all runnable tasks - this will not result in // signal emissions. m_runnableTasks.clear(); // a cancel() will result in a call to if ( m_runningTask ) m_runningTask->cancel(); } void DecryptVerifyFilesController::cancel() { kDebug(); try { d->m_errorDetected = true; if ( d->m_wizard ) d->m_wizard->close(); d->cancelAllTasks(); } catch ( const std::exception & e ) { kDebug() << "Caught exception: " << e.what(); } } #include "moc_decryptverifyfilescontroller.cpp" diff --git a/kleopatra/crypto/decryptverifytask.cpp b/kleopatra/crypto/decryptverifytask.cpp index a6e4ea12a5..400bc943a8 100644 --- a/kleopatra/crypto/decryptverifytask.cpp +++ b/kleopatra/crypto/decryptverifytask.cpp @@ -1,1352 +1,1354 @@ /* -*- mode: c++; c-basic-offset:4 -*- decryptverifytask.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2008 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "decryptverifytask.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Qt::escape +#ifndef Q_MOC_RUN #include +#endif #include #include #include using namespace Kleo::Crypto; using namespace Kleo; using namespace GpgME; using namespace boost; using namespace KMime::Types; namespace { static Error make_error( const gpg_err_code_t code ) { return Error( gpg_error( code ) ); } static AuditLog auditLogFromSender( QObject* sender ) { return AuditLog::fromJob( qobject_cast( sender ) ); } static bool addrspec_equal( const AddrSpec & lhs, const AddrSpec & rhs, Qt::CaseSensitivity cs ) { return lhs.localPart.compare( rhs.localPart, cs ) == 0 && lhs.domain.compare( rhs.domain, Qt::CaseInsensitive ) == 0; } static bool mailbox_equal( const Mailbox & lhs, const Mailbox & rhs, Qt::CaseSensitivity cs ) { return addrspec_equal( lhs.addrSpec(), rhs.addrSpec(), cs ); } static std::string stripAngleBrackets( const std::string & str ) { if ( str.empty() ) return str; if ( str[0] == '<' && str[str.size()-1] == '>' ) return str.substr( 1, str.size() - 2 ); return str; } static std::string email( const UserID & uid ) { if ( uid.parent().protocol() == OpenPGP ) if ( const char * const email = uid.email() ) return stripAngleBrackets( email ); else return std::string(); assert( uid.parent().protocol() == CMS ); if ( const char * const id = uid.id() ) if ( *id == '<' ) return stripAngleBrackets( id ); else return DN( id )[QLatin1String("EMAIL")].trimmed().toUtf8().constData(); else return std::string(); } static Mailbox mailbox( const UserID & uid ) { const std::string e = email( uid ); Mailbox mbox; if ( !e.empty() ) mbox.setAddress( e.c_str() ); return mbox; } static std::vector extractMailboxes( const Key & key ) { std::vector res; Q_FOREACH( const UserID & id, key.userIDs() ) { const Mailbox mbox = mailbox( id ); if ( !mbox.addrSpec().isEmpty() ) res.push_back( mbox ); } return res; } static std::vector extractMailboxes( const std::vector & signers ) { std::vector res; Q_FOREACH( const Key & i, signers ) { const std::vector bxs = extractMailboxes( i ); res.insert( res.end(), bxs.begin(), bxs.end() ); } return res; } static bool keyContainsMailbox( const Key & key, const Mailbox & mbox ) { const std::vector mbxs = extractMailboxes( key ); return std::find_if( mbxs.begin(), mbxs.end(), boost::bind( mailbox_equal, mbox, _1, Qt::CaseInsensitive ) ) != mbxs.end(); } static bool keysContainMailbox( const std::vector & keys, const Mailbox & mbox ) { return std::find_if( keys.begin(), keys.end(), boost::bind( keyContainsMailbox, _1, mbox ) ) != keys.end(); } static bool relevantInDecryptVerifyContext( const VerificationResult & r ) { // for D/V operations, we ignore verification results which are not errors and contain // no signatures (which means that the data was just not signed) return r.error() || r.numSignatures() > 0; } static QString signatureSummaryToString( int summary ) { if ( summary & Signature::None ) return i18n( "Error: Signature not verified" ); else if ( summary & Signature::Valid || summary & Signature::Green ) return i18n( "Good signature" ); else if ( summary & Signature::Red ) return i18n( "Bad signature" ); else if ( summary & Signature::KeyRevoked ) return i18n( "Signing certificate revoked" ); else if ( summary & Signature::KeyExpired ) return i18n( "Signing certificate expired" ); else if ( summary & Signature::KeyMissing ) return i18n( "No public certificate to verify the signature" ); else if ( summary & Signature::SigExpired ) return i18n( "Signature expired" ); else if ( summary & Signature::KeyMissing ) return i18n( "Certificate missing" ); else if ( summary & Signature::CrlMissing ) return i18n( "CRL missing" ); else if ( summary & Signature::CrlTooOld ) return i18n( "CRL too old" ); else if ( summary & Signature::BadPolicy ) return i18n( "Bad policy" ); else if ( summary & Signature::SysError ) return i18n( "System error" ); //### retrieve system error details? return QString(); } static QString formatValidSignatureWithTrustLevel( const UserID & id ) { if ( id.isNull() ) return QString(); switch ( id.validity() ) { case UserID::Marginal: return i18n( "The signature is valid but the trust in the certificate's validity is only marginal." ); case UserID::Full: return i18n( "The signature is valid and the certificate's validity is fully trusted." ); case UserID::Ultimate: return i18n( "The signature is valid and the certificate's validity is ultimately trusted." ); case UserID::Never: return i18n( "The signature is valid but the certificate's validity is not trusted." ); case UserID::Unknown: return i18n( "The signature is valid but the certificate's validity is unknown." ); case UserID::Undefined: default: return i18n( "The signature is valid but the certificate's validity is undefined." ); } } static QString renderFingerprint( const char * fpr ) { if ( !fpr ) return QString(); return QString::fromLatin1( "0x%1" ).arg( QString::fromLatin1( fpr ).toUpper() ); } static QString renderKeyLink( const QString & fpr, const QString & text ) { return QString::fromLatin1( "%2" ).arg( fpr, text ); } static QString renderKey( const Key & key ) { if ( key.isNull() ) return i18n( "Unknown certificate" ); return renderKeyLink( QLatin1String(key.primaryFingerprint()), Formatting::prettyName( key ) ); } static QString renderKeyEMailOnlyNameAsFallback( const Key & key ) { if ( key.isNull() ) return i18n( "Unknown certificate" ); const QString email = Formatting::prettyEMail( key ); const QString user = !email.isEmpty() ? email : Formatting::prettyName( key ); return renderKeyLink( QLatin1String(key.primaryFingerprint()), user ); } static QString formatDate( const QDateTime & dt ) { return KGlobal::locale()->formatDateTime( dt ); } static QString formatSigningInformation( const Signature & sig, const Key & key ) { if ( sig.isNull() ) return QString(); const QDateTime dt = sig.creationTime() != 0 ? QDateTime::fromTime_t( sig.creationTime() ) : QDateTime(); const QString signer = key.isNull() ? QString() : renderKeyEMailOnlyNameAsFallback( key ); const bool haveKey = !key.isNull(); const bool haveSigner = !signer.isEmpty(); const bool haveDate = dt.isValid(); if ( !haveKey ) { if ( haveDate ) return i18n( "Signed on %1 with unknown certificate %2.", formatDate( dt ), renderFingerprint( sig.fingerprint() ) ); else return i18n( "Signed with unknown certificate %1.", renderFingerprint( sig.fingerprint() ) ); } if ( haveSigner ) { if ( haveDate ) return i18nc( "date, key owner, key ID", "Signed on %1 by %2 (Key ID: %3).", formatDate( dt ), signer, renderFingerprint( key.shortKeyID() ) ); else return i18n( "Signed by %1 with certificate %2.", signer, renderKey( key ) ); } if ( haveDate ) return i18n( "Signed on %1 with certificate %2.", formatDate( dt ), renderKey( key ) ); return i18n( "Signed with certificate %1.", renderKey( key ) ); } static QString strikeOut( const QString & str, bool strike ) { return QString( strike ? QLatin1String("%1") : QLatin1String("%1") ).arg( Qt::escape( str ) ); } static QString formatInputOutputLabel( const QString & input, const QString & output, bool inputDeleted, bool outputDeleted ) { if ( output.isEmpty() ) return strikeOut( input, inputDeleted ); return i18nc( "Input file --> Output file (rarr is arrow", "%1 → %2", strikeOut( input, inputDeleted ), strikeOut( output, outputDeleted ) ); } static bool IsErrorOrCanceled( const GpgME::Error & err ) { return err || err.isCanceled(); } static bool IsErrorOrCanceled( const Result & res ) { return IsErrorOrCanceled( res.error() ); } static bool IsBad( const Signature & sig ) { return sig.summary() & Signature::Red; } static bool IsGoodOrValid( const Signature & sig ) { return (sig.summary() & Signature::Valid) || (sig.summary() & Signature::Green); } static UserID findUserIDByMailbox( const Key & key, const Mailbox & mbox ) { Q_FOREACH( const UserID & id, key.userIDs() ) if ( mailbox_equal( mailbox( id ), mbox, Qt::CaseInsensitive ) ) return id; return UserID(); } } class DecryptVerifyResult::SenderInfo { public: explicit SenderInfo( const Mailbox & infSender, const std::vector & signers_ ) : informativeSender( infSender ), signers( signers_ ) {} const Mailbox informativeSender; const std::vector signers; bool hasInformativeSender() const { return !informativeSender.addrSpec().isEmpty(); } bool conflicts() const { return hasInformativeSender() && hasKeys() && !keysContainMailbox( signers, informativeSender ); } bool hasKeys() const { return kdtools::any( signers, !boost::bind( &Key::isNull, _1 ) ); } std::vector signerMailboxes() const {return extractMailboxes( signers ); } }; namespace { static Task::Result::VisualCode codeForVerificationResult( const VerificationResult & res ) { if ( res.isNull() ) return Task::Result::NeutralSuccess; const std::vector sigs = res.signatures(); if ( sigs.empty() ) return Task::Result::Warning; if ( std::find_if( sigs.begin(), sigs.end(), IsBad ) != sigs.end() ) return Task::Result::Danger; if ( std::count_if( sigs.begin(), sigs.end(), IsGoodOrValid ) == sigs.size() ) return Task::Result::AllGood; return Task::Result::Warning; } static QString formatVerificationResultOverview( const VerificationResult & res, const DecryptVerifyResult::SenderInfo & info ) { if ( res.isNull() ) return QString(); const Error err = res.error(); if ( err.isCanceled() ) return i18n("Verification canceled."); else if ( err ) return i18n( "Verification failed: %1.", Qt::escape( QString::fromLocal8Bit( err.asString() ) ) ); const std::vector sigs = res.signatures(); const std::vector signers = info.signers; if ( sigs.empty() ) return i18n( "No signatures found." ); const uint bad = std::count_if( sigs.begin(), sigs.end(), IsBad ); if ( bad > 0 ) { return i18np("Invalid signature.", "%1 invalid signatures.", bad ); } const uint warn = std::count_if( sigs.begin(), sigs.end(), !boost::bind( IsGoodOrValid, _1 ) ); if ( warn > 0 ) return i18np("Not enough information to check signature validity.", "%1 signatures could not be verified.", warn ); //Good signature: QString text; if ( sigs.size() == 1 ) { const Key key = DecryptVerifyResult::keyForSignature( sigs[0], signers ); if ( key.isNull() ) return i18n( "Signature is valid." ); text = i18n( "Signed by %1", renderKeyEMailOnlyNameAsFallback( key ) ); if ( info.conflicts() ) text += i18n( "
Warning: The sender's mail address is not stored in the %1 used for signing.", renderKeyLink( QLatin1String(key.primaryFingerprint()), i18n( "certificate" ) ) ); } else { text = i18np("Valid signature.", "%1 valid signatures.", sigs.size() ); if ( info.conflicts() ) text += i18n( "
Warning: The sender's mail address is not stored in the certificates used for signing." ); } return text; } static QString formatDecryptionResultOverview( const DecryptionResult & result, const QString& errorString = QString() ) { const Error err = result.error(); if ( err.isCanceled() ) return i18n("Decryption canceled."); else if ( !errorString.isEmpty() ) return i18n( "Decryption failed: %1.", Qt::escape( errorString ) ); else if ( err ) return i18n( "Decryption failed: %1.", Qt::escape( QString::fromLocal8Bit( err.asString() ) ) ); return i18n("Decryption succeeded." ); } static QString formatSignature( const Signature & sig, const Key & key, const DecryptVerifyResult::SenderInfo & info ) { if ( sig.isNull() ) return QString(); const QString text = formatSigningInformation( sig, key ) + QLatin1String("
"); const bool red = sig.summary() & Signature::Red; if ( sig.summary() & Signature::Valid ) { const UserID id = findUserIDByMailbox( key, info.informativeSender ); return text + formatValidSignatureWithTrustLevel( !id.isNull() ? id : key.userID( 0 ) ); } if ( red ) return text + i18n("The signature is bad."); if ( !sig.summary() ) return text + i18n("The validity of the signature cannot be verified."); return text + i18n("The signature is invalid: %1", signatureSummaryToString( sig.summary() ) ); } static QStringList format( const std::vector & mbxs ) { QStringList res; std::transform( mbxs.begin(), mbxs.end(), std::back_inserter( res ), boost::bind( &Mailbox::prettyAddress, _1 ) ); return res; } static QString formatVerificationResultDetails( const VerificationResult & res, const DecryptVerifyResult::SenderInfo & info, const QString& errorString ) { if( (res.error().code() == GPG_ERR_EIO || res.error().code() == GPG_ERR_NO_DATA) && !errorString.isEmpty() ) return i18n( "Input error: %1", errorString ); const std::vector sigs = res.signatures(); const std::vector signers = KeyCache::instance()->findSigners( res ); QString details; Q_FOREACH ( const Signature & sig, sigs ) details += formatSignature( sig, DecryptVerifyResult::keyForSignature( sig, signers ), info ) + QLatin1Char('\n'); details = details.trimmed(); details.replace( QLatin1Char('\n'), QLatin1String("
") ); if ( info.conflicts() ) details += i18n( "

The sender's address %1 is not stored in the certificate. Stored: %2

", info.informativeSender.prettyAddress(), format( info.signerMailboxes() ).join( i18nc("separator for a list of e-mail addresses", ", " ) ) ); return details; } static QString formatDecryptionResultDetails( const DecryptionResult & res, const std::vector & recipients, const QString& errorString ) { if( (res.error().code() == GPG_ERR_EIO || res.error().code() == GPG_ERR_NO_DATA) && !errorString.isEmpty() ) return i18n( "Input error: %1", errorString ); if ( res.isNull() || !res.error() || res.error().isCanceled() ) return QString(); if ( recipients.empty() && res.numRecipients() > 0 ) return QLatin1String( "") + i18np( "One unknown recipient.", "%1 unknown recipients.", res.numRecipients() ) + QLatin1String(""); QString details; if ( !recipients.empty() ) { details += i18np( "Recipient:", "Recipients:", res.numRecipients() ); if ( res.numRecipients() == 1 ) return details + renderKey( recipients.front() ); details += QLatin1String("
    "); Q_FOREACH( const Key & key, recipients ) details += QLatin1String("
  • ") + renderKey( key ) + QLatin1String("
  • "); if ( recipients.size() < res.numRecipients() ) details += QLatin1String("
  • ") + i18np( "One unknown recipient", "%1 unknown recipients", res.numRecipients() - recipients.size() ) + QLatin1String("
  • "); details += QLatin1String("
"); } return details; } static QString formatDecryptVerifyResultOverview( const DecryptionResult & dr, const VerificationResult & vr, const DecryptVerifyResult::SenderInfo & info ) { if ( IsErrorOrCanceled( dr ) || !relevantInDecryptVerifyContext( vr ) ) return formatDecryptionResultOverview( dr ); return formatVerificationResultOverview( vr, info ); } static QString formatDecryptVerifyResultDetails( const DecryptionResult & dr, const VerificationResult & vr, const std::vector & recipients, const DecryptVerifyResult::SenderInfo & info, const QString& errorString ) { const QString drDetails = formatDecryptionResultDetails( dr, recipients, errorString ); if ( IsErrorOrCanceled( dr ) || !relevantInDecryptVerifyContext( vr ) ) return drDetails; return drDetails + ( drDetails.isEmpty() ? QString() : QLatin1String("
") ) + formatVerificationResultDetails( vr, info, errorString ); } } // anon namespace class DecryptVerifyResult::Private { DecryptVerifyResult* const q; public: Private( DecryptVerifyOperation type, const VerificationResult & vr, const DecryptionResult & dr, const QByteArray & stuff, int errCode, const QString & errString, const QString & input, const QString & output, const AuditLog & auditLog, const Mailbox & informativeSender, DecryptVerifyResult* qq ) : q( qq ), m_type( type ), m_verificationResult( vr ), m_decryptionResult( dr ), m_stuff( stuff ), m_error( errCode ), m_errorString( errString ), m_inputLabel( input ), m_outputLabel( output ), m_auditLog( auditLog ), m_informativeSender( informativeSender ) { } QString label() const { return formatInputOutputLabel( m_inputLabel, m_outputLabel, false, q->hasError() ); } DecryptVerifyResult::SenderInfo makeSenderInfo() const; bool isDecryptOnly() const { return m_type == Decrypt; } bool isVerifyOnly() const { return m_type == Verify; } bool isDecryptVerify() const { return m_type == DecryptVerify; } DecryptVerifyOperation m_type; VerificationResult m_verificationResult; DecryptionResult m_decryptionResult; QByteArray m_stuff; int m_error; QString m_errorString; QString m_inputLabel; QString m_outputLabel; const AuditLog m_auditLog; const Mailbox m_informativeSender; }; DecryptVerifyResult::SenderInfo DecryptVerifyResult::Private::makeSenderInfo() const { return SenderInfo( m_informativeSender, KeyCache::instance()->findSigners( m_verificationResult ) ); } shared_ptr AbstractDecryptVerifyTask::fromDecryptResult( const DecryptionResult & dr, const QByteArray & plaintext, const AuditLog & auditLog ) { return shared_ptr( new DecryptVerifyResult( Decrypt, VerificationResult(), dr, plaintext, 0, QString(), inputLabel(), outputLabel(), auditLog, informativeSender() ) ); } shared_ptr AbstractDecryptVerifyTask::fromDecryptResult( const GpgME::Error & err, const QString& what, const AuditLog & auditLog ) { return shared_ptr( new DecryptVerifyResult( Decrypt, VerificationResult(), DecryptionResult( err ), QByteArray(), err.code(), what, inputLabel(), outputLabel(), auditLog, informativeSender() ) ); } shared_ptr AbstractDecryptVerifyTask::fromDecryptVerifyResult( const DecryptionResult & dr, const VerificationResult & vr, const QByteArray & plaintext, const AuditLog & auditLog ) { return shared_ptr( new DecryptVerifyResult( DecryptVerify, vr, dr, plaintext, 0, QString(), inputLabel(), outputLabel(), auditLog, informativeSender() ) ); } shared_ptr AbstractDecryptVerifyTask::fromDecryptVerifyResult( const GpgME::Error & err, const QString & details, const AuditLog & auditLog ) { return shared_ptr( new DecryptVerifyResult( DecryptVerify, VerificationResult(), DecryptionResult( err ), QByteArray(), err.code(), details, inputLabel(), outputLabel(), auditLog, informativeSender() ) ); } shared_ptr AbstractDecryptVerifyTask::fromVerifyOpaqueResult( const VerificationResult & vr, const QByteArray & plaintext, const AuditLog & auditLog ) { return shared_ptr( new DecryptVerifyResult( Verify, vr, DecryptionResult(), plaintext, 0, QString(), inputLabel(), outputLabel(), auditLog, informativeSender() ) ); } shared_ptr AbstractDecryptVerifyTask::fromVerifyOpaqueResult( const GpgME::Error & err, const QString & details, const AuditLog & auditLog ) { return shared_ptr( new DecryptVerifyResult( Verify, VerificationResult( err ), DecryptionResult(), QByteArray(), err.code(), details, inputLabel(), outputLabel(), auditLog, informativeSender() ) ); } shared_ptr AbstractDecryptVerifyTask::fromVerifyDetachedResult( const VerificationResult & vr, const AuditLog & auditLog ) { return shared_ptr( new DecryptVerifyResult( Verify, vr, DecryptionResult(), QByteArray(), 0, QString(), inputLabel(), outputLabel(), auditLog, informativeSender() ) ); } shared_ptr AbstractDecryptVerifyTask::fromVerifyDetachedResult( const GpgME::Error & err, const QString & details, const AuditLog & auditLog ) { return shared_ptr( new DecryptVerifyResult( Verify, VerificationResult( err ), DecryptionResult(), QByteArray(), err.code(), details, inputLabel(), outputLabel(), auditLog, informativeSender() ) ); } DecryptVerifyResult::DecryptVerifyResult( DecryptVerifyOperation type, const VerificationResult& vr, const DecryptionResult& dr, const QByteArray& stuff, int errCode, const QString & errString, const QString & inputLabel, const QString & outputLabel, const AuditLog & auditLog, const Mailbox & informativeSender ) : Task::Result(), d( new Private( type, vr, dr, stuff, errCode, errString, inputLabel, outputLabel, auditLog, informativeSender, this ) ) { } QString DecryptVerifyResult::overview() const { QString ov; if ( d->isDecryptOnly() ) ov = formatDecryptionResultOverview( d->m_decryptionResult ); else if ( d->isVerifyOnly() ) ov = formatVerificationResultOverview( d->m_verificationResult, d->makeSenderInfo() ); else ov = formatDecryptVerifyResultOverview( d->m_decryptionResult, d->m_verificationResult, d->makeSenderInfo() ); return i18nc( "label: result example: foo.sig: Verification failed. ", "%1: %2", d->label(), ov ); } QString DecryptVerifyResult::details() const { if ( d->isDecryptOnly() ) return formatDecryptionResultDetails( d->m_decryptionResult, KeyCache::instance()->findRecipients( d->m_decryptionResult ), errorString() ); if ( d->isVerifyOnly() ) return formatVerificationResultDetails( d->m_verificationResult, d->makeSenderInfo(), errorString() ); return formatDecryptVerifyResultDetails( d->m_decryptionResult, d->m_verificationResult, KeyCache::instance()->findRecipients( d->m_decryptionResult ), d->makeSenderInfo(), errorString() ); } bool DecryptVerifyResult::hasError() const { return d->m_error != 0; } int DecryptVerifyResult::errorCode() const { return d->m_error; } QString DecryptVerifyResult::errorString() const { return d->m_errorString; } AuditLog DecryptVerifyResult::auditLog() const { return d->m_auditLog; } Task::Result::VisualCode DecryptVerifyResult::code() const { if ( ( d->m_type == DecryptVerify || d->m_type == Verify ) && relevantInDecryptVerifyContext( verificationResult() ) ) return codeForVerificationResult( verificationResult() ); return hasError() ? NeutralError : NeutralSuccess; } GpgME::VerificationResult DecryptVerifyResult::verificationResult() const { return d->m_verificationResult; } const Key & DecryptVerifyResult::keyForSignature( const Signature & sig, const std::vector & keys ) { if ( const char * const fpr = sig.fingerprint() ) { const std::vector::const_iterator it = std::lower_bound( keys.begin(), keys.end(), fpr, _detail::ByFingerprint() ); if ( it != keys.end() && _detail::ByFingerprint()( *it, fpr ) ) return *it; } static const Key null; return null; } class AbstractDecryptVerifyTask::Private { public: Mailbox informativeSender; }; AbstractDecryptVerifyTask::AbstractDecryptVerifyTask( QObject * parent ) : Task( parent ), d( new Private ) {} AbstractDecryptVerifyTask::~AbstractDecryptVerifyTask() {} Mailbox AbstractDecryptVerifyTask::informativeSender() const { return d->informativeSender; } void AbstractDecryptVerifyTask::setInformativeSender( const Mailbox & sender ) { d->informativeSender = sender; } class DecryptVerifyTask::Private { DecryptVerifyTask* const q; public: explicit Private( DecryptVerifyTask* qq ) : q( qq ), m_backend( 0 ), m_protocol( UnknownProtocol ) {} void slotResult( const DecryptionResult&, const VerificationResult&, const QByteArray& ); void registerJob( DecryptVerifyJob * job ) { q->connect( job, SIGNAL(result(GpgME::DecryptionResult,GpgME::VerificationResult,QByteArray)), q, SLOT(slotResult(GpgME::DecryptionResult,GpgME::VerificationResult,QByteArray)) ); q->connect( job, SIGNAL(progress(QString,int,int)), q, SLOT(setProgress(QString,int,int)) ); } void emitResult( const shared_ptr& result ); shared_ptr m_input; shared_ptr m_output; const CryptoBackend::Protocol* m_backend; Protocol m_protocol; }; void DecryptVerifyTask::Private::emitResult( const shared_ptr& result ) { q->emitResult( result ); emit q->decryptVerifyResult( result ); } void DecryptVerifyTask::Private::slotResult( const DecryptionResult& dr, const VerificationResult& vr, const QByteArray& plainText ) { { std::stringstream ss; ss << dr << '\n' << vr; kDebug() << ss.str().c_str(); } const AuditLog auditLog = auditLogFromSender( q->sender() ); if ( dr.error().code() || vr.error().code() ) { m_output->cancel(); } else { try { kleo_assert( !dr.isNull() || !vr.isNull() ); m_output->finalize(); } catch ( const GpgME::Exception & e ) { emitResult( q->fromDecryptResult( e.error(), QString::fromLocal8Bit( e.what() ), auditLog ) ); return; } catch ( const std::exception & e ) { emitResult( q->fromDecryptResult( make_error( GPG_ERR_INTERNAL ), i18n("Caught exception: %1", QString::fromLocal8Bit( e.what() ) ), auditLog ) ); return; } catch ( ... ) { emitResult( q->fromDecryptResult( make_error( GPG_ERR_INTERNAL ), i18n("Caught unknown exception"), auditLog ) ); return; } } const int drErr = dr.error().code(); const QString errorString = m_output->errorString(); if ( (drErr == GPG_ERR_EIO || drErr == GPG_ERR_NO_DATA) && !errorString.isEmpty() ) { emitResult( q->fromDecryptResult( dr.error(), errorString, auditLog ) ); return; } emitResult( q->fromDecryptVerifyResult( dr, vr, plainText, auditLog ) ); } DecryptVerifyTask::DecryptVerifyTask( QObject* parent ) : AbstractDecryptVerifyTask( parent ), d( new Private( this ) ) { } DecryptVerifyTask::~DecryptVerifyTask() { } void DecryptVerifyTask::setInput( const shared_ptr & input ) { d->m_input = input; kleo_assert( d->m_input && d->m_input->ioDevice() ); } void DecryptVerifyTask::setOutput( const shared_ptr & output ) { d->m_output = output; kleo_assert( d->m_output && d->m_output->ioDevice() ); } void DecryptVerifyTask::setProtocol( Protocol prot ) { kleo_assert( prot != UnknownProtocol ); d->m_protocol = prot; d->m_backend = CryptoBackendFactory::instance()->protocol( prot ); kleo_assert( d->m_backend ); } void DecryptVerifyTask::autodetectProtocolFromInput() { if ( !d->m_input ) return; const Protocol p = findProtocol( d->m_input->classification() ); if ( p == UnknownProtocol ) throw Exception( gpg_error( GPG_ERR_NOTHING_FOUND ), i18n("Could not determine whether this is an S/MIME or an OpenPGP signature/ciphertext - maybe it is neither ciphertext nor a signature?"), Exception::MessageOnly ); setProtocol( p ); } QString DecryptVerifyTask::label() const { return i18n( "Decrypting: %1...", d->m_input->label() ); } unsigned long long DecryptVerifyTask::inputSize() const { return d->m_input ? d->m_input->size() : 0; } QString DecryptVerifyTask::inputLabel() const { return d->m_input ? d->m_input->label() : QString(); } QString DecryptVerifyTask::outputLabel() const { return d->m_output ? d->m_output->label() : QString(); } Protocol DecryptVerifyTask::protocol() const { return d->m_protocol; } void DecryptVerifyTask::cancel() { } void DecryptVerifyTask::doStart() { kleo_assert( d->m_backend ); try { DecryptVerifyJob * const job = d->m_backend->decryptVerifyJob(); kleo_assert( job ); d->registerJob( job ); job->start( d->m_input->ioDevice(), d->m_output->ioDevice() ); } catch ( const GpgME::Exception & e ) { d->emitResult( fromDecryptVerifyResult( e.error(), QString::fromLocal8Bit( e.what() ), AuditLog() ) ); } catch ( const std::exception & e ) { d->emitResult( fromDecryptVerifyResult( make_error( GPG_ERR_INTERNAL ), i18n( "Caught exception: %1", QString::fromLocal8Bit( e.what() ) ), AuditLog() ) ); } catch ( ... ) { d->emitResult( fromDecryptVerifyResult( make_error( GPG_ERR_INTERNAL ), i18n( "Caught unknown exception" ), AuditLog() ) ); } } class DecryptTask::Private { DecryptTask* const q; public: explicit Private( DecryptTask* qq ) : q( qq ), m_backend( 0 ), m_protocol( UnknownProtocol ) {} void slotResult( const DecryptionResult&, const QByteArray& ); void registerJob( DecryptJob * job ) { q->connect( job, SIGNAL(result(GpgME::DecryptionResult,QByteArray)), q, SLOT(slotResult(GpgME::DecryptionResult,QByteArray)) ); q->connect( job, SIGNAL(progress(QString,int,int)), q, SLOT(setProgress(QString,int,int)) ); } void emitResult( const shared_ptr& result ); shared_ptr m_input; shared_ptr m_output; const CryptoBackend::Protocol* m_backend; Protocol m_protocol; }; void DecryptTask::Private::emitResult( const shared_ptr& result ) { q->emitResult( result ); emit q->decryptVerifyResult( result ); } void DecryptTask::Private::slotResult( const DecryptionResult& result, const QByteArray& plainText ) { { std::stringstream ss; ss << result; kDebug() << ss.str().c_str(); } const AuditLog auditLog = auditLogFromSender( q->sender() ); if ( result.error().code() ) { m_output->cancel(); } else { try { kleo_assert( !result.isNull() ); m_output->finalize(); } catch ( const GpgME::Exception & e ) { emitResult( q->fromDecryptResult( e.error(), QString::fromLocal8Bit( e.what() ), auditLog ) ); return; } catch ( const std::exception & e ) { emitResult( q->fromDecryptResult( make_error( GPG_ERR_INTERNAL ), i18n("Caught exception: %1", QString::fromLocal8Bit( e.what() ) ), auditLog ) ); return; } catch ( ... ) { emitResult( q->fromDecryptResult( make_error( GPG_ERR_INTERNAL ), i18n("Caught unknown exception"), auditLog ) ); return; } } const int drErr = result.error().code(); const QString errorString = m_output->errorString(); if ( (drErr == GPG_ERR_EIO || drErr == GPG_ERR_NO_DATA) && !errorString.isEmpty() ) { emitResult( q->fromDecryptResult( result.error(), errorString, auditLog ) ); return; } emitResult( q->fromDecryptResult( result, plainText, auditLog ) ); } DecryptTask::DecryptTask( QObject* parent ) : AbstractDecryptVerifyTask( parent ), d( new Private( this ) ) { } DecryptTask::~DecryptTask() { } void DecryptTask::setInput( const shared_ptr & input ) { d->m_input = input; kleo_assert( d->m_input && d->m_input->ioDevice() ); } void DecryptTask::setOutput( const shared_ptr & output ) { d->m_output = output; kleo_assert( d->m_output && d->m_output->ioDevice() ); } void DecryptTask::setProtocol( Protocol prot ) { kleo_assert( prot != UnknownProtocol ); d->m_protocol = prot; d->m_backend = CryptoBackendFactory::instance()->protocol( prot ); kleo_assert( d->m_backend ); } void DecryptTask::autodetectProtocolFromInput() { if ( !d->m_input ) return; const Protocol p = findProtocol( d->m_input->classification() ); if ( p == UnknownProtocol ) throw Exception( gpg_error( GPG_ERR_NOTHING_FOUND ), i18n("Could not determine whether this was S/MIME- or OpenPGP-encrypted - maybe it is not ciphertext at all?"), Exception::MessageOnly ); setProtocol( p ); } QString DecryptTask::label() const { return i18n( "Decrypting: %1...", d->m_input->label() ); } unsigned long long DecryptTask::inputSize() const { return d->m_input ? d->m_input->size() : 0; } QString DecryptTask::inputLabel() const { return d->m_input ? d->m_input->label() : QString(); } QString DecryptTask::outputLabel() const { return d->m_output ? d->m_output->label() : QString(); } Protocol DecryptTask::protocol() const { kleo_assert( !"not implemented" ); return UnknownProtocol; // ### TODO } void DecryptTask::cancel() { } void DecryptTask::doStart() { kleo_assert( d->m_backend ); try { DecryptJob * const job = d->m_backend->decryptJob(); kleo_assert( job ); d->registerJob( job ); job->start( d->m_input->ioDevice(), d->m_output->ioDevice() ); } catch ( const GpgME::Exception & e ) { d->emitResult( fromDecryptResult( e.error(), QString::fromLocal8Bit( e.what() ), AuditLog() ) ); } catch ( const std::exception & e ) { d->emitResult( fromDecryptResult( make_error( GPG_ERR_INTERNAL ), i18n("Caught exception: %1", QString::fromLocal8Bit( e.what() ) ), AuditLog() ) ); } catch ( ... ) { d->emitResult( fromDecryptResult( make_error( GPG_ERR_INTERNAL ), i18n("Caught unknown exception"), AuditLog() ) ); } } class VerifyOpaqueTask::Private { VerifyOpaqueTask* const q; public: explicit Private( VerifyOpaqueTask* qq ) : q( qq ), m_backend( 0 ), m_protocol( UnknownProtocol ) {} void slotResult( const VerificationResult&, const QByteArray& ); void registerJob( VerifyOpaqueJob* job ) { q->connect( job, SIGNAL(result(GpgME::VerificationResult,QByteArray)), q, SLOT(slotResult(GpgME::VerificationResult,QByteArray)) ); q->connect( job, SIGNAL(progress(QString,int,int)), q, SLOT(setProgress(QString,int,int)) ); } void emitResult( const shared_ptr& result ); shared_ptr m_input; shared_ptr m_output; const CryptoBackend::Protocol* m_backend; Protocol m_protocol; }; void VerifyOpaqueTask::Private::emitResult( const shared_ptr& result ) { q->emitResult( result ); emit q->decryptVerifyResult( result ); } void VerifyOpaqueTask::Private::slotResult( const VerificationResult& result, const QByteArray& plainText ) { { std::stringstream ss; ss << result; kDebug() << ss.str().c_str(); } const AuditLog auditLog = auditLogFromSender( q->sender() ); if ( result.error().code() ) { m_output->cancel(); } else { try { kleo_assert( !result.isNull() ); m_output->finalize(); } catch ( const GpgME::Exception & e ) { emitResult( q->fromDecryptResult( e.error(), QString::fromLocal8Bit( e.what() ), auditLog ) ); return; } catch ( const std::exception & e ) { emitResult( q->fromDecryptResult( make_error( GPG_ERR_INTERNAL ), i18n("Caught exception: %1", QString::fromLocal8Bit( e.what() ) ), auditLog ) ); return; } catch ( ... ) { emitResult( q->fromDecryptResult( make_error( GPG_ERR_INTERNAL ), i18n("Caught unknown exception"), auditLog ) ); return; } } const int drErr = result.error().code(); const QString errorString = m_output->errorString(); if ( (drErr == GPG_ERR_EIO || drErr == GPG_ERR_NO_DATA) && !errorString.isEmpty() ) { emitResult( q->fromDecryptResult( result.error(), errorString, auditLog ) ); return; } emitResult( q->fromVerifyOpaqueResult( result, plainText, auditLog ) ); } VerifyOpaqueTask::VerifyOpaqueTask( QObject* parent ) : AbstractDecryptVerifyTask( parent ), d( new Private( this ) ) { } VerifyOpaqueTask::~VerifyOpaqueTask() { } void VerifyOpaqueTask::setInput( const shared_ptr & input ) { d->m_input = input; kleo_assert( d->m_input && d->m_input->ioDevice() ); } void VerifyOpaqueTask::setOutput( const shared_ptr & output ) { d->m_output = output; kleo_assert( d->m_output && d->m_output->ioDevice() ); } void VerifyOpaqueTask::setProtocol( Protocol prot ) { kleo_assert( prot != UnknownProtocol ); d->m_protocol = prot; d->m_backend = CryptoBackendFactory::instance()->protocol( prot ); kleo_assert( d->m_backend ); } void VerifyOpaqueTask::autodetectProtocolFromInput() { if ( !d->m_input ) return; const Protocol p = findProtocol( d->m_input->classification() ); if ( p == UnknownProtocol ) throw Exception( gpg_error( GPG_ERR_NOTHING_FOUND ), i18n("Could not determine whether this is an S/MIME or an OpenPGP signature - maybe it is not a signature at all?"), Exception::MessageOnly ); setProtocol( p ); } QString VerifyOpaqueTask::label() const { return i18n( "Verifying: %1...", d->m_input->label() ); } unsigned long long VerifyOpaqueTask::inputSize() const { return d->m_input ? d->m_input->size() : 0; } QString VerifyOpaqueTask::inputLabel() const { return d->m_input ? d->m_input->label() : QString(); } QString VerifyOpaqueTask::outputLabel() const { return d->m_output ? d->m_output->label() : QString(); } Protocol VerifyOpaqueTask::protocol() const { return d->m_protocol; } void VerifyOpaqueTask::cancel() { } void VerifyOpaqueTask::doStart() { kleo_assert( d->m_backend ); try { VerifyOpaqueJob * const job = d->m_backend->verifyOpaqueJob(); kleo_assert( job ); d->registerJob( job ); job->start( d->m_input->ioDevice(), d->m_output ? d->m_output->ioDevice() : shared_ptr() ); } catch ( const GpgME::Exception & e ) { d->emitResult( fromVerifyOpaqueResult( e.error(), QString::fromLocal8Bit( e.what() ), AuditLog() ) ); } catch ( const std::exception & e ) { d->emitResult( fromVerifyOpaqueResult( make_error( GPG_ERR_INTERNAL ), i18n("Caught exception: %1", QString::fromLocal8Bit( e.what() ) ), AuditLog() ) ); } catch ( ... ) { d->emitResult( fromVerifyOpaqueResult( make_error( GPG_ERR_INTERNAL ), i18n("Caught unknown exception"), AuditLog() ) ); } } class VerifyDetachedTask::Private { VerifyDetachedTask* const q; public: explicit Private( VerifyDetachedTask* qq ) : q( qq ), m_backend( 0 ), m_protocol( UnknownProtocol ) {} void slotResult( const VerificationResult& ); void registerJob( VerifyDetachedJob* job ) { q->connect( job, SIGNAL(result(GpgME::VerificationResult)), q, SLOT(slotResult(GpgME::VerificationResult)) ); q->connect( job, SIGNAL(progress(QString,int,int)), q, SLOT(setProgress(QString,int,int)) ); } void emitResult( const shared_ptr& result ); shared_ptr m_input, m_signedData; const CryptoBackend::Protocol* m_backend; Protocol m_protocol; }; void VerifyDetachedTask::Private::emitResult( const shared_ptr& result ) { q->emitResult( result ); emit q->decryptVerifyResult( result ); } void VerifyDetachedTask::Private::slotResult( const VerificationResult& result ) { { std::stringstream ss; ss << result; kDebug() << ss.str().c_str(); } const AuditLog auditLog = auditLogFromSender( q->sender() ); try { kleo_assert( !result.isNull() ); emitResult( q->fromVerifyDetachedResult( result, auditLog ) ); } catch ( const GpgME::Exception & e ) { emitResult( q->fromVerifyDetachedResult( e.error(), QString::fromLocal8Bit( e.what() ), auditLog ) ); } catch ( const std::exception & e ) { emitResult( q->fromVerifyDetachedResult( make_error( GPG_ERR_INTERNAL ), i18n("Caught exception: %1", QString::fromLocal8Bit( e.what() ) ), auditLog ) ); } catch ( ... ) { emitResult( q->fromVerifyDetachedResult( make_error( GPG_ERR_INTERNAL ), i18n("Caught unknown exception"), auditLog ) ); } } VerifyDetachedTask::VerifyDetachedTask( QObject* parent ) : AbstractDecryptVerifyTask( parent ), d( new Private( this ) ) { } VerifyDetachedTask::~VerifyDetachedTask() { } void VerifyDetachedTask::setInput( const shared_ptr & input ) { d->m_input = input; kleo_assert( d->m_input && d->m_input->ioDevice() ); } void VerifyDetachedTask::setSignedData( const shared_ptr & signedData ) { d->m_signedData = signedData; kleo_assert( d->m_signedData && d->m_signedData->ioDevice() ); } void VerifyDetachedTask::setProtocol( Protocol prot ) { kleo_assert( prot != UnknownProtocol ); d->m_protocol = prot; d->m_backend = CryptoBackendFactory::instance()->protocol( prot ); kleo_assert( d->m_backend ); } void VerifyDetachedTask::autodetectProtocolFromInput() { if ( !d->m_input ) return; const Protocol p = findProtocol( d->m_input->classification() ); if ( p == UnknownProtocol ) throw Exception( gpg_error( GPG_ERR_NOTHING_FOUND ), i18n("Could not determine whether this is an S/MIME or an OpenPGP signature - maybe it is not a signature at all?"), Exception::MessageOnly ); setProtocol( p ); } unsigned long long VerifyDetachedTask::inputSize() const { return d->m_signedData ? d->m_signedData->size() : 0; } QString VerifyDetachedTask::label() const { return i18n( "Verifying signature: %1...", d->m_input->label() ); } QString VerifyDetachedTask::inputLabel() const { return d->m_input ? d->m_input->label() : QString(); } QString VerifyDetachedTask::outputLabel() const { return QString(); } Protocol VerifyDetachedTask::protocol() const { kleo_assert( !"not implemented" ); return UnknownProtocol; // ### TODO } void VerifyDetachedTask::cancel() { } void VerifyDetachedTask::doStart() { kleo_assert( d->m_backend ); try { VerifyDetachedJob * const job = d->m_backend->verifyDetachedJob(); kleo_assert( job ); d->registerJob( job ); job->start( d->m_input->ioDevice(), d->m_signedData->ioDevice() ); } catch ( const GpgME::Exception & e ) { d->emitResult( fromVerifyDetachedResult( e.error(), QString::fromLocal8Bit( e.what() ), AuditLog() ) ); } catch ( const std::exception & e ) { d->emitResult( fromVerifyDetachedResult( make_error( GPG_ERR_INTERNAL ), i18n("Caught exception: %1", QString::fromLocal8Bit( e.what() ) ), AuditLog() ) ); } catch ( ... ) { d->emitResult( fromVerifyDetachedResult( make_error( GPG_ERR_INTERNAL ), i18n("Caught unknown exception"), AuditLog() ) ); } } #include "moc_decryptverifytask.cpp" diff --git a/kleopatra/crypto/decryptverifytask.h b/kleopatra/crypto/decryptverifytask.h index 458e366ea9..d053fea98c 100644 --- a/kleopatra/crypto/decryptverifytask.h +++ b/kleopatra/crypto/decryptverifytask.h @@ -1,267 +1,269 @@ /* -*- mode: c++; c-basic-offset:4 -*- decryptverifytask.h This file is part of Kleopatra, the KDE keymanager Copyright (c) 2008 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #ifndef __KLEOPATRA_CRYPTO_DECRYPTVERIFYTASK_H__ #define __KLEOPATRA_CRYPTO_DECRYPTVERIFYTASK_H__ #include "task.h" #include #include +#ifndef Q_MOC_RUN #include +#endif namespace KMime { namespace Types { class Mailbox; } } namespace GpgME { class DecryptionResult; class VerificationResult; class Key; class Signature; } namespace Kleo { class Input; class Output; class AuditLog; } namespace Kleo { namespace Crypto { class DecryptVerifyResult; class AbstractDecryptVerifyTask : public Task { Q_OBJECT public: explicit AbstractDecryptVerifyTask( QObject* parent = 0 ); virtual ~AbstractDecryptVerifyTask(); virtual void autodetectProtocolFromInput() = 0; KMime::Types::Mailbox informativeSender() const; void setInformativeSender( const KMime::Types::Mailbox & senders ); Q_SIGNALS: void decryptVerifyResult( const boost::shared_ptr & ); protected: boost::shared_ptr fromDecryptResult( const GpgME::DecryptionResult & dr, const QByteArray & plaintext, const AuditLog & auditLog ); boost::shared_ptr fromDecryptResult( const GpgME::Error & err, const QString& details, const AuditLog & auditLog ); boost::shared_ptr fromDecryptVerifyResult( const GpgME::DecryptionResult & dr, const GpgME::VerificationResult & vr, const QByteArray & plaintext, const AuditLog & auditLog ); boost::shared_ptr fromDecryptVerifyResult( const GpgME::Error & err, const QString & what, const AuditLog & auditLog ); boost::shared_ptr fromVerifyOpaqueResult( const GpgME::VerificationResult & vr, const QByteArray & plaintext, const AuditLog & auditLog ); boost::shared_ptr fromVerifyOpaqueResult( const GpgME::Error & err, const QString & details, const AuditLog & auditLog ); boost::shared_ptr fromVerifyDetachedResult( const GpgME::VerificationResult & vr, const AuditLog & auditLog ); boost::shared_ptr fromVerifyDetachedResult( const GpgME::Error & err, const QString & details, const AuditLog & auditLog ); virtual QString inputLabel() const = 0; virtual QString outputLabel() const = 0; private: class Private; kdtools::pimpl_ptr d; }; class DecryptTask : public AbstractDecryptVerifyTask { Q_OBJECT public: explicit DecryptTask( QObject* parent = 0 ); ~DecryptTask(); void setInput( const boost::shared_ptr & input ); void setOutput( const boost::shared_ptr & output ); void setProtocol( GpgME::Protocol prot ); void autodetectProtocolFromInput(); /* reimp */ QString label() const; /* reimp */ GpgME::Protocol protocol() const; public Q_SLOTS: /* reimp */ void cancel(); private: /* reimp */ void doStart(); /* reimp */ QString inputLabel() const; /* reimp */ QString outputLabel() const; /* reimp */ unsigned long long inputSize() const; private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT( d, void slotResult( GpgME::DecryptionResult, QByteArray ) ) }; class VerifyDetachedTask : public AbstractDecryptVerifyTask { Q_OBJECT public: explicit VerifyDetachedTask( QObject* parent = 0 ); ~VerifyDetachedTask(); void setInput( const boost::shared_ptr & input ); void setSignedData( const boost::shared_ptr & signedData ); void setProtocol( GpgME::Protocol prot ); void autodetectProtocolFromInput(); /* reimp */ QString label() const; /* reimp */ GpgME::Protocol protocol() const; public Q_SLOTS: /* reimp */ void cancel(); private: /* reimp */ void doStart(); /* reimp */ QString inputLabel() const; /* reimp */ QString outputLabel() const; /* reimp */ unsigned long long inputSize() const; private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT( d, void slotResult( GpgME::VerificationResult ) ) }; class VerifyOpaqueTask : public AbstractDecryptVerifyTask { Q_OBJECT public: explicit VerifyOpaqueTask( QObject* parent = 0 ); ~VerifyOpaqueTask(); void setInput( const boost::shared_ptr & input ); void setOutput( const boost::shared_ptr & output ); void setProtocol( GpgME::Protocol prot ); void autodetectProtocolFromInput(); /* reimp */ QString label() const; /* reimp */ GpgME::Protocol protocol() const; public Q_SLOTS: /* reimp */ void cancel(); private: /* reimp */ void doStart(); /* reimp */ QString inputLabel() const; /* reimp */ QString outputLabel() const; /* reimp */ unsigned long long inputSize() const; private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT( d, void slotResult( GpgME::VerificationResult, QByteArray ) ) }; class DecryptVerifyTask : public AbstractDecryptVerifyTask { Q_OBJECT public: explicit DecryptVerifyTask( QObject* parent = 0 ); ~DecryptVerifyTask(); void setInput( const boost::shared_ptr & input ); void setSignedData( const boost::shared_ptr & signedData ); void setOutput( const boost::shared_ptr & output ); void setProtocol( GpgME::Protocol prot ); void autodetectProtocolFromInput(); /* reimp */ QString label() const; /* reimp */ GpgME::Protocol protocol() const; public Q_SLOTS: /* reimp */ void cancel(); private: /* reimp */ void doStart(); /* reimp */ QString inputLabel() const; /* reimp */ QString outputLabel() const; /* reimp */ unsigned long long inputSize() const; private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT( d, void slotResult( GpgME::DecryptionResult, GpgME::VerificationResult, QByteArray ) ) }; class DecryptVerifyResult : public Task::Result { friend class ::Kleo::Crypto::AbstractDecryptVerifyTask; public: class SenderInfo; /* reimp */ QString overview() const; /* reimp */ QString details() const; /* reimp */ bool hasError() const; /* reimp */ int errorCode() const; /* reimp */ QString errorString() const; /* reimp */ VisualCode code() const; /* reimp */ AuditLog auditLog() const; GpgME::VerificationResult verificationResult() const; static const GpgME::Key & keyForSignature( const GpgME::Signature & sig, const std::vector & keys ); private: static QString keyToString( const GpgME::Key & key ); private: DecryptVerifyResult(); DecryptVerifyResult( const DecryptVerifyResult& ); DecryptVerifyResult& operator=( const DecryptVerifyResult& other ); DecryptVerifyResult( DecryptVerifyOperation op, const GpgME::VerificationResult& vr, const GpgME::DecryptionResult& dr, const QByteArray& stuff, int errCode, const QString & errString, const QString & inputLabel, const QString & outputLabel, const AuditLog & auditLog, const KMime::Types::Mailbox & informativeSender ); private: class Private; kdtools::pimpl_ptr d; }; } } #endif //__KLEOPATRA_CRYPTO_DECRYPTVERIFYTASK_H__ diff --git a/kleopatra/crypto/encryptemailcontroller.cpp b/kleopatra/crypto/encryptemailcontroller.cpp index a4e6b7524a..ba4823a5c2 100644 --- a/kleopatra/crypto/encryptemailcontroller.cpp +++ b/kleopatra/crypto/encryptemailcontroller.cpp @@ -1,314 +1,316 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/encryptemailcontroller.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2007 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "encryptemailcontroller.h" #include "encryptemailtask.h" #include "taskcollection.h" #include #include #include #include #include #include #include "emailoperationspreferences.h" #include #include #include #include #include +#ifndef Q_MOC_RUN #include #include +#endif using namespace Kleo; using namespace Kleo::Crypto; using namespace Kleo::Crypto::Gui; using namespace boost; using namespace GpgME; using namespace KMime::Types; class EncryptEMailController::Private { friend class ::Kleo::Crypto::EncryptEMailController; EncryptEMailController * const q; public: explicit Private( Mode mode, EncryptEMailController * qq ); private: void slotWizardRecipientsResolved(); void slotWizardCanceled(); private: void ensureWizardCreated() const; void ensureWizardVisible(); void cancelAllTasks(); void schedule(); shared_ptr takeRunnable( GpgME::Protocol proto ); private: const Mode mode; std::vector< shared_ptr > runnable, completed; shared_ptr cms, openpgp; mutable QPointer wizard; }; EncryptEMailController::Private::Private( Mode m, EncryptEMailController * qq ) : q( qq ), mode( m ), runnable(), cms(), openpgp(), wizard() { } EncryptEMailController::EncryptEMailController( const shared_ptr & xc, Mode mode, QObject * p ) : Controller( xc, p ), d( new Private( mode, this ) ) { } EncryptEMailController::EncryptEMailController( Mode mode, QObject * p ) : Controller( p ), d( new Private( mode, this ) ) { } EncryptEMailController::~EncryptEMailController() { if ( d->wizard && !d->wizard->isVisible() ) delete d->wizard; //d->wizard->close(); ### ? } EncryptEMailController::Mode EncryptEMailController::mode() const { return d->mode; } void EncryptEMailController::setProtocol( Protocol proto ) { d->ensureWizardCreated(); const Protocol protocol = d->wizard->presetProtocol(); kleo_assert( protocol == UnknownProtocol || protocol == proto ); d->wizard->setPresetProtocol( proto ); } Protocol EncryptEMailController::protocol() const { d->ensureWizardCreated(); return d->wizard->selectedProtocol(); } const char * EncryptEMailController::protocolAsString() const { switch ( protocol() ) { case OpenPGP: return "OpenPGP"; case CMS: return "CMS"; default: throw Kleo::Exception( gpg_error( GPG_ERR_INTERNAL ), i18n("Call to EncryptEMailController::protocolAsString() is ambiguous.") ); } } void EncryptEMailController::startResolveRecipients() { startResolveRecipients( std::vector(), std::vector() ); } void EncryptEMailController::startResolveRecipients( const std::vector & recipients, const std::vector & senders ) { d->ensureWizardCreated(); d->wizard->setRecipients( recipients, senders ); d->ensureWizardVisible(); } void EncryptEMailController::Private::slotWizardRecipientsResolved() { emit q->recipientsResolved(); } void EncryptEMailController::Private::slotWizardCanceled() { q->setLastError( gpg_error( GPG_ERR_CANCELED ), i18n("User cancel") ); q->emitDoneOrError(); } void EncryptEMailController::setInputAndOutput( const shared_ptr & input, const shared_ptr & output ) { setInputsAndOutputs( std::vector< shared_ptr >( 1, input ), std::vector< shared_ptr >( 1, output ) ); } void EncryptEMailController::setInputsAndOutputs( const std::vector< shared_ptr > & inputs, const std::vector< shared_ptr > & outputs ) { kleo_assert( !inputs.empty() ); kleo_assert( outputs.size() == inputs.size() ); std::vector< shared_ptr > tasks; tasks.reserve( inputs.size() ); d->ensureWizardCreated(); const std::vector keys = d->wizard->resolvedCertificates(); kleo_assert( !keys.empty() ); for ( unsigned int i = 0, end = inputs.size() ; i < end ; ++i ) { const shared_ptr task( new EncryptEMailTask ); task->setInput( inputs[i] ); task->setOutput( outputs[i] ); if ( d->mode == ClipboardMode ) task->setAsciiArmor( true ); task->setRecipients( keys ); tasks.push_back( task ); } d->runnable.swap( tasks ); } void EncryptEMailController::start() { shared_ptr coll( new TaskCollection ); std::vector > tmp; std::copy( d->runnable.begin(), d->runnable.end(), std::back_inserter( tmp ) ); coll->setTasks( tmp ); d->ensureWizardCreated(); d->wizard->setTaskCollection( coll ); Q_FOREACH( const shared_ptr & t, tmp ) connectTask( t ); d->schedule(); } void EncryptEMailController::Private::schedule() { if ( !cms ) if ( const shared_ptr t = takeRunnable( CMS ) ) { t->start(); cms = t; } if ( !openpgp ) if ( const shared_ptr t = takeRunnable( OpenPGP ) ) { t->start(); openpgp = t; } if ( cms || openpgp ) return; kleo_assert( runnable.empty() ); q->emitDoneOrError(); } shared_ptr EncryptEMailController::Private::takeRunnable( GpgME::Protocol proto ) { const std::vector< shared_ptr >::iterator it = std::find_if( runnable.begin(), runnable.end(), boost::bind( &Task::protocol, _1 ) == proto ); if ( it == runnable.end() ) return shared_ptr(); const shared_ptr result = *it; runnable.erase( it ); return result; } void EncryptEMailController::doTaskDone( const Task * task, const shared_ptr & result ) { Q_UNUSED( result ); assert( task ); // We could just delete the tasks here, but we can't use // Qt::QueuedConnection here (we need sender()) and other slots // might not yet have executed. Therefore, we push completed tasks // into a burial container if ( task == d->cms.get() ) { d->completed.push_back( d->cms ); d->cms.reset(); } else if ( task == d->openpgp.get() ) { d->completed.push_back( d->openpgp ); d->openpgp.reset(); } QTimer::singleShot( 0, this, SLOT(schedule()) ); } void EncryptEMailController::cancel() { try { if ( d->wizard ) d->wizard->close(); d->cancelAllTasks(); } catch ( const std::exception & e ) { kDebug() << "Caught exception: " << e.what(); } } void EncryptEMailController::Private::cancelAllTasks() { // we just kill all runnable tasks - this will not result in // signal emissions. runnable.clear(); // a cancel() will result in a call to if ( cms ) cms->cancel(); if ( openpgp ) openpgp->cancel(); } void EncryptEMailController::Private::ensureWizardCreated() const { if ( wizard ) return; std::auto_ptr w( new EncryptEMailWizard ); w->setAttribute( Qt::WA_DeleteOnClose ); Kleo::EMailOperationsPreferences prefs; w->setQuickMode( prefs.quickEncryptEMail() ); connect( w.get(), SIGNAL(recipientsResolved()), q, SLOT(slotWizardRecipientsResolved()), Qt::QueuedConnection ); connect( w.get(), SIGNAL(canceled()), q, SLOT(slotWizardCanceled()), Qt::QueuedConnection ); wizard = w.release(); } void EncryptEMailController::Private::ensureWizardVisible() { ensureWizardCreated(); q->bringToForeground( wizard ); } #include "moc_encryptemailcontroller.cpp" diff --git a/kleopatra/crypto/encryptemailtask.cpp b/kleopatra/crypto/encryptemailtask.cpp index 3db2b1a6bb..709321f0f7 100644 --- a/kleopatra/crypto/encryptemailtask.cpp +++ b/kleopatra/crypto/encryptemailtask.cpp @@ -1,239 +1,241 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/encryptemailtask.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2007 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "encryptemailtask.h" #include #include #include #include #include #include #include #include #include #include #include #include #include // for Qt::escape +#ifndef Q_MOC_RUN #include +#endif using namespace Kleo; using namespace Kleo::Crypto; using namespace boost; using namespace GpgME; namespace { class EncryptEMailResult : public Task::Result { const EncryptionResult m_result; const AuditLog m_auditLog; public: EncryptEMailResult( const EncryptionResult & r, const AuditLog & auditLog ) : Task::Result(), m_result( r ), m_auditLog( auditLog ) {} /* reimp */ QString overview() const; /* reimp */ QString details() const; /* reimp */ int errorCode() const; /* reimp */ QString errorString() const; /* reimp */ VisualCode code() const; /* reimp */ AuditLog auditLog() const; }; QString makeResultString( const EncryptionResult& res ) { const Error err = res.error(); if ( err.isCanceled() ) return i18n( "Encryption canceled." ); if ( err ) return i18n( "Encryption failed: %1", Qt::escape( QString::fromLocal8Bit( err.asString() ) ) ); return i18n( "Encryption succeeded." ); } } class EncryptEMailTask::Private { friend class ::Kleo::Crypto::EncryptEMailTask; EncryptEMailTask * const q; public: explicit Private( EncryptEMailTask * qq ); private: std::auto_ptr createJob( GpgME::Protocol proto ); private: void slotResult( const EncryptionResult & ); private: shared_ptr input; shared_ptr output; std::vector recipients; QPointer job; }; EncryptEMailTask::Private::Private( EncryptEMailTask * qq ) : q( qq ), input(), output(), job( 0 ) { } EncryptEMailTask::EncryptEMailTask( QObject * p ) : Task( p ), d( new Private( this ) ) { } EncryptEMailTask::~EncryptEMailTask() {} void EncryptEMailTask::setInput( const shared_ptr & input ) { kleo_assert( !d->job ); kleo_assert( input ); d->input = input; } void EncryptEMailTask::setOutput( const shared_ptr & output ) { kleo_assert( !d->job ); kleo_assert( output ); d->output = output; } void EncryptEMailTask::setRecipients( const std::vector & recipients ) { kleo_assert( !d->job ); kleo_assert( !recipients.empty() ); d->recipients = recipients; } Protocol EncryptEMailTask::protocol() const { kleo_assert( !d->recipients.empty() ); return d->recipients.front().protocol(); } QString EncryptEMailTask::label() const { return d->input ? d->input->label() : QString(); } unsigned long long EncryptEMailTask::inputSize() const { return d->input ? d->input->size() : 0; } void EncryptEMailTask::doStart() { kleo_assert( !d->job ); kleo_assert( d->input ); kleo_assert( d->output ); kleo_assert( !d->recipients.empty() ); std::auto_ptr job = d->createJob( protocol() ); kleo_assert( job.get() ); job->start( d->recipients, d->input->ioDevice(), d->output->ioDevice(), /*alwaysTrust=*/true ); d->job = job.release(); } void EncryptEMailTask::cancel() { if ( d->job ) d->job->slotCancel(); } std::auto_ptr EncryptEMailTask::Private::createJob( GpgME::Protocol proto ) { const CryptoBackend::Protocol * const backend = CryptoBackendFactory::instance()->protocol( proto ); kleo_assert( backend ); bool shouldArmor = ( proto == OpenPGP || q->asciiArmor() ) && !output->binaryOpt(); std::auto_ptr encryptJob( backend->encryptJob( shouldArmor, /*textmode=*/false ) ); kleo_assert( encryptJob.get() ); if ( proto == CMS && !q->asciiArmor() && !output->binaryOpt() ) encryptJob->setOutputIsBase64Encoded( true ); connect( encryptJob.get(), SIGNAL(progress(QString,int,int)), q, SLOT(setProgress(QString,int,int)) ); connect( encryptJob.get(), SIGNAL(result(GpgME::EncryptionResult,QByteArray)), q, SLOT(slotResult(GpgME::EncryptionResult)) ); return encryptJob; } void EncryptEMailTask::Private::slotResult( const EncryptionResult & result ) { const Job * const job = qobject_cast( q->sender() ); if ( result.error().code() ) { output->cancel(); } else { output->finalize(); } q->emitResult( shared_ptr( new EncryptEMailResult( result, AuditLog::fromJob( job ) ) ) ); } QString EncryptEMailResult::overview() const { return makeOverview( makeResultString( m_result ) ); } QString EncryptEMailResult::details() const { return QString(); } int EncryptEMailResult::errorCode() const { return m_result.error().encodedError(); } QString EncryptEMailResult::errorString() const { return hasError() ? makeResultString( m_result ) : QString(); } AuditLog EncryptEMailResult::auditLog() const { return m_auditLog; } Task::Result::VisualCode EncryptEMailResult::code() const { if ( m_result.error().isCanceled() ) return Warning; return m_result.error().code() ? NeutralError : NeutralSuccess; } #include "moc_encryptemailtask.cpp" diff --git a/kleopatra/crypto/encryptemailtask.h b/kleopatra/crypto/encryptemailtask.h index d626e0e2b0..e3bc32aa5b 100644 --- a/kleopatra/crypto/encryptemailtask.h +++ b/kleopatra/crypto/encryptemailtask.h @@ -1,87 +1,89 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/encryptemailtask.h This file is part of Kleopatra, the KDE keymanager Copyright (c) 2007 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #ifndef __KLEOPATRA_CRYPTO_ENCRYPTEMAILTASK_H__ #define __KLEOPATRA_CRYPTO_ENCRYPTEMAILTASK_H__ #include #include #include +#ifndef Q_MOC_RUN #include +#endif #include namespace GpgME { class Key; } namespace Kleo { class Input; class Output; } namespace Kleo { namespace Crypto { class EncryptEMailTask : public Task { Q_OBJECT public: explicit EncryptEMailTask( QObject * parent=0 ); ~EncryptEMailTask(); void setInput( const boost::shared_ptr & input ); void setOutput( const boost::shared_ptr & output ); void setRecipients( const std::vector & recipients ); GpgME::Protocol protocol() const; /* reimp */ void cancel(); /* reimp */ QString label() const; private: /* reimp */ void doStart(); /* reimp */ unsigned long long inputSize() const; private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT( d, void slotResult( const GpgME::EncryptionResult & ) ) }; } } #endif /* __KLEOPATRA_CRYPTO_ENCRYPTEMAILTASK_H__ */ diff --git a/kleopatra/crypto/gui/decryptverifyfileswizard.cpp b/kleopatra/crypto/gui/decryptverifyfileswizard.cpp index c0a7d7d2b1..9a3405f572 100644 --- a/kleopatra/crypto/gui/decryptverifyfileswizard.cpp +++ b/kleopatra/crypto/gui/decryptverifyfileswizard.cpp @@ -1,268 +1,270 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/gui/decryptverifywizard.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2007 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "decryptverifyfileswizard.h" #include "decryptverifyoperationwidget.h" #include #include #include #include #include #include #include #include "libkleo/ui/filenamerequester.h" #include #include #include #include #include #include #include +#ifndef Q_MOC_RUN #include +#endif #include #include using namespace Kleo; using namespace Kleo::Crypto; using namespace Kleo::Crypto::Gui; using namespace boost; namespace { class HLine : public QFrame { Q_OBJECT public: explicit HLine( QWidget * p=0, Qt::WindowFlags f=0 ) : QFrame( p, f ) { setFrameStyle( QFrame::HLine|QFrame::Sunken ); } }; class OperationsWidget : public WizardPage { Q_OBJECT public: explicit OperationsWidget( QWidget * p=0 ); ~OperationsWidget(); void setOutputDirectory( const QString & dir ) { m_ui.outputDirectoryFNR.setFileName( dir ); } QString outputDirectory() const { return m_ui.outputDirectoryFNR.fileName(); } bool useOutputDirectory() const { return m_ui.useOutputDirectoryCB.isChecked(); } void ensureIndexAvailable( unsigned int idx ); DecryptVerifyOperationWidget * widget( unsigned int idx ) { return m_widgets.at( idx ); } bool isComplete() const { return true; } private: std::vector m_widgets; struct UI { QCheckBox useOutputDirectoryCB; QLabel outputDirectoryLB; FileNameRequester outputDirectoryFNR; ScrollArea scrollArea; // ### replace with KDScrollArea when done QVBoxLayout vlay; QHBoxLayout hlay; explicit UI( OperationsWidget * q ); } m_ui; }; } class DecryptVerifyFilesWizard::Private { friend class ::Kleo::Crypto::Gui::DecryptVerifyFilesWizard; DecryptVerifyFilesWizard * const q; public: Private( DecryptVerifyFilesWizard * qq ); ~Private(); void ensureIndexAvailable( unsigned int idx ) { operationsPage.ensureIndexAvailable( idx ); } private: OperationsWidget operationsPage; Gui::ResultPage resultPage; }; DecryptVerifyFilesWizard::DecryptVerifyFilesWizard( QWidget * p, Qt::WindowFlags f ) : Wizard( p, f ), d( new Private( this ) ) { } DecryptVerifyFilesWizard::~DecryptVerifyFilesWizard() {} void DecryptVerifyFilesWizard::setOutputDirectory( const QString & dir ) { d->operationsPage.setOutputDirectory( dir ); } QString DecryptVerifyFilesWizard::outputDirectory() const { return d->operationsPage.outputDirectory(); } bool DecryptVerifyFilesWizard::useOutputDirectory() const { return d->operationsPage.useOutputDirectory(); } DecryptVerifyOperationWidget * DecryptVerifyFilesWizard::operationWidget( unsigned int idx ) { d->ensureIndexAvailable( idx ); return d->operationsPage.widget( idx ); } void DecryptVerifyFilesWizard::onNext( int id ) { if ( id == OperationsPage ) QTimer::singleShot( 0, this, SIGNAL(operationPrepared()) ); Wizard::onNext( id ); } void DecryptVerifyFilesWizard::setTaskCollection( const shared_ptr & coll ) { kleo_assert( coll ); d->resultPage.setTaskCollection( coll ); } DecryptVerifyFilesWizard::Private::Private( DecryptVerifyFilesWizard * qq ) : q( qq ), operationsPage( q ), resultPage( q ) { q->setPage( DecryptVerifyFilesWizard::OperationsPage, &operationsPage ); q->setPage( DecryptVerifyFilesWizard::ResultPage, &resultPage ); connect( &resultPage, SIGNAL(linkActivated(QString)), q, SIGNAL(linkActivated(QString)) ); std::vector order; order.push_back( DecryptVerifyFilesWizard::OperationsPage ); order.push_back( DecryptVerifyFilesWizard::ResultPage ); q->setPageOrder( order ); operationsPage.setCommitPage( true ); } DecryptVerifyFilesWizard::Private::~Private() {} OperationsWidget::OperationsWidget( QWidget * p ) : WizardPage( p ), m_widgets(), m_ui( this ) { setTitle( i18n("Choose operations to be performed") ); setSubTitle( i18n("Here you can check and, if needed, override " "the operations Kleopatra detected for the input given.") ); setCommitPage( true ); setCustomNextButton( KGuiItem( i18n( "&Decrypt/Verify" ) ) ); } OperationsWidget::~OperationsWidget() {} OperationsWidget::UI::UI( OperationsWidget * q ) : useOutputDirectoryCB( i18n( "Create all output files in a single folder" ), q ), outputDirectoryLB( i18n("&Output folder:"), q ), outputDirectoryFNR( q ), scrollArea( q ), vlay( q ), hlay() { KDAB_SET_OBJECT_NAME( useOutputDirectoryCB ); KDAB_SET_OBJECT_NAME( outputDirectoryLB ); KDAB_SET_OBJECT_NAME( outputDirectoryFNR ); KDAB_SET_OBJECT_NAME( scrollArea ); KDAB_SET_OBJECT_NAME( vlay ); KDAB_SET_OBJECT_NAME( hlay ); outputDirectoryFNR.setFilter( QDir::Dirs ); useOutputDirectoryCB.setChecked( true ); connect( &useOutputDirectoryCB, SIGNAL(toggled(bool)), &outputDirectoryLB, SLOT(setEnabled(bool)) ); connect( &useOutputDirectoryCB, SIGNAL(toggled(bool)), &outputDirectoryFNR, SLOT(setEnabled(bool)) ); assert( qobject_cast(scrollArea.widget()->layout()) ); static_cast(scrollArea.widget()->layout())->addStretch( 1 ); outputDirectoryLB.setBuddy( &outputDirectoryFNR ); hlay.setMargin( 0 ); vlay.addWidget( &scrollArea, 1 ); vlay.addWidget( &useOutputDirectoryCB ); vlay.addLayout( &hlay ); hlay.addWidget( &outputDirectoryLB ); hlay.addWidget( &outputDirectoryFNR ); } void OperationsWidget::ensureIndexAvailable( unsigned int idx ) { if ( idx < m_widgets.size() ) return; assert( m_ui.scrollArea.widget() ); assert( qobject_cast( m_ui.scrollArea.widget()->layout() ) ); QBoxLayout & blay = *static_cast( m_ui.scrollArea.widget()->layout() ); for ( unsigned int i = m_widgets.size() ; i < idx+1 ; ++i ) { if ( i ) blay.insertWidget( blay.count()-1, new HLine( m_ui.scrollArea.widget() ) ); DecryptVerifyOperationWidget * w = new DecryptVerifyOperationWidget( m_ui.scrollArea.widget() ); blay.insertWidget( blay.count()-1, w ); w->show(); m_widgets.push_back( w ); } } #include "decryptverifyfileswizard.moc" diff --git a/kleopatra/crypto/gui/decryptverifyfileswizard.h b/kleopatra/crypto/gui/decryptverifyfileswizard.h index 9daa48c9b7..597c927f31 100644 --- a/kleopatra/crypto/gui/decryptverifyfileswizard.h +++ b/kleopatra/crypto/gui/decryptverifyfileswizard.h @@ -1,86 +1,88 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/gui/decryptverifyfileswizard.h This file is part of Kleopatra, the KDE keymanager Copyright (c) 2007 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #ifndef __KLEOPATRA_CRYPTO_GUI_DECRYPTVERIFYFILESWIZARD_H__ #define __KLEOPATRA_CRYPTO_GUI_DECRYPTVERIFYFILESWIZARD_H__ #include #include +#ifndef Q_MOC_RUN #include +#endif namespace Kleo { namespace Crypto { class Task; class TaskCollection; namespace Gui { class DecryptVerifyOperationWidget; class ResultDisplayWidget; class DecryptVerifyFilesWizard : public Wizard { Q_OBJECT public: enum Page { OperationsPage=0, ResultPage }; explicit DecryptVerifyFilesWizard( QWidget * parent=0, Qt::WindowFlags f=0 ); ~DecryptVerifyFilesWizard(); void setOutputDirectory( const QString & dir ); QString outputDirectory() const; bool useOutputDirectory() const; void setTaskCollection( const boost::shared_ptr & coll ); DecryptVerifyOperationWidget * operationWidget( unsigned int idx ); Q_SIGNALS: void operationPrepared(); void linkActivated( const QString & link ); private: /* reimpl */ void onNext( int id ); private: class Private; kdtools::pimpl_ptr d; }; } } } #endif /* __KLEOPATRA_CRYPTO_GUI_DECRYPTVERIFYFILESWIZARD_H__ */ diff --git a/kleopatra/crypto/gui/decryptverifyoperationwidget.cpp b/kleopatra/crypto/gui/decryptverifyoperationwidget.cpp index f70566c2c1..e33a57b47f 100644 --- a/kleopatra/crypto/gui/decryptverifyoperationwidget.cpp +++ b/kleopatra/crypto/gui/decryptverifyoperationwidget.cpp @@ -1,255 +1,257 @@ /* -*- mode: c++; c-basic-offset:4 -*- uiserver/decryptverifyoperationwidget.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2007 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "decryptverifyoperationwidget.h" #include #include "libkleo/ui/filenamerequester.h" #include #include #include #include #include +#ifndef Q_MOC_RUN #include +#endif using namespace Kleo; using namespace Kleo::Crypto::Gui; using namespace boost; class DecryptVerifyOperationWidget::Private { friend class ::Kleo::Crypto::Gui::DecryptVerifyOperationWidget; DecryptVerifyOperationWidget * const q; public: explicit Private( DecryptVerifyOperationWidget * qq ); ~Private(); void enableDisableWidgets() { const bool detached = ui.verifyDetachedCB.isChecked(); const bool archive = ui.archiveCB.isChecked(); ui.archiveCB.setEnabled( !detached ); ui.archivesCB.setEnabled( archive && !detached ); } private: struct UI { QGridLayout glay; QLabel inputLB; QStackedLayout inputStack; QLabel inputFileNameLB; FileNameRequester inputFileNameRQ; //------ QCheckBox verifyDetachedCB; //------ QLabel signedDataLB; QStackedLayout signedDataStack; QLabel signedDataFileNameLB; FileNameRequester signedDataFileNameRQ; //------ QHBoxLayout hlay; QCheckBox archiveCB; QComboBox archivesCB; explicit UI( DecryptVerifyOperationWidget * q ); } ui; }; DecryptVerifyOperationWidget::Private::UI::UI( DecryptVerifyOperationWidget * q ) : glay( q ), inputLB( i18n("Input file:"), q ), inputStack(), inputFileNameLB( q ), inputFileNameRQ( q ), verifyDetachedCB( i18n("&Input file is a detached signature"), q ), signedDataLB( i18n("&Signed data:"), q ), signedDataStack(), signedDataFileNameLB( q ), signedDataFileNameRQ( q ), hlay(), archiveCB( i18n("&Input file is an archive; unpack with:"), q ), archivesCB( q ) { KDAB_SET_OBJECT_NAME( glay ); KDAB_SET_OBJECT_NAME( inputLB ); KDAB_SET_OBJECT_NAME( inputStack ); KDAB_SET_OBJECT_NAME( inputFileNameLB ); KDAB_SET_OBJECT_NAME( inputFileNameRQ ); KDAB_SET_OBJECT_NAME( verifyDetachedCB ); KDAB_SET_OBJECT_NAME( signedDataLB ); KDAB_SET_OBJECT_NAME( signedDataStack ); KDAB_SET_OBJECT_NAME( signedDataFileNameLB ); KDAB_SET_OBJECT_NAME( signedDataFileNameRQ ); KDAB_SET_OBJECT_NAME( hlay ); KDAB_SET_OBJECT_NAME( archiveCB ); KDAB_SET_OBJECT_NAME( archivesCB ); inputStack.setMargin( 0 ); signedDataStack.setMargin( 0 ); signedDataLB.setEnabled( false ); signedDataFileNameLB.setEnabled( false ); signedDataFileNameRQ.setEnabled( false ); archivesCB.setEnabled( false ); glay.setMargin( 0 ); glay.addWidget( &inputLB, 0, 0 ); glay.addLayout( &inputStack, 0, 1 ); inputStack.addWidget( &inputFileNameLB ); inputStack.addWidget( &inputFileNameRQ ); glay.addWidget( &verifyDetachedCB, 1, 0, 1, 2 ); glay.addWidget( &signedDataLB, 2, 0 ); glay.addLayout( &signedDataStack, 2, 1 ); signedDataStack.addWidget( &signedDataFileNameLB ); signedDataStack.addWidget( &signedDataFileNameRQ ); glay.addLayout( &hlay, 3, 0, 1, 2 ); hlay.addWidget( &archiveCB ); hlay.addWidget( &archivesCB, 1 ); connect( &verifyDetachedCB, SIGNAL(toggled(bool)), &signedDataLB, SLOT(setEnabled(bool)) ); connect( &verifyDetachedCB, SIGNAL(toggled(bool)), &signedDataFileNameLB, SLOT(setEnabled(bool)) ); connect( &verifyDetachedCB, SIGNAL(toggled(bool)), &signedDataFileNameRQ, SLOT(setEnabled(bool)) ); connect( &verifyDetachedCB, SIGNAL(toggled(bool)), q, SLOT(enableDisableWidgets()) ); connect( &archiveCB, SIGNAL(toggled(bool)), q, SLOT(enableDisableWidgets()) ); } DecryptVerifyOperationWidget::Private::Private( DecryptVerifyOperationWidget * qq ) : q( qq ), ui( q ) { } DecryptVerifyOperationWidget::Private::~Private() {} DecryptVerifyOperationWidget::DecryptVerifyOperationWidget( QWidget * p ) : QWidget( p ), d( new Private( this ) ) { setMode( DecryptVerifyOpaque ); } DecryptVerifyOperationWidget::~DecryptVerifyOperationWidget() {} void DecryptVerifyOperationWidget::setArchiveDefinitions( const std::vector< shared_ptr > & archiveDefinitions ) { d->ui.archivesCB.clear(); Q_FOREACH( const shared_ptr & ad, archiveDefinitions ) d->ui.archivesCB.addItem( ad->label(), qVariantFromValue( ad ) ); } static const int Mutable = 1; static const int Const = 0; void DecryptVerifyOperationWidget::setMode( Mode mode ) { setMode( mode, shared_ptr() ); } void DecryptVerifyOperationWidget::setMode( Mode mode, const shared_ptr & ad ) { d->ui.verifyDetachedCB.setChecked( mode != DecryptVerifyOpaque ); QWidget * inputWidget; QWidget * signedDataWidget; if ( mode == VerifyDetachedWithSignedData ) { inputWidget = &d->ui.inputFileNameRQ; signedDataWidget = &d->ui.signedDataFileNameLB; } else { inputWidget = &d->ui.inputFileNameLB; signedDataWidget = &d->ui.signedDataFileNameRQ; } d->ui.inputStack.setCurrentWidget( inputWidget ); d->ui.signedDataStack.setCurrentWidget( signedDataWidget ); d->ui.inputLB.setBuddy( inputWidget ); d->ui.signedDataLB.setBuddy( signedDataWidget ); d->ui.archiveCB.setChecked( ad.get() != 0 ); for ( int i = 0, end = d->ui.archivesCB.count() ; i != end ; ++i ) if ( ad == d->ui.archivesCB.itemData( i ).value< shared_ptr >() ) { d->ui.archivesCB.setCurrentIndex( i ); return; } } DecryptVerifyOperationWidget::Mode DecryptVerifyOperationWidget::mode() const { if ( d->ui.verifyDetachedCB.isChecked() ) if ( d->ui.inputStack.currentIndex() == Const ) return VerifyDetachedWithSignature; else return VerifyDetachedWithSignedData; else return DecryptVerifyOpaque; } void DecryptVerifyOperationWidget::setInputFileName( const QString & name ) { d->ui.inputFileNameLB.setText( name ); d->ui.inputFileNameRQ.setFileName( name ); } QString DecryptVerifyOperationWidget::inputFileName() const { if ( d->ui.inputStack.currentIndex() == Const ) return d->ui.inputFileNameLB.text(); else return d->ui.inputFileNameRQ.fileName(); } void DecryptVerifyOperationWidget::setSignedDataFileName( const QString & name ) { d->ui.signedDataFileNameLB.setText( name ); d->ui.signedDataFileNameRQ.setFileName( name ); } QString DecryptVerifyOperationWidget::signedDataFileName() const { if ( d->ui.signedDataStack.currentIndex() == Const ) return d->ui.signedDataFileNameLB.text(); else return d->ui.signedDataFileNameRQ.fileName(); } shared_ptr DecryptVerifyOperationWidget::selectedArchiveDefinition() const { if ( mode() == DecryptVerifyOpaque && d->ui.archiveCB.isChecked() ) return d->ui.archivesCB.itemData( d->ui.archivesCB.currentIndex() ).value< shared_ptr >(); else return shared_ptr(); } #include "moc_decryptverifyoperationwidget.cpp" diff --git a/kleopatra/crypto/gui/newresultpage.cpp b/kleopatra/crypto/gui/newresultpage.cpp index 53993d1406..57822def34 100644 --- a/kleopatra/crypto/gui/newresultpage.cpp +++ b/kleopatra/crypto/gui/newresultpage.cpp @@ -1,239 +1,241 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/gui/resultpage.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2008 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "newresultpage.h" #include "resultlistwidget.h" #include "resultitemwidget.h" #include #include +#ifndef Q_MOC_RUN #include +#endif #include #include #include #include #include #include #include #include static const int ProgressBarHideDelay = 2000; // 2 secs using namespace Kleo; using namespace Kleo::Crypto; using namespace Kleo::Crypto::Gui; using namespace boost; class NewResultPage::Private { NewResultPage* const q; public: explicit Private( NewResultPage* qq ); void progress( const QString & msg, int progress, int total ); void result( const shared_ptr & result ); void started( const shared_ptr & result ); void allDone(); void keepOpenWhenDone( bool keep ); QLabel * labelForTag( const QString & tag ); std::vector< shared_ptr > m_collections; QTimer m_hideProgressTimer; QProgressBar* m_progressBar; QHash m_progressLabelByTag; QVBoxLayout* m_progressLabelLayout; int m_lastErrorItemIndex; ResultListWidget* m_resultList; QCheckBox* m_keepOpenCB; }; NewResultPage::Private::Private( NewResultPage* qq ) : q( qq ), m_lastErrorItemIndex( 0 ) { m_hideProgressTimer.setInterval( ProgressBarHideDelay ); m_hideProgressTimer.setSingleShot( true ); QBoxLayout* const layout = new QVBoxLayout( q ); QWidget* const labels = new QWidget; m_progressLabelLayout = new QVBoxLayout( labels ); layout->addWidget( labels ); m_progressBar = new QProgressBar; layout->addWidget( m_progressBar ); m_resultList = new ResultListWidget; connect( m_resultList, SIGNAL(linkActivated(QString)), q, SIGNAL(linkActivated(QString)) ); layout->addWidget( m_resultList, 1 ); m_keepOpenCB = new QCheckBox; m_keepOpenCB->setText( i18n( "Keep open after operation completed" ) ); m_keepOpenCB->setChecked(true ); connect( m_keepOpenCB, SIGNAL(toggled(bool)), q, SLOT(keepOpenWhenDone(bool)) ); layout->addWidget( m_keepOpenCB ); connect( &m_hideProgressTimer, SIGNAL(timeout()), m_progressBar, SLOT(hide()) ); } void NewResultPage::Private::progress( const QString & msg, int progress, int total ) { Q_UNUSED( msg ); assert( progress >= 0 ); assert( total >= 0 ); m_progressBar->setRange( 0, total ); m_progressBar->setValue( progress ); } void NewResultPage::Private::keepOpenWhenDone( bool ) { } void NewResultPage::Private::allDone() { assert( !m_collections.empty() ); if ( !m_resultList->isComplete() ) return; m_progressBar->setRange( 0, 100 ); m_progressBar->setValue( 100 ); const bool errorOccurred = kdtools::any( m_collections, mem_fn( &TaskCollection::errorOccurred ) ); m_collections.clear(); Q_FOREACH ( const QString &i, m_progressLabelByTag.keys() ) { //krazy:exclude=foreach if ( !i.isEmpty() ) { m_progressLabelByTag.value( i )->setText( i18n( "%1: All operations completed.", i ) ); } else { m_progressLabelByTag.value( i )->setText( i18n( "All operations completed." ) ); } } if ( QAbstractButton * cancel = q->wizard()->button( QWizard::CancelButton ) ) cancel->setEnabled( false ); emit q->completeChanged(); if ( !m_keepOpenCB->isChecked() && !errorOccurred ) if ( QWizard * wiz = q->wizard() ) if ( QAbstractButton * btn = wiz->button( QWizard::FinishButton ) ) QTimer::singleShot( 500, btn, SLOT(animateClick()) ); m_hideProgressTimer.start(); } void NewResultPage::Private::result( const shared_ptr & ) { } void NewResultPage::Private::started( const shared_ptr & task ) { assert( task ); const QString tag = task->tag(); QLabel * const label = labelForTag( tag ); assert( label ); if ( tag.isEmpty() ) label->setText( i18nc( "number, operation description", "Operation %1: %2", m_resultList->numberOfCompletedTasks() + 1, task->label() ) ); else label->setText( i18nc( "tag( \"OpenPGP\" or \"CMS\"), operation description", "%1: %2", tag, task->label() ) ); } NewResultPage::NewResultPage( QWidget * parent ) : QWizardPage( parent ), d( new Private( this ) ) { setTitle( i18n( "Results" ) ); } NewResultPage::~NewResultPage() { } bool NewResultPage::keepOpenWhenDone() const { return d->m_keepOpenCB->isChecked(); } void NewResultPage::setKeepOpenWhenDone( bool keep ) { d->m_keepOpenCB->setChecked( keep ); } void NewResultPage::setKeepOpenWhenDoneShown( bool on ) { d->m_keepOpenCB->setVisible( on ); if ( !on ) d->m_keepOpenCB->setChecked( true ); } void NewResultPage::setTaskCollection( const shared_ptr & coll ) { //clear(); ### PENDING(marc) implement addTaskCollection( coll ); } void NewResultPage::addTaskCollection( const shared_ptr & coll ) { assert( coll ); if ( kdtools::contains( d->m_collections, coll ) ) return; d->m_hideProgressTimer.stop(); d->m_progressBar->show(); d->m_collections.push_back( coll ); d->m_resultList->addTaskCollection( coll ); connect( coll.get(), SIGNAL(progress(QString,int,int)), this, SLOT(progress(QString,int,int)) ); connect( coll.get(), SIGNAL(done()), this, SLOT(allDone()) ); connect( coll.get(), SIGNAL(result(boost::shared_ptr)), this, SLOT(result(boost::shared_ptr)) ); connect( coll.get(), SIGNAL(started(boost::shared_ptr)), this, SLOT(started(boost::shared_ptr)) ); Q_FOREACH ( const shared_ptr & i, coll->tasks() ) { // create labels for all tags in collection assert( i ); QLabel * l = d->labelForTag( i->tag() ); assert( l ); (void)l; } emit completeChanged(); } QLabel* NewResultPage::Private::labelForTag( const QString & tag ) { if ( QLabel * const label = m_progressLabelByTag.value( tag ) ) return label; QLabel* label = new QLabel; label->setTextFormat( Qt::RichText ); label->setWordWrap( true ); m_progressLabelLayout->addWidget( label ); m_progressLabelByTag.insert( tag, label ); return label; } bool NewResultPage::isComplete() const { return d->m_resultList->isComplete(); } #include "moc_newresultpage.cpp" diff --git a/kleopatra/crypto/gui/newsignencryptfileswizard.cpp b/kleopatra/crypto/gui/newsignencryptfileswizard.cpp index 1d1155149f..b0491807b9 100644 --- a/kleopatra/crypto/gui/newsignencryptfileswizard.cpp +++ b/kleopatra/crypto/gui/newsignencryptfileswizard.cpp @@ -1,1110 +1,1112 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/gui/newsignencryptfileswizard.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2009 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "newsignencryptfileswizard.h" #include "newresultpage.h" #include "signingcertificateselectionwidget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#ifndef Q_MOC_RUN #include #include +#endif using namespace GpgME; using namespace boost; using namespace Kleo; using namespace Kleo::Crypto; using namespace Kleo::Crypto::Gui; enum Page { OperationPageId, RecipientsPageId, SignerPageId, ResultPageId, NumPages }; static void enable_disable( QAbstractButton & button, const QAbstractItemView * view ) { const QItemSelectionModel * ism = view ? view->selectionModel() : 0 ; button.setEnabled( ism && ism->hasSelection() ); } static void copy_selected_from_to( KeyTreeView & from, KeyTreeView & to ) { to.addKeysSelected( from.selectedKeys() ); from.view()->selectionModel()->clearSelection(); } static void move_selected_from_to( KeyTreeView & from, KeyTreeView & to ) { const std::vector keys = from.selectedKeys(); from.removeKeys( keys ); to.addKeysSelected( keys ); } static void remove_all_keys_not_xyz( KeyTreeView & ktv, Protocol proto ) { const std::vector k = kdtools::copy_if< std::vector >( ktv.keys(), boost::bind( &Key::protocol, _1 ) != proto ); ktv.removeKeys( k ); } static QString join_max( const QStringList & sl, const int max, const QString & glue ) { return QStringList( sl.mid( 0, max ) ).join( glue ); } namespace { // Simple dialog to show a list of files class ListDialog : public QDialog { Q_OBJECT public: explicit ListDialog( const QStringList & files, QWidget * parent=0 ) : QDialog( parent ), listWidget( this ), buttonBox( QDialogButtonBox::Close, Qt::Vertical, this ), hlay( this ) { setWindowTitle( i18nc("@title:window","Selected Files") ); KDAB_SET_OBJECT_NAME( listWidget ); KDAB_SET_OBJECT_NAME( buttonBox ); KDAB_SET_OBJECT_NAME( hlay ); listWidget.setSelectionMode( QListWidget::NoSelection ); listWidget.addItems( files ); hlay.addWidget( &listWidget ); hlay.addWidget( &buttonBox ); connect( &buttonBox, SIGNAL(rejected()), this, SLOT(reject()) ); } private: QListWidget listWidget; QDialogButtonBox buttonBox; QHBoxLayout hlay; }; // // This is a simple QLabel subclass, used mainly to have a widget // for the 'files' field of the wizard (though that one's unused as of now). // class ObjectsLabel : public QLabel { Q_OBJECT // ### PENDING(marc) deal with lots of files (->listbox) Q_PROPERTY( QStringList files READ files WRITE setFiles ) public: static const int MaxLinesShownInline = 5; explicit ObjectsLabel( QWidget * parent=0, Qt::WindowFlags f=0 ) : QLabel( parent, f ), m_dialog(), m_files( dummyFiles() ) { connect( this, SIGNAL(linkActivated(QString)), this, SLOT(slotLinkActivated()) ); updateText(); // updateGeometry() doesn't seem to reset the // minimumSizeHint(), using max-height dummy text here // does... Go figure m_files.clear(); } explicit ObjectsLabel( const QStringList & files, QWidget * parent=0, Qt::WindowFlags f=0 ) : QLabel( parent, f ), m_dialog(), m_files( files ) { connect( this, SIGNAL(linkActivated(QString)), this, SLOT(slotLinkActivated()) ); updateText(); } QStringList files() const { return m_files; } void setFiles( const QStringList & files ) { if ( m_files == files ) return; m_files = files; updateText(); } private Q_SLOTS: void slotLinkActivated() { if ( !m_dialog ) { m_dialog = new ListDialog( m_files, this ); m_dialog->setAttribute( Qt::WA_DeleteOnClose ); } if ( m_dialog->isVisible() ) m_dialog->raise(); else m_dialog->show(); } private: static QStringList dummyFiles() { QStringList dummy; for ( int i = 0 ; i < MaxLinesShownInline+1 ; ++i ) dummy.push_back( QString::number( i ) ); return dummy; } QString makeText() const { if ( m_files.empty() ) return QLatin1String("

") + i18n("No files selected.") + QLatin1String("

"); QString html = QLatin1String("

") + i18np("Selected file:", "Selected files:", m_files.size() ) + QLatin1String("

") + QLatin1String("
  • ") + join_max( m_files, MaxLinesShownInline, QLatin1String("
  • ") ) + QLatin1String("
") ; if ( m_files.size() > MaxLinesShownInline ) html += QLatin1String("

") + i18nc("@action","More...") + QLatin1String("

"); return html; } void updateText() { setText( makeText() ); } private: QPointer m_dialog; QStringList m_files; }; // // Helper wrapper around Kleo::FileNameRequester that adjusts // extensions to an ArchiveDefinition // class ArchiveFileNameRequester : public Kleo::FileNameRequester { Q_OBJECT public: explicit ArchiveFileNameRequester( Protocol protocol, QWidget * parent=0 ) : FileNameRequester( QDir::Files, parent ), m_protocol( protocol ), m_archiveDefinition() { setExistingOnly( false ); } public Q_SLOTS: void setArchiveDefinition( const boost::shared_ptr & ad ) { if ( ad == m_archiveDefinition ) return; const QString oldExt = m_archiveDefinition ? m_archiveDefinition->extensions( m_protocol ).front() : QString() ; const QString newExt = ad ? ad->extensions( m_protocol ).front() : QString() ; QString fn = fileName(); if ( fn.endsWith( oldExt ) ) fn.chop( oldExt.size() + 1 ); m_archiveDefinition = ad; if ( ad ) fn += QLatin1Char('.') + newExt; FileNameRequester::setFileName( fn ); } void setFileName( const QString & fn ) { const QString ext = m_archiveDefinition ? m_archiveDefinition->extensions( m_protocol ).front() : QString() ; if ( m_archiveDefinition && !fn.endsWith( ext ) ) FileNameRequester::setFileName( fn + QLatin1Char('.') + ext ); else FileNameRequester::setFileName( fn ); } private: const Protocol m_protocol; shared_ptr m_archiveDefinition; }; class WizardPage : public QWizardPage { Q_OBJECT public: explicit WizardPage( QWidget * parent=0 ) : QWizardPage( parent ), m_presetProtocol( UnknownProtocol ) { } bool isArchiveRequested() const { return field(QLatin1String("archive")).toBool(); } QString archiveName( Protocol p ) const { return field( p == OpenPGP ? QLatin1String("archive-name-pgp") : QLatin1String("archive-name-cms" )).toString(); } bool isRemoveUnencryptedFilesEnabled() const { return field(QLatin1String("remove")).toBool(); } bool isSignOnlySelected() const { return field(QLatin1String("sign")).toBool(); } bool isEncryptOnlySelected() const { return field(QLatin1String("encrypt")).toBool(); } bool isSignEncryptSelected() const { return field(QLatin1String("signencrypt")).toBool() ; } bool isSigningSelected() const { return isSignOnlySelected() || isSignEncryptSelected() ; } bool isEncryptionSelected() const { return isEncryptOnlySelected() || isSignEncryptSelected() ; } Protocol protocol() const { return m_presetProtocol; } Protocol effectiveProtocol() const { if ( isSignEncryptSelected() ) { assert( m_presetProtocol == OpenPGP || m_presetProtocol == UnknownProtocol ); return OpenPGP; } else { return m_presetProtocol; } } void setPresetProtocol( Protocol proto ) { if ( proto == m_presetProtocol ) return; m_presetProtocol = proto; doSetPresetProtocol(); } private: virtual void doSetPresetProtocol() {} private: Protocol m_presetProtocol; }; class OperationPage : public WizardPage { Q_OBJECT Q_PROPERTY( QStringList files READ files WRITE setFiles ) Q_PROPERTY( bool signingPreset READ isSigningPreset WRITE setSigningPreset ) Q_PROPERTY( bool signingUserMutable READ isSigningUserMutable WRITE setSigningUserMutable ) Q_PROPERTY( bool encryptionPreset READ isEncryptionPreset WRITE setEncryptionPreset ) Q_PROPERTY( bool encryptionUserMutable READ isEncryptionUserMutable WRITE setEncryptionUserMutable ) Q_PROPERTY( bool archiveUserMutable READ isArchiveUserMutable WRITE setArchiveUserMutable ) public: explicit OperationPage( QWidget * parent=0 ) : WizardPage( parent ), m_objectsLabel( this ), m_archiveCB( i18n("Archive files with:"), this ), m_archive( this ), m_archiveNamePgpLB( i18n("Archive name (OpenPGP):"), this ), m_archiveNamePgp( OpenPGP, this ), m_archiveNameCmsLB( i18n("Archive name (S/MIME):"), this ), m_archiveNameCms( CMS, this ), m_signencrypt( i18n("Sign and Encrypt (OpenPGP only)"), this ), m_encrypt( i18n("Encrypt"), this ), m_sign( i18n("Sign"), this ), m_armor( i18n("Text output (ASCII armor)"), this ), m_removeSource( i18n("Remove unencrypted original file when done"), this ), m_signingUserMutable( true ), m_encryptionUserMutable( true ), m_archiveUserMutable( true ), m_signingPreset( true ), m_encryptionPreset( true ), m_archiveDefinitions( ArchiveDefinition::getArchiveDefinitions() ) { setTitle( i18nc("@title","What do you want to do?") ); setSubTitle( i18nc("@title", "Please select here whether you want to sign or encrypt files.") ); KDAB_SET_OBJECT_NAME( m_objectsLabel ); KDAB_SET_OBJECT_NAME( m_signencrypt ); KDAB_SET_OBJECT_NAME( m_encrypt ); KDAB_SET_OBJECT_NAME( m_sign ); KDAB_SET_OBJECT_NAME( m_archiveCB ); KDAB_SET_OBJECT_NAME( m_archive ); KDAB_SET_OBJECT_NAME( m_archiveNamePgpLB ); KDAB_SET_OBJECT_NAME( m_archiveNamePgp ); KDAB_SET_OBJECT_NAME( m_archiveNameCmsLB ); KDAB_SET_OBJECT_NAME( m_archiveNameCms ); KDAB_SET_OBJECT_NAME( m_armor ); KDAB_SET_OBJECT_NAME( m_removeSource ); QGridLayout * glay = new QGridLayout; glay->addWidget( &m_archiveCB, 0, 0 ); glay->addWidget( &m_archive, 0, 1 ); glay->addWidget( &m_archiveNamePgpLB, 1, 0 ); glay->addWidget( &m_archiveNamePgp, 1, 1 ); glay->addWidget( &m_archiveNameCmsLB, 2, 0 ); glay->addWidget( &m_archiveNameCms, 2, 1 ); QVBoxLayout * vlay = new QVBoxLayout( this ); vlay->addWidget( &m_objectsLabel ); vlay->addLayout( glay ); vlay->addWidget( &m_signencrypt ); vlay->addWidget( &m_encrypt ); vlay->addWidget( &m_sign ); vlay->addStretch( 1 ); vlay->addWidget( &m_armor ); vlay->addWidget( &m_removeSource ); m_archiveNamePgpLB.setAlignment( Qt::AlignRight ); m_archiveNamePgpLB.setBuddy( &m_archiveNamePgp ); m_archiveNameCmsLB.setAlignment( Qt::AlignRight ); m_archiveNameCmsLB.setBuddy( &m_archiveNameCms ); m_armor.setChecked( false ); m_archive.setEnabled( false ); m_archiveNamePgpLB.setEnabled( false ); m_archiveNamePgp.setEnabled( false ); m_archiveNameCmsLB.setEnabled( false ); m_archiveNameCms.setEnabled( false ); Q_FOREACH( const shared_ptr & ad, m_archiveDefinitions ) m_archive.addItem( ad->label(), qVariantFromValue( ad ) ); registerField( QLatin1String("files"), this, "files" ); registerField( QLatin1String("signing-preset"), this, "signingPreset" ); registerField( QLatin1String("encryption-preset"), this, "encryptionPreset" ); registerField( QLatin1String("signencrypt"), &m_signencrypt ); registerField( QLatin1String("encrypt"), &m_encrypt ); registerField( QLatin1String("sign"), &m_sign ); registerField( QLatin1String("armor"), &m_armor ); registerField( QLatin1String("remove"), &m_removeSource ); registerField( QLatin1String("archive"), &m_archiveCB ); registerField( QLatin1String("archive-id"), &m_archive ); registerField( QLatin1String("archive-name-pgp"), &m_archiveNamePgp, "fileName" ); registerField( QLatin1String("archive-name-cms"), &m_archiveNameCms, "fileName" ); registerField( QLatin1String("signing-user-mutable"), this, "signingUserMutable" ); registerField( QLatin1String("encryption-user-mutable"), this, "encryptionUserMutable" ); registerField( QLatin1String("archive-user-mutable"), this, "archiveUserMutable" ); connect( &m_archive, SIGNAL(currentIndexChanged(int)), this, SLOT(slotArchiveDefinitionChanged()) ); connect( &m_signencrypt, SIGNAL(clicked()), this, SIGNAL(completeChanged()) ); connect( &m_encrypt, SIGNAL(clicked()), this, SIGNAL(completeChanged()) ); connect( &m_sign, SIGNAL(clicked()), this, SIGNAL(completeChanged()) ); connect( &m_archiveCB, SIGNAL(clicked()), this, SIGNAL(completeChanged()) ); connect( &m_archiveNamePgp, SIGNAL(fileNameChanged(QString)), this, SIGNAL(completeChanged()) ); connect( &m_archiveNameCms, SIGNAL(fileNameChanged(QString)), this, SIGNAL(completeChanged()) ); connect( &m_sign, SIGNAL(toggled(bool)), &m_removeSource, SLOT(setDisabled(bool)) ); connect( &m_archiveCB, SIGNAL(toggled(bool)), &m_archive, SLOT(setEnabled(bool)) ); connect( &m_archiveCB, SIGNAL(toggled(bool)), &m_archiveNamePgpLB, SLOT(setEnabled(bool)) ); connect( &m_archiveCB, SIGNAL(toggled(bool)), &m_archiveNamePgp, SLOT(setEnabled(bool)) ); connect( &m_archiveCB, SIGNAL(toggled(bool)), &m_archiveNameCmsLB, SLOT(setEnabled(bool)) ); connect( &m_archiveCB, SIGNAL(toggled(bool)), &m_archiveNameCms, SLOT(setEnabled(bool)) ); const shared_ptr ad = archiveDefinition(); m_archiveNamePgp.setArchiveDefinition( ad ); m_archiveNameCms.setArchiveDefinition( ad ); } QStringList files() const { return m_objectsLabel.files(); } void setFiles( const QStringList & files ) { m_objectsLabel.setFiles( files ); const QString archiveName = files.size() == 1 ? files.front() : /* else */ QDir( heuristicBaseDirectory( files ) ) .absoluteFilePath( i18nc("base name of an archive file, e.g. archive.zip or archive.tar.gz", "archive") ); m_archiveNamePgp.setFileName( archiveName ); m_archiveNameCms.setFileName( archiveName ); } bool isSigningPreset() const { return m_signingPreset; } void setSigningPreset( bool preset ) { if ( m_signingPreset == preset ) return; m_signingPreset = preset; updateSignEncryptArchiveWidgetStates(); } bool isSigningUserMutable() const { return m_signingUserMutable; } void setSigningUserMutable( bool mut ) { if ( m_signingUserMutable == mut ) return; m_signingUserMutable = mut; updateSignEncryptArchiveWidgetStates(); } bool isEncryptionPreset() const { return m_encryptionPreset; } void setEncryptionPreset( bool preset ) { if ( m_encryptionPreset == preset ) return; m_encryptionPreset = preset; updateSignEncryptArchiveWidgetStates(); } bool isEncryptionUserMutable() const { return m_encryptionUserMutable; } void setEncryptionUserMutable( bool mut ) { if ( m_encryptionUserMutable == mut ) return; m_encryptionUserMutable = mut; updateSignEncryptArchiveWidgetStates(); } bool isArchiveUserMutable() const { return m_archiveUserMutable; } void setArchiveUserMutable( bool mut ) { if ( m_archiveUserMutable == mut ) return; m_archiveUserMutable = mut; updateSignEncryptArchiveWidgetStates(); } /* reimp */ bool isComplete() const { return ( !isArchiveRequested() || !archiveName( OpenPGP ).isEmpty() && !archiveName( CMS ).isEmpty() ) // ### make more permissive && ( isSigningSelected() || isEncryptionSelected() ) ; } /* reimp */ bool validatePage() { if ( isSignOnlySelected() && isArchiveRequested() ) return KMessageBox::warningContinueCancel( this, i18nc("@info", "Archiving in combination with sign-only currently requires what are known as opaque signatures - " "unlike detached ones, these embed the content in the signature." "This format is rather unusual. You might want to archive the files separately, " "and then sign the archive as one file with Kleopatra." "Future versions of Kleopatra are expected to also support detached signatures in this case." ), i18nc("@title:window", "Unusual Signature Warning"), KStandardGuiItem::cont(), KStandardGuiItem::cancel(), QLatin1String("signencryptfileswizard-archive+sign-only-warning") ) == KMessageBox::Continue ; else return true; } /* reimp */ int nextId() const { return isEncryptionSelected() ? RecipientsPageId : SignerPageId ; } /* reimp */ void doSetPresetProtocol() { updateSignEncryptArchiveWidgetStates(); } shared_ptr archiveDefinition() const { return m_archive.itemData( m_archive.currentIndex() ).value< shared_ptr >(); } void setArchiveDefinition( const shared_ptr & ad ) { m_archive.setCurrentIndex( m_archive.findData( qVariantFromValue( ad ) ) ); } void setArchiveDefinition( const QString & adName ) { const std::vector< shared_ptr >::const_iterator it = kdtools::find_if( m_archiveDefinitions, boost::bind( &ArchiveDefinition::id, _1 ) == adName ); if ( it != m_archiveDefinitions.end() ) m_archive.setCurrentIndex( it - m_archiveDefinitions.begin() ); } private Q_SLOTS: void slotArchiveDefinitionChanged() { const shared_ptr ad = archiveDefinition(); m_archiveNamePgp.setArchiveDefinition( ad ); m_archiveNameCms.setArchiveDefinition( ad ); } private: void updateSignEncryptArchiveWidgetStates() { m_archiveCB.setEnabled( m_archiveUserMutable ); const bool mustEncrypt = m_encryptionPreset && !m_encryptionUserMutable ; const bool mustSign = m_signingPreset && !m_signingUserMutable ; const bool mayEncrypt = m_encryptionPreset || m_encryptionUserMutable ; const bool maySign = m_signingPreset || m_signingUserMutable ; const bool canSignEncrypt = protocol() != CMS && mayEncrypt && maySign ; const bool canSignOnly = maySign && !mustEncrypt ; const bool canEncryptOnly = mayEncrypt && !mustSign ; m_signencrypt.setEnabled( canSignEncrypt ); m_encrypt.setEnabled( canEncryptOnly ); m_sign.setEnabled( canSignOnly ); really_check( m_signencrypt, canSignEncrypt && m_signingPreset && m_encryptionPreset ); really_check( m_encrypt, canEncryptOnly && !m_signingPreset && m_encryptionPreset ); really_check( m_sign, canSignOnly && m_signingPreset && !m_encryptionPreset ); m_signencrypt.setToolTip( protocol() == CMS ? i18n("This operation is not available for S/MIME") : QString() ); } private: ObjectsLabel m_objectsLabel; QCheckBox m_archiveCB; QComboBox m_archive; QLabel m_archiveNamePgpLB; ArchiveFileNameRequester m_archiveNamePgp; QLabel m_archiveNameCmsLB; ArchiveFileNameRequester m_archiveNameCms; QRadioButton m_signencrypt, m_encrypt, m_sign; QCheckBox m_armor, m_removeSource; bool m_signingUserMutable, m_encryptionUserMutable, m_archiveUserMutable; bool m_signingPreset, m_encryptionPreset; const std::vector< shared_ptr > m_archiveDefinitions; }; class RecipientsPage : public WizardPage { Q_OBJECT public: explicit RecipientsPage( QWidget * parent=0 ) : WizardPage( parent ), m_lastEffectiveProtocol( static_cast(-1) ), // dummy start m_searchbar( this ), m_unselectedKTV( this ), m_selectPB( i18n("Add"), this ), m_unselectPB( i18n("Remove"), this ), m_selectedKTV( this ) { setTitle( i18nc("@title","For whom do you want to encrypt?") ); setSubTitle( i18nc("@title", "Please select for whom you want the files to be encrypted. " "Do not forget to pick one of your own certificates.") ); // the button may be there or not, the _text_ is static, though: setButtonText( QWizard::CommitButton, i18nc("@action","Encrypt") ); KDAB_SET_OBJECT_NAME( m_searchbar ); KDAB_SET_OBJECT_NAME( m_unselectedKTV ); KDAB_SET_OBJECT_NAME( m_selectPB ); KDAB_SET_OBJECT_NAME( m_unselectPB ); KDAB_SET_OBJECT_NAME( m_selectedKTV ); m_selectPB.setIcon( KIcon( QLatin1String("arrow-down") ) ); m_unselectPB.setIcon( KIcon( QLatin1String("arrow-up") ) ); m_selectPB.setEnabled( false ); m_unselectPB.setEnabled( false ); m_unselectedKTV.setHierarchicalModel( AbstractKeyListModel::createHierarchicalKeyListModel( &m_unselectedKTV ) ); m_unselectedKTV.setHierarchicalView( true ); m_selectedKTV.setFlatModel( AbstractKeyListModel::createFlatKeyListModel( &m_selectedKTV ) ); m_selectedKTV.setHierarchicalView( false ); QVBoxLayout * vlay = new QVBoxLayout( this ); vlay->addWidget( &m_searchbar ); vlay->addWidget( &m_unselectedKTV, 1 ); QHBoxLayout * hlay = new QHBoxLayout; hlay->addStretch( 1 ); hlay->addWidget( &m_selectPB ); hlay->addWidget( &m_unselectPB ); hlay->addStretch( 1 ); vlay->addLayout( hlay ); vlay->addWidget( &m_selectedKTV, 1 ); xconnect( &m_searchbar, SIGNAL(stringFilterChanged(QString)), &m_unselectedKTV, SLOT(setStringFilter(QString)) ); xconnect( &m_searchbar, SIGNAL(keyFilterChanged(boost::shared_ptr)), &m_unselectedKTV, SLOT(setKeyFilter(boost::shared_ptr)) ); connect( m_unselectedKTV.view()->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(slotUnselectedSelectionChanged()) ); connect( m_selectedKTV.view()->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(slotSelectedSelectionChanged()) ); connect( &m_selectPB, SIGNAL(clicked()), this, SLOT(select()) ); connect( &m_unselectPB, SIGNAL(clicked()), this, SLOT(unselect()) ); } /* reimp */ bool isComplete() const { return !m_selectedKTV.keys().empty(); } /* reimp */ int nextId() const { if ( isSigningSelected() ) return SignerPageId; else return ResultPageId; } static bool need_reload( Protocol now, Protocol then ) { if ( then == UnknownProtocol ) return false; if ( now == UnknownProtocol ) return true; return now != then; } static bool need_grep( Protocol now, Protocol then ) { return now != UnknownProtocol && then == UnknownProtocol ; } /* reimp */ void initializePage() { setCommitPage( !isSigningSelected() ); const Protocol currentEffectiveProtocol = effectiveProtocol(); if ( need_reload( currentEffectiveProtocol, m_lastEffectiveProtocol ) ) { std::vector keys = KeyCache::instance()->keys(); _detail::grep_can_encrypt( keys ); if ( currentEffectiveProtocol != UnknownProtocol ) _detail::grep_protocol( keys, currentEffectiveProtocol ); m_unselectedKTV.setKeys( keys ); } else if ( need_grep( currentEffectiveProtocol, m_lastEffectiveProtocol ) ) { remove_all_keys_not_xyz( m_unselectedKTV, currentEffectiveProtocol ); remove_all_keys_not_xyz( m_selectedKTV, currentEffectiveProtocol ); } m_lastEffectiveProtocol = currentEffectiveProtocol; } /* reimp */ bool validatePage() { const std::vector & r = keys(); if ( _detail::none_of_secret( r ) ) { if ( KMessageBox::warningContinueCancel( this, i18nc("@info", "None of the recipients you are encrypting to seems to be your own." "This means that you will not be able to decrypt the data anymore, once encrypted." "Do you want to continue, or cancel to change the recipient selection?"), i18nc("@title:window","Encrypt-To-Self Warning"), KStandardGuiItem::cont(), KStandardGuiItem::cancel(), QLatin1String("warn-encrypt-to-non-self"), KMessageBox::Notify|KMessageBox::Dangerous ) == KMessageBox::Cancel ) return false; else if ( isRemoveUnencryptedFilesEnabled() ) if ( KMessageBox::warningContinueCancel( this, i18nc("@info", "You have requested the unencrypted data to be removed after encryption." "Are you really sure you do not need to access the data anymore in decrypted form?"), i18nc("@title:window","Encrypt-To-Self Warning"), KStandardGuiItem::cont(), KStandardGuiItem::cancel(), QLatin1String("warn-encrypt-to-non-self-destructive"), KMessageBox::Notify|KMessageBox::Dangerous ) == KMessageBox::Cancel ) return false; } return true; } const std::vector & keys() const { return m_selectedKTV.keys(); } private Q_SLOTS: void slotUnselectedSelectionChanged() { enable_disable( m_selectPB, m_unselectedKTV.view() ); } void slotSelectedSelectionChanged() { enable_disable( m_unselectPB, m_selectedKTV.view() ); } void select() { copy_selected_from_to( m_unselectedKTV, m_selectedKTV ); emit completeChanged(); } void unselect() { move_selected_from_to( m_selectedKTV, m_unselectedKTV ); emit completeChanged(); } private: Protocol m_lastEffectiveProtocol; SearchBar m_searchbar; KeyTreeView m_unselectedKTV; QPushButton m_selectPB, m_unselectPB; KeyTreeView m_selectedKTV; }; class SignerPage : public WizardPage { Q_OBJECT public: explicit SignerPage( QWidget * parent=0 ) : WizardPage( parent ), signPref(), pgpCB( i18n("Sign with OpenPGP"), this ), cmsCB( i18n("Sign with S/MIME"), this ), widget( this ) { setTitle( i18nc("@title","Who do you want to sign as?") ); setSubTitle( i18nc("@title", "Please choose an identity with which to sign the data." ) ); // this one is always a commit page setCommitPage( true ); QVBoxLayout * vlay = new QVBoxLayout( this ); KDAB_SET_OBJECT_NAME( pgpCB ); KDAB_SET_OBJECT_NAME( cmsCB ); KDAB_SET_OBJECT_NAME( widget ); KDAB_SET_OBJECT_NAME( vlay ); vlay->addWidget( &pgpCB ); vlay->addWidget( &cmsCB ); widget.layout()->setMargin( 0 ); vlay->addWidget( &widget ); // ### connect something to completeChanged() // ### deal with widget.rememberAsDefault() connect( &pgpCB, SIGNAL(toggled(bool)), this, SLOT(slotSignProtocolToggled()) ); connect( &cmsCB, SIGNAL(toggled(bool)), this, SLOT(slotSignProtocolToggled()) ); } std::vector keys() const { const QMap keys = widget.selectedCertificates(); const bool pgp = pgpCB.isChecked(); const bool cms = cmsCB.isChecked(); std::vector result; result.reserve( pgp + cms ); if ( pgp ) result.push_back( keys[OpenPGP] ); if ( cms ) result.push_back( keys[CMS] ); // remove empty keys, for good measure... result.erase( std::remove_if( result.begin(), result.end(), mem_fn( &Key::isNull ) ), result.end() ); return result; } /* reimp */ bool isComplete() const { return !keys().empty(); } /* reimp */ int nextId() const { return ResultPageId ; } /* reimp */ void initializePage() { if ( QWizard * wiz = wizard() ) { // need to do this here, since wizard() == 0 in the ctor const NewSignEncryptFilesWizard *filesWizard = qobject_cast( wiz ); disconnect( filesWizard, SIGNAL(operationPrepared()), this, SLOT(slotCommitSigningPreferences()) ); connect( filesWizard, SIGNAL(operationPrepared()), this, SLOT(slotCommitSigningPreferences()) ); } bool pgp = effectiveProtocol() == OpenPGP; bool cms = effectiveProtocol() == CMS; if ( effectiveProtocol() == UnknownProtocol ) pgp = cms = true; assert( pgp || cms ); if ( isSignOnlySelected() ) { // free choice of OpenPGP and/or CMS // (except when protocol() requires otherwise): pgpCB.setEnabled( pgp ); cmsCB.setEnabled( cms ); pgpCB.setChecked( pgp ); cmsCB.setChecked( cms ); setButtonText( QWizard::CommitButton, i18nc("@action","Sign") ); } else { // we need signing keys for each of protocols that // make up the recipients: const std::vector & recipients = resolvedRecipients(); if ( _detail::none_of_protocol( recipients, OpenPGP ) ) pgp = false; if ( _detail::none_of_protocol( recipients, CMS ) ) cms = false; pgpCB.setEnabled( false ); cmsCB.setEnabled( false ); pgpCB.setChecked( pgp ); cmsCB.setChecked( cms ); setButtonText( QWizard::CommitButton, i18nc("@action","Sign && Encrypt") ); } if ( !signPref ) { signPref.reset( new KConfigBasedSigningPreferences( KGlobal::config() ) ); widget.setSelectedCertificates( signPref->preferredCertificate( OpenPGP ), signPref->preferredCertificate( CMS ) ); } } private: const std::vector & resolvedRecipients() const { assert( wizard() ); assert( qobject_cast( wizard() ) == static_cast( wizard() ) ); return static_cast( wizard() )->resolvedRecipients(); } private Q_SLOTS: void slotSignProtocolToggled() { widget.setAllowedProtocols( pgpCB.isChecked(), cmsCB.isChecked() ); emit completeChanged(); } void slotCommitSigningPreferences() { if ( widget.rememberAsDefault() ) Q_FOREACH( const GpgME::Key & key, keys() ) if ( !key.isNull() ) signPref->setPreferredCertificate( key.protocol(), key ); } private: shared_ptr signPref; QCheckBox pgpCB, cmsCB; SigningCertificateSelectionWidget widget; }; class ResultPage : public NewResultPage { Q_OBJECT public: explicit ResultPage( QWidget * parent=0 ) : NewResultPage( parent ) { setTitle( i18nc("@title","Results") ); setSubTitle( i18nc("@title", "Status and progress of the crypto operations is shown here." ) ); } }; } class NewSignEncryptFilesWizard::Private { friend class ::Kleo::Crypto::Gui::NewSignEncryptFilesWizard; NewSignEncryptFilesWizard * const q; public: explicit Private( NewSignEncryptFilesWizard * qq ) : q( qq ), operationPage( new OperationPage( q ) ), recipientsPage( new RecipientsPage( q ) ), signerPage( new SignerPage( q ) ), resultPage( new ResultPage( q ) ), createArchivePreset( false ), createArchiveUserMutable( true ), signingPreset( true ), signingUserMutable( true ), encryptionPreset( true ), encryptionUserMutable( true ) { KDAB_SET_OBJECT_NAME( operationPage ); KDAB_SET_OBJECT_NAME( recipientsPage ); KDAB_SET_OBJECT_NAME( signerPage ); KDAB_SET_OBJECT_NAME( resultPage ); q->setPage( OperationPageId, operationPage ); q->setPage( RecipientsPageId, recipientsPage ); q->setPage( SignerPageId, signerPage ); q->setPage( ResultPageId, resultPage ); connect( q, SIGNAL(currentIdChanged(int)), q, SLOT(slotCurrentIdChanged(int)) ); } private: void slotCurrentIdChanged( int id ) { if ( id == ResultPageId ) emit q->operationPrepared(); } private: int startId() const { if ( !createArchivePreset && !createArchiveUserMutable ) { if ( signingPreset && !encryptionPreset && !encryptionUserMutable ) return SignerPageId; if ( encryptionPreset && !signingPreset && !signingUserMutable || signingPreset && !signingUserMutable && encryptionPreset && !encryptionUserMutable ) return RecipientsPageId; } if ( signingUserMutable || encryptionUserMutable || createArchivePreset || createArchiveUserMutable ) return OperationPageId; else if ( encryptionPreset ) return RecipientsPageId; else return SignerPageId; } void updateStartId() { q->setStartId( startId() ); } private: OperationPage * operationPage; RecipientsPage * recipientsPage; SignerPage * signerPage; ResultPage * resultPage; bool createArchivePreset : 1; bool createArchiveUserMutable : 1; bool signingPreset : 1; bool signingUserMutable : 1; bool encryptionPreset : 1; bool encryptionUserMutable : 1; }; NewSignEncryptFilesWizard::NewSignEncryptFilesWizard( QWidget * parent, Qt::WindowFlags f ) : QWizard( parent, f ), d( new Private( this ) ) { } NewSignEncryptFilesWizard::~NewSignEncryptFilesWizard() { kDebug(); } void NewSignEncryptFilesWizard::setPresetProtocol( Protocol proto ) { d->operationPage->setPresetProtocol( proto ); d->recipientsPage->setPresetProtocol( proto ); d->signerPage->setPresetProtocol( proto ); } void NewSignEncryptFilesWizard::setCreateArchivePreset( bool preset ) { if ( preset == d->createArchivePreset && preset == isCreateArchiveSelected() ) return; d->createArchivePreset = preset; setField( QLatin1String("archive"), preset ); d->updateStartId(); } void NewSignEncryptFilesWizard::setCreateArchiveUserMutable( bool mut ) { if ( mut == d->createArchiveUserMutable ) return; d->createArchiveUserMutable = mut; setField( QLatin1String("archive-user-mutable"), mut ); d->updateStartId(); } void NewSignEncryptFilesWizard::setArchiveDefinitionId( const QString & id ) { d->operationPage->setArchiveDefinition( id ); } void NewSignEncryptFilesWizard::setSigningPreset( bool preset ) { if ( preset == d->signingPreset ) return; d->signingPreset = preset; setField( QLatin1String("signing-preset"), preset ); d->updateStartId(); } void NewSignEncryptFilesWizard::setSigningUserMutable( bool mut ) { if ( mut == d->signingUserMutable ) return; d->signingUserMutable = mut; setField( QLatin1String("signing-user-mutable"), mut ); d->updateStartId(); } void NewSignEncryptFilesWizard::setEncryptionPreset( bool preset ) { if ( preset == d->encryptionPreset ) return; d->encryptionPreset = preset; setField( QLatin1String("encryption-preset"), preset ); d->updateStartId(); } void NewSignEncryptFilesWizard::setEncryptionUserMutable( bool mut ) { if ( mut == d->encryptionUserMutable ) return; d->encryptionUserMutable = mut; setField( QLatin1String("encryption-user-mutable"), mut ); d->updateStartId(); } void NewSignEncryptFilesWizard::setFiles( const QStringList & files ) { setField( QLatin1String("files"), files ); } bool NewSignEncryptFilesWizard::isSigningSelected() const { return field(QLatin1String("sign")).toBool() || field(QLatin1String("signencrypt")).toBool() ; } bool NewSignEncryptFilesWizard::isEncryptionSelected() const { return field(QLatin1String("encrypt")).toBool() || field(QLatin1String("signencrypt")).toBool() ; } bool NewSignEncryptFilesWizard::isAsciiArmorEnabled() const { return field(QLatin1String("armor")).toBool(); } bool NewSignEncryptFilesWizard::isRemoveUnencryptedFilesEnabled() const { return isEncryptionSelected() && field(QLatin1String("remove")).toBool(); } bool NewSignEncryptFilesWizard::isCreateArchiveSelected() const { return field(QLatin1String("archive")).toBool(); } shared_ptr NewSignEncryptFilesWizard::selectedArchiveDefinition() const { return d->operationPage->archiveDefinition(); } QString NewSignEncryptFilesWizard::archiveFileName( Protocol p ) const { return d->/*any page*/operationPage->archiveName( p ); } const std::vector & NewSignEncryptFilesWizard::resolvedRecipients() const { return d->recipientsPage->keys(); } std::vector NewSignEncryptFilesWizard::resolvedSigners() const { return d->signerPage->keys(); } void NewSignEncryptFilesWizard::setTaskCollection( const shared_ptr & coll ) { d->resultPage->setTaskCollection( coll ); } #include "moc_newsignencryptfileswizard.cpp" #include "newsignencryptfileswizard.moc" diff --git a/kleopatra/crypto/gui/resolverecipientspage.cpp b/kleopatra/crypto/gui/resolverecipientspage.cpp index 582a80e55b..35d40ed4dc 100644 --- a/kleopatra/crypto/gui/resolverecipientspage.cpp +++ b/kleopatra/crypto/gui/resolverecipientspage.cpp @@ -1,719 +1,721 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/gui/resolverecipientspage.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2007 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "resolverecipientspage.h" #include "resolverecipientspage_p.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#ifndef Q_MOC_RUN #include #include +#endif #include using namespace GpgME; using namespace boost; using namespace Kleo; using namespace Kleo::Dialogs; using namespace Kleo::Crypto; using namespace Kleo::Crypto::Gui; using namespace KMime::Types; ResolveRecipientsPage::ListWidget::ListWidget( QWidget* parent, Qt::WindowFlags flags ) : QWidget( parent, flags ), m_protocol( UnknownProtocol ) { m_listWidget = new QListWidget; m_listWidget->setSelectionMode( QAbstractItemView::MultiSelection ); QVBoxLayout * const layout = new QVBoxLayout( this ); layout->addWidget( m_listWidget ); connect( m_listWidget, SIGNAL(itemSelectionChanged()), this, SLOT(onSelectionChange()) ); } ResolveRecipientsPage::ListWidget::~ListWidget() { } void ResolveRecipientsPage::ListWidget::onSelectionChange() { Q_FOREACH ( const QString& i, widgets.keys() ) { //krazy:exclude=foreach assert( items.contains( i ) ); widgets[i]->setSelected( items[i]->isSelected() ); } emit selectionChanged(); } void ResolveRecipientsPage::ListWidget::addEntry( const Mailbox& mbox ) { addEntry( mbox.prettyAddress(), mbox.prettyAddress(), mbox ); } void ResolveRecipientsPage::ListWidget::addEntry( const QString& id, const QString& name ) { addEntry( id, name, Mailbox() ); } void ResolveRecipientsPage::ListWidget::addEntry( const QString& id, const QString& name, const Mailbox& mbox ) { assert( !widgets.contains( id ) && !items.contains( id ) ); QListWidgetItem* item = new QListWidgetItem; item->setData( IdRole, id ); ItemWidget* wid = new ItemWidget( id, name, mbox, this ); connect( wid, SIGNAL(changed()), this, SIGNAL(completeChanged()) ); wid->setProtocol( m_protocol ); item->setSizeHint( wid->sizeHint() ); m_listWidget->addItem( item ); m_listWidget->setItemWidget( item, wid ); widgets[id] = wid; items[id] = item; } Mailbox ResolveRecipientsPage::ListWidget::mailbox( const QString& id ) const { return widgets.contains( id ) ? widgets[id]->mailbox() : Mailbox(); } void ResolveRecipientsPage::ListWidget::setCertificates( const QString& id, const std::vector& pgp, const std::vector& cms ) { assert( widgets.contains( id ) ); widgets[id]->setCertificates( pgp, cms ); } Key ResolveRecipientsPage::ListWidget::selectedCertificate( const QString& id ) const { return widgets.contains( id ) ? widgets[id]->selectedCertificate() : Key(); } GpgME::Key ResolveRecipientsPage::ListWidget::selectedCertificate( const QString& id, GpgME::Protocol prot ) const { return widgets.contains( id ) ? widgets[id]->selectedCertificate( prot ) : Key(); } QStringList ResolveRecipientsPage::ListWidget::identifiers() const { return widgets.keys(); } void ResolveRecipientsPage::ListWidget::setProtocol( GpgME::Protocol prot ) { if ( m_protocol == prot ) return; m_protocol = prot; Q_FOREACH ( ItemWidget* i, widgets ) i->setProtocol( prot ); } void ResolveRecipientsPage::ListWidget::removeEntry( const QString& id ) { if ( !widgets.contains( id ) ) return; delete items[id]; items.remove( id ); delete widgets[id]; widgets.remove( id ); } void ResolveRecipientsPage::ListWidget::showSelectionDialog( const QString& id ) { if ( !widgets.contains( id ) ) return; widgets[id]->showSelectionDialog(); } QStringList ResolveRecipientsPage::ListWidget::selectedEntries() const { QStringList entries; const QList items = m_listWidget->selectedItems(); Q_FOREACH ( const QListWidgetItem* i, items ) { entries.append( i->data( IdRole ).toString() ); } return entries; } ResolveRecipientsPage::ItemWidget::ItemWidget( const QString& id, const QString& name, const Mailbox& mbox, QWidget* parent, Qt::WindowFlags flags ) : QWidget( parent, flags ), m_id( id ), m_mailbox( mbox ), m_protocol( UnknownProtocol ), m_selected( false ) { assert( !m_id.isEmpty() ); setAutoFillBackground( true ); QHBoxLayout* layout = new QHBoxLayout( this ); layout->setMargin( 0 ); layout->addSpacing( 15 ); m_nameLabel = new QLabel; m_nameLabel->setText( name ); layout->addWidget( m_nameLabel ); layout->addStretch(); m_certLabel = new QLabel; m_certLabel->setText( i18n( "No certificate selected" ) ); layout->addWidget( m_certLabel ); m_certCombo = new QComboBox; connect( m_certCombo, SIGNAL(currentIndexChanged(int)), this, SIGNAL(changed()) ); layout->addWidget( m_certCombo ); m_selectButton = new QToolButton; m_selectButton->setText( i18n( "..." ) ); connect( m_selectButton, SIGNAL(clicked()), this, SLOT(showSelectionDialog()) ); layout->addWidget( m_selectButton ); layout->addSpacing( 15 ); setCertificates( std::vector(), std::vector() ); } void ResolveRecipientsPage::ItemWidget::updateVisibility() { m_certLabel->setVisible( m_certCombo->count() == 0 ); m_certCombo->setVisible( m_certCombo->count() > 0 ); } ResolveRecipientsPage::ItemWidget::~ItemWidget() { } QString ResolveRecipientsPage::ItemWidget::id() const { return m_id; } void ResolveRecipientsPage::ItemWidget::setSelected( bool selected ) { if ( m_selected == selected ) return; m_selected = selected; setBackgroundRole( selected ? QPalette::Highlight : QPalette::Base ); const QPalette::ColorRole foreground = selected ? QPalette::HighlightedText : QPalette::Text; setForegroundRole( foreground ); m_nameLabel->setForegroundRole( foreground ); m_certLabel->setForegroundRole( foreground ); } bool ResolveRecipientsPage::ItemWidget::isSelected() const { return m_selected; } static CertificateSelectionDialog::Option protocol2option( GpgME::Protocol proto ) { switch ( proto ) { case OpenPGP: return CertificateSelectionDialog::OpenPGPFormat; case CMS: return CertificateSelectionDialog::CMSFormat; default: return CertificateSelectionDialog::AnyFormat; } } static CertificateSelectionDialog * createCertificateSelectionDialog( QWidget* parent, GpgME::Protocol prot ) { CertificateSelectionDialog * const dlg = new CertificateSelectionDialog( parent ); const CertificateSelectionDialog::Options options = CertificateSelectionDialog::SingleSelection | CertificateSelectionDialog::EncryptOnly | CertificateSelectionDialog::MultiSelection | protocol2option( prot ); dlg->setOptions( options ); return dlg; } void ResolveRecipientsPage::ItemWidget::showSelectionDialog() { QPointer dlg = createCertificateSelectionDialog( this, m_protocol ); if ( dlg->exec() == QDialog::Accepted && dlg /* still with us? */ ) { const GpgME::Key cert = dlg->selectedCertificate(); if ( !cert.isNull() ) { addCertificateToComboBox( cert ); selectCertificateInComboBox( cert ); } } delete dlg; } Mailbox ResolveRecipientsPage::ItemWidget::mailbox() const { return m_mailbox; } void ResolveRecipientsPage::ItemWidget::selectCertificateInComboBox( const Key& key ) { m_certCombo->setCurrentIndex( m_certCombo->findData( QLatin1String(key.keyID()) ) ); } void ResolveRecipientsPage::ItemWidget::addCertificateToComboBox( const GpgME::Key& key ) { m_certCombo->addItem( Formatting::formatForComboBox( key ), QByteArray( key.keyID() ) ); if ( m_certCombo->count() == 1 ) m_certCombo->setCurrentIndex( 0 ); updateVisibility(); } void ResolveRecipientsPage::ItemWidget::resetCertificates() { std::vector certs; Key selected; switch ( m_protocol ) { case OpenPGP: certs = m_pgp; break; case CMS: certs = m_cms; break; case UnknownProtocol: certs = m_cms; certs.insert( certs.end(), m_pgp.begin(), m_pgp.end() ); } m_certCombo->clear(); Q_FOREACH ( const Key& i, certs ) addCertificateToComboBox( i ); if ( !m_selectedCertificates[m_protocol].isNull() ) selectCertificateInComboBox( m_selectedCertificates[m_protocol] ); else if ( m_certCombo->count() > 0 ) m_certCombo->setCurrentIndex( 0 ); updateVisibility(); emit changed(); } void ResolveRecipientsPage::ItemWidget::setProtocol( Protocol prot ) { if ( m_protocol == prot ) return; m_selectedCertificates[m_protocol] = selectedCertificate(); if ( m_protocol != UnknownProtocol ) ( m_protocol == OpenPGP ? m_pgp : m_cms ) = certificates(); m_protocol = prot; resetCertificates(); } void ResolveRecipientsPage::ItemWidget::setCertificates( const std::vector& pgp, const std::vector& cms ) { m_pgp = pgp; m_cms = cms; resetCertificates(); } Key ResolveRecipientsPage::ItemWidget::selectedCertificate() const { #ifdef QT_STL return KeyCache::instance()->findByKeyIDOrFingerprint( m_certCombo->itemData( m_certCombo->currentIndex(), ListWidget::IdRole ).toString().toStdString() ); #else const QString tmpStr = m_certCombo->itemData( m_certCombo->currentIndex(), ListWidget::IdRole ).toString(); const QByteArray asc = tmpStr.toLatin1(); std::string tmpstdstring = std::string(asc.constData(), asc.length()); return KeyCache::instance()->findByKeyIDOrFingerprint( tmpstdstring ); #endif } GpgME::Key ResolveRecipientsPage::ItemWidget::selectedCertificate( GpgME::Protocol prot ) const { return prot == m_protocol ? selectedCertificate() : m_selectedCertificates.value( prot ); } std::vector ResolveRecipientsPage::ItemWidget::certificates() const { std::vector certs; for ( int i = 0; i < m_certCombo->count(); ++i ) { #ifdef QT_STL certs.push_back( KeyCache::instance()->findByKeyIDOrFingerprint( m_certCombo->itemData( i, ListWidget::IdRole ).toString().toStdString() ) ); #else const QString tmpStr = m_certCombo->itemData( i, ListWidget::IdRole ).toString(); const QByteArray asc = tmpStr.toLatin1(); std::string tmpstdstring = std::string(asc.constData(), asc.length()); certs.push_back( KeyCache::instance()->findByKeyIDOrFingerprint( tmpstdstring ) ); #endif } return certs; } class ResolveRecipientsPage::Private { friend class ::Kleo::Crypto::Gui::ResolveRecipientsPage; ResolveRecipientsPage * const q; public: explicit Private( ResolveRecipientsPage * qq ); ~Private(); void setSelectedProtocol( Protocol protocol ); void selectionChanged(); void removeSelectedEntries(); void addRecipient(); void addRecipient( const Mailbox& mbox ); void addRecipient( const QString& id, const QString& name ); void updateProtocolRBVisibility(); void protocolSelected( int prot ); void writeSelectedCertificatesToPreferences(); void completeChangedInternal(); private: ListWidget* m_listWidget; QPushButton* m_addButton; QPushButton* m_removeButton; QRadioButton* m_pgpRB; QRadioButton* m_cmsRB; QLabel* m_additionalRecipientsLabel; Protocol m_presetProtocol; Protocol m_selectedProtocol; bool m_multipleProtocolsAllowed; boost::shared_ptr m_recipientPreferences; }; ResolveRecipientsPage::Private::Private( ResolveRecipientsPage * qq ) : q( qq ), m_presetProtocol( UnknownProtocol ), m_selectedProtocol( m_presetProtocol ), m_multipleProtocolsAllowed( false ), m_recipientPreferences() { connect( q, SIGNAL(completeChanged()), q, SLOT(completeChangedInternal()) ); q->setTitle( i18n( "Recipients" ) ); QVBoxLayout* const layout = new QVBoxLayout( q ); m_listWidget = new ListWidget; connect( m_listWidget, SIGNAL(selectionChanged()), q, SLOT(selectionChanged()) ); connect( m_listWidget, SIGNAL(completeChanged()), q, SIGNAL(completeChanged()) ); layout->addWidget( m_listWidget ); m_additionalRecipientsLabel = new QLabel; m_additionalRecipientsLabel->setWordWrap( true ); layout->addWidget( m_additionalRecipientsLabel ); m_additionalRecipientsLabel->setVisible( false ); QWidget* buttonWidget = new QWidget; QHBoxLayout* buttonLayout = new QHBoxLayout( buttonWidget ); buttonLayout->setMargin( 0 ); m_addButton = new QPushButton; connect( m_addButton, SIGNAL(clicked()), q, SLOT(addRecipient()) ); m_addButton->setText( i18n( "Add Recipient..." ) ); buttonLayout->addWidget( m_addButton ); m_removeButton = new QPushButton; m_removeButton->setEnabled( false ); m_removeButton->setText( i18n( "Remove Selected" ) ); connect( m_removeButton, SIGNAL(clicked()), q, SLOT(removeSelectedEntries()) ); buttonLayout->addWidget( m_removeButton ); buttonLayout->addStretch(); layout->addWidget( buttonWidget ); QWidget* protocolWidget = new QWidget; QHBoxLayout* protocolLayout = new QHBoxLayout( protocolWidget ); QButtonGroup* protocolGroup = new QButtonGroup( q ); connect( protocolGroup, SIGNAL(buttonClicked(int)), q, SLOT(protocolSelected(int)) ); m_pgpRB = new QRadioButton; m_pgpRB->setText( i18n( "OpenPGP" ) ); protocolGroup->addButton( m_pgpRB, OpenPGP ); protocolLayout->addWidget( m_pgpRB ); m_cmsRB = new QRadioButton; m_cmsRB->setText( i18n( "S/MIME" ) ); protocolGroup->addButton( m_cmsRB, CMS ); protocolLayout->addWidget( m_cmsRB ); protocolLayout->addStretch(); layout->addWidget( protocolWidget ); } ResolveRecipientsPage::Private::~Private() {} void ResolveRecipientsPage::Private::completeChangedInternal() { const bool isComplete = q->isComplete(); const std::vector keys = q->resolvedCertificates(); const bool haveSecret = std::find_if( keys.begin(), keys.end(), boost::bind( &Key::hasSecret, _1 ) ) != keys.end(); if ( isComplete && !haveSecret ) q->setExplanation( i18n( "Warning: None of the selected certificates seem to be your own. You will not be able to decrypt the encrypted data again." ) ); else q->setExplanation( QString() ); } void ResolveRecipientsPage::Private::updateProtocolRBVisibility() { const bool visible = !m_multipleProtocolsAllowed && m_presetProtocol == UnknownProtocol; m_cmsRB->setVisible( visible ); m_pgpRB->setVisible( visible ); if ( visible ) { if ( m_selectedProtocol == CMS ) m_cmsRB->click(); else m_pgpRB->click(); } } bool ResolveRecipientsPage::isComplete() const { const QStringList ids = d->m_listWidget->identifiers(); if ( ids.isEmpty() ) return false; Q_FOREACH ( const QString& i, ids ) { if ( d->m_listWidget->selectedCertificate( i ).isNull() ) return false; } return true; } ResolveRecipientsPage::ResolveRecipientsPage( QWidget * parent ) : WizardPage( parent ), d( new Private( this ) ) { } ResolveRecipientsPage::~ResolveRecipientsPage() {} Protocol ResolveRecipientsPage::selectedProtocol() const { return d->m_selectedProtocol; } void ResolveRecipientsPage::Private::setSelectedProtocol( Protocol protocol ) { if ( m_selectedProtocol == protocol ) return; m_selectedProtocol = protocol; m_listWidget->setProtocol( m_selectedProtocol ); emit q->selectedProtocolChanged(); } void ResolveRecipientsPage::Private::protocolSelected( int p ) { const Protocol protocol = static_cast( p ); assert( protocol != UnknownProtocol ); setSelectedProtocol( protocol ); } void ResolveRecipientsPage::setPresetProtocol( Protocol prot ) { if ( d->m_presetProtocol == prot ) return; d->m_presetProtocol = prot; d->setSelectedProtocol( prot ); if ( prot != UnknownProtocol ) d->m_multipleProtocolsAllowed = false; d->updateProtocolRBVisibility(); } Protocol ResolveRecipientsPage::presetProtocol() const { return d->m_presetProtocol; } bool ResolveRecipientsPage::multipleProtocolsAllowed() const { return d->m_multipleProtocolsAllowed; } void ResolveRecipientsPage::setMultipleProtocolsAllowed( bool allowed ) { if ( d->m_multipleProtocolsAllowed == allowed ) return; d->m_multipleProtocolsAllowed = allowed; if ( d->m_multipleProtocolsAllowed ) { setPresetProtocol( UnknownProtocol ); d->setSelectedProtocol( UnknownProtocol ); } d->updateProtocolRBVisibility(); } void ResolveRecipientsPage::Private::addRecipient( const QString& id, const QString& name ) { m_listWidget->addEntry( id, name ); } void ResolveRecipientsPage::Private::addRecipient( const Mailbox& mbox ) { m_listWidget->addEntry( mbox ); } void ResolveRecipientsPage::Private::addRecipient() { QPointer dlg = createCertificateSelectionDialog( q, q->selectedProtocol() ); if ( dlg->exec() != QDialog::Accepted || !dlg /*q already deleted*/ ) return; const std::vector keys = dlg->selectedCertificates(); int i = 0; Q_FOREACH( const Key & key, keys ) { const QStringList existing = m_listWidget->identifiers(); QString rec = i18n( "Recipient" ); while ( existing.contains( rec ) ) rec = i18nc( "%1 == number", "Recipient (%1)", ++i ); addRecipient( rec, rec ); const std::vector pgp = key.protocol() == OpenPGP ? std::vector( 1, key ) : std::vector(); const std::vector cms = key.protocol() == CMS ? std::vector( 1, key ) : std::vector(); m_listWidget->setCertificates( rec, pgp, cms ); } emit q->completeChanged(); } namespace { std::vector makeSuggestions( const boost::shared_ptr& prefs, const Mailbox& mb, GpgME::Protocol prot ) { std::vector suggestions; const Key remembered = prefs ? prefs->preferredCertificate( mb, prot ) : Key(); if ( !remembered.isNull() ) suggestions.push_back( remembered ); else suggestions = CertificateResolver::resolveRecipient( mb, prot ); return suggestions; } } static QString listKeysForInfo( const std::vector & keys ) { QStringList list; std::transform( keys.begin(), keys.end(), list.begin(), &Formatting::formatKeyLink ); return list.join( QLatin1String("
") ); } void ResolveRecipientsPage::setAdditionalRecipientsInfo( const std::vector & recipients ) { d->m_additionalRecipientsLabel->setVisible( !recipients.empty() ); if ( recipients.empty() ) return; d->m_additionalRecipientsLabel->setText( i18n( "

Recipients predefined via GnuPG settings:

%1
", listKeysForInfo( recipients ) ) ); } void ResolveRecipientsPage::setRecipients( const std::vector& recipients, const std::vector & encryptToSelfRecipients ) { uint cmsCount = 0; uint pgpCount = 0; uint senders = 0; Q_FOREACH( const Mailbox & mb, encryptToSelfRecipients ) { const QString id = QLatin1String("sender-") + QString::number( ++senders ); d->m_listWidget->addEntry( id, i18n("Sender"), mb ); const std::vector pgp = makeSuggestions( d->m_recipientPreferences, mb, OpenPGP ); const std::vector cms = makeSuggestions( d->m_recipientPreferences, mb, CMS ); pgpCount += !pgp.empty(); cmsCount += !cms.empty(); d->m_listWidget->setCertificates( id, pgp, cms ); } Q_FOREACH( const Mailbox& i, recipients ) { //TODO: const QString address = i.prettyAddress(); d->addRecipient( i ); const std::vector pgp = makeSuggestions( d->m_recipientPreferences, i, OpenPGP ); const std::vector cms = makeSuggestions( d->m_recipientPreferences, i, CMS ); pgpCount += pgp.empty() ? 0 : 1; cmsCount += cms.empty() ? 0 : 1; d->m_listWidget->setCertificates( address, pgp, cms ); } if ( d->m_presetProtocol == UnknownProtocol && !d->m_multipleProtocolsAllowed ) ( cmsCount > pgpCount ? d->m_cmsRB : d->m_pgpRB )->click(); } std::vector ResolveRecipientsPage::resolvedCertificates() const { std::vector certs; Q_FOREACH( const QString& i, d->m_listWidget->identifiers() ) { const GpgME::Key cert = d->m_listWidget->selectedCertificate( i ); if ( !cert.isNull() ) certs.push_back( cert ); } return certs; } void ResolveRecipientsPage::Private::selectionChanged() { m_removeButton->setEnabled( !m_listWidget->selectedEntries().isEmpty() ); } void ResolveRecipientsPage::Private::removeSelectedEntries() { Q_FOREACH ( const QString& i, m_listWidget->selectedEntries() ) m_listWidget->removeEntry( i ); emit q->completeChanged(); } void ResolveRecipientsPage::setRecipientsUserMutable( bool isMutable ) { d->m_addButton->setVisible( isMutable ); d->m_removeButton->setVisible( isMutable ); } bool ResolveRecipientsPage::recipientsUserMutable() const { return d->m_addButton->isVisible(); } boost::shared_ptr ResolveRecipientsPage::recipientPreferences() const { return d->m_recipientPreferences; } void ResolveRecipientsPage::setRecipientPreferences( const boost::shared_ptr& prefs ) { d->m_recipientPreferences = prefs; } void ResolveRecipientsPage::Private::writeSelectedCertificatesToPreferences() { if ( !m_recipientPreferences ) return; Q_FOREACH ( const QString& i, m_listWidget->identifiers() ) { const Mailbox mbox = m_listWidget->mailbox( i ); if ( !mbox.hasAddress() ) continue; const Key pgp = m_listWidget->selectedCertificate( i, OpenPGP ); if ( !pgp.isNull() ) m_recipientPreferences->setPreferredCertificate( mbox, OpenPGP, pgp ); const Key cms = m_listWidget->selectedCertificate( i, CMS ); if ( !cms.isNull() ) m_recipientPreferences->setPreferredCertificate( mbox, CMS, cms ); } } void ResolveRecipientsPage::onNext() { d->writeSelectedCertificatesToPreferences(); } #include "moc_resolverecipientspage_p.cpp" #include "moc_resolverecipientspage.cpp" diff --git a/kleopatra/crypto/gui/resolverecipientspage.h b/kleopatra/crypto/gui/resolverecipientspage.h index eb6f6dd560..690cafb3c8 100644 --- a/kleopatra/crypto/gui/resolverecipientspage.h +++ b/kleopatra/crypto/gui/resolverecipientspage.h @@ -1,128 +1,130 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/gui/resolverecipientspage.h This file is part of Kleopatra, the KDE keymanager Copyright (c) 2007 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #ifndef __KLEOPATRA_CRYPTO_GUI_RESOLVERECIPIENTSPAGE_H__ #define __KLEOPATRA_CRYPTO_GUI_RESOLVERECIPIENTSPAGE_H__ #include #include #include +#ifndef Q_MOC_RUN #include +#endif #include namespace GpgME { class Key; } namespace KMime { namespace Types { class Mailbox; } } namespace Kleo { namespace Crypto { class RecipientPreferences; namespace Gui { class ResolveRecipientsPage : public WizardPage { Q_OBJECT public: explicit ResolveRecipientsPage( QWidget * parent=0 ); ~ResolveRecipientsPage(); bool isComplete() const; /** * The protocol selected by the user (which is chosen by * the user in case none was preset) */ GpgME::Protocol selectedProtocol() const; /** * the protocol set before the dialog is shown. Defaults to * GpgME::UnknownProtocol */ GpgME::Protocol presetProtocol() const; void setPresetProtocol( GpgME::Protocol protocol ); bool multipleProtocolsAllowed() const; void setMultipleProtocolsAllowed( bool allowed ); bool symmetricEncryptionSelected() const; void setSymmetricEncryptionSelected( bool enabled ); bool symmetricEncryptionSelectable() const; void setSymmetricEncryptionSelectable( bool selectable ); /** if true, the user is allowed to remove/add recipients via the UI. * Defaults to @p false. */ bool recipientsUserMutable() const; void setRecipientsUserMutable( bool isMutable ); void setAdditionalRecipientsInfo( const std::vector & recipients ); void setRecipients( const std::vector & recipients, const std::vector & encryptToSelfRecipients ); std::vector resolvedCertificates() const; boost::shared_ptr recipientPreferences() const; void setRecipientPreferences( const boost::shared_ptr& prefs ); Q_SIGNALS: void selectedProtocolChanged(); private: /*reimpl*/ void onNext(); private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT( d, void selectionChanged() ) Q_PRIVATE_SLOT( d, void protocolSelected( int ) ) Q_PRIVATE_SLOT( d, void addRecipient() ) Q_PRIVATE_SLOT( d, void removeSelectedEntries() ) Q_PRIVATE_SLOT( d, void completeChangedInternal() ) class ListWidget; class ItemWidget; }; } } } #endif // __KLEOPATRA_CRYPTO_GUI_RESOLVERECIPIENTSPAGE_H__ diff --git a/kleopatra/crypto/gui/resultitemwidget.h b/kleopatra/crypto/gui/resultitemwidget.h index bf5c107c08..f171eeb6ba 100644 --- a/kleopatra/crypto/gui/resultitemwidget.h +++ b/kleopatra/crypto/gui/resultitemwidget.h @@ -1,82 +1,84 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/gui/resultitemwidget.h This file is part of Kleopatra, the KDE keymanager Copyright (c) 2008 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #ifndef __KLEOPATRA_CRYPTO_GUI_RESULTITEMWIDGET_H__ #define __KLEOPATRA_CRYPTO_GUI_RESULTITEMWIDGET_H__ #include #include #include +#ifndef Q_MOC_RUN #include +#endif class QString; namespace Kleo { namespace Crypto { class Task; namespace Gui { class ResultItemWidget : public QWidget { Q_OBJECT public: explicit ResultItemWidget( const boost::shared_ptr &result, QWidget * parent=0, Qt::WindowFlags flags=0 ); ~ResultItemWidget(); bool detailsVisible() const; bool hasErrorResult() const; void showCloseButton( bool show ); public Q_SLOTS: void showDetails( bool show = true ); void showAuditLog(); Q_SIGNALS: void linkActivated( const QString & link ); void closeButtonClicked(); void detailsToggled( bool ); private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT( d, void slotLinkActivated( QString ) ) }; } } } #endif // __KLEOPATRA_CRYPTO_GUI_RESULTITEMWIDGET_H__ diff --git a/kleopatra/crypto/gui/resultlistwidget.cpp b/kleopatra/crypto/gui/resultlistwidget.cpp index ee920e6b8c..061489fcae 100644 --- a/kleopatra/crypto/gui/resultlistwidget.cpp +++ b/kleopatra/crypto/gui/resultlistwidget.cpp @@ -1,235 +1,237 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/gui/resultlistwidget.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2008 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "resultlistwidget.h" #include "emailoperationspreferences.h" #include #include #include #include #include #include #include #include #include +#ifndef Q_MOC_RUN #include #include +#endif #include using namespace Kleo; using namespace Kleo::Crypto; using namespace Kleo::Crypto::Gui; using namespace boost; class ResultListWidget::Private { ResultListWidget* const q; public: explicit Private( ResultListWidget* qq ); void result( const shared_ptr & result ); void started( const shared_ptr & task ); void detailsToggled( bool ); void allTasksDone(); void addResultWidget( ResultItemWidget* widget ); void setupSingle(); void setupMulti(); void resizeIfStandalone(); std::vector< shared_ptr > m_collections; bool m_standaloneMode; int m_lastErrorItemIndex; ScrollArea * m_scrollArea; KPushButton * m_closeButton; QVBoxLayout * m_layout; QLabel * m_progressLabel; }; ResultListWidget::Private::Private( ResultListWidget* qq ) : q( qq ), m_collections(), m_standaloneMode( false ), m_lastErrorItemIndex( 0 ), m_scrollArea( 0 ), m_closeButton( 0 ), m_layout( 0 ), m_progressLabel( 0 ) { m_layout = new QVBoxLayout( q ); m_layout->setMargin( 0 ); m_layout->setSpacing( 0 ); m_progressLabel = new QLabel; m_progressLabel->setWordWrap( true ); m_layout->addWidget( m_progressLabel ); m_progressLabel->setVisible( false ); m_closeButton = new KPushButton; m_closeButton->setGuiItem( KStandardGuiItem::close() ); q->connect( m_closeButton, SIGNAL(clicked()), q, SLOT(close()) ); m_layout->addWidget( m_closeButton ); m_closeButton->setVisible( false ); } ResultListWidget::ResultListWidget( QWidget* parent, Qt::WindowFlags f ) : QWidget( parent, f ), d( new Private( this ) ) { } ResultListWidget::~ResultListWidget() { if ( !d->m_standaloneMode ) return; EMailOperationsPreferences prefs; prefs.setDecryptVerifyPopupGeometry( geometry() ); prefs.writeConfig(); } void ResultListWidget::Private::setupSingle() { m_layout->addStretch(); } void ResultListWidget::Private::resizeIfStandalone() { if ( m_standaloneMode ) q->resize( q->size().expandedTo( q->sizeHint() ) ); } void ResultListWidget::Private::setupMulti() { if ( m_scrollArea ) return; // already been here... m_scrollArea = new ScrollArea; assert( qobject_cast( m_scrollArea->widget()->layout() ) ); static_cast( m_scrollArea->widget()->layout() )->setMargin( 0 ); static_cast( m_scrollArea->widget()->layout() )->setSpacing( 2 ); static_cast( m_scrollArea->widget()->layout() )->addStretch(); m_layout->insertWidget( 0, m_scrollArea ); } void ResultListWidget::Private::addResultWidget( ResultItemWidget* widget ) { assert( widget ); assert( kdtools::any( m_collections, !boost::bind( &TaskCollection::isEmpty, _1 ) ) ); assert( m_scrollArea ); assert( m_scrollArea->widget() ); assert( qobject_cast( m_scrollArea->widget()->layout() ) ); QBoxLayout & blay = *static_cast( m_scrollArea->widget()->layout() ); blay.insertWidget( widget->hasErrorResult() ? m_lastErrorItemIndex++ : ( blay.count() - 1 ), widget ); widget->show(); resizeIfStandalone(); } void ResultListWidget::Private::allTasksDone() { if ( !q->isComplete() ) return; m_progressLabel->setVisible( false ); resizeIfStandalone(); emit q->completeChanged(); } void ResultListWidget::Private::result( const shared_ptr & result ) { assert( result ); assert( kdtools::any( m_collections, !boost::bind( &TaskCollection::isEmpty, _1 ) ) ); ResultItemWidget* wid = new ResultItemWidget( result ); q->connect( wid, SIGNAL(detailsToggled(bool)), q, SLOT(detailsToggled(bool)) ); q->connect( wid, SIGNAL(linkActivated(QString)), q, SIGNAL(linkActivated(QString)) ); q->connect( wid, SIGNAL(closeButtonClicked()), q, SLOT(close()) ); addResultWidget( wid ); } bool ResultListWidget::isComplete() const { return kdtools::all( d->m_collections, mem_fn( &TaskCollection::allTasksCompleted ) ); } unsigned int ResultListWidget::totalNumberOfTasks() const { return kdtools::accumulate_transform( d->m_collections, mem_fn( &TaskCollection::size ), 0U ); } unsigned int ResultListWidget::numberOfCompletedTasks() const { return kdtools::accumulate_transform( d->m_collections, mem_fn( &TaskCollection::numberOfCompletedTasks ), 0U ); } void ResultListWidget::setTaskCollection( const shared_ptr & coll ) { //clear(); ### PENDING(marc) implement addTaskCollection( coll ); } void ResultListWidget::addTaskCollection( const shared_ptr & coll ) { assert( coll ); assert( !coll->isEmpty() ); d->m_collections.push_back( coll ); connect( coll.get(), SIGNAL(result(boost::shared_ptr)), this, SLOT(result(boost::shared_ptr)) ); connect( coll.get(), SIGNAL(started(boost::shared_ptr)), this, SLOT(started(boost::shared_ptr)) ); connect( coll.get(), SIGNAL(done()), this, SLOT(allTasksDone()) ); d->setupMulti(); setStandaloneMode( d->m_standaloneMode ); } void ResultListWidget::Private::detailsToggled( bool ) { resizeIfStandalone(); } void ResultListWidget::Private::started( const shared_ptr & task ) { assert( task ); assert( m_progressLabel ); m_progressLabel->setText( i18nc( "number, operation description", "Operation %1: %2", q->numberOfCompletedTasks() + 1, task->label() ) ); resizeIfStandalone(); } void ResultListWidget::setStandaloneMode( bool standalone ) { d->m_standaloneMode = standalone; if ( totalNumberOfTasks() == 0 ) return; d->m_closeButton->setVisible( standalone ); d->m_progressLabel->setVisible( standalone ); } #include "moc_resultlistwidget.cpp" diff --git a/kleopatra/crypto/gui/resultlistwidget.h b/kleopatra/crypto/gui/resultlistwidget.h index 839d2f0f2d..584197f1e6 100644 --- a/kleopatra/crypto/gui/resultlistwidget.h +++ b/kleopatra/crypto/gui/resultlistwidget.h @@ -1,85 +1,87 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/gui/resultlistwidget.h This file is part of Kleopatra, the KDE keymanager Copyright (c) 2008 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #ifndef __KLEOPATRA_CRYPTO_GUI_RESULTLISTWIDGET_H__ #define __KLEOPATRA_CRYPTO_GUI_RESULTLISTWIDGET_H__ #include #include #include +#ifndef Q_MOC_RUN #include +#endif class QString; namespace Kleo { namespace Crypto { class TaskCollection; namespace Gui { class ResultListWidget : public QWidget { Q_OBJECT public: explicit ResultListWidget( QWidget * parent=0, Qt::WindowFlags flags=0 ); ~ResultListWidget(); void setTaskCollection( const boost::shared_ptr & coll ); void addTaskCollection( const boost::shared_ptr & coll ); void setStandaloneMode( bool standalone ); bool isComplete() const; unsigned int totalNumberOfTasks() const; unsigned int numberOfCompletedTasks() const; Q_SIGNALS: void linkActivated( const QString & link ); void completeChanged(); private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT( d, void result( boost::shared_ptr ) ) Q_PRIVATE_SLOT( d, void started( boost::shared_ptr ) ) Q_PRIVATE_SLOT( d, void detailsToggled(bool) ) Q_PRIVATE_SLOT( d, void allTasksDone() ) }; } } } #endif // __KLEOPATRA_CRYPTO_GUI_RESULTLISTWIDGET_H__ diff --git a/kleopatra/crypto/gui/resultpage.h b/kleopatra/crypto/gui/resultpage.h index 0bf3ba9957..7a14aaef4e 100644 --- a/kleopatra/crypto/gui/resultpage.h +++ b/kleopatra/crypto/gui/resultpage.h @@ -1,82 +1,84 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/gui/resultpage.h This file is part of Kleopatra, the KDE keymanager Copyright (c) 2008 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #ifndef __KLEOPATRA_CRYPTO_GUI_RESULTPAGE_H__ #define __KLEOPATRA_CRYPTO_GUI_RESULTPAGE_H__ #include #include #include +#ifndef Q_MOC_RUN #include +#endif namespace Kleo { namespace Crypto { class TaskCollection; namespace Gui { class ResultPage : public WizardPage { Q_OBJECT public: explicit ResultPage( QWidget* parent = 0, Qt::WindowFlags flags = 0 ); ~ResultPage(); void setTaskCollection( const boost::shared_ptr & coll ); /* reimp */ bool isComplete() const; bool keepOpenWhenDone() const; void setKeepOpenWhenDone( bool keep ); Q_SIGNALS: void linkActivated( const QString & link ); private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT( d, void progress( QString, int, int ) ) Q_PRIVATE_SLOT( d, void result( boost::shared_ptr ) ) Q_PRIVATE_SLOT( d, void started( boost::shared_ptr ) ) Q_PRIVATE_SLOT( d, void keepOpenWhenDone( bool ) ) Q_PRIVATE_SLOT( d, void allDone() ) }; } } } #endif // __KLEOPATRA_CRYPTO_GUI_RESULTPAGE_H__ diff --git a/kleopatra/crypto/gui/signencryptemailconflictdialog.cpp b/kleopatra/crypto/gui/signencryptemailconflictdialog.cpp index a3d9b31871..763ebd1b78 100644 --- a/kleopatra/crypto/gui/signencryptemailconflictdialog.cpp +++ b/kleopatra/crypto/gui/signencryptemailconflictdialog.cpp @@ -1,814 +1,816 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/gui/signencryptemailconflictdialog.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2009 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "signencryptemailconflictdialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#ifndef Q_MOC_RUN #include #include +#endif #include using namespace Kleo; using namespace Kleo::Crypto; using namespace Kleo::Crypto::Gui; using namespace Kleo::Dialogs; using namespace GpgME; using namespace boost; Q_DECLARE_METATYPE( GpgME::Key ) Q_DECLARE_METATYPE( GpgME::UserID ) namespace { // A QComboBox with an initial text (as known from web browsers) // // only works with read-only QComboBoxen, doesn't affect sizeHint // as it should... // class ComboBox : public QComboBox { Q_OBJECT Q_PROPERTY( QString initialText READ initialText WRITE setInitialText ) Q_PROPERTY( QIcon initialIcon READ initialIcon WRITE setInitialIcon ) public: explicit ComboBox( QWidget * parent=0 ) : QComboBox( parent ), m_initialText(), m_initialIcon() { } explicit ComboBox( const QString & initialText, QWidget * parent=0 ) : QComboBox( parent ), m_initialText( initialText ), m_initialIcon() { } explicit ComboBox( const QIcon & initialIcon, const QString & initialText, QWidget * parent=0 ) : QComboBox( parent ), m_initialText( initialText ), m_initialIcon( initialIcon ) { } QString initialText() const { return m_initialText; } QIcon initialIcon() const { return m_initialIcon; } public Q_SLOTS: void setInitialText( const QString & txt ) { if ( txt == m_initialText ) return; m_initialText = txt; if ( currentIndex() == -1 ) update(); } void setInitialIcon( const QIcon & icon ) { if ( icon.cacheKey() == m_initialIcon.cacheKey() ) return; m_initialIcon = icon; if ( currentIndex() == -1 ) update(); } protected: void paintEvent( QPaintEvent * ) { QStylePainter p( this ); p.setPen( palette().color( QPalette::Text ) ); QStyleOptionComboBox opt; initStyleOption( &opt ); p.drawComplexControl( QStyle::CC_ComboBox, opt ); if ( currentIndex() == -1 ) { opt.currentText = m_initialText; opt.currentIcon = m_initialIcon; } p.drawControl( QStyle::CE_ComboBoxLabel, opt ); } private: QString m_initialText; QIcon m_initialIcon; }; static QString make_initial_text( const std::vector & keys ) { if ( keys.empty() ) return i18n("(no matching certificates found)"); else return i18n("Please select a certificate"); } class KeysComboBox : public ComboBox { Q_OBJECT public: explicit KeysComboBox( QWidget * parent=0 ) : ComboBox( parent ) {} explicit KeysComboBox( const QString & initialText, QWidget * parent=0 ) : ComboBox( initialText, parent ) {} explicit KeysComboBox( const std::vector & keys, QWidget * parent=0 ) : ComboBox( make_initial_text( keys ), parent ) { setKeys( keys ); } void setKeys( const std::vector & keys ) { clear(); Q_FOREACH( const Key & key, keys ) addItem( Formatting::formatForComboBox( key ), qVariantFromValue( key ) ); } std::vector keys() const { std::vector result; result.reserve( count() ); for ( int i = 0, end = count() ; i != end ; ++i ) result.push_back( qvariant_cast( itemData(i) ) ); return result;; } int findOrAdd( const Key & key ) { for ( int i = 0, end = count() ; i != end ; ++i ) if ( _detail::ByFingerprint()( key, qvariant_cast( itemData(i) ) ) ) return i; insertItem( 0, Formatting::formatForComboBox( key ), qVariantFromValue( key ) ); return 0; } void addAndSelectCertificate( const Key & key ) { setCurrentIndex( findOrAdd( key ) ); } Key currentKey() const { return qvariant_cast( itemData( currentIndex() ) ); } }; class Line { public: static const unsigned int NumColumns = 4; Line( const QString & toFrom, const QString & mailbox, const std::vector & pgp, bool pgpAmbig, const std::vector & cms, bool cmsAmbig, QWidget * q, QGridLayout & glay ) : pgpAmbiguous( pgpAmbig ), cmsAmbiguous( cmsAmbig ), toFromLB( new QLabel( toFrom, q ) ), mailboxLB( new QLabel( mailbox, q ) ), sbox( new QStackedWidget( q ) ), pgpCB( new KeysComboBox( pgp, sbox ) ), cmsCB( new KeysComboBox( cms, sbox ) ), noProtocolCB( new KeysComboBox( i18n("(please choose between OpenPGP and S/MIME first)"), sbox ) ), toolTB( new QToolButton( q ) ) { KDAB_SET_OBJECT_NAME( toFromLB ); KDAB_SET_OBJECT_NAME( mailboxLB ); KDAB_SET_OBJECT_NAME( noProtocolCB ); KDAB_SET_OBJECT_NAME( pgpCB ); KDAB_SET_OBJECT_NAME( cmsCB ); KDAB_SET_OBJECT_NAME( sbox ); KDAB_SET_OBJECT_NAME( toolTB ); QFont bold; bold.setBold( true ); toFromLB->setFont( bold ); mailboxLB->setTextFormat( Qt::PlainText ); toolTB->setText( i18n("...") ); pgpCB->setEnabled( !pgp.empty() ); cmsCB->setEnabled( !cms.empty() ); noProtocolCB->setEnabled( false ); pgpCB->setKeys( pgp ); if ( pgpAmbiguous ) pgpCB->setCurrentIndex( -1 ); cmsCB->setKeys( cms ); if ( cmsAmbiguous ) cmsCB->setCurrentIndex( -1 ); sbox->addWidget( pgpCB ); sbox->addWidget( cmsCB ); sbox->addWidget( noProtocolCB ); sbox->setCurrentWidget( noProtocolCB ); const int row = glay.rowCount(); unsigned int col = 0; glay.addWidget( toFromLB, row, col++ ); glay.addWidget( mailboxLB, row, col++ ); glay.addWidget( sbox, row, col++ ); glay.addWidget( toolTB, row, col++ ); assert( col == NumColumns ); q->connect( pgpCB, SIGNAL(currentIndexChanged(int)), SLOT(slotCompleteChanged()) ); q->connect( cmsCB, SIGNAL(currentIndexChanged(int)), SLOT(slotCompleteChanged()) ); q->connect( toolTB, SIGNAL(clicked()), SLOT(slotCertificateSelectionDialogRequested()) ); } KeysComboBox * comboBox( Protocol proto ) const { if ( proto == OpenPGP ) return pgpCB; if ( proto == CMS ) return cmsCB; return 0; } QString mailboxText() const { return mailboxLB->text(); } void addAndSelectCertificate( const Key & key ) const { if ( KeysComboBox * const cb = comboBox( key.protocol() ) ) { cb->addAndSelectCertificate( key ); cb->setEnabled( true ); } } void showHide( Protocol proto, bool & first, bool showAll, bool op ) const { if ( op && ( showAll || wasInitiallyAmbiguous( proto ) ) ) { toFromLB->setVisible( first ); first = false; QFont font = mailboxLB->font(); font.setBold( wasInitiallyAmbiguous( proto ) ); mailboxLB->setFont( font ); sbox->setCurrentIndex( proto ); mailboxLB->show(); sbox->show(); toolTB->show(); } else { toFromLB->hide(); mailboxLB->hide(); sbox->hide(); toolTB->hide(); } } bool wasInitiallyAmbiguous( Protocol proto ) const { return proto == OpenPGP && pgpAmbiguous || proto == CMS && cmsAmbiguous ; } bool isStillAmbiguous( Protocol proto ) const { kleo_assert( proto == OpenPGP || proto == CMS ); const KeysComboBox * const cb = comboBox( proto ); return cb->currentIndex() == -1 ; } Key key( Protocol proto ) const { kleo_assert( proto == OpenPGP || proto == CMS ); const KeysComboBox * const cb = comboBox( proto ); return cb->currentKey(); } const QToolButton * toolButton() const { return toolTB; } void kill() { delete toFromLB; delete mailboxLB; delete sbox; delete toolTB; } private: bool pgpAmbiguous : 1; bool cmsAmbiguous : 1; QLabel * toFromLB; QLabel * mailboxLB; QStackedWidget * sbox; KeysComboBox * pgpCB; KeysComboBox * cmsCB; KeysComboBox * noProtocolCB; QToolButton * toolTB; }; } static CertificateSelectionDialog * create_certificate_selection_dialog( QWidget * parent, Protocol proto ) { CertificateSelectionDialog * const dlg = new CertificateSelectionDialog( parent ); dlg->setOptions( proto == OpenPGP ? CertificateSelectionDialog::OpenPGPFormat : proto == CMS ? CertificateSelectionDialog::CMSFormat : CertificateSelectionDialog::AnyFormat ); return dlg; } static CertificateSelectionDialog * create_encryption_certificate_selection_dialog( QWidget * parent, Protocol proto, const QString & mailbox ) { CertificateSelectionDialog * const dlg = create_certificate_selection_dialog( parent, proto ); dlg->setCustomLabelText( i18n("Please select an encryption certificate for recipient \"%1\"", mailbox ) ); dlg->setOptions( CertificateSelectionDialog::SingleSelection | CertificateSelectionDialog::EncryptOnly | dlg->options() ); return dlg; } static CertificateSelectionDialog * create_signing_certificate_selection_dialog( QWidget * parent, Protocol proto, const QString & mailbox ) { CertificateSelectionDialog * const dlg = create_certificate_selection_dialog( parent, proto ); dlg->setCustomLabelText( i18n("Please select a signing certificate for sender \"%1\"", mailbox ) ); dlg->setOptions( CertificateSelectionDialog::SingleSelection | CertificateSelectionDialog::SignOnly | CertificateSelectionDialog::SecretKeys | dlg->options() ); return dlg; } static QString make_top_label_conflict_text( bool sign, bool enc ) { return sign && enc ? i18n("Kleopatra cannot unambiguously determine matching certificates " "for all recipients/senders of the message.\n" "Please select the correct certificates for each recipient:") : sign ? i18n("Kleopatra cannot unambiguously determine matching certificates " "for the sender of the message.\n" "Please select the correct certificates for the sender:") : enc ? i18n("Kleopatra cannot unambiguously determine matching certificates " "for all recipients of the message.\n" "Please select the correct certificates for each recipient:" ) : /* else */ (kleo_assert_fail( sign || enc ),QString()) ; } static QString make_top_label_quickmode_text( bool sign, bool enc ) { return enc ? i18n("Please verify that correct certificates have been selected for each recipient:") : sign ? i18n("Please verify that the correct certificate has been selected for the sender:") : /*else*/ (kleo_assert_fail( sign || enc ),QString()) ; } class SignEncryptEMailConflictDialog::Private { friend class ::Kleo::Crypto::Gui::SignEncryptEMailConflictDialog; SignEncryptEMailConflictDialog * const q; public: explicit Private( SignEncryptEMailConflictDialog * qq ) : q( qq ), senders(), recipients(), sign( true ), encrypt( true ), presetProtocol( UnknownProtocol ), ui( q ) { } private: void updateTopLabelText() { ui.conflictTopLB.setText( make_top_label_conflict_text( sign, encrypt ) ); ui.quickModeTopLB.setText( make_top_label_quickmode_text( sign, encrypt ) ); } void showHideWidgets() { const Protocol proto = q->selectedProtocol(); const bool quickMode = q->isQuickMode(); const bool needProtocolSelection = presetProtocol == UnknownProtocol ; const bool needShowAllRecipientsCB = quickMode ? false : needProtocolSelection ? needShowAllRecipients( OpenPGP ) || needShowAllRecipients( CMS ) : /* else */ needShowAllRecipients( proto ) ; ui.showAllRecipientsCB.setVisible( needShowAllRecipientsCB ); ui.pgpRB.setVisible( needProtocolSelection ); ui.cmsRB.setVisible( needProtocolSelection ); const bool showAll = !needShowAllRecipientsCB || ui.showAllRecipientsCB.isChecked(); bool first; first = true; Q_FOREACH( const Line & line, ui.signers ) line.showHide( proto, first, showAll, sign ); ui.selectSigningCertificatesGB.setVisible( sign && ( showAll || !first ) ); first = true; Q_FOREACH( const Line & line, ui.recipients ) line.showHide( proto, first, showAll, encrypt ); ui.selectEncryptionCertificatesGB.setVisible( encrypt && ( showAll || !first ) ); } bool needShowAllRecipients( Protocol proto ) const { if ( sign ) if ( const unsigned int num = kdtools::count_if( ui.signers, boost::bind( &Line::wasInitiallyAmbiguous, _1, proto ) ) ) if ( num != ui.signers.size() ) return true; if ( encrypt ) if ( const unsigned int num = kdtools::count_if( ui.recipients, boost::bind( &Line::wasInitiallyAmbiguous, _1, proto ) ) ) if ( num != ui.recipients.size() ) return true; return false; } void createSendersAndRecipients() { ui.clearSendersAndRecipients(); ui.addSelectSigningCertificatesGB(); Q_FOREACH( const Sender & s, senders ) addSigner( s ); ui.addSelectEncryptionCertificatesGB(); Q_FOREACH( const Sender & s, senders ) addRecipient( s ); Q_FOREACH( const Recipient & r, recipients ) addRecipient( r ); } void addSigner( const Sender & s ) { ui.addSigner( s.mailbox().prettyAddress(), s.signingCertificateCandidates( OpenPGP ), s.isSigningAmbiguous( OpenPGP ), s.signingCertificateCandidates( CMS ), s.isSigningAmbiguous( CMS ), q ); } void addRecipient( const Sender & s ) { ui.addRecipient( s.mailbox().prettyAddress(), s.encryptToSelfCertificateCandidates( OpenPGP ), s.isEncryptionAmbiguous( OpenPGP ), s.encryptToSelfCertificateCandidates( CMS ), s.isEncryptionAmbiguous( CMS ), q ); } void addRecipient( const Recipient & r ) { ui.addRecipient( r.mailbox().prettyAddress(), r.encryptionCertificateCandidates( OpenPGP ), r.isEncryptionAmbiguous( OpenPGP ), r.encryptionCertificateCandidates( CMS ), r.isEncryptionAmbiguous( CMS ), q ); } bool isComplete( Protocol proto ) const; private: void enableDisableOkButton() { ui.setOkButtonEnabled( q->isComplete() ); } void slotCompleteChanged() { enableDisableOkButton(); } void slotShowAllRecipientsToggled( bool ) { showHideWidgets(); } void slotProtocolChanged() { showHideWidgets(); enableDisableOkButton(); } void slotCertificateSelectionDialogRequested() { const QObject * const s = q->sender(); const Protocol proto = q->selectedProtocol(); QPointer dlg; Q_FOREACH( const Line & l, ui.signers ) if ( s == l.toolButton() ) { dlg = create_signing_certificate_selection_dialog( q, proto, l.mailboxText() ); if ( dlg->exec() ) l.addAndSelectCertificate( dlg->selectedCertificate() ); // ### switch to key.protocol(), in case proto == UnknownProtocol break; } Q_FOREACH( const Line & l, ui.recipients ) if ( s == l.toolButton() ) { dlg = create_encryption_certificate_selection_dialog( q, proto, l.mailboxText() ); if ( dlg->exec() ) l.addAndSelectCertificate( dlg->selectedCertificate() ); // ### switch to key.protocol(), in case proto == UnknownProtocol break; } delete dlg; } private: std::vector senders; std::vector recipients; bool sign : 1; bool encrypt : 1; Protocol presetProtocol; private: struct Ui { QLabel conflictTopLB, quickModeTopLB; QCheckBox showAllRecipientsCB; QRadioButton pgpRB, cmsRB; QGroupBox selectSigningCertificatesGB; QGroupBox selectEncryptionCertificatesGB; QCheckBox quickModeCB; QDialogButtonBox buttonBox; QVBoxLayout vlay; QHBoxLayout hlay; QGridLayout glay; std::vector signers, recipients; void setOkButtonEnabled( bool enable ) { return buttonBox.button( QDialogButtonBox::Ok )->setEnabled( enable ); } explicit Ui( SignEncryptEMailConflictDialog * q ) : conflictTopLB( make_top_label_conflict_text( true, true ), q ), quickModeTopLB( make_top_label_quickmode_text( true, true ), q ), showAllRecipientsCB( i18n("Show all recipients"), q ), pgpRB( i18n("OpenPGP"), q ), cmsRB( i18n("S/MIME"), q ), selectSigningCertificatesGB( i18n("Select Signing Certificate"), q ), selectEncryptionCertificatesGB( i18n("Select Encryption Certificate"), q ), quickModeCB( i18n("Only show this dialog in case of conflicts (experimental)"), q ), buttonBox( QDialogButtonBox::Ok|QDialogButtonBox::Cancel, Qt::Horizontal, q ), vlay( q ), hlay(), glay(), signers(), recipients() { KDAB_SET_OBJECT_NAME( conflictTopLB ); KDAB_SET_OBJECT_NAME( quickModeTopLB ); KDAB_SET_OBJECT_NAME( showAllRecipientsCB ); KDAB_SET_OBJECT_NAME( pgpRB ); KDAB_SET_OBJECT_NAME( cmsRB ); KDAB_SET_OBJECT_NAME( selectSigningCertificatesGB ); KDAB_SET_OBJECT_NAME( selectEncryptionCertificatesGB ); KDAB_SET_OBJECT_NAME( quickModeCB ); KDAB_SET_OBJECT_NAME( buttonBox ); KDAB_SET_OBJECT_NAME( hlay ); KDAB_SET_OBJECT_NAME( glay ); KDAB_SET_OBJECT_NAME( vlay ); q->setWindowTitle( i18n("Select Certificates For Message") ); conflictTopLB.hide(); selectSigningCertificatesGB.setFlat( true ); selectEncryptionCertificatesGB.setFlat( true ); selectSigningCertificatesGB.setAlignment( Qt::AlignCenter ); selectEncryptionCertificatesGB.setAlignment( Qt::AlignCenter ); glay.setColumnStretch( 2, 1 ); glay.setColumnStretch( 3, 1 ); vlay.setSizeConstraint( QLayout::SetMinimumSize ); vlay.addWidget( &conflictTopLB ); vlay.addWidget( &quickModeTopLB ); hlay.addWidget( &showAllRecipientsCB ); hlay.addStretch( 1 ); hlay.addWidget( &pgpRB ); hlay.addWidget( &cmsRB ); vlay.addLayout( &hlay ); addSelectSigningCertificatesGB(); addSelectEncryptionCertificatesGB(); vlay.addLayout( &glay ); vlay.addStretch( 1 ); vlay.addWidget( &quickModeCB, 0, Qt::AlignCenter ); vlay.addWidget( &buttonBox ); connect( &buttonBox, SIGNAL(accepted()), q, SLOT(accept()) ); connect( &buttonBox, SIGNAL(rejected()), q, SLOT(reject()) ); connect( &showAllRecipientsCB, SIGNAL(toggled(bool)), q, SLOT(slotShowAllRecipientsToggled(bool)) ); connect( &pgpRB, SIGNAL(toggled(bool)), q, SLOT(slotProtocolChanged()) ); connect( &cmsRB, SIGNAL(toggled(bool)), q, SLOT(slotProtocolChanged()) ); } void clearSendersAndRecipients() { std::vector sig, enc; sig.swap( signers ); enc.swap( recipients ); kdtools::for_each( sig, mem_fn( &Line::kill ) ); kdtools::for_each( enc, mem_fn( &Line::kill ) ); glay.removeWidget( &selectSigningCertificatesGB ); glay.removeWidget( &selectEncryptionCertificatesGB ); } void addSelectSigningCertificatesGB() { glay.addWidget( &selectSigningCertificatesGB, glay.rowCount(), 0, 1, Line::NumColumns ); } void addSelectEncryptionCertificatesGB() { glay.addWidget( &selectEncryptionCertificatesGB, glay.rowCount(), 0, 1, Line::NumColumns ); } void addSigner( const QString & mailbox, const std::vector & pgp, bool pgpAmbiguous, const std::vector & cms, bool cmsAmbiguous, QWidget * q ) { Line line( i18n("From:"), mailbox, pgp, pgpAmbiguous, cms, cmsAmbiguous, q, glay ); signers.push_back( line ); } void addRecipient( const QString & mailbox, const std::vector & pgp, bool pgpAmbiguous, const std::vector & cms, bool cmsAmbiguous, QWidget * q ) { Line line( i18n("To:"), mailbox, pgp, pgpAmbiguous, cms, cmsAmbiguous, q, glay ); recipients.push_back( line ); } } ui; }; SignEncryptEMailConflictDialog::SignEncryptEMailConflictDialog( QWidget * parent, Qt::WindowFlags f ) : QDialog( parent, f ), d( new Private( this ) ) { } SignEncryptEMailConflictDialog::~SignEncryptEMailConflictDialog() {} void SignEncryptEMailConflictDialog::setPresetProtocol( Protocol p ) { if ( p == d->presetProtocol ) return; const KDSignalBlocker pgpBlocker( d->ui.pgpRB ); const KDSignalBlocker cmsBlocker( d->ui.cmsRB ); really_check( d->ui.pgpRB, p == OpenPGP ); really_check( d->ui.cmsRB, p == CMS ); d->presetProtocol = p; d->showHideWidgets(); d->enableDisableOkButton(); } Protocol SignEncryptEMailConflictDialog::selectedProtocol() const { if ( d->presetProtocol != UnknownProtocol ) return d->presetProtocol; if ( d->ui.pgpRB.isChecked() ) return OpenPGP; if ( d->ui.cmsRB.isChecked() ) return CMS; return UnknownProtocol; } void SignEncryptEMailConflictDialog::setSubject( const QString & subject ) { setWindowTitle( i18n("Select Certificates For Message \"%1\"", subject ) ); } void SignEncryptEMailConflictDialog::setSign( bool sign ) { if ( sign == d->sign ) return; d->sign = sign; d->updateTopLabelText(); d->showHideWidgets(); d->enableDisableOkButton(); } void SignEncryptEMailConflictDialog::setEncrypt( bool encrypt ) { if ( encrypt == d->encrypt ) return; d->encrypt = encrypt; d->updateTopLabelText(); d->showHideWidgets(); d->enableDisableOkButton(); } void SignEncryptEMailConflictDialog::setSenders( const std::vector & senders ) { if ( senders == d->senders ) return; d->senders = senders; d->createSendersAndRecipients(); d->showHideWidgets(); d->enableDisableOkButton(); } void SignEncryptEMailConflictDialog::setRecipients( const std::vector & recipients ) { if ( d->recipients == recipients ) return; d->recipients = recipients; d->createSendersAndRecipients(); d->showHideWidgets(); d->enableDisableOkButton(); } void SignEncryptEMailConflictDialog::pickProtocol() { if ( selectedProtocol() != UnknownProtocol ) return; // already picked const bool pgp = d->isComplete( OpenPGP ); const bool cms = d->isComplete( CMS ); if ( pgp && !cms ) d->ui.pgpRB.setChecked( true ); else if ( cms && !pgp ) d->ui.cmsRB.setChecked( true ); } bool SignEncryptEMailConflictDialog::isComplete() const { const Protocol proto = selectedProtocol(); return proto != UnknownProtocol && d->isComplete( proto ) ; } bool SignEncryptEMailConflictDialog::Private::isComplete( Protocol proto ) const { return ( !sign || kdtools::none_of( ui.signers, boost::bind( &Line::isStillAmbiguous, _1, proto ) ) ) && ( !encrypt || kdtools::none_of( ui.recipients, boost::bind( &Line::isStillAmbiguous, _1, proto ) ) ) ; } static std::vector get_keys( const std::vector & lines, Protocol proto ) { if ( proto == UnknownProtocol ) return std::vector(); assert( proto == OpenPGP || proto == CMS ); std::vector keys; keys.reserve( lines.size() ); kdtools::transform( lines, std::back_inserter( keys ), boost::bind( &Line::key, _1, proto ) ); kleo_assert( kdtools::none_of( keys, mem_fn( &Key::isNull ) ) ); return keys; } std::vector SignEncryptEMailConflictDialog::resolvedSigningKeys() const { return d->sign ? get_keys( d->ui.signers, selectedProtocol() ) : std::vector() ; } std::vector SignEncryptEMailConflictDialog::resolvedEncryptionKeys() const { return d->encrypt ? get_keys( d->ui.recipients, selectedProtocol() ) : std::vector() ; } void SignEncryptEMailConflictDialog::setQuickMode( bool on ) { d->ui.quickModeCB.setChecked( on ); } bool SignEncryptEMailConflictDialog::isQuickMode() const { return d->ui.quickModeCB.isChecked(); } void SignEncryptEMailConflictDialog::setConflict( bool conflict ) { d->ui.conflictTopLB.setVisible( conflict ); d->ui.quickModeTopLB.setVisible( !conflict ); } #include "moc_signencryptemailconflictdialog.cpp" #include "signencryptemailconflictdialog.moc" diff --git a/kleopatra/crypto/gui/signencryptwizard.cpp b/kleopatra/crypto/gui/signencryptwizard.cpp index 8840b54b9b..0df25af071 100644 --- a/kleopatra/crypto/gui/signencryptwizard.cpp +++ b/kleopatra/crypto/gui/signencryptwizard.cpp @@ -1,309 +1,311 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/gui/signencryptwizard.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2007 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "signencryptwizard.h" #include "objectspage.h" #include "resolverecipientspage.h" #include "signerresolvepage.h" #include "resultpage.h" #include #include #include #include #include #include #include #include #include #include +#ifndef Q_MOC_RUN #include +#endif using namespace Kleo; using namespace Kleo::Crypto; using namespace Kleo::Crypto::Gui; using namespace boost; using namespace GpgME; using namespace KMime::Types; class SignEncryptWizard::Private { friend class ::Kleo::Crypto::Gui::SignEncryptWizard; SignEncryptWizard * q; public: explicit Private( SignEncryptWizard * qq ); ~Private(); void setCommitPage( Page page ); Gui::ResolveRecipientsPage * recipientResolvePage; // clashes with enum of same name SignerResolvePage * signerResolvePage; Gui::ObjectsPage * objectsPage; // clashes with enum of same name Gui::ResultPage * resultPage; // clashes with enum of same name }; SignEncryptWizard::Private::Private( SignEncryptWizard * qq ) : q( qq ), recipientResolvePage( new Gui::ResolveRecipientsPage ), signerResolvePage( new SignerResolvePage ), objectsPage( new Gui::ObjectsPage ), resultPage( new Gui::ResultPage ) { connect( resultPage, SIGNAL(linkActivated(QString)), q, SIGNAL(linkActivated(QString)) ); q->setPage( SignEncryptWizard::ResolveSignerPage, signerResolvePage ); q->setPage( SignEncryptWizard::ObjectsPage, objectsPage ); q->setPage( SignEncryptWizard::ResolveRecipientsPage, recipientResolvePage ); q->setPage( SignEncryptWizard::ResultPage, resultPage ); //TODO: move the RecipientPreferences creation out of here, don't create a new instance for each wizard recipientResolvePage->setRecipientPreferences( shared_ptr( new KConfigBasedRecipientPreferences( KGlobal::config() ) ) ); signerResolvePage->setSigningPreferences( shared_ptr( new KConfigBasedSigningPreferences( KGlobal::config() ) ) ); q->resize( QSize( 640, 480 ).expandedTo( q->sizeHint() ) ); } void SignEncryptWizard::onNext( int currentId ) { if ( currentId == ResolveRecipientsPage ) QTimer::singleShot( 0, this, SIGNAL(recipientsResolved()) ); if ( currentId == ResolveSignerPage ) { //FIXME: Sign&Encrypt is only supported by OpenPGP. Remove this when we support this for CMS, too if ( encryptionSelected() && signingSelected() ) setPresetProtocol( OpenPGP ); QTimer::singleShot( 0, this, SIGNAL(signersResolved()) ); } if ( currentId == ObjectsPage ) QTimer::singleShot( 0, this, SIGNAL(objectsResolved()) ); } SignEncryptWizard::Private::~Private() {} SignEncryptWizard::SignEncryptWizard( QWidget * p, Qt::WindowFlags f ) : Wizard( p, f ), d( new Private( this ) ) { } SignEncryptWizard::~SignEncryptWizard() {} void SignEncryptWizard::setCommitPage( Page page ) { d->setCommitPage( page ); } void SignEncryptWizard::Private::setCommitPage( Page page ) { q->page( ResolveSignerPage )->setCommitPage( false ); q->page( ResolveRecipientsPage )->setCommitPage( false ); q->page( ObjectsPage )->setCommitPage( false ); q->page( ResultPage )->setCommitPage( false ); q->page( page )->setCommitPage( true ); } void SignEncryptWizard::setPresetProtocol( Protocol proto ) { d->signerResolvePage->setPresetProtocol( proto ); d->signerResolvePage->setProtocolSelectionUserMutable( proto == UnknownProtocol ); d->recipientResolvePage->setPresetProtocol( proto ); } GpgME::Protocol SignEncryptWizard::selectedProtocol() const { return d->recipientResolvePage->selectedProtocol(); } GpgME::Protocol SignEncryptWizard::presetProtocol() const { return d->recipientResolvePage->presetProtocol(); } void SignEncryptWizard::setEncryptionSelected( bool selected ) { d->signerResolvePage->setEncryptionSelected( selected ); } void SignEncryptWizard::setSigningSelected( bool selected ) { d->signerResolvePage->setSigningSelected( selected ); } bool SignEncryptWizard::isSigningUserMutable() const { return d->signerResolvePage->isSigningUserMutable(); } void SignEncryptWizard::setSigningUserMutable( bool isMutable ) { d->signerResolvePage->setSigningUserMutable( isMutable ); } bool SignEncryptWizard::isEncryptionUserMutable() const { return d->signerResolvePage->isEncryptionUserMutable(); } bool SignEncryptWizard::isMultipleProtocolsAllowed() const { return d->recipientResolvePage->multipleProtocolsAllowed(); } void SignEncryptWizard::setMultipleProtocolsAllowed( bool allowed ) { d->signerResolvePage->setMultipleProtocolsAllowed( allowed ); d->recipientResolvePage->setMultipleProtocolsAllowed( allowed ); } void SignEncryptWizard::setEncryptionUserMutable( bool isMutable ) { d->signerResolvePage->setEncryptionUserMutable( isMutable ); } void SignEncryptWizard::setFiles( const QStringList & files ) { d->objectsPage->setFiles( files ); } QFileInfoList SignEncryptWizard::resolvedFiles() const { const QStringList files = d->objectsPage->files(); QFileInfoList fileInfos; Q_FOREACH( const QString& i, files ) fileInfos.push_back( QFileInfo( i ) ); return fileInfos; } bool SignEncryptWizard::signingSelected() const { return d->signerResolvePage->signingSelected(); } bool SignEncryptWizard::encryptionSelected() const { return d->signerResolvePage->encryptionSelected(); } void SignEncryptWizard::setRecipients( const std::vector & recipients, const std::vector & encryptToSelfRecipients ) { d->recipientResolvePage->setRecipients( recipients, encryptToSelfRecipients ); } void SignEncryptWizard::setSignersAndCandidates( const std::vector & signers, const std::vector< std::vector > & keys ) { d->signerResolvePage->setSignersAndCandidates( signers, keys ); } void SignEncryptWizard::setTaskCollection( const shared_ptr & coll ) { kleo_assert( coll ); d->resultPage->setTaskCollection( coll ); } std::vector SignEncryptWizard::resolvedCertificates() const { return d->recipientResolvePage->resolvedCertificates(); } std::vector SignEncryptWizard::resolvedSigners() const { return d->signerResolvePage->resolvedSigners(); } bool SignEncryptWizard::isAsciiArmorEnabled() const { return d->signerResolvePage->isAsciiArmorEnabled(); } void SignEncryptWizard::setAsciiArmorEnabled( bool enabled ) { d->signerResolvePage->setAsciiArmorEnabled( enabled ); } bool SignEncryptWizard::removeUnencryptedFile() const { return d->signerResolvePage->removeUnencryptedFile(); } void SignEncryptWizard::setRemoveUnencryptedFile( bool remove ) { d->signerResolvePage->setRemoveUnencryptedFile( remove ); } bool SignEncryptWizard::recipientsUserMutable() const { return d->recipientResolvePage->recipientsUserMutable(); } void SignEncryptWizard::setRecipientsUserMutable( bool isMutable ) { d->recipientResolvePage->setRecipientsUserMutable( isMutable ); } void SignEncryptWizard::setSignerResolvePageValidator( const boost::shared_ptr& validator ) { d->signerResolvePage->setValidator( validator ); } Gui::SignerResolvePage* SignEncryptWizard::signerResolvePage() { return d->signerResolvePage; } const Gui::SignerResolvePage* SignEncryptWizard::signerResolvePage() const { return d->signerResolvePage; } Gui::ResolveRecipientsPage* SignEncryptWizard::resolveRecipientsPage() { return d->recipientResolvePage; } Gui::ObjectsPage* SignEncryptWizard::objectsPage() { return d->objectsPage; } Gui::ResultPage* SignEncryptWizard::resultPage() { return d->resultPage; } bool SignEncryptWizard::keepResultPageOpenWhenDone() const { return d->resultPage->keepOpenWhenDone(); } void SignEncryptWizard::setKeepResultPageOpenWhenDone( bool keep ) { d->resultPage->setKeepOpenWhenDone( keep ); } diff --git a/kleopatra/crypto/gui/signencryptwizard.h b/kleopatra/crypto/gui/signencryptwizard.h index d5475b3635..2b55bdaf28 100644 --- a/kleopatra/crypto/gui/signencryptwizard.h +++ b/kleopatra/crypto/gui/signencryptwizard.h @@ -1,163 +1,165 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/gui/signencryptwizard.h This file is part of Kleopatra, the KDE keymanager Copyright (c) 2007 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #ifndef __KLEOPATRA_CRYPTO_GUI_SIGNENCRYPTWIZARD_H__ #define __KLEOPATRA_CRYPTO_GUI_SIGNENCRYPTWIZARD_H__ #include #include #include #include #include +#ifndef Q_MOC_RUN #include +#endif #include namespace GpgME { class Key; } class QFileInfo; template class QList; typedef QList QFileInfoList; namespace Kleo { namespace Crypto { class Task; class TaskCollection; namespace Gui { class ObjectsPage; class ResolveRecipientsPage; class ResultPage; class SignerResolvePage; class SignEncryptWizard : public Wizard { Q_OBJECT public: explicit SignEncryptWizard( QWidget * parent=0, Qt::WindowFlags f=0 ); virtual ~SignEncryptWizard(); enum Page { ResolveSignerPage=0, ObjectsPage, ResolveRecipientsPage, ResultPage }; void setCommitPage( Page ); GpgME::Protocol presetProtocol() const; void setPresetProtocol( GpgME::Protocol proto ); GpgME::Protocol selectedProtocol() const; /// SignOrEncryptFiles mode subinterface //@{ QFileInfoList resolvedFiles() const; void setFiles( const QStringList & files ); bool signingSelected() const; void setSigningSelected( bool selected ); bool encryptionSelected() const; void setEncryptionSelected( bool selected ); bool isSigningUserMutable() const; void setSigningUserMutable( bool isMutable ); bool isEncryptionUserMutable() const; void setEncryptionUserMutable( bool isMutable ); bool isMultipleProtocolsAllowed() const; void setMultipleProtocolsAllowed( bool allowed ); //@} void setRecipients( const std::vector & recipients, const std::vector & encryptoToSelfRecipients ); /** if true, the user is allowed to remove/add recipients via the UI. * Defaults to @p false. */ bool recipientsUserMutable() const; void setRecipientsUserMutable( bool isMutable ); void setSignersAndCandidates( const std::vector & signers, const std::vector< std::vector > & keys ); void setTaskCollection( const boost::shared_ptr & tasks ); std::vector resolvedCertificates() const; std::vector resolvedSigners() const; bool isAsciiArmorEnabled() const; void setAsciiArmorEnabled( bool enabled ); bool removeUnencryptedFile() const; void setRemoveUnencryptedFile( bool remove ); bool keepResultPageOpenWhenDone() const; void setKeepResultPageOpenWhenDone( bool keep ); /*reimp*/ void onNext( int currentId ); Q_SIGNALS: void signersResolved(); void objectsResolved(); void recipientsResolved(); void linkActivated( const QString & link ); protected: Gui::SignerResolvePage* signerResolvePage(); const Gui::SignerResolvePage* signerResolvePage() const; Gui::ObjectsPage* objectsPage(); Gui::ResultPage* resultPage(); Gui::ResolveRecipientsPage* resolveRecipientsPage(); void setSignerResolvePageValidator( const boost::shared_ptr& validator ); private: class Private; kdtools::pimpl_ptr d; }; } } } #endif /* __KLEOPATRA_CRYPTO_GUI_SIGNENCRYPTWIZARD_H__ */ diff --git a/kleopatra/crypto/gui/signerresolvepage.h b/kleopatra/crypto/gui/signerresolvepage.h index a09b9976dc..669e635224 100644 --- a/kleopatra/crypto/gui/signerresolvepage.h +++ b/kleopatra/crypto/gui/signerresolvepage.h @@ -1,148 +1,150 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/gui/signerresolvepage.h This file is part of Kleopatra, the KDE keymanager Copyright (c) 2007 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #ifndef __KLEOPATRA_CRYPTO_GUI_SIGNERRESOLVEPAGE_H__ #define __KLEOPATRA_CRYPTO_GUI_SIGNERRESOLVEPAGE_H__ #include #include #include #include +#ifndef Q_MOC_RUN #include +#endif #include namespace GpgME { class Key; } namespace Kleo { namespace Crypto { class SigningPreferences; namespace Gui { class SignerResolvePage : public WizardPage { Q_OBJECT public: explicit SignerResolvePage( QWidget * parent=0, Qt::WindowFlags f=0 ); ~SignerResolvePage(); void setSignersAndCandidates( const std::vector & signers, const std::vector< std::vector > & keys ); std::vector resolvedSigners() const; std::vector signingCertificates( GpgME::Protocol protocol = GpgME::UnknownProtocol ) const; /*reimpl*/ bool isComplete() const; bool encryptionSelected() const; void setEncryptionSelected( bool selected ); bool signingSelected() const; void setSigningSelected( bool selected ); bool isEncryptionUserMutable() const; void setEncryptionUserMutable( bool ismutable ); bool isSigningUserMutable() const; void setSigningUserMutable( bool ismutable ); bool isAsciiArmorEnabled() const; void setAsciiArmorEnabled( bool enabled ); bool removeUnencryptedFile() const; void setRemoveUnencryptedFile( bool remove ); void setPresetProtocol( GpgME::Protocol protocol ); void setPresetProtocols( const std::vector& protocols ); std::vector selectedProtocols() const; std::vector selectedProtocolsWithoutSigningCertificate() const; void setMultipleProtocolsAllowed( bool allowed ); bool multipleProtocolsAllowed() const; void setProtocolSelectionUserMutable( bool ismutable ); bool protocolSelectionUserMutable() const; enum Operation { SignAndEncrypt=0, SignOnly, EncryptOnly }; Operation operation() const; class Validator { public: virtual ~Validator() {} virtual bool isComplete() const = 0; virtual QString explanation() const = 0; /** * returns a custom window title, or a null string if no custom * title is required. * (use this if the title needs dynamic adaption * depending on the user's selection) */ virtual QString customWindowTitle() const = 0; }; void setValidator( const boost::shared_ptr& ); boost::shared_ptr validator() const; void setSigningPreferences( const boost::shared_ptr& prefs ); boost::shared_ptr signingPreferences() const; private: /*reimpl*/ void onNext(); private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT( d, void operationButtonClicked( int ) ) Q_PRIVATE_SLOT( d, void selectCertificates() ) Q_PRIVATE_SLOT( d, void updateUi() ) }; } } } #endif // __KLEOPATRA_CRYPTO_GUI_SIGNERRESOLVEPAGE_H__ diff --git a/kleopatra/crypto/gui/signingcertificateselectionwidget.cpp b/kleopatra/crypto/gui/signingcertificateselectionwidget.cpp index d3ccd1ccd5..a2e1d5cbd1 100644 --- a/kleopatra/crypto/gui/signingcertificateselectionwidget.cpp +++ b/kleopatra/crypto/gui/signingcertificateselectionwidget.cpp @@ -1,171 +1,173 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/gui/signingcertificateselectionwidget.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2007, 2009 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "signingcertificateselectionwidget.h" #include "ui_signingcertificateselectionwidget.h" #include #include #include #include #include +#ifndef Q_MOC_RUN #include +#endif #include using namespace Kleo; using namespace Kleo::Crypto::Gui; class SigningCertificateSelectionWidget::Private { friend class ::SigningCertificateSelectionWidget; SigningCertificateSelectionWidget * const q; public: explicit Private( SigningCertificateSelectionWidget * qq ); ~Private(); static std::vector candidates( GpgME::Protocol prot ); static void addCandidates( GpgME::Protocol prot, QComboBox* combo ); private: Ui::SigningCertificateSelectionWidget ui; }; static GpgME::Key current_cert( const QComboBox & cb ) { const QByteArray fpr = cb.itemData( cb.currentIndex() ).toByteArray(); return KeyCache::instance()->findByFingerprint( fpr.constData() ); } static void select_cert( QComboBox & cb, const GpgME::Key & key ) { const QByteArray fpr = key.primaryFingerprint(); if ( !fpr.isEmpty() ) cb.setCurrentIndex( cb.findData( fpr ) ); } static void add_cert( QComboBox & cb, const GpgME::Key & key ) { cb.addItem( Formatting::formatForComboBox( key ), QVariant( QByteArray( key.primaryFingerprint() ) ) ); } SigningCertificateSelectionWidget::Private::Private( SigningCertificateSelectionWidget * qq ) : q( qq ), ui() { ui.setupUi( q ); addCandidates( GpgME::CMS, ui.cmsCombo ); addCandidates( GpgME::OpenPGP, ui.pgpCombo ); ui.rememberCO->setChecked( true ); } SigningCertificateSelectionWidget::Private::~Private() {} SigningCertificateSelectionWidget::SigningCertificateSelectionWidget( QWidget * parent, Qt::WindowFlags f ) : QWidget( parent, f ), d( new Private( this ) ) { } SigningCertificateSelectionWidget::~SigningCertificateSelectionWidget() {} void SigningCertificateSelectionWidget::setSelectedCertificates( const QMap& certificates ) { setSelectedCertificates( certificates[GpgME::OpenPGP], certificates[GpgME::CMS] ); } void SigningCertificateSelectionWidget::setSelectedCertificates( const GpgME::Key & pgp, const GpgME::Key & cms ) { select_cert( *d->ui.pgpCombo, pgp ); select_cert( *d->ui.cmsCombo, cms ); } std::vector SigningCertificateSelectionWidget::Private::candidates( GpgME::Protocol prot ) { assert( prot != GpgME::UnknownProtocol ); std::vector keys = KeyCache::instance()->keys(); std::vector::iterator end = keys.end(); end = std::remove_if( keys.begin(), end, boost::bind( &GpgME::Key::protocol, _1 ) != prot ); end = std::remove_if( keys.begin(), end, !boost::bind( &GpgME::Key::hasSecret, _1 ) ); assert( kdtools::all( keys.begin(), end, boost::bind( &GpgME::Key::hasSecret, _1 ) ) ); end = std::remove_if( keys.begin(), end, !boost::bind( &GpgME::Key::canReallySign, _1 ) ); end = std::remove_if( keys.begin(), end, boost::bind( &GpgME::Key::isExpired, _1 ) ); end = std::remove_if( keys.begin(), end, boost::bind( &GpgME::Key::isRevoked, _1 ) ); keys.erase( end, keys.end() ); return keys; } void SigningCertificateSelectionWidget::Private::addCandidates( GpgME::Protocol prot, QComboBox* combo ) { const std::vector keys = candidates( prot ); Q_FOREACH( const GpgME::Key& i, keys ) add_cert( *combo, i ); } QMap SigningCertificateSelectionWidget::selectedCertificates() const { QMap res; res.insert( GpgME::OpenPGP, current_cert( *d->ui.pgpCombo ) ); res.insert( GpgME::CMS, current_cert( *d->ui.cmsCombo ) ); return res; } bool SigningCertificateSelectionWidget::rememberAsDefault() const { return d->ui.rememberCO->isChecked(); } void SigningCertificateSelectionWidget::setAllowedProtocols( const QVector& allowedProtocols ) { setAllowedProtocols( allowedProtocols.contains( GpgME::OpenPGP ), allowedProtocols.contains( GpgME::CMS ) ); } void SigningCertificateSelectionWidget::setAllowedProtocols( bool pgp, bool cms ) { d->ui.pgpLabel->setVisible( pgp ); d->ui.pgpCombo->setVisible( pgp ); d->ui.cmsLabel->setVisible( cms ); d->ui.cmsCombo->setVisible( cms ); } diff --git a/kleopatra/crypto/gui/verifychecksumsdialog.cpp b/kleopatra/crypto/gui/verifychecksumsdialog.cpp index 16d1885e05..84eae31b78 100644 --- a/kleopatra/crypto/gui/verifychecksumsdialog.cpp +++ b/kleopatra/crypto/gui/verifychecksumsdialog.cpp @@ -1,389 +1,391 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/gui/verifychecksumsdialog.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2010 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "verifychecksumsdialog.h" #ifndef QT_NO_DIRMODEL #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#ifndef Q_MOC_RUN #include +#endif #include using namespace Kleo; using namespace Kleo::Crypto; using namespace Kleo::Crypto::Gui; using namespace boost; namespace { static Qt::GlobalColor statusColor[] = { Qt::color0, // Unknown - nothing Qt::green, // OK Qt::red, // Failed Qt::darkRed, // Error }; BOOST_STATIC_ASSERT((sizeof statusColor/sizeof *statusColor == VerifyChecksumsDialog::NumStatii)); class ColorizedFileSystemModel : public QDirModel { Q_OBJECT public: explicit ColorizedFileSystemModel( QObject * parent=0 ) : QDirModel( parent ), statusMap() { } /* reimp */ QVariant data( const QModelIndex & mi, int role=Qt::DisplayRole ) const { if ( mi.isValid() && role == Qt::BackgroundRole ) { const QHash::const_iterator it = statusMap.find( filePath( mi ) ); if ( it != statusMap.end() ) if ( const Qt::GlobalColor c = statusColor[*it] ) return c; } return QDirModel::data( mi, role ); } public Q_SLOTS: void setStatus( const QString & file, VerifyChecksumsDialog::Status status ) { if ( status >= VerifyChecksumsDialog::NumStatii || file.isEmpty() ) return; // canonicalize filename: const QModelIndex mi = index( file ); const QString canonical = filePath( mi ); if ( canonical.isEmpty() ) { kDebug() << "can't locate file " << file; return; } const QHash::iterator it = statusMap.find( canonical ); if ( it != statusMap.end() ) if ( *it == status ) return; // nothing to do else *it = status; else statusMap[canonical] = status; emitDataChangedFor( mi ); } void clearStatusInformation() { using std::swap; QHash oldStatusMap; swap( statusMap, oldStatusMap ); for ( QHash::const_iterator it = oldStatusMap.constBegin(), end = oldStatusMap.constEnd() ; it != end ; ++it ) emitDataChangedFor( it.key() ); } private: void emitDataChangedFor( const QString & file ) { emitDataChangedFor( index( file ) ); } void emitDataChangedFor( const QModelIndex & mi ) { const QModelIndex p = parent( mi ); emit dataChanged( index( mi.row(), 0, p ), index( mi.row(), columnCount( p ) - 1, p ) ); } private: QHash statusMap; }; static int find_layout_item( const QBoxLayout & blay ) { for ( int i = 0, end = blay.count() ; i < end ; ++i ) if ( QLayoutItem * item = blay.itemAt( i ) ) if ( item->layout() ) return i; return 0; } struct BaseWidget { QSortFilterProxyModel proxy; QLabel label; QTreeView view; BaseWidget( QDirModel * model, QWidget * parent, QVBoxLayout * vlay ) : proxy(), label( parent ), view( parent ) { KDAB_SET_OBJECT_NAME( proxy ); KDAB_SET_OBJECT_NAME( label ); KDAB_SET_OBJECT_NAME( view ); const int row = find_layout_item( *vlay ); vlay->insertWidget( row, &label ); vlay->insertWidget( row+1, &view, 1 ); proxy.setSourceModel( model ); view.setModel( &proxy ); QRect r; for( int i = 0; i < proxy.columnCount(); ++i ) view.resizeColumnToContents( i ); // define some minimum sizes view.header()->resizeSection( 0, qMax( view.header()->sectionSize( 0 ), 220 ) ); view.header()->resizeSection( 1, qMax( view.header()->sectionSize( 1 ), 75 ) ); view.header()->resizeSection( 2, qMax( view.header()->sectionSize( 2 ), 75 ) ); view.header()->resizeSection( 3, qMax( view.header()->sectionSize( 3 ), 140 ) ); for( int i = 0; i < proxy.rowCount(); ++i ) r = r.united( view.visualRect( proxy.index( proxy.columnCount() - 1, i ) ) ); view.setMinimumSize( QSize( qBound( r.width() + 4 * view.frameWidth(), 220+75+75+140 + 4 * view.frameWidth(), 1024 ), // 100 is the default defaultSectionSize qBound( r.height(), 220, 512 ) ) ); } void setBase( const QString & base ) { label.setText( base ); if ( QDirModel * fsm = qobject_cast( proxy.sourceModel() ) ) { view.setRootIndex( proxy.mapFromSource( fsm->index( base ) ) ); } else { kWarning() << "expect a QDirModel-derived class as proxy.sourceModel(), got "; if ( !proxy.sourceModel() ) { kWarning() << "a null pointer"; } else { kWarning() << proxy.sourceModel()->metaObject()->className(); } } } }; } // anon namespace class VerifyChecksumsDialog::Private { friend class ::Kleo::Crypto::Gui::VerifyChecksumsDialog; VerifyChecksumsDialog * const q; public: explicit Private( VerifyChecksumsDialog * qq ) : q( qq ), bases(), errors(), model(), ui( q ) { qRegisterMetaType( "Kleo::Crypto::Gui::VerifyChecksumsDialog::Status" ); } private: void slotErrorButtonClicked() { KMessageBox::errorList( q, i18n("The following errors and warnings were recorded:"), errors, i18n("Checksum Verification Errors") ); } private: void updateErrors() { const bool active = ui.isProgressBarActive(); ui.progressLabel.setVisible( active ); ui.progressBar. setVisible( active ); ui.errorLabel. setVisible( !active ); ui.errorButton. setVisible( !active && !errors.empty() ); if ( errors.empty() ) ui.errorLabel.setText( i18n("No errors occurred" ) ); else ui.errorLabel.setText( i18np( "One error occurred", "%1 errors occurred", errors.size() ) ); } private: QStringList bases; QStringList errors; ColorizedFileSystemModel model; struct UI { std::vector baseWidgets; QLabel progressLabel; QProgressBar progressBar; QLabel errorLabel; QPushButton errorButton; QDialogButtonBox buttonBox; QVBoxLayout vlay; QHBoxLayout hlay[2]; explicit UI( VerifyChecksumsDialog * q ) : baseWidgets(), progressLabel( i18n("Progress:"), q ), progressBar( q ), errorLabel( i18n("No errors occurred"), q ), errorButton( i18nc("Show Errors","Show"), q ), buttonBox( QDialogButtonBox::Close, Qt::Horizontal, q ), vlay( q ) { KDAB_SET_OBJECT_NAME( progressLabel ); KDAB_SET_OBJECT_NAME( progressBar ); KDAB_SET_OBJECT_NAME( errorLabel ); KDAB_SET_OBJECT_NAME( errorButton ); KDAB_SET_OBJECT_NAME( buttonBox ); KDAB_SET_OBJECT_NAME( vlay ); KDAB_SET_OBJECT_NAME( hlay[0] ); KDAB_SET_OBJECT_NAME( hlay[1] ); errorButton.setAutoDefault( false ); hlay[0].addWidget( &progressLabel ); hlay[0].addWidget( &progressBar, 1 ); hlay[1].addWidget( &errorLabel, 1 ); hlay[1].addWidget( &errorButton ); vlay.addLayout( &hlay[0] ); vlay.addLayout( &hlay[1] ); vlay.addWidget( &buttonBox ); errorLabel.hide(); errorButton.hide(); QPushButton * close = closeButton(); connect( close, SIGNAL(clicked()), q, SIGNAL(canceled()) ); connect( close, SIGNAL(clicked()), q, SLOT(accept()) ); connect( &errorButton, SIGNAL(clicked()), q, SLOT(slotErrorButtonClicked()) ); } ~UI() { qDeleteAll( baseWidgets ); } QPushButton * closeButton() const { return buttonBox.button( QDialogButtonBox::Close ); } void setBases( const QStringList & bases, QDirModel * model ) { // create new BaseWidgets: for ( unsigned int i = baseWidgets.size(), end = bases.size() ; i < end ; ++i ) baseWidgets.push_back( new BaseWidget( model, vlay.parentWidget(), &vlay ) ); // shed surplus BaseWidgets: for ( unsigned int i = bases.size(), end = baseWidgets.size() ; i < end ; ++i ) { delete baseWidgets.back(); baseWidgets.pop_back(); } assert( static_cast( bases.size() ) == baseWidgets.size() ); // update bases: for ( unsigned int i = 0 ; i < baseWidgets.size() ; ++i ) baseWidgets[i]->setBase( bases[i] ); } void setProgress( int cur, int tot ) { progressBar.setMaximum( tot ); progressBar.setValue( cur ); } bool isProgressBarActive() const { const int tot = progressBar.maximum(); const int cur = progressBar.value(); return !tot || cur != tot ; } } ui; }; VerifyChecksumsDialog::VerifyChecksumsDialog( QWidget * parent, Qt::WindowFlags flags ) : QDialog( parent, flags ), d( new Private( this ) ) { } VerifyChecksumsDialog::~VerifyChecksumsDialog() {} // slot void VerifyChecksumsDialog::setBaseDirectories( const QStringList & bases ) { if ( d->bases == bases ) return; d->bases = bases; d->ui.setBases( bases, &d->model ); } // slot void VerifyChecksumsDialog::setErrors( const QStringList & errors ) { if ( d->errors == errors ) return; d->errors = errors; d->updateErrors(); } // slot void VerifyChecksumsDialog::setProgress( int cur, int tot ) { d->ui.setProgress( cur, tot ); d->updateErrors(); } // slot void VerifyChecksumsDialog::setStatus( const QString & file, Status status ) { d->model.setStatus( file, status ); } // slot void VerifyChecksumsDialog::clearStatusInformation() { d->errors.clear(); d->updateErrors(); d->model.clearStatusInformation(); } #include "verifychecksumsdialog.moc" #include "moc_verifychecksumsdialog.cpp" #endif // QT_NO_DIRMODEL diff --git a/kleopatra/crypto/newsignencryptemailcontroller.cpp b/kleopatra/crypto/newsignencryptemailcontroller.cpp index 9e91f7d28c..b152a00249 100644 --- a/kleopatra/crypto/newsignencryptemailcontroller.cpp +++ b/kleopatra/crypto/newsignencryptemailcontroller.cpp @@ -1,569 +1,571 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/newsignencryptemailcontroller.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2009,2010 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "newsignencryptemailcontroller.h" #include "encryptemailtask.h" #include "signemailtask.h" #include "taskcollection.h" #include "sender.h" #include "recipient.h" #include "emailoperationspreferences.h" #include #include #include #include #include #include #include #include #include #include #include #include #include +#ifndef Q_MOC_RUN #include #include +#endif using namespace Kleo; using namespace Kleo::Crypto; using namespace Kleo::Crypto::Gui; using namespace boost; using namespace GpgME; using namespace KMime::Types; // // BEGIN Conflict Detection // /* This code implements the following conflict detection algortihm: 1. There is no conflict if and only if we have a Perfect Match. 2. A Perfect Match is defined as: a. either a Perfect OpenPGP-Match and not even a Partial S/MIME Match b. or a Perfect S/MIME-Match and not even a Partial OpenPGP-Match c. or a Perfect OpenPGP-Match and preselected protocol=OpenPGP d. or a Perfect S/MIME-Match and preselected protocol=S/MIME 3. For Protocol \in {OpenPGP,S/MIME}, a Perfect Protocol-Match is defined as: a. If signing, \foreach Sender, there is exactly one Matching Protocol-Certificate with i. can-sign=true ii. has-secret=true b. and, if encrypting, \foreach Recipient, there is exactly one Matching Protocol-Certificate with i. can-encrypt=true ii. (validity is not considered, cf. msg 24059) 4. For Protocol \in {OpenPGP,S/MIME}, a Partial Protocol-Match is defined as: a. If signing, \foreach Sender, there is at least one Matching Protocol-Certificate with i. can-sign=true ii. has-secret=true b. and, if encrypting, \foreach Recipient, there is at least one Matching Protocol-Certificate with i. can-encrypt=true ii. (validity is not considered, cf. msg 24059) 5. For Protocol \in {OpenPGP,S/MIME}, a Matching Protocol-Certificate is defined as matching by email-address. A revoked, disabled, or expired certificate is not considered a match. 6. Sender is defined as those mailboxes that have been set with the SENDER command. 7. Recipient is defined as those mailboxes that have been set with either the SENDER or the RECIPIENT commands. */ namespace { struct count_signing_certificates { typedef size_t result_type; const Protocol proto; explicit count_signing_certificates( Protocol proto ) : proto( proto ) {} size_t operator()( const Sender & sender ) const { const size_t result = sender.signingCertificateCandidates( proto ).size(); qDebug( "count_signing_certificates( %9s %20s ) == %2lu", proto == OpenPGP ? "OpenPGP," : proto == CMS ? "CMS," : ",", qPrintable( sender.mailbox().prettyAddress() ), result ); return result; } }; struct count_encrypt_certificates { typedef size_t result_type; const Protocol proto; explicit count_encrypt_certificates( Protocol proto ) : proto( proto ) {} size_t operator()( const Sender & sender ) const { const size_t result = sender.encryptToSelfCertificateCandidates( proto ).size(); qDebug( "count_encrypt_certificates( %9s %20s ) == %2lu", proto == OpenPGP ? "OpenPGP," : proto == CMS ? "CMS," : ",", qPrintable( sender.mailbox().prettyAddress() ), result ); return result; } size_t operator()( const Recipient & recipient ) const { const size_t result = recipient.encryptionCertificateCandidates( proto ).size(); qDebug( "count_encrypt_certificates( %9s %20s ) == %2lu", proto == OpenPGP ? "OpenPGP," : proto == CMS ? "CMS," : ",", qPrintable( recipient.mailbox().prettyAddress() ), result ); return result; } }; } static bool has_perfect_match( bool sign, bool encrypt, Protocol proto, const std::vector & senders, const std::vector & recipients ) { if ( sign ) if ( !kdtools::all( senders, boost::bind( count_signing_certificates( proto ), _1 ) == 1 ) ) return false; if ( encrypt ) if ( !kdtools::all( senders, boost::bind( count_encrypt_certificates( proto ), _1 ) == 1 ) || !kdtools::all( recipients, boost::bind( count_encrypt_certificates( proto ), _1 ) == 1 ) ) return false; return true; } static bool has_partial_match( bool sign, bool encrypt, Protocol proto, const std::vector & senders, const std::vector & recipients ) { if ( sign ) if ( !kdtools::all( senders, boost::bind( count_signing_certificates( proto ), _1 ) >= 1 ) ) return false; if ( encrypt ) if ( !kdtools::all( senders, boost::bind( count_encrypt_certificates( proto ), _1 ) >= 1 ) || !kdtools::all( recipients, boost::bind( count_encrypt_certificates( proto ), _1 ) >= 1 ) ) return false; return true; } static bool has_perfect_overall_match( bool sign, bool encrypt, const std::vector & senders, const std::vector & recipients, Protocol presetProtocol ) { return presetProtocol == OpenPGP && has_perfect_match( sign, encrypt, OpenPGP, senders, recipients ) || presetProtocol == CMS && has_perfect_match( sign, encrypt, CMS, senders, recipients ) || has_perfect_match( sign, encrypt, OpenPGP, senders, recipients ) && !has_partial_match( sign, encrypt, CMS, senders, recipients ) || has_perfect_match( sign, encrypt, CMS, senders, recipients ) && !has_partial_match( sign, encrypt, OpenPGP, senders, recipients ) ; } static bool has_conflict( bool sign, bool encrypt, const std::vector & senders, const std::vector & recipients, Protocol presetProtocol ) { return !has_perfect_overall_match( sign, encrypt, senders, recipients, presetProtocol ); } // // END Conflict Detection // static std::vector mailbox2sender( const std::vector & mbs ) { std::vector senders; senders.reserve( mbs.size() ); Q_FOREACH( const Mailbox & mb, mbs ) senders.push_back( Sender( mb ) ); return senders; } static std::vector mailbox2recipient( const std::vector & mbs ) { std::vector recipients; recipients.reserve( mbs.size() ); Q_FOREACH( const Mailbox & mb, mbs ) recipients.push_back( Recipient( mb ) ); return recipients; } class NewSignEncryptEMailController::Private { friend class ::Kleo::Crypto::NewSignEncryptEMailController; NewSignEncryptEMailController * const q; public: explicit Private( NewSignEncryptEMailController * qq ); ~Private(); private: void slotDialogAccepted(); void slotDialogRejected(); private: void ensureDialogVisible(); void cancelAllTasks(); void startSigning(); void startEncryption(); void schedule(); shared_ptr takeRunnable( GpgME::Protocol proto ); private: bool sign : 1; bool encrypt : 1; bool resolvingInProgress : 1; bool certificatesResolved : 1; bool detached : 1; Protocol presetProtocol; std::vector signers, recipients; std::vector< shared_ptr > runnable, completed; shared_ptr cms, openpgp; QPointer dialog; }; NewSignEncryptEMailController::Private::Private( NewSignEncryptEMailController * qq ) : q( qq ), sign( false ), encrypt( false ), resolvingInProgress( false ), certificatesResolved( false ), detached( false ), presetProtocol( UnknownProtocol ), signers(), recipients(), runnable(), cms(), openpgp(), dialog( new SignEncryptEMailConflictDialog ) { connect( dialog, SIGNAL(accepted()), q, SLOT(slotDialogAccepted()) ); connect( dialog, SIGNAL(rejected()), q, SLOT(slotDialogRejected()) ); } NewSignEncryptEMailController::Private::~Private() { delete dialog; } NewSignEncryptEMailController::NewSignEncryptEMailController( const shared_ptr & xc, QObject * p ) : Controller( xc, p ), d( new Private( this ) ) { } NewSignEncryptEMailController::NewSignEncryptEMailController( QObject * p ) : Controller( p ), d( new Private( this ) ) { } NewSignEncryptEMailController::~NewSignEncryptEMailController() { kDebug(); } void NewSignEncryptEMailController::setSubject( const QString & subject ) { d->dialog->setSubject( subject ); } void NewSignEncryptEMailController::setProtocol( Protocol proto ) { d->presetProtocol = proto; d->dialog->setPresetProtocol( proto ); } Protocol NewSignEncryptEMailController::protocol() const { return d->dialog->selectedProtocol(); } const char * NewSignEncryptEMailController::protocolAsString() const { switch ( protocol() ) { case OpenPGP: return "OpenPGP"; case CMS: return "CMS"; default: throw Kleo::Exception( gpg_error( GPG_ERR_INTERNAL ), i18n("Call to NewSignEncryptEMailController::protocolAsString() is ambiguous.") ); } } void NewSignEncryptEMailController::setSigning( bool sign ) { d->sign = sign; d->dialog->setSign( sign ); } bool NewSignEncryptEMailController::isSigning() const { return d->sign; } void NewSignEncryptEMailController::setEncrypting( bool encrypt ) { d->encrypt = encrypt; d->dialog->setEncrypt( encrypt ); } bool NewSignEncryptEMailController::isEncrypting() const { return d->encrypt; } void NewSignEncryptEMailController::setDetachedSignature( bool detached ) { d->detached = detached; } bool NewSignEncryptEMailController::isResolvingInProgress() const { return d->resolvingInProgress; } bool NewSignEncryptEMailController::areCertificatesResolved() const { return d->certificatesResolved; } static bool is_dialog_quick_mode( bool sign, bool encrypt ) { const EMailOperationsPreferences prefs; return ( !sign || prefs.quickSignEMail() ) && ( !encrypt || prefs.quickEncryptEMail() ) ; } static void save_dialog_quick_mode( bool on ) { EMailOperationsPreferences prefs; prefs.setQuickSignEMail( on ); prefs.setQuickEncryptEMail( on ); prefs.writeConfig(); } void NewSignEncryptEMailController::startResolveCertificates( const std::vector & r, const std::vector & s ) { d->certificatesResolved = false; d->resolvingInProgress = true; const std::vector senders = mailbox2sender( s ); const std::vector recipients = mailbox2recipient( r ); const bool quickMode = is_dialog_quick_mode( d->sign, d->encrypt ); const bool conflict = quickMode && has_conflict( d->sign, d->encrypt, senders, recipients, d->presetProtocol ); d->dialog->setQuickMode( quickMode ); d->dialog->setSenders( senders ); d->dialog->setRecipients( recipients ); d->dialog->pickProtocol(); d->dialog->setConflict( conflict ); if ( quickMode && !conflict ) QMetaObject::invokeMethod( this, "slotDialogAccepted", Qt::QueuedConnection ); else d->ensureDialogVisible(); } void NewSignEncryptEMailController::Private::slotDialogAccepted() { if ( dialog->isQuickMode() != is_dialog_quick_mode( sign, encrypt ) ) save_dialog_quick_mode( dialog->isQuickMode() ); resolvingInProgress = false; certificatesResolved = true; signers = dialog->resolvedSigningKeys(); recipients = dialog->resolvedEncryptionKeys(); QMetaObject::invokeMethod( q, "certificatesResolved", Qt::QueuedConnection ); } void NewSignEncryptEMailController::Private::slotDialogRejected() { resolvingInProgress = false; certificatesResolved = false; QMetaObject::invokeMethod( q, "error", Qt::QueuedConnection, Q_ARG( int, gpg_error( GPG_ERR_CANCELED ) ), Q_ARG( QString, i18n("User cancel") ) ); } void NewSignEncryptEMailController::startEncryption( const std::vector< shared_ptr > & inputs, const std::vector< shared_ptr > & outputs ) { kleo_assert( d->encrypt ); kleo_assert( !d->resolvingInProgress ); kleo_assert( !inputs.empty() ); kleo_assert( outputs.size() == inputs.size() ); std::vector< shared_ptr > tasks; tasks.reserve( inputs.size() ); kleo_assert( !d->recipients.empty() ); for ( unsigned int i = 0, end = inputs.size() ; i < end ; ++i ) { const shared_ptr task( new EncryptEMailTask ); task->setInput( inputs[i] ); task->setOutput( outputs[i] ); task->setRecipients( d->recipients ); tasks.push_back( task ); } // append to runnable stack d->runnable.insert( d->runnable.end(), tasks.begin(), tasks.end() ); d->startEncryption(); } void NewSignEncryptEMailController::Private::startEncryption() { shared_ptr coll( new TaskCollection ); const std::vector > tmp = kdtools::copy< std::vector > >( runnable ); coll->setTasks( tmp ); #if 0 #warning use a new result dialog // ### use a new result dialog dialog->setTaskCollection( coll ); #endif Q_FOREACH( const shared_ptr & t, tmp ) q->connectTask( t ); schedule(); } void NewSignEncryptEMailController::startSigning( const std::vector< shared_ptr > & inputs, const std::vector< shared_ptr > & outputs ) { kleo_assert( d->sign ); kleo_assert( !d->resolvingInProgress ); kleo_assert( !inputs.empty() ); kleo_assert( !outputs.empty() ); std::vector< shared_ptr > tasks; tasks.reserve( inputs.size() ); kleo_assert( !d->signers.empty() ); kleo_assert( kdtools::none_of( d->signers, mem_fn( &Key::isNull ) ) ); for ( unsigned int i = 0, end = inputs.size() ; i < end ; ++i ) { const shared_ptr task( new SignEMailTask ); task->setInput( inputs[i] ); task->setOutput( outputs[i] ); task->setSigners( d->signers ); task->setDetachedSignature( d->detached ); tasks.push_back( task ); } // append to runnable stack d->runnable.insert( d->runnable.end(), tasks.begin(), tasks.end() ); d->startSigning(); } void NewSignEncryptEMailController::Private::startSigning() { shared_ptr coll( new TaskCollection ); const std::vector > tmp = kdtools::copy< std::vector > >( runnable ); coll->setTasks( tmp ); #if 0 #warning use a new result dialog // ### use a new result dialog dialog->setTaskCollection( coll ); #endif Q_FOREACH( const shared_ptr & t, tmp ) q->connectTask( t ); schedule(); } void NewSignEncryptEMailController::Private::schedule() { if ( !cms ) if ( const shared_ptr t = takeRunnable( CMS ) ) { t->start(); cms = t; } if ( !openpgp ) if ( const shared_ptr t = takeRunnable( OpenPGP ) ) { t->start(); openpgp = t; } if ( cms || openpgp ) return; kleo_assert( runnable.empty() ); q->emitDoneOrError(); } shared_ptr NewSignEncryptEMailController::Private::takeRunnable( GpgME::Protocol proto ) { const std::vector< shared_ptr >::iterator it = std::find_if( runnable.begin(), runnable.end(), boost::bind( &Task::protocol, _1 ) == proto ); if ( it == runnable.end() ) return shared_ptr(); const shared_ptr result = *it; runnable.erase( it ); return result; } void NewSignEncryptEMailController::doTaskDone( const Task * task, const shared_ptr & result ) { assert( task ); if ( result && result->hasError() ) { QPointer that = this; if ( result->details().isEmpty() ) KMessageBox:: sorry( 0, result->overview(), i18nc("@title:window","Error") ); else KMessageBox::detailedSorry( 0, result->overview(), result->details(), i18nc("@title:window","Error") ); if ( !that ) return; } // We could just delete the tasks here, but we can't use // Qt::QueuedConnection here (we need sender()) and other slots // might not yet have executed. Therefore, we push completed tasks // into a burial container if ( task == d->cms.get() ) { d->completed.push_back( d->cms ); d->cms.reset(); } else if ( task == d->openpgp.get() ) { d->completed.push_back( d->openpgp ); d->openpgp.reset(); } QTimer::singleShot( 0, this, SLOT(schedule()) ); } void NewSignEncryptEMailController::cancel() { try { d->dialog->close(); d->cancelAllTasks(); } catch ( const std::exception & e ) { kDebug() << "Caught exception: " << e.what(); } } void NewSignEncryptEMailController::Private::cancelAllTasks() { // we just kill all runnable tasks - this will not result in // signal emissions. runnable.clear(); // a cancel() will result in a call to if ( cms ) cms->cancel(); if ( openpgp ) openpgp->cancel(); } void NewSignEncryptEMailController::Private::ensureDialogVisible() { q->bringToForeground( dialog ); } #include "moc_newsignencryptemailcontroller.cpp" diff --git a/kleopatra/crypto/recipient.h b/kleopatra/crypto/recipient.h index b2cd32b023..70c75aab86 100644 --- a/kleopatra/crypto/recipient.h +++ b/kleopatra/crypto/recipient.h @@ -1,99 +1,101 @@ /* -*- mode: c++; c-basic-offset:4 -*- ./crypto/recipient.h This file is part of Kleopatra, the KDE keymanager Copyright (c) 2009 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #ifndef __KLEOPATRA_CRYPTO_RECIPIENT_H__ #define __KLEOPATRA_CRYPTO_RECIPIENT_H__ #include +#ifndef Q_MOC_RUN #include +#endif #include namespace KMime { namespace Types { class Mailbox; } } namespace GpgME { class Key; class UserID; } namespace Kleo { namespace Crypto { class Recipient { public: Recipient() : d() {} explicit Recipient( const KMime::Types::Mailbox & mailbox ); void swap( Recipient & other ) { d.swap( other.d ); } bool isNull() const { return !d; } bool isEncryptionAmbiguous( GpgME::Protocol protocol ) const; const KMime::Types::Mailbox & mailbox() const; const std::vector & encryptionCertificateCandidates( GpgME::Protocol proto ) const; void setResolvedEncryptionKey( const GpgME::Key & key ); GpgME::Key resolvedEncryptionKey( GpgME::Protocol proto ) const; void setResolvedOpenPGPEncryptionUserID( const GpgME::UserID & uid ); GpgME::UserID resolvedOpenPGPEncryptionUserID() const; friend inline bool operator==( const Recipient & lhs, const Recipient & rhs ) { return rhs.d == lhs.d || lhs.deepEquals( rhs ) ; } private: void detach(); bool deepEquals( const Recipient & other ) const; private: class Private; boost::shared_ptr d; }; inline bool operator!=( const Recipient & lhs, const Recipient & rhs ) { return !operator==( lhs, rhs ); } } // namespace Crypto } // namespace Kleo #endif /* __KLEOPATRA_CRYPTO_RECIPIENT_H__ */ diff --git a/kleopatra/crypto/sender.h b/kleopatra/crypto/sender.h index c6b67e26b4..df000dd55b 100644 --- a/kleopatra/crypto/sender.h +++ b/kleopatra/crypto/sender.h @@ -1,104 +1,106 @@ /* -*- mode: c++; c-basic-offset:4 -*- ./crypto/sender.h This file is part of Kleopatra, the KDE keymanager Copyright (c) 2009 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #ifndef __KLEOPATRA_CRYPTO_SENDER_H__ #define __KLEOPATRA_CRYPTO_SENDER_H__ #include +#ifndef Q_MOC_RUN #include +#endif #include namespace KMime { namespace Types { class Mailbox; } } namespace GpgME { class Key; class UserID; } namespace Kleo { namespace Crypto { class Sender { public: Sender() : d() {} explicit Sender( const KMime::Types::Mailbox & mailbox ); void swap( Sender & other ) { d.swap( other.d ); } bool isNull() const { return !d; } bool isSigningAmbiguous( GpgME::Protocol proto ) const; bool isEncryptionAmbiguous( GpgME::Protocol proto ) const; const KMime::Types::Mailbox & mailbox() const; const std::vector & signingCertificateCandidates( GpgME::Protocol proto ) const; const std::vector & encryptToSelfCertificateCandidates( GpgME::Protocol proto ) const; void setResolvedSigningKey( const GpgME::Key & key ); GpgME::Key resolvedSigningKey( GpgME::Protocol proto ) const; void setResolvedEncryptionKey( const GpgME::Key & key ); GpgME::Key resolvedEncryptionKey( GpgME::Protocol proto ) const; void setResolvedOpenPGPEncryptionUserID( const GpgME::UserID & uid ); GpgME::UserID resolvedOpenPGPEncryptionUserID() const; friend inline bool operator==( const Sender & lhs, const Sender & rhs ) { return rhs.d == lhs.d || lhs.deepEquals( rhs ); } private: void detach(); bool deepEquals( const Sender & other ) const; private: class Private; boost::shared_ptr d; }; inline bool operator!=( const Sender & lhs, const Sender & rhs ) { return !operator==( lhs, rhs ); } } // namespace Crypto } // namespace Kleo #endif /* __KLEOPATRA_CRYPTO_SENDER_H__ */ diff --git a/kleopatra/crypto/signemailcontroller.cpp b/kleopatra/crypto/signemailcontroller.cpp index f4b2f4cfa2..c7f1b078cd 100644 --- a/kleopatra/crypto/signemailcontroller.cpp +++ b/kleopatra/crypto/signemailcontroller.cpp @@ -1,345 +1,347 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/signemailcontroller.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2007 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "signemailcontroller.h" #include "signemailtask.h" #include "certificateresolver.h" #include "taskcollection.h" #include #include #include #include #include "emailoperationspreferences.h" #include #include #include #include #include +#ifndef Q_MOC_RUN #include #include +#endif using namespace Kleo; using namespace Kleo::Crypto; using namespace Kleo::Crypto::Gui; using namespace boost; using namespace GpgME; using namespace KMime::Types; class SignEMailController::Private { friend class ::Kleo::Crypto::SignEMailController; SignEMailController * const q; public: explicit Private( Mode m, SignEMailController * qq ); ~Private(); private: void slotWizardSignersResolved(); void slotWizardCanceled(); // ### extract to base private: void ensureWizardCreated(); // ### extract to base void ensureWizardVisible(); // ### extract to base void cancelAllJobs(); // ### extract to base void schedule(); // ### extract to base shared_ptr takeRunnable( GpgME::Protocol proto ); // ### extract to base private: const Mode mode; std::vector< shared_ptr > runnable, completed; // ### extract to base shared_ptr cms, openpgp; // ### extract to base QPointer wizard; // ### extract to base Protocol protocol; // ### extract to base bool detached : 1; }; SignEMailController::Private::Private( Mode m, SignEMailController * qq ) : q( qq ), mode( m ), runnable(), cms(), openpgp(), wizard(), protocol( UnknownProtocol ), detached( false ) { } SignEMailController::Private::~Private() {} SignEMailController::SignEMailController( Mode mode, QObject * p ) : Controller( p ), d( new Private( mode, this ) ) { } SignEMailController::SignEMailController( const boost::shared_ptr & xc, Mode mode, QObject * p ) : Controller( xc, p ), d( new Private( mode, this ) ) { } SignEMailController::~SignEMailController() { /// ### extract to base if ( d->wizard && !d->wizard->isVisible() ) delete d->wizard; //d->wizard->close(); ### ? } SignEMailController::Mode SignEMailController::mode() const { return d->mode; } // ### extract to base void SignEMailController::setProtocol( Protocol proto ) { kleo_assert( d->protocol == UnknownProtocol || d->protocol == proto ); d->protocol = proto; d->ensureWizardCreated(); d->wizard->setPresetProtocol( proto ); } Protocol SignEMailController::protocol() const { return d->protocol; } void SignEMailController::startResolveSigners() { startResolveSigners( std::vector() ); } void SignEMailController::startResolveSigners( const std::vector & signers ) { const std::vector< std::vector > keys = CertificateResolver::resolveSigners( signers, d->protocol ); if ( !signers.empty() ) { kleo_assert( keys.size() == static_cast( signers.size() ) ); } d->ensureWizardCreated(); d->wizard->setSignersAndCandidates( signers, keys ); d->ensureWizardVisible(); } void SignEMailController::setDetachedSignature( bool detached ) { kleo_assert( !d->openpgp ); kleo_assert( !d->cms ); kleo_assert( d->completed.empty() ); kleo_assert( d->runnable.empty() ); d->detached = detached; } void SignEMailController::Private::slotWizardSignersResolved() { emit q->signersResolved(); } // ### extract to base void SignEMailController::Private::slotWizardCanceled() { q->setLastError( gpg_error( GPG_ERR_CANCELED ), i18n("User cancel") ); q->emitDoneOrError(); } void SignEMailController::setInputAndOutput( const shared_ptr & input, const shared_ptr & output ) { setInputsAndOutputs( std::vector< shared_ptr >( 1, input ), std::vector< shared_ptr >( 1, output ) ); } // ### extract to base void SignEMailController::setInputsAndOutputs( const std::vector< shared_ptr > & inputs, const std::vector< shared_ptr > & outputs ) { kleo_assert( !inputs.empty() ); kleo_assert( !outputs.empty() ); std::vector< shared_ptr > tasks; tasks.reserve( inputs.size() ); d->ensureWizardCreated(); const std::vector keys = d->wizard->resolvedSigners(); kleo_assert( !keys.empty() ); for ( unsigned int i = 0, end = inputs.size() ; i < end ; ++i ) { const shared_ptr task( new SignEMailTask ); task->setInput( inputs[i] ); task->setOutput( outputs[i] ); task->setSigners( keys ); task->setDetachedSignature( d->detached ); if ( d->mode == ClipboardMode ) { if ( d->protocol == OpenPGP ) task->setClearsign( true ); else task->setAsciiArmor( true ); } tasks.push_back( task ); } d->runnable.swap( tasks ); } // ### extract to base void SignEMailController::start() { shared_ptr coll( new TaskCollection ); std::vector > tmp; std::copy( d->runnable.begin(), d->runnable.end(), std::back_inserter( tmp ) ); coll->setTasks( tmp ); d->ensureWizardCreated(); d->wizard->setTaskCollection( coll ); Q_FOREACH( const shared_ptr & t, tmp ) connectTask( t ); d->schedule(); } // ### extract to base void SignEMailController::Private::schedule() { if ( !cms ) if ( const shared_ptr t = takeRunnable( CMS ) ) { t->start(); cms = t; } if ( !openpgp ) if ( const shared_ptr t = takeRunnable( OpenPGP ) ) { t->start(); openpgp = t; } if ( !cms && !openpgp ) { kleo_assert( runnable.empty() ); QPointer Q = q; Q_FOREACH( const shared_ptr t, completed ) { emit q->reportMicAlg( t->micAlg() ); if ( !Q ) return; } q->emitDoneOrError(); } } // ### extract to base shared_ptr SignEMailController::Private::takeRunnable( GpgME::Protocol proto ) { const std::vector< shared_ptr >::iterator it = std::find_if( runnable.begin(), runnable.end(), boost::bind( &Task::protocol, _1 ) == proto ); if ( it == runnable.end() ) return shared_ptr(); const shared_ptr result = *it; runnable.erase( it ); return result; } // ### extract to base void SignEMailController::doTaskDone( const Task * task, const shared_ptr & result ) { Q_UNUSED( result ); assert( task ); // We could just delete the tasks here, but we can't use // Qt::QueuedConnection here (we need sender()) and other slots // might not yet have executed. Therefore, we push completed tasks // into a burial container if ( task == d->cms.get() ) { d->completed.push_back( d->cms ); d->cms.reset(); } else if ( task == d->openpgp.get() ) { d->completed.push_back( d->openpgp ); d->openpgp.reset(); } QTimer::singleShot( 0, this, SLOT(schedule()) ); } // ### extract to base void SignEMailController::cancel() { try { if ( d->wizard ) d->wizard->close(); d->cancelAllJobs(); } catch ( const std::exception & e ) { kDebug() << "Caught exception: " << e.what(); } } // ### extract to base void SignEMailController::Private::cancelAllJobs() { // we just kill all runnable tasks - this will not result in // signal emissions. runnable.clear(); // a cancel() will result in a call to if ( cms ) cms->cancel(); if ( openpgp ) openpgp->cancel(); } // ### extract to base void SignEMailController::Private::ensureWizardCreated() { if ( wizard ) return; std::auto_ptr w( new SignEMailWizard ); w->setAttribute( Qt::WA_DeleteOnClose ); connect( w.get(), SIGNAL(signersResolved()), q, SLOT(slotWizardSignersResolved()), Qt::QueuedConnection ); connect( w.get(), SIGNAL(canceled()), q, SLOT(slotWizardCanceled()), Qt::QueuedConnection ); w->setPresetProtocol( protocol ); EMailOperationsPreferences prefs; w->setQuickMode( prefs.quickSignEMail() ); wizard = w.release(); } // ### extract to base void SignEMailController::Private::ensureWizardVisible() { ensureWizardCreated(); q->bringToForeground( wizard ); } #include "moc_signemailcontroller.cpp" diff --git a/kleopatra/crypto/signemailtask.cpp b/kleopatra/crypto/signemailtask.cpp index 12921975b7..ef4c8ff17b 100644 --- a/kleopatra/crypto/signemailtask.cpp +++ b/kleopatra/crypto/signemailtask.cpp @@ -1,286 +1,288 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/signemailtask.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2007 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "signemailtask.h" #include #include #include #include #include #include #include #include #include #include #include #include #include // for Qt::escape +#ifndef Q_MOC_RUN #include #include +#endif using namespace Kleo; using namespace Kleo::Crypto; using namespace boost; using namespace GpgME; namespace { class SignEMailResult : public Task::Result { const SigningResult m_result; const AuditLog m_auditLog; public: explicit SignEMailResult( const SigningResult & r, const AuditLog & auditLog ) : Task::Result(), m_result( r ), m_auditLog( auditLog ) {} /* reimp */ QString overview() const; /* reimp */ QString details() const; /* reimp */ int errorCode() const; /* reimp */ QString errorString() const; /* reimp */ VisualCode code() const; /* reimp */ AuditLog auditLog() const; }; QString makeResultString( const SigningResult& res ) { const Error err = res.error(); if ( err.isCanceled() ) return i18n( "Signing canceled." ); if ( err ) return i18n( "Signing failed: %1", Qt::escape( QString::fromLocal8Bit( err.asString() ) ) ); return i18n( "Signing succeeded." ); } } class SignEMailTask::Private { friend class ::Kleo::Crypto::SignEMailTask; SignEMailTask * const q; public: explicit Private( SignEMailTask * qq ); private: std::auto_ptr createJob( GpgME::Protocol proto ); private: void slotResult( const SigningResult & ); private: shared_ptr input; shared_ptr output; std::vector signers; bool detached; bool clearsign; QString micAlg; QPointer job; }; SignEMailTask::Private::Private( SignEMailTask * qq ) : q( qq ), input(), output(), signers(), detached( false ), clearsign( false ), micAlg(), job( 0 ) { } SignEMailTask::SignEMailTask( QObject * p ) : Task( p ), d( new Private( this ) ) { } SignEMailTask::~SignEMailTask() {} void SignEMailTask::setInput( const shared_ptr & input ) { kleo_assert( !d->job ); kleo_assert( input ); d->input = input; } void SignEMailTask::setOutput( const shared_ptr & output ) { kleo_assert( !d->job ); kleo_assert( output ); d->output = output; } void SignEMailTask::setSigners( const std::vector & signers ) { kleo_assert( !d->job ); kleo_assert( !signers.empty() ); kleo_assert( kdtools::none_of( signers, mem_fn( &Key::isNull ) ) ); d->signers = signers; } void SignEMailTask::setDetachedSignature( bool detached ) { kleo_assert( !d->job ); d->detached = detached; d->clearsign = false; } void SignEMailTask::setClearsign( bool clear ) { kleo_assert( !d->job ); d->clearsign = clear; d->detached = false; } Protocol SignEMailTask::protocol() const { kleo_assert( !d->signers.empty() ); return d->signers.front().protocol(); } QString SignEMailTask::label() const { return d->input ? d->input->label() : QString(); } unsigned long long SignEMailTask::inputSize() const { return d->input ? d->input->size() : 0; } void SignEMailTask::doStart() { kleo_assert( !d->job ); kleo_assert( d->input ); kleo_assert( d->output ); kleo_assert( !d->signers.empty() ); d->micAlg.clear(); std::auto_ptr job = d->createJob( protocol() ); kleo_assert( job.get() ); job->start( d->signers, d->input->ioDevice(), d->output->ioDevice(), d->clearsign ? GpgME::Clearsigned : d->detached ? GpgME::Detached : GpgME::NormalSignatureMode ); d->job = job.release(); } void SignEMailTask::cancel() { if ( d->job ) d->job->slotCancel(); } std::auto_ptr SignEMailTask::Private::createJob( GpgME::Protocol proto ) { const CryptoBackend::Protocol * const backend = CryptoBackendFactory::instance()->protocol( proto ); kleo_assert( backend ); bool shouldArmor = ( proto == OpenPGP || q->asciiArmor() ) && !output->binaryOpt(); std::auto_ptr signJob( backend->signJob( /*armor=*/ shouldArmor, /*textmode=*/false ) ); kleo_assert( signJob.get() ); if ( proto == CMS && !q->asciiArmor() && !output->binaryOpt() ) signJob->setOutputIsBase64Encoded( true ); connect( signJob.get(), SIGNAL(progress(QString,int,int)), q, SLOT(setProgress(QString,int,int)) ); connect( signJob.get(), SIGNAL(result(GpgME::SigningResult,QByteArray)), q, SLOT(slotResult(GpgME::SigningResult)) ); return signJob; } static QString collect_micalgs( const GpgME::SigningResult & result, GpgME::Protocol proto ) { const std::vector css = result.createdSignatures(); QStringList micalgs; #ifndef DASHBOT_HAS_STABLE_COMPILER Q_FOREACH( const GpgME::CreatedSignature & sig, css ) micalgs.push_back( QString::fromLatin1( sig.hashAlgorithmAsString() ).toLower() ); #else std::transform( css.begin(), css.end(), std::back_inserter( micalgs ), boost::bind( &QString::toLower, boost::bind( &QString::fromLatin1, boost::bind( &GpgME::CreatedSignature::hashAlgorithmAsString, _1 ), -1 ) ) ); #endif if ( proto == GpgME::OpenPGP ) for ( QStringList::iterator it = micalgs.begin(), end = micalgs.end() ; it != end ; ++it ) it->prepend( QLatin1String("pgp-") ); micalgs.sort(); micalgs.erase( std::unique( micalgs.begin(), micalgs.end() ), micalgs.end() ); return micalgs.join( QLatin1String(",") ); } void SignEMailTask::Private::slotResult( const SigningResult & result ) { const Job * const job = qobject_cast( q->sender() ); if ( result.error().code() ) { output->cancel(); } else { output->finalize(); micAlg = collect_micalgs( result, q->protocol() ); } q->emitResult( shared_ptr( new SignEMailResult( result, AuditLog::fromJob( job ) ) ) ); } QString SignEMailTask::micAlg() const { return d->micAlg; } QString SignEMailResult::overview() const { return makeOverview( makeResultString( m_result ) ); } QString SignEMailResult::details() const { return QString(); } int SignEMailResult::errorCode() const { return m_result.error().encodedError(); } QString SignEMailResult::errorString() const { return hasError() ? makeResultString( m_result ) : QString(); } Task::Result::VisualCode SignEMailResult::code() const { if ( m_result.error().isCanceled() ) return Warning; return m_result.error().code() ? NeutralError : NeutralSuccess; } AuditLog SignEMailResult::auditLog() const { return m_auditLog; } #include "moc_signemailtask.cpp" diff --git a/kleopatra/crypto/signemailtask.h b/kleopatra/crypto/signemailtask.h index 12e27414d6..8af906d00b 100644 --- a/kleopatra/crypto/signemailtask.h +++ b/kleopatra/crypto/signemailtask.h @@ -1,92 +1,94 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/signemailtask.h This file is part of Kleopatra, the KDE keymanager Copyright (c) 2007 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #ifndef __KLEOPATRA_CRYPTO_SIGNEMAILTASK_H__ #define __KLEOPATRA_CRYPTO_SIGNEMAILTASK_H__ #include #include #include +#ifndef Q_MOC_RUN #include +#endif #include namespace GpgME { class Key; } namespace Kleo { class Input; class Output; } namespace Kleo { namespace Crypto { class SignEMailTask : public Task { Q_OBJECT public: explicit SignEMailTask( QObject * parent=0 ); ~SignEMailTask(); void setInput( const boost::shared_ptr & input ); void setOutput( const boost::shared_ptr & output ); void setSigners( const std::vector & recipients ); void setDetachedSignature( bool detached ); void setClearsign( bool clear ); GpgME::Protocol protocol() const; /* reimp */ void cancel(); /* reimp */ QString label() const; QString micAlg() const; private: /* reimp */ void doStart(); /* reimp */ unsigned long long inputSize() const; private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT( d, void slotResult( const GpgME::SigningResult & ) ) }; } } #endif /* __KLEOPATRA_CRYPTO_SIGNEMAILTASK_H__ */ diff --git a/kleopatra/crypto/signencryptfilescontroller.cpp b/kleopatra/crypto/signencryptfilescontroller.cpp index 302d39b811..ab8be1af05 100644 --- a/kleopatra/crypto/signencryptfilescontroller.cpp +++ b/kleopatra/crypto/signencryptfilescontroller.cpp @@ -1,583 +1,585 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/signencryptfilescontroller.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2007 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "signencryptfilescontroller.h" #include "signencryptfilestask.h" #include "certificateresolver.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#ifndef Q_MOC_RUN #include +#endif using namespace Kleo; using namespace Kleo::Crypto; using namespace Kleo::Crypto::Gui; using namespace boost; using namespace GpgME; using namespace KMime::Types; namespace { struct is_dir : std::unary_function { bool operator()( const QString & file ) const { return QFileInfo( file ).isDir(); } }; } static bool contains_dir( const QStringList & files ) { return kdtools::any( files, is_dir() ); } class SignEncryptFilesController::Private { friend class ::Kleo::Crypto::SignEncryptFilesController; SignEncryptFilesController * const q; public: explicit Private( SignEncryptFilesController * qq ); ~Private(); private: void slotWizardOperationPrepared(); void slotWizardCanceled(); private: void ensureWizardCreated(); void ensureWizardVisible(); void updateWizardMode(); void cancelAllTasks(); void reportError( int err, const QString & details ) { q->setLastError( err, details ); q->emitDoneOrError(); } void schedule(); shared_ptr takeRunnable( GpgME::Protocol proto ); static void assertValidOperation( unsigned int ); static QString titleForOperation( unsigned int op ); private: std::vector< shared_ptr > runnable, completed; shared_ptr cms, openpgp; QPointer wizard; QStringList files; unsigned int operation; Protocol protocol; }; SignEncryptFilesController::Private::Private( SignEncryptFilesController * qq ) : q( qq ), runnable(), cms(), openpgp(), wizard(), files(), operation( SignAllowed|EncryptAllowed|ArchiveAllowed ), protocol( UnknownProtocol ) { } SignEncryptFilesController::Private::~Private() { kDebug(); } QString SignEncryptFilesController::Private::titleForOperation( unsigned int op ) { const bool signDisallowed = (op & SignMask) == SignDisallowed; const bool encryptDisallowed = (op & EncryptMask) == EncryptDisallowed; const bool archiveForced = (op & ArchiveMask) == ArchiveForced; kleo_assert( !signDisallowed || !encryptDisallowed ); if ( !signDisallowed && encryptDisallowed ) { if ( archiveForced ) return i18n( "Archive and Sign Files" ); else return i18n( "Sign Files" ); } if ( signDisallowed && !encryptDisallowed ) { if ( archiveForced ) return i18n( "Archive and Encrypt Files" ); else return i18n( "Encrypt Files" ); } if ( archiveForced ) return i18n( "Archive and Sign/Encrypt Files" ); else return i18n( "Sign/Encrypt Files" ); } SignEncryptFilesController::SignEncryptFilesController( QObject * p ) : Controller( p ), d( new Private( this ) ) { } SignEncryptFilesController::SignEncryptFilesController( const shared_ptr & ctx, QObject * p ) : Controller( ctx, p ), d( new Private( this ) ) { } SignEncryptFilesController::~SignEncryptFilesController() { kDebug(); if ( d->wizard && !d->wizard->isVisible() ) delete d->wizard; //d->wizard->close(); ### ? } void SignEncryptFilesController::setProtocol( Protocol proto ) { kleo_assert( d->protocol == UnknownProtocol || d->protocol == proto ); d->protocol = proto; d->ensureWizardCreated(); d->wizard->setPresetProtocol( proto ); } Protocol SignEncryptFilesController::protocol() const { return d->protocol; } // static void SignEncryptFilesController::Private::assertValidOperation( unsigned int op ) { kleo_assert( ( op & SignMask ) == SignDisallowed || ( op & SignMask ) == SignAllowed || ( op & SignMask ) == SignForced ); kleo_assert( ( op & EncryptMask ) == EncryptDisallowed || ( op & EncryptMask ) == EncryptAllowed || ( op & EncryptMask ) == EncryptForced ); kleo_assert( ( op & ArchiveMask ) == ArchiveDisallowed || ( op & ArchiveMask ) == ArchiveAllowed || ( op & ArchiveMask ) == ArchiveForced ); kleo_assert( ( op & ~(SignMask|EncryptMask|ArchiveMask) ) == 0 ); } void SignEncryptFilesController::setOperationMode( unsigned int mode ) { Private::assertValidOperation( mode ); if ( contains_dir( d->files ) ) mode = mode & ~ArchiveMask | ArchiveForced; d->operation = mode; d->updateWizardMode(); } void SignEncryptFilesController::Private::updateWizardMode() { if ( !wizard ) return; wizard->setWindowTitle( titleForOperation( operation ) ); const unsigned int signOp = (operation & SignMask); const unsigned int encrOp = (operation & EncryptMask); const unsigned int archOp = (operation & ArchiveMask); switch ( signOp ) { case SignForced: case SignDisallowed: wizard->setSigningPreset( signOp == SignForced ); wizard->setSigningUserMutable( false ); break; default: assert( !"Should not happen" ); case SignAllowed: wizard->setSigningPreset( encrOp == EncryptDisallowed ); wizard->setSigningUserMutable( true ); break; } switch ( encrOp ) { case EncryptForced: case EncryptDisallowed: wizard->setEncryptionPreset( encrOp == EncryptForced ); wizard->setEncryptionUserMutable( false ); break; default: assert( !"Should not happen" ); case EncryptAllowed: wizard->setEncryptionPreset( true ); wizard->setEncryptionUserMutable( true ); break; } switch ( archOp ) { case ArchiveForced: case ArchiveDisallowed: wizard->setCreateArchivePreset( archOp == ArchiveForced ); wizard->setCreateArchiveUserMutable( false ); break; default: assert( !"Shouldn't happen" ); case ArchiveAllowed: wizard->setCreateArchivePreset( false ); wizard->setEncryptionUserMutable( true ); break; }; } unsigned int SignEncryptFilesController::operationMode() const { return d->operation; } void SignEncryptFilesController::setFiles( const QStringList & files ) { kleo_assert( !files.empty() ); d->files = files; if ( contains_dir( files ) ) setOperationMode( ( operationMode() & ~ArchiveMask ) | ArchiveForced ); d->ensureWizardCreated(); d->wizard->setFiles( files ); } void SignEncryptFilesController::Private::slotWizardCanceled() { kDebug(); reportError( gpg_error( GPG_ERR_CANCELED ), i18n("User cancel") ); } void SignEncryptFilesController::start() { d->ensureWizardVisible(); } static const char * extension( bool pgp, bool sign, bool encrypt, bool ascii, bool detached ) { unsigned int cls = pgp ? Class::OpenPGP : Class::CMS ; if ( encrypt ) cls |= Class::CipherText; else if ( sign ) cls |= detached ? Class::DetachedSignature : Class::OpaqueSignature ; cls |= ascii ? Class::Ascii : Class::Binary ; if ( const char * const ext = outputFileExtension( cls ) ) return ext; else return "out"; } static shared_ptr createSignEncryptTaskForFileInfo( const QFileInfo & fi, bool pgp, bool sign, bool encrypt, bool ascii, bool removeUnencrypted, const std::vector & recipients, const std::vector & signers ) { const shared_ptr task( new SignEncryptFilesTask ); task->setSign( sign ); task->setEncrypt( encrypt ); task->setAsciiArmor( ascii ); task->setRemoveInputFileOnSuccess( removeUnencrypted ); if ( sign ) { task->setSigners( signers ); task->setDetachedSignature( true ); } if ( encrypt ) task->setRecipients( recipients ); const QString input = fi.absoluteFilePath(); task->setInputFileName( input ); task->setInput( Input::createFromFile( input ) ); const char * const ext = extension( pgp, sign, encrypt, ascii, true ); kleo_assert( ext ); const QString output = input + QLatin1Char('.') + QLatin1String(ext); task->setOutputFileName( output ); return task; } static shared_ptr createArchiveSignEncryptTaskForFiles( const QStringList & files, const QString & outputFileBaseName, const shared_ptr & ad, bool pgp, bool sign, bool encrypt, bool ascii, bool removeUnencrypted, const std::vector & recipients, const std::vector & signers ) { const shared_ptr task( new SignEncryptFilesTask ); task->setSign( sign ); task->setEncrypt( encrypt ); task->setAsciiArmor( ascii ); task->setRemoveInputFileOnSuccess( removeUnencrypted ); if ( sign ) { task->setSigners( signers ); task->setDetachedSignature( false ); } if ( encrypt ) task->setRecipients( recipients ); kleo_assert( ad ); const Protocol proto = pgp ? OpenPGP : CMS ; task->setInputFileNames( files ); task->setInput( ad->createInputFromPackCommand( proto, files ) ); const char * const ext = extension( pgp, sign, encrypt, ascii, false ); kleo_assert( ext ); kleo_assert( !ad->extensions( proto ).empty() ); task->setOutputFileName( outputFileBaseName + QLatin1Char('.') + QLatin1String(ext) ); return task; } static std::vector< shared_ptr > createSignEncryptTasksForFileInfo( const QFileInfo & fi, bool sign, bool encrypt, bool ascii, bool removeUnencrypted, const std::vector & pgpRecipients, const std::vector & pgpSigners, const std::vector & cmsRecipients, const std::vector & cmsSigners ) { std::vector< shared_ptr > result; const bool shallPgpSign = sign && !pgpSigners.empty(); const bool shallPgpEncrypt = encrypt && !pgpRecipients.empty(); const bool pgp = ( shallPgpEncrypt && ( !sign || shallPgpSign ) ) || ( !encrypt && shallPgpSign ); const bool shallCmsSign = sign && !cmsSigners.empty(); const bool shallCmsEncrypt = encrypt && !cmsRecipients.empty(); const bool cms = ( shallCmsEncrypt && ( !sign || shallCmsSign ) ) || ( !encrypt && shallCmsSign ); result.reserve( pgp + cms ); if ( pgp ) result.push_back( createSignEncryptTaskForFileInfo( fi, true, sign, encrypt, ascii, removeUnencrypted, pgpRecipients, pgpSigners ) ); if ( cms ) result.push_back( createSignEncryptTaskForFileInfo( fi, false, sign, encrypt, ascii, removeUnencrypted, cmsRecipients, cmsSigners ) ); return result; } static std::vector< shared_ptr > createArchiveSignEncryptTasksForFiles( const QStringList & files, const QString & pgpOutputFileBaseName, const QString & cmsOutputFileBaseName, const shared_ptr & ad, bool sign, bool encrypt, bool ascii, bool removeUnencrypted, const std::vector & pgpRecipients, const std::vector & pgpSigners, const std::vector & cmsRecipients, const std::vector & cmsSigners ) { std::vector< shared_ptr > result; const bool shallPgpSign = sign && !pgpSigners.empty(); const bool shallPgpEncrypt = encrypt && !pgpRecipients.empty(); const bool pgp = ( shallPgpEncrypt && ( !sign || shallPgpSign )) || ( !encrypt && shallPgpSign ); const bool shallCmsSign = sign && !cmsSigners.empty(); const bool shallCmsEncrypt = encrypt && !cmsRecipients.empty(); const bool cms = ( shallCmsEncrypt && ( !sign || shallCmsSign )) || ( !encrypt && shallCmsSign ); result.reserve( pgp + cms ); if ( pgp ) result.push_back( createArchiveSignEncryptTaskForFiles( files, pgpOutputFileBaseName, ad, true, sign, encrypt, ascii, removeUnencrypted, pgpRecipients, pgpSigners ) ); if ( cms ) result.push_back( createArchiveSignEncryptTaskForFiles( files, cmsOutputFileBaseName, ad, false, sign, encrypt, ascii, removeUnencrypted, cmsRecipients, cmsSigners ) ); return result; } void SignEncryptFilesController::Private::slotWizardOperationPrepared() { try { kleo_assert( wizard ); kleo_assert( !files.empty() ); const bool archive = wizard->isCreateArchiveSelected(); const bool sign = wizard->isSigningSelected(); const bool encrypt = wizard->isEncryptionSelected(); const bool ascii = wizard->isAsciiArmorEnabled(); const bool removeUnencrypted = wizard->isRemoveUnencryptedFilesEnabled(); std::vector pgpRecipients, cmsRecipients, pgpSigners, cmsSigners; if ( encrypt ) { const std::vector recipients = wizard->resolvedRecipients(); kdtools::copy_if( recipients.begin(), recipients.end(), std::back_inserter( pgpRecipients ), boost::bind( &Key::protocol, _1 ) == GpgME::OpenPGP ); kdtools::copy_if( recipients.begin(), recipients.end(), std::back_inserter( cmsRecipients ), boost::bind( &Key::protocol, _1 ) == GpgME::CMS ); kleo_assert( pgpRecipients.size() + cmsRecipients.size() == recipients.size() ); } if ( sign ) { const std::vector signers = wizard->resolvedSigners(); kdtools::copy_if( signers.begin(), signers.end(), std::back_inserter( pgpSigners ), boost::bind( &Key::protocol, _1 ) == GpgME::OpenPGP ); kdtools::copy_if( signers.begin(), signers.end(), std::back_inserter( cmsSigners ), boost::bind( &Key::protocol, _1 ) == GpgME::CMS ); kleo_assert( pgpSigners.size() + cmsSigners.size() == signers.size() ); } std::vector< shared_ptr > tasks; if ( !archive ) tasks.reserve( files.size() ); if ( archive ) tasks = createArchiveSignEncryptTasksForFiles( files, wizard->archiveFileName( OpenPGP ), wizard->archiveFileName( CMS ), wizard->selectedArchiveDefinition(), sign, encrypt, ascii, removeUnencrypted, pgpRecipients, pgpSigners, cmsRecipients, cmsSigners ); else Q_FOREACH( const QString & file, files ) { const std::vector< shared_ptr > created = createSignEncryptTasksForFileInfo( QFileInfo( file ), sign, encrypt, ascii, removeUnencrypted, pgpRecipients, pgpSigners, cmsRecipients, cmsSigners ); tasks.insert( tasks.end(), created.begin(), created.end() ); } const shared_ptr overwritePolicy( new OverwritePolicy( wizard ) ); Q_FOREACH( const shared_ptr & i, tasks ) i->setOverwritePolicy( overwritePolicy ); kleo_assert( runnable.empty() ); runnable.swap( tasks ); Q_FOREACH( const shared_ptr task, runnable ) q->connectTask( task ); shared_ptr coll( new TaskCollection ); std::vector > tmp; std::copy( runnable.begin(), runnable.end(), std::back_inserter( tmp ) ); coll->setTasks( tmp ); wizard->setTaskCollection( coll ); QTimer::singleShot( 0, q, SLOT(schedule()) ); } catch ( const Kleo::Exception & e ) { reportError( e.error().encodedError(), e.message() ); } catch ( const std::exception & e ) { reportError( gpg_error( GPG_ERR_UNEXPECTED ), i18n("Caught unexpected exception in SignEncryptFilesController::Private::slotWizardOperationPrepared: %1", QString::fromLocal8Bit( e.what() ) ) ); } catch ( ... ) { reportError( gpg_error( GPG_ERR_UNEXPECTED ), i18n("Caught unknown exception in SignEncryptFilesController::Private::slotWizardOperationPrepared") ); } } void SignEncryptFilesController::Private::schedule() { if ( !cms ) if ( const shared_ptr t = takeRunnable( CMS ) ) { t->start(); cms = t; } if ( !openpgp ) if ( const shared_ptr t = takeRunnable( OpenPGP ) ) { t->start(); openpgp = t; } if ( !cms && !openpgp ) { kleo_assert( runnable.empty() ); q->emitDoneOrError(); } } shared_ptr SignEncryptFilesController::Private::takeRunnable( GpgME::Protocol proto ) { const std::vector< shared_ptr >::iterator it = std::find_if( runnable.begin(), runnable.end(), boost::bind( &Task::protocol, _1 ) == proto ); if ( it == runnable.end() ) return shared_ptr(); const shared_ptr result = *it; runnable.erase( it ); return result; } void SignEncryptFilesController::doTaskDone( const Task * task, const shared_ptr & result ) { Q_UNUSED( result ) assert( task ); // We could just delete the tasks here, but we can't use // Qt::QueuedConnection here (we need sender()) and other slots // might not yet have executed. Therefore, we push completed tasks // into a burial container if ( task == d->cms.get() ) { d->completed.push_back( d->cms ); d->cms.reset(); } else if ( task == d->openpgp.get() ) { d->completed.push_back( d->openpgp ); d->openpgp.reset(); } QTimer::singleShot( 0, this, SLOT(schedule()) ); } void SignEncryptFilesController::cancel() { kDebug(); try { if ( d->wizard ) d->wizard->close(); d->cancelAllTasks(); } catch ( const std::exception & e ) { kDebug() << "Caught exception: " << e.what(); } } void SignEncryptFilesController::Private::cancelAllTasks() { // we just kill all runnable tasks - this will not result in // signal emissions. runnable.clear(); // a cancel() will result in a call to if ( cms ) cms->cancel(); if ( openpgp ) openpgp->cancel(); } void SignEncryptFilesController::Private::ensureWizardCreated() { if ( wizard ) return; std::auto_ptr w( new NewSignEncryptFilesWizard ); w->setAttribute( Qt::WA_DeleteOnClose ); connect( w.get(), SIGNAL(operationPrepared()), q, SLOT(slotWizardOperationPrepared()), Qt::QueuedConnection ); connect( w.get(), SIGNAL(rejected()), q, SLOT(slotWizardCanceled()), Qt::QueuedConnection ); wizard = w.release(); updateWizardMode(); } void SignEncryptFilesController::Private::ensureWizardVisible() { ensureWizardCreated(); q->bringToForeground( wizard ); } #include "moc_signencryptfilescontroller.cpp" diff --git a/kleopatra/crypto/signencryptfilescontroller.h b/kleopatra/crypto/signencryptfilescontroller.h index abc0c258fa..877297d464 100644 --- a/kleopatra/crypto/signencryptfilescontroller.h +++ b/kleopatra/crypto/signencryptfilescontroller.h @@ -1,104 +1,106 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/signencryptfilescontroller.h This file is part of Kleopatra, the KDE keymanager Copyright (c) 2007 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #ifndef __KLEOPATRA_CRYPTO_SIGNENCRYPTFILESCONTROLLER_H__ #define __KLEOPATRA_CRYPTO_SIGNENCRYPTFILESCONTROLLER_H__ #include #include #include #include +#ifndef Q_MOC_RUN #include +#endif #include namespace Kleo { namespace Crypto { class SignEncryptFilesController : public Controller { Q_OBJECT public: explicit SignEncryptFilesController( QObject * parent=0 ); explicit SignEncryptFilesController( const boost::shared_ptr & ctx, QObject * parent=0 ); ~SignEncryptFilesController(); void setProtocol( GpgME::Protocol proto ); GpgME::Protocol protocol() const; //const char * protocolAsString() const; enum Operation { SignDisallowed = 0, SignAllowed = 1, SignForced = 2, SignMask = SignAllowed|SignForced, EncryptDisallowed = 0, EncryptAllowed = 4, EncryptForced = 8, EncryptMask = EncryptAllowed|EncryptForced, ArchiveDisallowed = 0, ArchiveAllowed = 16, ArchiveForced = 32, ArchiveMask = ArchiveAllowed|ArchiveForced }; void setOperationMode( unsigned int mode ); unsigned int operationMode() const; void setFiles( const QStringList & files ); void start(); public Q_SLOTS: void cancel(); private: /* reimp */ void doTaskDone( const Task * task, const boost::shared_ptr & ); class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT( d, void slotWizardOperationPrepared() ) Q_PRIVATE_SLOT( d, void slotWizardCanceled() ) Q_PRIVATE_SLOT( d, void schedule() ) }; } } #endif /* __KLEOPATRA_UISERVER_SIGNENCRYPTFILESCONTROLLER_H__ */ diff --git a/kleopatra/crypto/signencryptfilestask.cpp b/kleopatra/crypto/signencryptfilestask.cpp index abfa6e44d7..e46b15dfeb 100644 --- a/kleopatra/crypto/signencryptfilestask.cpp +++ b/kleopatra/crypto/signencryptfilestask.cpp @@ -1,620 +1,622 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/signencryptfilestask.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2007 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "signencryptfilestask.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // for Qt::escape +#ifndef Q_MOC_RUN #include +#endif using namespace Kleo; using namespace Kleo::Crypto; using namespace boost; using namespace GpgME; namespace { QString formatInputOutputLabel( const QString & input, const QString & output, bool inputDeleted, bool outputDeleted ) { return i18nc( "Input file --> Output file (rarr is arrow", "%1 → %2", inputDeleted ? QString::fromLatin1("%1").arg( Qt::escape( input ) ) : Qt::escape( input ), outputDeleted ? QString::fromLatin1("%1").arg( Qt::escape( output ) ) : Qt::escape( output ) ); } class ErrorResult : public Task::Result { public: ErrorResult( bool sign, bool encrypt, const Error & err, const QString & errStr, const QString & input, const QString & output, const AuditLog & auditLog ) : Task::Result(), m_sign( sign ), m_encrypt( encrypt ), m_error( err ), m_errString( errStr ), m_inputLabel( input ), m_outputLabel( output ), m_auditLog( auditLog ) {} /* reimp */ QString overview() const; /* reimp */ QString details() const; /* reimp */ int errorCode() const { return m_error.encodedError(); } /* reimp */ QString errorString() const { return m_errString; } /* reimp */ VisualCode code() const { return NeutralError; } /* reimp */ AuditLog auditLog() const { return m_auditLog; } private: const bool m_sign; const bool m_encrypt; const Error m_error; const QString m_errString; const QString m_inputLabel; const QString m_outputLabel; const AuditLog m_auditLog; }; class SignEncryptFilesResult : public Task::Result { public: SignEncryptFilesResult( const SigningResult & sr, const shared_ptr & input, const shared_ptr & output, bool inputRemoved, bool outputCreated, const AuditLog & auditLog ) : Task::Result(), m_sresult( sr ), m_inputLabel( input ? input->label() : QString() ), m_inputErrorString( input ? input->errorString() : QString() ), m_outputLabel( output ? output->label() : QString() ), m_outputErrorString( output ? output->errorString() : QString() ), m_inputRemoved( inputRemoved ), m_outputCreated( outputCreated ), m_auditLog( auditLog ) { kDebug() << endl << "inputError :" << m_inputErrorString << endl << "outputError:" << m_outputErrorString; assert( !m_sresult.isNull() ); } SignEncryptFilesResult( const EncryptionResult & er, const shared_ptr & input, const shared_ptr & output, bool inputRemoved, bool outputCreated, const AuditLog & auditLog ) : Task::Result(), m_eresult( er ), m_inputLabel( input ? input->label() : QString() ), m_inputErrorString( input ? input->errorString() : QString() ), m_outputLabel( output ? output->label() : QString() ), m_outputErrorString( output ? output->errorString() : QString() ), m_inputRemoved( inputRemoved ), m_outputCreated( outputCreated ), m_auditLog( auditLog ) { kDebug() << endl << "inputError :" << m_inputErrorString << endl << "outputError:" << m_outputErrorString; assert( !m_eresult.isNull() ); } SignEncryptFilesResult( const SigningResult & sr, const EncryptionResult & er, const shared_ptr & input, const shared_ptr & output, bool inputRemoved, bool outputCreated, const AuditLog & auditLog ) : Task::Result(), m_sresult( sr ), m_eresult( er ), m_inputLabel( input ? input->label() : QString() ), m_inputErrorString( input ? input->errorString() : QString() ), m_outputLabel( output ? output->label() : QString() ), m_outputErrorString( output ? output->errorString() : QString() ), m_inputRemoved( inputRemoved ), m_outputCreated( outputCreated ), m_auditLog( auditLog ) { kDebug() << endl << "inputError :" << m_inputErrorString << endl << "outputError:" << m_outputErrorString; assert( !m_sresult.isNull() || !m_eresult.isNull() ); } /* reimp */ QString overview() const; /* reimp */ QString details() const; /* reimp */ int errorCode() const; /* reimp */ QString errorString() const; /* reimp */ VisualCode code() const; /* reimp */ AuditLog auditLog() const; private: const SigningResult m_sresult; const EncryptionResult m_eresult; const QString m_inputLabel; const QString m_inputErrorString; const QString m_outputLabel; const QString m_outputErrorString; const bool m_inputRemoved; const bool m_outputCreated; const AuditLog m_auditLog; }; static QString makeSigningOverview( const Error & err ) { if ( err.isCanceled() ) return i18n("Signing canceled."); if ( err ) return i18n("Signing failed." ); return i18n("Signing succeeded."); } static QString makeResultOverview( const SigningResult & result ) { return makeSigningOverview( result.error() ); } static QString makeEncryptionOverview( const Error & err ) { if ( err.isCanceled() ) return i18n("Encryption canceled."); if ( err ) return i18n("Encryption failed." ); return i18n("Encryption succeeded."); } static QString makeResultOverview( const EncryptionResult & result ) { return makeEncryptionOverview( result.error() ); } static QString makeResultOverview( const SigningResult & sr, const EncryptionResult & er ) { if ( er.isNull() && sr.isNull() ) return QString(); if ( er.isNull() ) return makeResultOverview( sr ); if ( sr.isNull() ) return makeResultOverview( er ); if ( sr.error().isCanceled() || sr.error() ) return makeResultOverview( sr ); if ( er.error().isCanceled() || er.error() ) return makeResultOverview( er ); return i18n( "Signing and encryption succeeded." ); } static QString escape( QString s ) { s = Qt::escape( s ); s.replace( QLatin1Char( '\n' ), QLatin1String( "
" ) ); return s; } static QString makeResultDetails( const SigningResult & result, const QString & inputError, const QString & outputError ) { const Error err = result.error(); if ( err.code() == GPG_ERR_EIO ) if ( !inputError.isEmpty() ) return i18n( "Input error: %1", escape( inputError ) ); else if ( !outputError.isEmpty() ) return i18n( "Output error: %1", escape( outputError ) ); if ( err ) return Qt::escape( QString::fromLocal8Bit( err.asString() ) ); return QString(); } static QString makeResultDetails( const EncryptionResult & result, const QString & inputError, const QString & outputError ) { const Error err = result.error(); if ( err.code() == GPG_ERR_EIO ) if ( !inputError.isEmpty() ) return i18n( "Input error: %1", escape( inputError ) ); else if ( !outputError.isEmpty() ) return i18n( "Output error: %1", escape( outputError ) ); if ( err ) return Qt::escape( QString::fromLocal8Bit( err.asString() ) ); return i18n(" Encryption succeeded." ); } } QString ErrorResult::overview() const { assert( m_error || m_error.isCanceled() ); assert( m_sign || m_encrypt ); const QString label = formatInputOutputLabel( m_inputLabel, m_outputLabel, false, true ); const bool canceled = m_error.isCanceled(); if ( m_sign && m_encrypt ) return canceled ? i18n( "%1: Sign/encrypt canceled.", label ) : i18n( " %1: Sign/encrypt failed.", label ); return i18nc( "label: result. Example: foo -> foo.gpg: Encryption failed.", "%1: %2", label, m_sign ? makeSigningOverview( m_error ) :makeEncryptionOverview( m_error ) ); } QString ErrorResult::details() const { return m_errString; } class SignEncryptFilesTask::Private { friend class ::Kleo::Crypto::SignEncryptFilesTask; SignEncryptFilesTask * const q; public: explicit Private( SignEncryptFilesTask * qq ); private: std::auto_ptr createSignJob( GpgME::Protocol proto ); std::auto_ptr createSignEncryptJob( GpgME::Protocol proto ); std::auto_ptr createEncryptJob( GpgME::Protocol proto ); shared_ptr makeErrorResult( const Error & err, const QString & errStr, const AuditLog & auditLog ); private: void slotResult( const SigningResult & ); void slotResult( const SigningResult &, const EncryptionResult & ); void slotResult( const EncryptionResult & ); private: shared_ptr input; shared_ptr output; QStringList inputFileNames; QString outputFileName; std::vector signers; std::vector recipients; bool sign : 1; bool encrypt : 1; bool detached : 1; bool removeInput : 1; QPointer job; shared_ptr m_overwritePolicy; }; SignEncryptFilesTask::Private::Private( SignEncryptFilesTask * qq ) : q( qq ), input(), output(), inputFileNames(), outputFileName(), signers(), recipients(), sign( true ), encrypt( true ), detached( false ), removeInput( false ), job( 0 ), m_overwritePolicy( new OverwritePolicy( 0 ) ) { q->setAsciiArmor( true ); } shared_ptr SignEncryptFilesTask::Private::makeErrorResult( const Error & err, const QString & errStr, const AuditLog & auditLog ) { return shared_ptr( new ErrorResult( sign, encrypt, err, errStr, input->label(), output->label(), auditLog ) ); } SignEncryptFilesTask::SignEncryptFilesTask( QObject * p ) : Task( p ), d( new Private( this ) ) { } SignEncryptFilesTask::~SignEncryptFilesTask() {} void SignEncryptFilesTask::setInputFileName( const QString & fileName ) { kleo_assert( !d->job ); kleo_assert( !fileName.isEmpty() ); d->inputFileNames = QStringList( fileName ); } void SignEncryptFilesTask::setInputFileNames( const QStringList & fileNames ) { kleo_assert( !d->job ); kleo_assert( !fileNames.empty() ); d->inputFileNames = fileNames; } void SignEncryptFilesTask::setInput( const shared_ptr & input ) { kleo_assert( !d->job ); kleo_assert( input ); d->input = input; } void SignEncryptFilesTask::setOutputFileName( const QString & fileName ) { kleo_assert( !d->job ); kleo_assert( !fileName.isEmpty() ); d->outputFileName = fileName; } void SignEncryptFilesTask::setSigners( const std::vector & signers ) { kleo_assert( !d->job ); d->signers = signers; } void SignEncryptFilesTask::setRecipients( const std::vector & recipients ) { kleo_assert( !d->job ); d->recipients = recipients; } void SignEncryptFilesTask::setOverwritePolicy( const shared_ptr & policy ) { kleo_assert( !d->job ); d->m_overwritePolicy = policy; } void SignEncryptFilesTask::setSign( bool sign ) { kleo_assert( !d->job ); d->sign = sign; } void SignEncryptFilesTask::setEncrypt( bool encrypt ) { kleo_assert( !d->job ); d->encrypt = encrypt; } void SignEncryptFilesTask::setRemoveInputFileOnSuccess( bool remove ) { kleo_assert( !d->job ); d->removeInput = remove; } void SignEncryptFilesTask::setDetachedSignature( bool detached ) { kleo_assert( !d->job ); d->detached = detached; } Protocol SignEncryptFilesTask::protocol() const { if ( d->sign && !d->signers.empty() ) return d->signers.front().protocol(); if ( d->encrypt ) { if ( !d->recipients.empty() ) return d->recipients.front().protocol(); else return GpgME::OpenPGP; // symmetric OpenPGP encryption } throw Kleo::Exception( gpg_error( GPG_ERR_INTERNAL ), i18n("Cannot determine protocol for task") ); } QString SignEncryptFilesTask::label() const { return d->input ? d->input->label() : QString(); } QString SignEncryptFilesTask::tag() const { return Formatting::displayName( protocol() ); } unsigned long long SignEncryptFilesTask::inputSize() const { return d->input ? d->input->size() : 0U ; } void SignEncryptFilesTask::doStart() { kleo_assert( !d->job ); if ( d->sign ) { kleo_assert( !d->signers.empty() ); } kleo_assert( d->input ); d->output = Output::createFromFile( d->outputFileName, d->m_overwritePolicy ); if ( d->encrypt ) if ( d->sign ) { std::auto_ptr job = d->createSignEncryptJob( protocol() ); kleo_assert( job.get() ); job->start( d->signers, d->recipients, d->input->ioDevice(), d->output->ioDevice(), true ); d->job = job.release(); } else { std::auto_ptr job = d->createEncryptJob( protocol() ); kleo_assert( job.get() ); job->start( d->recipients, d->input->ioDevice(), d->output->ioDevice(), true ); d->job = job.release(); } else if ( d->sign ) { std::auto_ptr job = d->createSignJob( protocol() ); kleo_assert( job.get() ); job->start( d->signers, d->input->ioDevice(), d->output->ioDevice(), d->detached ? GpgME::Detached : GpgME::NormalSignatureMode ); d->job = job.release(); } else { kleo_assert( !"Either 'sign' or 'encrypt' must be set!" ); } } void SignEncryptFilesTask::cancel() { if ( d->job ) d->job->slotCancel(); } std::auto_ptr SignEncryptFilesTask::Private::createSignJob( GpgME::Protocol proto ) { const CryptoBackend::Protocol * const backend = CryptoBackendFactory::instance()->protocol( proto ); kleo_assert( backend ); std::auto_ptr signJob( backend->signJob( q->asciiArmor(), /*textmode=*/false ) ); kleo_assert( signJob.get() ); connect( signJob.get(), SIGNAL(progress(QString,int,int)), q, SLOT(setProgress(QString,int,int)) ); connect( signJob.get(), SIGNAL(result(GpgME::SigningResult,QByteArray)), q, SLOT(slotResult(GpgME::SigningResult)) ); return signJob; } std::auto_ptr SignEncryptFilesTask::Private::createSignEncryptJob( GpgME::Protocol proto ) { const CryptoBackend::Protocol * const backend = CryptoBackendFactory::instance()->protocol( proto ); kleo_assert( backend ); std::auto_ptr signEncryptJob( backend->signEncryptJob( q->asciiArmor(), /*textmode=*/false ) ); kleo_assert( signEncryptJob.get() ); connect( signEncryptJob.get(), SIGNAL(progress(QString,int,int)), q, SLOT(setProgress(QString,int,int)) ); connect( signEncryptJob.get(), SIGNAL(result(GpgME::SigningResult,GpgME::EncryptionResult,QByteArray)), q, SLOT(slotResult(GpgME::SigningResult,GpgME::EncryptionResult)) ); return signEncryptJob; } std::auto_ptr SignEncryptFilesTask::Private::createEncryptJob( GpgME::Protocol proto ) { const CryptoBackend::Protocol * const backend = CryptoBackendFactory::instance()->protocol( proto ); kleo_assert( backend ); std::auto_ptr encryptJob( backend->encryptJob( q->asciiArmor(), /*textmode=*/false ) ); kleo_assert( encryptJob.get() ); connect( encryptJob.get(), SIGNAL(progress(QString,int,int)), q, SLOT(setProgress(QString,int,int)) ); connect( encryptJob.get(), SIGNAL(result(GpgME::EncryptionResult,QByteArray)), q, SLOT(slotResult(GpgME::EncryptionResult)) ); return encryptJob; } void SignEncryptFilesTask::Private::slotResult( const SigningResult & result ) { const Job * const job = qobject_cast( q->sender() ); const AuditLog auditLog = AuditLog::fromJob( job ); bool inputRemoved = false; bool outputCreated = false; if ( result.error().code() ) { output->cancel(); } else { try { kleo_assert( !result.isNull() ); output->finalize(); outputCreated = true; input->finalize(); if ( removeInput ) try { kdtools::for_each( inputFileNames, recursivelyRemovePath ); inputRemoved = true; } catch ( ... ) {} } catch ( const GpgME::Exception & e ) { q->emitResult( makeErrorResult( e.error(), QString::fromLocal8Bit( e.what() ), auditLog ) ); return; } } q->emitResult( shared_ptr( new SignEncryptFilesResult( result, input, output, inputRemoved, outputCreated, auditLog ) ) ); } void SignEncryptFilesTask::Private::slotResult( const SigningResult & sresult, const EncryptionResult & eresult ) { const Job * const job = qobject_cast( q->sender() ); const AuditLog auditLog = AuditLog::fromJob( job ); bool inputRemoved = false; bool outputCreated = false; if ( sresult.error().code() || eresult.error().code() ) { output->cancel(); } else { try { kleo_assert( !sresult.isNull() || !eresult.isNull() ); output->finalize(); outputCreated = true; input->finalize(); if ( removeInput ) try { kdtools::for_each( inputFileNames, recursivelyRemovePath ); inputRemoved = true; } catch ( ... ) {} } catch ( const GpgME::Exception & e ) { q->emitResult( makeErrorResult( e.error(), QString::fromLocal8Bit( e.what() ), auditLog ) ); return; } } q->emitResult( shared_ptr( new SignEncryptFilesResult( sresult, eresult, input, output, inputRemoved, outputCreated, auditLog ) ) ); } void SignEncryptFilesTask::Private::slotResult( const EncryptionResult & result ) { const Job * const job = qobject_cast( q->sender() ); const AuditLog auditLog = AuditLog::fromJob( job ); bool inputRemoved = false; bool outputCreated = false; if ( result.error().code() ) { output->cancel(); } else { try { kleo_assert( !result.isNull() ); output->finalize(); outputCreated = true; input->finalize(); if ( removeInput ) try { kdtools::for_each( inputFileNames, recursivelyRemovePath ); inputRemoved = true; } catch ( ... ) {} } catch ( const GpgME::Exception & e ) { q->emitResult( makeErrorResult( e.error(), QString::fromLocal8Bit( e.what() ), auditLog ) ); return; } } q->emitResult( shared_ptr( new SignEncryptFilesResult( result, input, output, inputRemoved, outputCreated, auditLog ) ) ); } QString SignEncryptFilesResult::overview() const { const QString files = formatInputOutputLabel( m_inputLabel, m_outputLabel, m_inputRemoved, !m_outputCreated ); return files + QLatin1String(": ") + makeOverview( makeResultOverview( m_sresult, m_eresult ) ); } QString SignEncryptFilesResult::details() const { return errorString(); } int SignEncryptFilesResult::errorCode() const { if ( m_sresult.error().code() ) return m_sresult.error().encodedError(); if ( m_eresult.error().code() ) return m_eresult.error().encodedError(); return 0; } QString SignEncryptFilesResult::errorString() const { const bool sign = !m_sresult.isNull(); const bool encrypt = !m_eresult.isNull(); kleo_assert( sign || encrypt ); if ( sign && encrypt ) { return m_sresult.error().code() ? makeResultDetails( m_sresult, m_inputErrorString, m_outputErrorString ) : m_eresult.error().code() ? makeResultDetails( m_eresult, m_inputErrorString, m_outputErrorString ) : QString(); } return sign ? makeResultDetails( m_sresult, m_inputErrorString, m_outputErrorString ) : /*else*/ makeResultDetails( m_eresult, m_inputErrorString, m_outputErrorString ) ; } Task::Result::VisualCode SignEncryptFilesResult::code() const { if ( m_sresult.error().isCanceled() || m_eresult.error().isCanceled() ) return Warning; return ( m_sresult.error().code() || m_eresult.error().code() ) ? NeutralError : NeutralSuccess; } AuditLog SignEncryptFilesResult::auditLog() const { return m_auditLog; } #include "moc_signencryptfilestask.cpp" diff --git a/kleopatra/crypto/task.cpp b/kleopatra/crypto/task.cpp index 9822623520..9a92ca0dff 100644 --- a/kleopatra/crypto/task.cpp +++ b/kleopatra/crypto/task.cpp @@ -1,242 +1,244 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/task.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2007 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "task.h" #include "task_p.h" #include #include #include #include #include #include #include #include #include +#ifndef Q_MOC_RUN #include +#endif using namespace Kleo; using namespace Kleo::Crypto; using namespace boost; using namespace GpgME; namespace { class ErrorResult : public Task::Result { public: ErrorResult( int code, const QString & details ) : Task::Result(), m_code( code ), m_details( details ) {} /* reimp */ QString overview() const { return makeOverview( m_details ); } /* reimp */ QString details() const { return QString(); } /* reimp */ int errorCode() const { return m_code; } /* reimp */ QString errorString() const { return m_details; } /* reimp */ VisualCode code() const { return NeutralError; } /* reimp */ AuditLog auditLog() const { return AuditLog(); } private: int m_code; QString m_details; }; } class Task::Private { friend class ::Kleo::Crypto::Task; Task * const q; public: explicit Private( Task * qq ); private: QString m_progressLabel; double m_processedPercent; bool m_asciiArmor; int m_id; }; namespace { static int nextTaskId = 0; } Task::Private::Private( Task * qq ) : q( qq ), m_progressLabel(), m_processedPercent( 0.0 ), m_asciiArmor( false ), m_id( nextTaskId++ ) { } Task::Task( QObject * p ) : QObject( p ), d( new Private( this ) ) { } Task::~Task() {} void Task::setAsciiArmor( bool armor ) { d->m_asciiArmor = armor; } bool Task::asciiArmor() const { return d->m_asciiArmor; } shared_ptr Task::makeErrorTask( int code, const QString & details, const QString & label ) { const shared_ptr t( new SimpleTask( label ) ); t->setResult( t->makeErrorResult( code, details ) ); return t; } int Task::id() const { return d->m_id; } unsigned long long Task::processedSize() const { return qRound( d->m_processedPercent * totalSize() ); } unsigned long long Task::totalSize() const { return inputSize(); } QString Task::tag() const { return QString(); } QString Task::progressLabel() const { return d->m_progressLabel; } void Task::setProgress( const QString & label, int processed, int total ) { const double percent = total > 0 ? static_cast( processed ) / total : 0.0; d->m_processedPercent = percent; d->m_progressLabel = label; emit progress( label, processedSize(), totalSize() ); } void Task::start() { try { doStart(); } catch ( const Kleo::Exception & e ) { QMetaObject::invokeMethod( this, "emitError", Qt::QueuedConnection, Q_ARG( int, e.error().encodedError() ), Q_ARG( QString, e.message() ) ); } catch ( const GpgME::Exception & e ) { QMetaObject::invokeMethod( this, "emitError", Qt::QueuedConnection, Q_ARG( int, e.error().encodedError() ), Q_ARG( QString, QString::fromLocal8Bit( e.what() ) ) ); } catch ( const std::exception & e ) { QMetaObject::invokeMethod( this, "emitError", Qt::QueuedConnection, Q_ARG( int, makeGnuPGError( GPG_ERR_UNEXPECTED ) ), Q_ARG( QString, QString::fromLocal8Bit( e.what() ) ) ); } catch ( ... ) { QMetaObject::invokeMethod( this, "emitError", Qt::QueuedConnection, Q_ARG( int, makeGnuPGError( GPG_ERR_UNEXPECTED ) ), Q_ARG( QString, i18n( "Unknown exception in Task::start()") ) ); } emit started(); } void Task::emitError( int errCode, const QString& details ) { emitResult( makeErrorResult( errCode, details ) ); } void Task::emitResult( const shared_ptr & r ) { d->m_processedPercent = 1.0; emit progress( progressLabel(), processedSize(), totalSize() ); emit result( r ); } shared_ptr Task::makeErrorResult( int errCode, const QString& details ) { return shared_ptr( new ErrorResult( errCode, details ) ); } static QString makeNonce() { // ### make better return QString::number( qrand(), 16 ); } class Task::Result::Private { public: Private() {} }; Task::Result::Result() : m_nonce( makeNonce() ), d( new Private() ) {} Task::Result::~Result() {} QString Task::Result::formatKeyLink( const char * fpr, const QString & content ) const { return QLatin1String("") + content + QLatin1String(""); } bool Task::Result::hasError() const { return errorCode() != 0; } static QString image( const char* img ) { // ### escape? return KIconLoader::global()->iconPath( QLatin1String(img), KIconLoader::Small ); } QString Task::Result::makeOverview( const QString& msg ) { return QLatin1String("") + msg + QLatin1String(""); } QString Task::Result::iconPath( VisualCode code ) { switch ( code ) { case Danger: return image( "dialog-error" ); case AllGood: return image( "dialog-ok" ); case Warning: return image( "dialog-warning" ); case NeutralError: case NeutralSuccess: default: return QString(); } } QString Task::Result::icon() const { return iconPath( code() ); } #include "moc_task_p.cpp" diff --git a/kleopatra/crypto/task.h b/kleopatra/crypto/task.h index ed4ce4b412..31e9ff6956 100644 --- a/kleopatra/crypto/task.h +++ b/kleopatra/crypto/task.h @@ -1,157 +1,159 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/task.h This file is part of Kleopatra, the KDE keymanager Copyright (c) 2007 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #ifndef __KLEOPATRA_CRYPTO_TASK_H__ #define __KLEOPATRA_CRYPTO_TASK_H__ #include #include #include #include +#ifndef Q_MOC_RUN #include +#endif class QColor; class QIcon; namespace Kleo { class AuditLog; } namespace Kleo { namespace Crypto { class Task : public QObject { Q_OBJECT public: explicit Task( QObject * parent=0 ); ~Task(); class Result; void setAsciiArmor( bool armor ); bool asciiArmor() const; virtual GpgME::Protocol protocol() const = 0; void start(); virtual QString label() const = 0; virtual QString tag() const; QString progressLabel() const; unsigned long long processedSize() const; unsigned long long totalSize() const; int id() const; static boost::shared_ptr makeErrorTask( int code, const QString & details, const QString & label ); public Q_SLOTS: virtual void cancel() = 0; Q_SIGNALS: #ifndef Q_MOC_RUN #ifndef DOXYGEN_SHOULD_SKIP_THIS private: // don't tell moc, but those signals are in fact private #endif #endif void progress( const QString & what, int processed, int total ); void result( const boost::shared_ptr & ); void started(); protected: boost::shared_ptr makeErrorResult( int errCode, const QString& details ); void emitResult( const boost::shared_ptr & result ); protected Q_SLOTS: void setProgress( const QString & msg, int processed, int total ); private Q_SLOTS: void emitError( int errCode, const QString& details ); private: virtual void doStart() = 0; virtual unsigned long long inputSize() const = 0; private: class Private; kdtools::pimpl_ptr d; }; class Task::Result { const QString m_nonce; public: Result(); virtual ~Result(); const QString & nonce() const { return m_nonce; } bool hasError() const; enum VisualCode { AllGood, Warning, Danger, NeutralSuccess, NeutralError }; virtual QString icon() const; virtual QString overview() const = 0; virtual QString details() const = 0; virtual int errorCode() const = 0; virtual QString errorString() const = 0; virtual VisualCode code() const = 0; virtual AuditLog auditLog() const = 0; protected: static QString iconPath( VisualCode code ); QString formatKeyLink( const char * fingerprint, const QString & content ) const; static QString makeOverview( const QString& msg ); private: class Private; kdtools::pimpl_ptr d; }; } } #endif /* __KLEOPATRA_CRYPTO_TASK_H__ */ diff --git a/kleopatra/crypto/taskcollection.cpp b/kleopatra/crypto/taskcollection.cpp index 067367baad..610e8f73d1 100644 --- a/kleopatra/crypto/taskcollection.cpp +++ b/kleopatra/crypto/taskcollection.cpp @@ -1,194 +1,196 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/taskcollection.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2008 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "taskcollection.h" #include +#ifndef Q_MOC_RUN #include +#endif #include #include #include #include using namespace Kleo; using namespace Kleo::Crypto; using namespace boost; class TaskCollection::Private { TaskCollection* const q; public: explicit Private( TaskCollection* qq ); void taskProgress( const QString &, int, int ); void taskResult( const shared_ptr & ); void taskStarted(); void calculateAndEmitProgress(); std::map > m_tasks; mutable int m_totalSize; mutable int m_processedSize; unsigned int m_nCompleted; QString m_lastProgressMessage; bool m_errorOccurred; }; TaskCollection::Private::Private( TaskCollection* qq ) : q( qq ), m_totalSize( 0 ), m_processedSize( 0 ), m_nCompleted( 0 ), m_errorOccurred( false ) { } int TaskCollection::numberOfCompletedTasks() const { return d->m_nCompleted; } size_t TaskCollection::size() const { return d->m_tasks.size(); } bool TaskCollection::allTasksCompleted() const { assert( d->m_nCompleted <= d->m_tasks.size() ); return d->m_nCompleted == d->m_tasks.size(); } void TaskCollection::Private::taskProgress( const QString & msg, int, int ) { m_lastProgressMessage = msg; calculateAndEmitProgress(); } void TaskCollection::Private::taskResult( const shared_ptr & result ) { assert( result ); ++m_nCompleted; m_errorOccurred = m_errorOccurred || result->hasError(); m_lastProgressMessage.clear(); calculateAndEmitProgress(); emit q->result( result ); if ( q->allTasksCompleted() ) emit q->done(); } void TaskCollection::Private::taskStarted() { const Task * const task = qobject_cast( q->sender() ); assert( task ); assert( m_tasks.find( task->id() ) != m_tasks.end() ); emit q->started( m_tasks[task->id()] ); calculateAndEmitProgress(); // start Knight-Rider-Mode right away (gpgsm doesn't report _any_ progress). } void TaskCollection::Private::calculateAndEmitProgress() { typedef std::map >::const_iterator ConstIterator; int total = 0; int processed = 0; uint knownSize = m_tasks.size(); for ( ConstIterator it = m_tasks.begin(), end = m_tasks.end(); it != end; ++it ) { const shared_ptr & i = it->second; assert( i ); if ( i->totalSize() == 0 ) --knownSize; processed += i->processedSize(); total += i->totalSize(); } // use the average of the known sizes to estimate the unknown ones: if ( knownSize > 0 ) total += static_cast( std::ceil( ( m_tasks.size() - knownSize ) * ( static_cast( total ) / knownSize ) ) ); if ( m_totalSize == total && m_processedSize == processed ) return; m_totalSize = total; m_processedSize = processed; if ( processed ) emit q->progress( m_lastProgressMessage, processed, total ); else // use knight-rider mode until we have some progress emit q->progress( m_lastProgressMessage, processed, 0 ); } TaskCollection::TaskCollection( QObject * parent ) : QObject( parent ), d( new Private( this ) ) { } TaskCollection::~TaskCollection() { } bool TaskCollection::isEmpty() const { return d->m_tasks.empty(); } bool TaskCollection::errorOccurred() const { return d->m_errorOccurred; } shared_ptr TaskCollection::taskById( int id ) const { const std::map >::const_iterator it = d->m_tasks.find( id ); return it != d->m_tasks.end() ? it->second : shared_ptr(); } std::vector > TaskCollection::tasks() const { typedef std::map >::const_iterator ConstIterator; std::vector > res; res.reserve( d->m_tasks.size() ); for ( ConstIterator it = d->m_tasks.begin(), end = d->m_tasks.end(); it != end; ++it ) res.push_back( it->second ); return res; } void TaskCollection::setTasks( const std::vector > & tasks ) { Q_FOREACH( const shared_ptr & i, tasks ) { assert( i ); d->m_tasks[i->id()] = i; connect( i.get(), SIGNAL(progress(QString,int,int)), this, SLOT(taskProgress(QString,int,int)) ); connect( i.get(), SIGNAL(result(boost::shared_ptr)), this, SLOT(taskResult(boost::shared_ptr)) ); connect( i.get(), SIGNAL(started()), this, SLOT(taskStarted()) ); } } #include "moc_taskcollection.cpp" diff --git a/kleopatra/crypto/taskcollection.h b/kleopatra/crypto/taskcollection.h index 9d901c9879..331176dfe6 100644 --- a/kleopatra/crypto/taskcollection.h +++ b/kleopatra/crypto/taskcollection.h @@ -1,83 +1,85 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/taskcollection.h This file is part of Kleopatra, the KDE keymanager Copyright (c) 2008 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #ifndef __KLEOPATRA_CRYPTO_TASKCOLLECTION_H__ #define __KLEOPATRA_CRYPTO_TASKCOLLECTION_H__ #include #include #include +#ifndef Q_MOC_RUN #include +#endif #include namespace Kleo { namespace Crypto { class TaskCollection : public QObject { Q_OBJECT public: explicit TaskCollection( QObject * parent=0 ); ~TaskCollection(); std::vector > tasks() const; boost::shared_ptr taskById( int id ) const; void setTasks( const std::vector > & tasks ); bool isEmpty() const; size_t size() const; int numberOfCompletedTasks() const; bool allTasksCompleted() const; bool errorOccurred() const; Q_SIGNALS: void progress( const QString & msg, int processed, int total ); void result( const boost::shared_ptr & result ); void started( const boost::shared_ptr & task ); void done(); private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT( d, void taskProgress( QString, int, int ) ) Q_PRIVATE_SLOT( d, void taskResult( boost::shared_ptr ) ) Q_PRIVATE_SLOT( d, void taskStarted() ) }; } } #endif // __KLEOPATRA_CRYPTO_TASKCOLLECTION_H__ diff --git a/kleopatra/crypto/verifychecksumscontroller.cpp b/kleopatra/crypto/verifychecksumscontroller.cpp index e85ea3d5e5..8c28bcb740 100644 --- a/kleopatra/crypto/verifychecksumscontroller.cpp +++ b/kleopatra/crypto/verifychecksumscontroller.cpp @@ -1,651 +1,653 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/verifychecksumscontroller.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2010 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "verifychecksumscontroller.h" #ifndef QT_NO_DIRMODEL #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#ifndef Q_MOC_RUN #include #include +#endif #include #include #include #include using namespace Kleo; using namespace Kleo::Crypto; using namespace Kleo::Crypto::Gui; using namespace boost; #ifdef Q_OS_UNIX static const bool HAVE_UNIX = true; #else static const bool HAVE_UNIX = false; #endif static const QLatin1String CHECKSUM_DEFINITION_ID_ENTRY( "checksum-definition-id" ); static const Qt::CaseSensitivity fs_cs = HAVE_UNIX ? Qt::CaseSensitive : Qt::CaseInsensitive ; // can we use QAbstractFileEngine::caseSensitive()? #if 0 static QStringList fs_sort( QStringList l ) { int (*QString_compare)(const QString&,const QString&,Qt::CaseSensitivity) = &QString::compare; kdtools::sort( l, boost::bind( QString_compare, _1, _2, fs_cs ) < 0 ); return l; } static QStringList fs_intersect( QStringList l1, QStringList l2 ) { int (*QString_compare)(const QString&,const QString&,Qt::CaseSensitivity) = &QString::compare; fs_sort( l1 ); fs_sort( l2 ); QStringList result; std::set_intersection( l1.begin(), l1.end(), l2.begin(), l2.end(), std::back_inserter( result ), boost::bind( QString_compare, _1, _2, fs_cs ) < 0 ); return result; } #endif static QList get_patterns( const std::vector< shared_ptr > & checksumDefinitions ) { QList result; Q_FOREACH( const shared_ptr & cd, checksumDefinitions ) if ( cd ) Q_FOREACH( const QString & pattern, cd->patterns() ) result.push_back( QRegExp( pattern, fs_cs ) ); return result; } namespace { struct matches_any : std::unary_function { const QList m_regexps; explicit matches_any( const QList & regexps ) : m_regexps( regexps ) {} bool operator()( const QString & s ) const { return kdtools::any( m_regexps, boost::bind( &QRegExp::exactMatch, _1, s ) ); } }; struct matches_none_of : std::unary_function { const QList m_regexps; explicit matches_none_of( const QList & regexps ) : m_regexps( regexps ) {} bool operator()( const QString & s ) const { return kdtools::none_of( m_regexps, boost::bind( &QRegExp::exactMatch, _1, s ) ); } }; } class VerifyChecksumsController::Private : public QThread { Q_OBJECT friend class ::Kleo::Crypto::VerifyChecksumsController; VerifyChecksumsController * const q; public: explicit Private( VerifyChecksumsController * qq ); ~Private(); Q_SIGNALS: void baseDirectories( const QStringList & ); void progress( int, int, const QString & ); void status( const QString & file, Kleo::Crypto::Gui::VerifyChecksumsDialog::Status ); private: void slotOperationFinished() { if ( dialog ) { dialog->setProgress( 100, 100 ); dialog->setErrors( errors ); } if ( !errors.empty() ) q->setLastError( gpg_error( GPG_ERR_GENERAL ), errors.join( QLatin1String("\n") ) ); q->emitDoneOrError(); } private: /* reimp */ void run(); private: QPointer dialog; mutable QMutex mutex; const std::vector< shared_ptr > checksumDefinitions; QStringList files; QStringList errors; volatile bool canceled; }; VerifyChecksumsController::Private::Private( VerifyChecksumsController * qq ) : q( qq ), dialog(), mutex(), checksumDefinitions( ChecksumDefinition::getChecksumDefinitions() ), files(), errors(), canceled( false ) { connect( this, SIGNAL(progress(int,int,QString)), q, SIGNAL(progress(int,int,QString)) ); connect( this, SIGNAL(finished()), q, SLOT(slotOperationFinished()) ); } VerifyChecksumsController::Private::~Private() { kDebug(); } VerifyChecksumsController::VerifyChecksumsController( QObject * p ) : Controller( p ), d( new Private( this ) ) { } VerifyChecksumsController::VerifyChecksumsController( const shared_ptr & ctx, QObject * p ) : Controller( ctx, p ), d( new Private( this ) ) { } VerifyChecksumsController::~VerifyChecksumsController() { kDebug(); } void VerifyChecksumsController::setFiles( const QStringList & files ) { kleo_assert( !d->isRunning() ); kleo_assert( !files.empty() ); const QMutexLocker locker( &d->mutex ); d->files = files; } void VerifyChecksumsController::start() { { const QMutexLocker locker( &d->mutex ); d->dialog = new VerifyChecksumsDialog; d->dialog->setAttribute( Qt::WA_DeleteOnClose ); d->dialog->setWindowTitle( i18nc("@title:window","Verify Checksum Results") ); connect( d->dialog, SIGNAL(canceled()), this, SLOT(cancel()) ); connect( d.get(), SIGNAL(baseDirectories(QStringList)), d->dialog, SLOT(setBaseDirectories(QStringList)) ); connect( d.get(), SIGNAL(progress(int,int,QString)), d->dialog, SLOT(setProgress(int,int)) ); connect( d.get(), SIGNAL(status(QString,Kleo::Crypto::Gui::VerifyChecksumsDialog::Status)), d->dialog, SLOT(setStatus(QString,Kleo::Crypto::Gui::VerifyChecksumsDialog::Status)) ); d->canceled = false; d->errors.clear(); } d->start(); d->dialog->show(); } void VerifyChecksumsController::cancel() { kDebug(); const QMutexLocker locker( &d->mutex ); d->canceled = true; } namespace { struct SumFile { QDir dir; QString sumFile; quint64 totalSize; shared_ptr checksumDefinition; }; } static QStringList filter_checksum_files( QStringList l, const QList & rxs ) { l.erase( std::remove_if( l.begin(), l.end(), matches_none_of( rxs ) ), l.end() ); return l; } namespace { struct File { QString name; QByteArray checksum; bool binary; }; } static QString decode( const QString & encoded ) { QString decoded; decoded.reserve( encoded.size() ); bool shift = false; Q_FOREACH( const QChar ch, encoded ) if ( shift ) { switch ( ch.toLatin1() ) { case '\\': decoded += QLatin1Char( '\\' ); break; case 'n': decoded += QLatin1Char( '\n' ); break; default: kDebug() << "invalid escape sequence" << '\\' << ch << "(interpreted as '" << ch << "')"; decoded += ch; break; } shift = false; } else { if ( ch == QLatin1Char( '\\' ) ) shift = true; else decoded += ch; } return decoded; } static std::vector parse_sum_file( const QString & fileName ) { std::vector files; QFile f( fileName ); if ( f.open( QIODevice::ReadOnly ) ) { QTextStream s( &f ); QRegExp rx( QLatin1String("(\\?)([a-f0-9A-F]+) ([ *])([^\n]+)\n*") ); while ( !s.atEnd() ) { const QString line = s.readLine(); if ( rx.exactMatch( line ) ) { assert( !rx.cap(4).endsWith( QLatin1Char('\n') ) ); const File file = { rx.cap( 1 ) == QLatin1String("\\") ? decode( rx.cap( 4 ) ) : rx.cap( 4 ), rx.cap( 2 ).toLatin1(), rx.cap( 3 ) == QLatin1String("*"), }; files.push_back( file ); } } } return files; } static quint64 aggregate_size( const QDir & dir, const QStringList & files ) { quint64 n = 0; Q_FOREACH( const QString & file, files ) n += QFileInfo( dir.absoluteFilePath( file ) ).size(); return n; } static shared_ptr filename2definition( const QString & fileName, const std::vector< shared_ptr > & checksumDefinitions ) { Q_FOREACH( const shared_ptr & cd, checksumDefinitions ) if ( cd ) Q_FOREACH( const QString & pattern, cd->patterns() ) if ( QRegExp( pattern, fs_cs ).exactMatch( fileName ) ) return cd; return shared_ptr(); } namespace { struct less_dir : std::binary_function { bool operator()( const QDir & lhs, const QDir & rhs ) const { return QString::compare( lhs.absolutePath(), rhs.absolutePath(), fs_cs ) < 0 ; } }; struct less_file : std::binary_function { bool operator()( const QString & lhs, const QString & rhs ) const { return QString::compare( lhs, rhs, fs_cs ) < 0 ; } }; struct sumfile_contains_file : std::unary_function { const QDir dir; const QString fileName; sumfile_contains_file( const QDir & dir_, const QString & fileName_ ) : dir( dir_ ), fileName( fileName_ ) {} bool operator()( const QString & sumFile ) const { const std::vector files = parse_sum_file( dir.absoluteFilePath( sumFile ) ); kDebug() << "find_sums_by_input_files: found " << files.size() << " files listed in " << qPrintable( dir.absoluteFilePath( sumFile ) ); Q_FOREACH( const File & file, files ) { const bool isSameFileName = ( QString::compare( file.name, fileName, fs_cs ) == 0 ); kDebug() << "find_sums_by_input_files: " << qPrintable( file.name ) << " == " << qPrintable( fileName ) << " ? " << isSameFileName; if ( isSameFileName ) return true; } return false; } }; } // IF is_dir(file) // add all sumfiles \in dir(file) // inputs.prepend( all dirs \in dir(file) ) // ELSE IF is_sum_file(file) // add // ELSE IF \exists sumfile in dir(file) \where sumfile \contains file // add sumfile // ELSE // error: no checksum found for "file" static QStringList find_base_directiories( const QStringList & files ) { // Step 1: find base dirs: std::set dirs; Q_FOREACH( const QString & file, files ) { const QFileInfo fi( file ); const QDir dir = fi.isDir() ? QDir( file ) : fi.dir() ; dirs.insert( dir ); } // Step 1a: collapse direct child directories bool changed; do { changed = false; std::set::iterator it = dirs.begin(); while ( it != dirs.end() ) { QDir dir = *it; if ( dir.cdUp() && dirs.count( dir ) ) { dirs.erase( it++ ); changed = true; } else { ++it; } } } while ( changed ); return kdtools::transform( dirs, mem_fn( &QDir::absolutePath ) ); } static std::vector find_sums_by_input_files( const QStringList & files, QStringList & errors, const function & progress, const std::vector< shared_ptr > & checksumDefinitions ) { const QList patterns = get_patterns( checksumDefinitions ); const matches_any is_sum_file( patterns ); std::map,less_dir> dirs2sums; // Step 1: find the sumfiles we need to check: std::deque inputs( files.begin(), files.end() ); int i = 0; while ( !inputs.empty() ) { const QString file = inputs.front(); kDebug() << "find_sums_by_input_files: considering " << qPrintable( file ); inputs.pop_front(); const QFileInfo fi( file ); const QString fileName = fi.fileName(); if ( fi.isDir() ) { kDebug() << "find_sums_by_input_files: it's a directory"; QDir dir( file ); const QStringList sumfiles = filter_checksum_files( dir.entryList( QDir::Files ), patterns ); kDebug() << "find_sums_by_input_files: found " << sumfiles.size() << " sum files: " << qPrintable( sumfiles.join(QLatin1String(", ")) ); dirs2sums[ dir ].insert( sumfiles.begin(), sumfiles.end() ); const QStringList dirs = dir.entryList( QDir::Dirs|QDir::NoDotAndDotDot ); kDebug() << "find_sums_by_input_files: found " << dirs.size() << " subdirs, prepending"; kdtools::transform( dirs, std::inserter( inputs, inputs.begin() ), boost::bind( &QDir::absoluteFilePath, cref(dir), _1 ) ); } else if ( is_sum_file( fileName ) ) { kDebug() << "find_sums_by_input_files: it's a sum file"; dirs2sums[fi.dir()].insert( fileName ); } else { kDebug() << "find_sums_by_input_files: it's something else; checking whether we'll find a sumfile for it..."; const QDir dir = fi.dir(); const QStringList sumfiles = filter_checksum_files( dir.entryList( QDir::Files ), patterns ); kDebug() << "find_sums_by_input_files: found " << sumfiles.size() << " potential sumfiles: " << qPrintable( sumfiles.join(QLatin1String(", ")) ); const QStringList::const_iterator it = kdtools::find_if( sumfiles, sumfile_contains_file( dir, fileName ) ); if ( it == sumfiles.end() ) errors.push_back( i18n( "Cannot find checksums file for file %1", file ) ); else dirs2sums[dir].insert( *it ); } if ( !progress.empty() ) progress( ++i ); } // Step 2: convert into vector: std::vector sumfiles; sumfiles.reserve( dirs2sums.size() ); for ( std::map,less_dir>::const_iterator it = dirs2sums.begin(), end = dirs2sums.end() ; it != end ; ++it ) { if ( it->second.empty() ) continue; const QDir & dir = it->first; Q_FOREACH( const QString & sumFileName, it->second ) { const std::vector summedfiles = parse_sum_file( dir.absoluteFilePath( sumFileName ) ); const SumFile sumFile = { it->first, sumFileName, aggregate_size( it->first, kdtools::transform( summedfiles, mem_fn( &File::name ) ) ), filename2definition( sumFileName, checksumDefinitions ), }; sumfiles.push_back( sumFile ); } if ( !progress.empty() ) progress( ++i ); } return sumfiles; } static QStringList c_lang_environment() { QStringList env = QProcess::systemEnvironment(); env.erase( std::remove_if( env.begin(), env.end(), boost::bind( &QRegExp::exactMatch, QRegExp( QLatin1String("^LANG=.*"), fs_cs ), _1 ) ), env.end() ); env.push_back( QLatin1String("LANG=C") ); return env; } static const struct { const char * string; VerifyChecksumsDialog::Status status; } statusStrings[] = { { "OK", VerifyChecksumsDialog::OK }, { "FAILED", VerifyChecksumsDialog::Failed }, }; static const size_t numStatusStrings = sizeof statusStrings / sizeof *statusStrings ; static VerifyChecksumsDialog::Status string2status( const QByteArray & str ) { for ( unsigned int i = 0 ; i < numStatusStrings ; ++i ) if ( str == statusStrings[i].string ) return statusStrings[i].status; return VerifyChecksumsDialog::Unknown; } static QString process( const SumFile & sumFile, bool * fatal, const QStringList & env, const function & status ) { QProcess p; p.setEnvironment( env ); p.setWorkingDirectory( sumFile.dir.absolutePath() ); p.setReadChannel( QProcess::StandardOutput ); const QString absFilePath = sumFile.dir.absoluteFilePath( sumFile.sumFile ); const QString program = sumFile.checksumDefinition->verifyCommand(); sumFile.checksumDefinition->startVerifyCommand( &p, QStringList( absFilePath ) ); QByteArray remainder; // used for filenames with newlines in them while ( p.state() != QProcess::NotRunning ) { p.waitForReadyRead(); while ( p.canReadLine() ) { const QByteArray line = p.readLine(); const int colonIdx = line.lastIndexOf( ':' ); if ( colonIdx < 0 ) { remainder += line; // no colon -> probably filename with a newline continue; } const QString file = QFile::decodeName( remainder + line.left( colonIdx ) ); remainder.clear(); const VerifyChecksumsDialog::Status result = string2status( line.mid( colonIdx+1 ).trimmed() ); status( sumFile.dir.absoluteFilePath( file ), result ); } } kDebug() << "[" << &p << "] Exit code " << p.exitCode(); if ( p.exitStatus() != QProcess::NormalExit || p.exitCode() != 0 ) { if ( fatal && p.error() == QProcess::FailedToStart ) *fatal = true; if ( p.error() == QProcess::UnknownError ) return i18n( "Error while running %1: %2", program, QString::fromLocal8Bit( p.readAllStandardError().trimmed().constData() ) ); else return i18n( "Failed to execute %1: %2", program, p.errorString() ); } return QString(); } namespace { static QDebug operator<<( QDebug s, const SumFile & sum ) { return s << "SumFile(" << sum.dir << "->" << sum.sumFile << "<-(" << sum.totalSize << ')' << ")\n"; } } void VerifyChecksumsController::Private::run() { QMutexLocker locker( &mutex ); const QStringList files = this->files; const std::vector< shared_ptr > checksumDefinitions = this->checksumDefinitions; locker.unlock(); QStringList errors; // // Step 0: find base directories: // emit baseDirectories( find_base_directiories( files ) ); // // Step 1: build a list of work to do (no progress): // const QString scanning = i18n("Scanning directories..."); emit progress( 0, 0, scanning ); const function progressCb = boost::bind( &Private::progress, this, _1, 0, scanning ); const function statusCb = boost::bind( &Private::status, this, _1, _2 ); const std::vector sumfiles = find_sums_by_input_files( files, errors, progressCb, checksumDefinitions ); Q_FOREACH( const SumFile & sumfile, sumfiles ) kDebug() << sumfile; if ( !canceled ) { emit progress( 0, 0, i18n("Calculating total size...") ); const quint64 total = kdtools::accumulate_transform( sumfiles, mem_fn( &SumFile::totalSize ), Q_UINT64_C(0) ); if ( !canceled ) { // // Step 2: perform work (with progress reporting): // const QStringList env = c_lang_environment(); // re-scale 'total' to fit into ints (wish QProgressDialog would use quint64...) const quint64 factor = total / std::numeric_limits::max() + 1 ; quint64 done = 0; Q_FOREACH( const SumFile & sumFile, sumfiles ) { emit progress( done/factor, total/factor, i18n("Verifying checksums (%2) in %1", sumFile.checksumDefinition->label(), sumFile.dir.path() ) ); bool fatal = false; const QString error = process( sumFile, &fatal, env, statusCb ); if ( !error.isEmpty() ) errors.push_back( error ); done += sumFile.totalSize; if ( fatal || canceled ) break; } emit progress( done/factor, total/factor, i18n("Done.") ); } } locker.relock(); this->errors = errors; // mutex unlocked by QMutexLocker } #include "moc_verifychecksumscontroller.cpp" #include "verifychecksumscontroller.moc" #endif // QT_NO_DIRMODEL diff --git a/kleopatra/crypto/verifychecksumscontroller.h b/kleopatra/crypto/verifychecksumscontroller.h index 5e069c8ea0..a2c1fb7434 100644 --- a/kleopatra/crypto/verifychecksumscontroller.h +++ b/kleopatra/crypto/verifychecksumscontroller.h @@ -1,78 +1,80 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/verifychecksumscontroller.h This file is part of Kleopatra, the KDE keymanager Copyright (c) 2010 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #ifndef __KLEOPATRA_CRYPTO_VERIFYCHECKSUMSCONTROLLER_H__ #define __KLEOPATRA_CRYPTO_VERIFYCHECKSUMSCONTROLLER_H__ #include #ifndef QT_NO_DIRMODEL #include #include #include +#ifndef Q_MOC_RUN #include +#endif #include namespace Kleo { namespace Crypto { class VerifyChecksumsController : public Controller { Q_OBJECT public: explicit VerifyChecksumsController( QObject * parent=0 ); explicit VerifyChecksumsController( const boost::shared_ptr & ctx, QObject * parent=0 ); ~VerifyChecksumsController(); void setFiles( const QStringList & files ); void start(); public Q_SLOTS: void cancel(); private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT( d, void slotOperationFinished() ) }; } } #endif // QT_NO_DIRMODEL #endif /* __KLEOPATRA_UISERVER_VERIFYCHECKSUMSCONTROLLER_H__ */ diff --git a/kleopatra/dialogs/certificatedetailsdialog.cpp b/kleopatra/dialogs/certificatedetailsdialog.cpp index bc5ffcb811..2296bc3fc1 100644 --- a/kleopatra/dialogs/certificatedetailsdialog.cpp +++ b/kleopatra/dialogs/certificatedetailsdialog.cpp @@ -1,483 +1,485 @@ /* -*- mode: c++; c-basic-offset:4 -*- dialogs/certificatedetailsdialog.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2008 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "certificatedetailsdialog.h" #include "ui_certificatedetailsdialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#ifndef Q_MOC_RUN #include +#endif #include #include using namespace Kleo; using namespace Kleo::Dialogs; using namespace Kleo::Commands; using namespace GpgME; using namespace boost; static bool own( const std::vector & sigs ) { const shared_ptr kc = KeyCache::instance(); Q_FOREACH( const UserID::Signature & sig, sigs ) { const Key signer = kc->findByKeyIDOrFingerprint( sig.signerKeyID() ); if ( signer.isNull() || !signer.hasSecret() ) return false; } return !sigs.empty(); } class CertificateDetailsDialog::Private { friend class ::Kleo::Dialogs::CertificateDetailsDialog; CertificateDetailsDialog * const q; public: explicit Private( CertificateDetailsDialog * qq ) : q( qq ), key(), certificationsModel(), subkeysModel(), ui( q ) { ui.certificationsTV->setModel( &certificationsModel ); connect( ui.certificationsTV->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), q, SLOT(slotCertificationSelectionChanged()) ); connect( ui.changePassphrasePB, SIGNAL(clicked()), q, SLOT(slotChangePassphraseClicked()) ); connect( ui.changeTrustLevelPB, SIGNAL(clicked()), q, SLOT(slotChangeTrustLevelClicked()) ); connect( ui.changeExpiryDatePB, SIGNAL(clicked()), q, SLOT(slotChangeExpiryDateClicked()) ); connect( ui.revokeCertificationPB, SIGNAL(clicked()), q, SLOT(slotRevokeCertificationClicked()) ); connect( ui.addUserIDPB, SIGNAL(clicked()), q, SLOT(slotAddUserIDClicked()) ); connect( ui.revokeUserIDPB, SIGNAL(clicked()), q, SLOT(slotRevokeUserIDClicked()) ); connect( ui.certifyUserIDPB, SIGNAL(clicked()), q, SLOT(slotCertifyUserIDClicked()) ); connect( ui.revokeCertificationPB, SIGNAL(clicked()), q, SLOT(slotRevokeCertificationClicked()) ); connect( ui.showCertificationsPB, SIGNAL(clicked()), q, SLOT(slotShowCertificationsClicked()) ); ui.subkeyTV->setModel( &subkeysModel ); // no selection (yet) connect( KeyCache::instance().get(), SIGNAL(keysMayHaveChanged()), q, SLOT(slotKeysMayHaveChanged()) ); } void readConfig() { KConfigGroup dialog( KGlobal::config(), "CertificateDetailsDialog" ); const QSize size = dialog.readEntry( "Size", QSize(600, 400) ); if ( size.isValid() ) { q->resize( size ); } } void writeConfig() { KConfigGroup dialog( KGlobal::config(), "CertificateDetailsDialog" ); dialog.writeEntry( "Size", q->size() ); dialog.sync(); } private: void startCommandImplementation( const QPointer & ptr, const char * slot ) { connect( ptr, SIGNAL(finished()), q, slot ); ptr->start(); enableDisableWidgets(); } template void startCommand( QPointer & ptr, const A & arg, const char * slot ) { if ( ptr ) return; ptr = new T( arg ); startCommandImplementation( ptr, slot ); } template void startCommand( QPointer & ptr, const char * slot ) { startCommand( ptr, this->key, slot ); } void commandFinished( QPointer & ptr ) { ptr = 0; enableDisableWidgets(); } void slotChangePassphraseClicked() { startCommand( changePassphraseCommand, SLOT(slotChangePassphraseCommandFinished()) ); } void slotChangePassphraseCommandFinished() { commandFinished( changePassphraseCommand ); } void slotChangeTrustLevelClicked() { startCommand( changeOwnerTrustCommand, SLOT(slotChangeOwnerTrustCommandFinished()) ); } void slotChangeOwnerTrustCommandFinished() { commandFinished( changeOwnerTrustCommand ); } void slotChangeExpiryDateClicked() { startCommand( changeExpiryDateCommand, SLOT(slotChangeExpiryDateCommandFinished()) ); } void slotChangeExpiryDateCommandFinished() { commandFinished( changeExpiryDateCommand ); } void slotAddUserIDClicked() { startCommand( addUserIDCommand, SLOT(slotAddUserIDCommandFinished()) ); } void slotAddUserIDCommandFinished() { commandFinished( addUserIDCommand ); } void slotCertifyUserIDClicked() { const std::vector uids = selectedUserIDs(); if ( uids.empty() ) return; startCommand( signCertificateCommand, uids, SLOT(slotSignCertificateCommandFinished()) ); } void slotSignCertificateCommandFinished() { commandFinished( signCertificateCommand ); } void slotRevokeCertificateClicked() { } void slotRevokeUserIDClicked() { } void slotRevokeCertificationClicked() { } void slotShowCertificationsClicked() { startSignatureListing(); enableDisableWidgets(); } void startSignatureListing() { if ( keyListJob ) return; const CryptoBackend::Protocol * const protocol = CryptoBackendFactory::instance()->protocol( key.protocol() ); if ( !protocol ) return; KeyListJob * const job = protocol->keyListJob( /*remote*/false, /*includeSigs*/true, /*validate*/true ); if ( !job ) return; connect( job, SIGNAL(result(GpgME::KeyListResult)), q, SLOT(slotSignatureListingDone(GpgME::KeyListResult)) ); connect( job, SIGNAL(nextKey(GpgME::Key)), q, SLOT(slotSignatureListingNextKey(GpgME::Key)) ); if ( const Error err = job->start( QStringList( QString::fromLatin1( key.primaryFingerprint() ) ) ) ) showSignatureListingErrorDialog( err ); else keyListJob = job; } void slotSignatureListingNextKey( const Key & key ) { // don't lose the secret flags ... Key merged = key; merged.mergeWith( this->key ); q->setKey( merged ); // fixup the tree view ui.certificationsTV->expandAll(); ui.certificationsTV->header()->resizeSections( QHeaderView::ResizeToContents ); } void slotSignatureListingDone( const KeyListResult & result ) { if ( result.error().isCanceled() ) ; else if ( result.error() ) showSignatureListingErrorDialog( result.error() ); else { ; // nothing to do } keyListJob = 0; enableDisableWidgets(); } void showSignatureListingErrorDialog( const Error & err ) { KMessageBox::information( q, i18nc("@info", "An error occurred while loading the certifications: " "%1", QString::fromLocal8Bit( err.asString() ) ), i18nc("@title","Certifications Loading Failed") ); } void slotCertificationSelectionChanged() { enableDisableWidgets(); } void slotKeysMayHaveChanged() { if ( const char * const fpr = key.primaryFingerprint() ) if ( !(key.keyListMode() & Extern) ) q->setKey( KeyCache::instance()->findByFingerprint( fpr ) ); } void slotDumpCertificate() { if ( dumpCertificateCommand ) return; if ( key.protocol() != CMS ) { ui.dumpLTW->clear(); return; } ui.dumpLTW->setLines( QStringList( i18n("Please wait while generating the dump...") ) ); dumpCertificateCommand = new DumpCertificateCommand( key ); dumpCertificateCommand->setUseDialog( false ); QPointer cmd = dumpCertificateCommand.data(); startCommandImplementation( cmd, SLOT(slotDumpCertificateCommandFinished()) ); } void slotDumpCertificateCommandFinished() { ui.dumpLTW->setLines( dumpCertificateCommand->output() ); } private: void updateWidgetVisibility() { const bool x509 = key.protocol() == CMS; const bool pgp = key.protocol() == OpenPGP; const bool secret = key.hasSecret(); const bool sigs = (key.keyListMode() & Signatures); const bool ultimateTrust = key.ownerTrust() == Key::Ultimate; const bool external = (key.keyListMode() & Extern); // Overview Tab ui.overviewActionsGB->setVisible( !external ); ui.changePassphrasePB->setVisible( secret ); ui.changeTrustLevelPB->setVisible( pgp && ( !secret || !ultimateTrust ) ); ui.changeExpiryDatePB->setVisible( pgp && secret ); // Certifications Tab ui.userIDsActionsGB->setVisible( !external && pgp ); ui.certificationsActionGB->setVisible( !external && pgp ); ui.addUserIDPB->setVisible( secret ); ui.expandAllCertificationsPB->setVisible( pgp && sigs ); ui.collapseAllCertificationsPB->setVisible( pgp && sigs ); ui.showCertificationsPB->setVisible( !external && pgp && !sigs ); // Technical Details Tab ui.tabWidget->setTabEnabled( ui.tabWidget->indexOf( ui.detailsTab ), pgp ); // Chain tab ui.tabWidget->setTabEnabled( ui.tabWidget->indexOf( ui.chainTab ), x509 ); // Dump tab ui.tabWidget->setTabEnabled( ui.tabWidget->indexOf( ui.dumpTab ), x509 ); // not implemented: ui.revokeCertificatePB->hide(); ui.revokeUserIDPB->hide(); ui.certificationsActionGB->hide(); } QModelIndexList selectedCertificationsIndexes() const { return ui.certificationsTV->selectionModel()->selectedRows(); } std::vector selectedUserIDs() const { const QModelIndexList mil = selectedCertificationsIndexes(); std::vector uids = certificationsModel.userIDs( mil, true ); uids.erase( std::remove_if( uids.begin(), uids.end(), mem_fn( &UserID::isNull ) ), uids.end() ); return uids; } std::vector selectedSignatures() const { const QModelIndexList mil = selectedCertificationsIndexes(); std::vector sigs = certificationsModel.signatures( mil ); sigs.erase( std::remove_if( sigs.begin(), sigs.end(), mem_fn( &UserID::Signature::isNull ) ), sigs.end() ); return sigs; } void enableDisableWidgets() { // Overview Tab ui.changePassphrasePB->setEnabled( !changePassphraseCommand ); ui.changeTrustLevelPB->setEnabled( !changeOwnerTrustCommand ); ui.changeExpiryDatePB->setEnabled( !changeExpiryDateCommand ); // Certifications Tab ui.addUserIDPB->setEnabled( !addUserIDCommand ); ui.showCertificationsPB->setEnabled( !keyListJob ); ui.showCertificationsPB->setText( keyListJob ? i18n("(please wait while certifications are being loaded)") : i18n("Load Certifications (may take a while)") ); const std::vector uids = selectedUserIDs(); const std::vector sigs = selectedSignatures(); ui.certifyUserIDPB->setEnabled( !uids.empty() && sigs.empty() && !signCertificateCommand ); ui.revokeUserIDPB->setEnabled( !uids.empty() && sigs.empty() ); ui.revokeCertificationPB->setEnabled( uids.empty() && !sigs.empty() && own( sigs ) ); } void updateLabel() { ui.overviewLB->setText( Formatting::formatOverview( key ) ); } void updateChainTab() { ui.chainTW->clear(); if ( key.protocol() != CMS ) return; QTreeWidgetItem * last = 0; const std::vector chain = KeyCache::instance()->findIssuers( key, KeyCache::RecursiveSearch|KeyCache::IncludeSubject ); if ( chain.empty() ) return; if ( !chain.back().isRoot() ) { last = new QTreeWidgetItem( ui.chainTW ); last->setText( 0, i18n("Issuer Certificate Not Found (%1)", DN( chain.back().issuerName() ).prettyDN() ) ); //last->setSelectable( false ); const QBrush & fg = ui.chainTW->palette().brush( QPalette::Disabled, QPalette::WindowText ); last->setForeground( 0, fg ); } for ( std::vector::const_reverse_iterator it = chain.rbegin(), end = chain.rend() ; it != end ; ++it ) { last = last ? new QTreeWidgetItem( last ) : new QTreeWidgetItem( ui.chainTW ) ; last->setText( 0, DN( it->userID(0).id() ).prettyDN() ); //last->setSelectable( true ); } ui.chainTW->expandAll(); } void propagateKey() { certificationsModel.setKey( key ); const QModelIndexList uidIndexes = certificationsModel.indexes( key.userIDs() ); Q_FOREACH( const QModelIndex & idx, uidIndexes ) ui.certificationsTV->setFirstColumnSpanned( idx.row(), idx.parent(), true ); subkeysModel.setKey( key ); ui.subkeyTV->header()->resizeSections( QHeaderView::ResizeToContents ); updateChainTab(); slotDumpCertificate(); } private: Key key; UserIDListModel certificationsModel; SubkeyListModel subkeysModel; QPointer changePassphraseCommand; QPointer changeOwnerTrustCommand; QPointer changeExpiryDateCommand; QPointer addUserIDCommand; QPointer signCertificateCommand; QPointer dumpCertificateCommand; QPointer keyListJob; struct UI : public Ui_CertificateDetailsDialog { explicit UI( Dialogs::CertificateDetailsDialog * qq ) : Ui_CertificateDetailsDialog() { setupUi( qq->mainWidget() ); qq->setButtons( KDialog::Help | KDialog::Close ); qq->setHelp(QString(), QLatin1String("kleopatra")); chainTW->header()->setResizeMode( 0, QHeaderView::Stretch ); dumpLTW->setFont( KGlobalSettings::fixedFont() ); dumpLTW->setMinimumVisibleLines( 15 ); dumpLTW->setMinimumVisibleColumns( 40 ); subkeyHLine->setTitle( i18nc("@title","Subkeys") ); } } ui; }; CertificateDetailsDialog::CertificateDetailsDialog( QWidget * p, Qt::WindowFlags f ) : KDialog( p, f ), d( new Private( this ) ) { d->readConfig(); } CertificateDetailsDialog::~CertificateDetailsDialog() { d->writeConfig(); } void CertificateDetailsDialog::setKey( const Key & key ) { d->key = key; d->updateWidgetVisibility(); d->updateLabel(); d->propagateKey(); d->enableDisableWidgets(); } Key CertificateDetailsDialog::key() const { return d->key; } #include "moc_certificatedetailsdialog.cpp" diff --git a/kleopatra/dialogs/certificateselectiondialog.cpp b/kleopatra/dialogs/certificateselectiondialog.cpp index 8caa459ccb..90dac06d32 100644 --- a/kleopatra/dialogs/certificateselectiondialog.cpp +++ b/kleopatra/dialogs/certificateselectiondialog.cpp @@ -1,356 +1,358 @@ /* -*- mode: c++; c-basic-offset:4 -*- dialogs/certificateselectiondialog.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2008 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "certificateselectiondialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#ifndef Q_MOC_RUN #include +#endif #include using namespace Kleo; using namespace Kleo::Dialogs; using namespace Kleo::Commands; using namespace boost; using namespace GpgME; class CertificateSelectionDialog::Private { friend class ::Kleo::Dialogs::CertificateSelectionDialog; CertificateSelectionDialog * const q; public: explicit Private( CertificateSelectionDialog * qq ); private: void reload() { Command * const cmd = new ReloadKeysCommand( 0 ); cmd->setParentWidget( q ); cmd->start(); } void create() { NewCertificateCommand * cmd = new NewCertificateCommand( 0 ); cmd->setParentWidget( q ); if ( ( options & AnyFormat ) != AnyFormat ) cmd->setProtocol( (options & OpenPGPFormat) ? OpenPGP : CMS ); cmd->start(); } void lookup() { Command * const cmd = new LookupCertificatesCommand( 0 ); cmd->setParentWidget( q ); cmd->start(); } void slotKeysMayHaveChanged(); void slotCurrentViewChanged( QAbstractItemView * newView ); void slotSelectionChanged(); void slotDoubleClicked( const QModelIndex & idx ); private: bool acceptable( const std::vector & keys ) { return !keys.empty(); } void filterAllowedKeys( std::vector & keys ); void updateLabelText() { ui.label.setText( !customLabelText.isEmpty() ? customLabelText : (options & MultiSelection) ? i18n( "Please select one or more of the following certificates:" ) : i18n( "Please select one of the following certificates:" ) ); } private: QPointer lastView; QString customLabelText; Options options; struct UI { QLabel label; SearchBar searchBar; TabWidget tabWidget; QDialogButtonBox buttonBox; QVBoxLayout vlay; explicit UI( CertificateSelectionDialog * q ) : label( q ), searchBar( q ), tabWidget( q ), buttonBox( q ), vlay( q ) { KDAB_SET_OBJECT_NAME( label ); KDAB_SET_OBJECT_NAME( searchBar ); KDAB_SET_OBJECT_NAME( tabWidget ); KDAB_SET_OBJECT_NAME( buttonBox ); KDAB_SET_OBJECT_NAME( vlay ); vlay.addWidget( &label ); vlay.addWidget( &searchBar ); vlay.addWidget( &tabWidget, 1 ); vlay.addWidget( &buttonBox ); QPushButton * const ok = buttonBox.addButton( QDialogButtonBox::Ok ); ok->setEnabled( false ); QPushButton * const cancel = buttonBox.addButton( QDialogButtonBox::Close ); Q_UNUSED( cancel ); QPushButton * const reload = buttonBox.addButton( i18n("Reload"), QDialogButtonBox::ActionRole ); QPushButton * const lookup = buttonBox.addButton( i18n("Lookup..."), QDialogButtonBox::ActionRole ); QPushButton * const create = buttonBox.addButton( i18n("New..."), QDialogButtonBox::ActionRole ); lookup->setToolTip( i18nc("@info:tooltip","Lookup certificates on server") ); reload->setToolTip( i18nc("@info:tooltip","Refresh certificate list") ); create->setToolTip( i18nc("@info:tooltip","Create a new certificate") ); connect( &buttonBox, SIGNAL(accepted()), q, SLOT(accept()) ); connect( &buttonBox, SIGNAL(rejected()), q, SLOT(reject()) ); connect( reload, SIGNAL(clicked()), q, SLOT(reload()) ); connect( lookup, SIGNAL(clicked()), q, SLOT(lookup()) ); connect( create, SIGNAL(clicked()), q, SLOT(create()) ); connect( KeyCache::instance().get(), SIGNAL(keysMayHaveChanged()), q, SLOT(slotKeysMayHaveChanged()) ); } } ui; }; CertificateSelectionDialog::Private::Private( CertificateSelectionDialog * qq ) : q( qq ), ui( q ) { ui.tabWidget.setFlatModel( AbstractKeyListModel::createFlatKeyListModel() ); ui.tabWidget.setHierarchicalModel( AbstractKeyListModel::createHierarchicalKeyListModel() ); ui.tabWidget.connectSearchBar( &ui.searchBar ); connect( &ui.tabWidget, SIGNAL(currentViewChanged(QAbstractItemView*)), q, SLOT(slotCurrentViewChanged(QAbstractItemView*)) ); updateLabelText(); q->setWindowTitle( i18n( "Certificate Selection" ) ); } CertificateSelectionDialog::CertificateSelectionDialog( QWidget * parent, Qt::WindowFlags f ) : QDialog( parent, f ), d( new Private( this ) ) { const KSharedConfig::Ptr config = KSharedConfig::openConfig( QLatin1String("kleopatracertificateselectiondialogrc") ); d->ui.tabWidget.loadViews( config.data() ); const KConfigGroup geometry( config, "Geometry" ); resize( geometry.readEntry( "size", size() ) ); d->slotKeysMayHaveChanged(); } CertificateSelectionDialog::~CertificateSelectionDialog() {} void CertificateSelectionDialog::setCustomLabelText( const QString & txt ) { if ( txt == d->customLabelText ) return; d->customLabelText = txt; d->updateLabelText(); } QString CertificateSelectionDialog::customLabelText() const { return d->customLabelText; } void CertificateSelectionDialog::setOptions( Options options ) { if ( d->options == options ) return; d->options = options; d->ui.tabWidget.setMultiSelection( options & MultiSelection ); d->slotKeysMayHaveChanged(); } CertificateSelectionDialog::Options CertificateSelectionDialog::options() const { return d->options; } void CertificateSelectionDialog::setStringFilter( const QString & filter ) { d->ui.tabWidget.setStringFilter( filter ); } void CertificateSelectionDialog::setKeyFilter( const shared_ptr & filter ) { d->ui.tabWidget.setKeyFilter( filter ); } void CertificateSelectionDialog::selectCertificates( const std::vector & keys ) { const QAbstractItemView * const view = d->ui.tabWidget.currentView(); if ( !view ) return; const KeyListModelInterface * const model = dynamic_cast( view->model() ); assert( model ); QItemSelectionModel * const sm = view->selectionModel(); assert( sm ); Q_FOREACH( const QModelIndex & idx, model->indexes( keys ) ) if ( idx.isValid() ) sm->select( idx, QItemSelectionModel::Select | QItemSelectionModel::Rows ); } void CertificateSelectionDialog::selectCertificate( const Key & key ) { selectCertificates( std::vector( 1, key ) ); } std::vector CertificateSelectionDialog::selectedCertificates() const { const QAbstractItemView * const view = d->ui.tabWidget.currentView(); if ( !view ) return std::vector(); const KeyListModelInterface * const model = dynamic_cast( view->model() ); assert( model ); const QItemSelectionModel * const sm = view->selectionModel(); assert( sm ); return model->keys( sm->selectedRows() ); } Key CertificateSelectionDialog::selectedCertificate() const { const std::vector keys = selectedCertificates(); return keys.empty() ? Key() : keys.front() ; } void CertificateSelectionDialog::hideEvent( QHideEvent * e ) { KSharedConfig::Ptr config = KSharedConfig::openConfig( QLatin1String("kleopatracertificateselectiondialogrc") ); d->ui.tabWidget.saveViews( config.data() ); KConfigGroup geometry( config, "Geometry" ); geometry.writeEntry( "size", size() ); QDialog::hideEvent( e ); } void CertificateSelectionDialog::Private::slotKeysMayHaveChanged() { q->setEnabled( true ); std::vector keys = (options & SecretKeys) ? KeyCache::instance()->secretKeys() : KeyCache::instance()->keys() ; filterAllowedKeys( keys ); const std::vector selected = q->selectedCertificates(); if ( AbstractKeyListModel * const model = ui.tabWidget.flatModel() ) model->setKeys( keys ); if ( AbstractKeyListModel * const model = ui.tabWidget.hierarchicalModel() ) model->setKeys( keys ); q->selectCertificates( selected ); } void CertificateSelectionDialog::Private::filterAllowedKeys( std::vector & keys ) { std::vector::iterator end = keys.end(); switch ( options & AnyFormat ) { case OpenPGPFormat: end = std::remove_if( keys.begin(), end, boost::bind( &Key::protocol, _1 ) != GpgME::OpenPGP ); break; case CMSFormat: end = std::remove_if( keys.begin(), end, boost::bind( &Key::protocol, _1 ) != GpgME::CMS ); break; default: case AnyFormat: ; } switch ( options & AnyCertificate ) { case SignOnly: end = std::remove_if( keys.begin(), end, !boost::bind( &Key::canReallySign, _1 ) ); break; case EncryptOnly: end = std::remove_if( keys.begin(), end, !boost::bind( &Key::canEncrypt, _1 ) ); break; default: case AnyCertificate: ; } if ( options & SecretKeys ) end = std::remove_if( keys.begin(), end, !boost::bind( &Key::hasSecret, _1 ) ); keys.erase( end, keys.end() ); } void CertificateSelectionDialog::Private::slotCurrentViewChanged( QAbstractItemView * newView ) { if ( lastView ) { disconnect( lastView, SIGNAL(doubleClicked(QModelIndex)), q, SLOT(slotDoubleClicked(QModelIndex)) ); assert( lastView->selectionModel() ); disconnect( lastView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), q, SLOT(slotSelectionChanged()) ); } lastView = newView; if ( newView ) { connect( newView, SIGNAL(doubleClicked(QModelIndex)), q, SLOT(slotDoubleClicked(QModelIndex)) ); assert( newView->selectionModel() ); connect( newView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), q, SLOT(slotSelectionChanged()) ); } slotSelectionChanged(); } void CertificateSelectionDialog::Private::slotSelectionChanged() { if ( QPushButton * const pb = ui.buttonBox.button( QDialogButtonBox::Ok ) ) pb->setEnabled( acceptable( q->selectedCertificates() ) ); } void CertificateSelectionDialog::Private::slotDoubleClicked( const QModelIndex & idx ) { QAbstractItemView * const view = ui.tabWidget.currentView(); assert( view ); const KeyListModelInterface * const model = dynamic_cast( view->model() ); assert( model ); Q_UNUSED( model ); QItemSelectionModel * const sm = view->selectionModel(); assert( sm ); sm->select( idx, QItemSelectionModel::ClearAndSelect|QItemSelectionModel::Rows ); QMetaObject::invokeMethod( q, "accept", Qt::QueuedConnection ); } void CertificateSelectionDialog::accept() { if ( d->acceptable( selectedCertificates() ) ) QDialog::accept(); } #include "moc_certificateselectiondialog.cpp" diff --git a/kleopatra/dialogs/certifycertificatedialog.cpp b/kleopatra/dialogs/certifycertificatedialog.cpp index 2a44873a57..2c1dd86b61 100644 --- a/kleopatra/dialogs/certifycertificatedialog.cpp +++ b/kleopatra/dialogs/certifycertificatedialog.cpp @@ -1,462 +1,464 @@ /* -*- mode: c++; c-basic-offset:4 -*- dialogs/signcertificatedialog.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2008 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "certifycertificatedialog.h" #include "certifycertificatedialog_p.h" #include #include #include #include #include #include #include #include #include #include #include #include #include // Qt::escape +#ifndef Q_MOC_RUN #include +#endif #include #include using namespace boost; using namespace GpgME; using namespace Kleo; using namespace Kleo::Dialogs; using namespace Kleo::Dialogs::CertifyCertificateDialogPrivate; void UserIDModel::setCertificateToCertify( const Key & key ) { m_key = key; clear(); const std::vector ids = key.userIDs(); for ( unsigned int i = 0; i < ids.size(); ++i ) { QStandardItem * const item = new QStandardItem; item->setText( Formatting::prettyUserID( key.userID( i ) ) ); item->setData( i, UserIDIndex ); item->setCheckable( true ); item->setEditable( false ); appendRow( item ); } } void UserIDModel::setCheckedUserIDs( const std::vector & uids ) { const std::vector sorted = kdtools::sorted( uids ); for ( unsigned int i = 0, end = rowCount() ; i != end ; ++i ) item( i )->setCheckState( kdtools::binary_search( sorted, i ) ? Qt::Checked : Qt::Unchecked ); } std::vector UserIDModel::checkedUserIDs() const { std::vector ids; for ( int i = 0; i < rowCount(); ++i ) if ( item( i )->checkState() == Qt::Checked ) ids.push_back( item( i )->data( UserIDIndex ).toUInt() ); return ids; } void SecretKeysModel::setSecretKeys( const std::vector & keys ) { clear(); m_secretKeys = keys; for ( unsigned int i = 0; i < m_secretKeys.size(); ++i ) { const Key key = m_secretKeys[i]; QStandardItem * const item = new QStandardItem; item->setText( Formatting::formatForComboBox( key ) ); item->setData( i, IndexRole ); item->setEditable( false ); appendRow( item ); } } std::vector SecretKeysModel::secretKeys() const { return m_secretKeys; } Key SecretKeysModel::keyFromItem( const QStandardItem * item ) const { assert( item ); const unsigned int idx = item->data( IndexRole ).toUInt(); assert( idx < m_secretKeys.size() ); return m_secretKeys[idx]; } Key SecretKeysModel::keyFromIndex( const QModelIndex & idx ) const { return keyFromItem( itemFromIndex( idx ) ); } SelectUserIDsPage::SelectUserIDsPage( QWidget * parent ) : QWizardPage( parent ), m_userIDModel() { QVBoxLayout * const layout = new QVBoxLayout ( this ); QLabel * const label = new QLabel; label->setText( i18n( "Step 1: Please select the user IDs you wish to certify." ) ); layout->addWidget( label ); m_listView = new QListView; m_listView->setModel( &m_userIDModel ); layout->addWidget( m_listView, 1 ); m_label = new QLabel; layout->addWidget( m_label ); m_checkbox = new QCheckBox; m_checkbox->setChecked( false ); m_checkbox->setText( i18n("I have verified the fingerprint") ); layout->addWidget( m_checkbox ); connect( m_checkbox, SIGNAL(toggled(bool)), this, SIGNAL(completeChanged()) ); connect( &m_userIDModel, SIGNAL(itemChanged(QStandardItem*)), this, SIGNAL(completeChanged()) ); } bool SelectUserIDsPage::isComplete() const { return m_checkbox->isChecked() && !selectedUserIDs().empty(); } void SelectUserIDsPage::setSelectedUserIDs( const std::vector & uids ) { m_userIDModel.setCheckedUserIDs( uids ); } std::vector SelectUserIDsPage::selectedUserIDs() const { return m_userIDModel.checkedUserIDs(); } void SelectUserIDsPage::setCertificateToCertify( const Key & key ) { m_label->setText( i18n( "Certificate: %1\nFingerprint: %2", Formatting::formatForComboBox( key ), QLatin1String(key.primaryFingerprint()) ) ); m_userIDModel.setCertificateToCertify( key ); } SelectCheckLevelPage::SelectCheckLevelPage( QWidget * parent ) : QWizardPage( parent ), m_ui() { m_ui.setupUi( this ); } unsigned int SelectCheckLevelPage::checkLevel() const { if ( m_ui.checkLevelNotCheckedRB->isChecked() ) return 1; if ( m_ui.checkLevelCasualRB->isChecked() ) return 2; if ( m_ui.checkLevelThoroughlyRB->isChecked() ) return 3; assert( !"No check level radiobutton checked" ); return 0; } OptionsPage::OptionsPage( QWidget * parent ) : QWizardPage( parent ), m_ui() { m_ui.setupUi( this ); m_ui.keyListView->setModel( &m_model ); connect( m_ui.keyListView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SIGNAL(completeChanged()) ); setCommitPage( true ); setButtonText( QWizard::CommitButton, i18n( "Certify" ) ); } bool OptionsPage::exportableCertificationSelected() const { return m_ui.exportableSignatureRB->isChecked(); } void OptionsPage::setCertificatesWithSecretKeys( const std::vector & keys ) { assert( !keys.empty() ); m_model.setSecretKeys( keys ); if ( keys.size() == 1 ) { m_ui.stackedWidget->setCurrentWidget( m_ui.singleKeyPage ); m_ui.singleKeyLabel->setText( i18n( "Certification will be performed using certificate %1.", Formatting::prettyNameAndEMail( keys[0] ) ) ); } else { m_ui.stackedWidget->setCurrentWidget( m_ui.multipleKeysPage ); } emit completeChanged(); } Key OptionsPage::selectedSecretKey() const { if ( m_model.secretKeys().size() == 1 ) return m_model.secretKeys().at( 0 ); const QModelIndexList idxs = m_ui.keyListView->selectionModel()->selectedIndexes(); assert( idxs.size() <= 1 ); return idxs.isEmpty() ? Key() : m_model.keyFromIndex( idxs[0] ); } bool OptionsPage::sendToServer() const { return m_ui.sendToServerCB->isChecked(); } bool OptionsPage::validatePage() { emit nextClicked(); return true; } bool OptionsPage::isComplete() const { return !selectedSecretKey().isNull(); } SummaryPage::SummaryPage( QWidget * parent ) : QWizardPage( parent ), m_complete( false ) { QGridLayout * const layout = new QGridLayout( this ); QLabel * const uidLabelLabel = new QLabel( i18n( "Signed user IDs:" ) ); uidLabelLabel->setAlignment( Qt::AlignTop ); int row = 0; layout->addWidget( new QLabel( i18n( "Summary:" ) ), row, 0, 1, 2 ); layout->addWidget( uidLabelLabel, ++row, 0 ); layout->addWidget( m_userIDsLabel = new QLabel, row, 1 ); #ifdef KLEO_SIGN_KEY_CERTLEVEL_SUPPORT layout->addWidget( new QLabel( i18n( "Check level:" ) ), ++row, 0 ); layout->addWidget( m_checkLevelLabel = new QLabel, row, 1 ); #else m_checkLevelLabel = 0; #endif layout->addWidget( new QLabel( i18n( "Selected secret key:" ) ), ++row, 0 ); layout->addWidget( m_secretKeyLabel = new QLabel, row, 1 ); m_secretKeyLabel->setTextFormat( Qt::PlainText ); layout->addWidget( m_resultLabel = new QLabel, ++row, 0, 1, 2, Qt::AlignCenter ); m_resultLabel->setWordWrap( true ); layout->setRowStretch( row, 1 ); m_resultLabel->setAlignment( Qt::AlignCenter ); } bool SummaryPage::isComplete() const { return m_complete; } void SummaryPage::setSummary( const SummaryPage::Summary & sum ) { const Key key = sum.certificateToCertify; QStringList ids; Q_FOREACH ( const unsigned int i, sum.selectedUserIDs ) ids += Qt::escape( Formatting::prettyUserID( key.userID( i ) ) ); m_userIDsLabel->setText( QLatin1String("") + ids.join( QLatin1String("
") ) + QLatin1String("
") ); m_secretKeyLabel->setText( sum.secretKey.isNull() ? i18n( "Default certificate" ) : Formatting::prettyNameAndEMail( sum.secretKey ) ); #ifdef KLEO_SIGN_KEY_CERTLEVEL_SUPPORT switch( sum.checkLevel ) { case 0: m_checkLevelLabel->setText( i18n( "No statement made" ) ); break; case 1: m_checkLevelLabel->setText( i18n( "Not checked" ) ); break; case 2: m_checkLevelLabel->setText( i18n( "Casually checked" ) ); break; case 3: m_checkLevelLabel->setText( i18n( "Thoroughly checked" ) ); break; } #endif } void SummaryPage::setComplete( bool complete ) { if ( complete == m_complete ) return; m_complete = complete; emit completeChanged(); } void SummaryPage::setResult( const Error & err ) { if ( err && !err.isCanceled() ) if ( err.code() == GPG_ERR_USER_1 ) m_resultLabel->setText( i18n( "The certificate was not certified because it was already certified by the same certificate." ) ); else m_resultLabel->setText( i18n( "The certificate could not be certified. Error: %1", Qt::escape( QString::fromLocal8Bit( err.asString() ) ) ) ); else if ( err.isCanceled() ) m_resultLabel->setText( i18n("Certification canceled.") ); else m_resultLabel->setText(i18n("Certification successful.") ); } class CertifyCertificateDialog::Private { friend class ::Kleo::Dialogs::CertifyCertificateDialog; CertifyCertificateDialog * const q; public: explicit Private( CertifyCertificateDialog * qq ) : q( qq ), summaryPageId( 0 ), selectUserIDsPage( 0 ), selectCheckLevelPage( 0 ), optionsPage( 0 ), summaryPage( 0 ) { selectUserIDsPage = new SelectUserIDsPage( q ); q->addPage( selectUserIDsPage ); //selectCheckLevelPage = new SelectCheckLevelPage( q ); //setting the cert level explicitly is not supported by the backend, //thus we omit the page from the UI //q->addPage( selectCheckLevelPage ); optionsPage = new OptionsPage( q ); q->addPage( optionsPage ); summaryPage = new SummaryPage( q ); summaryPageId = q->addPage( summaryPage ); connect( optionsPage, SIGNAL(nextClicked()), q, SIGNAL(certificationPrepared()) ); } Key key() const { return selectUserIDsPage ? selectUserIDsPage->certificateToCertify() : Key() ; } void ensureSummaryPageVisible(); void certificationResult( const Error & error ); void setOperationCompleted() { summaryPage->setComplete( true ); } SummaryPage::Summary createSummary() const { SummaryPage::Summary sum; sum.selectedUserIDs = selectUserIDsPage->selectedUserIDs(); sum.secretKey = optionsPage->selectedSecretKey(); sum.certificateToCertify = selectUserIDsPage->certificateToCertify(); //PENDING #ifdef KLEO_SIGN_KEY_CERTLEVEL_SUPPORT sum.checkLevel = selectCheckLevelPage->checkLevel(); #else sum.checkLevel = 0; #endif sum.exportable = optionsPage->exportableCertificationSelected(); sum.sendToServer = optionsPage->sendToServer(); return sum; } int summaryPageId; SelectUserIDsPage * selectUserIDsPage; SelectCheckLevelPage * selectCheckLevelPage; OptionsPage * optionsPage; SummaryPage * summaryPage; }; CertifyCertificateDialog::CertifyCertificateDialog( QWidget * p, Qt::WindowFlags f ) : QWizard( p, f ), d( new Private( this ) ) { } CertifyCertificateDialog::~CertifyCertificateDialog() {} void CertifyCertificateDialog::setCertificateToCertify( const Key & key ) { setWindowTitle( i18nc( "arg is name, email of certificate holder", "Certify Certificate: %1", Formatting::prettyName( key ) ) ); d->selectUserIDsPage->setCertificateToCertify( key ); } void CertifyCertificateDialog::setCertificatesWithSecretKeys( const std::vector & keys ) { d->optionsPage->setCertificatesWithSecretKeys( keys ); } bool CertifyCertificateDialog::exportableCertificationSelected() const { return d->optionsPage->exportableCertificationSelected(); } bool CertifyCertificateDialog::trustCertificationSelected() const { return false; } bool CertifyCertificateDialog::nonRevocableCertificationSelected() const { return false; } Key CertifyCertificateDialog::selectedSecretKey() const { return d->optionsPage->selectedSecretKey(); } bool CertifyCertificateDialog::sendToServer() const { return d->optionsPage->sendToServer(); } unsigned int CertifyCertificateDialog::selectedCheckLevel() const { //PENDING #ifdef KLEO_SIGN_KEY_CERTLEVEL_SUPPORT return d->selectCheckLevelPage->checkLevel(); #endif return 0; } void CertifyCertificateDialog::connectJob( SignKeyJob * job ) { connect( job, SIGNAL(result(GpgME::Error)), this, SLOT(certificationResult(GpgME::Error)) ); d->summaryPage->setSummary( d->createSummary() ); } void CertifyCertificateDialog::setError( const Error & error ) { d->setOperationCompleted(); d->summaryPage->setResult( error ); d->ensureSummaryPageVisible(); if ( error.isCanceled() ) close(); } void CertifyCertificateDialog::Private::certificationResult( const Error & err ) { setOperationCompleted(); summaryPage->setResult( err ); ensureSummaryPageVisible(); } namespace { struct UidEqual : std::binary_function { bool operator()( const UserID & lhs, const UserID & rhs ) const { return qstrcmp( lhs.parent().primaryFingerprint(), rhs.parent().primaryFingerprint() ) == 0 && qstrcmp( lhs.id(), rhs.id() ) == 0 ; } }; } void CertifyCertificateDialog::setSelectedUserIDs( const std::vector & uids ) { const Key key = d->key(); const char * const fpr = key.primaryFingerprint(); const std::vector all = key.userIDs(); std::vector indexes; indexes.reserve( uids.size() ); Q_FOREACH( const UserID & uid, uids ) { kleo_assert( qstrcmp( uid.parent().primaryFingerprint(), fpr ) == 0 ); const unsigned int idx = std::distance( all.begin(), kdtools::find_if( all, boost::bind( UidEqual(), _1, uid ) ) ); if ( idx < all.size() ) indexes.push_back( idx ); } d->selectUserIDsPage->setSelectedUserIDs( indexes ); } std::vector CertifyCertificateDialog::selectedUserIDs() const { return d->selectUserIDsPage->selectedUserIDs(); } void CertifyCertificateDialog::Private::ensureSummaryPageVisible() { while ( q->currentId() != summaryPageId ) q->next(); } #include "moc_certifycertificatedialog.cpp" #include "moc_certifycertificatedialog_p.cpp" diff --git a/kleopatra/dialogs/deletecertificatesdialog.cpp b/kleopatra/dialogs/deletecertificatesdialog.cpp index aa8f3db9e8..c244f6ccfa 100644 --- a/kleopatra/dialogs/deletecertificatesdialog.cpp +++ b/kleopatra/dialogs/deletecertificatesdialog.cpp @@ -1,249 +1,251 @@ /* -*- mode: c++; c-basic-offset:4 -*- dialogs/deletecertificatesdialog.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2009 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "deletecertificatesdialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#ifndef Q_MOC_RUN #include +#endif #include using namespace Kleo; using namespace Kleo::Dialogs; using namespace GpgME; using namespace boost; class DeleteCertificatesDialog::Private { friend class ::Kleo::Dialogs::DeleteCertificatesDialog; DeleteCertificatesDialog * const q; public: explicit Private( DeleteCertificatesDialog * qq ) : q( qq ), ui( q ) { } void slotWhatsThisRequested() { kDebug(); if ( QWidget * const widget = qobject_cast( q->sender() ) ) if ( !widget->whatsThis().isEmpty() ) QWhatsThis::showText( QCursor::pos(), widget->whatsThis() ); } void readConfig() { KConfigGroup dialog( KGlobal::config(), "DeleteCertificatesDialog" ); const QSize size = dialog.readEntry( "Size", QSize(600, 400) ); if ( size.isValid() ) { q->resize( size ); } } void writeConfig() { KConfigGroup dialog( KGlobal::config(), "DeleteCertificatesDialog" ); dialog.writeEntry( "Size", q->size() ); dialog.sync(); } private: struct UI { QLabel selectedLB; KeyTreeView selectedKTV; QLabel unselectedLB; KeyTreeView unselectedKTV; QDialogButtonBox buttonBox; QVBoxLayout vlay; explicit UI( DeleteCertificatesDialog * qq ) : selectedLB( i18n( "These are the certificates you have selected for deletion:" ), qq ), selectedKTV( qq ), unselectedLB( i18n("These certificates will be deleted even though you did not " "explicitly select them (Why?):"), qq ), unselectedKTV( qq ), buttonBox( QDialogButtonBox::Ok|QDialogButtonBox::Cancel ), vlay( qq ) { KDAB_SET_OBJECT_NAME( selectedLB ); KDAB_SET_OBJECT_NAME( selectedKTV ); KDAB_SET_OBJECT_NAME( unselectedLB ); KDAB_SET_OBJECT_NAME( unselectedKTV ); KDAB_SET_OBJECT_NAME( buttonBox ); KDAB_SET_OBJECT_NAME( vlay ); vlay.addWidget( &selectedLB ); vlay.addWidget( &selectedKTV, 1 ); vlay.addWidget( &unselectedLB ); vlay.addWidget( &unselectedKTV, 1 ); vlay.addWidget( &buttonBox ); const QString unselectedWhatsThis = i18nc( "@info:whatsthis", "Why do you want to delete more certificates than I selected?" "When you delete CA certificates (both root CAs and intermediate CAs), " "the certificates issued by them will also be deleted." "This can be nicely seen in Kleopatra's " "hierarchical view mode: In this mode, if you delete a certificate that has " "children, those children will also be deleted. Think of CA certificates as " "folders containing other certificates: When you delete the folder, you " "delete its contents, too." ); unselectedLB.setWhatsThis( unselectedWhatsThis ); unselectedKTV.setWhatsThis( unselectedWhatsThis ); buttonBox.button( QDialogButtonBox::Ok )->setText( i18nc("@action:button","Delete") ); connect( &unselectedLB, SIGNAL(linkActivated(QString)), qq, SLOT(slotWhatsThisRequested()) ); selectedKTV.setFlatModel( AbstractKeyListModel::createFlatKeyListModel( &selectedKTV ) ); unselectedKTV.setFlatModel( AbstractKeyListModel::createFlatKeyListModel( &unselectedKTV ) ); selectedKTV.setHierarchicalView( false ); selectedKTV.view()->setSelectionMode( QAbstractItemView::NoSelection ); unselectedKTV.setHierarchicalView( false ); unselectedKTV.view()->setSelectionMode( QAbstractItemView::NoSelection ); connect( &buttonBox, SIGNAL(accepted()), qq, SLOT(accept()) ); connect( &buttonBox, SIGNAL(rejected()), qq, SLOT(reject()) ); } } ui; }; DeleteCertificatesDialog::DeleteCertificatesDialog( QWidget * p, Qt::WindowFlags f ) : QDialog( p, f ), d( new Private( this ) ) { d->readConfig(); } DeleteCertificatesDialog::~DeleteCertificatesDialog() { d->writeConfig(); } void DeleteCertificatesDialog::setSelectedKeys( const std::vector & keys ) { d->ui.selectedKTV.setKeys( keys ); } void DeleteCertificatesDialog::setUnselectedKeys( const std::vector & keys ) { d->ui.unselectedLB .setVisible( !keys.empty() ); d->ui.unselectedKTV.setVisible( !keys.empty() ); d->ui.unselectedKTV.setKeys( keys ); } std::vector DeleteCertificatesDialog::keys() const { const std::vector sel = d->ui.selectedKTV.keys(); const std::vector uns = d->ui.unselectedKTV.keys(); std::vector result; result.reserve( sel.size() + uns.size() ); result.insert( result.end(), sel.begin(), sel.end() ); result.insert( result.end(), uns.begin(), uns.end() ); return result; } void DeleteCertificatesDialog::accept() { const std::vector sel = d->ui.selectedKTV.keys(); const std::vector uns = d->ui.unselectedKTV.keys(); const uint secret = kdtools::count_if( sel, mem_fn( &Key::hasSecret ) ) + kdtools::count_if( uns, mem_fn( &Key::hasSecret ) ); const uint total = sel.size() + uns.size(); int ret = KMessageBox::Continue; if ( secret ) ret = KMessageBox::warningContinueCancel( this, secret == total ? i18np("The certificate to be deleted is your own. " "It contains private key material, " "which is needed to decrypt past communication " "encrypted to the certificate, and should therefore " "not be deleted.", "All of the certificates to be deleted " "are your own. " "They contain private key material, " "which is needed to decrypt past communication " "encrypted to the certificate, and should therefore " "not be deleted.", secret ) : i18np("One of the certificates to be deleted " "is your own. " "It contains private key material, " "which is needed to decrypt past communication " "encrypted to the certificate, and should therefore " "not be deleted.", "Some of the certificates to be deleted " "are your own. " "They contain private key material, " "which is needed to decrypt past communication " "encrypted to the certificate, and should therefore " "not be deleted.", secret ), i18n("Secret Key Deletion"), KStandardGuiItem::guiItem( KStandardGuiItem::Delete ), KStandardGuiItem::cancel(), QString(), KMessageBox::Notify|KMessageBox::Dangerous ); if ( ret == KMessageBox::Continue ) QDialog::accept(); else QDialog::reject(); } #include "moc_deletecertificatesdialog.cpp" diff --git a/kleopatra/dialogs/lookupcertificatesdialog.cpp b/kleopatra/dialogs/lookupcertificatesdialog.cpp index fb3632a493..52e986c36e 100644 --- a/kleopatra/dialogs/lookupcertificatesdialog.cpp +++ b/kleopatra/dialogs/lookupcertificatesdialog.cpp @@ -1,247 +1,249 @@ /* -*- mode: c++; c-basic-offset:4 -*- dialogs/lookupcertificatesdialog.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2008 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "lookupcertificatesdialog.h" #include "ui_lookupcertificatesdialog.h" #include #include #include #include #include #include #include #include +#ifndef Q_MOC_RUN #include +#endif #include using namespace Kleo; using namespace Kleo::Dialogs; using namespace GpgME; using namespace boost; static const int minimalSearchTextLength = 2; // ### TODO: make that KIOSK-able class LookupCertificatesDialog::Private { friend class ::Kleo::Dialogs::LookupCertificatesDialog; LookupCertificatesDialog * const q; public: explicit Private( LookupCertificatesDialog * qq ); ~Private(); private: void slotSelectionChanged() { enableDisableWidgets(); } void slotSearchTextChanged() { enableDisableWidgets(); } void slotSearchClicked() { emit q->searchTextChanged( ui.findED->text() ); } void slotDetailsClicked() { assert( q->selectedCertificates().size() == 1 ); emit q->detailsRequested( q->selectedCertificates().front() ); } void slotSaveAsClicked() { emit q->saveAsRequested( q->selectedCertificates() ); } void readConfig(); void writeConfig(); void enableDisableWidgets(); QString searchText() const { return ui.findED->text().trimmed(); } QModelIndexList selectedIndexes() const { if ( const QItemSelectionModel * const sm = ui.resultTV->selectionModel() ) return sm->selectedRows(); else return QModelIndexList(); } unsigned int numSelectedCertificates() const { return selectedIndexes().size(); } private: AbstractKeyListModel * model; KeyListSortFilterProxyModel proxy; bool passive; struct Ui : Ui_LookupCertificatesDialog { explicit Ui( LookupCertificatesDialog * q ) : Ui_LookupCertificatesDialog() { setupUi( q ); saveAsPB->hide(); // ### not yet implemented in LookupCertificatesCommand findED->setClearButtonShown( true ); importPB()->setText( i18n("Import") ); importPB()->setEnabled( false ); HeaderView * hv = new HeaderView( Qt::Horizontal ); KDAB_SET_OBJECT_NAME( hv ); resultTV->setHeader( hv ); connect( resultTV, SIGNAL(doubleClicked(QModelIndex)), importPB(), SLOT(animateClick()) ); findED->setFocus(); } QPushButton * importPB() const { return buttonBox->button( QDialogButtonBox::Save ); } QPushButton * closePB() const { return buttonBox->button( QDialogButtonBox::Close ); } } ui; }; LookupCertificatesDialog::Private::Private( LookupCertificatesDialog * qq ) : q( qq ), model( AbstractKeyListModel::createFlatKeyListModel() ), proxy(), passive( false ), ui( q ) { KDAB_SET_OBJECT_NAME( model ); KDAB_SET_OBJECT_NAME( proxy ); proxy.setSourceModel( model ); ui.resultTV->setModel( &proxy ); connect( ui.resultTV->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), q, SLOT(slotSelectionChanged()) ); } LookupCertificatesDialog::Private::~Private() {} void LookupCertificatesDialog::Private::readConfig() { KConfigGroup dialog( KGlobal::config(), "LookupCertificatesDialog" ); const QSize size = dialog.readEntry( "Size", QSize(600, 400) ); if ( size.isValid() ) { q->resize( size ); } const QByteArray headerState = dialog.readEntry( "header", QByteArray()); if (!headerState.isEmpty()) ui.resultTV->header()->restoreState(headerState); } void LookupCertificatesDialog::Private::writeConfig() { KConfigGroup dialog( KGlobal::config(), "LookupCertificatesDialog" ); dialog.writeEntry( "header", ui.resultTV->header()->saveState()); dialog.writeEntry( "Size", q->size() ); dialog.sync(); } LookupCertificatesDialog::LookupCertificatesDialog( QWidget * p, Qt::WindowFlags f ) : QDialog( p, f ), d( new Private( this ) ) { d->ui.findPB->setEnabled(false); d->readConfig(); } LookupCertificatesDialog::~LookupCertificatesDialog() { d->writeConfig(); } void LookupCertificatesDialog::setCertificates( const std::vector & certs ) { d->model->setKeys( certs ); d->ui.resultTV->header()->resizeSections( QHeaderView::ResizeToContents ); d->ui.resultTV->setFocus(); } std::vector LookupCertificatesDialog::selectedCertificates() const { return d->proxy.keys( d->selectedIndexes() ); } void LookupCertificatesDialog::setPassive( bool on ) { if ( d->passive == on ) return; d->passive = on; d->enableDisableWidgets(); } bool LookupCertificatesDialog::isPassive() const { return d->passive; } void LookupCertificatesDialog::setSearchText( const QString &text ) { d->ui.findED->setText( text ); } QString LookupCertificatesDialog::searchText() const { return d->ui.findED->text(); } void LookupCertificatesDialog::accept() { assert( !d->selectedIndexes().empty() ); emit importRequested( selectedCertificates() ); QDialog::accept(); } void LookupCertificatesDialog::Private::enableDisableWidgets() { // enable/disable everything except 'close', based on passive: Q_FOREACH( QObject * const o, q->children() ) if ( QWidget * const w = qobject_cast( o ) ) w->setDisabled( passive && w != ui.closePB() && w != ui.buttonBox ); if ( passive ) return; ui.findPB->setEnabled( searchText().length() > minimalSearchTextLength ); const unsigned int n = numSelectedCertificates(); ui.detailsPB->setEnabled( n == 1 ); ui.saveAsPB->setEnabled( n == 1 ); ui.importPB()->setEnabled( n != 0 ); ui.importPB()->setDefault( false ); // otherwise Import becomes default button if enabled and return triggers both a search and accept() } #include "moc_lookupcertificatesdialog.cpp" diff --git a/kleopatra/dialogs/selftestdialog.cpp b/kleopatra/dialogs/selftestdialog.cpp index 44a8119ad6..a516895b57 100644 --- a/kleopatra/dialogs/selftestdialog.cpp +++ b/kleopatra/dialogs/selftestdialog.cpp @@ -1,344 +1,346 @@ /* -*- mode: c++; c-basic-offset:4 -*- dialogs/selftestdialog.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2008 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "selftestdialog.h" #include "ui_selftestdialog.h" #include #include #include #include #include +#ifndef Q_MOC_RUN #include +#endif #include #include using namespace Kleo; using namespace Kleo::Dialogs; using namespace boost; namespace { class Model : public QAbstractTableModel { Q_OBJECT public: explicit Model( QObject * parent=0 ) : QAbstractTableModel( parent ), m_tests() { } enum Column { TestName, TestResult, NumColumns }; const shared_ptr & fromModelIndex( const QModelIndex & idx ) const { const unsigned int row = idx.row(); if ( row < m_tests.size() ) return m_tests[row]; static const shared_ptr null; return null; } /* reimp */ int rowCount( const QModelIndex & idx ) const { return idx.isValid() ? 0 : m_tests.size() ; } /* reimp */ int columnCount( const QModelIndex & ) const { return NumColumns; } /* reimp */ QVariant data( const QModelIndex & idx, int role ) const { const unsigned int row = idx.row(); if ( idx.isValid() && row < m_tests.size() ) switch ( role ) { case Qt::DisplayRole: case Qt::ToolTipRole: switch ( idx.column() ) { case TestName: return m_tests[row]->name(); case TestResult: return m_tests[row]->skipped() ? i18n("Skipped") : m_tests[row]->passed() ? i18n("Passed") : /* else */ m_tests[row]->shortError(); } break; case Qt::BackgroundRole: return QColor( m_tests[row]->skipped() ? Qt::yellow : m_tests[row]->passed() ? Qt::green : Qt::red ); } return QVariant(); } /* reimp */ QVariant headerData( int section, Qt::Orientation o, int role ) const { if ( o == Qt::Horizontal && section >= 0 && section < NumColumns && role == Qt::DisplayRole ) switch ( section ) { case TestName: return i18n("Test Name"); case TestResult: return i18n("Result"); } return QVariant(); } void clear() { if ( m_tests.empty() ) return; beginRemoveRows( QModelIndex(), 0, m_tests.size() - 1 ); m_tests.clear(); endRemoveRows(); } void append( const std::vector< shared_ptr > & tests ) { if ( tests.empty() ) return; beginInsertRows( QModelIndex(), m_tests.size(), m_tests.size() + tests.size() ); m_tests.insert( m_tests.end(), tests.begin(), tests.end() ); endInsertRows(); } void reloadData() { if ( !m_tests.empty() ) emit dataChanged( index( 0, 0 ), index( m_tests.size() - 1, NumColumns - 1 ) ); } const shared_ptr & at( unsigned int idx ) const { return m_tests.at( idx ); } private: std::vector< shared_ptr > m_tests; }; class Proxy : public QSortFilterProxyModel { Q_OBJECT public: explicit Proxy( QObject * parent=0 ) : QSortFilterProxyModel( parent ), m_showAll( false ) { setDynamicSortFilter( true ); } bool showAll() const { return m_showAll; } Q_SIGNALS: void showAllChanged( bool ); public Q_SLOTS: void setShowAll( bool on ) { if ( on == m_showAll ) return; m_showAll = on; invalidateFilter(); emit showAllChanged( on ); } private: /* reimp */ bool filterAcceptsRow( int src_row, const QModelIndex & src_parent ) const { if ( m_showAll ) { return true; } if ( const Model * const model = qobject_cast( sourceModel() ) ) { if ( !src_parent.isValid() && src_row >= 0 && src_row < model->rowCount( src_parent ) ) { if ( const shared_ptr & t = model->at( src_row ) ) { return !t->passed() ; } else { kWarning() << "NULL test??"; } } else { if ( src_parent.isValid() ) { kWarning() << "view asks for subitems!"; } else { kWarning() << "index " << src_row << " is out of range [" << 0 << "," << model->rowCount( src_parent ) << "]"; } } } else { kWarning() << "expected a ::Model, got "; if ( !sourceModel() ) { kWarning() << "a null pointer"; } else { kWarning() << sourceModel()->metaObject()->className(); } } return false; } private: bool m_showAll; }; } class SelfTestDialog::Private { friend class ::Kleo::Dialogs::SelfTestDialog; SelfTestDialog * const q; public: explicit Private( SelfTestDialog * qq ) : q( qq ), model( q ), proxy( q ), ui( q ) { proxy.setSourceModel( &model ); ui.resultsTV->setModel( &proxy ); ui.detailsGB->hide(); ui.proposedCorrectiveActionGB->hide(); connect( ui.resultsTV->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), q, SLOT(slotSelectionChanged()) ); connect( ui.showAllCB, SIGNAL(toggled(bool)), &proxy, SLOT(setShowAll(bool)) ); } private: void slotSelectionChanged() { const int row = selectedRowIndex(); if ( row < 0 ) { ui.detailsLB->setText( i18n("(select test first)") ); ui.detailsGB->hide(); ui.proposedCorrectiveActionGB->hide(); } else { const shared_ptr & t = model.at( row ); ui.detailsLB->setText( t->longError() ); ui.detailsGB->setVisible( !t->passed() ); const QString action = t->proposedFix(); ui.proposedCorrectiveActionGB->setVisible( !t->passed() && !action.isEmpty() ); ui.proposedCorrectiveActionLB->setText( action ); ui.doItPB->setVisible( !t->passed() && t->canFixAutomatically() ); } } void slotDoItClicked() { if ( const shared_ptr st = model.fromModelIndex( selectedRow() ) ) if ( st->fix() ) model.reloadData(); } private: void updateColumnSizes() { ui.resultsTV->header()->resizeSections( QHeaderView::ResizeToContents ); } private: QModelIndex selectedRow() const { const QItemSelectionModel * const ism = ui.resultsTV->selectionModel(); if ( !ism ) return QModelIndex(); const QModelIndexList mil = ism->selectedRows(); return mil.empty() ? QModelIndex() : proxy.mapToSource( mil.front() ) ; } int selectedRowIndex() const { return selectedRow().row(); } private: Model model; Proxy proxy; struct UI : public Ui_SelfTestDialog { QPushButton * rerunPB; explicit UI( SelfTestDialog * qq ) : Ui_SelfTestDialog(), rerunPB( new QPushButton( i18n("Rerun Tests") ) ) { setupUi( qq ); buttonBox->addButton( rerunPB, QDialogButtonBox::ActionRole ); buttonBox->button( QDialogButtonBox::Ok )->setText( i18n("Continue") ); connect( rerunPB, SIGNAL(clicked()), qq, SIGNAL(updateRequested()) ); } } ui; }; SelfTestDialog::SelfTestDialog( QWidget * p, Qt::WindowFlags f ) : QDialog( p, f ), d( new Private( this ) ) { setAutomaticMode( false ); } SelfTestDialog::SelfTestDialog( const std::vector< shared_ptr > & tests, QWidget * p, Qt::WindowFlags f ) : QDialog( p, f ), d( new Private( this ) ) { addSelfTests( tests ); setAutomaticMode( false ); } SelfTestDialog::~SelfTestDialog() {} void SelfTestDialog::clear() { d->model.clear(); } void SelfTestDialog::addSelfTest( const shared_ptr & test ) { d->model.append( std::vector< shared_ptr >( 1, test ) ); d->updateColumnSizes(); } void SelfTestDialog::addSelfTests( const std::vector< shared_ptr > & tests ) { d->model.append( tests ); d->updateColumnSizes(); } void SelfTestDialog::setRunAtStartUp( bool on ) { d->ui.runAtStartUpCB->setChecked( on ); } bool SelfTestDialog::runAtStartUp() const { return d->ui.runAtStartUpCB->isChecked(); } void SelfTestDialog::setAutomaticMode( bool automatic ) { d->ui.buttonBox->button( QDialogButtonBox::Ok )->setVisible( automatic ); d->ui.buttonBox->button( QDialogButtonBox::Cancel )->setVisible( automatic ); d->ui.buttonBox->button( QDialogButtonBox::Close )->setVisible( !automatic ); } #include "selftestdialog.moc" #include "moc_selftestdialog.cpp" diff --git a/kleopatra/dialogs/setinitialpindialog.cpp b/kleopatra/dialogs/setinitialpindialog.cpp index cac9c08523..c64cca6529 100644 --- a/kleopatra/dialogs/setinitialpindialog.cpp +++ b/kleopatra/dialogs/setinitialpindialog.cpp @@ -1,209 +1,211 @@ /* -*- mode: c++; c-basic-offset:4 -*- dialogs/setinitialpindialog.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2009 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "setinitialpindialog.h" #include "ui_setinitialpindialog.h" #include #include #include // for Qt::escape #include +#ifndef Q_MOC_RUN #include +#endif #include using namespace Kleo; using namespace Kleo::Dialogs; using namespace GpgME; enum State { Unknown = 0, NotSet, AlreadySet, Ongoing, Ok, Failed, NumStates }; const char * icons[] = { // PENDING(marc) use better icons, once available "", // Unknown "", // NotSet "security-medium", // AlreadySet "movie-process-working-kde", // Ongoing "security-high", // Ok "security-low", // Failed }; BOOST_STATIC_ASSERT(( sizeof icons / sizeof (*icons) == NumStates )); BOOST_STATIC_ASSERT(( sizeof("movie-") == 7 )); static void update_widget( State state, bool delay, QLabel * resultLB, QLabel * lb, QPushButton * pb, QLabel * statusLB ) { assert( state >= 0 ); assert( state < NumStates ); const char * icon = icons[state]; if ( qstrncmp( icon, "movie-", sizeof("movie-")-1 ) == 0 ) resultLB->setMovie( KIconLoader::global()->loadMovie( QLatin1String(icon+sizeof("movie-")), KIconLoader::NoGroup ) ); else if ( icon && *icon ) resultLB->setPixmap( KIcon( QLatin1String(icon) ).pixmap( 32 ) ); else resultLB->setPixmap( QPixmap() ); lb->setEnabled( ( state == NotSet || state == Failed ) && !delay ); pb->setEnabled( ( state == NotSet || state == Failed ) && !delay ); if ( state == AlreadySet ) statusLB->setText( i18nc("@info","No NullPin found. If this PIN was not set by you personally, the card might have been tampered with.") ); } static QString format_error( const Error & err ) { if ( err.isCanceled() ) return i18nc("@info","Canceled setting PIN."); if ( err ) return i18nc("@info", "There was an error setting the PIN: %1.", Qt::escape( QString::fromLocal8Bit( err.asString() ) ) ); else return i18nc("@info","PIN set successfully."); } class SetInitialPinDialog::Private { friend class ::Kleo::Dialogs::SetInitialPinDialog; SetInitialPinDialog * const q; public: explicit Private( SetInitialPinDialog * qq ) : q( qq ), nksState( Unknown ), sigGState( Unknown ), ui( q ) { } private: void slotNksButtonClicked() { nksState = Ongoing; ui.nksStatusLB->clear(); updateWidgets(); emit q->nksPinRequested(); } void slotSigGButtonClicked() { sigGState = Ongoing; ui.sigGStatusLB->clear(); updateWidgets(); emit q->sigGPinRequested(); } private: void updateWidgets() { update_widget( nksState, false, ui.nksResultIcon, ui.nksLB, ui.nksPB, ui.nksStatusLB ); update_widget( sigGState, nksState == NotSet || nksState == Failed || nksState == Ongoing, ui.sigGResultIcon, ui.sigGLB, ui.sigGPB, ui.sigGStatusLB ); ui.closePB()->setEnabled( q->isComplete() ); ui.cancelPB()->setEnabled( !q->isComplete() ); } private: State nksState, sigGState; struct UI : public Ui::SetInitialPinDialog { explicit UI( Dialogs::SetInitialPinDialog * qq ) : Ui::SetInitialPinDialog() { setupUi( qq ); closePB()->setEnabled( false ); connect( closePB(), SIGNAL(clicked()), qq, SLOT(accept()) ); } QAbstractButton * closePB() const { assert( dialogButtonBox ); return dialogButtonBox->button( QDialogButtonBox::Close ); } QAbstractButton * cancelPB() const { assert( dialogButtonBox ); return dialogButtonBox->button( QDialogButtonBox::Cancel ); } } ui; }; SetInitialPinDialog::SetInitialPinDialog( QWidget * p, Qt::WindowFlags f ) : QDialog( p, f ), d( new Private( this ) ) { } SetInitialPinDialog::~SetInitialPinDialog() {} void SetInitialPinDialog::setNksPinPresent( bool on ) { d->nksState = on ? AlreadySet : NotSet ; d->updateWidgets(); } void SetInitialPinDialog::setSigGPinPresent( bool on ) { d->sigGState = on ? AlreadySet : NotSet ; d->updateWidgets(); } void SetInitialPinDialog::setNksPinSettingResult( const Error & err ) { d->ui.nksStatusLB->setText( format_error( err ) ); d->nksState = err.isCanceled() ? NotSet : err ? Failed : Ok ; d->updateWidgets(); } void SetInitialPinDialog::setSigGPinSettingResult( const Error & err ) { d->ui.sigGStatusLB->setText( format_error( err ) ); d->sigGState = err.isCanceled() ? NotSet : err ? Failed : Ok ; d->updateWidgets(); } bool SetInitialPinDialog::isComplete() const { return ( d->nksState == Ok || d->nksState == AlreadySet ) && ( d->sigGState == Ok || d->sigGState == AlreadySet ); } #include "moc_setinitialpindialog.cpp" diff --git a/kleopatra/kleopatraapplication.cpp b/kleopatra/kleopatraapplication.cpp index 06e9882207..b48e23b5c7 100644 --- a/kleopatra/kleopatraapplication.cpp +++ b/kleopatra/kleopatraapplication.cpp @@ -1,534 +1,536 @@ /* kleopatraapplication.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2008 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "kleopatraapplication.h" #include "mainwindow.h" #include "systrayicon.h" #include #include #include #include #include #include #include #include #include #ifdef HAVE_USABLE_ASSUAN # include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#ifndef Q_MOC_RUN #include #include #include #include +#endif #include using namespace Kleo; using namespace Kleo::Commands; using namespace boost; static void add_resources() { KGlobal::locale()->insertCatalog( QLatin1String("libkleopatra") ); KIconLoader::global()->addAppDir( QLatin1String("libkleopatra") ); KIconLoader::global()->addAppDir( QLatin1String("kwatchgnupg") ); KIconLoader::global()->addAppDir( QLatin1String("kdepim") ); } static const struct { const char * option; const char * description; char short_option[4]; } kleo_options[] = { { "daemon", I18N_NOOP("Run UI server only, hide main window"), "" }, { "openpgp", I18N_NOOP("Use OpenPGP for the following operation"), "p" }, { "cms", I18N_NOOP("Use CMS (X.509, S/MIME) for the following operation"), "c" }, { "import-certificate", I18N_NOOP("Import certificate file(s)"), "i" }, { "encrypt", I18N_NOOP("Encrypt file(s)"), "e" }, { "sign", I18N_NOOP("Sign file(s)"), "s" }, { "sign-encrypt", I18N_NOOP("Sign and/or encrypt file(s)"), "E" }, { "encrypt-sign", I18N_NOOP("Same as --sign-encrypt, do not use"), "" }, { "decrypt", I18N_NOOP("Decrypt file(s)"), "d" }, { "verify", I18N_NOOP("Verify file/signature"), "V" }, { "decrypt-verify", I18N_NOOP("Decrypt and/or verify file(s)"), "D" }, { "query ",I18N_NOOP("Search for Certificate by fingerprint"), "q" }, { "parent-windowid ", I18N_NOOP("Parent Window Id for dialogs"), "" }, //{ "show-certificate", I18N_NOOP("Show Certificate(s) by fingerprint(s)"), "" }, }; static KCmdLineOptions make_kleopatra_args() { KCmdLineOptions options; #ifdef HAVE_USABLE_ASSUAN options.add("uiserver-socket ", ki18n("Location of the socket the ui server is listening on" )); #endif for ( unsigned int i = 0 ; i < sizeof kleo_options / sizeof *kleo_options ; ++i ) { if ( *kleo_options[i].short_option ) options.add( kleo_options[i].short_option ); options.add( kleo_options[i].option, ki18n( kleo_options[i].description ) ); } options.add("+[File]", ki18n("File(s) to process")); return options; } // static KCmdLineOptions KleopatraApplication::commandLineOptions() { static KCmdLineOptions options = make_kleopatra_args(); return options; } static QList default_logging_options() { QList result; result.push_back( "io" ); return result; } class KleopatraApplication::Private { friend class ::KleopatraApplication; KleopatraApplication * const q; public: explicit Private( KleopatraApplication * qq ) : q( qq ), ignoreNewInstance( true ), firstNewInstance( true ) { KDAB_SET_OBJECT_NAME( readerStatus ); #ifndef QT_NO_SYSTEMTRAYICON KDAB_SET_OBJECT_NAME( sysTray ); sysTray.setAnyCardHasNullPin( readerStatus.anyCardHasNullPin() ); sysTray.setAnyCardCanLearnKeys( readerStatus.anyCardCanLearnKeys() ); connect( &readerStatus, SIGNAL(anyCardHasNullPinChanged(bool)), &sysTray, SLOT(setAnyCardHasNullPin(bool)) ); connect( &readerStatus, SIGNAL(anyCardCanLearnKeysChanged(bool)), &sysTray, SLOT(setAnyCardCanLearnKeys(bool)) ); #endif } private: void connectConfigureDialog() { if ( configureDialog && q->mainWindow() ) connect( configureDialog, SIGNAL(configCommitted()), q->mainWindow(), SLOT(slotConfigCommitted()) ); } void disconnectConfigureDialog() { if ( configureDialog && q->mainWindow() ) disconnect( configureDialog, SIGNAL(configCommitted()), q->mainWindow(), SLOT(slotConfigCommitted()) ); } public: bool ignoreNewInstance; bool firstNewInstance; QPointer configureDialog; QPointer mainWindow; SmartCard::ReaderStatus readerStatus; #ifndef QT_NO_SYSTEMTRAYICON SysTrayIcon sysTray; #endif shared_ptr keyCache; shared_ptr log; shared_ptr watcher; public: void setupKeyCache() { keyCache = KeyCache::mutableInstance(); watcher.reset( new FileSystemWatcher ); watcher->blacklistFiles( gnupgFileBlacklist() ); watcher->addPath( gnupgHomeDirectory() ); watcher->setDelay( 1000 ); keyCache->addFileSystemWatcher( watcher ); } void setupLogging() { log = Log::mutableInstance(); const QByteArray envOptions = qgetenv( "KLEOPATRA_LOGOPTIONS" ); const bool logAll = envOptions.trimmed() == "all"; const QList options = envOptions.isEmpty() ? default_logging_options() : envOptions.split( ',' ) ; const QByteArray dirNative = qgetenv( "KLEOPATRA_LOGDIR" ); if ( dirNative.isEmpty() ) return; const QString dir = QFile::decodeName( dirNative ); const QString logFileName = QDir( dir ).absoluteFilePath( QString::fromLatin1( "kleopatra.log.%1" ).arg( mygetpid() ) ); std::auto_ptr logFile( new QFile( logFileName ) ); if ( !logFile->open( QIODevice::WriteOnly | QIODevice::Append ) ) { kDebug() << "Could not open file for logging: " << logFileName << "\nLogging disabled"; return; } log->setOutputDirectory( dir ); if ( logAll || options.contains( "io" ) ) log->setIOLoggingEnabled( true ); qInstallMsgHandler( Log::messageHandler ); #ifdef HAVE_USABLE_ASSUAN if ( logAll || options.contains( "pipeio" ) ) KDPipeIODevice::setDebugLevel( KDPipeIODevice::Debug ); UiServer::setLogStream( log->logFile() ); #endif } }; KleopatraApplication::KleopatraApplication() : KUniqueApplication(), d( new Private( this ) ) { add_resources(); d->setupKeyCache(); d->setupLogging(); #ifndef QT_NO_SYSTEMTRAYICON d->sysTray.show(); #endif setQuitOnLastWindowClosed( false ); KWindowSystem::allowExternalProcessWindowActivation(); } KleopatraApplication::~KleopatraApplication() { // work around kdelibs bug https://bugs.kde.org/show_bug.cgi?id=162514 KGlobal::config()->sync(); } static QStringList files_from_args( const shared_ptr & args ) { QStringList result; for ( int i = 0, end = args->count() ; i < end ; ++i ) { const KUrl url = args->url(i); if ( url.protocol() == QLatin1String("file") ) result.push_back( url.toLocalFile() ); } return result; } namespace { typedef void (KleopatraApplication::*Func)( const QStringList &, GpgME::Protocol ); struct _Funcs { const char * opt; Func func; }; } int KleopatraApplication::newInstance() { kDebug() << "ignoreNewInstance =" << d->ignoreNewInstance; if ( d->ignoreNewInstance ) return 0; const shared_ptr args( KCmdLineArgs::parsedArgs(), mem_fn( &KCmdLineArgs::clear ) ); const QStringList files = files_from_args( args ); const bool openpgp = args->isSet( "openpgp" ); const bool cms = args->isSet( "cms" ); kDebug( openpgp ) << "found OpenPGP"; kDebug( cms ) << "found CMS"; if ( openpgp && cms ) { kDebug() << "ambigious protocol: --openpgp and --cms"; return 1; } // Check for --query command if ( args->isSet( "query" ) ) { const QString fingerPrint = args->getOption( "query" ); if ( fingerPrint.isEmpty() ) { kDebug() << "no fingerprint specified: --query"; return 1; } // Check for Parent Window id WId parentId = 0; if ( args->isSet( "parent-windowid" ) ) { #ifdef Q_OS_WIN //krazy:exclude=cpp parentId = reinterpret_cast(args->getOption( "parent-windowid" ).toULong()); #else parentId = static_cast(args->getOption( "parent-windowid" ).toULong()); #endif } // Search for local keys const GpgME::Key &key = Kleo::KeyCache::instance()->findByKeyIDOrFingerprint( fingerPrint.toLocal8Bit().data() ); if ( key.isNull() ) { // Show external search dialog LookupCertificatesCommand * const cmd = new LookupCertificatesCommand( fingerPrint, 0 ); if ( parentId != 0 ) { cmd->setParentWId( parentId ); }; cmd->start(); return 0; } else { // show local detail DetailsCommand * const cmd = new DetailsCommand( key, 0 ); if ( parentId != 0 ) { cmd->setParentWId( parentId ); }; cmd->start(); return 0; } } static const _Funcs funcs[] = { #ifndef QT_NO_SYSTEMTRAYICON { "import-certificate", &KleopatraApplication::importCertificatesFromFile }, #endif { "encrypt", &KleopatraApplication::encryptFiles }, { "sign", &KleopatraApplication::signFiles }, { "encrypt-sign", &KleopatraApplication::signEncryptFiles }, { "sign-encrypt", &KleopatraApplication::signEncryptFiles }, { "decrypt", &KleopatraApplication::decryptFiles }, { "verify", &KleopatraApplication::verifyFiles }, { "decrypt-verify", &KleopatraApplication::decryptVerifyFiles }, }; const _Funcs * const it1 = std::find_if( begin( funcs ), end( funcs ), boost::bind( &KCmdLineArgs::isSet, args, boost::bind( &_Funcs::opt, _1 ) ) ); if ( const Func func = it1 == end( funcs ) ? 0 : it1->func ) { const _Funcs * it2 = std::find_if( it1+1, end( funcs ), boost::bind( &KCmdLineArgs::isSet, args, boost::bind( &_Funcs::opt, _1 ) ) ); if ( it2 != end( funcs ) ) { kDebug() << "ambiguous command" << it1->opt << "vs." << it2->opt; return 1; } if ( files.empty() ) { kDebug() << it1->opt << "without arguments"; return 1; } kDebug() << "found" << it1->opt; (this->*func)( files, openpgp ? GpgME::OpenPGP : cms ? GpgME::CMS : GpgME::UnknownProtocol ); } else { if ( files.empty() ) { if ( ! ( d->firstNewInstance && isSessionRestored() ) ) { kDebug() << "openOrRaiseMainWindow"; openOrRaiseMainWindow(); } } else { kDebug() << "files without command"; // possible? return 1; } } return 0; } #ifndef QT_NO_SYSTEMTRAYICON const SysTrayIcon * KleopatraApplication::sysTrayIcon() const { return &d->sysTray; } SysTrayIcon * KleopatraApplication::sysTrayIcon() { return &d->sysTray; } #endif const MainWindow * KleopatraApplication::mainWindow() const { return d->mainWindow; } MainWindow * KleopatraApplication::mainWindow() { return d->mainWindow; } void KleopatraApplication::setMainWindow( MainWindow * mainWindow ) { if ( mainWindow == d->mainWindow ) return; d->disconnectConfigureDialog(); d->mainWindow = mainWindow; #ifndef QT_NO_SYSTEMTRAYICON d->sysTray.setMainWindow( mainWindow ); #endif d->connectConfigureDialog(); } static void open_or_raise( QWidget * w ) { if ( w->isMinimized() ) { KWindowSystem::unminimizeWindow( w->winId()); w->raise(); } else if ( w->isVisible() ) { w->raise(); } else { w->show(); } } void KleopatraApplication::toggleMainWindowVisibility() { if ( mainWindow() ) { mainWindow()->setVisible( !mainWindow()->isVisible() ); } else { openOrRaiseMainWindow(); } } void KleopatraApplication::restoreMainWindow() { kDebug() << "restoring main window"; // Sanity checks if ( !isSessionRestored() ) { kDebug() << "Not in session restore"; return; } if ( mainWindow() ) { kDebug() << "Already have main window"; return; } MainWindow * mw = new MainWindow; if ( KMainWindow::canBeRestored( 1 ) ) { // restore to hidden state, Mainwindow::readProperties() will // restore saved visibility. mw->restore( 1, false ); } mw->setAttribute( Qt::WA_DeleteOnClose ); setMainWindow( mw ); d->connectConfigureDialog(); } void KleopatraApplication::openOrRaiseMainWindow() { MainWindow * mw = mainWindow(); if ( !mw ) { mw = new MainWindow; mw->setAttribute( Qt::WA_DeleteOnClose ); setMainWindow( mw ); d->connectConfigureDialog(); } open_or_raise( mw ); } void KleopatraApplication::openOrRaiseConfigDialog() { if ( !d->configureDialog ) { d->configureDialog = new ConfigureDialog; d->configureDialog->setAttribute( Qt::WA_DeleteOnClose ); d->connectConfigureDialog(); } open_or_raise( d->configureDialog ); } #ifndef QT_NO_SYSTEMTRAYICON void KleopatraApplication::startMonitoringSmartCard() { d->readerStatus.startMonitoring(); } void KleopatraApplication::importCertificatesFromFile( const QStringList & files, GpgME::Protocol /*proto*/) { openOrRaiseMainWindow(); if ( !files.empty() ) d->sysTray.mainWindow()->importCertificatesFromFile( files ); } #endif // QT_NO_SYSTEMTRAYICON void KleopatraApplication::encryptFiles( const QStringList & files, GpgME::Protocol proto ) { SignEncryptFilesCommand * const cmd = new SignEncryptFilesCommand( files, 0 ); cmd->setEncryptionPolicy( Force ); cmd->setSigningPolicy( Allow ); if ( proto != GpgME::UnknownProtocol ) cmd->setProtocol( proto ); cmd->start(); } void KleopatraApplication::signFiles( const QStringList & files, GpgME::Protocol proto ) { SignEncryptFilesCommand * const cmd = new SignEncryptFilesCommand( files, 0 ); cmd->setSigningPolicy( Force ); cmd->setEncryptionPolicy( Deny ); if ( proto != GpgME::UnknownProtocol ) cmd->setProtocol( proto ); cmd->start(); } void KleopatraApplication::signEncryptFiles( const QStringList & files, GpgME::Protocol proto ) { SignEncryptFilesCommand * const cmd = new SignEncryptFilesCommand( files, 0 ); if ( proto != GpgME::UnknownProtocol ) cmd->setProtocol( proto ); cmd->start(); } void KleopatraApplication::decryptFiles( const QStringList & files, GpgME::Protocol /*proto*/ ) { DecryptVerifyFilesCommand * const cmd = new DecryptVerifyFilesCommand( files, 0 ); cmd->setOperation( Decrypt ); cmd->start(); } void KleopatraApplication::verifyFiles( const QStringList & files, GpgME::Protocol /*proto*/ ) { DecryptVerifyFilesCommand * const cmd = new DecryptVerifyFilesCommand( files, 0 ); cmd->setOperation( Verify ); cmd->start(); } void KleopatraApplication::decryptVerifyFiles( const QStringList & files, GpgME::Protocol /*proto*/ ) { DecryptVerifyFilesCommand * const cmd = new DecryptVerifyFilesCommand( files, 0 ); cmd->start(); } void KleopatraApplication::setIgnoreNewInstance( bool ignore ) { d->ignoreNewInstance = ignore; } void KleopatraApplication::setFirstNewInstance( bool on ) { d->firstNewInstance = on; } bool KleopatraApplication::ignoreNewInstance() const { return d->ignoreNewInstance; } diff --git a/kleopatra/libkleopatraclient/core/command.cpp b/kleopatra/libkleopatraclient/core/command.cpp index c32de6d49b..af3adf08ce 100644 --- a/kleopatra/libkleopatraclient/core/command.cpp +++ b/kleopatra/libkleopatraclient/core/command.cpp @@ -1,652 +1,654 @@ /* -*- mode: c++; c-basic-offset:4 -*- command.cpp This file is part of KleopatraClient, the Kleopatra interface library Copyright (c) 2008 Klarälvdalens Datakonsult AB KleopatraClient is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. KleopatraClient 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "command.h" #include "command_p.h" #include // Q_OS_WIN #ifdef Q_OS_WIN // HACK: AllowSetForegroundWindow needs _WIN32_WINDOWS >= 0x0490 set # ifndef _WIN32_WINDOWS # define _WIN32_WINDOWS 0x0500 # define _WIN32_WINNT 0x0500 // good enough for Vista too # endif # include # include #endif #include #include #include #include #include #include #include +#ifndef Q_MOC_RUN #include #include +#endif #include #include #include using namespace KLEOPATRACLIENT_NAMESPACE; using namespace boost; // copied from kleopatra/utils/hex.cpp static std::string hexencode( const std::string & in ) { std::string result; result.reserve( 3 * in.size() ); static const char hex[] = "0123456789ABCDEF"; for ( std::string::const_iterator it = in.begin(), end = in.end() ; it != end ; ++it ) switch ( const unsigned char ch = *it ) { default: if ( ( ch >= '!' && ch <= '~' ) || ch > 0xA0 ) { result += ch; break; } // else fall through case ' ': result += '+'; break; case '"': case '#': case '$': case '%': case '\'': case '+': case '=': result += '%'; result += hex[ (ch & 0xF0) >> 4 ]; result += hex[ (ch & 0x0F) ]; break; } return result; } #ifdef UNUSED static std::string hexencode( const char * in ) { if ( !in ) return std::string(); return hexencode( std::string( in ) ); } #endif // changed from returning QByteArray to returning std::string static std::string hexencode( const QByteArray & in ) { if ( in.isNull() ) return std::string(); return hexencode( std::string( in.data(), in.size() ) ); } // end copied from kleopatra/utils/hex.cpp Command::Command( QObject * p ) : QObject( p ), d( new Private( this ) ) { d->init(); } Command::Command( Private * pp, QObject * p ) : QObject( p ), d( pp ) { d->init(); } Command::~Command() { delete d; d = 0; } void Command::Private::init() { connect( this, SIGNAL(started()), q, SIGNAL(started()) ); connect( this, SIGNAL(finished()), q, SIGNAL(finished()) ); } void Command::setParentWId( WId wid ) { const QMutexLocker locker( &d->mutex ); d->inputs.parentWId = wid; } WId Command::parentWId() const { const QMutexLocker locker( &d->mutex ); return d->inputs.parentWId; } void Command::setServerLocation( const QString & location ) { const QMutexLocker locker( &d->mutex ); d->outputs.serverLocation = location; } QString Command::serverLocation() const { const QMutexLocker locker( &d->mutex ); return d->outputs.serverLocation; } bool Command::waitForFinished() { return d->wait(); } bool Command::waitForFinished( unsigned long ms ) { return d->wait( ms ); } bool Command::error() const { const QMutexLocker locker( &d->mutex ); return !d->outputs.errorString.isEmpty(); } bool Command::wasCanceled() const { const QMutexLocker locker( &d->mutex ); return d->outputs.canceled; } QString Command::errorString() const { const QMutexLocker locker( &d->mutex ); return d->outputs.errorString; } qint64 Command::serverPid() const { const QMutexLocker locker( &d->mutex ); return d->outputs.serverPid; } void Command::start() { d->start(); } void Command::cancel() { qDebug( "Sorry, not implemented: KleopatraClient::Command::Cancel" ); } void Command::setOptionValue( const char * name, const QVariant & value, bool critical ) { if ( !name || !*name ) return; const Private::Option opt = { value, true, critical }; const QMutexLocker locker( &d->mutex ); d->inputs.options[name] = opt; } QVariant Command::optionValue( const char * name ) const { if ( !name || !*name ) return QVariant(); const QMutexLocker locker( &d->mutex ); const std::map::const_iterator it = d->inputs.options.find( name ); if ( it == d->inputs.options.end() ) return QVariant(); else return it->second.value; } void Command::setOption( const char * name, bool critical ) { if ( !name || !*name ) return; const QMutexLocker locker( &d->mutex ); if ( isOptionSet( name ) ) unsetOption( name ); const Private::Option opt = { QVariant(), false, critical }; d->inputs.options[name] = opt; } void Command::unsetOption( const char * name ) { if ( !name || !*name ) return; const QMutexLocker locker( &d->mutex ); d->inputs.options.erase( name ); } bool Command::isOptionSet( const char * name ) const { if ( !name || !*name ) return false; const QMutexLocker locker( &d->mutex ); return d->inputs.options.count( name ); } bool Command::isOptionCritical( const char * name ) const { if ( !name || !*name ) return false; const QMutexLocker locker( &d->mutex ); const std::map::const_iterator it = d->inputs.options.find( name ); return it != d->inputs.options.end() && it->second.isCritical; } void Command::setFilePaths( const QStringList & filePaths ) { const QMutexLocker locker( &d->mutex ); d->inputs.filePaths = filePaths; } QStringList Command::filePaths() const { const QMutexLocker locker( &d->mutex ); return d->inputs.filePaths; } void Command::setRecipients( const QStringList & recipients, bool informative ) { const QMutexLocker locker( &d->mutex ); d->inputs.recipients = recipients; d->inputs.areRecipientsInformative = informative; } QStringList Command::recipients() const { const QMutexLocker locker( &d->mutex ); return d->inputs.recipients; } bool Command::areRecipientsInformative() const { const QMutexLocker locker( &d->mutex ); return d->inputs.areRecipientsInformative; } void Command::setSenders( const QStringList & senders, bool informative ) { const QMutexLocker locker( &d->mutex ); d->inputs.senders = senders; d->inputs.areSendersInformative = informative; } QStringList Command::senders() const { const QMutexLocker locker( &d->mutex ); return d->inputs.senders; } bool Command::areSendersInformative() const { const QMutexLocker locker( &d->mutex ); return d->inputs.areSendersInformative; } void Command::setInquireData( const char * what, const QByteArray & data ) { const QMutexLocker locker( &d->mutex ); d->inputs.inquireData[what] = data; } void Command::unsetInquireData( const char * what ) { const QMutexLocker locker( &d->mutex ); d->inputs.inquireData.erase( what ); } QByteArray Command::inquireData( const char * what ) const { const QMutexLocker locker( &d->mutex ); const std::map::const_iterator it = d->inputs.inquireData.find( what ); if ( it == d->inputs.inquireData.end() ) return QByteArray(); else return it->second; } bool Command::isInquireDataSet( const char * what ) const { const QMutexLocker locker( &d->mutex ); const std::map::const_iterator it = d->inputs.inquireData.find( what ); return it != d->inputs.inquireData.end(); } QByteArray Command::receivedData() const { const QMutexLocker locker( &d->mutex ); return d->outputs.data; } void Command::setCommand( const char * command ) { const QMutexLocker locker( &d->mutex ); d->inputs.command = command; } QByteArray Command::command() const { const QMutexLocker locker( &d->mutex ); return d->inputs.command; } // // here comes the ugly part // #ifdef HAVE_ASSUAN2 static void my_assuan_release( assuan_context_t ctx ) { if ( ctx ) assuan_release( ctx ); } #endif typedef shared_ptr< remove_pointer::type > AssuanContextBase; namespace { struct AssuanClientContext : AssuanContextBase { AssuanClientContext() : AssuanContextBase() {} #ifndef HAVE_ASSUAN2 explicit AssuanClientContext( assuan_context_t ctx ) : AssuanContextBase( ctx, &assuan_disconnect ) {} void reset( assuan_context_t ctx=0 ) { AssuanContextBase::reset( ctx, &assuan_disconnect ); } #else explicit AssuanClientContext( assuan_context_t ctx ) : AssuanContextBase( ctx, &my_assuan_release ) {} void reset( assuan_context_t ctx=0 ) { AssuanContextBase::reset( ctx, &my_assuan_release ); } #endif }; } #ifdef HAVE_ASSUAN2 // compatibility typedef - remove when we require assuan v2... typedef gpg_error_t assuan_error_t; #endif static assuan_error_t my_assuan_transact( const AssuanClientContext & ctx, const char *command, assuan_error_t (*data_cb)( void *, const void *, size_t )=0, void * data_cb_arg=0, assuan_error_t (*inquire_cb)( void *, const char * )=0, void * inquire_cb_arg=0, assuan_error_t (*status_cb)( void *, const char * )=0, void * status_cb_arg=0) { return assuan_transact( ctx.get(), command, data_cb, data_cb_arg, inquire_cb, inquire_cb_arg, status_cb, status_cb_arg ); } static QString to_error_string( int err ) { char buffer[1024]; gpg_strerror_r( static_cast(err), buffer, sizeof buffer ); buffer[sizeof buffer - 1] = '\0'; return QString::fromLocal8Bit( buffer ); } static QString gnupg_home_directory() { #ifdef Q_OS_WIN return QFile::decodeName( default_homedir() ); #else const QByteArray gnupgHome = qgetenv( "GNUPGHOME" ); if ( !gnupgHome.isEmpty() ) return QFile::decodeName( gnupgHome ); else return QDir::homePath() + QLatin1String( "/.gnupg" ); #endif } static QString get_default_socket_name() { const QString homeDir = gnupg_home_directory(); if ( homeDir.isEmpty() ) return QString(); return QDir( homeDir ).absoluteFilePath( QLatin1String( "S.uiserver" ) ); } static QString default_socket_name() { static QString name = get_default_socket_name(); return name; } static QString uiserver_executable() { return QLatin1String( "kleopatra" ); } static QString start_uiserver() { if ( !QProcess::startDetached( uiserver_executable(), QStringList() << QLatin1String( "--daemon" ) ) ) return Command::tr( "Failed to start uiserver %1" ).arg( uiserver_executable() ); else return QString(); } static assuan_error_t getinfo_pid_cb( void * opaque, const void * buffer, size_t length ) { qint64 & pid = *static_cast( opaque ); pid = QByteArray( static_cast( buffer ), length ).toLongLong(); return 0; } static assuan_error_t command_data_cb( void * opaque, const void * buffer, size_t length ) { QByteArray & ba = *static_cast( opaque ); ba.append( QByteArray( static_cast(buffer), length ) ); return 0; } namespace { struct inquire_data { const std::map * map; const AssuanClientContext * ctx; }; } static assuan_error_t command_inquire_cb( void * opaque, const char * what ) { if ( !opaque ) return 0; const inquire_data & id = *static_cast( opaque ); const std::map::const_iterator it = id.map->find( what ); if ( it != id.map->end() ) { const QByteArray & v = it->second; assuan_send_data( id.ctx->get(), v.data(), v.size() ); } return 0; } static inline std::ostream & operator<<( std::ostream & s, const QByteArray & ba ) { return s << std::string( ba.data(), ba.size() ); } static assuan_error_t send_option( const AssuanClientContext & ctx, const char * name, const QVariant & value ) { std::stringstream ss; ss << "OPTION " << name; if ( value.isValid() ) ss << '=' << value.toString().toUtf8(); return my_assuan_transact( ctx, ss.str().c_str() ); } static assuan_error_t send_file( const AssuanClientContext & ctx, const QString & file ) { std::stringstream ss; ss << "FILE " << hexencode( QFile::encodeName( file ) ); return my_assuan_transact( ctx, ss.str().c_str() ); } static assuan_error_t send_recipient( const AssuanClientContext & ctx, const QString & recipient, bool info ) { std::stringstream ss; ss << "RECIPIENT "; if ( info ) ss << "--info "; ss << "--" << hexencode( recipient.toUtf8() ); return my_assuan_transact( ctx, ss.str().c_str() ); } static assuan_error_t send_sender( const AssuanClientContext & ctx, const QString & sender, bool info ) { std::stringstream ss; ss << "SENDER "; if ( info ) ss << "--info "; ss << "--" << hexencode( sender.toUtf8() ); return my_assuan_transact( ctx, ss.str().c_str() ); } void Command::Private::run() { // Take a snapshot of the input data, and clear the output data: Inputs in; Outputs out; { const QMutexLocker locker( &mutex ); in = inputs; outputs = out; } out.canceled = false; if ( out.serverLocation.isEmpty() ) out.serverLocation = default_socket_name(); #ifndef HAVE_ASSUAN2 assuan_context_t naked_ctx = 0; #endif AssuanClientContext ctx; assuan_error_t err = 0; inquire_data id = { &in.inquireData, &ctx }; const QString socketName = out.serverLocation; if ( socketName.isEmpty() ) { out.errorString = tr("Invalid socket name!"); goto leave; } #ifndef HAVE_ASSUAN2 err = assuan_socket_connect( &naked_ctx, QFile::encodeName( socketName ).constData(), -1 ); #else { assuan_context_t naked_ctx = 0; err = assuan_new( &naked_ctx ); if ( err ) { out.errorString = tr( "Could not allocate resources to connect to Kleopatra UI server at %1: %2" ) .arg( socketName, to_error_string( err ) ); goto leave; } ctx.reset( naked_ctx ); } err = assuan_socket_connect( ctx.get(), QFile::encodeName( socketName ).constData(), -1, 0 ); #endif if ( err ) { qDebug( "UI server not running, starting it" ); const QString errorString = start_uiserver(); if ( !errorString.isEmpty() ) { out.errorString = errorString; goto leave; } // give it a bit of time to start up and try a couple of times for ( int i = 0 ; err && i < 20 ; ++i ) { msleep( 500 ); #ifndef HAVE_ASSUAN2 err = assuan_socket_connect( &naked_ctx, QFile::encodeName( socketName ).constData(), -1 ); #else err = assuan_socket_connect( ctx.get(), QFile::encodeName( socketName ).constData(), -1, 0 ); #endif } } if ( err ) { out.errorString = tr( "Could not connect to Kleopatra UI server at %1: %2" ) .arg( socketName, to_error_string( err ) ); goto leave; } #ifndef HAVE_ASSUAN2 ctx.reset( naked_ctx ); naked_ctx = 0; #endif out.serverPid = -1; err = my_assuan_transact( ctx, "GETINFO pid", &getinfo_pid_cb, &out.serverPid ); if ( err || out.serverPid <= 0 ) { out.errorString = tr( "Could not get the process-id of the Kleopatra UI server at %1: %2" ) .arg( socketName, to_error_string( err ) ); goto leave; } qDebug() << "Server PID =" << out.serverPid; #if defined(Q_OS_WIN) if ( !AllowSetForegroundWindow( (pid_t)out.serverPid ) ) qDebug() << "AllowSetForegroundWindow(" << out.serverPid << ") failed: " << GetLastError(); #endif if ( in.command.isEmpty() ) goto leave; if ( in.parentWId ) { #if defined(Q_OS_WIN32) err = send_option( ctx, "window-id", QString().sprintf( "%lx", reinterpret_cast( in.parentWId ) ) ); #else err = send_option( ctx, "window-id", QString().sprintf( "%lx", static_cast( in.parentWId ) ) ); #endif if ( err ) qDebug( "sending option window-id failed - ignoring" ); } for ( std::map::const_iterator it = in.options.begin(), end = in.options.end() ; it != end ; ++it ) if ( ( err = send_option( ctx, it->first.c_str(), it->second.hasValue ? it->second.value.toString() : QVariant() ) ) ) { if ( it->second.isCritical ) { out.errorString = tr("Failed to send critical option %1: %2") .arg( QString::fromLatin1( it->first.c_str() ), to_error_string( err ) ); goto leave; } else { qDebug() << "Failed to send non-critical option" << it->first.c_str() << ":" << to_error_string( err ); } } Q_FOREACH( const QString & filePath, in.filePaths ) if ( ( err = send_file( ctx, filePath ) ) ) { out.errorString = tr("Failed to send file path %1: %2") .arg( filePath, to_error_string( err ) ); goto leave; } Q_FOREACH( const QString & sender, in.senders ) if ( ( err = send_sender( ctx, sender, in.areSendersInformative ) ) ) { out.errorString = tr("Failed to send sender %1: %2") .arg( sender, to_error_string( err ) ); goto leave; } Q_FOREACH( const QString & recipient, in.recipients ) if ( ( err = send_recipient( ctx, recipient, in.areRecipientsInformative ) ) ) { out.errorString = tr("Failed to send recipient %1: %2") .arg( recipient, to_error_string( err ) ); goto leave; } #if 0 setup I/O; #endif err = my_assuan_transact( ctx, in.command.constData(), &command_data_cb, &out.data, &command_inquire_cb, &id ); if ( err ) { if ( gpg_err_code( err ) == GPG_ERR_CANCELED ) out.canceled = true; else out.errorString = tr( "Command (%1) failed: %2" ) .arg( QString::fromLatin1( in.command.constData() ) ).arg( to_error_string( err ) ); goto leave; } leave: const QMutexLocker locker( &mutex ); // copy outputs to where Command can see them: outputs = out; } diff --git a/kleopatra/main.cpp b/kleopatra/main.cpp index 6f1956153c..ca89d81aaa 100644 --- a/kleopatra/main.cpp +++ b/kleopatra/main.cpp @@ -1,348 +1,350 @@ /* main.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2001,2002,2004,2008 Klar�vdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "aboutdata.h" #include "kleopatraapplication.h" #include "mainwindow.h" #include #include #include #include #ifdef HAVE_USABLE_ASSUAN # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include #else namespace Kleo { class UiServer; } #endif #include #ifdef KDEPIM_MOBILE_UI # include #endif #include #include #include #include #include #include #include // for Qt::escape #include #include #include #include #include #include #include +#ifndef Q_MOC_RUN #include +#endif #include using namespace boost; static const int SPLASHSCREEN_TIMEOUT = 5000; // 5s namespace { template boost::shared_ptr make_shared_ptr( T * t ) { return t ? boost::shared_ptr( t ) : boost::shared_ptr() ; } } static QPixmap UserIcon_nocached( const char * name ) { // KIconLoader insists on caching all pixmaps. Since the splash // screen is a particularly large 'icon' and used only once, // caching is unneccesary and just hurts startup performance. KIconLoader * const il = KIconLoader::global(); assert( il ); const QString iconPath = il->iconPath( QLatin1String( name ), KIconLoader::User ); return iconPath.isEmpty() ? il->unknown() : QPixmap( iconPath ) ; } #ifndef QT_NO_SPLASHSCREEN class SplashScreen : public KSplashScreen { QBasicTimer m_timer; public: SplashScreen() : KSplashScreen( UserIcon_nocached( "kleopatra_splashscreen" ), Qt::WindowStaysOnTopHint ), m_timer() { m_timer.start( SPLASHSCREEN_TIMEOUT, this ); } protected: void timerEvent( QTimerEvent * ev ) { if ( ev->timerId() == m_timer.timerId() ) { m_timer.stop(); hide(); } else { KSplashScreen::timerEvent( ev ); } } }; #else class SplashScreen {}; #endif // QT_NO_SPLASHSCREEN static bool selfCheck( SplashScreen & splash ) { #ifndef QT_NO_SPLASHSCREEN splash.showMessage( i18n("Performing Self-Check...") ); #endif Kleo::Commands::SelfTestCommand cmd( 0 ); cmd.setAutoDelete( false ); cmd.setAutomaticMode( true ); #ifndef QT_NO_SPLASHSCREEN cmd.setSplashScreen( &splash ); #endif QEventLoop loop; QObject::connect( &cmd, SIGNAL(finished()), &loop, SLOT(quit()) ); #ifndef QT_NO_SPLASHSCREEN QObject::connect( &cmd, SIGNAL(info(QString)), &splash, SLOT(showMessage(QString)) ); #endif QTimer::singleShot( 0, &cmd, SLOT(start()) ); // start() may emit finished()... loop.exec(); if ( cmd.isCanceled() ) { #ifndef QT_NO_SPLASHSCREEN splash.showMessage( i18nc("did not pass", "Self-Check Failed") ); #endif return false; } else { #ifndef QT_NO_SPLASHSCREEN splash.showMessage( i18n("Self-Check Passed") ); #endif return true; } } static void fillKeyCache( SplashScreen * splash, Kleo::UiServer * server ) { QEventLoop loop; Kleo::ReloadKeysCommand * cmd = new Kleo::ReloadKeysCommand( 0 ); QObject::connect( cmd, SIGNAL(finished()), &loop, SLOT(quit()) ); #ifdef HAVE_USABLE_ASSUAN QObject::connect( cmd, SIGNAL(finished()), server, SLOT(enableCryptoCommands()) ); #else Q_UNUSED( server ); #endif #ifndef QT_NO_SPLASHSCREEN splash->showMessage( i18n("Loading certificate cache...") ); #else Q_UNUSED( splash ); #endif cmd->start(); loop.exec(); #ifndef QT_NO_SPLASHSCREEN splash->showMessage( i18n("Certificate cache loaded.") ); #endif } int main( int argc, char** argv ) { QTime timer; timer.start(); const GpgME::Error gpgmeInitError = GpgME::initializeLibrary(0); { const unsigned int threads = QThreadPool::globalInstance()->maxThreadCount(); QThreadPool::globalInstance()->setMaxThreadCount( qMax( 2U, threads ) ); } AboutData aboutData; KCmdLineArgs::init(argc, argv, &aboutData); #ifdef KDEPIM_MOBILE_UI KDeclarativeApplicationBase::preApplicationSetup( KleopatraApplication::commandLineOptions() ); #else KCmdLineArgs::addCmdLineOptions( KleopatraApplication::commandLineOptions() ); #endif kDebug() << "Statup timing:" << timer.elapsed() << "ms elapsed: Command line args created"; KleopatraApplication app; #ifdef KDEPIM_MOBILE_UI KDeclarativeApplicationBase::postApplicationSetup(); #endif kDebug() << "Startup timing:" << timer.elapsed() << "ms elapsed: Application created"; KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); if ( gpgmeInitError ) { KMessageBox::sorry( 0, i18nc("@info", "The version of the GpgME library you are running against " "is older than the one that the GpgME++ library was built against." "Kleopatra will not function in this setting." "Please ask your administrator for help in resolving this issue."), i18nc("@title", "GpgME Too Old") ); return EXIT_FAILURE; } SplashScreen splash; const QString installPath = Kleo::gpg4winInstallPath(); Kleo::ChecksumDefinition::setInstallPath( installPath ); Kleo::ArchiveDefinition::setInstallPath( installPath ); int rc; #ifdef HAVE_USABLE_ASSUAN try { Kleo::UiServer server( args->getOption("uiserver-socket") ); kDebug() << "Startup timing:" << timer.elapsed() << "ms elapsed: UiServer created"; QObject::connect( &server, SIGNAL(startKeyManagerRequested()), &app, SLOT(openOrRaiseMainWindow()) ); QObject::connect( &server, SIGNAL(startConfigDialogRequested()), &app, SLOT(openOrRaiseConfigDialog()) ); #define REGISTER( Command ) server.registerCommandFactory( boost::shared_ptr( new Kleo::GenericAssuanCommandFactory ) ) REGISTER( CreateChecksumsCommand ); REGISTER( DecryptCommand ); REGISTER( DecryptFilesCommand ); REGISTER( DecryptVerifyFilesCommand ); REGISTER( EchoCommand ); REGISTER( EncryptCommand ); REGISTER( EncryptFilesCommand ); REGISTER( EncryptSignFilesCommand ); REGISTER( ImportFilesCommand ); REGISTER( PrepEncryptCommand ); REGISTER( PrepSignCommand ); REGISTER( SelectCertificateCommand ); REGISTER( SignCommand ); REGISTER( SignEncryptFilesCommand ); REGISTER( SignFilesCommand ); #ifndef QT_NO_DIRMODEL REGISTER( VerifyChecksumsCommand ); #endif // QT_NO_DIRMODEL REGISTER( VerifyCommand ); REGISTER( VerifyFilesCommand ); #undef REGISTER server.start(); kDebug() << "Startup timing:" << timer.elapsed() << "ms elapsed: UiServer started"; #endif const bool daemon = args->isSet("daemon"); if ( !daemon && app.isSessionRestored() ) { app.restoreMainWindow(); } #ifndef QT_NO_SPLASHSCREEN // Don't show splash screen if daemon or session restore if ( !( daemon || app.isSessionRestored() ) ) splash.show(); #endif if ( !selfCheck( splash ) ) return 1; kDebug() << "Startup timing:" << timer.elapsed() << "ms elapsed: SelfCheck completed"; #ifdef HAVE_USABLE_ASSUAN fillKeyCache( &splash, &server ); #else fillKeyCache( &splash, 0 ); #endif kDebug() << "Startup timing:" << timer.elapsed() << "ms elapsed: KeyCache loaded"; #ifndef QT_NO_SYSTEMTRAYICON app.startMonitoringSmartCard(); #endif app.setIgnoreNewInstance( false ); if ( !daemon ) { app.newInstance(); app.setFirstNewInstance( false ); kDebug() << "Startup timing:" << timer.elapsed() << "ms elapsed: new instance created"; #ifndef QT_NO_SPLASHSCREEN splash.finish( app.mainWindow() ); #endif // QT_NO_SPLASHSCREEN } rc = app.exec(); #ifdef HAVE_USABLE_ASSUAN app.setIgnoreNewInstance( true ); QObject::disconnect( &server, SIGNAL(startKeyManagerRequested()), &app, SLOT(openOrRaiseMainWindow()) ); QObject::disconnect( &server, SIGNAL(startConfigDialogRequested()), &app, SLOT(openOrRaiseConfigDialog()) ); server.stop(); server.waitForStopped(); } catch ( const std::exception & e ) { QMessageBox::information( 0, i18n("GPG UI Server Error"), i18n("The Kleopatra GPG UI Server Module could not be initialized.
" "The error given was: %1
" "You can use Kleopatra as a certificate manager, but cryptographic plugins that " "rely on a GPG UI Server being present might not work correctly, or at all.
", Qt::escape( QString::fromUtf8( e.what() ) ) )); #ifndef QT_NO_SYSTEMTRAYICON app.startMonitoringSmartCard(); #endif app.setIgnoreNewInstance( false ); rc = app.exec(); app.setIgnoreNewInstance( true ); } #endif return rc; } diff --git a/kleopatra/mainwindow_desktop.cpp b/kleopatra/mainwindow_desktop.cpp index 8379af79dc..b08c8f4eb9 100644 --- a/kleopatra/mainwindow_desktop.cpp +++ b/kleopatra/mainwindow_desktop.cpp @@ -1,544 +1,546 @@ /* -*- mode: c++; c-basic-offset:4 -*- mainwindow_desktop.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2007 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "mainwindow_desktop.h" #include "aboutdata.h" #include "models/keylistmodel.h" #include "models/keylistsortfilterproxymodel.h" #include "view/searchbar.h" #include "view/tabwidget.h" #include "view/keylistcontroller.h" #include "commands/selftestcommand.h" #include "commands/importcrlcommand.h" #include "commands/importcertificatefromfilecommand.h" #include "commands/decryptverifyfilescommand.h" #include "commands/signencryptfilescommand.h" #include "utils/detail_p.h" #include "utils/gnupg-helper.h" #include "utils/action_data.h" #include "utils/classify.h" #include "utils/filedialog.h" // from libkdepim #include "progresswidget/statusbarprogresswidget.h" #include "progresswidget/progressdialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#ifndef Q_MOC_RUN #include #include +#endif #include #ifdef Q_OS_WIN32 static const bool OS_WIN = true; #else static const bool OS_WIN = false; #endif using namespace Kleo; using namespace Kleo::Commands; using namespace boost; using namespace GpgME; namespace { static const KAboutData * aboutGpg4WinData() { static const AboutGpg4WinData data; return &data; } } static KGuiItem KStandardGuiItem_quit() { static const QString app = KGlobal::mainComponent().aboutData()->programName(); KGuiItem item = KStandardGuiItem::quit(); item.setText( i18nc( "Quit [ApplicationName]", "&Quit %1", app ) ); return item; } static KGuiItem KStandardGuiItem_close() { KGuiItem item = KStandardGuiItem::close(); item.setText( i18n("Only &Close Window" ) ); return item; } static bool isQuitting = false; class MainWindow::Private { friend class ::MainWindow; MainWindow * const q; public: explicit Private( MainWindow * qq ); ~Private(); template void createAndStart() { ( new T( this->currentView(), &this->controller ) )->start(); } template void createAndStart( QAbstractItemView * view ) { ( new T( view, &this->controller ) )->start(); } template void createAndStart( const QStringList & a ) { ( new T( a, this->currentView(), &this->controller ) )->start(); } template void createAndStart( const QStringList & a, QAbstractItemView * view ) { ( new T( a, view, &this->controller ) )->start(); } void closeAndQuit() { const QString app = KGlobal::mainComponent().aboutData()->programName(); const int rc = KMessageBox::questionYesNoCancel( q, i18n("%1 may be used by other applications as a service.\n" "You may instead want to close this window without exiting %1.", app ), i18n("Really Quit?"), KStandardGuiItem_close(), KStandardGuiItem_quit(), KStandardGuiItem::cancel(), QLatin1String("really-quit-") + app.toLower() ); if ( rc == KMessageBox::Cancel ) return; isQuitting = true; if ( !q->close() ) return; // WARNING: 'this' might be deleted at this point! if ( rc == KMessageBox::No ) qApp->quit(); } void configureToolbars() { KEditToolBar dlg( q->factory() ); dlg.exec(); } void editKeybindings() { KShortcutsDialog::configure( q->actionCollection(), KShortcutsEditor::LetterShortcutsAllowed ); } void selfTest() { createAndStart(); } void configureBackend(); void showHandbook(); void gnupgLogViewer() { if( !QProcess::startDetached(QLatin1String("kwatchgnupg") ) ) KMessageBox::error( q, i18n( "Could not start the GnuPG Log Viewer (kwatchgnupg). " "Please check your installation." ), i18n( "Error Starting KWatchGnuPG" ) ); } void gnupgAdministrativeConsole() { if( !QProcess::startDetached(QLatin1String("kgpgconf") ) ) KMessageBox::error( q, i18n( "Could not start the GnuPG Administrative Console (kgpgconf). " "Please check your installation." ), i18n( "Error Starting KGpgConf" ) ); } void slotConfigCommitted(); void slotContextMenuRequested( QAbstractItemView *, const QPoint & p ) { if ( QMenu * const menu = qobject_cast( q->factory()->container( QLatin1String("listview_popup"), q ) ) ) menu->exec( p ); else kDebug() << "no \"listview_popup\" in kleopatra's ui.rc file"; } void aboutGpg4Win() { ( new KAboutApplicationDialog( aboutGpg4WinData(), KAboutApplicationDialog::HideKdeVersion|KAboutApplicationDialog::HideTranslators, q ) )->show(); } private: void setupActions(); QAbstractItemView * currentView() const { return ui.tabWidget.currentView(); } private: Kleo::KeyListController controller; bool firstShow : 1; struct UI { TabWidget tabWidget; explicit UI( MainWindow * q ); } ui; }; MainWindow::Private::UI::UI(MainWindow *q) : tabWidget( q ) { KDAB_SET_OBJECT_NAME( tabWidget ); QWidget *mainWidget = new QWidget; QVBoxLayout *vbox = new QVBoxLayout; vbox->setSpacing(0); mainWidget->setLayout(vbox); SearchBar * const searchBar = new SearchBar; vbox->addWidget(searchBar); tabWidget.connectSearchBar( searchBar ); vbox->addWidget(&tabWidget); q->setCentralWidget(mainWidget); KPIM::ProgressDialog * progressDialog = new KPIM::ProgressDialog( q->statusBar(), q ); KDAB_SET_OBJECT_NAME( progressDialog ); progressDialog->hide(); KPIM::StatusbarProgressWidget * statusBarProgressWidget = new KPIM::StatusbarProgressWidget( progressDialog, q->statusBar() ); KDAB_SET_OBJECT_NAME( statusBarProgressWidget ); q->statusBar()->addPermanentWidget( statusBarProgressWidget, 0 ); statusBarProgressWidget->show(); } MainWindow::Private::Private( MainWindow * qq ) : q( qq ), controller( q ), firstShow( true ), ui( q ) { KDAB_SET_OBJECT_NAME( controller ); AbstractKeyListModel * flatModel = AbstractKeyListModel::createFlatKeyListModel( q ); AbstractKeyListModel * hierarchicalModel = AbstractKeyListModel::createHierarchicalKeyListModel( q ); KDAB_SET_OBJECT_NAME( flatModel ); KDAB_SET_OBJECT_NAME( hierarchicalModel ); controller.setFlatModel( flatModel ); controller.setHierarchicalModel( hierarchicalModel ); controller.setTabWidget( &ui.tabWidget ); ui.tabWidget.setFlatModel( flatModel ); ui.tabWidget.setHierarchicalModel( hierarchicalModel ); setupActions(); connect( &controller, SIGNAL(message(QString,int)), q->statusBar(), SLOT(showMessage(QString,int)) ); connect( &controller, SIGNAL(contextMenuRequested(QAbstractItemView*,QPoint)), q, SLOT(slotContextMenuRequested(QAbstractItemView*,QPoint)) ); q->createGUI( QLatin1String("kleopatra.rc") ); q->setAcceptDrops( true ); q->setAutoSaveSettings(); } MainWindow::Private::~Private() {} MainWindow::MainWindow( QWidget* parent, Qt::WindowFlags flags ) : KXmlGuiWindow( parent, flags ), d( new Private( this ) ) { } MainWindow::~MainWindow() {} void MainWindow::Private::setupActions() { KActionCollection * const coll = q->actionCollection(); const action_data action_data[] = { // most have been MOVED TO keylistcontroller.cpp // Tools menu #ifndef Q_OS_WIN { "tools_start_kwatchgnupg", i18n("GnuPG Log Viewer"), QString(), "kwatchgnupg", q, SLOT(gnupgLogViewer()), QString(), false, true }, #endif #if 0 { "tools_start_kgpgconf", i18n("GnuPG Administrative Console"), QString(), "kgpgconf", q, SLOT(gnupgLogViewer()), QString(), false, true }, #endif // most have been MOVED TO keylistcontroller.cpp #if 0 { "configure_backend", i18n("Configure GnuPG Backend..."), QString(), 0, q, SLOT(configureBackend()), QString(), false, true }, #endif // Settings menu { "settings_self_test", i18n("Perform Self-Test"), QString(), 0, q, SLOT(selfTest()), QString(), false, true }, // Help menu #ifdef Q_WS_WIN { "help_about_gpg4win", i18n("About Gpg4win"), QString(), "gpg4win-compact", q, SLOT(aboutGpg4Win()), QString(), false, true }, #endif // most have been MOVED TO keylistcontroller.cpp }; make_actions_from_data( action_data, /*sizeof action_data / sizeof *action_data,*/ coll ); if ( QAction * action = coll->action( QLatin1String("configure_backend") ) ) action->setMenuRole( QAction::NoRole ); //prevent Qt OS X heuristics for config* actions KStandardAction::close( q, SLOT(close()), coll ); KStandardAction::quit( q, SLOT(closeAndQuit()), coll ); KStandardAction::configureToolbars( q, SLOT(configureToolbars()), coll ); KStandardAction::keyBindings( q, SLOT(editKeybindings()), coll ); KStandardAction::preferences( qApp, SLOT(openOrRaiseConfigDialog()), coll ); q->createStandardStatusBarAction(); q->setStandardToolBarMenuEnabled( true ); controller.createActions( coll ); ui.tabWidget.createActions( coll ); } void MainWindow::Private::configureBackend() { Kleo::CryptoConfig * const config = Kleo::CryptoBackendFactory::instance()->config(); if ( !config ) { KMessageBox::error( q, i18n( "Could not configure the cryptography backend (gpgconf tool not found)" ), i18n( "Configuration Error" ) ); return; } Kleo::CryptoConfigDialog dlg( config ); const int result = dlg.exec(); // Forget all data parsed from gpgconf, so that we show updated information // when reopening the configuration dialog. config->clear(); if ( result == QDialog::Accepted ) { #if 0 // Tell other apps (e.g. kmail) that the gpgconf data might have changed QDBusMessage message = QDBusMessage::createSignal(QString(), "org.kde.kleo.CryptoConfig", "changed"); QDBusConnection::sessionBus().send(message); #endif } } void MainWindow::Private::slotConfigCommitted() { controller.updateConfig(); } void MainWindow::closeEvent( QCloseEvent * e ) { // KMainWindow::closeEvent() insists on quitting the application, // so do not let it touch the event... kDebug(); if ( d->controller.hasRunningCommands() ) { if ( d->controller.shutdownWarningRequired() ) { const int ret = KMessageBox::warningContinueCancel( this, i18n("There are still some background operations ongoing. " "These will be terminated when closing the window. " "Proceed?"), i18n("Ongoing Background Tasks") ); if ( ret != KMessageBox::Continue ) { e->ignore(); return; } } d->controller.cancelCommands(); if ( d->controller.hasRunningCommands() ) { // wait for them to be finished: setEnabled( false ); QEventLoop ev; QTimer::singleShot( 100, &ev, SLOT(quit()) ); connect( &d->controller, SIGNAL(commandsExecuting(bool)), &ev, SLOT(quit()) ); ev.exec(); kWarning( d->controller.hasRunningCommands() ) << "controller still has commands running, this may crash now..."; setEnabled( true ); } } if ( isQuitting || kapp->sessionSaving() ) { d->ui.tabWidget.saveViews( KGlobal::config().data() ); saveMainWindowSettings( KConfigGroup( KGlobal::config(), autoSaveGroup() ) ); e->accept(); } else { e->ignore(); hide(); } } void MainWindow::showEvent( QShowEvent * e ) { KXmlGuiWindow::showEvent( e ); if ( d->firstShow ) { d->ui.tabWidget.loadViews( KGlobal::config().data() ); d->firstShow = false; } if ( !savedGeometry.isEmpty() ) { restoreGeometry( savedGeometry ); } } void MainWindow::hideEvent( QHideEvent * e ) { savedGeometry = saveGeometry(); KXmlGuiWindow::hideEvent( e ); } void MainWindow::importCertificatesFromFile( const QStringList & files ) { if ( !files.empty() ) d->createAndStart( files ); } static QStringList extract_local_files( const QMimeData * data ) { const QList urls = data->urls(); // begin workaround KDE/Qt misinterpretation of text/uri-list QList::const_iterator end = urls.end(); if ( urls.size() > 1 && !urls.back().isValid() ) --end; // end workaround QStringList result; std::transform( urls.begin(), end, std::back_inserter( result ), boost::bind( &QUrl::toLocalFile, _1 ) ); result.erase( std::remove_if( result.begin(), result.end(), boost::bind( &QString::isEmpty, _1 ) ), result.end() ); return result; } static bool can_decode_local_files( const QMimeData * data ) { if ( !data ) return false; return !extract_local_files( data ).empty(); } void MainWindow::dragEnterEvent( QDragEnterEvent * e ) { kDebug(); if ( can_decode_local_files( e->mimeData() ) ) e->acceptProposedAction(); } void MainWindow::dropEvent( QDropEvent * e ) { kDebug(); if ( !can_decode_local_files( e->mimeData() ) ) return; e->setDropAction( Qt::CopyAction ); const QStringList files = extract_local_files( e->mimeData() ); const unsigned int classification = classify( files ); QMenu menu; QAction * const signEncrypt = menu.addAction( i18n("Sign/Encrypt...") ); QAction * const decryptVerify = mayBeAnyMessageType( classification ) ? menu.addAction( i18n("Decrypt/Verify...") ) : 0 ; if ( signEncrypt || decryptVerify ) menu.addSeparator(); QAction * const importCerts = mayBeAnyCertStoreType( classification ) ? menu.addAction( i18n("Import Certificates") ) : 0 ; QAction * const importCRLs = mayBeCertificateRevocationList( classification ) ? menu.addAction( i18n("Import CRLs") ) : 0 ; if ( importCerts || importCRLs ) menu.addSeparator(); if ( !signEncrypt && !decryptVerify && !importCerts && !importCRLs ) return; menu.addAction( i18n("Cancel") ); const QAction * const chosen = menu.exec( mapToGlobal( e->pos() ) ); if ( !chosen ) return; if ( chosen == signEncrypt ) d->createAndStart( files ); else if ( chosen == decryptVerify ) d->createAndStart( files ); else if ( chosen == importCerts ) d->createAndStart( files ); else if ( chosen == importCRLs ) d->createAndStart( files ); e->accept(); } void MainWindow::readProperties( const KConfigGroup & cg ) { kDebug(); KXmlGuiWindow::readProperties(cg); savedGeometry = cg.readEntry("savedGeometry", QByteArray() ); if ( !savedGeometry.isEmpty() ) { restoreGeometry( savedGeometry ); } if (! cg.readEntry("hidden", false)) show(); } void MainWindow::saveProperties( KConfigGroup & cg ) { kDebug(); KXmlGuiWindow::saveProperties( cg ); cg.writeEntry( "hidden", isHidden() ); if ( isHidden() ) { cg.writeEntry( "savedGeometry", savedGeometry ); } else { cg.writeEntry( "savedGeometry", saveGeometry() ); } } #include "moc_mainwindow_desktop.cpp" diff --git a/kleopatra/mainwindow_mobile.cpp b/kleopatra/mainwindow_mobile.cpp index 8709c15865..0cb00fb27a 100644 --- a/kleopatra/mainwindow_mobile.cpp +++ b/kleopatra/mainwindow_mobile.cpp @@ -1,391 +1,393 @@ /* -*- mode: c++; c-basic-offset:4 -*- mainwindow_mobile.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2010 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "mainwindow_mobile.h" #include "aboutdata.h" #include "models/keylistmodel.h" #include "models/keylistsortfilterproxymodel.h" #include "view/searchbar.h" #if 0 #include "view/tabwidget.h" #endif #include "view/keytreeview.h" #include "view/keylistcontroller.h" #include "commands/selftestcommand.h" #include "commands/importcrlcommand.h" #include "commands/importcertificatefromfilecommand.h" #include "commands/decryptverifyfilescommand.h" #include "commands/signencryptfilescommand.h" #include "utils/detail_p.h" #include "utils/gnupg-helper.h" #include "utils/action_data.h" #include "utils/classify.h" #include "utils/filedialog.h" // from libkdepim #include "progresswidget/statusbarprogresswidget.h" #include "progresswidget/progressdialog.h" // from mobileui #include "declarativewidgetbase.h" #include #include #include #include #include #include #include #include #if 0 #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#ifndef Q_MOC_RUN #include #include +#endif #include #ifdef Q_OS_WIN32 static const bool OS_WIN = true; #else static const bool OS_WIN = false; #endif using namespace Kleo; using namespace Kleo::Commands; using namespace boost; using namespace GpgME; namespace { static const KAboutData * aboutGpg4WinData() { static const AboutGpg4WinData data; return &data; } } class MainWindow::KeyTreeViewItem : public DeclarativeWidgetBase { Q_OBJECT public: explicit KeyTreeViewItem( QGraphicsItem * parent=0 ) : DeclarativeWidgetBase( parent ) {} ~KeyTreeViewItem() {} }; class MainWindow::SearchBarItem : public DeclarativeWidgetBase { Q_OBJECT public: explicit SearchBarItem( QGraphicsItem * parent=0 ) : DeclarativeWidgetBase( parent ) {} ~SearchBarItem() {} }; static KGuiItem KStandardGuiItem_quit() { static const QString app = KGlobal::mainComponent().aboutData()->programName(); KGuiItem item = KStandardGuiItem::quit(); item.setText( i18nc( "Quit [ApplicationName]", "&Quit %1", app ) ); return item; } static KGuiItem KStandardGuiItem_close() { KGuiItem item = KStandardGuiItem::close(); item.setText( i18n("Only &Close Window" ) ); return item; } class MainWindow::Private { friend class ::MainWindow; MainWindow * const q; public: explicit Private( MainWindow * qq ); ~Private(); void start( Command * c ) { c->setParentWidget( q ); c->start(); } template void createAndStart() { this->start( new T( this->currentView(), &this->controller ) ); } template void createAndStart( QAbstractItemView * view ) { start( new T( view, &this->controller ) ); } template void createAndStart( const QStringList & a ) { start( new T( a, this->currentView(), &this->controller ) ); } template void createAndStart( const QStringList & a, QAbstractItemView * view ) { start( new T( a, view, &this->controller ) ); } void closeAndQuit() { qApp->quit(); } void selfTest() { createAndStart(); } void configureBackend(); void showHandbook(); void gnupgLogViewer() { if( !QProcess::startDetached( QLatin1String( "kwatchgnupg" ) ) ) KMessageBox::error( q, i18n( "Could not start the GnuPG Log Viewer (kwatchgnupg). " "Please check your installation." ), i18n( "Error Starting KWatchGnuPG" ) ); } void gnupgAdministrativeConsole() { if( !QProcess::startDetached( QLatin1String( "kgpgconf" ) ) ) KMessageBox::error( q, i18n( "Could not start the GnuPG Administrative Console (kgpgconf). " "Please check your installation." ), i18n( "Error Starting KGpgConf" ) ); } void slotConfigCommitted(); void slotSearchBarTextChanged( const QString & ); void aboutGpg4Win() { ( new KAboutApplicationDialog( aboutGpg4WinData(), KAboutApplicationDialog::HideKdeVersion|KAboutApplicationDialog::HideTranslators, q ) )->show(); } private: void setupActions(); void tryToConnectSearchBarToKeyTreeView() { if ( searchBar && keyTreeView ) keyTreeView->connectSearchBar( searchBar ); } QAbstractItemView * currentView() const { return controller.currentView(); } private: QPointer searchBar; QPointer keyTreeView; Kleo::KeyListController controller; bool firstShow : 1; }; MainWindow::Private::Private( MainWindow * qq ) : q( qq ), searchBar(), keyTreeView(), controller( q ), firstShow( true ) { KDAB_SET_OBJECT_NAME( controller ); AbstractKeyListModel * flatModel = AbstractKeyListModel::createFlatKeyListModel( q ); AbstractKeyListModel * hierarchicalModel = AbstractKeyListModel::createHierarchicalKeyListModel( q ); KDAB_SET_OBJECT_NAME( flatModel ); KDAB_SET_OBJECT_NAME( hierarchicalModel ); controller.setFlatModel( flatModel ); controller.setHierarchicalModel( hierarchicalModel ); controller.setParentWidget( q ); } MainWindow::Private::~Private() {} MainWindow::MainWindow( QWidget * parent ) : KDeclarativeFullScreenView( QLatin1String("kleopatra-mobile"), parent ), d( new Private( this ) ) { } MainWindow::~MainWindow() {} void MainWindow::Private::setupActions() { KActionCollection * const coll = q->actionCollection(); const action_data action_data[] = { // Settings menu { "settings_self_test", i18n("Perform Self-Test"), QString(), 0, q, SLOT(selfTest()), QString(), false, true }, }; make_actions_from_data( action_data, coll ); KStandardAction::close( q, SLOT(close()), coll ); KStandardAction::quit( q, SLOT(closeAndQuit()), coll ); KStandardAction::preferences( qApp, SLOT(openOrRaiseConfigDialog()), coll ); controller.createActions( coll ); } void MainWindow::doDelayedInit() { qmlRegisterType( "org.kde.kleopatra", 2, 1, "KeyTreeView" ); qmlRegisterType ( "org.kde.kleopatra", 2, 1, "SearchBar" ); d->setupActions(); engine()->rootContext()->setContextProperty( QLatin1String( "application" ), QVariant::fromValue( static_cast( this ) ) ); } void MainWindow::registerKeyTreeView( KeyTreeView * view ) { if ( !view ) return; view->setFlatModel( d->controller.flatModel() ); view->setHierarchicalModel( d->controller.hierarchicalModel() ); QTreeView * const v = view->view(); v->setItemsExpandable( false ); v->header()->setResizeMode( QHeaderView::Stretch ); v->header()->hide(); d->controller.addView( v ); d->controller.setCurrentView( v ); d->keyTreeView = view; d->tryToConnectSearchBarToKeyTreeView(); connect( v->model(), SIGNAL(rowsInserted(QModelIndex,int,int)), SIGNAL(certificatesAvailabilityChanged()) ); connect( v->model(), SIGNAL(rowsRemoved(QModelIndex,int,int)), SIGNAL(certificatesAvailabilityChanged()) ); connect( v->model(), SIGNAL(modelReset()), SIGNAL(certificatesAvailabilityChanged()) ); emit certificatesAvailabilityChanged(); } void MainWindow::registerSearchBar( SearchBar * bar ) { if ( !bar ) return; d->searchBar = bar; bar->setFixedHeight( 0 ); connect( bar, SIGNAL(stringFilterChanged(QString)), this, SLOT(slotSearchBarTextChanged(QString)) ); d->tryToConnectSearchBarToKeyTreeView(); } void MainWindow::Private::slotConfigCommitted() { controller.updateConfig(); } void MainWindow::closeEvent( QCloseEvent * e ) { d->closeAndQuit(); // KMainWindow::closeEvent() insists on quitting the application, // so do not let it touch the event... kDebug(); if ( d->controller.hasRunningCommands() ) { if ( d->controller.shutdownWarningRequired() ) { const int ret = KMessageBox::warningContinueCancel( this, i18n("There are still some background operations ongoing. " "These will be terminated when closing the window. " "Proceed?"), i18n("Ongoing Background Tasks") ); if ( ret != KMessageBox::Continue ) { e->ignore(); return; } } d->controller.cancelCommands(); if ( d->controller.hasRunningCommands() ) { // wait for them to be finished: setEnabled( false ); QEventLoop ev; QTimer::singleShot( 100, &ev, SLOT(quit()) ); connect( &d->controller, SIGNAL(commandsExecuting(bool)), &ev, SLOT(quit()) ); ev.exec(); kWarning( d->controller.hasRunningCommands() ) << "controller still has commands running, this may crash now..."; setEnabled( true ); } } e->accept(); } void MainWindow::keyPressEvent( QKeyEvent * e ) { static bool isSendingEvent = false; if ( !isSendingEvent && d->searchBar && !e->text().isEmpty() ) { const struct guard { guard() { isSendingEvent = true; } ~guard() { isSendingEvent = false; } } guard; QCoreApplication::sendEvent( d->searchBar->lineEdit(), e ); } else { KDeclarativeFullScreenView::keyPressEvent( e ); } } void MainWindow::importCertificatesFromFile( const QStringList & files ) { if ( !files.empty() ) d->createAndStart( files ); } void MainWindow::Private::slotSearchBarTextChanged( const QString & text ) { if ( text.isEmpty() && searchBar && searchBar->isVisible() ) { searchBar->setFixedHeight( 0 ); searchBar->hide(); } else if ( !text.isEmpty() && searchBar && !searchBar->isVisible() ) { searchBar->setFixedHeight( searchBar->minimumSizeHint().height() ); searchBar->show(); searchBar->setFocus(); } } bool MainWindow::certificatesAvailable() const { return (d->keyTreeView && d->keyTreeView->view()->model()->rowCount()); } #include "moc_mainwindow_mobile.cpp" #include "mainwindow_mobile.moc" diff --git a/kleopatra/models/keycache.cpp b/kleopatra/models/keycache.cpp index f35600fb3c..4f20ea1d4a 100644 --- a/kleopatra/models/keycache.cpp +++ b/kleopatra/models/keycache.cpp @@ -1,971 +1,973 @@ /* -*- mode: c++; c-basic-offset:4 -*- models/keycache.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2007,2008 Klarälvdalens Datakonsult AB Kleopatra 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. Kleopatra 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "keycache.h" #include "keycache_p.h" #include "predicates.h" #include "smimevalidationpreferences.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#ifndef Q_MOC_RUN #include #include #include #include #include +#endif #include #include #include #include using namespace Kleo; using namespace GpgME; using namespace boost; using namespace KMime::Types; static const unsigned int hours2ms = 1000 * 60 * 60; // // // KeyCache // // namespace { make_comparator_str( ByEMail, .first.c_str() ); struct is_string_empty : std::unary_function { bool operator()( const char * s ) const { return !s || !*s; } }; } class KeyCache::Private { friend class ::Kleo::KeyCache; KeyCache * const q; public: explicit Private( KeyCache * qq ) : q( qq ) { connect( &m_autoKeyListingTimer, SIGNAL(timeout()), q, SLOT(startKeyListing()) ); updateAutoKeyListingTimer(); } template < template