Page MenuHome GnuPG

No OneTemporary

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 042416486..dbba139e2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,336 +1,337 @@
project(kleopatra)
include(MacroOptionalAddSubdirectory)
set( kleopatra_version 2.0.12 )
set( kleopatra_release FALSE )
if (NOT kleopatra_release)
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.svn")
if ( NOT KdeSubversion_FOUND )
find_package( KdeSubversion )
endif ( NOT KdeSubversion_FOUND )
if ( KdeSubversion_FOUND )
KdeSubversion_WC_INFO( ${PROJECT_SOURCE_DIR} Kleopatra )
string( SUBSTRING "${Kleopatra_WC_LAST_CHANGED_DATE}" 0 10 Kleopatra_WC_LAST_CHANGED_DATE )
set( kleopatra_version "${kleopatra_version}-svn${Kleopatra_WC_REVISION} (${Kleopatra_WC_LAST_CHANGED_DATE})" )
endif ( KdeSubversion_FOUND )
endif (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.svn")
endif (NOT kleopatra_release)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version-kleopatra.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/version-kleopatra.h )
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config-kleopatra.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kleopatra.h )
include_directories(
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_SOURCE_DIR}/libkleo
${CMAKE_SOURCE_DIR}/libkdepim
${Boost_INCLUDE_DIR}
${QGPGME_INCLUDES}
${GPGME_INCLUDES} )
if (USABLE_ASSUAN_FOUND)
include_directories(${ASSUAN_INCLUDES})
endif(USABLE_ASSUAN_FOUND)
add_definitions ( -DQT3_SUPPORT -DQT3_SUPPORT_WARNINGS -D_ASSUAN_ONLY_GPG_ERRORS -DQT_STL )
remove_definitions ( -DQT_NO_STL )
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS}")
add_subdirectory( pics )
add_subdirectory( conf )
if ( USABLE_ASSUAN_FOUND AND BUILD_libkleopatraclient )
# can't use macro_optional_add_subdirectory here, since it's split
# off into ConfigureChecks.cmake..
add_subdirectory( libkleopatraclient )
endif ( USABLE_ASSUAN_FOUND AND BUILD_libkleopatraclient )
add_subdirectory( kgpgconf )
add_subdirectory( kwatchgnupg )
add_subdirectory( tests )
if ( WIN32 )
set( _kleopatra_extra_uiserver_SRCS
uiserver/uiserver_win.cpp
)
set( _kleopatra_extra_SRCS
utils/gnupg-registry.c
selftest/registrycheck.cpp
)
else ( WIN32 )
set( _kleopatra_extra_uiserver_SRCS
uiserver/uiserver_unix.cpp
)
set( _kleopatra_extra_SRCS
)
endif ( WIN32 )
if ( USABLE_ASSUAN_FOUND )
add_definitions ( -DKLEOPATRACLIENT_NAMESPACE=KleopatraClientCopy -DKLEOPATRACLIENTCORE_EXPORT= )
set(_kleopatra_uiserver_SRCS
uiserver/sessiondata.cpp
uiserver/uiserver.cpp
${_kleopatra_extra_uiserver_SRCS}
uiserver/assuanserverconnection.cpp
uiserver/echocommand.cpp
uiserver/decryptverifycommandemailbase.cpp
uiserver/decryptverifycommandfilesbase.cpp
uiserver/signcommand.cpp
uiserver/signencryptfilescommand.cpp
uiserver/prepencryptcommand.cpp
uiserver/encryptcommand.cpp
uiserver/selectcertificatecommand.cpp
uiserver/importfilescommand.cpp
libkleopatraclient/core/command.cpp
selftest/uiservercheck.cpp
)
if ( WIN32 )
set( _kleopatra_uiserver_extra_libs ${ASSUAN_VANILLA_LIBRARIES} )
else ( WIN32 )
set( _kleopatra_uiserver_extra_libs ${ASSUAN_PTHREAD_LIBRARIES} )
endif( WIN32 )
if ( HAVE_GPG_ERR_SOURCE_KLEO )
add_definitions( -DGPG_ERR_SOURCE_DEFAULT=GPG_ERR_SOURCE_KLEO )
else( HAVE_GPG_ERR_SOURCE_KLEO )
add_definitions( -DGPG_ERR_SOURCE_DEFAULT=GPG_ERR_SOURCE_USER_1 )
endif( HAVE_GPG_ERR_SOURCE_KLEO )
else ( USABLE_ASSUAN_FOUND )
set(_kleopatra_uiserver_SRCS)
endif ( USABLE_ASSUAN_FOUND )
kde4_add_ui_files( _kleopatra_uiserver_SRCS
crypto/gui/signingcertificateselectionwidget.ui)
set( _kleopatra_SRCS
utils/gnupg-helper.cpp
utils/filesystemwatcher.cpp
utils/filedialog.cpp
utils/kdpipeiodevice.cpp
utils/kdlogtextwidget.cpp
utils/kdsignalblocker.cpp
utils/headerview.cpp
utils/scrollarea.cpp
utils/dragqueen.cpp
utils/multivalidator.cpp
utils/progressmanager.cpp
utils/systemtrayicon.cpp
utils/hex.cpp
+ utils/path-helper.cpp
utils/input.cpp
utils/output.cpp
utils/exception.cpp
utils/formatting.cpp
utils/validation.cpp
utils/wsastarter.cpp
utils/classify.cpp
utils/iodevicelogger.cpp
utils/log.cpp
utils/action_data.cpp
utils/types.cpp
selftest/selftest.cpp
selftest/enginecheck.cpp
selftest/gpgconfcheck.cpp
selftest/gpgagentcheck.cpp
smartcard/readerstatus.cpp
${_kleopatra_extra_SRCS}
models/keycache.cpp
models/keylistmodel.cpp
models/keylistsortfilterproxymodel.cpp
models/subkeylistmodel.cpp
models/useridlistmodel.cpp
view/keylistcontroller.cpp
view/keytreeview.cpp
view/searchbar.cpp
view/tabwidget.cpp
dialogs/certificateselectiondialog.cpp
dialogs/expirydialog.cpp
dialogs/lookupcertificatesdialog.cpp
dialogs/ownertrustdialog.cpp
dialogs/selftestdialog.cpp
dialogs/certifycertificatedialog.cpp
dialogs/exportsecretkeydialog.cpp
dialogs/adduseriddialog.cpp
dialogs/certificatedetailsdialog.cpp
dialogs/exportcertificatesdialog.cpp
dialogs/deletecertificatesdialog.cpp
dialogs/setinitialpindialog.cpp
crypto/certificateresolver.cpp
crypto/task.cpp
crypto/taskcollection.cpp
crypto/decryptverifytask.cpp
crypto/decryptverifyemailcontroller.cpp
crypto/decryptverifyfilescontroller.cpp
crypto/encryptemailtask.cpp
crypto/encryptemailcontroller.cpp
crypto/signencryptfilestask.cpp
crypto/signemailtask.cpp
crypto/signemailcontroller.cpp
crypto/gui/wizard.cpp
crypto/gui/wizardpage.cpp
crypto/gui/signingcertificateselectionwidget.cpp
crypto/gui/signingcertificateselectiondialog.cpp
crypto/gui/resultitemwidget.cpp
crypto/gui/resultlistwidget.cpp
crypto/gui/resultpage.cpp
crypto/gui/newresultpage.cpp
crypto/gui/newsignencryptfileswizard.cpp
crypto/gui/decryptverifyoperationwidget.cpp
crypto/gui/decryptverifyfileswizard.cpp
crypto/gui/objectspage.cpp
crypto/gui/resolverecipientspage.cpp
crypto/gui/signerresolvepage.cpp
crypto/gui/encryptemailwizard.cpp
crypto/gui/signemailwizard.cpp
crypto/gui/signencryptfileswizard.cpp
crypto/gui/signencryptwizard.cpp
crypto/controller.cpp
crypto/signencryptfilescontroller.cpp
commands/command.cpp
commands/gnupgprocesscommand.cpp
commands/detailscommand.cpp
commands/exportcertificatecommand.cpp
commands/importcertificatescommand.cpp
commands/importcertificatefromfilecommand.cpp
commands/importcertificatefromclipboardcommand.cpp
commands/lookupcertificatescommand.cpp
commands/reloadkeyscommand.cpp
commands/refreshx509certscommand.cpp
commands/refreshopenpgpcertscommand.cpp
commands/deletecertificatescommand.cpp
commands/decryptverifyfilescommand.cpp
commands/signencryptfilescommand.cpp
commands/encryptclipboardcommand.cpp
commands/signclipboardcommand.cpp
commands/decryptverifyclipboardcommand.cpp
commands/clearcrlcachecommand.cpp
commands/dumpcrlcachecommand.cpp
commands/dumpcertificatecommand.cpp
commands/importcrlcommand.cpp
commands/changeexpirycommand.cpp
commands/changeownertrustcommand.cpp
commands/changepassphrasecommand.cpp
commands/certifycertificatecommand.cpp
commands/selftestcommand.cpp
commands/exportsecretkeycommand.cpp
commands/exportopenpgpcertstoservercommand.cpp
commands/adduseridcommand.cpp
commands/newcertificatecommand.cpp
commands/setinitialpincommand.cpp
commands/learncardkeyscommand.cpp
${_kleopatra_uiserver_files}
conf/configuredialog.cpp
newcertificatewizard/listwidget.cpp
newcertificatewizard/newcertificatewizard.cpp
aboutdata.cpp
systrayicon.cpp
kleopatraapplication.cpp
main.cpp )
if ( KLEO_MODEL_TEST )
add_definitions( -DKLEO_MODEL_TEST )
set( _kleopatra_SRCS ${_kleopatra_SRCS} models/modeltest.cpp )
endif ( KLEO_MODEL_TEST )
kde4_add_ui_files( _kleopatra_SRCS
dialogs/certificationoptionswidget.ui
dialogs/expirydialog.ui
dialogs/lookupcertificatesdialog.ui
dialogs/ownertrustdialog.ui
dialogs/selectchecklevelwidget.ui
dialogs/selftestdialog.ui
dialogs/exportsecretkeydialog.ui
dialogs/adduseriddialog.ui
dialogs/certificatedetailsdialog.ui
dialogs/setinitialpindialog.ui
newcertificatewizard/listwidget.ui
newcertificatewizard/chooseprotocolpage.ui
newcertificatewizard/enterdetailspage.ui
newcertificatewizard/overviewpage.ui
newcertificatewizard/keycreationpage.ui
newcertificatewizard/resultpage.ui
newcertificatewizard/advancedsettingsdialog.ui
)
kde4_add_kcfg_files( _kleopatra_SRCS
kcfg/tooltippreferences.kcfgc
kcfg/emailoperationspreferences.kcfgc
kcfg/smimevalidationpreferences.kcfgc
)
if (KDEPIM_ONLY_KLEO)
add_definitions( -DKDEPIM_ONLY_KLEO -DKDEPIM_EXPORT= )
set( _kleopatra_libkdepim_SRCS
../libkdepim/progressmanager.cpp
../libkdepim/progressdialog.cpp
../libkdepim/overlaywidget.cpp
../libkdepim/ssllabel.cpp
../libkdepim/statusbarprogresswidget.cpp
)
set( _kleopatra_libkdepim_LIBS )
else(KDEPIM_ONLY_KLEO)
set( _kleopatra_libkdepim_SRCS )
set( _kleopatra_libkdepim_LIBS kdepim )
endif(KDEPIM_ONLY_KLEO)
set( _kleopatra_mainwindow_SRCS
mainwindow.cpp
)
add_definitions ( -DKDE_DEFAULT_DEBUG_AREA=5151 )
kde4_add_app_icon(_kleopatra_mainwindow_SRCS "ox*-app-kleopatra.png")
kde4_add_executable(kleopatra_bin ${_kleopatra_SRCS} ${_kleopatra_mainwindow_SRCS} ${_kleopatra_uiserver_SRCS} ${_kleopatra_libkdepim_SRCS} )
set_target_properties(kleopatra_bin PROPERTIES OUTPUT_NAME kleopatra)
set( _kleopatra_extra_libs ${QT_QT3SUPPORT_LIBRARY} )
if ( NOT KDE4_KCMUTILS_LIBS )
set( KDE4_KCMUTILS_LIBS ${KDE4_KUTILS_LIBS} )
endif ( NOT KDE4_KCMUTILS_LIBS )
target_link_libraries(kleopatra_bin ${_kleopatra_extra_libs} kleo ${QGPGME_LIBRARIES} ${KDE4_KDEUI_LIBS} ${KDE4_KMIME_LIBRARY} ${KDE4_KCMUTILS_LIBS} ${_kleopatra_uiserver_extra_libs} ${_kleopatra_libkdepim_LIBS})
if ( USABLE_ASSUAN_FOUND )
target_link_libraries(kleopatra_bin ${QT_QTNETWORK_LIBRARY})
ENDIF ( USABLE_ASSUAN_FOUND )
install(TARGETS kleopatra_bin ${INSTALL_TARGETS_DEFAULT_ARGS})
########### install files ###############
install( FILES kleopatra.desktop
kleopatra_import.desktop
DESTINATION ${XDG_APPS_INSTALL_DIR} )
install( FILES kleopatra_signencryptfiles.desktop
kleopatra_signencryptfolders.desktop
kleopatra_decryptverifyfiles.desktop
kleopatra_decryptverifyfolders.desktop
DESTINATION ${SERVICES_INSTALL_DIR} )
install( FILES kleopatra.rc DESTINATION ${DATA_INSTALL_DIR}/kleopatra )
kde4_install_icons( ${ICON_INSTALL_DIR} )
diff --git a/crypto/decryptverifyfilescontroller.cpp b/crypto/decryptverifyfilescontroller.cpp
index 1abdf7443..09b434ad3 100644
--- a/crypto/decryptverifyfilescontroller.cpp
+++ b/crypto/decryptverifyfilescontroller.cpp
@@ -1,425 +1,397 @@
/* -*- 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 <config-kleopatra.h>
#include "decryptverifyfilescontroller.h"
+
#include <crypto/gui/decryptverifyoperationwidget.h>
#include <crypto/gui/decryptverifyfileswizard.h>
#include <crypto/decryptverifytask.h>
#include <crypto/taskcollection.h>
#include <utils/classify.h>
#include <utils/gnupg-helper.h>
+#include <utils/path-helper.h>
#include <utils/input.h>
#include <utils/output.h>
#include <utils/kleo_assert.h>
#include <KDebug>
#include <KLocalizedString>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QPointer>
#include <QTimer>
#include <boost/shared_ptr.hpp>
#include <memory>
#include <vector>
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 QString heuristicBaseDirectory( const QStringList& fileNames );
static shared_ptr<AbstractDecryptVerifyTask> taskFromOperationWidget( const DecryptVerifyOperationWidget * w, const QString & fileName, const QDir & outDir, const shared_ptr<OverwritePolicy> & overwritePolicy );
explicit Private( DecryptVerifyFilesController* qq );
void slotWizardOperationPrepared();
void slotWizardCanceled();
void schedule();
QStringList prepareWizardFromPassedFiles();
std::vector<shared_ptr<Task> > buildTasks( const QStringList &, const shared_ptr<OverwritePolicy> & );
- QString heuristicBaseDirectory() const;
-
void ensureWizardCreated();
void ensureWizardVisible();
void reportError( int err, const QString & details ) {
emit q->error( err, details );
}
void cancelAllTasks();
QStringList m_passedFiles, m_filesAfterPreparation;
QPointer<DecryptVerifyFilesWizard> m_wizard;
std::vector<shared_ptr<const DecryptVerifyResult> > m_results;
std::vector<shared_ptr<Task> > m_runnableTasks, m_completedTasks;
shared_ptr<Task> m_runningTask;
bool m_errorDetected;
DecryptVerifyOperation m_operation;
};
// static
shared_ptr<AbstractDecryptVerifyTask> DecryptVerifyFilesController::Private::taskFromOperationWidget( const DecryptVerifyOperationWidget * w, const QString & fileName, const QDir & outDir, const shared_ptr<OverwritePolicy> & overwritePolicy ) {
kleo_assert( w );
shared_ptr<AbstractDecryptVerifyTask> task;
switch ( w->mode() ) {
case DecryptVerifyOperationWidget::VerifyDetachedWithSignature:
{
shared_ptr<VerifyDetachedTask> 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<VerifyDetachedTask> 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:
{
shared_ptr<DecryptVerifyTask> t( new DecryptVerifyTask );
t->setInput( Input::createFromFile( fileName ) );
t->setOutput( Output::createFromFile( outDir.absoluteFilePath( outputFileName( QFileInfo( fileName ).fileName() ) ), overwritePolicy ) );
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<VerificationResult>();
}
void DecryptVerifyFilesController::Private::slotWizardOperationPrepared()
{
try {
ensureWizardCreated();
std::vector<shared_ptr<Task> > tasks = buildTasks( m_filesAfterPreparation, shared_ptr<OverwritePolicy>( new OverwritePolicy( m_wizard ) ) );
kleo_assert( m_runnableTasks.empty() );
m_runnableTasks.swap( tasks );
shared_ptr<TaskCollection> coll( new TaskCollection );
Q_FOREACH( const shared_ptr<Task> & 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<const Task::Result> & result )
{
assert( task );
assert( task == d->m_runningTask.get() );
// 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<const DecryptVerifyResult> & dvr = boost::dynamic_pointer_cast<const DecryptVerifyResult>( 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<Task> 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<const DecryptVerifyResult> & i, m_results )
emit q->verificationResult( i->verificationResult() );
q->emitDoneOrError();
}
}
void DecryptVerifyFilesController::Private::ensureWizardCreated()
{
if ( m_wizard )
return;
std::auto_ptr<DecryptVerifyFilesWizard> 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();
}
QStringList DecryptVerifyFilesController::Private::prepareWizardFromPassedFiles()
{
ensureWizardCreated();
QStringList fileNames;
unsigned int counter = 0;
Q_FOREACH( const QString & fname, m_passedFiles ) {
kleo_assert( !fname.isEmpty() );
const unsigned int classification = classify( fname );
if ( mayBeOpaqueSignature( classification ) || mayBeCipherText( classification ) || mayBeDetachedSignature( classification ) ) {
DecryptVerifyOperationWidget * const op = m_wizard->operationWidget( counter++ );
kleo_assert( op != 0 );
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 );
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->setMode( DecryptVerifyOperationWidget::DecryptVerifyOpaque );
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->setMode( DecryptVerifyOperationWidget::VerifyDetachedWithSignedData );
op->setInputFileName( s );
op->setSignedDataFileName( fname );
fileNames.push_back( fname );
}
}
}
}
kleo_assert( counter == static_cast<unsigned>( fileNames.size() ) );
if ( !counter )
throw Kleo::Exception( makeGnuPGError( GPG_ERR_ASS_NO_INPUT ), i18n("No usable inputs found") );
- m_wizard->setOutputDirectory( heuristicBaseDirectory() );
+ m_wizard->setOutputDirectory( heuristicBaseDirectory( m_passedFiles ) );
return fileNames;
}
std::vector< shared_ptr<Task> > DecryptVerifyFilesController::Private::buildTasks( const QStringList & fileNames, const shared_ptr<OverwritePolicy> & 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<shared_ptr<Task> > 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<const ExecutionContext> & ctx, QObject* parent ) : Controller( ctx, parent ), d( new Private( this ) )
{
}
DecryptVerifyFilesController::~DecryptVerifyFilesController() { kDebug(); }
void DecryptVerifyFilesController::start()
{
d->m_filesAfterPreparation = d->prepareWizardFromPassedFiles();
d->ensureWizardVisible();
}
-static QString commonPrefix( const QString & s1, const QString & s2 ) {
- return QString( s1.data(), std::mismatch( s1.data(), s1.data() + std::min( s1.size(), s2.size() ), s2.data() ).first - s1.data() );
-}
-
-static QString longestCommonPrefix( const QStringList & sl ) {
- if ( sl.empty() )
- return QString();
- QString result = sl.front();
- Q_FOREACH( const QString & s, sl )
- result = commonPrefix( s, result );
- return result;
-}
-
-QString DecryptVerifyFilesController::Private::heuristicBaseDirectory() const {
- return heuristicBaseDirectory( m_passedFiles );
-}
-
-
-QString DecryptVerifyFilesController::Private::heuristicBaseDirectory( const QStringList& fileNames ) {
- const QString candidate = longestCommonPrefix( fileNames );
- const QFileInfo fi( candidate );
- if ( fi.isDir() )
- return candidate;
- else
- return fi.absolutePath();
-}
-
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 ) {
qDebug( "Caught exception: %s", e.what() );
}
}
#include "decryptverifyfilescontroller.moc"
diff --git a/uiserver/assuanserverconnection.cpp b/uiserver/assuanserverconnection.cpp
index 6b0aaa302..667e5a5bf 100644
--- a/uiserver/assuanserverconnection.cpp
+++ b/uiserver/assuanserverconnection.cpp
@@ -1,1459 +1,1442 @@
/* -*- mode: c++; c-basic-offset:4 -*-
uiserver/assuanserverconnection.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.
*/
#ifndef QT_NO_CAST_TO_ASCII
# define QT_NO_CAST_TO_ASCII
#endif
#ifndef QT_NO_CAST_FROM_ASCII
# define QT_NO_CAST_FROM_ASCII
#endif
#include <config-kleopatra.h>
#include <version-kleopatra.h>
#include "assuanserverconnection.h"
#include "assuancommand.h"
#include "sessiondata.h"
#include <models/keycache.h> // :(
#include <utils/input.h>
#include <utils/output.h>
#include <utils/gnupg-helper.h>
+#include <utils/path-helper.h>
#include <utils/detail_p.h>
#include <utils/hex.h>
#include <utils/log.h>
#include <utils/exception.h>
#include <utils/kleo_assert.h>
#include <utils/getpid.h>
#include <utils/stl_util.h>
#include <gpgme++/data.h>
#include <gpgme++/key.h>
#include <kmime/kmime_header_parsing.h>
#include <KLocalizedString>
#include <KWindowSystem>
#include <KMessageBox>
#include <QSocketNotifier>
#include <QTimer>
#include <QVariant>
#include <QPointer>
#include <QFileInfo>
#include <QDebug>
#include <QStringList>
#include <QDialog>
#include <QRegExp>
#include <kleo-assuan.h>
#include <boost/type_traits/remove_pointer.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/bind.hpp>
#include <boost/mem_fn.hpp>
#include <boost/mpl/if.hpp>
#include <vector>
#include <map>
#include <string>
#include <memory>
#include <algorithm>
#include <errno.h>
#ifdef __GNUC__
# include <ext/algorithm> // for is_sorted
#endif
#ifdef Q_OS_WIN32
# include <io.h>
# include <process.h>
#else
# include <sys/types.h>
# include <unistd.h>
#endif
#ifdef Q_WS_X11
# include <qx11info_x11.h>
# include <X11/Xlib.h>
#endif
using namespace Kleo;
using namespace boost;
static const unsigned int INIT_SOCKET_FLAGS = 3; // says info assuan...
//static int(*USE_DEFAULT_HANDLER)(assuan_context_t,char*) = 0;
static const int FOR_READING = 0;
static const unsigned int MAX_ACTIVE_FDS = 32;
// shared_ptr for assuan_context_t w/ deleter enforced to assuan_deinit_server:
typedef shared_ptr< remove_pointer<assuan_context_t>::type > AssuanContextBase;
struct AssuanContext : AssuanContextBase {
AssuanContext() : AssuanContextBase() {}
explicit AssuanContext( assuan_context_t ctx ) : AssuanContextBase( ctx, &assuan_deinit_server ) {}
void reset( assuan_context_t ctx=0 ) { AssuanContextBase::reset( ctx, &assuan_deinit_server ); }
};
static inline gpg_error_t assuan_process_done_msg( assuan_context_t ctx, gpg_error_t err, const char * err_msg ) {
return assuan_process_done( ctx, assuan_set_error( ctx, err, err_msg ) );
}
static inline gpg_error_t assuan_process_done_msg( assuan_context_t ctx, gpg_error_t err, const std::string & err_msg ) {
return assuan_process_done_msg( ctx, err, err_msg.c_str() );
}
static inline gpg_error_t assuan_process_done_msg( assuan_context_t ctx, gpg_error_t err, const QString & err_msg ) {
return assuan_process_done_msg( ctx, err, err_msg.toUtf8().constData() );
}
static std::map<std::string,std::string> upcase_option( const char * option, std::map<std::string,std::string> options ) {
std::string value;
bool value_found = false;
std::map<std::string,std::string>::iterator it = options.begin();
while ( it != options.end() )
if ( qstricmp( it->first.c_str(), option ) == 0 ) {
value = it->second;
options.erase( it++ );
value_found = true;
} else {
++it;
}
if ( value_found )
options[option] = value;
return options;
}
static std::map<std::string,std::string> parse_commandline( const char * line ) {
std::map<std::string,std::string> result;
if ( line ) {
const char * begin = line;
const char * lastEQ = 0;
while ( *line ) {
if ( *line == ' ' || *line == '\t' ) {
if ( begin != line ) {
if ( begin[0] == '-' && begin[1] == '-' )
begin += 2; // skip initial "--"
if ( lastEQ && lastEQ > begin )
result[ std::string( begin, lastEQ - begin ) ] = hexdecode( std::string( lastEQ+1, line - (lastEQ+1) ) );
else
result[ std::string( begin, line - begin ) ] = std::string();
}
begin = line + 1;
} else if ( *line == '=' ) {
if ( line == begin )
throw Exception( gpg_error( GPG_ERR_ASS_SYNTAX ),
i18n("No option name given") );
else
lastEQ = line;
}
++line;
}
if ( begin != line ) {
if ( begin[0] == '-' && begin[1] == '-' )
begin += 2; // skip initial "--"
if ( lastEQ && lastEQ > begin )
result[ std::string( begin, lastEQ - begin ) ] = hexdecode( std::string( lastEQ+1, line - (lastEQ+1 ) ) );
else
result[ begin ] = std::string();
}
}
return result;
}
static WId wid_from_string( const QString & winIdStr, bool * ok=0 ) {
return
#ifdef Q_OS_WIN32
reinterpret_cast<WId>
#else
static_cast<WId>
#endif
( winIdStr.toULongLong( ok, 16 ) );
}
static void apply_window_id( QWidget * widget, const QString & winIdStr ) {
if ( !widget || winIdStr.isEmpty() )
return;
bool ok = false;
const WId wid = wid_from_string( winIdStr, &ok );
if ( !ok ) {
qDebug() << "window-id value" << wid << "doesn't look like a number";
return;
}
if ( QWidget * pw = QWidget::find( wid ) )
widget->setParent( pw, widget->windowFlags() );
else {
KWindowSystem::setMainWindow( widget, wid );
}
}
//
//
// AssuanServerConnection:
//
//
class AssuanServerConnection::Private : public QObject {
Q_OBJECT
friend class ::Kleo::AssuanServerConnection;
friend class ::Kleo::AssuanCommandFactory;
friend class ::Kleo::AssuanCommand;
AssuanServerConnection * const q;
public:
Private( assuan_fd_t fd_, const std::vector< shared_ptr<AssuanCommandFactory> > & factories_, AssuanServerConnection * qq );
~Private();
Q_SIGNALS:
void startKeyManager();
public Q_SLOTS:
void slotReadActivity( int ) {
assert( ctx );
if ( const int err = assuan_process_next( ctx.get() ) ) {
//if ( err == -1 || gpg_err_code(err) == GPG_ERR_EOF ) {
topHalfDeletion();
if ( nohupedCommands.empty() )
bottomHalfDeletion();
//} else {
//assuan_process_done( ctx.get(), err );
//return;
//}
}
}
int startCommandBottomHalf();
private:
void nohupDone( AssuanCommand * cmd ) {
const std::vector< shared_ptr<AssuanCommand> >::iterator it
= std::find_if( nohupedCommands.begin(), nohupedCommands.end(),
bind( &shared_ptr<AssuanCommand>::get, _1 ) == cmd );
assert( it != nohupedCommands.end() );
nohupedCommands.erase( it );
if ( nohupedCommands.empty() && closed )
bottomHalfDeletion();
}
void commandDone( AssuanCommand * cmd ) {
if ( !cmd || cmd != currentCommand.get() )
return;
currentCommand.reset();
}
void topHalfDeletion() {
if ( currentCommand )
currentCommand->canceled();
if ( fd != ASSUAN_INVALID_FD ) {
#ifdef Q_OS_WIN32
CloseHandle( fd );
#else
::close( fd );
#endif
}
notifiers.clear();
closed = true;
}
void bottomHalfDeletion() {
if ( sessionId )
SessionDataHandler::instance()->exitSession( sessionId );
cleanup();
const QPointer<Private> that = this;
emit q->closed( q );
if ( that ) // still there
q->deleteLater();
}
private:
static void reset_handler( assuan_context_t ctx_ ) {
assert( assuan_get_pointer( ctx_ ) );
AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( ctx_ ) );
conn.reset();
}
static int option_handler( assuan_context_t ctx_, const char * key, const char * value ) {
assert( assuan_get_pointer( ctx_ ) );
AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( ctx_ ) );
if ( key && key[0] == '-' && key[1] == '-' )
key += 2; // skip "--"
conn.options[key] = QString::fromUtf8( value );
return 0;
//return gpg_error( GPG_ERR_UNKNOWN_OPTION );
}
static int session_handler( assuan_context_t ctx_, char * line ) {
assert( assuan_get_pointer( ctx_ ) );
AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( ctx_ ) );
const QString str = QString::fromUtf8( line );
QRegExp rx( QLatin1String( "(\\d+)(?:\\s+(.*))?" ) );
if ( !rx.exactMatch( str ) ) {
static const QString errorString = i18n("Parse error");
return assuan_process_done_msg( ctx_, gpg_error( GPG_ERR_ASS_SYNTAX ), errorString );
}
bool ok = false;
if ( const qulonglong id = rx.cap( 1 ).toULongLong( &ok ) ) {
if ( ok && id <= std::numeric_limits<unsigned int>::max() ) {
SessionDataHandler::instance()->enterSession( id );
conn.sessionId = id;
} else {
static const QString errorString = i18n("Parse error: numeric session id too large");
return assuan_process_done_msg( ctx_, gpg_error( GPG_ERR_ASS_SYNTAX ), errorString );
}
}
if ( !rx.cap( 2 ).isEmpty() )
conn.sessionTitle = rx.cap( 2 );
qDebug( "session_handler: id=%lu, title=%s",
static_cast<unsigned long>( conn.sessionId ), qPrintable( conn.sessionTitle ) );
return assuan_process_done( ctx_, 0 );
}
static int capabilities_handler( assuan_context_t ctx_, char * line ) {
if ( !QByteArray( line ).trimmed().isEmpty() ) {
static const QString errorString = i18n("CAPABILITIES does not take arguments");
return assuan_process_done_msg( ctx_, gpg_error( GPG_ERR_ASS_PARAMETER ), errorString );
}
static const char capabilities[] =
"SENDER=info\n"
"RECIPIENT=info\n"
"SESSION\n"
;
return assuan_process_done( ctx_, assuan_send_data( ctx_, capabilities, sizeof capabilities - 1 ) );
}
static int getinfo_handler( assuan_context_t ctx_, char * line ) {
assert( assuan_get_pointer( ctx_ ) );
AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( ctx_ ) );
if ( qstrcmp( line, "version" ) == 0 ) {
static const char version[] = "Kleopatra " KLEOPATRA_VERSION_STRING ;
return assuan_process_done( ctx_, assuan_send_data( ctx_, version, sizeof version - 1 ) );
}
QByteArray ba;
if ( qstrcmp( line, "pid" ) == 0 )
ba = QByteArray::number( mygetpid() );
else if ( qstrcmp( line, "options" ) == 0 )
ba = conn.dumpOptions();
else if ( qstrcmp( line, "x-mementos" ) == 0 )
ba = conn.dumpMementos();
else if ( qstrcmp( line, "senders" ) == 0 )
ba = conn.dumpSenders();
else if ( qstrcmp( line, "recipients" ) == 0 )
ba = conn.dumpRecipients();
else if ( qstrcmp( line, "x-files" ) == 0 )
ba = conn.dumpFiles();
else {
static const QString errorString = i18n("Unknown value for WHAT");
return assuan_process_done_msg( ctx_, gpg_error( GPG_ERR_ASS_PARAMETER ), errorString );
}
return assuan_process_done( ctx_, assuan_send_data( ctx_, ba.constData(), ba.size() ) );
}
static int start_keymanager_handler( assuan_context_t ctx_, char * line ) {
assert( assuan_get_pointer( ctx_ ) );
AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( ctx_ ) );
if ( line && *line ) {
static const QString errorString = i18n("START_KEYMANAGER does not take arguments");
return assuan_process_done_msg( ctx_, gpg_error( GPG_ERR_ASS_PARAMETER ), errorString );
}
emit conn.q->startKeyManagerRequested();
return assuan_process_done( ctx_, 0 );
}
static int start_confdialog_handler( assuan_context_t ctx_, char * line ) {
assert( assuan_get_pointer( ctx_ ) );
AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( ctx_ ) );
if ( line && *line ) {
static const QString errorString = i18n("START_CONFDIALOG does not take arguments");
return assuan_process_done_msg( ctx_, gpg_error( GPG_ERR_ASS_PARAMETER ), errorString );
}
emit conn.q->startConfigDialogRequested();
return assuan_process_done( ctx_, 0 );
}
template <bool in> struct Input_or_Output : mpl::if_c<in,Input,Output> {};
// format: TAG (FD|FD=\d+|FILE=...)
template <bool in, typename T_memptr>
static int IO_handler( assuan_context_t ctx_, char * line_, T_memptr which ) {
assert( assuan_get_pointer( ctx_ ) );
AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( ctx_ ) );
try {
/*const*/ std::map<std::string,std::string> options = upcase_option( "FD", upcase_option( "FILE", parse_commandline( line_ ) ) );
if ( options.size() < 1 || options.size() > 2 )
throw gpg_error( GPG_ERR_ASS_SYNTAX );
shared_ptr< typename Input_or_Output<in>::type > io;
if ( options.count( "FD" ) ) {
if ( options.count( "FILE" ) )
throw gpg_error( GPG_ERR_CONFLICT );
assuan_fd_t fd = ASSUAN_INVALID_FD;
const std::string fdstr = options["FD"];
if ( fdstr.empty() ) {
if ( const gpg_error_t err = assuan_receivefd( conn.ctx.get(), &fd ) )
throw err;
} else {
#ifdef Q_OS_WIN32
fd = (assuan_fd_t)lexical_cast<intptr_t>( fdstr );
#else
fd = lexical_cast<assuan_fd_t>( fdstr );
#endif
}
io = Input_or_Output<in>::type::createFromPipeDevice( fd, in ? i18n( "Message #%1", (conn.*which).size() + 1 ) : QString() );
options.erase( "FD" );
} else if ( options.count( "FILE" ) ) {
if ( options.count( "FD" ) )
throw gpg_error( GPG_ERR_CONFLICT );
const QString filePath = QFile::decodeName( options["FILE"].c_str() );
if ( filePath.isEmpty() )
throw Exception( gpg_error( GPG_ERR_ASS_SYNTAX ), i18n("Empty file path") );
const QFileInfo fi( filePath );
if ( !fi.isAbsolute() )
throw Exception( gpg_error( GPG_ERR_INV_ARG ), i18n("Only absolute file paths are allowed") );
if ( !fi.isFile() )
throw Exception( gpg_error( GPG_ERR_INV_ARG ), i18n("Only files are allowed in INPUT/OUTPUT FILE") );
else
io = Input_or_Output<in>::type::createFromFile( fi.absoluteFilePath(), true );
options.erase( "FILE" );
} else {
throw gpg_error( GPG_ERR_ASS_PARAMETER );
}
if ( options.size() )
throw gpg_error( GPG_ERR_UNKNOWN_OPTION );
(conn.*which).push_back( io );
qDebug() << "AssuanServerConnection: added" << io->label();
return assuan_process_done( conn.ctx.get(), 0 );
} catch ( const GpgME::Exception & e ) {
return assuan_process_done_msg( conn.ctx.get(), e.error().encodedError(), e.message().c_str() );
} catch ( const std::exception & ) {
return assuan_process_done( conn.ctx.get(), gpg_error( GPG_ERR_ASS_SYNTAX ) );
} catch ( const gpg_error_t e ) {
return assuan_process_done( conn.ctx.get(), e );
} catch ( ... ) {
return assuan_process_done_msg( conn.ctx.get(), gpg_error( GPG_ERR_UNEXPECTED ), "unknown exception caught" );
}
}
static int input_handler( assuan_context_t ctx, char * line ) {
return IO_handler<true>( ctx, line, &Private::inputs );
}
static int output_handler( assuan_context_t ctx, char * line ) {
return IO_handler<false>( ctx, line, &Private::outputs );
}
static int message_handler( assuan_context_t ctx, char * line ) {
return IO_handler<true>( ctx, line, &Private::messages );
}
static int file_handler( assuan_context_t ctx_, char * line ) {
assert( assuan_get_pointer( ctx_ ) );
AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( ctx_ ) );
try {
const QFileInfo fi( QFile::decodeName( hexdecode( line ).c_str() ) );
if ( !fi.isAbsolute() )
throw Exception( gpg_error( GPG_ERR_INV_ARG ), i18n("Only absolute file paths are allowed") );
if ( !fi.exists() )
throw gpg_error( GPG_ERR_ENOENT );
if ( !fi.isReadable() || fi.isDir() && !fi.isExecutable() )
throw gpg_error( GPG_ERR_EPERM );
conn.files.push_back( fi.absoluteFilePath() );
return assuan_process_done( conn.ctx.get(), 0 );
} catch ( const Exception & e ) {
return assuan_process_done_msg( conn.ctx.get(), e.error().encodedError(), e.message().toUtf8().constData() );
} catch ( const gpg_error_t e ) {
return assuan_process_done( conn.ctx.get(), e );
} catch ( ... ) {
return assuan_process_done_msg( conn.ctx.get(), gpg_error( GPG_ERR_UNEXPECTED ), i18n("unknown exception caught").toUtf8().constData() );
}
}
static bool parse_informative( const char * & begin, GpgME::Protocol & protocol ) {
protocol = GpgME::UnknownProtocol;
bool informative = false;
const char * pos = begin;
while ( true ) {
while ( *pos == ' ' || *pos == '\t' )
++pos;
if ( qstrnicmp( pos, "--info", strlen("--info") ) == 0 ) {
informative = true;
pos += strlen("--info");
if ( *pos == '=' ) {
++pos;
break;
}
} else if ( qstrnicmp( pos, "--protocol=", strlen("--protocol=") ) == 0 ) {
pos += strlen("--protocol=");
if ( qstrnicmp( pos, "OpenPGP", strlen("OpenPGP") ) == 0 ) {
protocol = GpgME::OpenPGP;
pos += strlen("OpenPGP");
} else if ( qstrnicmp( pos, "CMS", strlen("CMS") ) == 0 ) {
protocol = GpgME::CMS;
pos += strlen("CMS");
} else
;
} else if ( qstrncmp( pos, "-- ", strlen("-- ") ) == 0 ) {
pos += 3;
while ( *pos == ' ' || *pos == '\t' )
++pos;
break;
} else
break;
}
begin = pos;
return informative;
}
template <typename T_memptr, typename T_memptr2>
static int recipient_sender_handler( T_memptr mp, T_memptr2 info, assuan_context_t ctx, char * line, bool sender=false ) {
assert( assuan_get_pointer( ctx ) );
AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( ctx ) );
if ( !line || !*line )
return assuan_process_done( conn.ctx.get(), gpg_error( GPG_ERR_INV_ARG ) );
const char * begin = line;
const char * const end = begin + qstrlen( line );
GpgME::Protocol proto = GpgME::UnknownProtocol;
const bool informative = parse_informative( begin, proto );
if ( !(conn.*mp).empty() && informative != (conn.*info) )
return assuan_process_done_msg( conn.ctx.get(), gpg_error( GPG_ERR_CONFLICT ),
i18n("Cannot mix --info with non-info SENDER or RECIPIENT").toUtf8().constData() );
KMime::Types::Mailbox mb;
if ( !KMime::HeaderParsing::parseMailbox( begin, end, mb ) )
return assuan_process_done_msg( conn.ctx.get(), gpg_error( GPG_ERR_INV_ARG ),
i18n("Argument is not a valid RFC-2822 mailbox").toUtf8().constData() );
if ( begin != end )
return assuan_process_done_msg( conn.ctx.get(), gpg_error( GPG_ERR_INV_ARG ),
i18n("Garbage after valid RFC-2822 mailbox detected").toUtf8().constData() );
(conn.*info) = informative;
(conn.*mp).push_back( mb );
// ### we should wait for the KeyCache to become ready here,
// ### but we don't have time anymore to turn SENDER into a
// ### command, so we just ignore this for now:
const QString email = mb.addrSpec().asString();
(void)assuan_write_line( conn.ctx.get(), qPrintable( QString().sprintf( "# ok, parsed as \"%s\"", qPrintable( email ) ) ) );
if ( sender && !informative ) {
const std::vector<GpgME::Key> seckeys =
kdtools::copy_if<std::vector<GpgME::Key> >( KeyCache::instance()->findByEMailAddress( email.toStdString() ),
mem_fn( &GpgME::Key::hasSecret ) );
if ( seckeys.empty() )
(void)assuan_write_line( conn.ctx.get(), "# no matching keys found" );
else
Q_FOREACH( const GpgME::Key & key, seckeys )
(void)assuan_write_line( conn.ctx.get(), qPrintable( QString().sprintf( "# matching %s key %s", key.protocolAsString(), key.primaryFingerprint() ) ) );
const bool pgp = proto != GpgME::CMS && kdtools::any( seckeys, bind( &GpgME::Key::protocol, _1 ) == GpgME::OpenPGP );
const bool cms = proto != GpgME::OpenPGP && kdtools::any( seckeys, bind( &GpgME::Key::protocol, _1 ) == GpgME::CMS );
if ( cms != pgp )
proto = pgp ? GpgME::OpenPGP : GpgME::CMS ;
if ( cms && pgp )
if ( conn.bias != GpgME::UnknownProtocol ) {
proto = conn.bias;
} else {
if ( conn.options.count("window-id") )
proto =
KMessageBox::questionYesNoWId( wid_from_string( conn.options["window-id"].toString() ),
i18nc("@info",
"<para>The sender address <email>%1</email> matches more than one cryptographic format.</para>"
"<para>Which format do you want to use?</para>", email ),
i18nc("@title","Format Choice"),
KGuiItem( i18nc("@action:button","Send OpenPGP-Signed") ),
KGuiItem( i18nc("@action:button","Send S/MIME-Signed") ),
QLatin1String("uiserver-sender-ask-protocol") ) == KMessageBox::Yes
? GpgME::OpenPGP
: GpgME::CMS ;
else
proto =
KMessageBox::questionYesNo( 0, i18nc("@info",
"<para>The sender address <email>%1</email> matches more than one cryptographic format.</para>"
"<para>Which format do you want to use?</para>", email ),
i18nc("@title","Format Choice"),
KGuiItem( i18nc("@action:button","Send OpenPGP-Signed") ),
KGuiItem( i18nc("@action:button","Send S/MIME-Signed") ),
QLatin1String("uiserver-sender-ask-protocol") ) == KMessageBox::Yes
? GpgME::OpenPGP
: GpgME::CMS ;
}
conn.bias = proto;
switch ( proto ) {
case GpgME::OpenPGP:
(void)assuan_write_status( conn.ctx.get(), "PROTOCOL", "OpenPGP" );
break;
case GpgME::CMS:
(void)assuan_write_status( conn.ctx.get(), "PROTOCOL", "CMS" );
break;
case GpgME::UnknownProtocol:
; // keep compiler happy
};
}
return assuan_process_done( ctx, 0 );
}
static int recipient_handler( assuan_context_t ctx, char * line ) {
return recipient_sender_handler( &Private::recipients, &Private::informativeRecipients, ctx, line );
}
static int sender_handler( assuan_context_t ctx, char * line ) {
return recipient_sender_handler( &Private::senders, &Private::informativeSenders, ctx, line, true );
}
QByteArray dumpOptions() const {
QByteArray result;
for ( std::map<std::string,QVariant>::const_iterator it = options.begin(), end = options.end() ; it != end ; ++it )
result += it->first.c_str() + it->second.toString().toUtf8() + '\n';
return result;
}
static QByteArray dumpStringList( const QStringList & sl ) {
return sl.join( QLatin1String( "\n" ) ).toUtf8();
}
template <typename T_container>
static QByteArray dumpStringList( const T_container & c ) {
QStringList sl;
std::copy( c.begin(), c.end(), std::back_inserter( sl ) );
return dumpStringList( sl );
}
template <typename T_container>
static QByteArray dumpMailboxes( const T_container & c ) {
QStringList sl;
std::transform( c.begin(), c.end(),
std::back_inserter( sl ),
bind( &KMime::Types::Mailbox::prettyAddress, _1 ) );
return dumpStringList( sl );
}
QByteArray dumpSenders() const {
return dumpMailboxes( senders );
}
QByteArray dumpRecipients() const {
return dumpMailboxes( recipients );
}
QByteArray dumpMementos() const {
QByteArray result;
for ( std::map< QByteArray, shared_ptr<AssuanCommand::Memento> >::const_iterator it = mementos.begin(), end = mementos.end() ; it != end ; ++it ) {
char buf[2 + 2*sizeof(void*) + 2];
sprintf( buf, "0x%p\n", ( void* )it->second.get() );
buf[sizeof(buf)-1] = '\0';
result += it->first + QByteArray::fromRawData( buf, sizeof buf );
}
return result;
}
QByteArray dumpFiles() const {
return dumpStringList( kdtools::copy<QStringList>( files ) );
}
void cleanup();
void reset() {
options.clear();
senders.clear();
informativeSenders = false;
recipients.clear();
informativeRecipients = false;
sessionTitle.clear();
sessionId = 0;
mementos.clear();
files.clear();
std::for_each( inputs.begin(), inputs.end(),
bind( &Input::finalize, _1 ) );
inputs.clear();
std::for_each( outputs.begin(), outputs.end(),
bind( &Output::finalize, _1 ) );
outputs.clear();
std::for_each( messages.begin(), messages.end(),
bind( &Input::finalize, _1 ) );
messages.clear();
bias = GpgME::UnknownProtocol;
}
assuan_fd_t fd;
AssuanContext ctx;
bool closed : 1;
bool cryptoCommandsEnabled : 1;
bool commandWaitingForCryptoCommandsEnabled : 1;
bool currentCommandIsNohup : 1;
bool informativeSenders; // address taken, so no : 1
bool informativeRecipients; // address taken, so no : 1
GpgME::Protocol bias;
QString sessionTitle;
unsigned int sessionId;
std::vector< shared_ptr<QSocketNotifier> > notifiers;
std::vector< shared_ptr<AssuanCommandFactory> > factories; // sorted: _detail::ByName<std::less>
shared_ptr<AssuanCommand> currentCommand;
std::vector< shared_ptr<AssuanCommand> > nohupedCommands;
std::map<std::string,QVariant> options;
std::vector<KMime::Types::Mailbox> senders, recipients;
std::vector< shared_ptr<Input> > inputs, messages;
std::vector< shared_ptr<Output> > outputs;
std::vector<QString> files;
std::map< QByteArray, shared_ptr<AssuanCommand::Memento> > mementos;
};
void AssuanServerConnection::Private::cleanup() {
assert( nohupedCommands.empty() );
reset();
currentCommand.reset();
currentCommandIsNohup = false;
commandWaitingForCryptoCommandsEnabled = false;
notifiers.clear();
ctx.reset();
fd = ASSUAN_INVALID_FD;
}
AssuanServerConnection::Private::Private( assuan_fd_t fd_, const std::vector< shared_ptr<AssuanCommandFactory> > & factories_, AssuanServerConnection * qq )
: QObject(),
q( qq ),
fd( fd_ ),
closed( false ),
cryptoCommandsEnabled( false ),
commandWaitingForCryptoCommandsEnabled( false ),
currentCommandIsNohup( false ),
informativeSenders( false ),
informativeRecipients( false ),
bias( GpgME::UnknownProtocol ),
sessionId( 0 ),
factories( factories_ )
{
#ifdef __GNUC__
assert( __gnu_cxx::is_sorted( factories_.begin(), factories_.end(), _detail::ByName<std::less>() ) );
#endif
if ( fd == ASSUAN_INVALID_FD )
throw Exception( gpg_error( GPG_ERR_INV_ARG ), "pre-assuan_init_socket_server_ext" );
assuan_context_t naked_ctx = 0;
if ( const gpg_error_t err = assuan_init_socket_server_ext( &naked_ctx, fd, INIT_SOCKET_FLAGS ) )
throw Exception( err, "assuan_init_socket_server_ext" );
ctx.reset( naked_ctx ); naked_ctx = 0;
// for callbacks, associate the context with this connection:
assuan_set_pointer( ctx.get(), this );
FILE* const logFile = Log::instance()->logFile();
assuan_set_log_stream( ctx.get(), logFile ? logFile : stderr );
// register FDs with the event loop:
assuan_fd_t fds[MAX_ACTIVE_FDS];
const int numFDs = assuan_get_active_fds( ctx.get(), FOR_READING, fds, MAX_ACTIVE_FDS );
assert( numFDs != -1 ); // == 1
if ( !numFDs || fds[0] != fd ) {
const shared_ptr<QSocketNotifier> sn( new QSocketNotifier( (int)fd, QSocketNotifier::Read ), mem_fn( &QObject::deleteLater ) );
connect( sn.get(), SIGNAL(activated(int)), this, SLOT(slotReadActivity(int)) );
notifiers.push_back( sn );
}
notifiers.reserve( notifiers.size() + numFDs );
for ( int i = 0 ; i < numFDs ; ++i ) {
const shared_ptr<QSocketNotifier> sn( new QSocketNotifier( (int)fds[i], QSocketNotifier::Read ), mem_fn( &QObject::deleteLater ) );
connect( sn.get(), SIGNAL(activated(int)), this, SLOT(slotReadActivity(int)) );
notifiers.push_back( sn );
}
// register our INPUT/OUTPUT/MESSGAE/FILE handlers:
if ( const gpg_error_t err = assuan_register_command( ctx.get(), "INPUT", input_handler ) )
throw Exception( err, "register \"INPUT\" handler" );
if ( const gpg_error_t err = assuan_register_command( ctx.get(), "MESSAGE", message_handler ) )
throw Exception( err, "register \"MESSAGE\" handler" );
if ( const gpg_error_t err = assuan_register_command( ctx.get(), "OUTPUT", output_handler ) )
throw Exception( err, "register \"OUTPUT\" handler" );
if ( const gpg_error_t err = assuan_register_command( ctx.get(), "FILE", file_handler ) )
throw Exception( err, "register \"FILE\" handler" );
// register user-defined commands:
Q_FOREACH( shared_ptr<AssuanCommandFactory> fac, factories )
if ( const gpg_error_t err = assuan_register_command( ctx.get(), fac->name(), fac->_handler() ) )
throw Exception( err, std::string( "register \"" ) + fac->name() + "\" handler" );
if ( const gpg_error_t err = assuan_register_command( ctx.get(), "GETINFO", getinfo_handler ) )
throw Exception( err, "register \"GETINFO\" handler" );
if ( const gpg_error_t err = assuan_register_command( ctx.get(), "START_KEYMANAGER", start_keymanager_handler ) )
throw Exception( err, "register \"START_KEYMANAGER\" handler" );
if ( const gpg_error_t err = assuan_register_command( ctx.get(), "START_CONFDIALOG", start_confdialog_handler ) )
throw Exception( err, "register \"START_CONFDIALOG\" handler" );
if ( const gpg_error_t err = assuan_register_command( ctx.get(), "RECIPIENT", recipient_handler ) )
throw Exception( err, "register \"RECIPIENT\" handler" );
if ( const gpg_error_t err = assuan_register_command( ctx.get(), "SENDER", sender_handler ) )
throw Exception( err, "register \"SENDER\" handler" );
if ( const gpg_error_t err = assuan_register_command( ctx.get(), "SESSION", session_handler ) )
throw Exception( err, "register \"SESSION\" handler" );
if ( const gpg_error_t err = assuan_register_command( ctx.get(), "CAPABILITIES", capabilities_handler ) )
throw Exception( err, "register \"CAPABILITIES\" handler" );
assuan_set_hello_line( ctx.get(), "GPG UI server (Kleopatra/" KLEOPATRA_VERSION_STRING ") ready to serve" );
//assuan_set_hello_line( ctx.get(), GPG UI server (qApp->applicationName() + " v" + kapp->applicationVersion() + "ready to serve" )
// some notifiers we're interested in:
if ( const gpg_error_t err = assuan_register_reset_notify( ctx.get(), reset_handler ) )
throw Exception( err, "register reset notify" );
if ( const gpg_error_t err = assuan_register_option_handler( ctx.get(), option_handler ) )
throw Exception( err, "register option handler" );
// and last, we need to call assuan_accept, which doesn't block
// (d/t INIT_SOCKET_FLAGS), but performs vital connection
// establishing handling:
if ( const gpg_error_t err = assuan_accept( ctx.get() ) )
throw Exception( err, "assuan_accept" );
}
AssuanServerConnection::Private::~Private() {
cleanup();
}
AssuanServerConnection::AssuanServerConnection( assuan_fd_t fd, const std::vector< shared_ptr<AssuanCommandFactory> > & factories, QObject * p )
: QObject( p ), d( new Private( fd, factories, this ) )
{
}
AssuanServerConnection::~AssuanServerConnection() {}
void AssuanServerConnection::enableCryptoCommands( bool on ) {
if ( on == d->cryptoCommandsEnabled )
return;
d->cryptoCommandsEnabled = on;
if ( d->commandWaitingForCryptoCommandsEnabled )
QTimer::singleShot( 0, d.get(), SLOT(startCommandBottomHalf()) );
}
//
//
// AssuanCommand:
//
//
namespace Kleo {
class InquiryHandler : public QObject {
Q_OBJECT
public:
#ifdef HAVE_ASSUAN_INQUIRE_EXT
explicit InquiryHandler( const char * keyword_, QObject * p=0 )
: QObject( p ),
# ifndef HAVE_NEW_STYLE_ASSUAN_INQUIRE_EXT
buffer( 0 ),
buflen( 0 ),
# endif
keyword( keyword_ )
{
}
# ifdef HAVE_NEW_STYLE_ASSUAN_INQUIRE_EXT
static int handler( void * cb_data, int rc, unsigned char * buffer, size_t buflen )
{
assert( cb_data );
InquiryHandler * this_ = static_cast<InquiryHandler*>(cb_data);
emit this_->signal( rc, QByteArray::fromRawData( reinterpret_cast<const char*>(buffer), buflen ), this_->keyword );
std::free( buffer );
delete this_;
return 0;
}
# else
static int handler( void * cb_data, int rc )
{
assert( cb_data );
InquiryHandler * this_ = static_cast<InquiryHandler*>(cb_data);
emit this_->signal( rc, QByteArray::fromRawData( reinterpret_cast<const char*>(this_->buffer), this_->buflen ), this_->keyword );
std::free( this_->buffer );
delete this_;
return 0;
}
# endif
private:
# ifndef HAVE_NEW_STYLE_ASSUAN_INQUIRE_EXT
friend class ::Kleo::AssuanCommand;
unsigned char * buffer;
size_t buflen;
# endif
const char * keyword;
#endif // HAVE_ASSUAN_INQUIRE_EXT
Q_SIGNALS:
void signal( int rc, const QByteArray & data, const QByteArray & keyword );
};
} // namespace Kleo
class AssuanCommand::Private {
public:
Private()
: informativeRecipients( false ),
informativeSenders( false ),
bias( GpgME::UnknownProtocol ),
done( false ),
nohup( false )
{
}
std::map<std::string,QVariant> options;
std::vector< shared_ptr<Input> > inputs, messages;
std::vector< shared_ptr<Output> > outputs;
std::vector<QString> files;
std::vector<KMime::Types::Mailbox> recipients, senders;
bool informativeRecipients, informativeSenders;
GpgME::Protocol bias;
QString sessionTitle;
unsigned int sessionId;
QByteArray utf8ErrorKeepAlive;
AssuanContext ctx;
bool done;
bool nohup;
};
AssuanCommand::AssuanCommand()
: d( new Private )
{
}
AssuanCommand::~AssuanCommand() {
}
int AssuanCommand::start() {
try {
if ( const int err = doStart() )
if ( !d->done )
done( err );
return 0;
} catch ( const Exception & e ) {
if ( !d->done )
done( e.error_code(), e.message() );
return 0;
} catch ( const GpgME::Exception & e ) {
if ( !d->done )
done( e.error(), QString::fromLocal8Bit( e.message().c_str() ) );
return 0;
} catch ( const std::exception & e ) {
if ( !d->done )
done( makeError( GPG_ERR_INTERNAL ), i18n("Caught unexpected exception: %1", QString::fromLocal8Bit( e.what() ) ) );
return 0;
} catch ( ... ) {
if ( !d->done )
done( makeError( GPG_ERR_INTERNAL ), i18n("Caught unknown exception - please report this error to the developers." ) );
return 0;
}
}
void AssuanCommand::canceled() {
d->done = true;
doCanceled();
}
// static
int AssuanCommand::makeError( int code ) {
return makeGnuPGError( code );
}
bool AssuanCommand::hasOption( const char * opt ) const {
return d->options.count( opt );
}
QVariant AssuanCommand::option( const char * opt ) const {
const std::map<std::string,QVariant>::const_iterator it = d->options.find( opt );
if ( it == d->options.end() )
return QVariant();
else
return it->second;
}
const std::map<std::string,QVariant> & AssuanCommand::options() const {
return d->options;
}
namespace {
template <typename U, typename V>
std::vector<U> keys( const std::map<U,V> & map ) {
std::vector<U> result;
result.resize( map.size() );
for ( typename std::map<U,V>::const_iterator it = map.begin(), end = map.end() ; it != end ; ++it )
result.push_back( it->first );
return result;
}
}
const std::map< QByteArray, shared_ptr<AssuanCommand::Memento> > & AssuanCommand::mementos() const {
// oh, hack :(
assert( assuan_get_pointer( d->ctx.get() ) );
const AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( d->ctx.get() ) );
return conn.mementos;
}
bool AssuanCommand::hasMemento( const QByteArray & tag ) const {
if ( const unsigned int id = sessionId() )
return SessionDataHandler::instance()->sessionData(id)->mementos.count( tag ) || mementos().count( tag ) ;
else
return mementos().count( tag );
}
shared_ptr<AssuanCommand::Memento> AssuanCommand::memento( const QByteArray & tag ) const {
if ( const unsigned int id = sessionId() ) {
const shared_ptr<SessionDataHandler> sdh = SessionDataHandler::instance();
const shared_ptr<SessionData> sd = sdh->sessionData(id);
const std::map< QByteArray, shared_ptr<Memento> >::const_iterator it = sd->mementos.find( tag );
if ( it != sd->mementos.end() )
return it->second;
}
const std::map< QByteArray, shared_ptr<Memento> >::const_iterator it = mementos().find( tag );
if ( it == mementos().end() )
return shared_ptr<Memento>();
else
return it->second;
}
QByteArray AssuanCommand::registerMemento( const shared_ptr<Memento> & mem ) {
const QByteArray tag = QByteArray::number( reinterpret_cast<qulonglong>( mem.get() ), 36 );
return registerMemento( tag, mem );
}
QByteArray AssuanCommand::registerMemento( const QByteArray & tag, const shared_ptr<Memento> & mem ) {
// oh, hack :(
assert( assuan_get_pointer( d->ctx.get() ) );
AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( d->ctx.get() ) );
if ( const unsigned int id = sessionId() )
SessionDataHandler::instance()->sessionData(id)->mementos[tag] = mem;
else
conn.mementos[tag] = mem;
return tag;
}
void AssuanCommand::removeMemento( const QByteArray & tag ) {
// oh, hack :(
assert( assuan_get_pointer( d->ctx.get() ) );
AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( d->ctx.get() ) );
conn.mementos.erase( tag );
if ( const unsigned int id = sessionId() )
SessionDataHandler::instance()->sessionData(id)->mementos.erase( tag );
}
const std::vector< shared_ptr<Input> > & AssuanCommand::inputs() const {
return d->inputs;
}
const std::vector< shared_ptr<Input> > & AssuanCommand::messages() const {
return d->messages;
}
const std::vector< shared_ptr<Output> > & AssuanCommand::outputs() const {
return d->outputs;
}
QStringList AssuanCommand::fileNames() const {
return kdtools::copy<QStringList>( d->files );
}
unsigned int AssuanCommand::numFiles() const {
return d->files.size();
}
void AssuanCommand::sendStatus( const char * keyword, const QString & text ) {
sendStatusEncoded( keyword, text.toUtf8().constData() );
}
void AssuanCommand::sendStatusEncoded( const char * keyword, const std::string & text ) {
if ( d->nohup )
return;
if ( const int err = assuan_write_status( d->ctx.get(), keyword, text.c_str() ) )
throw Exception( err, i18n( "Can not send \"%1\" status", QString::fromLatin1( keyword ) ) );
}
void AssuanCommand::sendData( const QByteArray & data, bool moreToCome ) {
if ( d->nohup )
return;
if ( const gpg_error_t err = assuan_send_data( d->ctx.get(), data.constData(), data.size() ) )
throw Exception( err, i18n( "Can not send data" ) );
if ( !moreToCome )
if ( const gpg_error_t err = assuan_send_data( d->ctx.get(), 0, 0 ) ) // flush
throw Exception( err, i18n( "Can not flush data" ) );
}
int AssuanCommand::inquire( const char * keyword, QObject * receiver, const char * slot, unsigned int maxSize ) {
assert( keyword );
assert( receiver );
assert( slot );
if ( d->nohup )
return makeError( GPG_ERR_INV_OP );
#ifdef HAVE_ASSUAN_INQUIRE_EXT
std::auto_ptr<InquiryHandler> ih( new InquiryHandler( keyword, receiver ) );
receiver->connect( ih.get(), SIGNAL(signal(int,QByteArray,QByteArray)), slot );
if ( const gpg_error_t err = assuan_inquire_ext( d->ctx.get(), keyword,
# ifndef HAVE_NEW_STYLE_ASSUAN_INQUIRE_EXT
&ih->buffer, &ih->buflen,
# endif
maxSize, InquiryHandler::handler, ih.get() ) )
return err;
ih.release();
return 0;
#else
return makeError( GPG_ERR_NOT_SUPPORTED ); // libassuan too old
#endif // HAVE_ASSUAN_INQUIRE_EXT
}
void AssuanCommand::done( const GpgME::Error& err, const QString & details ) {
if ( d->ctx && !d->done && !details.isEmpty() ) {
qDebug() << "AssuanCommand::done(): Error: " << details;
d->utf8ErrorKeepAlive = details.toUtf8();
if ( !d->nohup )
assuan_set_error( d->ctx.get(), err.encodedError(), d->utf8ErrorKeepAlive.constData() );
}
done( err );
}
void AssuanCommand::done( const GpgME::Error& err ) {
if ( !d->ctx ) {
qDebug( "AssuanCommand::done( %s ): called with NULL ctx.", err.asString() );
return;
}
if ( d->done ) {
qDebug( "AssuanCommand::done( %s ): called twice!", err.asString() );
return;
}
d->done = true;
std::for_each( d->messages.begin(), d->messages.end(),
bind( &Input::finalize, _1 ) );
std::for_each( d->inputs.begin(), d->inputs.end(),
bind( &Input::finalize, _1 ) );
std::for_each( d->outputs.begin(), d->outputs.end(),
bind( &Output::finalize, _1 ) );
d->messages.clear();
d->inputs.clear();
d->outputs.clear();
d->files.clear();
// oh, hack :(
assert( assuan_get_pointer( d->ctx.get() ) );
AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( d->ctx.get() ) );
if ( d->nohup ) {
conn.nohupDone( this );
return;
}
const gpg_error_t rc = assuan_process_done( d->ctx.get(), err.encodedError() );
if ( gpg_err_code( rc ) != GPG_ERR_NO_ERROR )
qFatal( "AssuanCommand::done: assuan_process_done returned error %d (%s)",
static_cast<int>(rc), gpg_strerror(rc) );
d->utf8ErrorKeepAlive.clear();
conn.commandDone( this );
}
void AssuanCommand::setNohup( bool nohup ) {
d->nohup = nohup;
}
bool AssuanCommand::isNohup() const {
return d->nohup;
}
bool AssuanCommand::isDone() const {
return d->done;
}
QString AssuanCommand::sessionTitle() const {
return d->sessionTitle;
}
unsigned int AssuanCommand::sessionId() const {
return d->sessionId;
}
bool AssuanCommand::informativeSenders() const {
return d->informativeSenders;
}
bool AssuanCommand::informativeRecipients() const {
return d->informativeRecipients;
}
const std::vector<KMime::Types::Mailbox> & AssuanCommand::recipients() const {
return d->recipients;
}
const std::vector<KMime::Types::Mailbox> & AssuanCommand::senders() const {
return d->senders;
}
int AssuanCommandFactory::_handle( assuan_context_t ctx, char * line, const char * commandName ) {
assert( assuan_get_pointer( ctx ) );
AssuanServerConnection::Private & conn = *static_cast<AssuanServerConnection::Private*>( assuan_get_pointer( ctx ) );
try {
const std::vector< shared_ptr<AssuanCommandFactory> >::const_iterator it
= std::lower_bound( conn.factories.begin(), conn.factories.end(), commandName, _detail::ByName<std::less>() );
kleo_assert( it != conn.factories.end() );
kleo_assert( *it );
kleo_assert( qstricmp( (*it)->name(), commandName ) == 0 );
const shared_ptr<AssuanCommand> cmd = (*it)->create();
kleo_assert( cmd );
cmd->d->ctx = conn.ctx;
cmd->d->options = conn.options;
cmd->d->inputs.swap( conn.inputs ); kleo_assert( conn.inputs.empty() );
cmd->d->messages.swap( conn.messages ); kleo_assert( conn.messages.empty() );
cmd->d->outputs.swap( conn.outputs ); kleo_assert( conn.outputs.empty() );
cmd->d->files.swap( conn.files ); kleo_assert( conn.files.empty() );
cmd->d->senders.swap( conn.senders ); kleo_assert( conn.senders.empty() );
cmd->d->recipients.swap( conn.recipients ); kleo_assert( conn.recipients.empty() );
cmd->d->informativeRecipients = conn.informativeRecipients;
cmd->d->informativeSenders = conn.informativeSenders;
cmd->d->bias = conn.bias;
cmd->d->sessionTitle = conn.sessionTitle;
cmd->d->sessionId = conn.sessionId;
const std::map<std::string,std::string> cmdline_options = parse_commandline( line );
for ( std::map<std::string,std::string>::const_iterator it = cmdline_options.begin(), end = cmdline_options.end() ; it != end ; ++it )
cmd->d->options[it->first] = QString::fromUtf8( it->second.c_str() );
bool nohup = false;
if ( cmd->d->options.count( "nohup" ) ) {
if ( !cmd->d->options["nohup"].toString().isEmpty() )
return assuan_process_done_msg( conn.ctx.get(), gpg_error( GPG_ERR_ASS_PARAMETER ), "--nohup takes no argument" );
nohup = true;
cmd->d->options.erase( "nohup" );
}
conn.currentCommand = cmd;
conn.currentCommandIsNohup = nohup;
QTimer::singleShot( 0, &conn, SLOT(startCommandBottomHalf()) );
return 0;
} catch ( const Exception & e ) {
return assuan_process_done_msg( conn.ctx.get(), e.error_code(), e.message() );
} catch ( const std::exception & e ) {
return assuan_process_done_msg( conn.ctx.get(), gpg_error( GPG_ERR_UNEXPECTED ), e.what() );
} catch ( ... ) {
return assuan_process_done_msg( conn.ctx.get(), gpg_error( GPG_ERR_UNEXPECTED ), i18n("Caught unknown exception") );
}
}
int AssuanServerConnection::Private::startCommandBottomHalf() {
commandWaitingForCryptoCommandsEnabled = currentCommand && !cryptoCommandsEnabled;
if ( !cryptoCommandsEnabled )
return 0;
const shared_ptr<AssuanCommand> cmd = currentCommand;
if ( !cmd )
return 0;
currentCommand.reset();
const bool nohup = currentCommandIsNohup;
currentCommandIsNohup = false;
try {
if ( const int err = cmd->start() )
if ( cmd->isDone() )
return err;
else
return assuan_process_done( ctx.get(), err );
if ( cmd->isDone() )
return 0;
if ( nohup ) {
cmd->setNohup( true );
nohupedCommands.push_back( cmd );
return assuan_process_done_msg( ctx.get(), 0, "Command put in the background to continue executing after connection end." );
} else {
currentCommand = cmd;
return 0;
}
} catch ( const Exception & e ) {
return assuan_process_done_msg( ctx.get(), e.error_code(), e.message() );
} catch ( const std::exception & e ) {
return assuan_process_done_msg( ctx.get(), gpg_error( GPG_ERR_UNEXPECTED ), e.what() );
} catch ( ... ) {
return assuan_process_done_msg( ctx.get(), gpg_error( GPG_ERR_UNEXPECTED ), i18n("Caught unknown exception") );
}
}
//
//
// AssuanCommand convenience methods
//
//
/*!
Checks the \c --mode parameter.
\returns The parameter as an AssuanCommand::Mode enum value.
If no \c --mode was given, or it's value wasn't recognized, throws
an Kleo::Exception.
*/
AssuanCommand::Mode AssuanCommand::checkMode() const {
if ( !hasOption( "mode" ) )
throw Exception( makeError( GPG_ERR_MISSING_VALUE ), i18n( "Required --mode option missing" ) );
const QString modeString = option("mode").toString().toLower();
if ( modeString == QLatin1String( "filemanager" ) )
return FileManager;
if ( modeString == QLatin1String( "email" ) )
return EMail;
throw Exception( makeError( GPG_ERR_INV_ARG ), i18n( "invalid mode: \"%1\"", modeString ) );
}
/*!
Checks the \c --protocol parameter.
\returns The parameter as a GpgME::Protocol enum value.
If \c --protocol was given, but has an invalid value, throws an
Kleo::Exception.
If no \c --protocol was given, checks the connection bias, if
available, otherwise, in FileManager mode, returns
GpgME::UnknownProtocol, but if \a mode == \c EMail, throws an
Kleo::Exception instead.
*/
GpgME::Protocol AssuanCommand::checkProtocol( Mode mode, int options ) const {
if ( !hasOption("protocol") )
if ( d->bias != GpgME::UnknownProtocol )
return d->bias;
else if ( mode == AssuanCommand::EMail && ( options & AllowProtocolMissing ) == 0 )
throw Exception( makeError( GPG_ERR_MISSING_VALUE ), i18n( "Required --protocol option missing" ) );
else
return GpgME::UnknownProtocol;
else
if ( mode == AssuanCommand::FileManager )
throw Exception( makeError( GPG_ERR_INV_FLAG ), i18n("--protocol is not allowed here") );
const QString protocolString = option("protocol").toString().toLower();
if ( protocolString == QLatin1String( "openpgp" ) )
return GpgME::OpenPGP;
if ( protocolString == QLatin1String( "cms" ) )
return GpgME::CMS;
throw Exception( makeError( GPG_ERR_INV_ARG ), i18n( "invalid protocol \"%1\"", protocolString ) );
}
void AssuanCommand::doApplyWindowID( QWidget * widget ) const {
if ( !widget || !hasOption( "window-id" ) )
return;
apply_window_id( widget, option("window-id").toString() );
}
WId AssuanCommand::parentWId() const {
return wid_from_string( option("window-id").toString() );
}
-static QString commonPrefix( const QString & s1, const QString & s2 ) {
- return QString( s1.data(), std::mismatch( s1.data(), s1.data() + std::min( s1.size(), s2.size() ), s2.data() ).first - s1.data() );
-}
-
-static QString longestCommonPrefix( const QStringList & sl ) {
- if ( sl.empty() )
- return QString();
- QString result = sl.front();
- Q_FOREACH( const QString & s, sl )
- result = commonPrefix( s, result );
- return result;
-}
-
QString AssuanCommand::heuristicBaseDirectory() const {
- const QString candidate = longestCommonPrefix( fileNames() );
- const QFileInfo fi( candidate );
- if ( fi.isDir() )
- return candidate;
- else
- return fi.absolutePath();
+ return Kleo::heuristicBaseDirectory( fileNames() );
}
#include "assuanserverconnection.moc"
#include "moc_assuanserverconnection.cpp"
diff --git a/utils/path-helper.cpp b/utils/path-helper.cpp
new file mode 100644
index 000000000..2750229e4
--- /dev/null
+++ b/utils/path-helper.cpp
@@ -0,0 +1,86 @@
+/* -*- mode: c++; c-basic-offset:4 -*-
+ utils/path-helper.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 <config-kleopatra.h>
+
+#include "path-helper.h"
+
+#include <utils/stl_util.h>
+
+#include <QString>
+#include <QStringList>
+#include <QFileInfo>
+#include <QDir>
+
+#include <boost/bind.hpp>
+
+#include <algorithm>
+
+using namespace Kleo;
+using namespace boost;
+
+static QString commonPrefix( const QString & s1, const QString & s2 ) {
+ return QString( s1.data(), std::mismatch( s1.data(), s1.data() + std::min( s1.size(), s2.size() ), s2.data() ).first - s1.data() );
+}
+
+static QString longestCommonPrefix( const QStringList & sl ) {
+ if ( sl.empty() )
+ return QString();
+ QString result = sl.front();
+ Q_FOREACH( const QString & s, sl )
+ result = commonPrefix( s, result );
+ return result;
+}
+
+QString Kleo::heuristicBaseDirectory( const QStringList & fileNames ) {
+ const QString candidate = longestCommonPrefix( fileNames );
+ const QFileInfo fi( candidate );
+ if ( fi.isDir() )
+ return candidate;
+ else
+ return fi.absolutePath();
+}
+
+QStringList Kleo::makeRelativeTo( const QString & base, const QStringList & fileNames ) {
+
+ if ( base.isEmpty() )
+ return fileNames;
+ else
+ return makeRelativeTo( QDir( base ), fileNames );
+
+}
+
+QStringList Kleo::makeRelativeTo( const QDir & baseDir, const QStringList & fileNames ) {
+ return kdtools::transform<QStringList>
+ ( fileNames,
+ bind( &QDir::relativeFilePath, &baseDir, _1 ) );
+}
diff --git a/utils/path-helper.h b/utils/path-helper.h
new file mode 100644
index 000000000..799fb2a0d
--- /dev/null
+++ b/utils/path-helper.h
@@ -0,0 +1,47 @@
+/* -*- mode: c++; c-basic-offset:4 -*-
+ utils/path-helper.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_UTILS_PATH_HELPER_H__
+#define __KLEOPATRA_UTILS_PATH_HELPER_H__
+
+class QString;
+class QStringList;
+class QDir;
+
+namespace Kleo {
+
+ QString heuristicBaseDirectory( const QStringList & files );
+ QStringList makeRelativeTo( const QDir & dir, const QStringList & files );
+ QStringList makeRelativeTo( const QString & dir, const QStringList & files );
+}
+
+#endif /* __KLEOPATRA_UTILS_PATH_HELPER_H__ */

File Metadata

Mime Type
text/x-diff
Expires
Thu, Jul 17, 1:15 AM (13 h, 48 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
ab/b1/05c6e942483c79326b5f277c0fea

Event Timeline