00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
#ifdef HAVE_CONFIG_H
00034
#include <config.h>
00035
#endif
00036
00037
#include "certificatewizardimpl.h"
00038
#include "storedtransferjob.h"
00039
00040
00041
#include <kleo/oidmap.h>
00042
#include <kleo/keygenerationjob.h>
00043
#include <kleo/dn.h>
00044
#include <kleo/cryptobackendfactory.h>
00045
00046
#include <ui/progressdialog.h>
00047
00048
00049
#include <gpgmepp/keygenerationresult.h>
00050
00051
00052
#include <kabc/stdaddressbook.h>
00053
#include <kabc/addressee.h>
00054
00055
#include <kmessagebox.h>
00056
#include <klocale.h>
00057
#include <kapplication.h>
00058
#include <kdebug.h>
00059
#include <kdialog.h>
00060
#include <kurlrequester.h>
00061
#include <kdcopservicestarter.h>
00062
#include <dcopclient.h>
00063
#include <kio/job.h>
00064
#include <kio/netaccess.h>
00065
00066
00067
#include <qlineedit.h>
00068
#include <qtextedit.h>
00069
#include <qpushbutton.h>
00070
#include <qcheckbox.h>
00071
#include <qradiobutton.h>
00072
#include <qlayout.h>
00073
#include <qlabel.h>
00074
00075
#include <assert.h>
00076
00077
static QString attributeLabel(
const QString & attr,
bool required ) {
00078
if ( attr.isEmpty() )
00079
return QString::null;
00080
const QString label = Kleo::DNAttributeMapper::instance()->name2label( attr );
00081
if ( !label.isEmpty() )
00082
if ( required )
00083
return i18n(
"Format string for the labels in the \"Your Personal Data\" page - required field",
00084
"*%1 (%2):").arg( label, attr );
00085
else
00086
return i18n(
"Format string for the labels in the \"Your Personal Data\" page",
00087
"%1 (%2):").arg( label, attr );
00088
00089
else if ( required )
00090
return '*' + attr +
':';
00091
else
00092
return attr +
':';
00093 }
00094
00095
static QString attributeFromKey(
QString key ) {
00096
return key.remove(
'!' );
00097 }
00098
00099
static bool availForMod(
const QLineEdit * le ) {
00100
return le && le->isEnabled();
00101 }
00102
00103
00104
00105
00106
00107
00108
00109
00110 CertificateWizardImpl::CertificateWizardImpl(
QWidget* parent,
const char* name,
bool modal, WFlags fl )
00111 : CertificateWizard( parent, name, modal, fl )
00112 {
00113
00114 setNextEnabled( generatePage,
false );
00115
00116
00117 createPersonalDataPage();
00118
00119
00120 storeUR->setMode( KFile::File );
00121 storeUR->setFilter(
"application/pkcs10" );
00122 connect( storeUR, SIGNAL( urlSelected(
const QString& ) ),
00123
this, SLOT( slotURLSelected(
const QString& ) ) );
00124
00125
const KConfigGroup config( KGlobal::config(),
"CertificateCreationWizard" );
00126 caEmailED->setText( config.readEntry(
"CAEmailAddress" ) );
00127
00128 connect(
this, SIGNAL( helpClicked() ),
00129
this, SLOT( slotHelpClicked() ) );
00130 connect( insertAddressButton, SIGNAL( clicked() ),
00131
this, SLOT( slotSetValuesFromWhoAmI() ) );
00132 }
00133
00134
static bool requirementsAreMet(
const CertificateWizardImpl::AttrPairList & list ) {
00135
for ( CertificateWizardImpl::AttrPairList::const_iterator it = list.begin() ;
00136 it != list.
end() ; ++it ) {
00137
const QLineEdit * le = (*it).second;
00138
if ( !le )
00139
continue;
00140
const QString key = (*it).first;
00141
#ifndef NDEBUG
00142
kdbgstream s = kdDebug();
00143
#else
00144
kndbgstream s = kdDebug();
00145
#endif
00146
s <<
"requirementsAreMet(): checking \"" << key <<
"\" against \"" << le->text() <<
"\": ";
00147
if ( key.endsWith(
"!") && le->text().stripWhiteSpace().isEmpty() ) {
00148 s <<
"required field is empty!" << endl;
00149
return false;
00150 }
00151 s <<
"ok" << endl;
00152 }
00153
return true;
00154 }
00155
00156
00157
00158
00159
void CertificateWizardImpl::slotEnablePersonalDataPageExit() {
00160 setNextEnabled( personalDataPage, requirementsAreMet( _attrPairList ) );
00161 }
00162
00163
00164
00165
00166
00167 CertificateWizardImpl::~CertificateWizardImpl()
00168 {
00169
00170 }
00171
00172
static const char * oidForAttributeName(
const QString & attr ) {
00173
QCString attrUtf8 = attr.utf8();
00174
for (
unsigned int i = 0 ; i < numOidMaps ; ++i )
00175
if ( qstricmp( attrUtf8, oidmap[i].name ) == 0 )
00176
return oidmap[i].oid;
00177
return 0;
00178 }
00179
00180
00181
00182
00183
void CertificateWizardImpl::slotGenerateCertificate()
00184 {
00185
00186
QString certParms;
00187 certParms +=
"<GnupgKeyParms format=\"internal\">\n";
00188 certParms +=
"Key-Type: RSA\n";
00189 certParms +=
"Key-Length: 1024\n";
00190 certParms +=
"Key-Usage: ";
00191
if ( signOnlyCB->isChecked() )
00192 certParms +=
"Sign";
00193
else if ( encryptOnlyCB->isChecked() )
00194 certParms +=
"Encrypt";
00195
else
00196 certParms +=
"Sign, Encrypt";
00197 certParms +=
"\n";
00198 certParms +=
"name-dn: ";
00199
00200
QString email;
00201
QStringList rdns;
00202
for( AttrPairList::const_iterator it = _attrPairList.begin(); it != _attrPairList.end(); ++it ) {
00203
const QString attr = attributeFromKey( (*it).first.upper() );
00204
const QLineEdit * le = (*it).second;
00205
if ( !le )
00206
continue;
00207
00208
const QString value = le->text().stripWhiteSpace();
00209
if ( value.isEmpty() )
00210
continue;
00211
00212
if ( attr ==
"EMAIL" ) {
00213
00214
00215
00216 email = value;
00217
if ( !brokenCA->isChecked() )
00218
continue;
00219 }
00220
00221
if (
const char * oid = oidForAttributeName( attr ) ) {
00222
00223 rdns.push_back( QString::fromUtf8( oid ) +
'=' + value );
00224 }
else {
00225 rdns.push_back( attr +
'=' + value );
00226 }
00227 }
00228 certParms += rdns.join(
",");
00229
if( !email.isEmpty() )
00230 certParms +=
"\nname-email: " + email;
00231 certParms +=
"\n</GnupgKeyParms>\n";
00232
00233 kdDebug() << certParms << endl;
00234
00235
Kleo::KeyGenerationJob * job =
00236 Kleo::CryptoBackendFactory::instance()->smime()->keyGenerationJob();
00237 assert( job );
00238
00239 connect( job, SIGNAL(result(
const GpgME::KeyGenerationResult&,
const QByteArray&)),
00240 SLOT(slotResult(
const GpgME::KeyGenerationResult&,
const QByteArray&)) );
00241
00242 certificateTE->setText( certParms );
00243
00244
const GpgME::Error err = job->
start( certParms );
00245
if ( err )
00246 KMessageBox::error(
this,
00247 i18n(
"Could not start certificate generation: %1" )
00248 .arg( QString::fromLocal8Bit( err.asString() ) ),
00249 i18n(
"Certificate Manager Error" ) );
00250
else {
00251 generatePB->setEnabled(
false );
00252 setBackEnabled( generatePage,
false );
00253 (
void)
new Kleo::ProgressDialog( job, i18n(
"Generating key"),
this );
00254 }
00255 }
00256
00257
00258
void CertificateWizardImpl::slotResult(
const GpgME::KeyGenerationResult & res,
00259
const QByteArray & keyData ) {
00260
00261 _keyData = keyData;
00262
00263
if ( res.error().isCanceled() || res.error() ) {
00264 setNextEnabled( generatePage,
false );
00265 setBackEnabled( generatePage,
true );
00266 setFinishEnabled( finishPage,
false );
00267 generatePB->setEnabled(
true );
00268
if ( !res.error().isCanceled() )
00269 KMessageBox::error(
this,
00270 i18n(
"Could not generate certificate: %1" )
00271 .arg( QString::fromLatin1( res.error().asString() ) ),
00272 i18n(
"Certificate Manager Error" ) );
00273 }
else {
00274
00275
00276 setNextEnabled( generatePage,
true );
00277 setFinishEnabled( finishPage,
true );
00278 }
00279 }
00280
00281
void CertificateWizardImpl::slotHelpClicked()
00282 {
00283 kapp->invokeHelp(
"newcert" );
00284 }
00285
00286
void CertificateWizardImpl::slotSetValuesFromWhoAmI()
00287 {
00288
const KABC::Addressee a = KABC::StdAddressBook::self()->whoAmI();
00289
if ( a.isEmpty() )
00290
return;
00291
const KABC::Address adr = a.address(KABC::Address::Work);
00292
00293
for ( AttrPairList::const_iterator it = _attrPairList.begin() ;
00294 it != _attrPairList.end() ; ++it ) {
00295
QLineEdit * le = (*it).second;
00296
if ( !availForMod( le ) )
00297
continue;
00298
00299
const QString attr = attributeFromKey( (*it).first.upper() );
00300
if ( attr ==
"CN" )
00301 le->setText( a.formattedName() );
00302
else if ( attr ==
"EMAIL" )
00303 le->setText( a.preferredEmail() );
00304
else if ( attr ==
"O" )
00305 le->setText( a.organization() );
00306
else if ( attr ==
"OU" )
00307 le->setText( a.custom(
"KADDRESSBOOK",
"X-Department" ) );
00308
else if ( attr ==
"L" )
00309 le->setText( adr.locality() );
00310
else if ( attr ==
"SP" )
00311 le->setText( adr.region() );
00312
else if ( attr ==
"PC" )
00313 le->setText( adr.postalCode() );
00314
else if ( attr ==
"SN" )
00315 le->setText( a.familyName() );
00316
else if ( attr ==
"GN" )
00317 le->setText( a.givenName() );
00318
else if ( attr ==
"T" )
00319 le->setText( a.title() );
00320
else if ( attr ==
"BC" )
00321 le->setText( a.role() );
00322 }
00323 }
00324
00325
void CertificateWizardImpl::createPersonalDataPage()
00326 {
00327
QGridLayout* grid =
new QGridLayout( edContainer, 2, 1,
00328 KDialog::marginHint(), KDialog::spacingHint() );
00329
00330 KConfigGroup config( KGlobal::config(),
"CertificateCreationWizard" );
00331
QStringList attrOrder = config.readListEntry(
"DNAttributeOrder" );
00332
if ( attrOrder.empty() )
00333 attrOrder <<
"CN!" <<
"L" <<
"OU" <<
"O!" <<
"C!" <<
"EMAIL!";
00334
int row = 0;
00335
00336
for ( QStringList::const_iterator it = attrOrder.begin() ; it != attrOrder.end() ; ++it, ++row ) {
00337
const QString key = (*it).stripWhiteSpace().upper();
00338
const QString attr = attributeFromKey( key );
00339
if ( attr.isEmpty() ) {
00340 --row;
00341
continue;
00342 }
00343
const QString preset = config.readEntry( attr );
00344
const QString label = config.readEntry( attr +
"_label",
00345 attributeLabel( attr, key.endsWith(
"!") ) );
00346
00347
QLineEdit * le =
new QLineEdit( edContainer );
00348 grid->addWidget( le, row, 1 );
00349 grid->addWidget(
new QLabel( le, label.isEmpty() ? attr : label, edContainer ), row, 0 );
00350
00351 le->setText( preset );
00352
if ( config.entryIsImmutable( attr ) )
00353 le->setEnabled(
false );
00354
00355 _attrPairList.append(qMakePair(key, le));
00356
00357 connect( le, SIGNAL(textChanged(
const QString&)),
00358 SLOT(slotEnablePersonalDataPageExit()) );
00359 }
00360
00361
00362
if (KABC::StdAddressBook::self()->whoAmI().isEmpty() ||
00363 !config.readBoolEntry(
"ShowSetWhoAmI",
true))
00364 insertAddressButton->setEnabled(
false );
00365
00366 slotEnablePersonalDataPageExit();
00367 }
00368
00369
bool CertificateWizardImpl::sendToCA()
const {
00370
return sendToCARB->isChecked();
00371 }
00372
00373
QString CertificateWizardImpl::caEMailAddress()
const {
00374
return caEmailED->text().stripWhiteSpace();
00375 }
00376
00377
void CertificateWizardImpl::slotURLSelected(
const QString& _url )
00378 {
00379 KURL url = KURL::fromPathOrURL( _url.stripWhiteSpace() );
00380
#if ! KDE_IS_VERSION(3,2,90)
00381
00382
00383
QString fileName = url.fileName();
00384
int pos = fileName.findRev(
'.' );
00385
if ( pos < 0 )
00386 url.setFileName( fileName +
".p10" );
00387
#endif
00388
storeUR->setURL( url.prettyURL() );
00389 }
00390
00391 KURL CertificateWizardImpl::saveFileUrl()
const {
00392
return KURL::fromPathOrURL( storeUR->url().stripWhiteSpace() );
00393 }
00394
00395
void CertificateWizardImpl::showPage(
QWidget * page )
00396 {
00397 CertificateWizard::showPage( page );
00398
if ( page == generatePage ) {
00399
00400
00401
if ( storeInFileRB->isChecked() ) {
00402 storeUR->setEnabled(
true );
00403 caEmailED->setEnabled(
false );
00404 storeUR->setFocus();
00405 }
else {
00406 storeUR->setEnabled(
false );
00407 caEmailED->setEnabled(
true );
00408 caEmailED->setFocus();
00409 }
00410 }
00411 }
00412
00413
static const char*
const dcopObjectId =
"KMailIface";
00417
void CertificateWizardImpl::sendCertificate(
const QString& email,
const QByteArray& certificateData )
00418 {
00419
QString error;
00420
QCString dcopService;
00421
int result = KDCOPServiceStarter::self()->
00422 findServiceFor(
"DCOP/Mailer", QString::null,
00423 QString::null, &error, &dcopService );
00424
if ( result != 0 ) {
00425 kdDebug() <<
"Couldn't connect to KMail\n";
00426 KMessageBox::error(
this,
00427 i18n(
"DCOP Communication Error, unable to send certificate using KMail.\n%1" ).arg( error ) );
00428
return;
00429 }
00430
00431
QCString dummy;
00432
00433
00434
00435
if ( !kapp->dcopClient()->findObject( dcopService, dcopObjectId,
"",
QByteArray(), dcopService, dummy ) ) {
00436 KDCOPServiceStarter::self()->startServiceFor(
"DCOP/Mailer", QString::null,
00437 QString::null, &error, &dcopService );
00438 assert( kapp->dcopClient()->findObject( dcopService, dcopObjectId,
"",
QByteArray(), dcopService, dummy ) );
00439 }
00440
00441 DCOPClient* dcopClient = kapp->dcopClient();
00442
QByteArray data;
00443
QDataStream arg( data, IO_WriteOnly );
00444 arg << email;
00445 arg << certificateData;
00446
if( !dcopClient->send( dcopService, dcopObjectId,
00447
"sendCertificate(QString,QByteArray)", data ) ) {
00448 KMessageBox::error(
this,
00449 i18n(
"DCOP Communication Error, unable to send certificate using KMail." ) );
00450
return;
00451 }
00452
00453 CertificateWizard::accept();
00454 }
00455
00456
00457
00458
00459
void CertificateWizardImpl::accept()
00460 {
00461
if( sendToCA() ) {
00462
00463 sendCertificate( caEMailAddress(), _keyData );
00464 }
else {
00465
00466 KURL url = saveFileUrl();
00467
bool overwrite =
false;
00468
if ( KIO::NetAccess::exists( url,
false ,
this ) ) {
00469
if ( KMessageBox::Cancel == KMessageBox::warningContinueCancel(
00470
this,
00471 i18n(
"A file named \"%1\" already exists. "
00472
"Are you sure you want to overwrite it?" ).arg( url.prettyURL() ),
00473 i18n(
"Overwrite File?" ),
00474 i18n(
"&Overwrite" ) ) )
00475
return;
00476 overwrite =
true;
00477 }
00478
00479 KIO::Job* uploadJob = KIOext::put( _keyData, url, -1, overwrite,
false );
00480 uploadJob->setWindow(
this );
00481 connect( uploadJob, SIGNAL( result( KIO::Job* ) ),
00482
this, SLOT( slotUploadResult( KIO::Job* ) ) );
00483
00484 setFinishEnabled( finishPage,
false );
00485 }
00486 }
00487
00492
void CertificateWizardImpl::slotUploadResult( KIO::Job* job )
00493 {
00494
if ( job->error() ) {
00495 job->showErrorDialog();
00496 setFinishEnabled( finishPage,
true );
00497 }
else {
00498
00499 CertificateWizard::accept();
00500 }
00501 }
00502
00503
#include "certificatewizardimpl.moc"