libkpgp

kpgpui.cpp

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 <stdio.h>
00020 
00021 #include <qvgroupbox.h>
00022 #include <qvbox.h>
00023 #include <qlabel.h>
00024 #include <qwhatsthis.h>
00025 #include <qtooltip.h>
00026 #include <qapplication.h>
00027 #include <qtextcodec.h>
00028 #include <qdatetime.h>
00029 #include <qpixmap.h>
00030 #include <qlayout.h>
00031 #include <qtimer.h>
00032 #include <qpopupmenu.h>
00033 #include <qregexp.h>
00034 
00035 #include <klocale.h>
00036 #include <kpassdlg.h>
00037 #include <kcharsets.h>
00038 #include <kseparator.h>
00039 #include <kiconloader.h>
00040 #include <klistview.h>
00041 #include <kconfigbase.h>
00042 #include <kconfig.h>
00043 #include <kprogress.h>
00044 #include <kapplication.h>
00045 #include <kwin.h>
00046 #if KDE_IS_VERSION( 3, 1, 90 )
00047 #include <kglobalsettings.h>
00048 #endif
00049 
00050 #include "kpgp.h"
00051 #include "kpgpui.h"
00052 #include "kpgpkey.h"
00053 
00054 #include <assert.h>
00055 #include <string.h> // for memcpy(3)
00056 
00057 const int Kpgp::KeySelectionDialog::sCheckSelectionDelay = 250;
00058 
00059 namespace Kpgp {
00060 
00061 PassphraseDialog::PassphraseDialog( QWidget *parent,
00062                                     const QString &caption, bool modal,
00063                                     const QString &keyID )
00064   :KDialogBase( parent, 0, modal, caption, Ok|Cancel )
00065 {
00066   QHBox *hbox = makeHBoxMainWidget();
00067   hbox->setSpacing( spacingHint() );
00068   hbox->setMargin( marginHint() );
00069 
00070   QLabel *label = new QLabel(hbox);
00071   label->setPixmap( BarIcon("pgp-keys") );
00072 
00073   QWidget *rightArea = new QWidget( hbox );
00074   QVBoxLayout *vlay = new QVBoxLayout( rightArea, 0, spacingHint() );
00075 
00076   if (keyID.isNull())
00077     label = new QLabel(i18n("Please enter your OpenPGP passphrase:"),rightArea);
00078   else
00079     label = new QLabel(i18n("Please enter the OpenPGP passphrase for\n\"%1\":").arg(keyID),
00080                        rightArea);
00081   lineedit = new KPasswordEdit( rightArea );
00082   lineedit->setEchoMode(QLineEdit::Password);
00083   lineedit->setMinimumWidth( fontMetrics().maxWidth()*20 );
00084   lineedit->setFocus();
00085   connect( lineedit, SIGNAL(returnPressed()), this, SLOT(slotOk()) );
00086 
00087   vlay->addWidget( label );
00088   vlay->addWidget( lineedit );
00089 
00090   disableResize();
00091 }
00092 
00093 
00094 PassphraseDialog::~PassphraseDialog()
00095 {
00096 }
00097 
00098 const char * PassphraseDialog::passphrase()
00099 {
00100   return lineedit->password();
00101 }
00102 
00103 
00104 // ------------------------------------------------------------------------
00105 // Forbidden accels for KMail: AC GH OP
00106 //                  for KNode: ACE H O
00107 Config::Config( QWidget *parent, const char *name, bool encrypt )
00108   : QWidget( parent, name ), pgp( Module::getKpgp() )
00109 {
00110   QGroupBox * group;
00111   QLabel    * label;
00112   QString     msg;
00113 
00114 
00115   QVBoxLayout *topLayout = new QVBoxLayout( this, 0, KDialog::spacingHint() );
00116 
00117   group = new QVGroupBox( i18n("Warning"), this );
00118   group->layout()->setSpacing( KDialog::spacingHint() );
00119   // (mmutz) work around Qt label bug in 3.0.0 (and possibly later):
00120   // 1. Don't use rich text: No <qt><b>...</b></qt>
00121   label = new QLabel( i18n("Please check if encryption really "
00122     "works before you start using it seriously. Also note that attachments "
00123     "are not encrypted by the PGP/GPG module."), group );
00124   // 2. instead, set the font to bold:
00125   QFont labelFont = label->font();
00126   labelFont.setBold( true );
00127   label->setFont( labelFont );
00128   // 3. and activate wordwarp:
00129   label->setAlignment( AlignLeft|WordBreak );
00130   // end; to remove the workaround, add <qt><b>..</b></qt> around the
00131   // text and remove lines QFont... -> label->setAlignment(...).
00132   topLayout->addWidget( group );
00133 
00134   group = new QVGroupBox( i18n("Encryption Tool"), this );
00135   group->layout()->setSpacing( KDialog::spacingHint() );
00136 
00137   QHBox * hbox = new QHBox( group );
00138   label = new QLabel( i18n("Select encryption tool to &use:"), hbox );
00139   toolCombo = new QComboBox( false, hbox );
00140   toolCombo->insertStringList( QStringList()
00141                    << i18n("Autodetect")
00142                    << i18n("GnuPG - Gnu Privacy Guard")
00143                    << i18n("PGP Version 2.x")
00144                    << i18n("PGP Version 5.x")
00145                    << i18n("PGP Version 6.x")
00146                    << i18n("Do not use any encryption tool") );
00147   label->setBuddy( toolCombo );
00148   hbox->setStretchFactor( toolCombo, 1 );
00149   connect( toolCombo, SIGNAL( activated( int ) ),
00150            this, SIGNAL( changed( void ) ) );
00151   // This is the place to add a KURLRequester to be used for asking
00152   // the user for the path to the executable...
00153   topLayout->addWidget( group );
00154 
00155   mpOptionsGroupBox = new QVGroupBox( i18n("Options"), this );
00156   mpOptionsGroupBox->layout()->setSpacing( KDialog::spacingHint() );
00157   storePass = new QCheckBox( i18n("&Keep passphrase in memory"),
00158                              mpOptionsGroupBox );
00159   connect( storePass, SIGNAL( toggled( bool ) ),
00160            this, SIGNAL( changed( void ) ) );
00161   msg = i18n( "<qt><p>When this option is enabled, the passphrase of your "
00162           "private key will be remembered by the application as long "
00163           "as the application is running. Thus you will only have to "
00164           "enter the passphrase once.</p><p>Be aware that this could be a "
00165           "security risk. If you leave your computer, others "
00166           "can use it to send signed messages and/or read your encrypted "
00167           "messages. If a core dump occurs, the contents of your RAM will "
00168           "be saved onto disk, including your passphrase.</p>"
00169           "<p>Note that when using KMail, this setting only applies "
00170           "if you are not using gpg-agent. It is also ignored "
00171           "if you are using crypto plugins.</p></qt>" );
00172   QWhatsThis::add( storePass, msg );
00173   if( encrypt ) {
00174     encToSelf = new QCheckBox( i18n("Always encr&ypt to self"),
00175                                mpOptionsGroupBox );
00176    connect( encToSelf, SIGNAL( toggled( bool ) ),
00177            this, SIGNAL( changed( void ) ) );
00178 
00179     msg = i18n( "<qt><p>When this option is enabled, the message/file "
00180         "will not only be encrypted with the receiver's public key, "
00181         "but also with your key. This will enable you to decrypt the "
00182         "message/file at a later time. This is generally a good idea."
00183         "</p></qt>" );
00184     QWhatsThis::add( encToSelf, msg );
00185   }
00186   else
00187     encToSelf = 0;
00188   showCipherText = new QCheckBox( i18n("&Show signed/encrypted text after "
00189                                        "composing"),
00190                                   mpOptionsGroupBox );
00191   connect( showCipherText, SIGNAL( toggled( bool ) ),
00192            this, SIGNAL( changed( void ) ) );
00193 
00194   msg = i18n( "<qt><p>When this option is enabled, the signed/encrypted text "
00195           "will be shown in a separate window, enabling you to know how "
00196           "it will look before it is sent. This is a good idea when "
00197           "you are verifying that your encryption system works.</p></qt>" );
00198   QWhatsThis::add( showCipherText, msg );
00199   if( encrypt ) {
00200     showKeyApprovalDlg = new QCheckBox( i18n("Always show the encryption "
00201                                              "keys &for approval"),
00202                                         mpOptionsGroupBox );
00203     connect( showKeyApprovalDlg, SIGNAL( toggled( bool ) ),
00204            this, SIGNAL( changed( void ) ) );
00205     msg = i18n( "<qt><p>When this option is enabled, the application will "
00206         "always show you a list of public keys from which you can "
00207         "choose the one it will use for encryption. If it is off, "
00208         "the application will only show the dialog if it cannot find "
00209         "the right key or if there are several which could be used. "
00210         "</p></qt>" );
00211     QWhatsThis::add( showKeyApprovalDlg, msg );
00212 }
00213   else
00214     showKeyApprovalDlg = 0;
00215 
00216   topLayout->addWidget( mpOptionsGroupBox );
00217 
00218   topLayout->addStretch(1);
00219 
00220   setValues();  // is this needed by KNode, b/c for KMail, it's not.
00221 }
00222 
00223 
00224 Config::~Config()
00225 {
00226 }
00227 
00228 void
00229 Config::setValues()
00230 {
00231   // set default values
00232   storePass->setChecked( pgp->storePassPhrase() );
00233   if( 0 != encToSelf )
00234     encToSelf->setChecked( pgp->encryptToSelf() );
00235   showCipherText->setChecked( pgp->showCipherText() );
00236   if( 0 != showKeyApprovalDlg )
00237     showKeyApprovalDlg->setChecked( pgp->showKeyApprovalDlg() );
00238 
00239   int type = 0;
00240   switch (pgp->pgpType) {
00241     // translate Kpgp::Module enum to combobox' entries:
00242   default:
00243   case Module::tAuto: type = 0; break;
00244   case Module::tGPG:  type = 1; break;
00245   case Module::tPGP2: type = 2; break;
00246   case Module::tPGP5: type = 3; break;
00247   case Module::tPGP6: type = 4; break;
00248   case Module::tOff:  type = 5; break;
00249   }
00250   toolCombo->setCurrentItem( type );
00251 }
00252 
00253 void
00254 Config::applySettings()
00255 {
00256   pgp->setStorePassPhrase(storePass->isChecked());
00257   if( 0 != encToSelf )
00258     pgp->setEncryptToSelf(encToSelf->isChecked());
00259   pgp->setShowCipherText(showCipherText->isChecked());
00260   if( 0 != showKeyApprovalDlg )
00261     pgp->setShowKeyApprovalDlg( showKeyApprovalDlg->isChecked() );
00262 
00263   Module::PGPType type;
00264   switch ( toolCombo->currentItem() ) {
00265     // convert combobox entry indices to Kpgp::Module constants:
00266   default:
00267   case 0: type = Module::tAuto; break;
00268   case 1: type = Module::tGPG;  break;
00269   case 2: type = Module::tPGP2; break;
00270   case 3: type = Module::tPGP5; break;
00271   case 4: type = Module::tPGP6; break;
00272   case 5: type = Module::tOff;  break;
00273   }
00274   pgp->pgpType = type;
00275 
00276   pgp->writeConfig(true);
00277 }
00278 
00279 
00280 
00281 // ------------------------------------------------------------------------
00282 KeySelectionDialog::KeySelectionDialog( const KeyList& keyList,
00283                                         const QString& title,
00284                                         const QString& text,
00285                                         const KeyIDList& keyIds,
00286                                         const bool rememberChoice,
00287                                         const unsigned int allowedKeys,
00288                                         const bool extendedSelection,
00289                                         QWidget *parent, const char *name,
00290                                         bool modal )
00291   : KDialogBase( parent, name, modal, title, Default|Ok|Cancel, Ok ),
00292     mRememberCB( 0 ),
00293     mAllowedKeys( allowedKeys ),
00294     mCurrentContextMenuItem( 0 )
00295 {
00296   if ( kapp )
00297     KWin::setIcons( winId(), kapp->icon(), kapp->miniIcon() );
00298   Kpgp::Module *pgp = Kpgp::Module::getKpgp();
00299   KConfig *config = pgp->getConfig();
00300   KConfigGroup dialogConfig( config, "Key Selection Dialog" );
00301 
00302   QSize defaultSize( 580, 400 );
00303   QSize dialogSize = dialogConfig.readSizeEntry( "Dialog size", &defaultSize );
00304 
00305   resize( dialogSize );
00306 
00307   mCheckSelectionTimer = new QTimer( this );
00308   mStartSearchTimer = new QTimer( this );
00309 
00310   // load the key status icons
00311   mKeyGoodPix    = new QPixmap( UserIcon("key_ok") );
00312   mKeyBadPix     = new QPixmap( UserIcon("key_bad") );
00313   mKeyUnknownPix = new QPixmap( UserIcon("key_unknown") );
00314   mKeyValidPix   = new QPixmap( UserIcon("key") );
00315 
00316   QFrame *page = makeMainWidget();
00317   QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() );
00318 
00319   if( !text.isEmpty() ) {
00320     QLabel *label = new QLabel( page );
00321     label->setText( text );
00322     topLayout->addWidget( label );
00323   }
00324 
00325   QHBoxLayout * hlay = new QHBoxLayout( topLayout ); // inherits spacing
00326   QLineEdit * le = new QLineEdit( page );
00327   hlay->addWidget( new QLabel( le, i18n("&Search for:"), page ) );
00328   hlay->addWidget( le, 1 );
00329   le->setFocus();
00330 
00331   connect( le, SIGNAL(textChanged(const QString&)),
00332        this, SLOT(slotSearch(const QString&)) );
00333   connect( mStartSearchTimer, SIGNAL(timeout()), SLOT(slotFilter()) );
00334 
00335   mListView = new KListView( page );
00336   mListView->addColumn( i18n("Key ID") );
00337   mListView->addColumn( i18n("User ID") );
00338   mListView->setAllColumnsShowFocus( true );
00339   mListView->setResizeMode( QListView::LastColumn );
00340   mListView->setRootIsDecorated( true );
00341   mListView->setShowSortIndicator( true );
00342   mListView->setSorting( 1, true ); // sort by User ID
00343   mListView->setShowToolTips( true );
00344   if( extendedSelection ) {
00345     mListView->setSelectionMode( QListView::Extended );
00346     //mListView->setSelectionMode( QListView::Multi );
00347   }
00348   topLayout->addWidget( mListView, 10 );
00349 
00350   if (rememberChoice) {
00351     mRememberCB = new QCheckBox( i18n("Remember choice"), page );
00352     topLayout->addWidget( mRememberCB );
00353     QWhatsThis::add(mRememberCB,
00354                     i18n("<qt><p>If you check this box your choice will "
00355                          "be stored and you will not be asked again."
00356                          "</p></qt>"));
00357   }
00358 
00359   initKeylist( keyList, keyIds );
00360 
00361   QListViewItem *lvi;
00362   if( extendedSelection ) {
00363     lvi = mListView->currentItem();
00364     slotCheckSelection();
00365   }
00366   else {
00367     lvi = mListView->selectedItem();
00368     slotCheckSelection( lvi );
00369   }
00370   // make sure that the selected item is visible
00371   // (ensureItemVisible(...) doesn't work correctly in Qt 3.0.0)
00372   if( lvi != 0 )
00373     mListView->center( mListView->contentsX(), mListView->itemPos( lvi ) );
00374 
00375   if( extendedSelection ) {
00376     connect( mCheckSelectionTimer, SIGNAL( timeout() ),
00377              this,                 SLOT( slotCheckSelection() ) );
00378     connect( mListView, SIGNAL( selectionChanged() ),
00379              this,      SLOT( slotSelectionChanged() ) );
00380   }
00381   else {
00382     connect( mListView, SIGNAL( selectionChanged( QListViewItem* ) ),
00383              this,      SLOT( slotSelectionChanged( QListViewItem* ) ) );
00384   }
00385   connect( mListView, SIGNAL( doubleClicked ( QListViewItem *, const QPoint &, int ) ), this, SLOT( accept() ) );
00386 
00387   connect( mListView, SIGNAL( contextMenuRequested( QListViewItem*,
00388                                                     const QPoint&, int ) ),
00389            this,      SLOT( slotRMB( QListViewItem*, const QPoint&, int ) ) );
00390 
00391   setButtonText( KDialogBase::Default, i18n("&Reread Keys") );
00392   connect( this, SIGNAL( defaultClicked() ),
00393            this, SLOT( slotRereadKeys() ) );
00394 }
00395 
00396 
00397 KeySelectionDialog::~KeySelectionDialog()
00398 {
00399   Kpgp::Module *pgp = Kpgp::Module::getKpgp();
00400   KConfig *config = pgp->getConfig();
00401   KConfigGroup dialogConfig( config, "Key Selection Dialog" );
00402   dialogConfig.writeEntry( "Dialog size", size() );
00403   config->sync();
00404   delete mKeyGoodPix;
00405   delete mKeyBadPix;
00406   delete mKeyUnknownPix;
00407   delete mKeyValidPix;
00408 }
00409 
00410 
00411 KeyID KeySelectionDialog::key() const
00412 {
00413   if( mListView->isMultiSelection() || mKeyIds.isEmpty() )
00414     return KeyID();
00415   else
00416     return mKeyIds.first();
00417 }
00418 
00419 
00420 void KeySelectionDialog::initKeylist( const KeyList& keyList,
00421                                       const KeyIDList& keyIds )
00422 {
00423   QListViewItem* firstSelectedItem = 0;
00424   mKeyIds.clear();
00425   mListView->clear();
00426 
00427   // build a list of all public keys
00428   for( KeyListIterator it( keyList ); it.current(); ++it ) {
00429     KeyID curKeyId = (*it)->primaryKeyID();
00430 
00431     QListViewItem* primaryUserID = new QListViewItem( mListView, curKeyId,
00432                                                       (*it)->primaryUserID() );
00433 
00434     // select and open the given key
00435     if( keyIds.findIndex( curKeyId ) != -1 ) {
00436       if( 0 == firstSelectedItem ) {
00437         firstSelectedItem = primaryUserID;
00438       }
00439       mListView->setSelected( primaryUserID, true );
00440       mKeyIds.append( curKeyId );
00441     }
00442     primaryUserID->setOpen( false );
00443 
00444     // set icon for this key
00445     switch( keyValidity( *it ) ) {
00446       case 0: // the key's validity can't be determined
00447         primaryUserID->setPixmap( 0, *mKeyUnknownPix );
00448         break;
00449       case 1: // key is valid but not trusted
00450         primaryUserID->setPixmap( 0, *mKeyValidPix );
00451         break;
00452       case 2: // key is valid and trusted
00453         primaryUserID->setPixmap( 0, *mKeyGoodPix );
00454         break;
00455       case -1: // key is invalid
00456         primaryUserID->setPixmap( 0, *mKeyBadPix );
00457         break;
00458     }
00459 
00460     QListViewItem* childItem;
00461 
00462     childItem = new QListViewItem( primaryUserID, "",
00463                                    i18n( "Fingerprint: %1" )
00464                                    .arg( beautifyFingerprint( (*it)->primaryFingerprint() ) ) );
00465     if( primaryUserID->isSelected() && mListView->isMultiSelection() ) {
00466       mListView->setSelected( childItem, true );
00467     }
00468 
00469     childItem = new QListViewItem( primaryUserID, "", keyInfo( *it ) );
00470     if( primaryUserID->isSelected() && mListView->isMultiSelection() ) {
00471       mListView->setSelected( childItem, true );
00472     }
00473 
00474     UserIDList userIDs = (*it)->userIDs();
00475     UserIDListIterator uidit( userIDs );
00476     if( *uidit ) {
00477       ++uidit; // skip the primary user ID
00478       for( ; *uidit; ++uidit ) {
00479         childItem = new QListViewItem( primaryUserID, "", (*uidit)->text() );
00480         if( primaryUserID->isSelected() && mListView->isMultiSelection() ) {
00481           mListView->setSelected( childItem, true );
00482         }
00483       }
00484     }
00485   }
00486 
00487   if( 0 != firstSelectedItem ) {
00488     mListView->setCurrentItem( firstSelectedItem );
00489   }
00490 }
00491 
00492 
00493 QString KeySelectionDialog::keyInfo( const Kpgp::Key *key ) const
00494 {
00495   QString status, remark;
00496   if( key->revoked() ) {
00497     status = i18n("Revoked");
00498   }
00499   else if( key->expired() ) {
00500     status = i18n("Expired");
00501   }
00502   else if( key->disabled() ) {
00503     status = i18n("Disabled");
00504   }
00505   else if( key->invalid() ) {
00506     status = i18n("Invalid");
00507   }
00508   else {
00509     Validity keyTrust = key->keyTrust();
00510     switch( keyTrust ) {
00511     case KPGP_VALIDITY_UNDEFINED:
00512       status = i18n("Undefined trust");
00513       break;
00514     case KPGP_VALIDITY_NEVER:
00515       status = i18n("Untrusted");
00516       break;
00517     case KPGP_VALIDITY_MARGINAL:
00518       status = i18n("Marginally trusted");
00519       break;
00520     case KPGP_VALIDITY_FULL:
00521       status = i18n("Fully trusted");
00522       break;
00523     case KPGP_VALIDITY_ULTIMATE:
00524       status = i18n("Ultimately trusted");
00525       break;
00526     case KPGP_VALIDITY_UNKNOWN:
00527     default:
00528       status = i18n("Unknown");
00529     }
00530     if( key->secret() ) {
00531       remark = i18n("Secret key available");
00532     }
00533     else if( !key->canEncrypt() ) {
00534       remark = i18n("Sign only key");
00535     }
00536     else if( !key->canSign() ) {
00537       remark = i18n("Encryption only key");
00538     }
00539   }
00540 
00541   QDateTime dt;
00542   dt.setTime_t( key->creationDate() );
00543   if( remark.isEmpty() ) {
00544     return " " + i18n("creation date and status of an OpenPGP key",
00545                       "Creation date: %1, Status: %2")
00546                      .arg( KGlobal::locale()->formatDate( dt.date(), true ) )
00547                      .arg( status );
00548   }
00549   else {
00550     return " " + i18n("creation date, status and remark of an OpenPGP key",
00551                       "Creation date: %1, Status: %2 (%3)")
00552                      .arg( KGlobal::locale()->formatDate( dt.date(), true ) )
00553                      .arg( status )
00554                      .arg( remark );
00555   }
00556 }
00557 
00558 QString KeySelectionDialog::beautifyFingerprint( const QCString& fpr ) const
00559 {
00560   QCString result;
00561 
00562   if( 40 == fpr.length() ) {
00563     // convert to this format:
00564     // 0000 1111 2222 3333 4444  5555 6666 7777 8888 9999
00565     result.fill( ' ', 50 );
00566     memcpy( result.data()     , fpr.data()     , 4 );
00567     memcpy( result.data() +  5, fpr.data() +  4, 4 );
00568     memcpy( result.data() + 10, fpr.data() +  8, 4 );
00569     memcpy( result.data() + 15, fpr.data() + 12, 4 );
00570     memcpy( result.data() + 20, fpr.data() + 16, 4 );
00571     memcpy( result.data() + 26, fpr.data() + 20, 4 );
00572     memcpy( result.data() + 31, fpr.data() + 24, 4 );
00573     memcpy( result.data() + 36, fpr.data() + 28, 4 );
00574     memcpy( result.data() + 41, fpr.data() + 32, 4 );
00575     memcpy( result.data() + 46, fpr.data() + 36, 4 );
00576   }
00577   else if( 32 == fpr.length() ) {
00578     // convert to this format:
00579     // 00 11 22 33 44 55 66 77  88 99 AA BB CC DD EE FF
00580     result.fill( ' ', 48 );
00581     memcpy( result.data()     , fpr.data()     , 2 );
00582     memcpy( result.data() +  3, fpr.data() +  2, 2 );
00583     memcpy( result.data() +  6, fpr.data() +  4, 2 );
00584     memcpy( result.data() +  9, fpr.data() +  6, 2 );
00585     memcpy( result.data() + 12, fpr.data() +  8, 2 );
00586     memcpy( result.data() + 15, fpr.data() + 10, 2 );
00587     memcpy( result.data() + 18, fpr.data() + 12, 2 );
00588     memcpy( result.data() + 21, fpr.data() + 14, 2 );
00589     memcpy( result.data() + 25, fpr.data() + 16, 2 );
00590     memcpy( result.data() + 28, fpr.data() + 18, 2 );
00591     memcpy( result.data() + 31, fpr.data() + 20, 2 );
00592     memcpy( result.data() + 34, fpr.data() + 22, 2 );
00593     memcpy( result.data() + 37, fpr.data() + 24, 2 );
00594     memcpy( result.data() + 40, fpr.data() + 26, 2 );
00595     memcpy( result.data() + 43, fpr.data() + 28, 2 );
00596     memcpy( result.data() + 46, fpr.data() + 30, 2 );
00597   }
00598   else { // unknown length of fingerprint
00599     result = fpr;
00600   }
00601 
00602   return result;
00603 }
00604 
00605 int KeySelectionDialog::keyValidity( const Kpgp::Key *key ) const
00606 {
00607   if( 0 == key ) {
00608     return -1;
00609   }
00610 
00611   if( ( mAllowedKeys & EncrSignKeys ) == EncryptionKeys ) {
00612     // only encryption keys are allowed
00613     if( ( mAllowedKeys & ValidKeys ) && !key->isValidEncryptionKey() ) {
00614       // only valid encryption keys are allowed
00615       return -1;
00616     }
00617     else if( !key->canEncrypt() ) {
00618       return -1;
00619     }
00620   }
00621   else if( ( mAllowedKeys & EncrSignKeys ) == SigningKeys ) {
00622     // only signing keys are allowed
00623     if( ( mAllowedKeys & ValidKeys ) && !key->isValidSigningKey() ) {
00624       // only valid signing keys are allowed
00625       return -1;
00626     }
00627     else if( !key->canSign() ) {
00628       return -1;
00629     }
00630   }
00631   else if( ( mAllowedKeys & ValidKeys ) && !key->isValid() ) {
00632     // only valid keys are allowed
00633     return -1;
00634   }
00635 
00636   // check the key's trust
00637   int val = 0;
00638   Validity keyTrust = key->keyTrust();
00639   switch( keyTrust ) {
00640   case KPGP_VALIDITY_NEVER:
00641     val = -1;
00642     break;
00643   case KPGP_VALIDITY_MARGINAL:
00644   case KPGP_VALIDITY_FULL:
00645   case KPGP_VALIDITY_ULTIMATE:
00646     val = 2;
00647     break;
00648   case KPGP_VALIDITY_UNDEFINED:
00649     if( mAllowedKeys & TrustedKeys ) {
00650       // only trusted keys are allowed
00651       val = -1;
00652     }
00653     else {
00654       val = 1;
00655     }
00656     break;
00657   case KPGP_VALIDITY_UNKNOWN:
00658   default:
00659     val = 0;
00660   }
00661 
00662   return val;
00663 }
00664 
00665 
00666 void KeySelectionDialog::updateKeyInfo( const Kpgp::Key* key,
00667                                         QListViewItem* lvi ) const
00668 {
00669   if( 0 == lvi ) {
00670     return;
00671   }
00672 
00673   if( lvi->parent() != 0 ) {
00674     lvi = lvi->parent();
00675   }
00676 
00677   if( 0 == key ) {
00678     // the key doesn't exist anymore -> delete it from the list view
00679     while( lvi->firstChild() ) {
00680       kdDebug(5100) << "Deleting '" << lvi->firstChild()->text( 1 ) << "'\n";
00681       delete lvi->firstChild();
00682     }
00683     kdDebug(5100) << "Deleting key 0x" << lvi->text( 0 ) << " ("
00684                   << lvi->text( 1 ) << ")\n";
00685     delete lvi;
00686     lvi = 0;
00687     return;
00688   }
00689 
00690   // update the icon for this key
00691   switch( keyValidity( key ) ) {
00692   case 0: // the key's validity can't be determined
00693     lvi->setPixmap( 0, *mKeyUnknownPix );
00694     break;
00695   case 1: // key is valid but not trusted
00696     lvi->setPixmap( 0, *mKeyValidPix );
00697     break;
00698   case 2: // key is valid and trusted
00699     lvi->setPixmap( 0, *mKeyGoodPix );
00700     break;
00701   case -1: // key is invalid
00702     lvi->setPixmap( 0, *mKeyBadPix );
00703     break;
00704   }
00705 
00706   // update the key info for this key
00707   // the key info is identified by a leading space; this shouldn't be
00708   // a problem because User Ids shouldn't start with a space
00709   for( lvi = lvi->firstChild(); lvi; lvi = lvi->nextSibling() ) {
00710     if( lvi->text( 1 ).at(0) == ' ' ) {
00711       lvi->setText( 1, keyInfo( key ) );
00712       break;
00713     }
00714   }
00715 }
00716 
00717 
00718 int
00719 KeySelectionDialog::keyAdmissibility( QListViewItem* lvi,
00720                                       TrustCheckMode trustCheckMode ) const
00721 {
00722   // Return:
00723   //  -1 = key must not be chosen,
00724   //   0 = not enough information to decide whether the give key is allowed
00725   //       or not,
00726   //   1 = key can be chosen
00727 
00728   if( mAllowedKeys == AllKeys ) {
00729     return 1;
00730   }
00731 
00732   Kpgp::Module *pgp = Kpgp::Module::getKpgp();
00733 
00734   if( 0 == pgp ) {
00735     return 0;
00736   }
00737 
00738   KeyID keyId = getKeyId( lvi );
00739   Kpgp::Key* key = pgp->publicKey( keyId );
00740 
00741   if( 0 == key ) {
00742     return 0;
00743   }
00744 
00745   int val = 0;
00746   if( trustCheckMode == ForceTrustCheck ) {
00747     key = pgp->rereadKey( keyId, true );
00748     updateKeyInfo( key, lvi );
00749     val = keyValidity( key );
00750   }
00751   else {
00752     val = keyValidity( key );
00753     if( ( trustCheckMode == AllowExpensiveTrustCheck ) && ( 0 == val ) ) {
00754       key = pgp->rereadKey( keyId, true );
00755       updateKeyInfo( key, lvi );
00756       val = keyValidity( key );
00757     }
00758   }
00759 
00760   switch( val ) {
00761   case -1: // key is not usable
00762     return -1;
00763     break;
00764   case 0: // key status unknown
00765     return 0;
00766     break;
00767   case 1: // key is valid, but untrusted
00768     if( mAllowedKeys & TrustedKeys ) {
00769       // only trusted keys are allowed
00770       return -1;
00771     }
00772     return 1;
00773     break;
00774   case 2: // key is trusted
00775     return 1;
00776     break;
00777   default:
00778     kdDebug( 5100 ) << "Error: Invalid key status value.\n";
00779   }
00780 
00781   return 0;
00782 }
00783 
00784 
00785 KeyID
00786 KeySelectionDialog::getKeyId( const QListViewItem* lvi ) const
00787 {
00788   KeyID keyId;
00789 
00790   if( 0 != lvi ) {
00791     if( 0 != lvi->parent() ) {
00792       keyId = lvi->parent()->text(0).local8Bit();
00793     }
00794     else {
00795       keyId = lvi->text(0).local8Bit();
00796     }
00797   }
00798 
00799   return keyId;
00800 }
00801 
00802 
00803 void KeySelectionDialog::slotRereadKeys()
00804 {
00805   Kpgp::Module *pgp = Kpgp::Module::getKpgp();
00806 
00807   if( 0 == pgp ) {
00808     return;
00809   }
00810 
00811   KeyList keys;
00812 
00813   if( PublicKeys & mAllowedKeys ) {
00814     pgp->readPublicKeys( true );
00815     keys = pgp->publicKeys();
00816   }
00817   else {
00818     pgp->readSecretKeys( true );
00819     keys = pgp->secretKeys();
00820   }
00821 
00822   // save the current position of the contents
00823   int offsetY = mListView->contentsY();
00824 
00825   if( mListView->isMultiSelection() ) {
00826     disconnect( mListView, SIGNAL( selectionChanged() ),
00827                 this,      SLOT( slotSelectionChanged() ) );
00828   }
00829   else {
00830     disconnect( mListView, SIGNAL( selectionChanged( QListViewItem * ) ),
00831                 this,      SLOT( slotSelectionChanged( QListViewItem * ) ) );
00832   }
00833 
00834   initKeylist( keys, KeyIDList( mKeyIds ) );
00835   slotFilter();
00836 
00837   if( mListView->isMultiSelection() ) {
00838     connect( mListView, SIGNAL( selectionChanged() ),
00839              this,      SLOT( slotSelectionChanged() ) );
00840     slotSelectionChanged();
00841   }
00842   else {
00843     connect( mListView, SIGNAL( selectionChanged( QListViewItem * ) ),
00844              this,      SLOT( slotSelectionChanged( QListViewItem * ) ) );
00845   }
00846 
00847   // restore the saved position of the contents
00848   mListView->setContentsPos( 0, offsetY );
00849 }
00850 
00851 
00852 void KeySelectionDialog::slotSelectionChanged( QListViewItem * lvi )
00853 {
00854   slotCheckSelection( lvi );
00855 }
00856 
00857 
00858 void KeySelectionDialog::slotSelectionChanged()
00859 {
00860   kdDebug(5100) << "KeySelectionDialog::slotSelectionChanged()\n";
00861 
00862   // (re)start the check selection timer. Checking the selection is delayed
00863   // because else drag-selection doesn't work very good (checking key trust
00864   // is slow).
00865   mCheckSelectionTimer->start( sCheckSelectionDelay );
00866 }
00867 
00868 
00869 void KeySelectionDialog::slotCheckSelection( QListViewItem* plvi /* = 0 */ )
00870 {
00871   kdDebug(5100) << "KeySelectionDialog::slotCheckSelection()\n";
00872 
00873   if( !mListView->isMultiSelection() ) {
00874     mKeyIds.clear();
00875     KeyID keyId = getKeyId( plvi );
00876     if( !keyId.isEmpty() ) {
00877       mKeyIds.append( keyId );
00878       enableButtonOK( 1 == keyAdmissibility( plvi, AllowExpensiveTrustCheck ) );
00879     }
00880     else {
00881       enableButtonOK( false );
00882     }
00883   }
00884   else {
00885     mCheckSelectionTimer->stop();
00886 
00887     // As we might change the selection, we have to disconnect the slot
00888     // to prevent recursion
00889     disconnect( mListView, SIGNAL( selectionChanged() ),
00890                 this,      SLOT( slotSelectionChanged() ) );
00891 
00892     KeyIDList newKeyIdList;
00893     QValueList<QListViewItem*> keysToBeChecked;
00894 
00895     bool keysAllowed = true;
00896     enum { UNKNOWN, SELECTED, DESELECTED } userAction = UNKNOWN;
00897     // Iterate over the tree to find selected keys.
00898     for( QListViewItem *lvi = mListView->firstChild();
00899          0 != lvi;
00900          lvi = lvi->nextSibling() ) {
00901       // We make sure that either all items belonging to a key are selected
00902       // or unselected. As it's possible to select/deselect multiple keys at
00903       // once in extended selection mode we have to figure out whether the user
00904       // selected or deselected keys.
00905 
00906       // First count the selected items of this key
00907       int itemCount = 1 + lvi->childCount();
00908       int selectedCount = lvi->isSelected() ? 1 : 0;
00909       for( QListViewItem *clvi = lvi->firstChild();
00910            0 != clvi;
00911            clvi = clvi->nextSibling() ) {
00912         if( clvi->isSelected() ) {
00913           ++selectedCount;
00914         }
00915       }
00916 
00917       if( userAction == UNKNOWN ) {
00918         // Figure out whether the user selected or deselected this key
00919         // Remark: A selected count of 0 doesn't mean anything since in
00920         //         extended selection mode a normal left click deselects
00921         //         the not clicked items.
00922         if( 0 < selectedCount ) {
00923           if( -1 == mKeyIds.findIndex( lvi->text(0).local8Bit() ) ) {
00924             // some items of this key are selected and the key wasn't selected
00925             // before => the user selected something
00926             kdDebug(5100) << "selectedCount: "<<selectedCount<<"/"<<itemCount
00927                           <<" --- User selected key "<<lvi->text(0)<<endl;
00928             userAction = SELECTED;
00929           }
00930           else if( ( itemCount > selectedCount ) &&
00931                    ( -1 != mKeyIds.findIndex( lvi->text(0).local8Bit() ) ) ) {
00932             // some items of this key are unselected and the key was selected
00933             // before => the user deselected something
00934             kdDebug(5100) << "selectedCount: "<<selectedCount<<"/"<<itemCount
00935                           <<" --- User deselected key "<<lvi->text(0)<<endl;
00936             userAction = DESELECTED;
00937           }
00938         }
00939       }
00940       if( itemCount == selectedCount ) {
00941         // add key to the list of selected keys
00942         KeyID keyId = lvi->text(0).local8Bit();
00943         newKeyIdList.append( keyId );
00944         int admissibility = keyAdmissibility( lvi, NoExpensiveTrustCheck );
00945         if( -1 == admissibility ) {
00946           keysAllowed = false;
00947         }
00948         else if ( 0 == admissibility ) {
00949           keysToBeChecked.append( lvi );
00950         }
00951       }
00952       else if( 0 < selectedCount ) {
00953         // not all items of this key are selected or unselected. change this
00954         // according to the user's action
00955         if( userAction == SELECTED ) {
00956           // select all items of this key
00957           mListView->setSelected( lvi, true );
00958           for( QListViewItem *clvi = lvi->firstChild();
00959                0 != clvi;
00960                clvi = clvi->nextSibling() ) {
00961             mListView->setSelected( clvi, true );
00962           }
00963           // add key to the list of selected keys
00964           KeyID keyId = lvi->text(0).local8Bit();
00965           newKeyIdList.append( keyId );
00966           int admissibility = keyAdmissibility( lvi, NoExpensiveTrustCheck );
00967           if( -1 == admissibility ) {
00968             keysAllowed = false;
00969           }
00970           else if ( 0 == admissibility ) {
00971             keysToBeChecked.append( lvi );
00972           }
00973         }
00974         else { // userAction == DESELECTED
00975           // deselect all items of this key
00976           mListView->setSelected( lvi, false );
00977           for( QListViewItem *clvi = lvi->firstChild();
00978                0 != clvi;
00979                clvi = clvi->nextSibling() ) {
00980             mListView->setSelected( clvi, false );
00981           }
00982         }
00983       }
00984     }
00985     kdDebug(5100) << "Selected keys: " << newKeyIdList.toStringList().join(", ") << endl;
00986     mKeyIds = newKeyIdList;
00987     if( !keysToBeChecked.isEmpty() ) {
00988       keysAllowed = keysAllowed && checkKeys( keysToBeChecked );
00989     }
00990     enableButtonOK( keysAllowed );
00991 
00992     connect( mListView, SIGNAL( selectionChanged() ),
00993              this,      SLOT( slotSelectionChanged() ) );
00994   }
00995 }
00996 
00997 
00998 bool KeySelectionDialog::checkKeys( const QValueList<QListViewItem*>& keys ) const
00999 {
01000   KProgressDialog* pProgressDlg = 0;
01001   bool keysAllowed = true;
01002   kdDebug(5100) << "Checking keys...\n";
01003 
01004   pProgressDlg = new KProgressDialog( 0, 0, i18n("Checking Keys"),
01005                                       i18n("Checking key 0xMMMMMMMM..."),
01006                                       true );
01007   pProgressDlg->setAllowCancel( false );
01008   pProgressDlg->progressBar()->setTotalSteps( keys.count() );
01009   pProgressDlg->setMinimumDuration( 1000 );
01010   pProgressDlg->show();
01011 
01012   for( QValueList<QListViewItem*>::ConstIterator it = keys.begin();
01013        it != keys.end();
01014        ++it ) {
01015     kdDebug(5100) << "Checking key 0x" << getKeyId( *it ) << "...\n";
01016     pProgressDlg->setLabel( i18n("Checking key 0x%1...")
01017                             .arg( getKeyId( *it ) ) );
01018     kapp->processEvents();
01019     keysAllowed = keysAllowed && ( -1 != keyAdmissibility( *it, AllowExpensiveTrustCheck ) );
01020     pProgressDlg->progressBar()->advance( 1 );
01021     kapp->processEvents();
01022   }
01023 
01024   delete pProgressDlg;
01025   pProgressDlg = 0;
01026 
01027   return keysAllowed;
01028 }
01029 
01030 
01031 void KeySelectionDialog::slotRMB( QListViewItem* lvi, const QPoint& pos, int )
01032 {
01033   if( !lvi ) {
01034     return;
01035   }
01036 
01037   mCurrentContextMenuItem = lvi;
01038 
01039   QPopupMenu menu(this);
01040   menu.insertItem( i18n( "Recheck Key" ), this, SLOT( slotRecheckKey() ) );
01041   menu.exec( pos );
01042 }
01043 
01044 
01045 void KeySelectionDialog::slotRecheckKey()
01046 {
01047   if( 0 != mCurrentContextMenuItem ) {
01048     // force rereading the key
01049     keyAdmissibility( mCurrentContextMenuItem, ForceTrustCheck );
01050     // recheck the selection
01051     slotCheckSelection( mCurrentContextMenuItem );
01052   }
01053 }
01054 
01055 void KeySelectionDialog::slotOk()
01056 {
01057   if( mCheckSelectionTimer->isActive() ) {
01058     slotCheckSelection();
01059   }
01060   mStartSearchTimer->stop();
01061   accept();
01062 }
01063 
01064 
01065 void KeySelectionDialog::slotCancel()
01066 {
01067   mCheckSelectionTimer->stop();
01068   mStartSearchTimer->stop();
01069   mKeyIds.clear();
01070   reject();
01071 }
01072 
01073 void KeySelectionDialog::slotSearch( const QString & text )
01074 {
01075   mSearchText = text.stripWhiteSpace().upper();
01076   mStartSearchTimer->start( sCheckSelectionDelay, true /*single-shot*/ );
01077 }
01078 
01079 void KeySelectionDialog::slotFilter()
01080 {
01081   if ( mSearchText.isEmpty() ) {
01082     showAllItems();
01083     return;
01084   }
01085 
01086   // OK, so we need to filter:
01087   QRegExp keyIdRegExp( "(?:0x)?[A-F0-9]{1,8}", false /*case-insens.*/ );
01088   if ( keyIdRegExp.exactMatch( mSearchText ) ) {
01089     if ( mSearchText.startsWith( "0X" ) )
01090       // search for keyID only:
01091       filterByKeyID( mSearchText.mid( 2 ) );
01092     else
01093       // search for UID and keyID:
01094       filterByKeyIDOrUID( mSearchText );
01095   } else {
01096     // search in UID:
01097     filterByUID( mSearchText );
01098   }
01099 }
01100 
01101 void KeySelectionDialog::filterByKeyID( const QString & keyID )
01102 {
01103   assert( keyID.length() <= 8 );
01104   assert( !keyID.isEmpty() ); // regexp in slotFilter should prevent these
01105   if ( keyID.isEmpty() )
01106     showAllItems();
01107   else
01108     for ( QListViewItem * item = mListView->firstChild() ; item ; item = item->nextSibling() )
01109       item->setVisible( item->text( 0 ).upper().startsWith( keyID ) );
01110 }
01111 
01112 void KeySelectionDialog::filterByKeyIDOrUID( const QString & str )
01113 {
01114   assert( !str.isEmpty() );
01115 
01116   // match beginnings of words:
01117   QRegExp rx( "\\b" + QRegExp::escape( str ), false );
01118 
01119   for ( QListViewItem * item = mListView->firstChild() ; item ; item = item->nextSibling() )
01120     item->setVisible( item->text( 0 ).upper().startsWith( str )
01121               || rx.search( item->text( 1 ) ) >= 0
01122               || anyChildMatches( item, rx ) );
01123 
01124 }
01125 
01126 void KeySelectionDialog::filterByUID( const QString & str )
01127 {
01128   assert( !str.isEmpty() );
01129 
01130   // match beginnings of words:
01131   QRegExp rx( "\\b" + QRegExp::escape( str ), false );
01132 
01133   for ( QListViewItem * item = mListView->firstChild() ; item ; item = item->nextSibling() )
01134     item->setVisible( rx.search( item->text( 1 ) ) >= 0
01135               || anyChildMatches( item, rx ) );
01136 }
01137 
01138 
01139 bool KeySelectionDialog::anyChildMatches( const QListViewItem * item, QRegExp & rx ) const
01140 {
01141   if ( !item )
01142     return false;
01143 
01144   QListViewItem * stop = item->nextSibling(); // It's OK if stop is NULL...
01145 
01146   for ( QListViewItemIterator it( item->firstChild() ) ; it.current() && it.current() != stop ; ++it )
01147     if ( rx.search( it.current()->text( 1 ) ) >= 0 ) {
01148       //item->setOpen( true ); // do we want that?
01149       return true;
01150     }
01151   return false;
01152 }
01153 
01154 void KeySelectionDialog::showAllItems()
01155 {
01156   for ( QListViewItem * item = mListView->firstChild() ; item ; item = item->nextSibling() )
01157     item->setVisible( true );
01158 }
01159 
01160 // ------------------------------------------------------------------------
01161 KeyRequester::KeyRequester( QWidget * parent, bool multipleKeys,
01162                 unsigned int allowedKeys, const char * name )
01163   : QWidget( parent, name ),
01164     mDialogCaption( i18n("OpenPGP Key Selection") ),
01165     mDialogMessage( i18n("Please select an OpenPGP key to use.") ),
01166     mMulti( multipleKeys ),
01167     mAllowedKeys( allowedKeys ),
01168     d( 0 )
01169 {
01170   QHBoxLayout * hlay = new QHBoxLayout( this, 0, KDialog::spacingHint() );
01171 
01172   // the label where the key id is to be displayed:
01173   mLabel = new QLabel( this );
01174   mLabel->setFrameStyle( QFrame::Panel | QFrame::Sunken );
01175 
01176   // the button to unset any key:
01177   mEraseButton = new QPushButton( this );
01178   mEraseButton->setAutoDefault( false );
01179   mEraseButton->setSizePolicy( QSizePolicy( QSizePolicy::Minimum,
01180                         QSizePolicy::Minimum ) );
01181   mEraseButton->setPixmap( SmallIcon( "clear_left" ) );
01182   QToolTip::add( mEraseButton, i18n("Clear") );
01183 
01184   // the button to call the KeySelectionDialog:
01185   mDialogButton = new QPushButton( i18n("Change..."), this );
01186   mDialogButton->setAutoDefault( false );
01187 
01188   hlay->addWidget( mLabel, 1 );
01189   hlay->addWidget( mEraseButton );
01190   hlay->addWidget( mDialogButton );
01191 
01192   connect( mEraseButton, SIGNAL(clicked()), SLOT(slotEraseButtonClicked()) );
01193   connect( mDialogButton, SIGNAL(clicked()), SLOT(slotDialogButtonClicked()) );
01194 
01195   setSizePolicy( QSizePolicy( QSizePolicy::MinimumExpanding,
01196                   QSizePolicy::Fixed ) );
01197 }
01198 
01199 KeyRequester::~KeyRequester() {
01200 
01201 }
01202 
01203 KeyIDList KeyRequester::keyIDs() const {
01204   return mKeys;
01205 }
01206 
01207 void KeyRequester::setKeyIDs( const KeyIDList & keyIDs ) {
01208   mKeys = keyIDs;
01209   if ( mKeys.empty() ) {
01210     mLabel->clear();
01211     return;
01212   }
01213   if ( mKeys.size() > 1 )
01214     setMultipleKeysEnabled( true );
01215 
01216   QString s = mKeys.toStringList().join(", ");
01217 
01218   mLabel->setText( s );
01219   QToolTip::remove( mLabel );
01220   QToolTip::add( mLabel, s );
01221 }
01222 
01223 void KeyRequester::slotDialogButtonClicked() {
01224   Module * pgp = Module::getKpgp();
01225 
01226   if ( !pgp ) {
01227     kdWarning() << "Kpgp::KeyRequester::slotDialogButtonClicked(): No pgp module found!" << endl;
01228     return;
01229   }
01230 
01231   setKeyIDs( keyRequestHook( pgp ) );
01232   emit changed();
01233 }
01234 
01235 void KeyRequester::slotEraseButtonClicked() {
01236   mKeys.clear();
01237   mLabel->clear();
01238   emit changed();
01239 }
01240 
01241 void KeyRequester::setDialogCaption( const QString & caption ) {
01242   mDialogCaption = caption;
01243 }
01244 
01245 void KeyRequester::setDialogMessage( const QString & msg ) {
01246   mDialogMessage = msg;
01247 }
01248 
01249 bool KeyRequester::isMultipleKeysEnabled() const {
01250   return mMulti;
01251 }
01252 
01253 void KeyRequester::setMultipleKeysEnabled( bool multi ) {
01254   if ( multi == mMulti ) return;
01255 
01256   if ( !multi && mKeys.size() > 1 )
01257     mKeys.erase( ++mKeys.begin(), mKeys.end() );
01258 
01259   mMulti = multi;
01260 }
01261 
01262 int KeyRequester::allowedKeys() const {
01263   return mAllowedKeys;
01264 }
01265 
01266 void KeyRequester::setAllowedKeys( int allowedKeys ) {
01267   mAllowedKeys = allowedKeys;
01268 }
01269 
01270 
01271 PublicKeyRequester::PublicKeyRequester( QWidget * parent, bool multi,
01272                     unsigned int allowed, const char * name )
01273   : KeyRequester( parent, multi, allowed & ~SecretKeys, name )
01274 {
01275 
01276 }
01277 
01278 PublicKeyRequester::~PublicKeyRequester() {
01279 
01280 }
01281 
01282 KeyIDList PublicKeyRequester::keyRequestHook( Module * pgp ) const {
01283   assert( pgp );
01284   return pgp->selectPublicKeys( mDialogCaption, mDialogMessage, mKeys, QString::null, mAllowedKeys );
01285 }
01286 
01287 SecretKeyRequester::SecretKeyRequester( QWidget * parent, bool multi,
01288                     unsigned int allowed, const char * name )
01289   : KeyRequester( parent, multi, allowed & ~PublicKeys, name )
01290 {
01291 
01292 }
01293 
01294 SecretKeyRequester::~SecretKeyRequester() {
01295 
01296 }
01297 
01298 KeyIDList SecretKeyRequester::keyRequestHook( Module * pgp ) const {
01299   assert( pgp );
01300 
01301   KeyID keyID = mKeys.first();
01302   keyID = pgp->selectSecretKey( mDialogCaption, mDialogMessage, keyID );
01303 
01304   return KeyIDList() << keyID;
01305 }
01306 
01307 
01308 
01309 // ------------------------------------------------------------------------
01310 KeyApprovalDialog::KeyApprovalDialog( const QStringList& addresses,
01311                                       const QValueVector<KeyIDList>& keyIDs,
01312                                       const int allowedKeys,
01313                                       QWidget *parent, const char *name,
01314                                       bool modal )
01315   : KDialogBase( parent, name, modal, i18n("Encryption Key Approval"),
01316                  Ok|Cancel, Ok ),
01317     mKeys( keyIDs ),
01318     mAllowedKeys( allowedKeys ),
01319     mPrefsChanged( false )
01320 {
01321   Kpgp::Module *pgp = Kpgp::Module::getKpgp();
01322 
01323   if( pgp == 0 )
01324     return;
01325 
01326   // ##### error handling
01327   // if( addresses.isEmpty() || keyList.isEmpty() ||
01328   //     addresses.count()+1 != keyList.count() )
01329   //   do something;
01330 
01331   QFrame *page = makeMainWidget();
01332   QVBoxLayout *topLayout = new QVBoxLayout( page, 0, KDialog::spacingHint() );
01333 
01334   QLabel *label = new QLabel( i18n("The following keys will be used for "
01335                                    "encryption:"),
01336                               page );
01337   topLayout->addWidget( label );
01338 
01339   QScrollView* sv = new QScrollView( page );
01340   sv->setResizePolicy( QScrollView::AutoOneFit );
01341   topLayout->addWidget( sv );
01342   QVBox* bigvbox = new QVBox( sv->viewport() );
01343   bigvbox->setMargin( KDialog::marginHint() );
01344   bigvbox->setSpacing( KDialog::spacingHint() );
01345   sv->addChild( bigvbox );
01346 
01347   QButtonGroup *mChangeButtonGroup = new QButtonGroup( bigvbox );
01348   mChangeButtonGroup->hide();
01349   mAddressLabels.resize( addresses.count() );
01350   mKeyIdsLabels.resize( keyIDs.size() );
01351   //mKeyIdListBoxes.resize( keyIDs.size() );
01352   mEncrPrefCombos.resize( addresses.count() );
01353 
01354   // the sender's key
01355   if( pgp->encryptToSelf() ) {
01356     mEncryptToSelf = 1;
01357     QHBox* hbox = new QHBox( bigvbox );
01358     new QLabel( i18n("Your keys:"), hbox );
01359     QLabel* keyidsL = new QLabel( hbox );
01360     if( keyIDs[0].isEmpty() ) {
01361       keyidsL->setText( i18n("<none> means 'no key'", "<none>") );
01362     }
01363     else {
01364       keyidsL->setText( "0x" + keyIDs[0].toStringList().join( "\n0x" ) );
01365     }
01366     keyidsL->setFrameStyle( QFrame::Panel | QFrame::Sunken );
01367     /*
01368     QListBox* keyidLB = new QListBox( hbox );
01369     if( keyIDs[0].isEmpty() ) {
01370       keyidLB->insertItem( i18n("<none>") );
01371     }
01372     else {
01373       keyidLB->insertStringList( keyIDs[0].toStringList() );
01374     }
01375     keyidLB->setSelectionMode( QListBox::NoSelection );
01376     keyidLB->setFrameStyle( QFrame::Panel | QFrame::Sunken );
01377     */
01378     QPushButton *button = new QPushButton( i18n("Change..."), hbox );
01379     mChangeButtonGroup->insert( button );
01380     button->setAutoDefault( false );
01381     hbox->setStretchFactor( keyidsL, 10 );
01382     mKeyIdsLabels.insert( 0, keyidsL );
01383     //hbox->setStretchFactor( keyidLB, 10 );
01384     //mKeyIdListBoxes.insert( 0, keyidLB );
01385 
01386     new KSeparator( Horizontal, bigvbox );
01387   }
01388   else {
01389     mEncryptToSelf = 0;
01390     // insert dummy KeyIdListBox
01391     mKeyIdsLabels.insert( 0, 0 );
01392     //mKeyIdListBoxes.insert( 0, 0 );
01393   }
01394 
01395   QStringList::ConstIterator ait;
01396   QValueVector<KeyIDList>::const_iterator kit;
01397   int i;
01398   for( ait = addresses.begin(), kit = keyIDs.begin(), i = 0;
01399        ( ait != addresses.end() ) && ( kit != keyIDs.end() );
01400        ++ait, ++kit, ++i ) {
01401     if( i == 0 ) {
01402       ++kit; // skip the sender's key id
01403     }
01404     else {
01405       new KSeparator( Horizontal, bigvbox );
01406     }
01407 
01408     QHBox *hbox = new QHBox( bigvbox );
01409     new QLabel( i18n("Recipient:"), hbox );
01410     QLabel *addressL = new QLabel( *ait, hbox );
01411     hbox->setStretchFactor( addressL, 10 );
01412     mAddressLabels.insert( i, addressL  );
01413 
01414     hbox = new QHBox( bigvbox );
01415     new QLabel( i18n("Encryption keys:"), hbox );
01416     QLabel* keyidsL = new QLabel( hbox );
01417     if( (*kit).isEmpty() ) {
01418       keyidsL->setText( i18n("<none> means 'no key'", "<none>") );
01419     }
01420     else {
01421       keyidsL->setText( "0x" + (*kit).toStringList().join( "\n0x" ) );
01422     }
01423     keyidsL->setFrameStyle( QFrame::Panel | QFrame::Sunken );
01424     /*
01425     QListBox* keyidLB = new QListBox( hbox );
01426     if( (*kit).isEmpty() ) {
01427       keyidLB->insertItem( i18n("<none>") );
01428     }
01429     else {
01430       keyidLB->insertStringList( (*kit).toStringList() );
01431     }
01432     keyidLB->setSelectionMode( QListBox::NoSelection );
01433     keyidLB->setFrameStyle( QFrame::Panel | QFrame::Sunken );
01434     */
01435     QPushButton *button = new QPushButton( i18n("Change..."), hbox );
01436     mChangeButtonGroup->insert( button );
01437     button->setAutoDefault( false );
01438     hbox->setStretchFactor( keyidsL, 10 );
01439     mKeyIdsLabels.insert( i + 1, keyidsL );
01440     //hbox->setStretchFactor( keyidLB, 10 );
01441     //mKeyIdListBoxes.insert( i + 1, keyidLB );
01442 
01443     hbox = new QHBox( bigvbox );
01444     new QLabel( i18n("Encryption preference:"), hbox );
01445     QComboBox *encrPrefCombo = new QComboBox( hbox );
01446     encrPrefCombo->insertItem( i18n("<none>") );
01447     encrPrefCombo->insertItem( i18n("Never Encrypt with This Key") );
01448     encrPrefCombo->insertItem( i18n("Always Encrypt with This Key") );
01449     encrPrefCombo->insertItem( i18n("Encrypt Whenever Encryption is Possible") );
01450     encrPrefCombo->insertItem( i18n("Always Ask") );
01451     encrPrefCombo->insertItem( i18n("Ask Whenever Encryption is Possible") );
01452 
01453     EncryptPref encrPref = pgp->encryptionPreference( *ait );
01454     switch( encrPref ) {
01455       case NeverEncrypt:
01456         encrPrefCombo->setCurrentItem( 1 );
01457         break;
01458       case AlwaysEncrypt:
01459         encrPrefCombo->setCurrentItem( 2 );
01460         break;
01461       case AlwaysEncryptIfPossible:
01462         encrPrefCombo->setCurrentItem( 3 );
01463         break;
01464       case AlwaysAskForEncryption:
01465         encrPrefCombo->setCurrentItem( 4 );
01466         break;
01467       case AskWheneverPossible:
01468         encrPrefCombo->setCurrentItem( 5 );
01469         break;
01470       default:
01471         encrPrefCombo->setCurrentItem( 0 );
01472     }
01473     connect( encrPrefCombo, SIGNAL(activated(int)),
01474              this, SLOT(slotPrefsChanged(int)) );
01475     mEncrPrefCombos.insert( i, encrPrefCombo );
01476   }
01477   connect( mChangeButtonGroup, SIGNAL(clicked(int)),
01478            this, SLOT(slotChangeEncryptionKey(int)) );
01479 
01480   // calculate the optimal width for the dialog
01481   int dialogWidth = marginHint()
01482                   + sv->frameWidth()
01483                   + bigvbox->sizeHint().width()
01484                   + sv->verticalScrollBar()->sizeHint().width()
01485                   + sv->frameWidth()
01486                   + marginHint()
01487                   + 2;
01488   // calculate the optimal height for the dialog
01489   int dialogHeight = marginHint()
01490                    + label->sizeHint().height()
01491                    + topLayout->spacing()
01492                    + sv->frameWidth()
01493                    + bigvbox->sizeHint().height()
01494                    + sv->horizontalScrollBar()->sizeHint().height()
01495                    + sv->frameWidth()
01496                    + topLayout->spacing()
01497                    + actionButton( KDialogBase::Cancel )->sizeHint().height()
01498                    + marginHint()
01499                    + 2;
01500   // don't make the dialog too large
01501   QRect desk = KGlobalSettings::desktopGeometry(this);
01502   int screenWidth = desk.width();
01503   if( dialogWidth > 3*screenWidth/4 )
01504     dialogWidth = 3*screenWidth/4;
01505   int screenHeight = desk.height();
01506   if( dialogHeight > 7*screenHeight/8 )
01507     dialogHeight = 7*screenHeight/8;
01508 
01509   setInitialSize( QSize( dialogWidth, dialogHeight ) );
01510 }
01511 
01512 void
01513 KeyApprovalDialog::slotChangeEncryptionKey( int nr )
01514 {
01515   Kpgp::Module *pgp = Kpgp::Module::getKpgp();
01516 
01517   kdDebug(5100)<<"Key approval dialog size is "
01518                <<width()<<"x"<<height()<<endl;
01519 
01520   if( pgp == 0 )
01521     return;
01522 
01523   if( !mEncryptToSelf )
01524     nr++;
01525   KeyIDList keyIds = mKeys[nr];
01526   if( nr == 0 ) {
01527     keyIds = pgp->selectPublicKeys( i18n("Encryption Key Selection"),
01528                                     i18n("if in your language something like "
01529                                          "'key(s)' isn't possible please "
01530                                          "use the plural in the translation",
01531                                          "Select the key(s) which should "
01532                                          "be used to encrypt the message "
01533                                          "to yourself."),
01534                                     keyIds,
01535                                     "",
01536                                     mAllowedKeys );
01537   }
01538   else {
01539     keyIds = pgp->selectPublicKeys( i18n("Encryption Key Selection"),
01540                                     i18n("if in your language something like "
01541                                          "'key(s)' isn't possible please "
01542                                          "use the plural in the translation",
01543                                          "Select the key(s) which should "
01544                                          "be used to encrypt the message "
01545                                          "for\n%1")
01546                                     .arg( mAddressLabels[nr-1]->text() ),
01547                                     keyIds,
01548                                     mAddressLabels[nr-1]->text(),
01549                                     mAllowedKeys );
01550   }
01551   if( !keyIds.isEmpty() ) {
01552     mKeys[nr] = keyIds;
01553     QLabel* keyidsL = mKeyIdsLabels[nr];
01554     keyidsL->setText( "0x" + keyIds.toStringList().join( "\n0x" ) );
01555     /*
01556     QListBox* qlb = mKeyIdListBoxes[nr];
01557     qlb->clear();
01558     qlb->insertStringList( keyIds.toStringList() );
01559     */
01560   }
01561 }
01562 
01563 
01564 void
01565 KeyApprovalDialog::slotOk()
01566 {
01567   Kpgp::Module *pgp = Kpgp::Module::getKpgp();
01568 
01569   if( pgp == 0 ) {
01570     accept();
01571     return;
01572   }
01573 
01574   if( mPrefsChanged ) {
01575     // store the changed preferences
01576     for( unsigned int i = 0; i < mAddressLabels.size(); i++ ) {
01577       // traverse all Address and Encryption Preference widgets
01578       EncryptPref encrPref;
01579       switch( mEncrPrefCombos[i]->currentItem() ) {
01580         case 1:
01581           encrPref = NeverEncrypt;
01582           break;
01583         case 2:
01584           encrPref = AlwaysEncrypt;
01585           break;
01586         case 3:
01587           encrPref = AlwaysEncryptIfPossible;
01588           break;
01589         case 4:
01590           encrPref = AlwaysAskForEncryption;
01591           break;
01592         case 5:
01593           encrPref = AskWheneverPossible;
01594           break;
01595         default:
01596         case 0:
01597           encrPref = UnknownEncryptPref;
01598       }
01599       pgp->setEncryptionPreference( mAddressLabels[i]->text(), encrPref );
01600     }
01601   }
01602 
01603   accept();
01604 }
01605 
01606 
01607 void
01608 KeyApprovalDialog::slotCancel()
01609 {
01610   reject();
01611 }
01612 
01613 
01614 
01615 // ------------------------------------------------------------------------
01616 CipherTextDialog::CipherTextDialog( const QCString & text,
01617                                     const QCString & charset, QWidget *parent,
01618                                     const char *name, bool modal )
01619   :KDialogBase( parent, name, modal, i18n("OpenPGP Information"), Ok|Cancel, Ok)
01620 {
01621   // FIXME (post KDE2.2): show some more info, e.g. the output of GnuPG/PGP
01622   QFrame *page = makeMainWidget();
01623   QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() );
01624 
01625   QLabel *label = new QLabel( page );
01626   label->setText(i18n("Result of the last encryption/sign operation:"));
01627   topLayout->addWidget( label );
01628 
01629   mEditBox = new QMultiLineEdit( page );
01630   mEditBox->setReadOnly(true);
01631   topLayout->addWidget( mEditBox, 10 );
01632 
01633   QString unicodeText;
01634   if (charset.isEmpty())
01635     unicodeText = QString::fromLocal8Bit(text.data());
01636   else {
01637     bool ok=true;
01638     QTextCodec *codec = KGlobal::charsets()->codecForName(charset, ok);
01639     if(!ok)
01640       unicodeText = QString::fromLocal8Bit(text.data());
01641     else
01642       unicodeText = codec->toUnicode(text.data(), text.length());
01643   }
01644 
01645   mEditBox->setText(unicodeText);
01646 
01647   setMinimumSize();
01648 }
01649 
01650 void CipherTextDialog::setMinimumSize()
01651 {
01652   // this seems to force a layout of the entire document, so we get a
01653   // a proper contentsWidth(). Is there a better way?
01654   for ( int i = 0; i < mEditBox->paragraphs(); i++ )
01655       (void) mEditBox->paragraphRect( i );
01656 
01657   mEditBox->setMinimumHeight( mEditBox->fontMetrics().lineSpacing() * 25 );
01658 
01659   int textWidth = mEditBox->contentsWidth() + 30;
01660 
01661 
01662 #if KDE_IS_VERSION( 3, 1, 90 )
01663   int maxWidth = KGlobalSettings::desktopGeometry(parentWidget()).width()-100;
01664 #else
01665   KConfig gc("kdeglobals", false, false);
01666   gc.setGroup("Windows");
01667   int maxWidth;
01668   if (QApplication::desktop()->isVirtualDesktop() &&
01669       gc.readBoolEntry("XineramaEnabled", true) &&
01670       gc.readBoolEntry("XineramaPlacementEnabled", true)) {
01671     maxWidth = QApplication::desktop()->screenGeometry(QApplication::desktop()->screenNumber(parentWidget())).width()-100;
01672   } else {
01673     maxWidth = QApplication::desktop()->geometry().width()-100;
01674   }
01675 #endif
01676 
01677   mEditBox->setMinimumWidth( QMIN( textWidth, maxWidth ) );
01678 }
01679 
01680 void KeyRequester::virtual_hook( int, void* ) {}
01681 
01682 void PublicKeyRequester::virtual_hook( int id, void* data ) {
01683   base::virtual_hook( id, data );
01684 }
01685 
01686 void SecretKeyRequester::virtual_hook( int id, void* data ) {
01687   base::virtual_hook( id, data );
01688 }
01689 
01690 } // namespace Kpgp
01691 
01692 
01693 
01694 #include "kpgpui.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys