37 #include "certificateinfowidgetimpl.h"
40 #include <kleo/keylistjob.h>
42 #include <kleo/cryptobackendfactory.h>
44 #include <ui/progressdialog.h>
47 #include <gpgmepp/keylistresult.h>
50 #include <tdelocale.h>
51 #include <kdialogbase.h>
52 #include <tdemessagebox.h>
55 #include <tdeglobalsettings.h>
58 #include <tqlistview.h>
59 #include <tqtextedit.h>
61 #include <tqpushbutton.h>
63 #include <tqapplication.h>
64 #include <tqdatetime.h>
65 #include <tqstylesheet.h>
66 #include <tqtextcodec.h>
71 CertificateInfoWidgetImpl::CertificateInfoWidgetImpl(
const GpgME::Key & key,
bool external,
72 TQWidget * parent,
const char * name )
73 : CertificateInfoWidget( parent, name ),
74 mExternal( external ),
76 mHaveKeyLocally( false )
78 importButton->setEnabled(
false );
80 listView->setColumnWidthMode( 1, TQListView::Maximum );
81 TQFontMetrics fm = fontMetrics();
82 listView->setColumnWidth( 1, fm.width( i18n(
"Information") ) * 5 );
84 listView->header()->setClickEnabled(
false );
85 listView->setSorting( -1 );
87 connect( listView, TQ_SIGNAL( selectionChanged( TQListViewItem* ) ),
88 this, TQ_SLOT( slotShowInfo( TQListViewItem* ) ) );
89 pathView->setColumnWidthMode( 0, TQListView::Maximum );
90 pathView->header()->hide();
92 connect( pathView, TQ_SIGNAL( doubleClicked( TQListViewItem* ) ),
93 this, TQ_SLOT( slotShowCertPathDetails( TQListViewItem* ) ) );
94 connect( pathView, TQ_SIGNAL( returnPressed( TQListViewItem* ) ),
95 this, TQ_SLOT( slotShowCertPathDetails( TQListViewItem* ) ) );
96 connect( importButton, TQ_SIGNAL( clicked() ),
97 this, TQ_SLOT( slotImportCertificate() ) );
99 dumpView->setFont( TDEGlobalSettings::fixedFont() );
105 static TQString time_t2string( time_t t ) {
108 return dt.toString();
111 void CertificateInfoWidgetImpl::setKey(
const GpgME::Key & key ) {
114 mHaveKeyLocally =
false;
118 importButton->setEnabled(
false );
123 mChain.push_front( key );
124 startKeyExistanceCheck();
127 TQListViewItem * item = 0;
128 item =
new TQListViewItem( listView, item, i18n(
"Valid"), TQString(
"From %1 to %2")
129 .arg( time_t2string( key.subkey(0).creationTime() ),
130 time_t2string( key.subkey(0).expirationTime() ) ) );
131 item =
new TQListViewItem( listView, item, i18n(
"Can be used for signing"),
132 key.canSign() ? i18n(
"Yes") : i18n(
"No") );
133 item =
new TQListViewItem( listView, item, i18n(
"Can be used for encryption"),
134 key.canEncrypt() ? i18n(
"Yes") : i18n(
"No") );
135 item =
new TQListViewItem( listView, item, i18n(
"Can be used for certification"),
136 key.canCertify() ? i18n(
"Yes") : i18n(
"No") );
137 item =
new TQListViewItem( listView, item, i18n(
"Can be used for authentication"),
138 key.canAuthenticate() ? i18n(
"Yes") : i18n(
"No" ) );
139 item =
new TQListViewItem( listView, item, i18n(
"Fingerprint"), key.primaryFingerprint() );
140 item =
new TQListViewItem( listView, item, i18n(
"Issuer"), Kleo::DN( key.issuerName() ).prettyDN() );
141 item =
new TQListViewItem( listView, item, i18n(
"Serial Number"), key.issuerSerial() );
143 const Kleo::DN dn = key.userID(0).id();
146 static TQMap<TQString,TQString> dnComponentNames;
147 if ( dnComponentNames.isEmpty() ) {
148 dnComponentNames[
"C"] = i18n(
"Country");
149 dnComponentNames[
"OU"] = i18n(
"Organizational Unit");
150 dnComponentNames[
"O"] = i18n(
"Organization");
151 dnComponentNames[
"L"] = i18n(
"Location");
152 dnComponentNames[
"CN"] = i18n(
"Common Name");
153 dnComponentNames[
"EMAIL"] = i18n(
"Email");
156 for ( Kleo::DN::const_iterator dnit = dn.begin() ; dnit != dn.end() ; ++dnit ) {
157 TQString displayName = (*dnit).name();
158 if( dnComponentNames.contains(displayName) ) displayName = dnComponentNames[displayName];
159 item =
new TQListViewItem( listView, item, displayName, (*dnit).value() );
162 const std::vector<GpgME::UserID> uids = key.userIDs();
163 if ( !uids.empty() ) {
164 item =
new TQListViewItem( listView, item, i18n(
"Subject"),
165 Kleo::DN( uids.front().id() ).prettyDN() );
166 for ( std::vector<GpgME::UserID>::const_iterator it = uids.begin() + 1 ; it != uids.end() ; ++it ) {
169 const TQString email = TQString::fromUtf8( (*it).id() ).stripWhiteSpace();
170 if ( email.isEmpty() )
172 if ( email.startsWith(
"<" ) )
173 item =
new TQListViewItem( listView, item, i18n(
"Email"),
174 email.mid( 1, email.length()-2 ) );
176 item =
new TQListViewItem( listView, item, i18n(
"A.k.a."), email );
181 startCertificateChainListing();
182 startCertificateDump();
185 static void showChainListError( TQWidget * parent,
const GpgME::Error & err,
const char * subject ) {
187 const TQString msg = i18n(
"<qt><p>An error occurred while fetching "
188 "the certificate <b>%1</b> from the backend:</p>"
189 "<p><b>%2</b></p></qt>")
190 .arg( subject ? TQString::fromUtf8( subject ) : TQString(),
191 TQString::fromLocal8Bit( err.asString() ) );
192 KMessageBox::error( parent, msg, i18n(
"Certificate Listing Failed" ) );
195 void CertificateInfoWidgetImpl::startCertificateChainListing() {
196 kdDebug() <<
"CertificateInfoWidgetImpl::startCertificateChainListing()" << endl;
198 if ( mChain.empty() ) {
200 kdWarning() <<
"CertificateInfoWidgetImpl::startCertificateChainListing(): mChain is empty!" << endl;
203 const char * chainID = mChain.front().chainID();
204 if ( !chainID || !*chainID ) {
206 kdDebug() <<
"CertificateInfoWidgetImpl::startCertificateChainListing(): empty chain ID - root not found" << endl;
209 const char * fpr = mChain.front().primaryFingerprint();
210 if ( tqstricmp( fpr, chainID ) == 0 ) {
211 kdDebug() <<
"CertificateInfoWidgetImpl::startCertificateChainListing(): chain_id equals fingerprint -> found root" << endl;
214 if ( mChain.size() > 100 ) {
216 kdWarning() <<
"CertificateInfoWidgetImpl::startCertificateChainListing(): maximum chain length of 100 exceeded!" << endl;
219 if ( !mFoundIssuer ) {
221 kdDebug() <<
"CertificateInfoWidgetImpl::startCertificateChainListing(): issuer not found - giving up" << endl;
225 mFoundIssuer =
false;
231 Kleo::KeyListJob * job =
232 Kleo::CryptoBackendFactory::instance()->smime()->keyListJob(
false );
235 connect( job, TQ_SIGNAL(result(
const GpgME::KeyListResult&)),
236 TQ_SLOT(slotCertificateChainListingResult(
const GpgME::KeyListResult&)) );
237 connect( job, TQ_SIGNAL(nextKey(
const GpgME::Key&)),
238 TQ_SLOT(slotNextKey(
const GpgME::Key&)) );
240 kdDebug() <<
"Going to fetch" << endl
241 <<
" issuer : \"" << mChain.front().issuerName() <<
"\"" << endl
242 <<
" chain id: " << mChain.front().chainID() << endl
244 <<
" subject : \"" << mChain.front().userID(0).id() <<
"\"" << endl
245 <<
" subj.fpr: " << mChain.front().primaryFingerprint() << endl;
247 const GpgME::Error err = job->start( mChain.front().chainID() );
250 showChainListError(
this, err, mChain.front().issuerName() );
252 (
void)
new Kleo::ProgressDialog( job, i18n(
"Fetching Certificate Chain"),
this );
255 void CertificateInfoWidgetImpl::startCertificateDump() {
256 TDEProcess* proc =
new TDEProcess(
this );
258 (*proc) <<
"--dump-keys";
259 (*proc) << mChain.front().primaryFingerprint();
261 TQObject::connect( proc, TQ_SIGNAL( receivedStdout(TDEProcess *,
char *,
int) ),
262 this, TQ_SLOT( slotCollectStdout(TDEProcess *,
char *,
int) ) );
263 TQObject::connect( proc, TQ_SIGNAL( receivedStderr(TDEProcess *,
char *,
int) ),
264 this, TQ_SLOT( slotCollectStderr(TDEProcess *,
char *,
int) ) );
265 TQObject::connect( proc, TQ_SIGNAL( processExited(TDEProcess*) ),
266 this, TQ_SLOT( slotDumpProcessExited(TDEProcess*) ) );
268 if ( !proc->start( TDEProcess::NotifyOnExit, (TDEProcess::Communication)(TDEProcess::Stdout | TDEProcess::Stderr) ) ) {
269 TQString wmsg = i18n(
"Failed to execute gpgsm:\n%1").arg( i18n(
"program not found" ) );
270 dumpView->setText( TQStyleSheet::escape( wmsg ) );
275 void CertificateInfoWidgetImpl::slotCollectStdout(TDEProcess *,
char *buffer,
int buflen)
277 mDumpOutput += TQCString(buffer, buflen+1);
280 void CertificateInfoWidgetImpl::slotCollectStderr(TDEProcess *,
char *buffer,
int buflen)
282 mDumpError += TQCString(buffer, buflen+1);
285 void CertificateInfoWidgetImpl::slotDumpProcessExited(TDEProcess* proc) {
286 int rc = ( proc->normalExit() ) ? proc->exitStatus() : -1 ;
289 dumpView->setText( TQStyleSheet::escape( TQString::fromUtf8( mDumpOutput ) ) );
291 if ( !mDumpError.isEmpty() ) {
292 dumpView->setText( TQStyleSheet::escape( TQString::fromUtf8( mDumpError ) ) );
295 TQString wmsg = i18n(
"Failed to execute gpgsm:\n%1");
297 wmsg = wmsg.arg( i18n(
"program cannot be executed" ) );
299 wmsg = wmsg.arg( strerror(rc) );
300 dumpView->setText( TQStyleSheet::escape( wmsg ) );
307 void CertificateInfoWidgetImpl::slotNextKey(
const GpgME::Key & key ) {
308 kdDebug() <<
"CertificateInfoWidgetImpl::slotNextKey( \""
309 << key.userID(0).id() <<
"\" )" << endl;
314 mChain.push_front( key );
319 void CertificateInfoWidgetImpl::updateChainView() {
321 if ( mChain.empty() )
323 TQListViewItem * item = 0;
325 TQValueList<GpgME::Key>::const_iterator it = mChain.begin();
327 if ( (*it).chainID() && qstrcmp( (*it).chainID(), (*it).primaryFingerprint() ) == 0 )
328 item =
new TQListViewItem( pathView, Kleo::DN( (*it++).userID(0).
id() ).prettyDN() );
330 item =
new TQListViewItem( pathView, i18n(
"Issuer certificate not found ( %1)")
331 .arg( Kleo::DN( (*it).issuerName() ).prettyDN() ) );
332 item->setOpen(
true );
333 item->setEnabled(
false );
335 item->setOpen(
true );
338 while ( it != mChain.end() ) {
339 item =
new TQListViewItem( item, Kleo::DN( (*it++).userID(0).
id() ).prettyDN() );
340 item->setOpen(
true );
344 void CertificateInfoWidgetImpl::slotCertificateChainListingResult(
const GpgME::KeyListResult & res ) {
346 return showChainListError(
this, res.error(), mChain.front().issuerName() );
348 startCertificateChainListing();
351 void CertificateInfoWidgetImpl::slotShowInfo( TQListViewItem * item ) {
352 textView->setText( item->text(1) );
355 void CertificateInfoWidgetImpl::slotShowCertPathDetails( TQListViewItem * item ) {
363 unsigned int totalCount = 0;
365 for (
const TQListViewItem * i = pathView->firstChild() ; i ; i = i->firstChild() ) {
367 itemIndex = totalCount;
371 assert( totalCount == mChain.size() || totalCount == mChain.size() + 1 );
374 if ( totalCount == mChain.size() + 1 )
377 assert( itemIndex >= 0 );
379 KDialogBase * dialog =
380 new KDialogBase(
this,
"dialog",
false, i18n(
"Additional Information for Key"),
381 KDialogBase::Close, KDialogBase::Close );
382 CertificateInfoWidgetImpl * top =
383 new CertificateInfoWidgetImpl( mChain[itemIndex], mExternal, dialog );
384 dialog->setMainWidget( top );
386 connect( top, TQ_SIGNAL(requestCertificateDownload(
const TQString&,
const TQString&)),
387 TQ_SIGNAL(requestCertificateDownload(
const TQString&,
const TQString&)) );
392 void CertificateInfoWidgetImpl::slotImportCertificate()
394 if ( mChain.empty() || mChain.back().isNull() )
396 const Kleo::DN dn = mChain.back().userID( 0 ).id();
397 emit requestCertificateDownload( mChain.back().primaryFingerprint(), dn.prettyDN() );
398 importButton->setEnabled(
false );
401 void CertificateInfoWidgetImpl::startKeyExistanceCheck() {
405 if ( mChain.empty() || mChain.back().isNull() )
408 const TQString fingerprint = mChain.back().primaryFingerprint();
409 if ( fingerprint.isEmpty() )
414 Kleo::KeyListJob * job =
415 Kleo::CryptoBackendFactory::instance()->smime()->keyListJob(
false );
418 connect( job, TQ_SIGNAL(nextKey(
const GpgME::Key&)),
419 TQ_SLOT(slotKeyExistanceCheckNextCandidate(
const GpgME::Key&)) );
420 connect( job, TQ_SIGNAL(result(
const GpgME::KeyListResult&)),
421 TQ_SLOT(slotKeyExistanceCheckFinished()) );
423 job->start( fingerprint );
426 void CertificateInfoWidgetImpl::slotKeyExistanceCheckNextCandidate(
const GpgME::Key & key ) {
427 if ( key.isNull() || mChain.empty() || !key.primaryFingerprint() )
430 if ( qstrcmp( key.primaryFingerprint(),
431 mChain.back().primaryFingerprint() ) == 0 )
432 mHaveKeyLocally =
true;
435 void CertificateInfoWidgetImpl::slotKeyExistanceCheckFinished() {
436 importButton->setEnabled( !mHaveKeyLocally );
440 #include "certificateinfowidgetimpl.moc"