00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
#ifdef HAVE_CONFIG_H
00034
#include <config.h>
00035
#endif
00036
00037
#include "certificateinfowidgetimpl.h"
00038
00039
00040
#include <kleo/keylistjob.h>
00041
#include <kleo/dn.h>
00042
#include <kleo/cryptobackendfactory.h>
00043
00044
#include <ui/progressdialog.h>
00045
00046
00047
#include <gpgmepp/keylistresult.h>
00048
00049
00050
#include <klocale.h>
00051
#include <kdialogbase.h>
00052
#include <kmessagebox.h>
00053
#include <kdebug.h>
00054
#include <kprocio.h>
00055
00056
00057
#include <qlistview.h>
00058
#include <qtextedit.h>
00059
#include <qheader.h>
00060
#include <qpushbutton.h>
00061
#include <qcursor.h>
00062
#include <qapplication.h>
00063
#include <qdatetime.h>
00064
00065
00066
#include <assert.h>
00067
#include <qtextcodec.h>
00068
00069 CertificateInfoWidgetImpl::CertificateInfoWidgetImpl(
const GpgME::Key & key,
bool external,
00070
QWidget * parent,
const char * name )
00071 : CertificateInfoWidget( parent, name ),
00072 mExternal( external ),
00073 mFoundIssuer( true ),
00074 mHaveKeyLocally( false )
00075 {
00076 importButton->setEnabled(
false );
00077
00078 listView->setColumnWidthMode( 1, QListView::Maximum );
00079
QFontMetrics fm = fontMetrics();
00080 listView->setColumnWidth( 1, fm.width( i18n(
"Information") ) * 5 );
00081
00082 listView->header()->setClickEnabled(
false );
00083 listView->setSorting( -1 );
00084
00085 connect( listView, SIGNAL( selectionChanged(
QListViewItem* ) ),
00086
this, SLOT( slotShowInfo(
QListViewItem* ) ) );
00087 pathView->setColumnWidthMode( 0, QListView::Maximum );
00088 pathView->header()->hide();
00089
00090 connect( pathView, SIGNAL( doubleClicked(
QListViewItem* ) ),
00091
this, SLOT( slotShowCertPathDetails(
QListViewItem* ) ) );
00092 connect( pathView, SIGNAL( returnPressed(
QListViewItem* ) ),
00093
this, SLOT( slotShowCertPathDetails(
QListViewItem* ) ) );
00094 connect( importButton, SIGNAL( clicked() ),
00095
this, SLOT( slotImportCertificate() ) );
00096
00097
if ( !key.isNull() )
00098 setKey( key );
00099 }
00100
00101
static QString time_t2string( time_t t ) {
00102
QDateTime dt;
00103 dt.setTime_t( t );
00104
return dt.toString();
00105 }
00106
00107
void CertificateInfoWidgetImpl::setKey(
const GpgME::Key & key ) {
00108 mChain.clear();
00109 mFoundIssuer =
true;
00110 mHaveKeyLocally =
false;
00111
00112 listView->clear();
00113 pathView->clear();
00114 importButton->setEnabled(
false );
00115
00116
if ( key.isNull() )
00117
return;
00118
00119 mChain.push_front( key );
00120 startKeyExistanceCheck();
00121
00122
00123
QListViewItem * item = 0;
00124 item =
new QListViewItem( listView, item, i18n(
"Valid"),
QString(
"From %1 to %2")
00125 .arg( time_t2string( key.subkey(0).creationTime() ),
00126 time_t2string( key.subkey(0).expirationTime() ) ) );
00127 item =
new QListViewItem( listView, item, i18n(
"Can be used for signing"),
00128 key.canSign() ? i18n(
"Yes") : i18n("No") );
00129 item =
new QListViewItem( listView, item, i18n(
"Can be used for encryption"),
00130 key.canEncrypt() ? i18n(
"Yes") : i18n("No") );
00131 item =
new QListViewItem( listView, item, i18n(
"Can be used for certification"),
00132 key.canCertify() ? i18n(
"Yes") : i18n("No") );
00133 item =
new QListViewItem( listView, item, i18n(
"Can be used for authentication"),
00134 key.canAuthenticate() ? i18n(
"Yes") : i18n("No" ) );
00135 item =
new QListViewItem( listView, item, i18n(
"Fingerprint"), key.subkey(0).fingerprint() );
00136 item =
new QListViewItem( listView, item, i18n(
"Issuer"),
Kleo::DN( key.issuerName() ).prettyDN() );
00137 item =
new QListViewItem( listView, item, i18n(
"Serial Number"), key.issuerSerial() );
00138
00139
const Kleo::DN dn = key.userID(0).id();
00140
00141
00142
static QMap<QString,QString> dnComponentNames;
00143
if ( dnComponentNames.isEmpty() ) {
00144 dnComponentNames[
"C"] = i18n(
"Country");
00145 dnComponentNames[
"OU"] = i18n(
"Organizational Unit");
00146 dnComponentNames[
"O"] = i18n(
"Organization");
00147 dnComponentNames[
"L"] = i18n(
"Location");
00148 dnComponentNames[
"CN"] = i18n(
"Common Name");
00149 dnComponentNames[
"EMAIL"] = i18n(
"Email");
00150 }
00151
00152
for ( Kleo::DN::const_iterator dnit = dn.
begin() ; dnit != dn.
end() ; ++dnit ) {
00153
QString displayName = (*dnit).name();
00154
if( dnComponentNames.contains(displayName) ) displayName = dnComponentNames[displayName];
00155 item =
new QListViewItem( listView, item, displayName, (*dnit).value() );
00156 }
00157
00158
const std::vector<GpgME::UserID> uids = key.userIDs();
00159
if ( !uids.empty() ) {
00160 item =
new QListViewItem( listView, item, i18n(
"Subject"),
00161
Kleo::DN( uids.front().id() ).prettyDN() );
00162
for ( std::vector<GpgME::UserID>::const_iterator it = uids.begin() + 1 ; it != uids.end() ; ++it ) {
00163
if ( !(*it).id() )
00164
continue;
00165
const QString email = QString::fromUtf8( (*it).id() ).stripWhiteSpace();
00166
if ( email.isEmpty() )
00167
continue;
00168
if ( email.startsWith(
"<" ) )
00169 item =
new QListViewItem( listView, item, i18n(
"Email"),
00170 email.mid( 1, email.length()-2 ) );
00171
else
00172 item =
new QListViewItem( listView, item, i18n(
"A.k.a."), email );
00173 }
00174 }
00175
00176 updateChainView();
00177 startCertificateChainListing();
00178 startCertificateDump();
00179 }
00180
00181
static void showChainListError(
QWidget * parent,
const GpgME::Error & err,
const char * subject ) {
00182 assert( err );
00183
const QString msg = i18n(
"<qt><p>An error occurred while fetching "
00184
"the certificate <b>%1</b> from the backend:</p>"
00185
"<p><b>%2</b></p></qt>")
00186 .arg( subject ? QString::fromUtf8( subject ) : QString::null,
00187 QString::fromLocal8Bit( err.asString() ) );
00188 KMessageBox::error( parent, msg, i18n(
"Certificate Listing Failed" ) );
00189 }
00190
00191
void CertificateInfoWidgetImpl::startCertificateChainListing() {
00192 kdDebug() <<
"CertificateInfoWidgetImpl::startCertificateChainListing()" << endl;
00193
00194
if ( mChain.empty() ) {
00195
00196 kdWarning() <<
"CertificateInfoWidgetImpl::startCertificateChainListing(): mChain is empty!" << endl;
00197
return;
00198 }
00199
const char * chainID = mChain.front().chainID();
00200
if ( !chainID || !*chainID ) {
00201
00202 kdDebug() <<
"CertificateInfoWidgetImpl::startCertificateChainListing(): empty chain ID - root not found" << endl;
00203
return;
00204 }
00205
const char * fpr = mChain.front().subkey(0).fingerprint();
00206
if ( qstricmp( fpr, chainID ) == 0 ) {
00207 kdDebug() <<
"CertificateInfoWidgetImpl::startCertificateChainListing(): chain_id equals fingerprint -> found root" << endl;
00208
return;
00209 }
00210
if ( mChain.size() > 100 ) {
00211
00212 kdWarning() <<
"CertificateInfoWidgetImpl::startCertificateChainListing(): maximum chain length of 100 exceeded!" << endl;
00213
return;
00214 }
00215
if ( !mFoundIssuer ) {
00216
00217 kdDebug() <<
"CertificateInfoWidgetImpl::startCertificateChainListing(): issuer not found - giving up" << endl;
00218
return;
00219 }
00220
00221 mFoundIssuer =
false;
00222
00223
00224
00225
00226
00227
Kleo::KeyListJob * job =
00228 Kleo::CryptoBackendFactory::instance()->smime()->keyListJob(
false );
00229 assert( job );
00230
00231 connect( job, SIGNAL(result(
const GpgME::KeyListResult&)),
00232 SLOT(slotCertificateChainListingResult(
const GpgME::KeyListResult&)) );
00233 connect( job, SIGNAL(nextKey(
const GpgME::Key&)),
00234 SLOT(slotNextKey(
const GpgME::Key&)) );
00235
00236 kdDebug() <<
"Going to fetch" << endl
00237 <<
" issuer : \"" << mChain.front().issuerName() <<
"\"" << endl
00238 <<
" chain id: " << mChain.front().chainID() << endl
00239 <<
"for" << endl
00240 <<
" subject : \"" << mChain.front().userID(0).id() <<
"\"" << endl
00241 <<
" subj.fpr: " << mChain.front().subkey(0).fingerprint() << endl;
00242
00243
const GpgME::Error err = job->
start( mChain.front().chainID() );
00244
00245
if ( err )
00246 showChainListError(
this, err, mChain.front().issuerName() );
00247
else
00248 (
void)
new Kleo::ProgressDialog( job, i18n(
"Fetching Certificate Chain"),
this );
00249 }
00250
00251
void CertificateInfoWidgetImpl::startCertificateDump() {
00252 KProcess* proc =
new KProcess(
this );
00253 (*proc) <<
"gpgsm";
00254 (*proc) <<
"--dump-keys";
00255 (*proc) << mChain.front().subkey(0).fingerprint();
00256
00257 QObject::connect( proc, SIGNAL( receivedStdout(KProcess *,
char *,
int) ),
00258
this, SLOT( slotCollectStdout(KProcess *,
char *,
int) ) );
00259 QObject::connect( proc, SIGNAL( receivedStderr(KProcess *,
char *,
int) ),
00260
this, SLOT( slotCollectStderr(KProcess *,
char *,
int) ) );
00261 QObject::connect( proc, SIGNAL( processExited(KProcess*) ),
00262
this, SLOT( slotDumpProcessExited(KProcess*) ) );
00263
00264
if ( !proc->start( KProcess::NotifyOnExit, (KProcess::Communication)(KProcess::Stdout | KProcess::Stderr) ) ) {
00265
QString wmsg = i18n(
"Failed to execute gpgsm:\n%1").arg( i18n(
"program not found" ) );
00266 dumpView->setText( wmsg );
00267 }
00268 }
00269
00270
void CertificateInfoWidgetImpl::slotCollectStdout(KProcess *,
char *buffer,
int buflen)
00271 {
00272 mDumpOutput +=
QCString(buffer, buflen+1);
00273 }
00274
00275
void CertificateInfoWidgetImpl::slotCollectStderr(KProcess *,
char *buffer,
int buflen)
00276 {
00277 mDumpError +=
QCString(buffer, buflen+1);
00278 }
00279
00280
void CertificateInfoWidgetImpl::slotDumpProcessExited(KProcess* proc) {
00281
int rc = ( proc->normalExit() ) ? proc->exitStatus() : -1 ;
00282
00283
if ( rc == 0 ) {
00284 dumpView->setText( QString::fromUtf8( mDumpOutput ) );
00285 }
else {
00286
if ( !mDumpError.isEmpty() ) {
00287 dumpView->setText( QString::fromUtf8( mDumpError ) );
00288 }
else
00289 {
00290
QString wmsg = i18n(
"Failed to execute gpgsm:\n%1");
00291
if ( rc == -1 )
00292 wmsg = wmsg.arg( i18n(
"program cannot be executed" ) );
00293
else
00294 wmsg = wmsg.arg( strerror(rc) );
00295 dumpView->setText( wmsg );
00296 }
00297 }
00298
00299 proc->deleteLater();
00300 }
00301
00302
void CertificateInfoWidgetImpl::slotNextKey(
const GpgME::Key & key ) {
00303 kdDebug() <<
"CertificateInfoWidgetImpl::slotNextKey( \""
00304 << key.userID(0).id() <<
"\" )" << endl;
00305
if ( key.isNull() )
00306
return;
00307
00308 mFoundIssuer =
true;
00309 mChain.push_front( key );
00310 updateChainView();
00311
00312 }
00313
00314
void CertificateInfoWidgetImpl::updateChainView() {
00315 pathView->clear();
00316
if ( mChain.empty() )
00317
return;
00318 QListViewItem * item = 0;
00319
00320
QValueList<GpgME::Key>::const_iterator it = mChain.begin();
00321
00322
if ( (*it).chainID() && qstrcmp( (*it).chainID(), (*it).subkey(0).fingerprint() ) == 0 )
00323 item =
new QListViewItem( pathView,
Kleo::DN( (*it++).userID(0).
id() ).prettyDN() );
00324
else {
00325 item =
new QListViewItem( pathView, i18n(
"Issuer certificate not found ( %1)")
00326 .arg(
Kleo::DN( (*it).issuerName() ).prettyDN() ) );
00327 item->setOpen(
true );
00328 item->setEnabled(
false );
00329 }
00330 item->setOpen(
true );
00331
00332
00333
while ( it != mChain.
end() ) {
00334 item =
new QListViewItem( item,
Kleo::DN( (*it++).userID(0).
id() ).prettyDN() );
00335 item->setOpen(
true );
00336 }
00337 }
00338
00339
void CertificateInfoWidgetImpl::slotCertificateChainListingResult(
const GpgME::KeyListResult & res ) {
00340
if ( res.error() )
00341
return showChainListError(
this, res.error(), mChain.front().issuerName() );
00342
else
00343 startCertificateChainListing();
00344 }
00345
00346
void CertificateInfoWidgetImpl::slotShowInfo( QListViewItem * item ) {
00347 textView->setText( item->text(1) );
00348 }
00349
00350
void CertificateInfoWidgetImpl::slotShowCertPathDetails( QListViewItem * item ) {
00351
if ( !item )
00352
return;
00353
00354
00355
00356
00357
00358
unsigned int totalCount = 0;
00359
int itemIndex = -1;
00360
for (
const QListViewItem * i = pathView->firstChild() ; i ; i = i->firstChild() ) {
00361
if ( i == item )
00362 itemIndex = totalCount;
00363 ++totalCount;
00364 }
00365
00366 assert( totalCount == mChain.size() || totalCount == mChain.size() + 1 );
00367
00368
00369
if ( totalCount == mChain.size() + 1 )
00370 --itemIndex;
00371
00372 assert( itemIndex >= 0 );
00373
00374 KDialogBase * dialog =
00375
new KDialogBase(
this,
"dialog",
false, i18n(
"Additional Information for Key"),
00376 KDialogBase::Close, KDialogBase::Close );
00377 CertificateInfoWidgetImpl * top =
00378
new CertificateInfoWidgetImpl( mChain[itemIndex], mExternal, dialog );
00379 dialog->setMainWidget( top );
00380
00381 connect( top, SIGNAL(requestCertificateDownload(
const QString&,
const QString&)),
00382 SIGNAL(requestCertificateDownload(
const QString&,
const QString&)) );
00383 dialog->show();
00384 }
00385
00386
00387
void CertificateInfoWidgetImpl::slotImportCertificate()
00388 {
00389
if ( mChain.empty() || mChain.back().isNull() )
00390
return;
00391
const Kleo::DN dn = mChain.back().userID( 0 ).id();
00392 emit requestCertificateDownload( mChain.back().subkey(0).fingerprint(), dn.
prettyDN() );
00393 importButton->setEnabled(
false );
00394 }
00395
00396
void CertificateInfoWidgetImpl::startKeyExistanceCheck() {
00397
if ( !mExternal )
00398
00399
return;
00400
if ( mChain.empty() || mChain.back().isNull() )
00401
00402
return;
00403
const QString fingerprint = mChain.back().subkey(0).fingerprint();
00404
if ( fingerprint.isEmpty() )
00405
00406
return;
00407
00408
00409
Kleo::KeyListJob * job =
00410 Kleo::CryptoBackendFactory::instance()->smime()->keyListJob(
false );
00411 assert( job );
00412
00413 connect( job, SIGNAL(nextKey(
const GpgME::Key&)),
00414 SLOT(slotKeyExistanceCheckNextCandidate(
const GpgME::Key&)) );
00415 connect( job, SIGNAL(result(
const GpgME::KeyListResult&)),
00416 SLOT(slotKeyExistanceCheckFinished()) );
00417
00418 job->
start( fingerprint );
00419 }
00420
00421
void CertificateInfoWidgetImpl::slotKeyExistanceCheckNextCandidate(
const GpgME::Key & key ) {
00422
if ( key.isNull() || mChain.empty() || !key.subkey(0).fingerprint() )
00423
return;
00424
00425
if ( qstrcmp( key.subkey(0).fingerprint(),
00426 mChain.back().subkey(0).fingerprint() ) == 0 )
00427 mHaveKeyLocally =
true;
00428 }
00429
00430
void CertificateInfoWidgetImpl::slotKeyExistanceCheckFinished() {
00431 importButton->setEnabled( !mHaveKeyLocally );
00432 }
00433
00434
00435
#include "certificateinfowidgetimpl.moc"