37 #include "certificatewizardimpl.h"
38 #include "storedtransferjob.h"
41 #include <kleo/oidmap.h>
42 #include <kleo/keygenerationjob.h>
44 #include <kleo/cryptobackendfactory.h>
46 #include <ui/progressdialog.h>
49 #include <gpgmepp/keygenerationresult.h>
52 #include <tdeabc/stdaddressbook.h>
53 #include <tdeabc/addressee.h>
55 #include <tdemessagebox.h>
56 #include <tdelocale.h>
57 #include <tdeapplication.h>
60 #include <kurlrequester.h>
61 #include <kdcopservicestarter.h>
62 #include <dcopclient.h>
63 #include <tdeio/job.h>
64 #include <tdeio/netaccess.h>
67 #include <tqlineedit.h>
68 #include <tqtextedit.h>
69 #include <tqpushbutton.h>
70 #include <tqcheckbox.h>
71 #include <tqradiobutton.h>
74 #include <tqcombobox.h>
79 static const unsigned int keyLengths[] = {
80 1024, 1532, 2048, 3072, 4096
82 static const unsigned int numKeyLengths =
sizeof keyLengths /
sizeof *keyLengths;
84 static TQString attributeLabel(
const TQString & attr,
bool required ) {
87 const TQString label = Kleo::DNAttributeMapper::instance()->name2label( attr );
88 if ( !label.isEmpty() )
90 return i18n(
"Format string for the labels in the \"Your Personal Data\" page - required field",
91 "*%1 (%2):").arg( label, attr );
93 return i18n(
"Format string for the labels in the \"Your Personal Data\" page",
94 "%1 (%2):").arg( label, attr );
97 return '*' + attr +
':';
102 static TQString attributeFromKey( TQString key ) {
103 return key.remove(
'!' );
106 static bool availForMod(
const TQLineEdit * le ) {
107 return le && le->isEnabled();
117 CertificateWizardImpl::CertificateWizardImpl( TQWidget* parent,
const char* name,
bool modal, WFlags fl )
118 : CertificateWizard( parent, name, modal, fl )
121 setNextEnabled( generatePage,
false );
124 createPersonalDataPage();
127 storeUR->setMode( KFile::File );
128 storeUR->setFilter(
"application/pkcs10" );
129 connect( storeUR, TQ_SIGNAL( urlSelected(
const TQString& ) ),
130 this, TQ_SLOT( slotURLSelected(
const TQString& ) ) );
132 const TDEConfigGroup config( TDEGlobal::config(),
"CertificateCreationWizard" );
133 caEmailED->setText( config.readEntry(
"CAEmailAddress" ) );
135 connect(
this, TQ_SIGNAL( helpClicked() ),
136 this, TQ_SLOT( slotHelpClicked() ) );
137 connect( insertAddressButton, TQ_SIGNAL( clicked() ),
138 this, TQ_SLOT( slotSetValuesFromWhoAmI() ) );
140 for (
unsigned int i = 0 ; i < numKeyLengths ; ++i )
141 keyLengthCB->insertItem( i18n(
"%n bit",
"%n bits", keyLengths[i] ) );
144 static bool requirementsAreMet(
const CertificateWizardImpl::AttrPairList & list ) {
145 for ( CertificateWizardImpl::AttrPairList::const_iterator it = list.begin() ;
146 it != list.end() ; ++it ) {
147 const TQLineEdit * le = (*it).second;
150 const TQString key = (*it).first;
152 kdbgstream s = kdDebug();
154 kndbgstream s = kdDebug();
156 s <<
"requirementsAreMet(): checking \"" << key <<
"\" against \"" << le->text() <<
"\": ";
157 if ( key.endsWith(
"!") && le->text().stripWhiteSpace().isEmpty() ) {
158 s <<
"required field is empty!" << endl;
169 void CertificateWizardImpl::slotEnablePersonalDataPageExit() {
170 setNextEnabled( personalDataPage, requirementsAreMet( _attrPairList ) );
177 CertificateWizardImpl::~CertificateWizardImpl()
182 static const char * oidForAttributeName(
const TQString & attr ) {
183 TQCString attrUtf8 = attr.utf8();
184 for (
unsigned int i = 0 ; i < numOidMaps ; ++i )
185 if ( tqstricmp( attrUtf8, oidmap[i].name ) == 0 )
186 return oidmap[i].oid;
193 void CertificateWizardImpl::slotGenerateCertificate()
197 certParms +=
"<GnupgKeyParms format=\"internal\">\n";
198 certParms +=
"Key-Type: RSA\n";
199 certParms += TQString(
"Key-Length: %1\n" ).arg( keyLengths[keyLengthCB->currentItem()] );
200 certParms +=
"Key-Usage: ";
201 if ( signOnlyCB->isChecked() )
203 else if ( encryptOnlyCB->isChecked() )
204 certParms +=
"Encrypt";
206 certParms +=
"Sign, Encrypt";
208 certParms +=
"name-dn: ";
212 for( AttrPairList::const_iterator it = _attrPairList.begin(); it != _attrPairList.end(); ++it ) {
213 const TQString attr = attributeFromKey( (*it).first.upper() );
214 const TQLineEdit * le = (*it).second;
218 const TQString value = le->text().stripWhiteSpace();
219 if ( value.isEmpty() )
222 if ( attr ==
"EMAIL" ) {
227 if ( !brokenCA->isChecked() )
231 if (
const char * oid = oidForAttributeName( attr ) ) {
233 rdns.push_back( TQString::fromUtf8( oid ) +
'=' + Kleo::DN::escape( value ) );
235 rdns.push_back( attr +
'=' + Kleo::DN::escape( value ) );
238 certParms += rdns.join(
",");
239 if( !email.isEmpty() )
240 certParms +=
"\nname-email: " + email;
241 certParms +=
"\n</GnupgKeyParms>\n";
243 kdDebug() << certParms << endl;
245 Kleo::KeyGenerationJob * job =
246 Kleo::CryptoBackendFactory::instance()->smime()->keyGenerationJob();
249 connect( job, TQ_SIGNAL(result(
const GpgME::KeyGenerationResult&,
const TQByteArray&)),
250 TQ_SLOT(slotResult(
const GpgME::KeyGenerationResult&,
const TQByteArray&)) );
252 certificateTE->setText( certParms );
254 const GpgME::Error err = job->start( certParms );
256 KMessageBox::error(
this,
257 i18n(
"Could not start certificate generation: %1" )
258 .arg( TQString::fromLocal8Bit( err.asString() ) ),
259 i18n(
"Certificate Manager Error" ) );
261 generatePB->setEnabled(
false );
262 setBackEnabled( generatePage,
false );
263 (void)
new Kleo::ProgressDialog( job, i18n(
"Generating key"), this );
268 void CertificateWizardImpl::slotResult(
const GpgME::KeyGenerationResult & res,
269 const TQByteArray & keyData ) {
273 if ( res.error().isCanceled() || res.error() ) {
274 setNextEnabled( generatePage,
false );
275 setBackEnabled( generatePage,
true );
276 setFinishEnabled( finishPage,
false );
277 generatePB->setEnabled(
true );
278 if ( !res.error().isCanceled() )
279 KMessageBox::error(
this,
280 i18n(
"Could not generate certificate: %1" )
281 .arg( TQString::fromLatin1( res.error().asString() ) ),
282 i18n(
"Certificate Manager Error" ) );
286 setNextEnabled( generatePage,
true );
287 setFinishEnabled( finishPage,
true );
291 void CertificateWizardImpl::slotHelpClicked()
293 kapp->invokeHelp(
"newcert" );
296 void CertificateWizardImpl::slotSetValuesFromWhoAmI()
298 const TDEABC::Addressee a = TDEABC::StdAddressBook::self(
true )->whoAmI();
301 const TDEABC::Address adr = a.address(TDEABC::Address::Work);
303 for ( AttrPairList::const_iterator it = _attrPairList.begin() ;
304 it != _attrPairList.end() ; ++it ) {
305 TQLineEdit * le = (*it).second;
306 if ( !availForMod( le ) )
309 const TQString attr = attributeFromKey( (*it).first.upper() );
311 le->setText( a.formattedName() );
312 else if ( attr ==
"EMAIL" )
313 le->setText( a.preferredEmail() );
314 else if ( attr ==
"O" )
315 le->setText( a.organization() );
316 else if ( attr ==
"OU" )
317 le->setText( a.custom(
"KADDRESSBOOK",
"X-Department" ) );
318 else if ( attr ==
"L" )
319 le->setText( adr.locality() );
320 else if ( attr ==
"SP" )
321 le->setText( adr.region() );
322 else if ( attr ==
"PC" )
323 le->setText( adr.postalCode() );
324 else if ( attr ==
"SN" )
325 le->setText( a.familyName() );
326 else if ( attr ==
"GN" )
327 le->setText( a.givenName() );
328 else if ( attr ==
"T" )
329 le->setText( a.title() );
330 else if ( attr ==
"BC" )
331 le->setText( a.role() );
335 void CertificateWizardImpl::createPersonalDataPage()
337 TQGridLayout* grid =
new TQGridLayout( edContainer, 2, 1,
338 KDialog::marginHint(), KDialog::spacingHint() );
340 TDEConfigGroup config( TDEGlobal::config(),
"CertificateCreationWizard" );
341 TQStringList attrOrder = config.readListEntry(
"DNAttributeOrder" );
342 if ( attrOrder.empty() )
343 attrOrder <<
"CN!" <<
"L" <<
"OU" <<
"O!" <<
"C!" <<
"EMAIL!";
346 for ( TQStringList::const_iterator it = attrOrder.begin() ; it != attrOrder.end() ; ++it, ++row ) {
347 const TQString key = (*it).stripWhiteSpace().upper();
348 const TQString attr = attributeFromKey( key );
349 if ( attr.isEmpty() ) {
353 const TQString preset = config.readEntry( attr );
354 const TQString label = config.readEntry( attr +
"_label",
355 attributeLabel( attr, key.endsWith(
"!") ) );
357 TQLineEdit * le =
new TQLineEdit( edContainer );
358 grid->addWidget( le, row, 1 );
359 grid->addWidget(
new TQLabel( le, label.isEmpty() ? attr : label, edContainer ), row, 0 );
361 le->setText( preset );
362 if ( config.entryIsImmutable( attr ) )
363 le->setEnabled(
false );
365 _attrPairList.append(qMakePair(key, le));
367 connect( le, TQ_SIGNAL(textChanged(
const TQString&)),
368 TQ_SLOT(slotEnablePersonalDataPageExit()) );
372 if (TDEABC::StdAddressBook::self(
true )->whoAmI().isEmpty() ||
373 !config.readBoolEntry(
"ShowSetWhoAmI",
true))
374 insertAddressButton->setEnabled(
false );
376 slotEnablePersonalDataPageExit();
379 bool CertificateWizardImpl::sendToCA()
const {
380 return sendToCARB->isChecked();
383 TQString CertificateWizardImpl::caEMailAddress()
const {
384 return caEmailED->text().stripWhiteSpace();
387 void CertificateWizardImpl::slotURLSelected(
const TQString& _url )
389 KURL url = KURL::fromPathOrURL( _url.stripWhiteSpace() );
390 #if ! KDE_IS_VERSION(3,2,90)
393 TQString fileName = url.fileName();
394 int pos = fileName.findRev(
'.' );
396 url.setFileName( fileName +
".p10" );
398 storeUR->setURL( url.prettyURL() );
401 KURL CertificateWizardImpl::saveFileUrl()
const {
402 return KURL::fromPathOrURL( storeUR->url().stripWhiteSpace() );
405 void CertificateWizardImpl::showPage( TQWidget * page )
407 CertificateWizard::showPage( page );
408 if ( page == generatePage ) {
411 if ( storeInFileRB->isChecked() ) {
412 storeUR->setEnabled(
true );
413 caEmailED->setEnabled(
false );
416 storeUR->setEnabled(
false );
417 caEmailED->setEnabled(
true );
418 caEmailED->setFocus();
423 static const char*
const dcopObjectId =
"KMailIface";
427 void CertificateWizardImpl::sendCertificate(
const TQString& email,
const TQByteArray& certificateData )
430 TQCString dcopService;
431 int result = KDCOPServiceStarter::self()->
432 findServiceFor(
"DCOP/Mailer", TQString(),
433 TQString(), &error, &dcopService );
435 kdDebug() <<
"Couldn't connect to KMail\n";
436 KMessageBox::error(
this,
437 i18n(
"DCOP Communication Error, unable to send certificate using KMail.\n%1" ).arg( error ) );
444 if ( !kapp->dcopClient()->findObject( dcopService, dcopObjectId,
"", TQByteArray(), dummy, dummy ) ) {
445 DCOPRef ref( dcopService, dcopService );
446 DCOPReply reply = ref.call(
"load()" );
447 if ( reply.isValid() && (
bool)reply ) {
448 Q_ASSERT( kapp->dcopClient()->findObject( dcopService, dcopObjectId,
"", TQByteArray(), dummy, dummy ) );
450 kdWarning() <<
"Error loading " << dcopService << endl;
453 DCOPClient* dcopClient = kapp->dcopClient();
455 TQDataStream arg( data, IO_WriteOnly );
457 arg << certificateData;
458 if( !dcopClient->send( dcopService, dcopObjectId,
459 "sendCertificate(TQString,TQByteArray)", data ) ) {
460 KMessageBox::error(
this,
461 i18n(
"DCOP Communication Error, unable to send certificate using KMail." ) );
465 CertificateWizard::accept();
471 void CertificateWizardImpl::accept()
475 sendCertificate( caEMailAddress(), _keyData );
478 KURL url = saveFileUrl();
479 bool overwrite =
false;
480 if ( TDEIO::NetAccess::exists( url,
false ,
this ) ) {
481 if ( KMessageBox::Cancel == KMessageBox::warningContinueCancel(
483 i18n(
"A file named \"%1\" already exists. "
484 "Are you sure you want to overwrite it?" ).arg( url.prettyURL() ),
485 i18n(
"Overwrite File?" ),
486 i18n(
"&Overwrite" ) ) )
491 TDEIO::Job* uploadJob = TDEIOext::put( _keyData, url, -1, overwrite,
false );
492 uploadJob->setWindow(
this );
493 connect( uploadJob, TQ_SIGNAL( result( TDEIO::Job* ) ),
494 this, TQ_SLOT( slotUploadResult( TDEIO::Job* ) ) );
496 setFinishEnabled( finishPage,
false );
504 void CertificateWizardImpl::slotUploadResult( TDEIO::Job* job )
506 if ( job->error() ) {
507 job->showErrorDialog();
508 setFinishEnabled( finishPage,
true );
511 CertificateWizard::accept();
515 #include "certificatewizardimpl.moc"