/*
certmanager . cpp
This file is part of Kleopatra , the KDE keymanager
Copyright ( c ) 2001 , 2002 , 2004 Klar <EFBFBD> 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 TQt library by Trolltech AS , Norway ( or with modified versions
of TQt that use the same license as TQt ) , 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
TQt . 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 .
*/
# ifdef HAVE_CONFIG_H
# include <config.h>
# endif
# include "certmanager.h"
# include "certlistview.h"
# include "certificatewizardimpl.h"
# include "certificateinfowidgetimpl.h"
# include "crlview.h"
# include "customactions.h"
# include "hierarchyanalyser.h"
# include "storedtransferjob.h"
# include "conf/configuredialog.h"
// libkleopatra
# include <kleo/cryptobackendfactory.h>
# include <kleo/downloadjob.h>
# include <kleo/importjob.h>
# include <kleo/exportjob.h>
# include <kleo/multideletejob.h>
# include <kleo/deletejob.h>
# include <kleo/keylistjob.h>
# include <kleo/dn.h>
# include <kleo/keyfilter.h>
# include <kleo/keyfiltermanager.h>
# include <kleo/hierarchicalkeylistjob.h>
# include <kleo/refreshkeysjob.h>
# include <kleo/cryptoconfig.h>
# include <ui/progressdialog.h>
# include <ui/progressbar.h>
# include <ui/keyselectiondialog.h>
# include <ui/cryptoconfigdialog.h>
// GPGME++
# include <gpgmepp/importresult.h>
# include <gpgmepp/keylistresult.h>
# include <gpgmepp/key.h>
// KDE
# include <kfiledialog.h>
# include <kprocess.h>
# include <kaction.h>
# include <kapplication.h>
# include <klocale.h>
# include <kmessagebox.h>
# include <dcopclient.h>
# include <ktoolbar.h>
# include <kstatusbar.h>
# include <kstandarddirs.h>
# include <kdebug.h>
# include <kdialogbase.h>
# include <kkeydialog.h>
# include <ktempfile.h>
# include <kio/job.h>
# include <kio/netaccess.h>
# include <kstdaccel.h>
// TQt
# include <tqfontmetrics.h>
# include <tqpopupmenu.h>
// other
# include <algorithm>
# include <assert.h>
# include <kdepimmacros.h>
# include <kinputdialog.h>
namespace {
class KDE_EXPORT DisplayStrategy : public Kleo : : KeyListView : : DisplayStrategy {
public :
~ DisplayStrategy ( ) { }
virtual TQFont keyFont ( const GpgME : : Key & key , const TQFont & font ) const {
const Kleo : : KeyFilter * filter = Kleo : : KeyFilterManager : : instance ( ) - > filterMatching ( key ) ;
return filter ? filter - > font ( font ) : font ;
}
virtual TQColor keyForeground ( const GpgME : : Key & key , const TQColor & c ) const {
const Kleo : : KeyFilter * filter = Kleo : : KeyFilterManager : : instance ( ) - > filterMatching ( key ) ;
if ( filter & & filter - > fgColor ( ) . isValid ( ) )
return filter - > fgColor ( ) ;
return c ;
}
virtual TQColor keyBackground ( const GpgME : : Key & key , const TQColor & c ) const {
const Kleo : : KeyFilter * filter = Kleo : : KeyFilterManager : : instance ( ) - > filterMatching ( key ) ;
if ( filter & & filter - > bgColor ( ) . isValid ( ) )
return filter - > bgColor ( ) ;
return c ;
}
} ;
class KDE_EXPORT ColumnStrategy : public Kleo : : KeyListView : : ColumnStrategy {
public :
~ ColumnStrategy ( ) { }
TQString title ( int col ) const ;
TQString text ( const GpgME : : Key & key , int col ) const ;
int width ( int col , const TQFontMetrics & fm ) const ;
} ;
TQString ColumnStrategy : : title ( int col ) const {
switch ( col ) {
case 0 : return i18n ( " Subject " ) ;
case 1 : return i18n ( " Issuer " ) ;
case 2 : return i18n ( " Serial " ) ;
default : return TQString ( ) ;
}
}
TQString ColumnStrategy : : text ( const GpgME : : Key & key , int col ) const {
switch ( col ) {
case 0 : return Kleo : : DN ( key . userID ( 0 ) . id ( ) ) . prettyDN ( ) ;
case 1 : return Kleo : : DN ( key . issuerName ( ) ) . prettyDN ( ) ;
case 2 : return key . issuerSerial ( ) ? TQString : : fromUtf8 ( key . issuerSerial ( ) ) : TQString ( ) ;
default : return TQString ( ) ;
}
}
int ColumnStrategy : : width ( int col , const TQFontMetrics & fm ) const {
int factor = - 1 ;
switch ( col ) {
case 0 : factor = 6 ; break ;
case 1 : factor = 4 ; break ;
default : return - 1 ;
}
return fm . width ( title ( col ) ) * factor ;
}
} // anon namespace
CertManager : : CertManager ( bool remote , const TQString & query , const TQString & import ,
TQWidget * tqparent , const char * name , WFlags f )
: KMainWindow ( tqparent , name , f | WDestructiveClose ) ,
mCrlView ( 0 ) ,
mDirmngrProc ( 0 ) ,
mHierarchyAnalyser ( 0 ) ,
mLineEditAction ( 0 ) ,
mComboAction ( 0 ) ,
mFindAction ( 0 ) ,
mImportCertFromFileAction ( 0 ) ,
mImportCRLFromFileAction ( 0 ) ,
mNextFindRemote ( remote ) ,
mRemote ( remote ) ,
mDirMngrFound ( false )
{
readConfig ( query . isEmpty ( ) ) ;
createStatusBar ( ) ;
createActions ( ) ;
createGUI ( ) ;
setAutoSaveSettings ( ) ;
// Main Window --------------------------------------------------
mKeyListView = new CertKeyListView ( new ColumnStrategy ( ) , new DisplayStrategy ( ) , this , " mKeyListView " ) ;
mKeyListView - > setSelectionMode ( TQListView : : Extended ) ;
setCentralWidget ( mKeyListView ) ;
connect ( mKeyListView , TQT_SIGNAL ( doubleClicked ( Kleo : : KeyListViewItem * , const TQPoint & , int ) ) ,
TQT_SLOT ( slotViewDetails ( Kleo : : KeyListViewItem * ) ) ) ;
connect ( mKeyListView , TQT_SIGNAL ( returnPressed ( Kleo : : KeyListViewItem * ) ) ,
TQT_SLOT ( slotViewDetails ( Kleo : : KeyListViewItem * ) ) ) ;
connect ( mKeyListView , TQT_SIGNAL ( selectionChanged ( ) ) ,
TQT_SLOT ( slotSelectionChanged ( ) ) ) ;
connect ( mKeyListView , TQT_SIGNAL ( contextMenu ( Kleo : : KeyListViewItem * , const TQPoint & ) ) ,
TQT_SLOT ( slotContextMenu ( Kleo : : KeyListViewItem * , const TQPoint & ) ) ) ;
connect ( mKeyListView , TQT_SIGNAL ( dropped ( const KURL : : List & ) ) ,
TQT_SLOT ( slotDropped ( const KURL : : List & ) ) ) ;
mLineEditAction - > setText ( query ) ;
if ( ! mRemote & & ! mNextFindRemote | | ! query . isEmpty ( ) )
slotSearch ( ) ;
if ( ! import . isEmpty ( ) )
slotImportCertFromFile ( KURL ( import ) ) ;
slotToggleHierarchicalView ( mHierarchicalView ) ;
updateStatusBarLabels ( ) ;
slotSelectionChanged ( ) ; // initial state for selection-dependent actions
}
CertManager : : ~ CertManager ( ) {
writeConfig ( ) ;
delete mDirmngrProc ; mDirmngrProc = 0 ;
delete mHierarchyAnalyser ; mHierarchyAnalyser = 0 ;
}
void CertManager : : readConfig ( bool noQueryGiven ) {
KConfig config ( " kleopatrarc " ) ;
config . setGroup ( " Display Options " ) ;
mHierarchicalView = config . readBoolEntry ( " hierarchicalView " , false ) ;
if ( noQueryGiven ) {
mNextFindRemote = config . readBoolEntry ( " startInRemoteMode " , false ) ;
}
}
void CertManager : : writeConfig ( ) {
KConfig config ( " kleopatrarc " ) ;
config . setGroup ( " Display Options " ) ;
config . writeEntry ( " hierarchicalView " , mKeyListView - > hierarchical ( ) ) ;
config . writeEntry ( " startInRemoteMode " , mNextFindRemote ) ;
}
void CertManager : : createStatusBar ( ) {
KStatusBar * bar = statusBar ( ) ;
mProgressBar = new Kleo : : ProgressBar ( bar , " mProgressBar " ) ;
mProgressBar - > reset ( ) ;
mProgressBar - > setFixedSize ( TQSize ( 100 , mProgressBar - > height ( ) * 3 / 5 ) ) ;
bar - > addWidget ( mProgressBar , 0 , true ) ;
mStatusLabel = new TQLabel ( bar , " mStatusLabel " ) ;
bar - > addWidget ( mStatusLabel , 1 , false ) ;
}
static inline void connectEnableOperationSignal ( TQObject * s , TQObject * d ) {
TQObject : : connect ( s , TQT_SIGNAL ( enableOperations ( bool ) ) ,
d , TQT_SLOT ( setEnabled ( bool ) ) ) ;
}
void CertManager : : createActions ( ) {
KAction * action = 0 ;
( void ) KStdAction : : quit ( TQT_TQOBJECT ( this ) , TQT_SLOT ( close ( ) ) , actionCollection ( ) ) ;
action = KStdAction : : redisplay ( TQT_TQOBJECT ( this ) , TQT_SLOT ( slotRedisplay ( ) ) , actionCollection ( ) ) ;
// work around the fact that the stdaction has no shortcut
KShortcut reloadShortcut = KStdAccel : : shortcut ( KStdAccel : : Reload ) ;
reloadShortcut . append ( KKey ( CTRL + Key_R ) ) ;
action - > setShortcut ( reloadShortcut ) ;
connectEnableOperationSignal ( TQT_TQOBJECT ( this ) , action ) ;
action = new KAction ( i18n ( " Stop Operation " ) , " stop " , Key_Escape ,
TQT_TQOBJECT ( this ) , TQT_SIGNAL ( stopOperations ( ) ) ,
actionCollection ( ) , " view_stop_operations " ) ;
action - > setEnabled ( false ) ;
( void ) new KAction ( i18n ( " New Key Pair... " ) , " filenew " , 0 ,
TQT_TQOBJECT ( this ) , TQT_SLOT ( newCertificate ( ) ) ,
actionCollection ( ) , " file_new_certificate " ) ;
connect ( new KToggleAction ( i18n ( " Hierarchical Key List " ) , 0 ,
actionCollection ( ) , " view_hierarchical " ) ,
TQT_SIGNAL ( toggled ( bool ) ) , TQT_SLOT ( slotToggleHierarchicalView ( bool ) ) ) ;
action = new KAction ( i18n ( " Expand All " ) , 0 , CTRL + Key_Period ,
TQT_TQOBJECT ( this ) , TQT_SLOT ( slotExpandAll ( ) ) ,
actionCollection ( ) , " view_expandall " ) ;
action = new KAction ( i18n ( " Collapse All " ) , 0 , CTRL + Key_Comma ,
TQT_TQOBJECT ( this ) , TQT_SLOT ( slotCollapseAll ( ) ) ,
actionCollection ( ) , " view_collapseall " ) ;
( void ) new KAction ( i18n ( " Refresh CRLs " ) , 0 , 0 ,
TQT_TQOBJECT ( this ) , TQT_SLOT ( slotRefreshKeys ( ) ) ,
actionCollection ( ) , " certificates_refresh_clr " ) ;
# ifdef NOT_IMPLEMENTED_ANYWAY
mRevokeCertificateAction = new KAction ( i18n ( " Revoke " ) , 0 ,
TQT_TQOBJECT ( this ) , TQT_SLOT ( revokeCertificate ( ) ) ,
actionCollection ( ) , " edit_revoke_certificate " ) ;
connectEnableOperationSignal ( this , mRevokeCertificateAction ) ;
mExtendCertificateAction = new KAction ( i18n ( " Extend " ) , 0 ,
TQT_TQOBJECT ( this ) , TQT_SLOT ( extendCertificate ( ) ) ,
actionCollection ( ) , " edit_extend_certificate " ) ;
connectEnableOperationSignal ( this , mExtendCertificateAction ) ;
# endif
mDeleteCertificateAction = new KAction ( i18n ( " Delete " ) , " editdelete " , Key_Delete ,
TQT_TQOBJECT ( this ) , TQT_SLOT ( slotDeleteCertificate ( ) ) ,
actionCollection ( ) , " edit_delete_certificate " ) ;
connectEnableOperationSignal ( TQT_TQOBJECT ( this ) , mDeleteCertificateAction ) ;
mValidateCertificateAction = new KAction ( i18n ( " Validate " ) , " reload " , SHIFT + Key_F5 ,
TQT_TQOBJECT ( this ) , TQT_SLOT ( slotValidate ( ) ) ,
actionCollection ( ) , " certificates_validate " ) ;
connectEnableOperationSignal ( TQT_TQOBJECT ( this ) , mValidateCertificateAction ) ;
mImportCertFromFileAction = new KAction ( i18n ( " Import Certificates... " ) , 0 ,
TQT_TQOBJECT ( this ) , TQT_SLOT ( slotImportCertFromFile ( ) ) ,
actionCollection ( ) , " file_import_certificates " ) ;
connectEnableOperationSignal ( TQT_TQOBJECT ( this ) , mImportCertFromFileAction ) ;
mImportCRLFromFileAction = new KAction ( i18n ( " Import CRLs... " ) , 0 ,
TQT_TQOBJECT ( this ) , TQT_SLOT ( importCRLFromFile ( ) ) ,
actionCollection ( ) , " file_import_crls " ) ;
connectEnableOperationSignal ( TQT_TQOBJECT ( this ) , mImportCRLFromFileAction ) ;
mExportCertificateAction = new KAction ( i18n ( " Export Certificates... " ) , " export " , 0 ,
TQT_TQOBJECT ( this ) , TQT_SLOT ( slotExportCertificate ( ) ) ,
actionCollection ( ) , " file_export_certificate " ) ;
mExportSecretKeyAction = new KAction ( i18n ( " Export Secret Key... " ) , " export " , 0 ,
TQT_TQOBJECT ( this ) , TQT_SLOT ( slotExportSecretKey ( ) ) ,
actionCollection ( ) , " file_export_secret_keys " ) ;
connectEnableOperationSignal ( TQT_TQOBJECT ( this ) , mExportSecretKeyAction ) ;
mViewCertDetailsAction = new KAction ( i18n ( " Certificate Details... " ) , 0 , 0 ,
TQT_TQOBJECT ( this ) , TQT_SLOT ( slotViewDetails ( ) ) , actionCollection ( ) ,
" view_certificate_details " ) ;
mDownloadCertificateAction = new KAction ( i18n ( " Download " ) , 0 , 0 ,
TQT_TQOBJECT ( this ) , TQT_SLOT ( slotDownloadCertificate ( ) ) , actionCollection ( ) ,
" download_certificate " ) ;
const TQString dirmngr = KStandardDirs : : findExe ( " gpgsm " ) ;
mDirMngrFound = ! dirmngr . isEmpty ( ) ;
action = new KAction ( i18n ( " Dump CRL Cache... " ) , 0 ,
TQT_TQOBJECT ( this ) , TQT_SLOT ( slotViewCRLs ( ) ) ,
actionCollection ( ) , " crl_dump_crl_cache " ) ;
action - > setEnabled ( mDirMngrFound ) ; // we also need dirmngr for this
action = new KAction ( i18n ( " Clear CRL Cache... " ) , 0 ,
TQT_TQOBJECT ( this ) , TQT_SLOT ( slotClearCRLs ( ) ) ,
actionCollection ( ) , " crl_clear_crl_cache " ) ;
action - > setEnabled ( mDirMngrFound ) ; // we also need dirmngr for this
action = new KAction ( i18n ( " GnuPG Log Viewer... " ) , " pgp-keys " , 0 , TQT_TQOBJECT ( this ) ,
TQT_SLOT ( slotStartWatchGnuPG ( ) ) , actionCollection ( ) , " tools_start_kwatchgnupg " ) ;
// disable action if no kwatchgnupg binary is around
if ( KStandardDirs : : findExe ( " kwatchgnupg " ) . isEmpty ( ) ) action - > setEnabled ( false ) ;
( void ) new LabelAction ( i18n ( " Search: " ) , actionCollection ( ) , " label_action " ) ;
mLineEditAction = new LineEditAction ( TQString ( ) , actionCollection ( ) , TQT_TQOBJECT ( this ) ,
TQT_SLOT ( slotSearch ( ) ) ,
" query_lineedit_action " ) ;
TQStringList lst ;
lst < < i18n ( " In Local Certificates " ) < < i18n ( " In External Certificates " ) ;
mComboAction = new ComboAction ( lst , actionCollection ( ) , TQT_TQOBJECT ( this ) , TQT_SLOT ( slotToggleRemote ( int ) ) ,
" location_combo_action " , mNextFindRemote ? 1 : 0 ) ;
mFindAction = new KAction ( i18n ( " Find " ) , " tqfind " , 0 , TQT_TQOBJECT ( this ) , TQT_SLOT ( slotSearch ( ) ) ,
actionCollection ( ) , " tqfind " ) ;
KStdAction : : keyBindings ( TQT_TQOBJECT ( this ) , TQT_SLOT ( slotEditKeybindings ( ) ) , actionCollection ( ) ) ;
KStdAction : : preferences ( TQT_TQOBJECT ( this ) , TQT_SLOT ( slotShowConfigurationDialog ( ) ) , actionCollection ( ) ) ;
new KAction ( i18n ( " Configure &GpgME Backend " ) , 0 , 0 , TQT_TQOBJECT ( this ) , TQT_SLOT ( slotConfigureGpgME ( ) ) ,
actionCollection ( ) , " configure_gpgme " ) ;
createStandardStatusBarAction ( ) ;
updateImportActions ( true ) ;
}
void CertManager : : updateImportActions ( bool enable ) {
mImportCRLFromFileAction - > setEnabled ( mDirMngrFound & & enable ) ;
mImportCertFromFileAction - > setEnabled ( enable ) ;
}
void CertManager : : slotEditKeybindings ( ) {
KKeyDialog : : configure ( actionCollection ( ) , true ) ;
}
void CertManager : : slotShowConfigurationDialog ( ) {
ConfigureDialog dlg ( this ) ;
connect ( & dlg , TQT_SIGNAL ( configCommitted ( ) ) , TQT_SLOT ( slotRepaint ( ) ) ) ;
dlg . exec ( ) ;
}
void CertManager : : slotConfigureGpgME ( ) {
Kleo : : CryptoConfig * config = Kleo : : CryptoBackendFactory : : instance ( ) - > config ( ) ;
if ( config ) {
Kleo : : CryptoConfigDialog dlg ( config ) ;
int result = dlg . exec ( ) ;
// Forget all data parsed from gpgconf, so that we show updated information
// when reopening the configuration dialog.
config - > clear ( ) ;
if ( result = = TQDialog : : Accepted )
{
// Tell other apps (e.g. kmail) that the gpgconf data might have changed
kapp - > dcopClient ( ) - > emitDCOPSignal ( " KPIM::CryptoConfig " , " changed() " , TQByteArray ( ) ) ;
}
}
}
void CertManager : : slotRepaint ( )
{
mKeyListView - > tqrepaintContents ( ) ;
}
void CertManager : : slotToggleRemote ( int idx ) {
mNextFindRemote = idx ! = 0 ;
}
void CertManager : : slotToggleHierarchicalView ( bool hier ) {
mHierarchicalView = hier ;
mKeyListView - > setHierarchical ( hier ) ;
mKeyListView - > setRootIsDecorated ( hier ) ;
if ( KAction * act = action ( " view_expandall " ) )
act - > setEnabled ( hier ) ;
if ( KAction * act = action ( " view_collapseall " ) )
act - > setEnabled ( hier ) ;
if ( KToggleAction * act =
static_cast < KToggleAction * > ( action ( " view_hierarchical " ) ) )
act - > setChecked ( hier ) ;
if ( hier & & ! mCurrentQuery . isEmpty ( ) )
startRedisplay ( false ) ;
}
void CertManager : : slotExpandAll ( ) {
for ( TQListViewItemIterator it ( mKeyListView ) ; it . current ( ) ; + + it )
it . current ( ) - > setOpen ( true ) ;
}
void CertManager : : slotCollapseAll ( ) {
for ( TQListViewItemIterator it ( mKeyListView ) ; it . current ( ) ; + + it )
it . current ( ) - > setOpen ( false ) ;
}
void CertManager : : connectJobToStatusBarProgress ( Kleo : : Job * job , const TQString & initialText ) {
assert ( mProgressBar ) ;
if ( ! job )
return ;
if ( ! initialText . isEmpty ( ) )
statusBar ( ) - > message ( initialText ) ;
connect ( job , TQT_SIGNAL ( progress ( const TQString & , int , int ) ) ,
mProgressBar , TQT_SLOT ( slotProgress ( const TQString & , int , int ) ) ) ;
connect ( job , TQT_SIGNAL ( done ( ) ) , mProgressBar , TQT_SLOT ( reset ( ) ) ) ;
connect ( this , TQT_SIGNAL ( stopOperations ( ) ) , job , TQT_SLOT ( slotCancel ( ) ) ) ;
action ( " view_stop_operations " ) - > setEnabled ( true ) ;
emit enableOperations ( false ) ;
}
void CertManager : : disconnectJobFromStatusBarProgress ( const GpgME : : Error & err ) {
updateStatusBarLabels ( ) ;
const TQString msg = err . isCanceled ( ) ? i18n ( " Canceled. " )
: err ? i18n ( " Failed. " )
: i18n ( " Done. " ) ;
statusBar ( ) - > message ( msg , 4000 ) ;
action ( " view_stop_operations " ) - > setEnabled ( false ) ;
emit enableOperations ( true ) ;
slotSelectionChanged ( ) ;
}
void CertManager : : updateStatusBarLabels ( ) {
mKeyListView - > flushKeys ( ) ;
int total = 0 ;
for ( TQListViewItemIterator it ( mKeyListView ) ; it . current ( ) ; + + it )
+ + total ;
mStatusLabel - > setText ( i18n ( " %n Key. " , " %n Keys. " , total ) ) ;
}
//
//
// Key Listing:
//
//
static std : : set < std : : string > extractKeyFingerprints ( const TQPtrList < Kleo : : KeyListViewItem > & items ) {
std : : set < std : : string > result ;
for ( TQPtrListIterator < Kleo : : KeyListViewItem > it ( items ) ; it . current ( ) ; + + it )
if ( const char * fpr = it . current ( ) - > key ( ) . primaryFingerprint ( ) )
result . insert ( fpr ) ;
return result ;
}
static TQStringList stringlistFromSet ( const std : : set < std : : string > & set ) {
// ARGH. This is madness. Shitty TQt containers don't support TQStringList( patterns.begin(), patterns.end() ) :/
TQStringList sl ;
for ( std : : set < std : : string > : : const_iterator it = set . begin ( ) ; it ! = set . end ( ) ; + + it )
// let's make extra sure, maybe someone tries to make TQt not support std::string->TQString conversion
sl . push_back ( TQString : : tqfromLatin1 ( it - > c_str ( ) ) ) ;
return sl ;
}
void CertManager : : slotRefreshKeys ( ) {
const TQStringList keys = stringlistFromSet ( extractKeyFingerprints ( mKeyListView - > selectedItems ( ) ) ) ;
Kleo : : RefreshKeysJob * job = Kleo : : CryptoBackendFactory : : instance ( ) - > smime ( ) - > refreshKeysJob ( ) ;
assert ( job ) ;
connect ( job , TQT_SIGNAL ( result ( const GpgME : : Error & ) ) ,
this , TQT_SLOT ( slotRefreshKeysResult ( const GpgME : : Error & ) ) ) ;
connectJobToStatusBarProgress ( job , i18n ( " Refreshing keys... " ) ) ;
if ( const GpgME : : Error err = job - > start ( keys ) )
slotRefreshKeysResult ( err ) ;
}
void CertManager : : slotRefreshKeysResult ( const GpgME : : Error & err ) {
disconnectJobFromStatusBarProgress ( err ) ;
if ( err . isCanceled ( ) )
return ;
if ( err )
KMessageBox : : error ( this , i18n ( " An error occurred while trying to refresh "
" keys: \n %1 " ) . tqarg ( TQString : : fromLocal8Bit ( err . asString ( ) ) ) ,
i18n ( " Refreshing Keys Failed " ) ) ;
}
static void showKeyListError ( TQWidget * tqparent , const GpgME : : Error & err ) {
assert ( err ) ;
const TQString msg = i18n ( " <qt><p>An error occurred while fetching "
" the certificates from the backend:</p> "
" <p><b>%1</b></p></qt> " )
. tqarg ( TQString : : fromLocal8Bit ( err . asString ( ) ) ) ;
KMessageBox : : error ( tqparent , msg , i18n ( " Certificate Listing Failed " ) ) ;
}
void CertManager : : slotSearch ( ) {
mPreviouslySelectedFingerprints . clear ( ) ;
// Clear display
mKeyListView - > clear ( ) ;
mCurrentQuery = mLineEditAction - > text ( ) ;
startKeyListing ( false , false , mCurrentQuery ) ;
}
void CertManager : : startRedisplay ( bool validate ) {
mPreviouslySelectedFingerprints = extractKeyFingerprints ( mKeyListView - > selectedItems ( ) ) ;
if ( mPreviouslySelectedFingerprints . empty ( ) )
startKeyListing ( validate , true , mCurrentQuery ) ;
else
startKeyListing ( validate , true , mPreviouslySelectedFingerprints ) ;
}
void CertManager : : startKeyListing ( bool validating , bool refresh , const std : : set < std : : string > & patterns ) {
startKeyListing ( validating , refresh , stringlistFromSet ( patterns ) ) ;
}
void CertManager : : startKeyListing ( bool validating , bool refresh , const TQStringList & patterns ) {
mRemote = mNextFindRemote ;
mLineEditAction - > setEnabled ( false ) ;
mComboAction - > setEnabled ( false ) ;
mFindAction - > setEnabled ( false ) ;
Kleo : : KeyListJob * job = 0 ;
if ( ! validating & & ! refresh & & mKeyListView - > hierarchical ( ) & & ! patterns . empty ( ) )
job = new Kleo : : HierarchicalKeyListJob ( Kleo : : CryptoBackendFactory : : instance ( ) - > smime ( ) ,
mRemote , false , validating ) ;
else
job = Kleo : : CryptoBackendFactory : : instance ( ) - > smime ( ) - > keyListJob ( mRemote , false , validating ) ;
assert ( job ) ;
connect ( job , TQT_SIGNAL ( nextKey ( const GpgME : : Key & ) ) ,
mKeyListView , refresh ? TQT_SLOT ( slotRefreshKey ( const GpgME : : Key & ) ) : TQT_SLOT ( slotAddKey ( const GpgME : : Key & ) ) ) ;
connect ( job , TQT_SIGNAL ( result ( const GpgME : : KeyListResult & ) ) ,
this , TQT_SLOT ( slotKeyListResult ( const GpgME : : KeyListResult & ) ) ) ;
connectJobToStatusBarProgress ( job , i18n ( " Fetching keys... " ) ) ;
const GpgME : : Error err = job - > start ( patterns ) ;
if ( err ) {
showKeyListError ( this , err ) ;
return ;
}
mProgressBar - > setProgress ( 0 , 0 ) ; // enable busy indicator
}
static void selectKeys ( Kleo : : KeyListView * lv , const std : : set < std : : string > & fprs ) {
if ( ! lv | | fprs . empty ( ) )
return ;
for ( TQListViewItemIterator it ( lv ) ; it . current ( ) ; + + it )
if ( Kleo : : KeyListViewItem * item = Kleo : : lvi_cast < Kleo : : KeyListViewItem > ( it . current ( ) ) ) {
const char * fpr = item - > key ( ) . primaryFingerprint ( ) ;
item - > setSelected ( fpr & & fprs . find ( fpr ) ! = fprs . end ( ) ) ;
}
}
void CertManager : : slotKeyListResult ( const GpgME : : KeyListResult & res ) {
if ( res . error ( ) )
showKeyListError ( this , res . error ( ) ) ;
else if ( res . isTruncated ( ) )
KMessageBox : : information ( this ,
i18n ( " The query result has been truncated. \n "
" Either the local or a remote limit on "
" the maximum number of returned hits has "
" been exceeded. \n "
" You can try to increase the local limit "
" in the configuration dialog, but if one "
" of the configured servers is the limiting "
" factor, you have to refine your search. " ) ) ;
mLineEditAction - > setEnabled ( true ) ;
mComboAction - > setEnabled ( true ) ;
mFindAction - > setEnabled ( true ) ;
mLineEditAction - > focusAll ( ) ;
disconnectJobFromStatusBarProgress ( res . error ( ) ) ;
selectKeys ( mKeyListView , mPreviouslySelectedFingerprints ) ;
}
void CertManager : : slotContextMenu ( Kleo : : KeyListViewItem * item , const TQPoint & point ) {
if ( ! item )
return ;
if ( TQPopupMenu * popup = static_cast < TQPopupMenu * > ( factory ( ) - > container ( " listview_popup " , this ) ) )
popup - > exec ( point ) ;
}
/**
This slot is invoked when the user selects " New certificate "
*/
void CertManager : : newCertificate ( )
{
CertificateWizardImpl wizard ( this ) ;
wizard . exec ( ) ;
}
/**
This slot is invoked when the user selects revoke certificate .
The slot will revoke the selected certificates
*/
void CertManager : : revokeCertificate ( )
{
qDebug ( " Not Yet Implemented " ) ;
}
/**
This slot is invoked when the user selects extend certificate .
It will send an extension request for the selected certificates
*/
void CertManager : : extendCertificate ( )
{
qDebug ( " Not Yet Implemented " ) ;
}
//
//
// Downloading / Importing Certificates
//
//
/**
This slot is invoked when the user selects Certificates / Import / From File .
*/
void CertManager : : slotImportCertFromFile ( )
{
const TQString filter = " application/x-x509-ca-cert application/x-pkcs12 application/pkcs7-mime " ;
//const TQString filter = TQString("*.pem *.der *.p7c *.p12|") + i18n("Certificates (*.pem *.der *.p7c *.p12)");
slotImportCertFromFile ( KFileDialog : : getOpenURL ( TQString ( ) , filter , this ,
i18n ( " Select Certificate File " ) ) ) ;
}
void CertManager : : slotImportCertFromFile ( const KURL & certURL )
{
if ( ! certURL . isValid ( ) ) // empty or malformed
return ;
mPreviouslySelectedFingerprints . clear ( ) ;
// Prevent two simultaneous imports
updateImportActions ( false ) ;
// Download the cert
KIOext : : StoredTransferJob * importJob = KIOext : : storedGet ( certURL ) ;
importJob - > setWindow ( this ) ;
connect ( importJob , TQT_SIGNAL ( result ( KIO : : Job * ) ) , TQT_SLOT ( slotImportResult ( KIO : : Job * ) ) ) ;
}
void CertManager : : slotImportResult ( KIO : : Job * job )
{
if ( job - > error ( ) ) {
job - > showErrorDialog ( ) ;
} else {
KIOext : : StoredTransferJob * trJob = static_cast < KIOext : : StoredTransferJob * > ( job ) ;
startCertificateImport ( trJob - > data ( ) , trJob - > url ( ) . fileName ( ) ) ;
}
updateImportActions ( true ) ;
}
static void showCertificateDownloadError ( TQWidget * tqparent , const GpgME : : Error & err , const TQString & certDisplayName ) {
assert ( err ) ;
const TQString msg = i18n ( " <qt><p>An error occurred while trying "
" to download the certificate %1:</p> "
" <p><b>%2</b></p></qt> " )
. tqarg ( certDisplayName )
. tqarg ( TQString : : fromLocal8Bit ( err . asString ( ) ) ) ;
KMessageBox : : error ( tqparent , msg , i18n ( " Certificate Download Failed " ) ) ;
}
void CertManager : : slotDownloadCertificate ( ) {
mPreviouslySelectedFingerprints . clear ( ) ;
TQPtrList < Kleo : : KeyListViewItem > items = mKeyListView - > selectedItems ( ) ;
for ( TQPtrListIterator < Kleo : : KeyListViewItem > it ( items ) ; it . current ( ) ; + + it )
if ( ! it . current ( ) - > key ( ) . isNull ( ) )
if ( const char * fpr = it . current ( ) - > key ( ) . primaryFingerprint ( ) )
slotStartCertificateDownload ( fpr , it . current ( ) - > text ( 0 ) ) ;
}
// Called from slotDownloadCertificate and from the certificate-details widget
void CertManager : : slotStartCertificateDownload ( const TQString & fingerprint , const TQString & displayName ) {
if ( fingerprint . isEmpty ( ) )
return ;
Kleo : : DownloadJob * job =
Kleo : : CryptoBackendFactory : : instance ( ) - > smime ( ) - > downloadJob ( false /* no armor */ ) ;
assert ( job ) ;
connect ( job , TQT_SIGNAL ( result ( const GpgME : : Error & , const TQByteArray & ) ) ,
TQT_SLOT ( slotCertificateDownloadResult ( const GpgME : : Error & , const TQByteArray & ) ) ) ;
connectJobToStatusBarProgress ( job , i18n ( " Fetching certificate from server... " ) ) ;
const GpgME : : Error err = job - > start ( fingerprint ) ;
if ( err )
showCertificateDownloadError ( this , err , displayName ) ;
else {
mProgressBar - > setProgress ( 0 , 0 ) ;
mJobsDisplayNameMap . insert ( job , displayName ) ;
}
}
TQString CertManager : : displayNameForJob ( const Kleo : : Job * job )
{
JobsDisplayNameMap : : iterator it = mJobsDisplayNameMap . tqfind ( job ) ;
TQString displayName ;
if ( it ! = mJobsDisplayNameMap . end ( ) ) {
displayName = * it ;
mJobsDisplayNameMap . remove ( it ) ;
} else {
kdWarning ( ) < < " Job not found in map: " < < job < < endl ;
}
return displayName ;
}
// Don't call directly!
void CertManager : : slotCertificateDownloadResult ( const GpgME : : Error & err , const TQByteArray & keyData ) {
TQString displayName = displayNameForJob ( static_cast < const Kleo : : Job * > ( sender ( ) ) ) ;
if ( err )
showCertificateDownloadError ( this , err , displayName ) ;
else
startCertificateImport ( keyData , displayName ) ;
disconnectJobFromStatusBarProgress ( err ) ;
}
static void showCertificateImportError ( TQWidget * tqparent , const GpgME : : Error & err , const TQString & certDisplayName ) {
assert ( err ) ;
const TQString msg = i18n ( " <qt><p>An error occurred while trying "
" to import the certificate %1:</p> "
" <p><b>%2</b></p></qt> " )
. tqarg ( certDisplayName )
. tqarg ( TQString : : fromLocal8Bit ( err . asString ( ) ) ) ;
KMessageBox : : error ( tqparent , msg , i18n ( " Certificate Import Failed " ) ) ;
}
void CertManager : : startCertificateImport ( const TQByteArray & keyData , const TQString & certDisplayName ) {
Kleo : : ImportJob * job = Kleo : : CryptoBackendFactory : : instance ( ) - > smime ( ) - > importJob ( ) ;
assert ( job ) ;
connect ( job , TQT_SIGNAL ( result ( const GpgME : : ImportResult & ) ) ,
TQT_SLOT ( slotCertificateImportResult ( const GpgME : : ImportResult & ) ) ) ;
connectJobToStatusBarProgress ( job , i18n ( " Importing certificates... " ) ) ;
kdDebug ( ) < < " Importing certificate. keyData size: " < < keyData . size ( ) < < endl ;
const GpgME : : Error err = job - > start ( keyData ) ;
if ( err )
showCertificateImportError ( this , err , certDisplayName ) ;
else {
mProgressBar - > setProgress ( 0 , 0 ) ;
mJobsDisplayNameMap . insert ( job , certDisplayName ) ;
}
}
void CertManager : : slotCertificateImportResult ( const GpgME : : ImportResult & res ) {
TQString displayName = displayNameForJob ( static_cast < const Kleo : : Job * > ( sender ( ) ) ) ;
if ( res . error ( ) . isCanceled ( ) ) {
// do nothing
} else if ( res . error ( ) ) {
showCertificateImportError ( this , res . error ( ) , displayName ) ;
} else {
const TQString normalLine = i18n ( " <tr><td align= \" right \" >%1</td><td>%2</td></tr> " ) ;
const TQString boldLine = i18n ( " <tr><td align= \" right \" ><b>%1</b></td><td>%2</td></tr> " ) ;
TQStringList lines ;
lines . push_back ( normalLine . tqarg ( i18n ( " Total number processed: " ) ,
TQString : : number ( res . numConsidered ( ) ) ) ) ;
lines . push_back ( normalLine . tqarg ( i18n ( " Imported: " ) ,
TQString : : number ( res . numImported ( ) ) ) ) ;
if ( res . newSignatures ( ) )
lines . push_back ( normalLine . tqarg ( i18n ( " New signatures: " ) ,
TQString : : number ( res . newSignatures ( ) ) ) ) ;
if ( res . newUserIDs ( ) )
lines . push_back ( normalLine . tqarg ( i18n ( " New user IDs: " ) ,
TQString : : number ( res . newUserIDs ( ) ) ) ) ;
if ( res . numKeysWithoutUserID ( ) )
lines . push_back ( normalLine . tqarg ( i18n ( " Keys without user IDs: " ) ,
TQString : : number ( res . numKeysWithoutUserID ( ) ) ) ) ;
if ( res . newSubkeys ( ) )
lines . push_back ( normalLine . tqarg ( i18n ( " New subkeys: " ) ,
TQString : : number ( res . newSubkeys ( ) ) ) ) ;
if ( res . newRevocations ( ) )
lines . push_back ( boldLine . tqarg ( i18n ( " Newly revoked: " ) ,
TQString : : number ( res . newRevocations ( ) ) ) ) ;
if ( res . notImported ( ) )
lines . push_back ( boldLine . tqarg ( i18n ( " Not imported: " ) ,
TQString : : number ( res . notImported ( ) ) ) ) ;
if ( res . numUnchanged ( ) )
lines . push_back ( normalLine . tqarg ( i18n ( " Unchanged: " ) ,
TQString : : number ( res . numUnchanged ( ) ) ) ) ;
if ( res . numSecretKeysConsidered ( ) )
lines . push_back ( normalLine . tqarg ( i18n ( " Secret keys processed: " ) ,
TQString : : number ( res . numSecretKeysConsidered ( ) ) ) ) ;
if ( res . numSecretKeysImported ( ) )
lines . push_back ( normalLine . tqarg ( i18n ( " Secret keys imported: " ) ,
TQString : : number ( res . numSecretKeysImported ( ) ) ) ) ;
if ( res . numSecretKeysConsidered ( ) - res . numSecretKeysImported ( ) - res . numSecretKeysUnchanged ( ) > 0 )
lines . push_back ( boldLine . tqarg ( i18n ( " Secret keys <em>not</em> imported: " ) ,
TQString : : number ( res . numSecretKeysConsidered ( )
- res . numSecretKeysImported ( )
- res . numSecretKeysUnchanged ( ) ) ) ) ;
if ( res . numSecretKeysUnchanged ( ) )
lines . push_back ( normalLine . tqarg ( i18n ( " Secret keys unchanged: " ) ,
TQString : : number ( res . numSecretKeysUnchanged ( ) ) ) ) ;
KMessageBox : : information ( this ,
i18n ( " <qt><p>Detailed results of importing %1:</p> "
" <table>%2</table></qt> " )
. tqarg ( displayName ) . tqarg ( lines . join ( TQString ( ) ) ) ,
i18n ( " Certificate Import Result " ) ) ;
disconnectJobFromStatusBarProgress ( res . error ( ) ) ;
// save the fingerprints of imported certs for later selection:
const std : : vector < GpgME : : Import > imports = res . imports ( ) ;
for ( std : : vector < GpgME : : Import > : : const_iterator it = imports . begin ( ) ; it ! = imports . end ( ) ; + + it )
mPreviouslySelectedFingerprints . insert ( it - > fingerprint ( ) ) ;
}
importNextURLOrRedisplay ( ) ;
}
/**
This slot is called when the dirmngr process that imports a
certificate file exists .
*/
void CertManager : : slotDirmngrExited ( ) {
if ( ! mDirmngrProc - > normalExit ( ) )
KMessageBox : : error ( this , i18n ( " The GpgSM process that tried to import the CRL file ended prematurely because of an unexpected error. " ) , i18n ( " Certificate Manager Error " ) ) ;
else if ( mDirmngrProc - > exitStatus ( ) )
KMessageBox : : error ( this , i18n ( " An error occurred when trying to import the CRL file. The output from GpgSM was: \n %1 " ) . tqarg ( mErrorbuffer ) , i18n ( " Certificate Manager Error " ) ) ;
else
KMessageBox : : information ( this , i18n ( " CRL file imported successfully. " ) , i18n ( " Certificate Manager Information " ) ) ;
delete mDirmngrProc ; mDirmngrProc = 0 ;
if ( ! mImportCRLTempFile . isEmpty ( ) )
TQFile : : remove ( mImportCRLTempFile ) ;
updateImportActions ( true ) ;
}
/**
This slot will import CRLs from a file .
*/
void CertManager : : importCRLFromFile ( ) {
// loadcrl can only work with DER encoded files (verified with dirmngr 1.0.3)
TQString filter = TQString ( " *.crl *.arl *-crl.der *-arl.der| " ) + i18n ( " Certificate Revocation List, DER encoded (*.crl *.arl *-crl.der *-arl.der) " ) ;
KURL url = KFileDialog : : getOpenURL ( TQString ( ) ,
filter ,
this ,
i18n ( " Select CRL File " ) ) ;
if ( url . isValid ( ) ) {
updateImportActions ( false ) ;
if ( url . isLocalFile ( ) ) {
startImportCRL ( url . path ( ) , false ) ;
updateImportActions ( true ) ;
} else {
KTempFile tempFile ;
KURL destURL ;
destURL . setPath ( tempFile . name ( ) ) ;
KIO : : Job * copyJob = KIO : : file_copy ( url , destURL , 0600 , true , false ) ;
copyJob - > setWindow ( this ) ;
connect ( copyJob , TQT_SIGNAL ( result ( KIO : : Job * ) ) ,
TQT_SLOT ( slotImportCRLJobFinished ( KIO : : Job * ) ) ) ;
}
}
}
void CertManager : : slotImportCRLJobFinished ( KIO : : Job * job )
{
KIO : : FileCopyJob * fcjob = static_cast < KIO : : FileCopyJob * > ( job ) ;
TQString tempFilePath = fcjob - > destURL ( ) . path ( ) ;
if ( job - > error ( ) ) {
job - > showErrorDialog ( ) ;
TQFile : : remove ( tempFilePath ) ; // unlink tempfile
updateImportActions ( true ) ;
return ;
}
startImportCRL ( tempFilePath , true ) ;
}
bool CertManager : : connectAndStartDirmngr ( const char * slot , const char * processname ) {
assert ( slot ) ;
assert ( processname ) ;
assert ( mDirmngrProc ) ;
mErrorbuffer = TQString ( ) ;
connect ( mDirmngrProc , TQT_SIGNAL ( processExited ( KProcess * ) ) , slot ) ;
connect ( mDirmngrProc , TQT_SIGNAL ( receivedStderr ( KProcess * , char * , int ) ) ,
this , TQT_SLOT ( slotStderr ( KProcess * , char * , int ) ) ) ;
if ( ! mDirmngrProc - > start ( KProcess : : NotifyOnExit , KProcess : : Stderr ) ) {
delete mDirmngrProc ; mDirmngrProc = 0 ;
KMessageBox : : error ( this , i18n ( " Unable to start %1 process. Please check your installation. " ) . tqarg ( processname ) , i18n ( " Certificate Manager Error " ) ) ;
return false ;
}
return true ;
}
void CertManager : : startImportCRL ( const TQString & filename , bool isTempFile )
{
assert ( ! mDirmngrProc ) ;
mImportCRLTempFile = isTempFile ? filename : TQString ( ) ;
mDirmngrProc = new KProcess ( ) ;
* mDirmngrProc < < " gpgsm " < < " --call-dirmngr " < < " loadcrl " < < filename ;
if ( ! connectAndStartDirmngr ( TQT_SLOT ( slotDirmngrExited ( ) ) , " gpgsm " ) ) {
updateImportActions ( true ) ;
if ( isTempFile )
TQFile : : remove ( mImportCRLTempFile ) ; // unlink tempfile
}
}
void CertManager : : startClearCRLs ( ) {
assert ( ! mDirmngrProc ) ;
mDirmngrProc = new KProcess ( ) ;
* mDirmngrProc < < " dirmngr " < < " --flush " ;
//*mDirmngrProc << "gpgsm" << "--call-dimngr" << "flush"; // use this once it's implemented!
connectAndStartDirmngr ( TQT_SLOT ( slotClearCRLsResult ( ) ) , " dirmngr " ) ;
}
void CertManager : : slotStderr ( KProcess * , char * buf , int len ) {
mErrorbuffer + = TQString : : fromLocal8Bit ( buf , len ) ;
}
/**
This slot will import CRLs from an LDAP server .
*/
void CertManager : : importCRLFromLDAP ( )
{
qDebug ( " Not Yet Implemented " ) ;
}
void CertManager : : slotViewCRLs ( ) {
if ( ! mCrlView )
mCrlView = new CRLView ( this ) ;
mCrlView - > show ( ) ;
mCrlView - > slotUpdateView ( ) ;
}
void CertManager : : slotClearCRLs ( ) {
startClearCRLs ( ) ;
}
void CertManager : : slotClearCRLsResult ( ) {
assert ( mDirmngrProc ) ;
if ( ! mDirmngrProc - > normalExit ( ) )
KMessageBox : : error ( this , i18n ( " The DirMngr process that tried to clear the CRL cache ended prematurely because of an unexpected error. " ) , i18n ( " Certificate Manager Error " ) ) ;
else if ( mDirmngrProc - > exitStatus ( ) )
KMessageBox : : error ( this , i18n ( " An error occurred when trying to clear the CRL cache. The output from DirMngr was: \n %1 " ) . tqarg ( mErrorbuffer ) , i18n ( " Certificate Manager Error " ) ) ;
else
KMessageBox : : information ( this , i18n ( " CRL cache cleared successfully. " ) , i18n ( " Certificate Manager Information " ) ) ;
delete mDirmngrProc ; mDirmngrProc = 0 ;
}
static void showDeleteError ( TQWidget * tqparent , const GpgME : : Error & err ) {
assert ( err ) ;
const TQString msg = i18n ( " <qt><p>An error occurred while trying to delete "
" the certificates:</p> "
" <p><b>%1</b></p></qt> " )
. tqarg ( TQString : : fromLocal8Bit ( err . asString ( ) ) ) ;
KMessageBox : : error ( tqparent , msg , i18n ( " Certificate Deletion Failed " ) ) ;
}
static bool ByFingerprint ( const GpgME : : Key & left , const GpgME : : Key & right ) {
return qstricmp ( left . primaryFingerprint ( ) , right . primaryFingerprint ( ) ) < 0 ;
}
static bool WithRespectToFingerprints ( const GpgME : : Key & left , const GpgME : : Key & right ) {
return qstricmp ( left . primaryFingerprint ( ) , right . primaryFingerprint ( ) ) = = 0 ;
}
void CertManager : : slotDeleteCertificate ( ) {
mItemsToDelete = mKeyListView - > selectedItems ( ) ;
if ( mItemsToDelete . isEmpty ( ) )
return ;
std : : vector < GpgME : : Key > keys ;
keys . reserve ( mItemsToDelete . count ( ) ) ;
TQStringList keyDisplayNames ;
for ( TQPtrListIterator < Kleo : : KeyListViewItem > it ( mItemsToDelete ) ; it . current ( ) ; + + it )
if ( ! it . current ( ) - > key ( ) . isNull ( ) ) {
keys . push_back ( it . current ( ) - > key ( ) ) ;
keyDisplayNames . push_back ( it . current ( ) - > text ( 0 ) ) ;
}
if ( keys . empty ( ) )
return ;
if ( ! mHierarchyAnalyser ) {
mHierarchyAnalyser = new HierarchyAnalyser ( TQT_TQOBJECT ( this ) , " mHierarchyAnalyser " ) ;
Kleo : : KeyListJob * job = Kleo : : CryptoBackendFactory : : instance ( ) - > smime ( ) - > keyListJob ( ) ;
assert ( job ) ;
connect ( job , TQT_SIGNAL ( nextKey ( const GpgME : : Key & ) ) ,
mHierarchyAnalyser , TQT_SLOT ( slotNextKey ( const GpgME : : Key & ) ) ) ;
connect ( job , TQT_SIGNAL ( result ( const GpgME : : KeyListResult & ) ) ,
this , TQT_SLOT ( slotDeleteCertificate ( ) ) ) ;
connectJobToStatusBarProgress ( job , i18n ( " Checking key dependencies... " ) ) ;
if ( const GpgME : : Error error = job - > start ( TQStringList ( ) ) ) {
showKeyListError ( this , error ) ;
delete mHierarchyAnalyser ; mHierarchyAnalyser = 0 ;
}
return ;
} else
disconnectJobFromStatusBarProgress ( 0 ) ;
std : : vector < GpgME : : Key > keysToDelete = keys ;
for ( std : : vector < GpgME : : Key > : : const_iterator it = keys . begin ( ) ; it ! = keys . end ( ) ; + + it )
if ( ! it - > isNull ( ) ) {
const std : : vector < GpgME : : Key > subjects
= mHierarchyAnalyser - > subjectsForIssuerRecursive ( it - > primaryFingerprint ( ) ) ;
keysToDelete . insert ( keysToDelete . end ( ) , subjects . begin ( ) , subjects . end ( ) ) ;
}
std : : sort ( keysToDelete . begin ( ) , keysToDelete . end ( ) , ByFingerprint ) ;
keysToDelete . erase ( std : : unique ( keysToDelete . begin ( ) , keysToDelete . end ( ) ,
WithRespectToFingerprints ) ,
keysToDelete . end ( ) ) ;
delete mHierarchyAnalyser ; mHierarchyAnalyser = 0 ;
if ( keysToDelete . size ( ) > keys . size ( ) )
if ( KMessageBox : : warningContinueCancel ( this ,
i18n ( " Some or all of the selected "
" certificates are issuers (CA certificates) "
" for other, non-selected certificates. \n "
" Deleting a CA certificate will also delete "
" all certificates issued by it. " ) ,
i18n ( " Deleting CA Certificates " ) )
! = KMessageBox : : Continue )
return ;
const TQString msg = keysToDelete . size ( ) > keys . size ( )
? i18n ( " Do you really want to delete this certificate and the %1 certificates it certified? " ,
" Do you really want to delete these %n certificates and the %1 certificates they certified? " ,
keys . size ( ) ) . tqarg ( keysToDelete . size ( ) - keys . size ( ) )
: i18n ( " Do you really want to delete this certificate? " ,
" Do you really want to delete these %n certificates? " , keys . size ( ) ) ;
if ( KMessageBox : : warningContinueCancelList ( this , msg , keyDisplayNames ,
i18n ( " Delete Certificates " ) ,
KGuiItem ( i18n ( " Delete " ) , " editdelete " ) ,
" ConfirmDeleteCert " , KMessageBox : : Dangerous )
! = KMessageBox : : Continue )
return ;
if ( Kleo : : DeleteJob * job = Kleo : : CryptoBackendFactory : : instance ( ) - > smime ( ) - > deleteJob ( ) )
job - > slotCancel ( ) ;
else {
TQString str = keys . size ( ) = = 1
? i18n ( " <qt><p>An error occurred while trying to delete "
" the certificate:</p> "
" <p><b>%1</b><p></qt> " )
: i18n ( " <qt><p>An error occurred while trying to delete "
" the certificates:</p> "
" <p><b>%1</b><p></qt> " ) ;
KMessageBox : : error ( this ,
str . tqarg ( i18n ( " Operation not supported by the backend. " ) ) ,
i18n ( " Certificate Deletion Failed " ) ) ;
}
mItemsToDelete . clear ( ) ; // re-create according to the real selection
for ( std : : vector < GpgME : : Key > : : const_iterator it = keysToDelete . begin ( ) ; it ! = keysToDelete . end ( ) ; + + it )
if ( Kleo : : KeyListViewItem * item = mKeyListView - > itemByFingerprint ( it - > primaryFingerprint ( ) ) )
mItemsToDelete . append ( item ) ;
Kleo : : MultiDeleteJob * job = new Kleo : : MultiDeleteJob ( Kleo : : CryptoBackendFactory : : instance ( ) - > smime ( ) ) ;
assert ( job ) ;
connect ( job , TQT_SIGNAL ( result ( const GpgME : : Error & , const GpgME : : Key & ) ) ,
TQT_SLOT ( slotDeleteResult ( const GpgME : : Error & , const GpgME : : Key & ) ) ) ;
connectJobToStatusBarProgress ( job , i18n ( " Deleting keys... " ) ) ;
const GpgME : : Error err = job - > start ( keys , true ) ;
if ( err )
showDeleteError ( this , err ) ;
else
mProgressBar - > setProgress ( 0 , 0 ) ;
}
void CertManager : : slotDeleteResult ( const GpgME : : Error & err , const GpgME : : Key & ) {
if ( err )
showDeleteError ( this , err ) ;
else {
const int infinity = 100 ; // infinite loop guard...
mItemsToDelete . setAutoDelete ( true ) ;
for ( int i = 0 ; i < infinity ; + + i ) {
TQPtrListIterator < Kleo : : KeyListViewItem > it ( mItemsToDelete ) ;
while ( Kleo : : KeyListViewItem * cur = it . current ( ) ) {
+ + it ;
if ( cur - > childCount ( ) = = 0 ) {
mItemsToDelete . remove ( cur ) ;
}
}
if ( mItemsToDelete . isEmpty ( ) )
break ;
}
mItemsToDelete . setAutoDelete ( false ) ;
Q_ASSERT ( mItemsToDelete . isEmpty ( ) ) ;
mItemsToDelete . clear ( ) ;
}
disconnectJobFromStatusBarProgress ( err ) ;
}
void CertManager : : slotViewDetails ( Kleo : : KeyListViewItem * item ) {
if ( ! item | | item - > key ( ) . isNull ( ) )
return ;
// <UGH>
KDialogBase * dialog = new KDialogBase ( this , " dialog " , false , i18n ( " Additional Information for Key " ) , KDialogBase : : Close , KDialogBase : : Close ) ;
CertificateInfoWidgetImpl * top = new CertificateInfoWidgetImpl ( item - > key ( ) , isRemote ( ) , dialog ) ;
dialog - > setMainWidget ( top ) ;
// </UGH>
connect ( top , TQT_SIGNAL ( requestCertificateDownload ( const TQString & , const TQString & ) ) ,
TQT_SLOT ( slotStartCertificateDownload ( const TQString & , const TQString & ) ) ) ;
dialog - > show ( ) ;
}
void CertManager : : slotViewDetails ( )
{
TQPtrList < Kleo : : KeyListViewItem > items = mKeyListView - > selectedItems ( ) ;
if ( items . isEmpty ( ) )
return ;
// selectedItem() doesn't work in Extended mode.
// But we only want to show the details of one item...
slotViewDetails ( items . first ( ) ) ;
}
void CertManager : : slotSelectionChanged ( )
{
mKeyListView - > flushKeys ( ) ;
bool b = mKeyListView - > hasSelection ( ) ;
mExportCertificateAction - > setEnabled ( b ) ;
mViewCertDetailsAction - > setEnabled ( b ) ;
mDeleteCertificateAction - > setEnabled ( b ) ;
# ifdef NOT_IMPLEMENTED_ANYWAY
mRevokeCertificateAction - > setEnabled ( b ) ;
mExtendCertificateAction - > setEnabled ( b ) ;
# endif
mDownloadCertificateAction - > setEnabled ( b & & mRemote ) ;
mValidateCertificateAction - > setEnabled ( ! mRemote ) ;
}
void CertManager : : slotExportCertificate ( ) {
TQPtrList < Kleo : : KeyListViewItem > items = mKeyListView - > selectedItems ( ) ;
if ( items . isEmpty ( ) )
return ;
TQStringList fingerprints ;
for ( TQPtrListIterator < Kleo : : KeyListViewItem > it ( items ) ; it . current ( ) ; + + it )
if ( ! it . current ( ) - > key ( ) . isNull ( ) )
if ( const char * fpr = it . current ( ) - > key ( ) . primaryFingerprint ( ) )
fingerprints . push_back ( fpr ) ;
startCertificateExport ( fingerprints ) ;
}
static void showCertificateExportError ( TQWidget * tqparent , const GpgME : : Error & err ) {
assert ( err ) ;
const TQString msg = i18n ( " <qt><p>An error occurred while trying to export "
" the certificate:</p> "
" <p><b>%1</b></p></qt> " )
. tqarg ( TQString : : fromLocal8Bit ( err . asString ( ) ) ) ;
KMessageBox : : error ( tqparent , msg , i18n ( " Certificate Export Failed " ) ) ;
}
void CertManager : : startCertificateExport ( const TQStringList & fingerprints ) {
if ( fingerprints . empty ( ) )
return ;
// we need to use PEM (ascii armoured) format, since DER (binary)
// can't transport more than one certificate *sigh* this is madness :/
Kleo : : ExportJob * job = Kleo : : CryptoBackendFactory : : instance ( ) - > smime ( ) - > publicKeyExportJob ( true ) ;
assert ( job ) ;
connect ( job , TQT_SIGNAL ( result ( const GpgME : : Error & , const TQByteArray & ) ) ,
TQT_SLOT ( slotCertificateExportResult ( const GpgME : : Error & , const TQByteArray & ) ) ) ;
connectJobToStatusBarProgress ( job , i18n ( " Exporting certificate... " ) ) ;
const GpgME : : Error err = job - > start ( fingerprints ) ;
if ( err )
showCertificateExportError ( this , err ) ;
else
mProgressBar - > setProgress ( 0 , 0 ) ;
}
// return true if we should proceed, false if we should abort
static bool checkOverwrite ( const KURL & url , bool & overwrite , TQWidget * w )
{
if ( KIO : : NetAccess : : exists ( url , false /*dest*/ , w ) ) {
if ( KMessageBox : : Cancel = =
KMessageBox : : warningContinueCancel (
w ,
i18n ( " A file named \" %1 \" already exists. "
" Are you sure you want to overwrite it? " ) . tqarg ( url . prettyURL ( ) ) ,
i18n ( " Overwrite File? " ) ,
i18n ( " &Overwrite " ) ) )
return false ;
overwrite = true ;
}
return true ;
}
void CertManager : : slotCertificateExportResult ( const GpgME : : Error & err , const TQByteArray & data ) {
disconnectJobFromStatusBarProgress ( err ) ;
if ( err ) {
showCertificateExportError ( this , err ) ;
return ;
}
kdDebug ( ) < < " CertManager::slotCertificateExportResult(): got " < < data . size ( ) < < " bytes " < < endl ;
const TQString filter = TQString ( " *.pem| " ) + i18n ( " ASCII Armored Certificate Bundles (*.pem) " ) ;
const KURL url = KFileDialog : : getOpenURL ( TQString ( ) ,
filter ,
this ,
i18n ( " Save Certificate " ) ) ;
if ( ! url . isValid ( ) )
return ;
bool overwrite = false ;
if ( ! checkOverwrite ( url , overwrite , this ) )
return ;
KIO : : Job * uploadJob = KIOext : : put ( data , url , - 1 , overwrite , false /*resume*/ ) ;
uploadJob - > setWindow ( this ) ;
connect ( uploadJob , TQT_SIGNAL ( result ( KIO : : Job * ) ) ,
this , TQT_SLOT ( slotUploadResult ( KIO : : Job * ) ) ) ;
}
void CertManager : : slotExportSecretKey ( ) {
Kleo : : KeySelectionDialog dlg ( i18n ( " Secret Key Export " ) ,
" <qt> " +
i18n ( " Select the secret key to export "
" (<b>Warning: The PKCS#12 format is insecure; "
" exporting secret keys is discouraged</b>): " ) +
" </qt> " ,
std : : vector < GpgME : : Key > ( ) ,
Kleo : : KeySelectionDialog : : SecretKeys | Kleo : : KeySelectionDialog : : SMIMEKeys ,
false /* no multiple selection */ ,
false /* no remember choice box */ ,
this , " secret key export key selection dialog " ) ;
//dlg.setHideInvalidKeys( false );
if ( dlg . exec ( ) ! = TQDialog : : Accepted )
return ;
startSecretKeyExport ( dlg . fingerprint ( ) ) ;
}
static void showSecretKeyExportError ( TQWidget * tqparent , const GpgME : : Error & err ) {
assert ( err ) ;
const TQString msg = i18n ( " <qt><p>An error occurred while trying to export "
" the secret key:</p> "
" <p><b>%1</b></p></qt> " )
. tqarg ( TQString : : fromLocal8Bit ( err . asString ( ) ) ) ;
KMessageBox : : error ( tqparent , msg , i18n ( " Secret-Key Export Failed " ) ) ;
}
void CertManager : : startSecretKeyExport ( const TQString & fingerprint ) {
if ( fingerprint . isEmpty ( ) )
return ;
// PENDING(marc): let user choose between binary and PEM format?
// Check if gpgsm supports --p12-charset
Kleo : : CryptoConfig * config = Kleo : : CryptoBackendFactory : : instance ( ) - > config ( ) ;
TQString charset ;
if ( config & & config - > entry ( " gpgsm " , " Configuration " , " p12-charset " ) ) {
// This comes from gnupg's sources, agent/minip12.c
// In fact, any charset supported by iconv would work, but we don't link to iconv directly...
static const char * charsets [ ] = {
" utf8 " ,
" iso-8859-1 " ,
" iso-8859-15 " ,
" iso-8859-2 " ,
" iso-8859-3 " ,
" iso-8859-4 " ,
" iso-8859-5 " ,
" iso-8859-6 " ,
" iso-8859-7 " ,
" iso-8859-8 " ,
" iso-8859-9 " ,
" koi8-r " ,
" ibm437 " ,
" ibm850 " ,
" euc-jp " ,
" big5 " ,
NULL
} ;
TQStringList charsetList ;
for ( const char * * c = charsets ; * c ; + + c ) {
charsetList . append ( TQString : : tqfromLatin1 ( * c ) ) ;
}
// TODO this selection could be done in a derived KeySelectionDialog which would add a combobox,
// it would be better integrated.
bool ok ;
charset = KInputDialog : : getItem ( i18n ( " Exporting secret key... " ) ,
i18n ( " Choose a charset for encoding the pkcs#12 passphrase (utf8 is recommended) " ) ,
charsetList ,
0 , false /*editable*/ ,
& ok , this ) ;
if ( ! ok )
return ;
}
Kleo : : ExportJob * job = Kleo : : CryptoBackendFactory : : instance ( ) - > smime ( ) - > secretKeyExportJob ( false , charset ) ;
assert ( job ) ;
connect ( job , TQT_SIGNAL ( result ( const GpgME : : Error & , const TQByteArray & ) ) ,
TQT_SLOT ( slotSecretKeyExportResult ( const GpgME : : Error & , const TQByteArray & ) ) ) ;
connectJobToStatusBarProgress ( job , i18n ( " Exporting secret key... " ) ) ;
const GpgME : : Error err = job - > start ( fingerprint ) ;
if ( err )
showSecretKeyExportError ( this , err ) ;
else
mProgressBar - > setProgress ( 0 , 0 ) ;
}
void CertManager : : slotSecretKeyExportResult ( const GpgME : : Error & err , const TQByteArray & data ) {
disconnectJobFromStatusBarProgress ( err ) ;
if ( err ) {
showSecretKeyExportError ( this , err ) ;
return ;
}
kdDebug ( ) < < " CertManager::slotSecretKeyExportResult(): got " < < data . size ( ) < < " bytes " < < endl ;
TQString filter = TQString ( " *.p12| " ) + i18n ( " PKCS#12 Key Bundle (*.p12) " ) ;
KURL url = KFileDialog : : getOpenURL ( TQString ( ) ,
filter ,
this ,
i18n ( " Save Certificate " ) ) ;
if ( ! url . isValid ( ) )
return ;
bool overwrite = false ;
if ( ! checkOverwrite ( url , overwrite , this ) )
return ;
KIO : : Job * uploadJob = KIOext : : put ( data , url , - 1 , overwrite , false /*resume*/ ) ;
uploadJob - > setWindow ( this ) ;
connect ( uploadJob , TQT_SIGNAL ( result ( KIO : : Job * ) ) ,
this , TQT_SLOT ( slotUploadResult ( KIO : : Job * ) ) ) ;
}
void CertManager : : slotUploadResult ( KIO : : Job * job )
{
if ( job - > error ( ) )
job - > showErrorDialog ( ) ;
}
void CertManager : : slotDropped ( const KURL : : List & lst )
{
mURLsToImport = lst ;
if ( ! lst . empty ( ) )
importNextURLOrRedisplay ( ) ;
}
void CertManager : : importNextURLOrRedisplay ( )
{
if ( ! mURLsToImport . empty ( ) ) {
// We can only import them one by one, otherwise the jobs would run into each other
KURL url = mURLsToImport . front ( ) ;
mURLsToImport . pop_front ( ) ;
slotImportCertFromFile ( url ) ;
} else {
if ( isRemote ( ) )
return ;
startKeyListing ( false , true , mPreviouslySelectedFingerprints ) ;
}
}
void CertManager : : slotStartWatchGnuPG ( )
{
KProcess certManagerProc ;
certManagerProc < < " kwatchgnupg " ;
if ( ! certManagerProc . start ( KProcess : : DontCare ) )
KMessageBox : : error ( this , i18n ( " Could not start GnuPG LogViewer (kwatchgnupg). "
" Please check your installation! " ) ,
i18n ( " Kleopatra Error " ) ) ;
}
# include "certmanager.moc"