32 #ifndef QT_NO_CAST_TO_ASCII 
   33 # define QT_NO_CAST_TO_ASCII 
   35 #ifndef QT_NO_CAST_FROM_ASCII 
   36 # define QT_NO_CAST_FROM_ASCII 
   39 #include <config-kleopatra.h> 
   40 #include <version-kleopatra.h> 
   57 #include <kleo/stl_util.h> 
   58 #include <kleo/exception.h> 
   60 #include <gpgme++/data.h> 
   61 #include <gpgme++/key.h> 
   63 #include <kmime/kmime_header_parsing.h> 
   66 #include <KLocalizedString> 
   67 #include <KWindowSystem> 
   68 #include <KMessageBox> 
   70 #include <QSocketNotifier> 
   75 #include <QStringList> 
   81 #ifndef Q_MOC_RUN // QTBUG-22829 
   82 #include <boost/type_traits/remove_pointer.hpp> 
   84 #include <boost/lexical_cast.hpp> 
   86 #include <boost/bind.hpp> 
   87 #include <boost/mem_fn.hpp> 
   88 #include <boost/mpl/if.hpp> 
  100 # include <ext/algorithm>  
  105 # include <process.h> 
  107 # include <sys/types.h> 
  112 # include <qx11info_x11.h> 
  113 # include <X11/Xlib.h> 
  116 using namespace Kleo;
 
  117 using namespace boost;
 
  125 static void my_assuan_release( assuan_context_t ctx ) {
 
  127         assuan_release( ctx );
 
  136     explicit AssuanContext( assuan_context_t ctx ) : 
AssuanContextBase( ctx, &assuan_deinit_server ) {}
 
  138     explicit AssuanContext( assuan_context_t ctx ) : 
AssuanContextBase( ctx, &my_assuan_release ) {}
 
  142     void reset( assuan_context_t ctx=0 ) { AssuanContextBase::reset( ctx, &assuan_deinit_server ); }
 
  144     void reset( assuan_context_t ctx=0 ) { AssuanContextBase::reset( ctx, &my_assuan_release ); }
 
  149     return assuan_process_done( ctx, assuan_set_error( ctx, err, err_msg ) );
 
  160 static std::map<std::string,std::string> 
upcase_option( 
const char * 
option, std::map<std::string,std::string> options ) {
 
  162     bool value_found = 
false;
 
  163     std::map<std::string,std::string>::iterator it = options.begin();
 
  164     while ( it != options.end() )
 
  165         if ( qstricmp( it->first.c_str(), 
option ) == 0 ) {
 
  167             options.erase( it++ );
 
  178     std::map<std::string,std::string> result;
 
  180         const char * begin = line;
 
  181         const char * lastEQ = 0;
 
  183             if ( *line == 
' ' || *line == 
'\t' ) {
 
  184                 if ( begin != line ) {
 
  185                     if ( begin[0] == 
'-' && begin[1] == 
'-' )
 
  187                     if ( lastEQ && lastEQ > begin )
 
  193             } 
else if ( *line == 
'=' ) {
 
  195                     throw Exception( gpg_error( GPG_ERR_ASS_SYNTAX ),
 
  196                                      i18n(
"No option name given") );
 
  202         if ( begin != line ) {
 
  203             if ( begin[0] == 
'-' && begin[1] == 
'-' )
 
  205             if ( lastEQ && lastEQ > begin )
 
  217 #if defined(Q_OS_WIN32) || defined(_WIN32_WCE) 
  218         reinterpret_cast<WId
> 
  222              ( winIdStr.toULongLong( ok, 16 ) );
 
  226     if ( !widget || winIdStr.isEmpty() )
 
  231         kDebug() << 
"window-id value" << wid << 
"doesn't look like a number";
 
  234     if ( 
QWidget * pw = QWidget::find( wid ) )
 
  235         widget->setParent( pw, widget->windowFlags() );
 
  237         KWindowSystem::setMainWindow( widget, wid );
 
  247 class AssuanServerConnection::Private : 
public QObject {
 
  249     friend class ::Kleo::AssuanServerConnection;
 
  250     friend class ::Kleo::AssuanCommandFactory;
 
  251     friend class ::Kleo::AssuanCommand;
 
  258     void startKeyManager();
 
  261     void slotReadActivity( 
int ) {
 
  264         if ( 
const int err = assuan_process_next( ctx.get() ) ) {
 
  267         if ( 
const int err = assuan_process_next( ctx.get(), &done ) || done ) {
 
  271                 if ( nohupedCommands.empty() )
 
  272                     bottomHalfDeletion();
 
  280     int startCommandBottomHalf();
 
  284         const std::vector< shared_ptr<AssuanCommand> >::iterator it
 
  285             = std::find_if( nohupedCommands.begin(), nohupedCommands.end(),
 
  287         assert( it != nohupedCommands.end() );
 
  288         nohupedCommands.erase( it );
 
  289         if ( nohupedCommands.empty() && closed )
 
  290             bottomHalfDeletion();
 
  294         if ( !cmd || cmd != currentCommand.get() )
 
  296         currentCommand.reset();
 
  299     void topHalfDeletion() {
 
  300         if ( currentCommand )
 
  301             currentCommand->canceled();
 
  304             CloseHandle( (HANDLE)fd );
 
  305 #elif defined(Q_OS_WIN32) 
  315     void bottomHalfDeletion() {
 
  319         const QPointer<Private> that = 
this;
 
  327     static void reset_handler( assuan_context_t ctx_ ) {
 
  329     static gpg_error_t reset_handler( assuan_context_t ctx_, 
char * ) {
 
  331         assert( assuan_get_pointer( ctx_ ) );
 
  333         AssuanServerConnection::Private & conn = *
static_cast<AssuanServerConnection::Private*
>( assuan_get_pointer( ctx_ ) );
 
  343     static int option_handler( assuan_context_t ctx_, 
const char * key, 
const char * value ) {
 
  345     static gpg_error_t option_handler( assuan_context_t ctx_, 
const char * key, 
const char * value ) {
 
  347         assert( assuan_get_pointer( ctx_ ) );
 
  349         AssuanServerConnection::Private & conn = *
static_cast<AssuanServerConnection::Private*
>( assuan_get_pointer( ctx_ ) );
 
  351         if ( key && key[0] == 
'-' && key[1] == 
'-' )
 
  353         conn.options[key] = QString::fromUtf8( value );
 
  360     static int session_handler( assuan_context_t ctx_, 
char * line ) {
 
  362     static gpg_error_t session_handler( assuan_context_t ctx_, 
char * line ) {
 
  364         assert( assuan_get_pointer( ctx_ ) );
 
  365         AssuanServerConnection::Private & conn = *
static_cast<AssuanServerConnection::Private*
>( assuan_get_pointer( ctx_ ) );
 
  367         const QString str = QString::fromUtf8( line );
 
  368         QRegExp rx( QLatin1String( 
"(\\d+)(?:\\s+(.*))?" ) );
 
  369         if ( !rx.exactMatch( str ) ) {
 
  370             static const QString errorString = i18n(
"Parse error");
 
  374         if ( 
const qulonglong 
id = rx.cap( 1 ).toULongLong( &ok ) ) {
 
  375             if ( ok && 
id <= std::numeric_limits<unsigned int>::max() ) {
 
  379                 static const QString errorString = i18n(
"Parse error: numeric session id too large");
 
  383         if ( !rx.cap( 2 ).isEmpty() )
 
  384             conn.sessionTitle = rx.cap( 2 );
 
  385         kDebug() << 
"session_handler: " 
  386                  << 
"id=" << 
static_cast<unsigned long>( conn.sessionId )
 
  387                  << 
", title=" << qPrintable( conn.sessionTitle );
 
  388         return assuan_process_done( ctx_, 0 );
 
  392     static int capabilities_handler( assuan_context_t ctx_, 
char * line ) {
 
  394     static gpg_error_t capabilities_handler( assuan_context_t ctx_, 
char * line ) {
 
  396         if ( !QByteArray( line ).trimmed().isEmpty() ) {
 
  397             static const QString errorString = i18n(
"CAPABILITIES does not take arguments");
 
  400         static const char capabilities[] =
 
  405         return assuan_process_done( ctx_, assuan_send_data( ctx_, capabilities, 
sizeof capabilities - 1 ) );
 
  409     static int getinfo_handler( assuan_context_t ctx_, 
char * line ) {
 
  411     static gpg_error_t getinfo_handler( assuan_context_t ctx_, 
char * line ) {
 
  413         assert( assuan_get_pointer( ctx_ ) );
 
  414         AssuanServerConnection::Private & conn = *
static_cast<AssuanServerConnection::Private*
>( assuan_get_pointer( ctx_ ) );
 
  416         if ( qstrcmp( line, 
"version" ) == 0 ) {
 
  417             static const char version[] = 
"Kleopatra " KLEOPATRA_VERSION_STRING ;
 
  418             return assuan_process_done( ctx_, assuan_send_data( ctx_, version, 
sizeof version - 1 ) );
 
  422         if ( qstrcmp( line, 
"pid" ) == 0 )
 
  423             ba = QByteArray::number( 
mygetpid() );
 
  424         else if ( qstrcmp( line, 
"options" ) == 0 )
 
  425             ba = conn.dumpOptions();
 
  426         else if ( qstrcmp( line, 
"x-mementos" ) == 0 )
 
  427             ba = conn.dumpMementos();
 
  428         else if ( qstrcmp( line, 
"senders" ) == 0 )
 
  429             ba = conn.dumpSenders();
 
  430         else if ( qstrcmp( line, 
"recipients" ) == 0 )
 
  431             ba = conn.dumpRecipients();
 
  432         else if ( qstrcmp( line, 
"x-files" ) == 0 )
 
  433             ba = conn.dumpFiles();
 
  435             static const QString errorString = i18n(
"Unknown value for WHAT");
 
  438         return assuan_process_done( ctx_, assuan_send_data( ctx_, ba.constData(), ba.size() ) );
 
  442     static int start_keymanager_handler( assuan_context_t ctx_, 
char * line ) {
 
  444     static gpg_error_t start_keymanager_handler( assuan_context_t ctx_, 
char * line ) {
 
  446         assert( assuan_get_pointer( ctx_ ) );
 
  447         AssuanServerConnection::Private & conn = *
static_cast<AssuanServerConnection::Private*
>( assuan_get_pointer( ctx_ ) );
 
  449         if ( line && *line ) {
 
  450             static const QString errorString = i18n(
"START_KEYMANAGER does not take arguments");
 
  454         emit conn.q->startKeyManagerRequested();
 
  456         return assuan_process_done( ctx_, 0 );
 
  460     static int start_confdialog_handler( assuan_context_t ctx_, 
char * line ) {
 
  462     static gpg_error_t start_confdialog_handler( assuan_context_t ctx_, 
char * line ) {
 
  464         assert( assuan_get_pointer( ctx_ ) );
 
  465         AssuanServerConnection::Private & conn = *
static_cast<AssuanServerConnection::Private*
>( assuan_get_pointer( ctx_ ) );
 
  467         if ( line && *line ) {
 
  468             static const QString errorString = i18n(
"START_CONFDIALOG does not take arguments");
 
  472         emit conn.q->startConfigDialogRequested();
 
  474         return assuan_process_done( ctx_, 0 );
 
  477     template <
bool in> 
struct Input_or_Output : mpl::if_c<in,Input,Output> {};
 
  480     template <
bool in, 
typename T_memptr>
 
  482     static int IO_handler( assuan_context_t ctx_, 
char * line_, T_memptr which ) {
 
  484     static gpg_error_t IO_handler( assuan_context_t ctx_, 
char * line_, T_memptr which ) {
 
  486         assert( assuan_get_pointer( ctx_ ) );
 
  487         AssuanServerConnection::Private & conn = *
static_cast<AssuanServerConnection::Private*
>( assuan_get_pointer( ctx_ ) );
 
  489         char *binOpt = strstr ( line_, 
"--binary" );
 
  491         if ( binOpt && !in ) {
 
  495             memset (binOpt, 
' ', 8 );
 
  501             if ( options.size() < 1 || options.size() > 2 )
 
  502                 throw gpg_error( GPG_ERR_ASS_SYNTAX );
 
  506             if ( options.count( 
"FD" ) ) {
 
  508                 if ( options.count( 
"FILE" ) )
 
  509                     throw gpg_error( GPG_ERR_CONFLICT );
 
  515                 if ( fdstr.empty() ) {
 
  516                     if ( 
const gpg_error_t err = assuan_receivefd( conn.ctx.get(), &fd ) )
 
  521 #elif defined(Q_OS_WIN32) 
  528                 io = Input_or_Output<in>::type::createFromPipeDevice( fd, in ? i18n( 
"Message #%1", (conn.*which).size() + 1 ) : QString() );
 
  530                 options.erase( 
"FD" );
 
  532             } 
else if ( options.count( 
"FILE" ) ) {
 
  534                 if ( options.count( 
"FD" ) )
 
  535                     throw gpg_error( GPG_ERR_CONFLICT );
 
  537                 const QString filePath = QFile::decodeName( options[
"FILE"].c_str() );
 
  538                 if ( filePath.isEmpty() )
 
  539                     throw Exception( gpg_error( GPG_ERR_ASS_SYNTAX ), i18n(
"Empty file path") );
 
  540                 const QFileInfo fi( filePath );
 
  541                 if ( !fi.isAbsolute() )
 
  542                     throw Exception( gpg_error( GPG_ERR_INV_ARG ), i18n(
"Only absolute file paths are allowed") );
 
  544                     throw Exception( gpg_error( GPG_ERR_INV_ARG ), i18n(
"Only files are allowed in INPUT/OUTPUT FILE") );
 
  546                     io = Input_or_Output<in>::type::createFromFile( fi.absoluteFilePath(), true );
 
  548                 options.erase( 
"FILE" );
 
  552                 throw gpg_error( GPG_ERR_ASS_PARAMETER );
 
  556             if ( options.size() )
 
  557                 throw gpg_error( GPG_ERR_UNKNOWN_OPTION );
 
  559             (conn.*which).push_back( io );
 
  561             if ( binOpt && !in ) {
 
  564                 kDebug() << 
"Configured output for binary data";
 
  567             kDebug() << 
"AssuanServerConnection: added" << io->label();
 
  569             return assuan_process_done( conn.ctx.get(), 0 );
 
  570         } 
catch ( 
const GpgME::Exception & e ) {
 
  572         } 
catch ( 
const std::exception & ) {
 
  573             return assuan_process_done( conn.ctx.get(), gpg_error( GPG_ERR_ASS_SYNTAX ) );
 
  574         } 
catch ( 
const gpg_error_t e ) {
 
  575             return assuan_process_done( conn.ctx.get(), e );
 
  583     static int input_handler( assuan_context_t ctx, 
char * line ) {
 
  585     static gpg_error_t input_handler( assuan_context_t ctx, 
char * line ) {
 
  587         return IO_handler<true>( ctx, line, &Private::inputs );
 
  591     static int output_handler( assuan_context_t ctx, 
char * line ) {
 
  593     static gpg_error_t output_handler( assuan_context_t ctx, 
char * line ) {
 
  595         return IO_handler<false>( ctx, line, &Private::outputs );
 
  599     static int message_handler( assuan_context_t ctx, 
char * line ) {
 
  601     static gpg_error_t message_handler( assuan_context_t ctx, 
char * line ) {
 
  603         return IO_handler<true>( ctx, line, &Private::messages );
 
  607     static int file_handler( assuan_context_t ctx_, 
char * line ) {
 
  609     static gpg_error_t file_handler( assuan_context_t ctx_, 
char * line ) {
 
  611         assert( assuan_get_pointer( ctx_ ) );
 
  612         AssuanServerConnection::Private & conn = *
static_cast<AssuanServerConnection::Private*
>( assuan_get_pointer( ctx_ ) );
 
  615             const QFileInfo fi( QFile::decodeName( 
hexdecode( line ).c_str() ) );
 
  616             if ( !fi.isAbsolute() )
 
  617                 throw Exception( gpg_error( GPG_ERR_INV_ARG ), i18n(
"Only absolute file paths are allowed") );
 
  619                 throw gpg_error( GPG_ERR_ENOENT );
 
  620             if ( !fi.isReadable() || ( fi.isDir() && !fi.isExecutable() ) )
 
  621                 throw gpg_error( GPG_ERR_EPERM );
 
  623             conn.files.push_back( fi.absoluteFilePath() );
 
  625             return assuan_process_done( conn.ctx.get(), 0 );
 
  626         } 
catch ( 
const Exception & e ) {
 
  628         } 
catch ( 
const gpg_error_t e ) {
 
  629             return assuan_process_done( conn.ctx.get(), e );
 
  631             return assuan_process_done_msg( conn.ctx.get(), gpg_error( GPG_ERR_UNEXPECTED ), i18n(
"unknown exception caught").toUtf8().constData() );
 
  635     static bool parse_informative( 
const char * & begin, GpgME::Protocol & protocol ) {
 
  636         protocol = GpgME::UnknownProtocol;
 
  637         bool informative = 
false;
 
  638         const char * pos = begin;
 
  640             while ( *pos == 
' ' || *pos == 
'\t' )
 
  642             if ( qstrnicmp( pos, 
"--info", strlen(
"--info") ) == 0 ) {
 
  644                 pos += strlen(
"--info");
 
  649             } 
else if ( qstrnicmp( pos, 
"--protocol=", strlen(
"--protocol=") ) == 0 ) {
 
  650                 pos += strlen(
"--protocol=");
 
  651                 if ( qstrnicmp( pos, 
"OpenPGP", strlen(
"OpenPGP") ) == 0 ) {
 
  653                     pos += strlen(
"OpenPGP");
 
  654                 } 
else if ( qstrnicmp( pos, 
"CMS", strlen(
"CMS") ) == 0 ) {
 
  656                     pos += strlen(
"CMS");
 
  660             } 
else if ( qstrncmp( pos, 
"-- ", strlen(
"-- ") ) == 0 ) {
 
  662                 while ( *pos == 
' ' || *pos == 
'\t' )
 
  672     template <
typename T_memptr, 
typename T_memptr2>
 
  674     static int recipient_sender_handler( T_memptr mp, T_memptr2 info, assuan_context_t ctx, 
char * line, 
bool sender=
false ) {
 
  676     static gpg_error_t recipient_sender_handler( T_memptr mp, T_memptr2 info, assuan_context_t ctx, 
char * line, 
bool sender=
false ) {
 
  678         assert( assuan_get_pointer( ctx ) );
 
  679         AssuanServerConnection::Private & conn = *
static_cast<AssuanServerConnection::Private*
>( assuan_get_pointer( ctx ) );
 
  681         if ( !line || !*line )
 
  682             return assuan_process_done( conn.ctx.get(), gpg_error( GPG_ERR_INV_ARG ) );
 
  683         const char * begin     = line;
 
  684         const char * 
const end = begin + qstrlen( line );
 
  685         GpgME::Protocol proto = GpgME::UnknownProtocol;
 
  686         const bool informative = parse_informative( begin, proto );
 
  687         if ( !(conn.*mp).empty() && informative != (conn.*info) )
 
  689                                             i18n(
"Cannot mix --info with non-info SENDER or RECIPIENT").toUtf8().constData() );
 
  690         KMime::Types::Mailbox mb;
 
  691         if ( !KMime::HeaderParsing::parseMailbox( begin, end, mb ) )
 
  693                                             i18n(
"Argument is not a valid RFC-2822 mailbox").toUtf8().constData() );
 
  696                                             i18n(
"Garbage after valid RFC-2822 mailbox detected").toUtf8().constData() );
 
  697         (conn.*info) = informative;
 
  698         (conn.*mp).push_back( mb );
 
  700         const QString 
email = mb.addrSpec().asString();
 
  701         (void)assuan_write_line( conn.ctx.get(), qPrintable( QString().sprintf( 
"# ok, parsed as \"%s\"", qPrintable( email ) ) ) );
 
  702         if ( sender && !informative )
 
  705             return assuan_process_done( ctx, 0 );
 
  709     static int recipient_handler( assuan_context_t ctx, 
char * line ) {
 
  711     static gpg_error_t recipient_handler( assuan_context_t ctx, 
char * line ) {
 
  713         return recipient_sender_handler( &Private::recipients, &Private::informativeRecipients, ctx, line );
 
  717     static int sender_handler( assuan_context_t ctx, 
char * line ) {
 
  719     static gpg_error_t sender_handler( assuan_context_t ctx, 
char * line ) {
 
  721         return recipient_sender_handler( &Private::senders, &Private::informativeSenders, ctx, line, 
true );
 
  724     QByteArray dumpOptions()
 const {
 
  726         for ( std::map<std::string,QVariant>::const_iterator it = options.begin(), end = options.end() ; it != end ; ++it )
 
  727             result += it->first.c_str() + it->second.toString().toUtf8() + 
'\n';
 
  731     static QByteArray dumpStringList( 
const QStringList & sl ) {
 
  732         return sl.join( QLatin1String( 
"\n" ) ).toUtf8();
 
  735     template <
typename T_container>
 
  736     static QByteArray dumpStringList( 
const T_container & c ) {
 
  738         std::copy( c.begin(), c.end(), std::back_inserter( sl ) );
 
  739         return dumpStringList( sl );
 
  742     template <
typename T_container>
 
  743     static QByteArray dumpMailboxes( 
const T_container & c ) {
 
  745         std::transform( c.begin(), c.end(),
 
  746                         std::back_inserter( sl ),
 
  747                         boost::bind( &KMime::Types::Mailbox::prettyAddress, _1 ) );
 
  748         return dumpStringList( sl );
 
  751     QByteArray dumpSenders()
 const {
 
  752         return dumpMailboxes( senders );
 
  755     QByteArray dumpRecipients()
 const {
 
  756         return dumpMailboxes( recipients );
 
  759     QByteArray dumpMementos()
 const {
 
  762             char buf[2 + 2*
sizeof(
void*) + 2];
 
  763             sprintf( buf, 
"0x%p\n", ( 
void* )it->second.get() );
 
  764             buf[
sizeof(buf)-1] = 
'\0';
 
  765             result += it->first + QByteArray::fromRawData( buf, 
sizeof buf );
 
  770     QByteArray dumpFiles()
 const {
 
  771         return dumpStringList( kdtools::copy<QStringList>( files ) );
 
  778         informativeSenders = 
false;
 
  780         informativeRecipients = 
false;
 
  781         sessionTitle.clear();
 
  785         std::for_each( inputs.begin(), inputs.end(),
 
  788         std::for_each( outputs.begin(), outputs.end(),
 
  791         std::for_each( messages.begin(), messages.end(),
 
  794         bias = GpgME::UnknownProtocol;
 
  800     bool cryptoCommandsEnabled : 1;
 
  801     bool commandWaitingForCryptoCommandsEnabled : 1;
 
  802     bool currentCommandIsNohup : 1;
 
  803     bool informativeSenders;    
 
  804     bool informativeRecipients; 
 
  805     GpgME::Protocol bias;
 
  806     QString sessionTitle;
 
  807     unsigned int sessionId;
 
  808     std::vector< shared_ptr<QSocketNotifier> > notifiers;
 
  809     std::vector< shared_ptr<AssuanCommandFactory> > factories; 
 
  811     std::vector< shared_ptr<AssuanCommand> > nohupedCommands;
 
  812     std::map<std::string,QVariant> options;
 
  813     std::vector<KMime::Types::Mailbox> senders, recipients;
 
  814     std::vector< shared_ptr<Input> > inputs, messages;
 
  815     std::vector< shared_ptr<Output> > outputs;
 
  816     std::vector<QString> files;
 
  817     std::map< QByteArray, shared_ptr<AssuanCommand::Memento> > mementos;
 
  820 void AssuanServerConnection::Private::cleanup() {
 
  821     assert( nohupedCommands.empty() );
 
  823     currentCommand.reset();
 
  824     currentCommandIsNohup = 
false;
 
  825     commandWaitingForCryptoCommandsEnabled = 
false;
 
  836       cryptoCommandsEnabled( false ),
 
  837       commandWaitingForCryptoCommandsEnabled( false ),
 
  838       currentCommandIsNohup( false ),
 
  839       informativeSenders( false ),
 
  840       informativeRecipients( false ),
 
  841       bias( GpgME::UnknownProtocol ),
 
  843       factories( factories_ )
 
  850         throw Exception( gpg_error( GPG_ERR_INV_ARG ), 
"pre-assuan_init_socket_server_ext" );
 
  853     assuan_context_t naked_ctx = 0;
 
  854     if ( 
const gpg_error_t err = assuan_init_socket_server_ext( &naked_ctx, fd, 
INIT_SOCKET_FLAGS ) )
 
  857         assuan_context_t naked_ctx = 0;
 
  858         if ( 
const gpg_error_t err = assuan_new( &naked_ctx ) )
 
  859             throw Exception( err, 
"assuan_new" );
 
  860         ctx.reset( naked_ctx );
 
  862     if ( 
const gpg_error_t err = assuan_init_socket_server( ctx.get(), fd, 
INIT_SOCKET_FLAGS ) )
 
  864         throw Exception( err, 
"assuan_init_socket_server_ext" );
 
  867     ctx.reset( naked_ctx ); naked_ctx = 0;
 
  871     assuan_set_pointer( ctx.get(), this );
 
  873     FILE* 
const logFile = Log::instance()->logFile();
 
  874     assuan_set_log_stream( ctx.get(), logFile ? logFile : stderr );
 
  879     assert( numFDs != -1 ); 
 
  881     if ( !numFDs || fds[0] != fd ) {
 
  882         const shared_ptr<QSocketNotifier> sn( 
new QSocketNotifier( (intptr_t)fd, QSocketNotifier::Read ), mem_fn( &QObject::deleteLater ) );
 
  883         connect( sn.get(), SIGNAL(activated(
int)), 
this, SLOT(slotReadActivity(
int)) );
 
  884         notifiers.push_back( sn );
 
  887     notifiers.reserve( notifiers.size() + numFDs );
 
  888     for ( 
int i = 0 ; i < numFDs ; ++i ) {
 
  889         const shared_ptr<QSocketNotifier> sn( 
new QSocketNotifier( (intptr_t)fds[i], QSocketNotifier::Read ), mem_fn( &QObject::deleteLater ) );
 
  890         connect( sn.get(), SIGNAL(activated(
int)), 
this, SLOT(slotReadActivity(
int)) );
 
  891         notifiers.push_back( sn );
 
  897     if ( 
const gpg_error_t err = assuan_register_command( ctx.get(), 
"INPUT",  input_handler ) )
 
  899     if ( 
const gpg_error_t err = assuan_register_command( ctx.get(), 
"INPUT",  input_handler, 
"" ) )
 
  901         throw Exception( err, 
"register \"INPUT\" handler" );
 
  903     if ( 
const gpg_error_t err = assuan_register_command( ctx.get(), 
"MESSAGE",  message_handler ) )
 
  905     if ( 
const gpg_error_t err = assuan_register_command( ctx.get(), 
"MESSAGE",  message_handler, 
"" ) )
 
  907         throw Exception( err, 
"register \"MESSAGE\" handler" );
 
  909     if ( 
const gpg_error_t err = assuan_register_command( ctx.get(), 
"OUTPUT", output_handler ) )
 
  911     if ( 
const gpg_error_t err = assuan_register_command( ctx.get(), 
"OUTPUT", output_handler, 
"" ) )
 
  913         throw Exception( err, 
"register \"OUTPUT\" handler" );
 
  915     if ( 
const gpg_error_t err = assuan_register_command( ctx.get(), 
"FILE", file_handler ) )
 
  917     if ( 
const gpg_error_t err = assuan_register_command( ctx.get(), 
"FILE", file_handler, 
"" ) )
 
  919         throw Exception( err, 
"register \"FILE\" handler" );
 
  925         if ( 
const gpg_error_t err = assuan_register_command( ctx.get(), fac->name(), fac->_handler() ) )
 
  927         if ( 
const gpg_error_t err = assuan_register_command( ctx.get(), fac->name(), fac->_handler(), 
"" ) )
 
  929             throw Exception( err, 
std::string( 
"register \"" ) + fac->name() + 
"\" handler" );
 
  932     if ( 
const gpg_error_t err = assuan_register_command( ctx.get(), 
"GETINFO", getinfo_handler ) )
 
  934     if ( 
const gpg_error_t err = assuan_register_command( ctx.get(), 
"GETINFO", getinfo_handler, 
"" ) )
 
  936         throw Exception( err, 
"register \"GETINFO\" handler" );
 
  938     if ( 
const gpg_error_t err = assuan_register_command( ctx.get(), 
"START_KEYMANAGER", start_keymanager_handler ) )
 
  940     if ( 
const gpg_error_t err = assuan_register_command( ctx.get(), 
"START_KEYMANAGER", start_keymanager_handler, 
"" ) )
 
  942         throw Exception( err, 
"register \"START_KEYMANAGER\" handler" );
 
  944     if ( 
const gpg_error_t err = assuan_register_command( ctx.get(), 
"START_CONFDIALOG", start_confdialog_handler ) )
 
  946     if ( 
const gpg_error_t err = assuan_register_command( ctx.get(), 
"START_CONFDIALOG", start_confdialog_handler, 
"" ) )
 
  948         throw Exception( err, 
"register \"START_CONFDIALOG\" handler" );
 
  950     if ( 
const gpg_error_t err = assuan_register_command( ctx.get(), 
"RECIPIENT", recipient_handler ) )
 
  952     if ( 
const gpg_error_t err = assuan_register_command( ctx.get(), 
"RECIPIENT", recipient_handler, 
"" ) )
 
  954         throw Exception( err, 
"register \"RECIPIENT\" handler" );
 
  956     if ( 
const gpg_error_t err = assuan_register_command( ctx.get(), 
"SENDER", sender_handler ) )
 
  958     if ( 
const gpg_error_t err = assuan_register_command( ctx.get(), 
"SENDER", sender_handler, 
"" ) )
 
  960         throw Exception( err, 
"register \"SENDER\" handler" );
 
  962     if ( 
const gpg_error_t err = assuan_register_command( ctx.get(), 
"SESSION", session_handler ) )
 
  964     if ( 
const gpg_error_t err = assuan_register_command( ctx.get(), 
"SESSION", session_handler, 
"" ) )
 
  966         throw Exception( err, 
"register \"SESSION\" handler" );
 
  968     if ( 
const gpg_error_t err = assuan_register_command( ctx.get(), 
"CAPABILITIES", capabilities_handler ) )
 
  970     if ( 
const gpg_error_t err = assuan_register_command( ctx.get(), 
"CAPABILITIES", capabilities_handler, 
"" ) )
 
  972         throw Exception( err, 
"register \"CAPABILITIES\" handler" );
 
  974     assuan_set_hello_line( ctx.get(), 
"GPG UI server (Kleopatra/" KLEOPATRA_VERSION_STRING 
") ready to serve" );
 
  979     if ( 
const gpg_error_t err = assuan_register_reset_notify( ctx.get(), reset_handler ) )
 
  980         throw Exception( err, 
"register reset notify" );
 
  981     if ( 
const gpg_error_t err = assuan_register_option_handler( ctx.get(), option_handler ) )
 
  982         throw Exception( err, 
"register option handler" );
 
  987     if ( 
const gpg_error_t err = assuan_accept( ctx.get() ) )
 
  988         throw Exception( err, 
"assuan_accept" );
 
  991 AssuanServerConnection::Private::~Private() {
 
  996     : QObject( p ), 
d( new Private( fd, factories, this ) )
 
 1004     if ( on == d->cryptoCommandsEnabled )
 
 1006     d->cryptoCommandsEnabled = on;
 
 1007     if ( d->commandWaitingForCryptoCommandsEnabled )
 
 1008         QTimer::singleShot( 0, d.
get(), SLOT(startCommandBottomHalf()) );
 
 1020 class InquiryHandler : 
public QObject {
 
 1024 #if defined(HAVE_ASSUAN2) || defined(HAVE_ASSUAN_INQUIRE_EXT) 
 1025     explicit InquiryHandler( 
const char * keyword_, QObject * p=0 )
 
 1027 # if !defined(HAVE_ASSUAN2) && !defined(HAVE_NEW_STYLE_ASSUAN_INQUIRE_EXT)
 
 1036 # if defined(HAVE_ASSUAN2) || defined(HAVE_NEW_STYLE_ASSUAN_INQUIRE_EXT) 
 1037 #  ifndef HAVE_ASSUAN2 
 1038     static int handler( 
void * cb_data, 
int rc, 
unsigned char * buffer, 
size_t buflen )
 
 1040     static gpg_error_t handler( 
void * cb_data, gpg_error_t rc, 
unsigned char * buffer, 
size_t buflen )
 
 1044         InquiryHandler * this_ = 
static_cast<InquiryHandler*
>(cb_data);
 
 1045         emit this_->signal( rc, QByteArray::fromRawData( reinterpret_cast<const char*>(buffer), buflen ), this_->keyword );
 
 1046         std::free( buffer );
 
 1051     static int handler( 
void * cb_data, 
int rc )
 
 1054         InquiryHandler * this_ = 
static_cast<InquiryHandler*
>(cb_data);
 
 1055         emit this_->signal( rc, QByteArray::fromRawData( reinterpret_cast<const char*>(this_->buffer), this_->buflen ), this_->keyword );
 
 1056         std::free( this_->buffer );
 
 1063 #if !defined(HAVE_ASSUAN2) && !defined(HAVE_NEW_STYLE_ASSUAN_INQUIRE_EXT) 
 1064     friend class ::Kleo::AssuanCommand;
 
 1065     unsigned char * buffer;
 
 1068     const char * keyword;
 
 1069 #endif // defined(HAVE_ASSUAN2) || defined(HAVE_ASSUAN_INQUIRE_EXT) 
 1072     void signal( 
int rc, 
const QByteArray & data, 
const QByteArray & keyword );
 
 1077 class AssuanCommand::Private {
 
 1082           bias( GpgME::UnknownProtocol ),
 
 1089     std::map<std::string,QVariant> 
options;
 
 1091     std::vector< shared_ptr<Output> > 
outputs;
 
 1092     std::vector<QString> files;
 
 1095     GpgME::Protocol bias;
 
 1098     QByteArray utf8ErrorKeepAlive;
 
 1116         if ( 
const int err = doStart() )
 
 1120     } 
catch ( 
const Exception & e ) {
 
 1122             done( e.error_code(), e.message() );
 
 1124     } 
catch ( 
const GpgME::Exception & e ) {
 
 1126             done( e.error(), QString::fromLocal8Bit( e.message().c_str() ) );
 
 1128     } 
catch ( 
const std::exception & e ) {
 
 1130             done( 
makeError( GPG_ERR_INTERNAL ), i18n(
"Caught unexpected exception: %1", QString::fromLocal8Bit( e.what() ) ) );
 
 1134             done( 
makeError( GPG_ERR_INTERNAL ), i18n(
"Caught unknown exception - please report this error to the developers." ) );
 
 1150     return d->options.count( opt );
 
 1154     const std::map<std::string,QVariant>::const_iterator it = d->options.find( opt );
 
 1155     if ( it == d->options.end() )
 
 1166     template <
typename U, 
typename V>
 
 1167     std::vector<U> keys( 
const std::map<U,V> & map ) {
 
 1168         std::vector<U> result;
 
 1169         result.resize( map.size() );
 
 1170         for ( 
typename std::map<U,V>::const_iterator it = map.begin(), end = map.end() ; it != end ; ++it )
 
 1171             result.push_back( it->first );
 
 1176 const std::map< QByteArray, shared_ptr<AssuanCommand::Memento> > & AssuanCommand::mementos()
 const {
 
 1178     assert( assuan_get_pointer( d->ctx.
get() ) );
 
 1179     const AssuanServerConnection::Private & conn = *
static_cast<AssuanServerConnection::Private*
>( assuan_get_pointer( d->ctx.
get() ) );
 
 1180     return conn.mementos;
 
 1184     if ( 
const unsigned int id = 
sessionId() )
 
 1187         return mementos().count( tag );
 
 1191     if ( 
const unsigned int id = 
sessionId() ) {
 
 1194         const std::map< QByteArray, shared_ptr<Memento> >::const_iterator it = sd->mementos.find( tag );
 
 1195         if ( it != sd->mementos.end() )
 
 1198     const std::map< QByteArray, shared_ptr<Memento> >::const_iterator it = mementos().find( tag );
 
 1199     if ( it == mementos().end() )
 
 1206     const QByteArray tag = QByteArray::number( reinterpret_cast<qulonglong>( mem.get() ), 36 );
 
 1212     assert( assuan_get_pointer( d->ctx.
get() ) );
 
 1213     AssuanServerConnection::Private & conn = *
static_cast<AssuanServerConnection::Private*
>( assuan_get_pointer( d->ctx.
get() ) );
 
 1215     if ( 
const unsigned int id = 
sessionId() )
 
 1218         conn.mementos[tag] = mem;
 
 1224     assert( assuan_get_pointer( d->ctx.
get() ) );
 
 1225     AssuanServerConnection::Private & conn = *
static_cast<AssuanServerConnection::Private*
>( assuan_get_pointer( d->ctx.
get() ) );
 
 1227     conn.mementos.erase( tag );
 
 1228     if ( 
const unsigned int id = 
sessionId() )
 
 1245     return kdtools::copy<QStringList>( d->files );
 
 1249     return d->files.size();
 
 1259     if ( 
const int err = assuan_write_status( d->ctx.
get(), keyword, text.c_str() ) )
 
 1260         throw Exception( err, i18n( 
"Cannot send \"%1\" status", QString::fromLatin1( keyword ) ) );
 
 1266     if ( 
const gpg_error_t err = assuan_send_data( d->ctx.
get(), data.constData(), data.size() ) )
 
 1267         throw Exception( err, i18n( 
"Cannot send data" ) );
 
 1269         if ( 
const gpg_error_t err = assuan_send_data( d->ctx.
get(), 0, 0 ) ) 
 
 1270             throw Exception( err, i18n( 
"Cannot flush data" ) );
 
 1281 #if defined(HAVE_ASSUAN2) || defined(HAVE_ASSUAN_INQUIRE_EXT) 
 1282     std::auto_ptr<InquiryHandler> ih( 
new InquiryHandler( keyword, receiver ) );
 
 1283     receiver->connect( ih.get(), SIGNAL(
signal(
int,QByteArray,QByteArray)), 
slot );
 
 1284     if ( 
const gpg_error_t err = assuan_inquire_ext( d->ctx.
get(), keyword,
 
 1285 # if !defined(HAVE_ASSUAN2) && !defined(HAVE_NEW_STYLE_ASSUAN_INQUIRE_EXT) 
 1286                                                      &ih->buffer, &ih->buflen,
 
 1288                                                      maxSize, InquiryHandler::handler, ih.get() ) )
 
 1293     return makeError( GPG_ERR_NOT_SUPPORTED ); 
 
 1294 #endif // defined(HAVE_ASSUAN2) || defined(HAVE_ASSUAN_INQUIRE_EXT) 
 1298     if ( d->ctx && !d->done && !details.isEmpty() ) {
 
 1299         kDebug() << 
"Error: " << details;
 
 1300         d->utf8ErrorKeepAlive = details.toUtf8();
 
 1302             assuan_set_error( d->ctx.
get(), err.encodedError(), d->utf8ErrorKeepAlive.constData() );
 
 1309         kDebug() << err.asString() << 
": called with NULL ctx.";
 
 1313         kDebug() << err.asString() << 
": called twice!";
 
 1319     std::for_each( d->messages.begin(), d->messages.end(),
 
 1321     std::for_each( d->inputs.begin(), d->inputs.end(),
 
 1323     std::for_each( d->outputs.begin(), d->outputs.end(),
 
 1325     d->messages.clear();
 
 1331     assert( assuan_get_pointer( d->ctx.
get() ) );
 
 1332     AssuanServerConnection::Private & conn = *
static_cast<AssuanServerConnection::Private*
>( assuan_get_pointer( d->ctx.
get() ) );
 
 1335         conn.nohupDone( 
this );
 
 1339     const gpg_error_t rc = assuan_process_done( d->ctx.
get(), err.encodedError() );
 
 1340     if ( gpg_err_code( rc ) != GPG_ERR_NO_ERROR )
 
 1341         qFatal( 
"AssuanCommand::done: assuan_process_done returned error %d (%s)",
 
 1342                 static_cast<int>(rc), gpg_strerror(rc) );
 
 1344     d->utf8ErrorKeepAlive.clear();
 
 1346     conn.commandDone( 
this );
 
 1363     return d->sessionTitle;
 
 1367     return d->sessionId;
 
 1371     return d->informativeSenders;
 
 1375     return d->informativeRecipients;
 
 1379     return d->recipients;
 
 1386 #ifndef HAVE_ASSUAN2 
 1391     assert( assuan_get_pointer( ctx ) );
 
 1392     AssuanServerConnection::Private & conn = *
static_cast<AssuanServerConnection::Private*
>( assuan_get_pointer( ctx ) );
 
 1396         const std::vector< shared_ptr<AssuanCommandFactory> >::const_iterator it
 
 1400         kleo_assert( qstricmp( (*it)->name(), commandName ) == 0 );
 
 1405         cmd->d->ctx     = conn.ctx;
 
 1406         cmd->d->options = conn.options;
 
 1407         cmd->d->inputs.swap( conn.inputs );     
kleo_assert( conn.inputs.empty() );
 
 1408         cmd->d->messages.swap( conn.messages ); 
kleo_assert( conn.messages.empty() );
 
 1409         cmd->d->outputs.swap( conn.outputs );   
kleo_assert( conn.outputs.empty() );
 
 1410         cmd->d->files.swap( conn.files );       
kleo_assert( conn.files.empty() );
 
 1411         cmd->d->senders.swap( conn.senders );   
kleo_assert( conn.senders.empty() );
 
 1412         cmd->d->recipients.swap( conn.recipients ); 
kleo_assert( conn.recipients.empty() );
 
 1413         cmd->d->informativeRecipients = conn.informativeRecipients;
 
 1414         cmd->d->informativeSenders    = conn.informativeSenders;
 
 1415         cmd->d->bias                  = conn.bias;
 
 1416         cmd->d->sessionTitle          = conn.sessionTitle;
 
 1417         cmd->d->sessionId             = conn.sessionId;
 
 1419         const std::map<std::string,std::string> cmdline_options = 
parse_commandline( line );
 
 1420         for ( std::map<std::string,std::string>::const_iterator it = cmdline_options.begin(), end = cmdline_options.end() ; it != end ; ++it )
 
 1421             cmd->d->options[it->first] = QString::fromUtf8( it->second.c_str() );
 
 1424         if ( cmd->d->options.count( 
"nohup" ) ) {
 
 1425             if ( !cmd->d->options[
"nohup"].toString().isEmpty() )
 
 1426                 return assuan_process_done_msg( conn.ctx.get(), gpg_error( GPG_ERR_ASS_PARAMETER ), 
"--nohup takes no argument" );
 
 1428             cmd->d->options.erase( 
"nohup" );
 
 1431         conn.currentCommand = cmd;
 
 1432         conn.currentCommandIsNohup = nohup;
 
 1434         QTimer::singleShot( 0, &conn, SLOT(startCommandBottomHalf()) );
 
 1438     } 
catch ( 
const Exception & e ) {
 
 1440     } 
catch ( 
const std::exception & e ) {
 
 1443         return assuan_process_done_msg( conn.ctx.get(), gpg_error( GPG_ERR_UNEXPECTED ), i18n(
"Caught unknown exception") );
 
 1447 int AssuanServerConnection::Private::startCommandBottomHalf() {
 
 1449     commandWaitingForCryptoCommandsEnabled = currentCommand && !cryptoCommandsEnabled;
 
 1451     if ( !cryptoCommandsEnabled )
 
 1458     currentCommand.reset();
 
 1460     const bool nohup = currentCommandIsNohup;
 
 1461     currentCommandIsNohup = 
false;
 
 1465         if ( 
const int err = cmd->start() ) {
 
 1466             if ( cmd->isDone() )
 
 1469                 return assuan_process_done( ctx.get(), err );
 
 1472         if ( cmd->isDone() )
 
 1476             cmd->setNohup( 
true );
 
 1477             nohupedCommands.push_back( cmd );
 
 1478             return assuan_process_done_msg( ctx.get(), 0, 
"Command put in the background to continue executing after connection end." );
 
 1480             currentCommand = cmd;
 
 1484     } 
catch ( 
const Exception & e ) {
 
 1486     } 
catch ( 
const std::exception & e ) {
 
 1489         return assuan_process_done_msg( ctx.get(), gpg_error( GPG_ERR_UNEXPECTED ), i18n(
"Caught unknown exception") );
 
 1509     if ( !hasOption( 
"mode" ) )
 
 1510         throw Exception( makeError( GPG_ERR_MISSING_VALUE ), i18n( 
"Required --mode option missing" ) );
 
 1512     const QString modeString = 
option(
"mode").toString().toLower();
 
 1513     if ( modeString == QLatin1String( 
"filemanager" ) )
 
 1515     if ( modeString == QLatin1String( 
"email" ) )
 
 1517     throw Exception( makeError( GPG_ERR_INV_ARG ), i18n( 
"invalid mode: \"%1\"", modeString ) );
 
 1534     if ( !hasOption(
"protocol") )
 
 1535         if ( 
d->bias != GpgME::UnknownProtocol )
 
 1538             throw Exception( makeError( GPG_ERR_MISSING_VALUE ), i18n( 
"Required --protocol option missing" ) );
 
 1540             return GpgME::UnknownProtocol;
 
 1543             throw Exception( makeError( GPG_ERR_INV_FLAG ), i18n(
"--protocol is not allowed here") );
 
 1545     const QString protocolString = 
option(
"protocol").toString().toLower();
 
 1546     if ( protocolString == QLatin1String( 
"openpgp" ) )
 
 1548     if ( protocolString == QLatin1String( 
"cms" ) )
 
 1550     throw Exception( makeError( GPG_ERR_INV_ARG ), i18n( 
"invalid protocol \"%1\"", protocolString ) );
 
 1553 void AssuanCommand::doApplyWindowID( 
QWidget * widget )
 const {
 
 1554     if ( !widget || !hasOption( 
"window-id" ) )
 
 1563 #include "assuanserverconnection.moc" 
 1564 #include "moc_assuanserverconnection.cpp" 
static const int FOR_READING
 
static const unsigned int MAX_ACTIVE_FDS
 
shared_ptr< remove_pointer< assuan_context_t >::type > AssuanContextBase
 
static void apply_window_id(QWidget *widget, const QString &winIdStr)
 
~AssuanServerConnection()
 
bool hasMemento(const QByteArray &tag) const 
 
virtual void finalize()=0
 
static std::map< std::string, std::string > parse_commandline(const char *line)
 
static std::string email(const UserID &uid)
 
static gpg_error_t assuan_process_done_msg(assuan_context_t ctx, gpg_error_t err, const char *err_msg)
 
void sendStatusEncoded(const char *keyword, const std::string &text)
 
boost::shared_ptr< Memento > memento(const QByteArray &tag) const 
 
static std::map< std::string, std::string > upcase_option(const char *option, std::map< std::string, std::string > options)
 
void removeMemento(const QByteArray &tag)
 
static const unsigned int INIT_SOCKET_FLAGS
 
QStringList fileNames() const 
 
const std::vector< KMime::Types::Mailbox > & senders() const 
 
void sendData(const QByteArray &data, bool moreToCome=false)
 
static WId wid_from_string(const QString &winIdStr, bool *ok=0)
 
static boost::shared_ptr< SessionDataHandler > instance()
 
int inquire(const char *keyword, QObject *receiver, const char *slot, unsigned int maxSize=0)
 
const std::vector< boost::shared_ptr< Output > > & outputs() const 
 
#define ASSUAN_INVALID_FD
 
QVariant option(const char *opt) const 
 
QString sessionTitle() const 
 
void enableCryptoCommands(bool enable=true)
 
void sendStatus(const char *keyword, const QString &text)
 
const std::vector< KMime::Types::Mailbox > & recipients() const 
 
static int _handle(assuan_context_s *, char *, const char *)
 
virtual void setBinaryOpt(bool value)=0
 
static int makeError(int code)
 
int makeGnuPGError(int code)
 
unsigned int numFiles() const 
 
#define kleo_assert(cond)
 
const std::vector< boost::shared_ptr< Input > > & inputs() const 
 
Base class for GnuPG UI Server commands. 
 
void done(const GpgME::Error &err=GpgME::Error())
 
bool hasOption(const char *opt) const 
 
QByteArray registerMemento(const boost::shared_ptr< Memento > &mem)
 
GpgME::Protocol checkProtocol(Mode mode, int options=0) const 
 
unsigned int sessionId() const 
 
bool informativeSenders() const 
 
bool informativeRecipients() const 
 
const std::map< std::string, QVariant > & options() const 
 
std::string hexdecode(const char *s)
 
const std::vector< boost::shared_ptr< Input > > & messages() const