• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdepim
  • Sitemap
  • Contact Us
 

libkpgp

kpgpui.cpp

Go to the documentation of this file.
00001 /*
00002     kpgpui.cpp
00003 
00004     Copyright (C) 2001,2002 the KPGP authors
00005     See file AUTHORS.kpgp for details
00006 
00007     This file is part of KPGP, the KDE PGP/GnuPG support library.
00008 
00009     KPGP is free software; you can redistribute it and/or modify
00010     it under the terms of the GNU General Public License as published by
00011     the Free Software Foundation; either version 2 of the License, or
00012     (at your option) any later version.
00013 
00014     You should have received a copy of the GNU General Public License
00015     along with this program; if not, write to the Free Software Foundation,
00016     Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
00017  */
00018 
00019 #include "kpgpui.h"
00020 #include "kpgp.h"
00021 #include "kpgpkey.h"
00022 
00023 #include <QLabel>
00024 #include <QApplication>
00025 #include <QTextCodec>
00026 #include <QDateTime>
00027 #include <QPixmap>
00028 #include <QLayout>
00029 #include <QTimer>
00030 #include <QMenu>
00031 #include <QRegExp>
00032 #include <QFrame>
00033 #include <QByteArray>
00034 #include <QVBoxLayout>
00035 #include <QHBoxLayout>
00036 #include <QProgressBar>
00037 #include <QButtonGroup>
00038 #include <q3multilineedit.h>
00039 #include <QGroupBox>
00040 
00041 #include <k3listview.h>
00042 #include <kvbox.h>
00043 #include <kconfiggroup.h>
00044 #include <klocale.h>
00045 #include <kpassworddialog.h>
00046 #include <kcharsets.h>
00047 #include <kseparator.h>
00048 #include <kiconloader.h>
00049 #include <kconfigbase.h>
00050 #include <kconfig.h>
00051 #include <kprogressdialog.h>
00052 #include <kwindowsystem.h>
00053 #include <kpushbutton.h>
00054 #include <kglobalsettings.h>
00055 #include <klineedit.h>
00056 
00057 #include <assert.h>
00058 #include <string.h> // for memcpy(3)
00059 
00060 const int Kpgp::KeySelectionDialog::sCheckSelectionDelay = 250;
00061 
00062 namespace Kpgp {
00063 
00064 PassphraseDialog::PassphraseDialog( QWidget *parent,
00065                                     const QString &caption,
00066                                     const QString &keyID )
00067   :KPasswordDialog( parent )
00068 {
00069   setCaption( caption );
00070   setButtons( Ok|Cancel );
00071 
00072   setPixmap( BarIcon("dialog-password") );
00073 
00074   if (keyID.isNull())
00075     setPrompt(i18n("Please enter your OpenPGP passphrase:"));
00076   else
00077     setPrompt(i18n("Please enter the OpenPGP passphrase for\n\"%1\":", keyID) );
00078 }
00079 
00080 
00081 PassphraseDialog::~PassphraseDialog()
00082 {
00083 }
00084 
00085 QString PassphraseDialog::passphrase()
00086 {
00087   return password();
00088 }
00089 
00090 
00091 // ------------------------------------------------------------------------
00092 // Forbidden accels for KMail: AC GH OP
00093 //                  for KNode: ACE H O
00094 Config::Config( QWidget *parent, bool encrypt )
00095   : QWidget( parent ), pgp( Module::getKpgp() )
00096 {
00097   QGroupBox * group;
00098   QLabel    * label;
00099   QString     msg;
00100 
00101 
00102   QVBoxLayout *topLayout = new QVBoxLayout( this );
00103   topLayout->setSpacing( KDialog::spacingHint() );
00104   topLayout->setMargin( 0 );
00105 
00106   group = new QGroupBox( i18n("Warning"), this );
00107   QVBoxLayout *lay = new QVBoxLayout(group);
00108   lay->setSpacing( KDialog::spacingHint() );
00109   // (mmutz) work around Qt label bug in 3.0.0 (and possibly later):
00110   // 1. Don't use rich text: No <qt><b>...</b></qt>
00111   label = new QLabel( i18n("Please check if encryption really "
00112     "works before you start using it seriously. Also note that attachments "
00113     "are not encrypted by the PGP/GPG module."), group );
00114   label->setWordWrap( true );
00115   lay->addWidget( label );
00116   // 2. instead, set the font to bold:
00117   QFont labelFont = label->font();
00118   labelFont.setBold( true );
00119   label->setFont( labelFont );
00120   // 3. and activate wordwarp:
00121   // end; to remove the workaround, add <qt><b>..</b></qt> around the
00122   // text and remove lines QFont... -> label->setAlignment(...).
00123   topLayout->addWidget( group );
00124   group = new QGroupBox( i18n("Encryption Tool"), this );
00125   lay = new QVBoxLayout(group);
00126   lay->setSpacing( KDialog::spacingHint() );
00127 
00128   KHBox * hbox = new KHBox( group );
00129   lay->addWidget( hbox );
00130   label = new QLabel( i18n("Select encryption tool to &use:"), hbox );
00131   toolCombo = new QComboBox( hbox );
00132   toolCombo->setEditable( false );
00133   toolCombo->addItems( QStringList()
00134                    << i18n("Autodetect")
00135                    << i18n("GnuPG - Gnu Privacy Guard")
00136                    << i18n("PGP Version 2.x")
00137                    << i18n("PGP Version 5.x")
00138                    << i18n("PGP Version 6.x")
00139                    << i18n("Do not use any encryption tool") );
00140   label->setBuddy( toolCombo );
00141   hbox->setStretchFactor( toolCombo, 1 );
00142   connect( toolCombo, SIGNAL( activated( int ) ),
00143            this, SIGNAL( changed( void ) ) );
00144   // This is the place to add a KUrlRequester to be used for asking
00145   // the user for the path to the executable...
00146   topLayout->addWidget( group );
00147 
00148   mpOptionsGroupBox = new QGroupBox( i18n("Options"), this );
00149   lay = new QVBoxLayout( mpOptionsGroupBox );
00150   lay->setSpacing( KDialog::spacingHint() );
00151   storePass = new QCheckBox( i18n("&Keep passphrase in memory"),
00152                              mpOptionsGroupBox );
00153   lay->addWidget( storePass );
00154   connect( storePass, SIGNAL( toggled( bool ) ),
00155            this, SIGNAL( changed( void ) ) );
00156   msg = i18n( "<qt><p>When this option is enabled, the passphrase of your "
00157           "private key will be remembered by the application as long "
00158           "as the application is running. Thus you will only have to "
00159           "enter the passphrase once.</p><p>Be aware that this could be a "
00160           "security risk. If you leave your computer, others "
00161           "can use it to send signed messages and/or read your encrypted "
00162           "messages. If a core dump occurs, the contents of your RAM will "
00163           "be saved onto disk, including your passphrase.</p>"
00164           "<p>Note that when using KMail, this setting only applies "
00165           "if you are not using gpg-agent. It is also ignored "
00166           "if you are using crypto plugins.</p></qt>" );
00167   storePass->setWhatsThis( msg );
00168   if( encrypt ) {
00169     encToSelf = new QCheckBox( i18n("Always encr&ypt to self"),
00170                                mpOptionsGroupBox );
00171    connect( encToSelf, SIGNAL( toggled( bool ) ),
00172            this, SIGNAL( changed( void ) ) );
00173 
00174     msg = i18n( "<qt><p>When this option is enabled, the message/file "
00175         "will not only be encrypted with the receiver's public key, "
00176         "but also with your key. This will enable you to decrypt the "
00177         "message/file at a later time. This is generally a good idea."
00178         "</p></qt>" );
00179     encToSelf->setWhatsThis( msg );
00180   }
00181   else
00182     encToSelf = 0;
00183   showCipherText = new QCheckBox( i18n("&Show signed/encrypted text after "
00184                                        "composing"));
00185   lay->addWidget( showCipherText );
00186   connect( showCipherText, SIGNAL( toggled( bool ) ),
00187            this, SIGNAL( changed( void ) ) );
00188 
00189   msg = i18n( "<qt><p>When this option is enabled, the signed/encrypted text "
00190           "will be shown in a separate window, enabling you to know how "
00191           "it will look before it is sent. This is a good idea when "
00192           "you are verifying that your encryption system works.</p></qt>" );
00193   showCipherText->setWhatsThis( msg );
00194   if( encrypt ) {
00195     showKeyApprovalDlg = new QCheckBox( i18n("Always show the encryption "
00196                                              "keys &for approval"));
00197     lay->addWidget( showKeyApprovalDlg );
00198     connect( showKeyApprovalDlg, SIGNAL( toggled( bool ) ),
00199            this, SIGNAL( changed( void ) ) );
00200     msg = i18n( "<qt><p>When this option is enabled, the application will "
00201         "always show you a list of public keys from which you can "
00202         "choose the one it will use for encryption. If it is off, "
00203         "the application will only show the dialog if it cannot find "
00204         "the right key or if there are several which could be used. "
00205         "</p></qt>" );
00206     showKeyApprovalDlg->setWhatsThis( msg );
00207 }
00208   else
00209     showKeyApprovalDlg = 0;
00210 
00211   topLayout->addWidget( mpOptionsGroupBox );
00212 
00213   topLayout->addStretch(1);
00214 
00215   setValues();  // is this needed by KNode, b/c for KMail, it's not.
00216 }
00217 
00218 
00219 Config::~Config()
00220 {
00221 }
00222 
00223 void
00224 Config::setValues()
00225 {
00226   // set default values
00227   storePass->setChecked( pgp->storePassPhrase() );
00228   if( 0 != encToSelf )
00229     encToSelf->setChecked( pgp->encryptToSelf() );
00230   showCipherText->setChecked( pgp->showCipherText() );
00231   if( 0 != showKeyApprovalDlg )
00232     showKeyApprovalDlg->setChecked( pgp->showKeyApprovalDlg() );
00233 
00234   int type = 0;
00235   switch (pgp->pgpType) {
00236     // translate Kpgp::Module enum to combobox' entries:
00237   default:
00238   case Module::tAuto: type = 0; break;
00239   case Module::tGPG:  type = 1; break;
00240   case Module::tPGP2: type = 2; break;
00241   case Module::tPGP5: type = 3; break;
00242   case Module::tPGP6: type = 4; break;
00243   case Module::tOff:  type = 5; break;
00244   }
00245   toolCombo->setCurrentIndex( type );
00246 }
00247 
00248 void
00249 Config::applySettings()
00250 {
00251   pgp->setStorePassPhrase(storePass->isChecked());
00252   if( 0 != encToSelf )
00253     pgp->setEncryptToSelf(encToSelf->isChecked());
00254   pgp->setShowCipherText(showCipherText->isChecked());
00255   if( 0 != showKeyApprovalDlg )
00256     pgp->setShowKeyApprovalDlg( showKeyApprovalDlg->isChecked() );
00257 
00258   Module::PGPType type;
00259   switch ( toolCombo->currentIndex() ) {
00260     // convert combobox entry indices to Kpgp::Module constants:
00261   default:
00262   case 0: type = Module::tAuto; break;
00263   case 1: type = Module::tGPG;  break;
00264   case 2: type = Module::tPGP2; break;
00265   case 3: type = Module::tPGP5; break;
00266   case 4: type = Module::tPGP6; break;
00267   case 5: type = Module::tOff;  break;
00268   }
00269   pgp->pgpType = type;
00270 
00271   pgp->writeConfig(true);
00272 }
00273 
00274 
00275 
00276 // ------------------------------------------------------------------------
00277 KeySelectionDialog::KeySelectionDialog( const KeyList& keyList,
00278                                         const QString& title,
00279                                         const QString& text,
00280                                         const KeyIDList& keyIds,
00281                                         const bool rememberChoice,
00282                                         const unsigned int allowedKeys,
00283                                         const bool extendedSelection,
00284                                         QWidget *parent )
00285   : KDialog( parent ),
00286     mRememberCB( 0 ),
00287     mAllowedKeys( allowedKeys ),
00288     mCurrentContextMenuItem( 0 )
00289 {
00290   setCaption( title );
00291   setButtons( Default|Ok|Cancel );
00292   if ( qApp ) {
00293     KWindowSystem::setIcons( winId(),
00294                              qApp->windowIcon().pixmap( IconSize( KIconLoader::Desktop ),
00295                                                         IconSize( KIconLoader::Desktop ) ),
00296                              qApp->windowIcon().pixmap( IconSize( KIconLoader::Small ),
00297                                                         IconSize( KIconLoader::Small ) ) );
00298   }
00299   Kpgp::Module *pgp = Kpgp::Module::getKpgp();
00300   KConfig *config = pgp->getConfig();
00301   KConfigGroup dialogConfig( config, "Key Selection Dialog" );
00302 
00303   QSize defaultSize( 580, 400 );
00304   QSize dialogSize = dialogConfig.readEntry( "Dialog size", defaultSize );
00305 
00306   resize( dialogSize );
00307 
00308   mCheckSelectionTimer = new QTimer( this );
00309   mStartSearchTimer = new QTimer( this );
00310   mStartSearchTimer->setSingleShot( true );
00311 
00312   // load the key status icons
00313   mKeyGoodPix    = new QPixmap( UserIcon("key_ok") );
00314   mKeyBadPix     = new QPixmap( UserIcon("key_bad") );
00315   mKeyUnknownPix = new QPixmap( UserIcon("key_unknown") );
00316   mKeyValidPix   = new QPixmap( UserIcon("key") );
00317 
00318   QFrame *page = new QFrame( this );
00319   setMainWidget( page );
00320   QVBoxLayout *topLayout = new QVBoxLayout( page );
00321   topLayout->setSpacing( spacingHint() );
00322   topLayout->setMargin( 0 );
00323 
00324   if( !text.isEmpty() ) {
00325     QLabel *label = new QLabel( page );
00326     label->setText( text );
00327     topLayout->addWidget( label );
00328   }
00329 
00330   QHBoxLayout * hlay = new QHBoxLayout(); // inherits spacing
00331   topLayout->addLayout( hlay );
00332   QLineEdit * le = new QLineEdit( page );
00333   QLabel *label = new QLabel( i18n("&Search for:"), page );
00334   label->setBuddy( le );
00335   hlay->addWidget( label );
00336   hlay->addWidget( le, 1 );
00337   le->setFocus();
00338 
00339   connect( le, SIGNAL(textChanged(const QString&)),
00340        this, SLOT(slotSearch(const QString&)) );
00341   connect( mStartSearchTimer, SIGNAL(timeout()), SLOT(slotFilter()) );
00342 
00343   mListView = new K3ListView( page );
00344   mListView->addColumn( i18n("Key ID") );
00345   mListView->addColumn( i18n("User ID") );
00346   mListView->setAllColumnsShowFocus( true );
00347   mListView->setResizeMode( Q3ListView::LastColumn );
00348   mListView->setRootIsDecorated( true );
00349   mListView->setShowSortIndicator( true );
00350   mListView->setSorting( 1, true ); // sort by User ID
00351   mListView->setShowToolTips( true );
00352   if( extendedSelection ) {
00353     mListView->setSelectionMode( Q3ListView::Extended );
00354     //mListView->setSelectionMode( QListView::Multi );
00355   }
00356   topLayout->addWidget( mListView, 10 );
00357 
00358   if (rememberChoice) {
00359     mRememberCB = new QCheckBox( i18n("Remember choice"), page );
00360     topLayout->addWidget( mRememberCB );
00361     mRememberCB->setWhatsThis(
00362                     i18n("<qt><p>If you check this box your choice will "
00363                          "be stored and you will not be asked again."
00364                          "</p></qt>"));
00365   }
00366 
00367   initKeylist( keyList, keyIds );
00368 
00369   Q3ListViewItem *lvi;
00370   if( extendedSelection ) {
00371     lvi = mListView->currentItem();
00372     slotCheckSelection();
00373   }
00374   else {
00375     lvi = mListView->selectedItem();
00376     slotCheckSelection( lvi );
00377   }
00378   // make sure that the selected item is visible
00379   // (ensureItemVisible(...) doesn't work correctly in Qt 3.0.0)
00380   if( lvi != 0 )
00381     mListView->center( mListView->contentsX(), mListView->itemPos( lvi ) );
00382 
00383   if( extendedSelection ) {
00384     connect( mCheckSelectionTimer, SIGNAL( timeout() ),
00385              this,                 SLOT( slotCheckSelection() ) );
00386     connect( mListView, SIGNAL( selectionChanged() ),
00387              this,      SLOT( slotSelectionChanged() ) );
00388   }
00389   else {
00390     connect( mListView, SIGNAL( selectionChanged( Q3ListViewItem* ) ),
00391              this,      SLOT( slotSelectionChanged( Q3ListViewItem* ) ) );
00392   }
00393   connect( mListView, SIGNAL( doubleClicked ( Q3ListViewItem *, const QPoint &, int ) ), this, SLOT( accept() ) );
00394 
00395   connect( mListView, SIGNAL( contextMenuRequested( Q3ListViewItem*,
00396                                                     const QPoint&, int ) ),
00397            this,      SLOT( slotRMB( Q3ListViewItem*, const QPoint&, int ) ) );
00398 
00399   setButtonGuiItem( KDialog::Default, KGuiItem(i18n("&Reread Keys")) );
00400   connect( this, SIGNAL( defaultClicked() ),
00401            this, SLOT( slotRereadKeys() ) );
00402   connect(this, SIGNAL( okClicked()),SLOT(slotOk()));
00403   connect(this,SIGNAL( cancelClicked()),SLOT(slotCancel()));
00404 }
00405 
00406 
00407 KeySelectionDialog::~KeySelectionDialog()
00408 {
00409   Kpgp::Module *pgp = Kpgp::Module::getKpgp();
00410   KConfig *config = pgp->getConfig();
00411   KConfigGroup dialogConfig( config, "Key Selection Dialog" );
00412   dialogConfig.writeEntry( "Dialog size", size() );
00413   config->sync();
00414   delete mKeyGoodPix;
00415   delete mKeyBadPix;
00416   delete mKeyUnknownPix;
00417   delete mKeyValidPix;
00418 }
00419 
00420 
00421 KeyID KeySelectionDialog::key() const
00422 {
00423   if( mListView->isMultiSelection() || mKeyIds.isEmpty() )
00424     return KeyID();
00425   else
00426     return mKeyIds.first();
00427 }
00428 
00429 
00430 void KeySelectionDialog::initKeylist( const KeyList& keyList,
00431                                       const KeyIDList& keyIds )
00432 {
00433   Q3ListViewItem* firstSelectedItem = 0;
00434   mKeyIds.clear();
00435   mListView->clear();
00436 
00437   // build a list of all public keys
00438   for( KeyListIterator it( keyList ); it.current(); ++it ) {
00439     KeyID curKeyId = (*it)->primaryKeyID();
00440 
00441     Q3ListViewItem* primaryUserID = new Q3ListViewItem( mListView, curKeyId,
00442                                                       (*it)->primaryUserID() );
00443 
00444     // select and open the given key
00445     if( keyIds.indexOf( curKeyId ) != -1 ) {
00446       if( 0 == firstSelectedItem ) {
00447         firstSelectedItem = primaryUserID;
00448       }
00449       mListView->setSelected( primaryUserID, true );
00450       mKeyIds.append( curKeyId );
00451     }
00452     primaryUserID->setOpen( false );
00453 
00454     // set icon for this key
00455     switch( keyValidity( *it ) ) {
00456       case 0: // the key's validity can't be determined
00457         primaryUserID->setPixmap( 0, *mKeyUnknownPix );
00458         break;
00459       case 1: // key is valid but not trusted
00460         primaryUserID->setPixmap( 0, *mKeyValidPix );
00461         break;
00462       case 2: // key is valid and trusted
00463         primaryUserID->setPixmap( 0, *mKeyGoodPix );
00464         break;
00465       case -1: // key is invalid
00466         primaryUserID->setPixmap( 0, *mKeyBadPix );
00467         break;
00468     }
00469 
00470     Q3ListViewItem* childItem;
00471 
00472     childItem = new Q3ListViewItem( primaryUserID, "",
00473                                    i18n( "Fingerprint: %1" ,
00474                                      beautifyFingerprint( (*it)->primaryFingerprint() ) ) );
00475     if( primaryUserID->isSelected() && mListView->isMultiSelection() ) {
00476       mListView->setSelected( childItem, true );
00477     }
00478 
00479     childItem = new Q3ListViewItem( primaryUserID, "", keyInfo( *it ) );
00480     if( primaryUserID->isSelected() && mListView->isMultiSelection() ) {
00481       mListView->setSelected( childItem, true );
00482     }
00483 
00484     UserIDList userIDs = (*it)->userIDs();
00485     UserIDListIterator uidit( userIDs );
00486     if( *uidit ) {
00487       ++uidit; // skip the primary user ID
00488       for( ; *uidit; ++uidit ) {
00489         childItem = new Q3ListViewItem( primaryUserID, "", (*uidit)->text() );
00490         if( primaryUserID->isSelected() && mListView->isMultiSelection() ) {
00491           mListView->setSelected( childItem, true );
00492         }
00493       }
00494     }
00495   }
00496 
00497   if( 0 != firstSelectedItem ) {
00498     mListView->setCurrentItem( firstSelectedItem );
00499   }
00500 }
00501 
00502 
00503 QString KeySelectionDialog::keyInfo( const Kpgp::Key *key ) const
00504 {
00505   QString status, remark;
00506   if( key->revoked() ) {
00507     status = i18n("Revoked");
00508   }
00509   else if( key->expired() ) {
00510     status = i18n("Expired");
00511   }
00512   else if( key->disabled() ) {
00513     status = i18n("Disabled");
00514   }
00515   else if( key->invalid() ) {
00516     status = i18n("Invalid");
00517   }
00518   else {
00519     Validity keyTrust = key->keyTrust();
00520     switch( keyTrust ) {
00521     case KPGP_VALIDITY_UNDEFINED:
00522       status = i18n("Undefined trust");
00523       break;
00524     case KPGP_VALIDITY_NEVER:
00525       status = i18n("Untrusted");
00526       break;
00527     case KPGP_VALIDITY_MARGINAL:
00528       status = i18n("Marginally trusted");
00529       break;
00530     case KPGP_VALIDITY_FULL:
00531       status = i18n("Fully trusted");
00532       break;
00533     case KPGP_VALIDITY_ULTIMATE:
00534       status = i18n("Ultimately trusted");
00535       break;
00536     case KPGP_VALIDITY_UNKNOWN:
00537     default:
00538       status = i18n("Unknown");
00539     }
00540     if( key->secret() ) {
00541       remark = i18n("Secret key available");
00542     }
00543     else if( !key->canEncrypt() ) {
00544       remark = i18n("Sign only key");
00545     }
00546     else if( !key->canSign() ) {
00547       remark = i18n("Encryption only key");
00548     }
00549   }
00550 
00551   QDateTime dt;
00552   dt.setTime_t( key->creationDate() );
00553   if( remark.isEmpty() ) {
00554     return ' ' + i18nc("creation date and status of an OpenPGP key",
00555                       "Creation date: %1, Status: %2",
00556                        KGlobal::locale()->formatDate( dt.date(), KLocale::ShortDate ) ,
00557                        status );
00558   }
00559   else {
00560     return ' ' + i18nc("creation date, status and remark of an OpenPGP key",
00561                       "Creation date: %1, Status: %2 (%3)",
00562                        KGlobal::locale()->formatDate( dt.date(), KLocale::ShortDate ) ,
00563                        status ,
00564                        remark );
00565   }
00566 }
00567 
00568 QString KeySelectionDialog::beautifyFingerprint( const QByteArray& fpr ) const
00569 {
00570   QByteArray result;
00571 
00572   if( 40 == fpr.length() ) {
00573     // convert to this format:
00574     // 0000 1111 2222 3333 4444  5555 6666 7777 8888 9999
00575     result.fill( ' ', 50 );
00576     memcpy( result.data()     , fpr.data()     , 4 );
00577     memcpy( result.data() +  5, fpr.data() +  4, 4 );
00578     memcpy( result.data() + 10, fpr.data() +  8, 4 );
00579     memcpy( result.data() + 15, fpr.data() + 12, 4 );
00580     memcpy( result.data() + 20, fpr.data() + 16, 4 );
00581     memcpy( result.data() + 26, fpr.data() + 20, 4 );
00582     memcpy( result.data() + 31, fpr.data() + 24, 4 );
00583     memcpy( result.data() + 36, fpr.data() + 28, 4 );
00584     memcpy( result.data() + 41, fpr.data() + 32, 4 );
00585     memcpy( result.data() + 46, fpr.data() + 36, 4 );
00586   }
00587   else if( 32 == fpr.length() ) {
00588     // convert to this format:
00589     // 00 11 22 33 44 55 66 77  88 99 AA BB CC DD EE FF
00590     result.fill( ' ', 48 );
00591     memcpy( result.data()     , fpr.data()     , 2 );
00592     memcpy( result.data() +  3, fpr.data() +  2, 2 );
00593     memcpy( result.data() +  6, fpr.data() +  4, 2 );
00594     memcpy( result.data() +  9, fpr.data() +  6, 2 );
00595     memcpy( result.data() + 12, fpr.data() +  8, 2 );
00596     memcpy( result.data() + 15, fpr.data() + 10, 2 );
00597     memcpy( result.data() + 18, fpr.data() + 12, 2 );
00598     memcpy( result.data() + 21, fpr.data() + 14, 2 );
00599     memcpy( result.data() + 25, fpr.data() + 16, 2 );
00600     memcpy( result.data() + 28, fpr.data() + 18, 2 );
00601     memcpy( result.data() + 31, fpr.data() + 20, 2 );
00602     memcpy( result.data() + 34, fpr.data() + 22, 2 );
00603     memcpy( result.data() + 37, fpr.data() + 24, 2 );
00604     memcpy( result.data() + 40, fpr.data() + 26, 2 );
00605     memcpy( result.data() + 43, fpr.data() + 28, 2 );
00606     memcpy( result.data() + 46, fpr.data() + 30, 2 );
00607   }
00608   else { // unknown length of fingerprint
00609     result = fpr;
00610   }
00611 
00612   return result;
00613 }
00614 
00615 int KeySelectionDialog::keyValidity( const Kpgp::Key *key ) const
00616 {
00617   if( 0 == key ) {
00618     return -1;
00619   }
00620 
00621   if( ( mAllowedKeys & EncrSignKeys ) == EncryptionKeys ) {
00622     // only encryption keys are allowed
00623     if( ( mAllowedKeys & ValidKeys ) && !key->isValidEncryptionKey() ) {
00624       // only valid encryption keys are allowed
00625       return -1;
00626     }
00627     else if( !key->canEncrypt() ) {
00628       return -1;
00629     }
00630   }
00631   else if( ( mAllowedKeys & EncrSignKeys ) == SigningKeys ) {
00632     // only signing keys are allowed
00633     if( ( mAllowedKeys & ValidKeys ) && !key->isValidSigningKey() ) {
00634       // only valid signing keys are allowed
00635       return -1;
00636     }
00637     else if( !key->canSign() ) {
00638       return -1;
00639     }
00640   }
00641   else if( ( mAllowedKeys & ValidKeys ) && !key->isValid() ) {
00642     // only valid keys are allowed
00643     return -1;
00644   }
00645 
00646   // check the key's trust
00647   int val = 0;
00648   Validity keyTrust = key->keyTrust();
00649   switch( keyTrust ) {
00650   case KPGP_VALIDITY_NEVER:
00651     val = -1;
00652     break;
00653   case KPGP_VALIDITY_MARGINAL:
00654   case KPGP_VALIDITY_FULL:
00655   case KPGP_VALIDITY_ULTIMATE:
00656     val = 2;
00657     break;
00658   case KPGP_VALIDITY_UNDEFINED:
00659     if( mAllowedKeys & TrustedKeys ) {
00660       // only trusted keys are allowed
00661       val = -1;
00662     }
00663     else {
00664       val = 1;
00665     }
00666     break;
00667   case KPGP_VALIDITY_UNKNOWN:
00668   default:
00669     val = 0;
00670   }
00671 
00672   return val;
00673 }
00674 
00675 
00676 void KeySelectionDialog::updateKeyInfo( const Kpgp::Key* key,
00677                                         Q3ListViewItem* lvi ) const
00678 {
00679   if( 0 == lvi ) {
00680     return;
00681   }
00682 
00683   if( lvi->parent() != 0 ) {
00684     lvi = lvi->parent();
00685   }
00686 
00687   if( 0 == key ) {
00688     // the key doesn't exist anymore -> delete it from the list view
00689     while( lvi->firstChild() ) {
00690       kDebug( 5326 ) <<"Deleting '" << lvi->firstChild()->text( 1 ) <<"'";
00691       delete lvi->firstChild();
00692     }
00693     kDebug( 5326 ) <<"Deleting key 0x" << lvi->text( 0 ) <<" ("
00694                   << lvi->text( 1 ) << ")\n";
00695     delete lvi;
00696     lvi = 0;
00697     return;
00698   }
00699 
00700   // update the icon for this key
00701   switch( keyValidity( key ) ) {
00702   case 0: // the key's validity can't be determined
00703     lvi->setPixmap( 0, *mKeyUnknownPix );
00704     break;
00705   case 1: // key is valid but not trusted
00706     lvi->setPixmap( 0, *mKeyValidPix );
00707     break;
00708   case 2: // key is valid and trusted
00709     lvi->setPixmap( 0, *mKeyGoodPix );
00710     break;
00711   case -1: // key is invalid
00712     lvi->setPixmap( 0, *mKeyBadPix );
00713     break;
00714   }
00715 
00716   // update the key info for this key
00717   // the key info is identified by a leading space; this shouldn't be
00718   // a problem because User Ids shouldn't start with a space
00719   for( lvi = lvi->firstChild(); lvi; lvi = lvi->nextSibling() ) {
00720     if( lvi->text( 1 ).at(0) == ' ' ) {
00721       lvi->setText( 1, keyInfo( key ) );
00722       break;
00723     }
00724   }
00725 }
00726 
00727 
00728 int
00729 KeySelectionDialog::keyAdmissibility( Q3ListViewItem* lvi,
00730                                       TrustCheckMode trustCheckMode ) const
00731 {
00732   // Return:
00733   //  -1 = key must not be chosen,
00734   //   0 = not enough information to decide whether the give key is allowed
00735   //       or not,
00736   //   1 = key can be chosen
00737 
00738   if( mAllowedKeys == AllKeys ) {
00739     return 1;
00740   }
00741 
00742   Kpgp::Module *pgp = Kpgp::Module::getKpgp();
00743 
00744   if( 0 == pgp ) {
00745     return 0;
00746   }
00747 
00748   KeyID keyId = getKeyId( lvi );
00749   Kpgp::Key* key = pgp->publicKey( keyId );
00750 
00751   if( 0 == key ) {
00752     return 0;
00753   }
00754 
00755   int val = 0;
00756   if( trustCheckMode == ForceTrustCheck ) {
00757     key = pgp->rereadKey( keyId, true );
00758     updateKeyInfo( key, lvi );
00759     val = keyValidity( key );
00760   }
00761   else {
00762     val = keyValidity( key );
00763     if( ( trustCheckMode == AllowExpensiveTrustCheck ) && ( 0 == val ) ) {
00764       key = pgp->rereadKey( keyId, true );
00765       updateKeyInfo( key, lvi );
00766       val = keyValidity( key );
00767     }
00768   }
00769 
00770   switch( val ) {
00771   case -1: // key is not usable
00772     return -1;
00773     break;
00774   case 0: // key status unknown
00775     return 0;
00776     break;
00777   case 1: // key is valid, but untrusted
00778     if( mAllowedKeys & TrustedKeys ) {
00779       // only trusted keys are allowed
00780       return -1;
00781     }
00782     return 1;
00783     break;
00784   case 2: // key is trusted
00785     return 1;
00786     break;
00787   default:
00788     kDebug( 5326 ) <<"Error: Invalid key status value.";
00789   }
00790 
00791   return 0;
00792 }
00793 
00794 
00795 KeyID
00796 KeySelectionDialog::getKeyId( const Q3ListViewItem* lvi ) const
00797 {
00798   KeyID keyId;
00799 
00800   if( 0 != lvi ) {
00801     if( 0 != lvi->parent() ) {
00802       keyId = lvi->parent()->text(0).toLocal8Bit();
00803     }
00804     else {
00805       keyId = lvi->text(0).toLocal8Bit();
00806     }
00807   }
00808 
00809   return keyId;
00810 }
00811 
00812 
00813 void KeySelectionDialog::slotRereadKeys()
00814 {
00815   Kpgp::Module *pgp = Kpgp::Module::getKpgp();
00816 
00817   if( 0 == pgp ) {
00818     return;
00819   }
00820 
00821   KeyList keys;
00822 
00823   if( PublicKeys & mAllowedKeys ) {
00824     pgp->readPublicKeys( true );
00825     keys = pgp->publicKeys();
00826   }
00827   else {
00828     pgp->readSecretKeys( true );
00829     keys = pgp->secretKeys();
00830   }
00831 
00832   // save the current position of the contents
00833   int offsetY = mListView->contentsY();
00834 
00835   if( mListView->isMultiSelection() ) {
00836     disconnect( mListView, SIGNAL( selectionChanged() ),
00837                 this,      SLOT( slotSelectionChanged() ) );
00838   }
00839   else {
00840     disconnect( mListView, SIGNAL( selectionChanged( Q3ListViewItem * ) ),
00841                 this,      SLOT( slotSelectionChanged( Q3ListViewItem * ) ) );
00842   }
00843 
00844   initKeylist( keys, KeyIDList( mKeyIds ) );
00845   slotFilter();
00846 
00847   if( mListView->isMultiSelection() ) {
00848     connect( mListView, SIGNAL( selectionChanged() ),
00849              this,      SLOT( slotSelectionChanged() ) );
00850     slotSelectionChanged();
00851   }
00852   else {
00853     connect( mListView, SIGNAL( selectionChanged( Q3ListViewItem * ) ),
00854              this,      SLOT( slotSelectionChanged( Q3ListViewItem * ) ) );
00855   }
00856 
00857   // restore the saved position of the contents
00858   mListView->setContentsPos( 0, offsetY );
00859 }
00860 
00861 
00862 void KeySelectionDialog::slotSelectionChanged( Q3ListViewItem * lvi )
00863 {
00864   slotCheckSelection( lvi );
00865 }
00866 
00867 
00868 void KeySelectionDialog::slotSelectionChanged()
00869 {
00870   kDebug( 5326 ) <<"KeySelectionDialog::slotSelectionChanged()";
00871 
00872   // (re)start the check selection timer. Checking the selection is delayed
00873   // because else drag-selection doesn't work very good (checking key trust
00874   // is slow).
00875   mCheckSelectionTimer->start( sCheckSelectionDelay );
00876 }
00877 
00878 
00879 void KeySelectionDialog::slotCheckSelection( Q3ListViewItem* plvi /* = 0 */ )
00880 {
00881   kDebug( 5326 ) <<"KeySelectionDialog::slotCheckSelection()";
00882 
00883   if( !mListView->isMultiSelection() ) {
00884     mKeyIds.clear();
00885     KeyID keyId = getKeyId( plvi );
00886     if( !keyId.isEmpty() ) {
00887       mKeyIds.append( keyId );
00888       enableButton( Ok, 1 == keyAdmissibility( plvi, AllowExpensiveTrustCheck ) );
00889     }
00890     else {
00891       enableButton( Ok, false );
00892     }
00893   }
00894   else {
00895     mCheckSelectionTimer->stop();
00896 
00897     // As we might change the selection, we have to disconnect the slot
00898     // to prevent recursion
00899     disconnect( mListView, SIGNAL( selectionChanged() ),
00900                 this,      SLOT( slotSelectionChanged() ) );
00901 
00902     KeyIDList newKeyIdList;
00903     QList<Q3ListViewItem*> keysToBeChecked;
00904 
00905     bool keysAllowed = true;
00906     enum { UNKNOWN, SELECTED, DESELECTED } userAction = UNKNOWN;
00907     // Iterate over the tree to find selected keys.
00908     for( Q3ListViewItem *lvi = mListView->firstChild();
00909          0 != lvi;
00910          lvi = lvi->nextSibling() ) {
00911       // We make sure that either all items belonging to a key are selected
00912       // or unselected. As it's possible to select/deselect multiple keys at
00913       // once in extended selection mode we have to figure out whether the user
00914       // selected or deselected keys.
00915 
00916       // First count the selected items of this key
00917       int itemCount = 1 + lvi->childCount();
00918       int selectedCount = lvi->isSelected() ? 1 : 0;
00919       for( Q3ListViewItem *clvi = lvi->firstChild();
00920            0 != clvi;
00921            clvi = clvi->nextSibling() ) {
00922         if( clvi->isSelected() ) {
00923           ++selectedCount;
00924         }
00925       }
00926 
00927       if( userAction == UNKNOWN ) {
00928         // Figure out whether the user selected or deselected this key
00929         // Remark: A selected count of 0 doesn't mean anything since in
00930         //         extended selection mode a normal left click deselects
00931         //         the not clicked items.
00932         if( 0 < selectedCount ) {
00933           if( -1 == mKeyIds.indexOf( lvi->text(0).toLocal8Bit() ) ) {
00934             // some items of this key are selected and the key wasn't selected
00935             // before => the user selected something
00936             kDebug( 5326 ) <<"selectedCount:"<<selectedCount<<"/"<<itemCount
00937                           <<"--- User selected key"<<lvi->text(0);
00938             userAction = SELECTED;
00939           }
00940           else if( ( itemCount > selectedCount ) &&
00941                    ( -1 != mKeyIds.indexOf( lvi->text(0).toLocal8Bit() ) ) ) {
00942             // some items of this key are unselected and the key was selected
00943             // before => the user deselected something
00944             kDebug( 5326 ) <<"selectedCount:"<<selectedCount<<"/"<<itemCount
00945                           <<"--- User deselected key"<<lvi->text(0);
00946             userAction = DESELECTED;
00947           }
00948         }
00949       }
00950       if( itemCount == selectedCount ) {
00951         // add key to the list of selected keys
00952         KeyID keyId = lvi->text(0).toLocal8Bit();
00953         newKeyIdList.append( keyId );
00954         int admissibility = keyAdmissibility( lvi, NoExpensiveTrustCheck );
00955         if( -1 == admissibility ) {
00956           keysAllowed = false;
00957         }
00958         else if ( 0 == admissibility ) {
00959           keysToBeChecked.append( lvi );
00960         }
00961       }
00962       else if( 0 < selectedCount ) {
00963         // not all items of this key are selected or unselected. change this
00964         // according to the user's action
00965         if( userAction == SELECTED ) {
00966           // select all items of this key
00967           mListView->setSelected( lvi, true );
00968           for( Q3ListViewItem *clvi = lvi->firstChild();
00969                0 != clvi;
00970                clvi = clvi->nextSibling() ) {
00971             mListView->setSelected( clvi, true );
00972           }
00973           // add key to the list of selected keys
00974           KeyID keyId = lvi->text(0).toLocal8Bit();
00975           newKeyIdList.append( keyId );
00976           int admissibility = keyAdmissibility( lvi, NoExpensiveTrustCheck );
00977           if( -1 == admissibility ) {
00978             keysAllowed = false;
00979           }
00980           else if ( 0 == admissibility ) {
00981             keysToBeChecked.append( lvi );
00982           }
00983         }
00984         else { // userAction == DESELECTED
00985           // deselect all items of this key
00986           mListView->setSelected( lvi, false );
00987           for( Q3ListViewItem *clvi = lvi->firstChild();
00988                0 != clvi;
00989                clvi = clvi->nextSibling() ) {
00990             mListView->setSelected( clvi, false );
00991           }