certmanager/lib

qgpgmekeylistjob.cpp
00001 /*
00002     qgpgmekeylistjob.cpp
00003 
00004     This file is part of libkleopatra, the KDE keymanagement library
00005     Copyright (c) 2004 Klarälvdalens Datakonsult AB
00006 
00007     Libkleopatra is free software; you can redistribute it and/or
00008     modify it under the terms of the GNU General Public License as
00009     published by the Free Software Foundation; either version 2 of the
00010     License, or (at your option) any later version.
00011 
00012     Libkleopatra is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015     General Public License for more details.
00016 
00017     You should have received a copy of the GNU General Public License
00018     along with this program; if not, write to the Free Software
00019     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00020 
00021     In addition, as a special exception, the copyright holders give
00022     permission to link the code of this program with any edition of
00023     the TQt library by Trolltech AS, Norway (or with modified versions
00024     of TQt that use the same license as TQt), and distribute linked
00025     combinations including the two.  You must obey the GNU General
00026     Public License in all respects for all of the code used other than
00027     TQt.  If you modify this file, you may extend this exception to
00028     your version of the file, but you are not obligated to do so.  If
00029     you do not wish to do so, delete this exception statement from
00030     your version.
00031 */
00032 
00033 #ifdef HAVE_CONFIG_H
00034 #include <config.h>
00035 #endif
00036 
00037 #include "qgpgmekeylistjob.h"
00038 
00039 #include <qgpgme/eventloopinteractor.h>
00040 
00041 #include <gpgmepp/key.h>
00042 #include <gpgmepp/context.h>
00043 #include <gpgmepp/keylistresult.h>
00044 #include <gpg-error.h>
00045 
00046 #include <tdemessagebox.h>
00047 #include <tdelocale.h>
00048 #include <kdebug.h>
00049 
00050 #include <tqstringlist.h>
00051 #include <tqtimer.h>
00052 
00053 #include <algorithm>
00054 
00055 #include <stdlib.h>
00056 #include <string.h>
00057 #include <assert.h>
00058 
00059 Kleo::QGpgMEKeyListJob::QGpgMEKeyListJob( GpgME::Context * context )
00060   : KeyListJob( QGpgME::EventLoopInteractor::instance(), "Kleo::QGpgMEKeyListJob" ),
00061     QGpgMEJob( this, context ),
00062     mResult(), mSecretOnly( false )
00063 {
00064   assert( context );
00065 }
00066 
00067 Kleo::QGpgMEKeyListJob::~QGpgMEKeyListJob() {
00068 }
00069 
00070 void Kleo::QGpgMEKeyListJob::setup( const TQStringList & pats, bool secretOnly ) {
00071   assert( !patterns() );
00072 
00073   mSecretOnly = secretOnly;
00074   setPatterns( pats );
00075 }
00076 
00077 GpgME::Error Kleo::QGpgMEKeyListJob::start( const TQStringList & pats, bool secretOnly ) {
00078   setup( pats, secretOnly );
00079 
00080   hookupContextToEventLoopInteractor();
00081   connect( QGpgME::EventLoopInteractor::instance(),
00082        TQT_SIGNAL(nextKeyEventSignal(GpgME::Context*,const GpgME::Key&)),
00083        TQT_SLOT(slotNextKeyEvent(GpgME::Context*,const GpgME::Key&)) );
00084 
00085   // The communication channel between gpgme and gpgsm is limited in
00086   // the number of patterns that can be transported, but they won't
00087   // say to how much, so we need to find out ourselves if we get a
00088   // LINE_TOO_LONG error back...
00089 
00090   // We could of course just feed them single patterns, and that would
00091   // probably be easier, but the performance penalty would currently
00092   // be noticable.
00093 
00094   while ( const GpgME::Error err = mCtx->startKeyListing( patterns(), mSecretOnly ) ) {
00095     if ( err.code() == GPG_ERR_LINE_TOO_LONG ) {
00096       setChunkSize( chunkSize()/2 );
00097       if ( chunkSize() >= 1 ) {
00098     kdDebug(5150) << "QGpgMEKeyListJob::start(): retrying keylisting with chunksize " << chunkSize() << endl;
00099     continue;
00100       }
00101     } else if ( err.code() == GPG_ERR_EOF ) {
00102         kdDebug(5150) << "QGpgMEKeyListJob::start(): early end of keylisting, trying to fake an empty result" << endl;
00103         TQTimer::singleShot( 10, this, TQT_SLOT(slotFakeOperationDoneEvent()) );
00104         return GpgME::Error();
00105     }
00106     deleteLater();
00107     mResult = GpgME::KeyListResult( 0, err );
00108     return err;
00109   }
00110   mResult = GpgME::KeyListResult( 0, 0 );
00111   return 0;
00112 }
00113 
00114 GpgME::KeyListResult Kleo::QGpgMEKeyListJob::exec( const TQStringList & pats, bool secretOnly, std::vector<GpgME::Key> & keys ) {
00115   setup( pats, secretOnly );
00116 
00117   // The communication channel between gpgme and gpgsm is limited in
00118   // the number of patterns that can be transported, but they won't
00119   // say to how much, so we need to find out ourselves if we get a
00120   // LINE_TOO_LONG error back...
00121 
00122   // We could of course just feed them single patterns, and that would
00123   // probably be easier, but the performance penalty would currently
00124   // be noticable.
00125 
00126   for (;;) {
00127     keys.clear();
00128     mResult = attemptSyncKeyListing( keys );
00129     if ( !mResult.error() || mResult.error().code() != GPG_ERR_LINE_TOO_LONG )
00130       return mResult;
00131     // got LINE_TOO_LONG, try a smaller chunksize:
00132     setChunkSize( chunkSize()/2 );
00133     if ( chunkSize() < 1 )
00134       // chunks smaller than one can't be -> return the error.
00135       return mResult;
00136     kdDebug(5150) << "QGpgMEKeyListJob::exec(): retrying keylisting with chunksize " << chunkSize() << endl;
00137   }
00138   kdFatal(5150) << "QGpgMEKeyListJob::exec(): Oops, this is not supposed to happen!" << endl;
00139   return GpgME::KeyListResult();
00140 }
00141 
00142 GpgME::KeyListResult Kleo::QGpgMEKeyListJob::attemptSyncKeyListing( std::vector<GpgME::Key> & keys ) {
00143   GpgME::KeyListResult result;
00144   for ( const char* * chunk = patterns() ; chunk ; chunk = nextChunk() ) {
00145 
00146     if ( const GpgME::Error err = mCtx->startKeyListing( chunk, mSecretOnly ) )
00147       return GpgME::KeyListResult( 0, err );
00148 
00149     GpgME::Error err;
00150     do
00151       keys.push_back( mCtx->nextKey( err ) );
00152     while ( !err );
00153     keys.pop_back();
00154     result.mergeWith( mCtx->endKeyListing() );
00155     if ( result.error() )
00156       break;
00157   }
00158   return result;
00159 }
00160 
00161 void Kleo::QGpgMEKeyListJob::slotNextKeyEvent( GpgME::Context * context, const GpgME::Key & key ) {
00162   if ( context == mCtx )
00163     emit nextKey( key );
00164 }
00165 
00166 void Kleo::QGpgMEKeyListJob::slotFakeOperationDoneEvent() {
00167   const GpgME::KeyListResult res = mCtx->keyListResult();
00168   if ( !res.error().code() == GPG_ERR_EOF )
00169     kdDebug(5150) << "QGpgMEKeyListJob::slotFakeOperationDoneEvent: expected EOF, got "
00170                   << res.error().asString() << endl;
00171   mResult = GpgME::KeyListResult();
00172   emit done();
00173   emit result( mResult );
00174   deleteLater();
00175 }
00176 
00177 void Kleo::QGpgMEKeyListJob::slotOperationDoneEvent( GpgME::Context * context, const GpgME::Error & ) {
00178   if ( context != mCtx )
00179     return;
00180   mResult.mergeWith( mCtx->keyListResult() );
00181   if ( !mResult.error() )
00182     if ( const char* * chunk = nextChunk() ) {
00183       if ( const GpgME::Error err = mCtx->startKeyListing( chunk, mSecretOnly ) )
00184     mResult.mergeWith( GpgME::KeyListResult( 0, err ) );
00185       else
00186     return;
00187     }
00188   emit done();
00189   emit result( mResult );
00190   deleteLater();
00191 }
00192 
00193 void Kleo::QGpgMEKeyListJob::showErrorDialog( TQWidget * parent, const TQString & caption ) const {
00194   if ( !mResult.error() || mResult.error().isCanceled() )
00195     return;
00196   const TQString msg = i18n( "<qt><p>An error occurred while fetching "
00197                 "the keys from the backend:</p>"
00198                 "<p><b>%1</b></p></qt>" )
00199     .arg( TQString::fromLocal8Bit( mResult.error().asString() ) );
00200   KMessageBox::error( parent, msg, caption );
00201 }
00202 
00203 #include "qgpgmekeylistjob.moc"