33 #include <config-kleopatra.h>
37 #include "ui_chooseprotocolpage.h"
38 #include "ui_enterdetailspage.h"
39 #include "ui_overviewpage.h"
40 #include "ui_keycreationpage.h"
41 #include "ui_resultpage.h"
43 #include "ui_advancedsettingsdialog.h"
55 #include <kleo/stl_util.h>
57 #include <kleo/oidmap.h>
58 #include <kleo/keygenerationjob.h>
59 #include <kleo/cryptobackendfactory.h>
60 #include <kleo/cryptobackend.h>
62 #include <gpgme++/global.h>
63 #include <gpgme++/keygenerationresult.h>
66 #include <KConfigGroup>
71 #include <KMessageBox>
73 #include <QRegExpValidator>
75 #include <QMetaProperty>
79 #include <QDesktopServices>
81 #include <boost/range.hpp>
86 using namespace Kleo::NewCertificateUi;
87 using namespace Kleo::Commands;
88 using namespace GpgME;
89 using namespace boost;
103 kdtools::for_each_adjacent_pair( wl, &QWidget::setTabOrder );
125 static bool is_rsa(
unsigned int algo ) {
126 return is_algo( static_cast<gpgme_pubkey_algo_t>( algo ),
RSA );
129 static bool is_dsa(
unsigned int algo ) {
130 return is_algo( static_cast<gpgme_pubkey_algo_t>( algo ),
DSA );
133 static bool is_elg(
unsigned int algo ) {
134 return is_algo( static_cast<gpgme_pubkey_algo_t>( algo ),
ELG );
139 const bool autoExclusive = b->autoExclusive();
140 b->setAutoExclusive(
false );
141 b->setChecked( b->isEnabled() && on );
142 b->setAutoExclusive( autoExclusive );
145 static void set_keysize( QComboBox * cb,
unsigned int strength ) {
148 const int idx = cb->findData( static_cast<int>( strength ) );
150 kWarning() <<
"keysize " << strength <<
" not allowed";
151 cb->setCurrentIndex( idx );
157 const int idx = cb->currentIndex();
160 return cb->itemData( idx ).toInt();
164 namespace NewCertificateUi {
168 explicit WizardPage(
QWidget * parent=0 )
181 if (
const QAbstractButton *
const b = this->button( button ) )
182 return b->isVisible();
191 if ( QAbstractButton *
const b = this->button( button ) )
192 b->setVisible( visible );
196 #define FIELD(type, name) type name() const { return field( QLatin1String(#name) ).value<type>(); }
198 FIELD(
bool, signingAllowed )
199 FIELD(
bool, encryptionAllowed )
200 FIELD(
bool, certificationAllowed )
201 FIELD(
bool, authenticationAllowed )
205 FIELD( QString, comment )
208 FIELD(
int, keyType )
209 FIELD(
int, keyStrength )
211 FIELD(
int, subkeyType )
212 FIELD(
int, subkeyStrength )
214 FIELD( QDate, expiryDate )
216 FIELD( QStringList, additionalUserIDs )
217 FIELD( QStringList, additionalEMailAddresses )
218 FIELD( QStringList, dnsNames )
219 FIELD( QStringList, uris )
221 FIELD( QString, url )
222 FIELD( QString, error )
223 FIELD( QString, result )
224 FIELD( QString, fingerprint )
230 using namespace Kleo::NewCertificateUi;
234 class AdvancedSettingsDialog :
public QDialog {
236 Q_PROPERTY( QStringList additionalUserIDs READ additionalUserIDs WRITE setAdditionalUserIDs )
237 Q_PROPERTY( QStringList additionalEMailAddresses READ additionalEMailAddresses WRITE setAdditionalEMailAddresses )
238 Q_PROPERTY( QStringList dnsNames READ dnsNames WRITE setDnsNames )
239 Q_PROPERTY( QStringList uris READ uris WRITE setUris )
240 Q_PROPERTY( uint keyStrength READ keyStrength WRITE setKeyStrength )
241 Q_PROPERTY( uint keyType READ keyType WRITE setKeyType )
242 Q_PROPERTY( uint subkeyStrength READ subkeyStrength WRITE setSubkeyStrength )
243 Q_PROPERTY( uint subkeyType READ subkeyType WRITE setSubkeyType )
244 Q_PROPERTY(
bool signingAllowed READ signingAllowed WRITE setSigningAllowed )
245 Q_PROPERTY(
bool encryptionAllowed READ encryptionAllowed WRITE setEncryptionAllowed )
246 Q_PROPERTY(
bool certificationAllowed READ certificationAllowed WRITE setCertificationAllowed )
247 Q_PROPERTY(
bool authenticationAllowed READ authenticationAllowed WRITE setAuthenticationAllowed )
248 Q_PROPERTY( QDate expiryDate READ expiryDate WRITE setExpiryDate )
250 explicit AdvancedSettingsDialog(
QWidget * parent=0 )
252 protocol( UnknownProtocol ),
253 pgpDefaultAlgorithm( GPGME_PK_ELG_E ),
254 cmsDefaultAlgorithm( GPGME_PK_RSA ),
255 keyTypeImmutable(
false ),
259 const QDate today = QDate::currentDate();
260 ui.expiryDE->setMinimumDate( today );
261 ui.expiryDE->setDate( today.addYears( 2 ) );
262 ui.emailLW->setDefaultValue( i18n(
"new email") );
263 ui.dnsLW->setDefaultValue( i18n(
"new dns name") );
264 ui.uriLW->setDefaultValue( i18n(
"new uri") );
266 fillKeySizeComboBoxen();
269 void setProtocol( GpgME::Protocol proto ) {
270 if ( protocol == proto )
273 loadDefaultKeyType();
276 void setAdditionalUserIDs(
const QStringList & items ) { ui.uidLW->setItems( items ); }
277 QStringList additionalUserIDs()
const {
return ui.uidLW->items(); }
279 void setAdditionalEMailAddresses(
const QStringList & items ) { ui.emailLW->setItems( items ); }
280 QStringList additionalEMailAddresses()
const {
return ui.emailLW->items(); }
282 void setDnsNames(
const QStringList & items ) { ui.dnsLW->setItems( items ); }
283 QStringList dnsNames()
const {
return ui.dnsLW->items(); }
285 void setUris(
const QStringList & items ) { ui.uriLW->setItems( items ); }
286 QStringList uris()
const {
return ui.uriLW->items(); }
289 void setKeyStrength(
unsigned int strength ) {
293 unsigned int keyStrength()
const {
295 ui.dsaRB->isChecked() ?
get_keysize( ui.dsaKeyStrengthCB ) :
296 ui.rsaRB->isChecked() ?
get_keysize( ui.rsaKeyStrengthCB ) : 0 ;
299 void setKeyType(
unsigned int algo ) {
300 QRadioButton *
const rb =
301 is_rsa( algo ) ? ui.rsaRB :
302 is_dsa( algo ) ? ui.dsaRB : 0 ;
304 rb->setChecked(
true );
306 unsigned int keyType()
const {
308 ui.dsaRB->isChecked() ? GPGME_PK_DSA :
309 ui.rsaRB->isChecked() ? GPGME_PK_RSA :
313 void setSubkeyType(
unsigned int algo ) { ui.elgCB->setChecked(
is_elg( algo ) ); }
314 unsigned int subkeyType()
const {
return ui.elgCB->isChecked() ? GPGME_PK_ELG_E : 0 ; }
316 void setSubkeyStrength(
unsigned int strength ) {
319 unsigned int subkeyStrength()
const {
323 void setSigningAllowed(
bool on ) { ui.signingCB->setChecked( on ); }
324 bool signingAllowed()
const {
return ui.signingCB->isChecked(); }
326 void setEncryptionAllowed(
bool on ) { ui.encryptionCB->setChecked( on ); }
327 bool encryptionAllowed()
const {
return ui.encryptionCB->isChecked(); }
329 void setCertificationAllowed(
bool on ) { ui.certificationCB->setChecked( on ); }
330 bool certificationAllowed()
const {
return ui.certificationCB->isChecked(); }
332 void setAuthenticationAllowed(
bool on ) { ui.authenticationCB->setChecked( on ); }
333 bool authenticationAllowed()
const {
return ui.authenticationCB->isChecked(); }
335 void setExpiryDate(
const QDate & date ) {
if ( date.isValid() ) ui.expiryDE->setDate( date );
else ui.expiryCB->setChecked(
false ); }
336 QDate expiryDate()
const {
return ui.expiryCB->isChecked() ? ui.expiryDE->date() : QDate() ; }
342 void slotKeyMaterialSelectionChanged() {
343 const unsigned int algo = keyType();
344 const unsigned int sk_algo = subkeyType();
346 if ( !keyTypeImmutable ) {
347 ui.elgCB->setEnabled(
is_dsa( algo ) );
348 if ( sender() == ui.dsaRB || sender() == ui.rsaRB )
349 ui.elgCB->setChecked(
is_dsa( algo ) );
352 ui.encryptionCB->setEnabled(
true );
353 ui.encryptionCB->setChecked(
true );
354 ui.signingCB->setEnabled(
true );
355 ui.signingCB->setChecked(
true );
356 ui.authenticationCB->setEnabled(
true );
357 }
else if (
is_dsa( algo ) ) {
358 ui.encryptionCB->setEnabled(
false );
360 ui.encryptionCB->setChecked(
true );
362 ui.encryptionCB->setChecked(
false );
369 void slotSigningAllowedToggled(
bool on ) {
370 if ( !on && protocol ==
CMS && !encryptionAllowed() )
371 setEncryptionAllowed(
true );
373 void slotEncryptionAllowedToggled(
bool on ) {
374 if ( !on && protocol ==
CMS && !signingAllowed() )
375 setSigningAllowed(
true );
379 void fillKeySizeComboBoxen();
380 void loadDefaultKeyType();
381 void updateWidgetVisibility();
384 GpgME::Protocol protocol;
385 unsigned int pgpDefaultAlgorithm;
386 unsigned int cmsDefaultAlgorithm;
387 bool keyTypeImmutable;
388 Ui_AdvancedSettingsDialog ui;
391 class ChooseProtocolPage :
public WizardPage {
394 explicit ChooseProtocolPage(
QWidget * p=0 )
396 initialized( false ),
400 registerField( QLatin1String(
"pgp"), ui.pgpCLB );
403 void setProtocol( Protocol proto ) {
405 ui.pgpCLB->setChecked(
true );
406 else if ( proto ==
CMS )
407 ui.x509CLB->setChecked(
true );
414 Protocol protocol()
const {
416 ui.pgpCLB->isChecked() ?
OpenPGP :
417 ui.x509CLB->isChecked() ?
CMS : UnknownProtocol ;
420 void initializePage() {
421 if ( !initialized ) {
422 connect( ui.pgpCLB, SIGNAL(clicked()), wizard(), SLOT(next()), Qt::QueuedConnection );
423 connect( ui.x509CLB, SIGNAL(clicked()), wizard(), SLOT(next()), Qt::QueuedConnection );
428 bool isComplete()
const {
429 return protocol() != UnknownProtocol ;
433 bool initialized : 1;
434 Ui_ChooseProtocolPage ui;
444 class EnterDetailsPage :
public WizardPage {
447 explicit EnterDetailsPage(
QWidget * p=0 )
448 : WizardPage( p ), dialog( this ), ui()
453 ui.errorLB->setText( QLatin1String(
"2<br>1") );
454 ui.errorLB->setFixedHeight( ui.errorLB->minimumSizeHint().height() );
457 connect( ui.resultLE, SIGNAL(textChanged(QString)),
458 SIGNAL(completeChanged()) );
460 connect( ui.emailLE, SIGNAL(textChanged(QString)),
461 SIGNAL(completeChanged()) );
462 connect( ui.addEmailToDnCB, SIGNAL(toggled(
bool)),
463 SLOT(slotUpdateResultLabel()) );
464 registerDialogPropertiesAsFields();
465 registerField( QLatin1String(
"dn"), ui.resultLE );
466 registerField( QLatin1String(
"name"), ui.nameLE );
467 registerField( QLatin1String(
"email"), ui.emailLE );
468 registerField( QLatin1String(
"comment"), ui.commentLE );
472 bool isComplete()
const;
473 void initializePage() {
485 void registerDialogPropertiesAsFields();
488 QString pgpUserID()
const;
489 QString cmsDN()
const;
492 void slotAdvancedSettingsClicked();
493 void slotUpdateResultLabel() {
494 ui.resultLE->setText( pgp() ? pgpUserID() : cmsDN() );
498 QVector<Line> lineList;
501 AdvancedSettingsDialog dialog;
502 Ui_EnterDetailsPage ui;
505 class OverviewPage :
public WizardPage {
508 explicit OverviewPage(
QWidget * p=0 )
509 : WizardPage( p ), ui()
512 setCommitPage(
true );
516 void initializePage() {
521 void slotShowDetails() {
522 ui.textBrowser->setHtml( i18nFormatGnupgKeyParms( ui.showAllDetailsCB->isChecked() ) );
526 QStringList i18nKeyUsages()
const;
527 QStringList i18nSubkeyUsages()
const;
528 QStringList i18nCombinedKeyUsages()
const;
529 QString i18nFormatGnupgKeyParms(
bool details )
const;
535 class KeyCreationPage :
public WizardPage {
538 explicit KeyCreationPage(
QWidget * p=0 )
545 bool isComplete()
const {
549 void initializePage() {
555 const CryptoBackend::Protocol *
const proto = CryptoBackendFactory::instance()->protocol( pgp() ?
OpenPGP :
CMS );
558 KeyGenerationJob *
const j = proto->keyGenerationJob();
561 connect( j, SIGNAL(result(GpgME::KeyGenerationResult,QByteArray,QString)),
562 this, SLOT(slotResult(GpgME::KeyGenerationResult,QByteArray,QString)) );
563 if (
const Error err = j->start( createGnupgKeyParms() ) )
564 setField( QLatin1String(
"error"), i18n(
"Could not start certificate creation: %1",
565 QString::fromLocal8Bit( err.asString() ) ) );
569 QStringList keyUsages()
const;
570 QStringList subkeyUsages()
const;
571 QString createGnupgKeyParms()
const;
574 void slotResult(
const GpgME::KeyGenerationResult & result,
const QByteArray & request,
const QString & auditLog )
576 Q_UNUSED( auditLog );
577 if ( result.error().code() ) {
578 setField( QLatin1String(
"error"), result.error().isCanceled()
579 ? i18n(
"Operation canceled.")
580 : i18n(
"Could not create certificate: %1",
581 QString::fromLocal8Bit( result.error().asString() ) ) );
582 setField( QLatin1String(
"url"), QString() );
583 setField( QLatin1String(
"result"), QString() );
584 }
else if ( pgp() ) {
585 setField( QLatin1String(
"error"), QString() );
586 setField( QLatin1String(
"url"), QString() );
587 setField( QLatin1String(
"result"), i18n(
"Certificate created successfully.\n"
588 "Fingerprint: %1", QLatin1String(result.fingerprint()) ) );
590 QFile file( tmpDir().absoluteFilePath( QLatin1String(
"request.p10") ) );
592 if ( !file.open( QIODevice::WriteOnly ) ) {
593 setField( QLatin1String(
"error"), i18n(
"Could not write output file %1: %2",
594 file.fileName(), file.errorString() ) );
595 setField( QLatin1String(
"url"), QString() );
596 setField( QLatin1String(
"result"), QString() );
598 file.write( request );
599 setField( QLatin1String(
"error"), QString() );
600 setField( QLatin1String(
"url"), QUrl::fromLocalFile( file.fileName() ).toString() );
601 setField( QLatin1String(
"result"), i18n(
"Certificate created successfully.") );
604 setField( QLatin1String(
"fingerprint"), QString::fromLatin1( result.fingerprint() ) );
606 emit completeChanged();
607 QMetaObject::invokeMethod( wizard(),
"next", Qt::QueuedConnection );
611 QPointer<KeyGenerationJob> job;
612 Ui_KeyCreationPage ui;
615 class ResultPage :
public WizardPage {
618 explicit ResultPage(
QWidget * p=0 )
620 initialized( false ),
621 successfullyCreatedSigningCertificate( false ),
622 successfullyCreatedEncryptionCertificate( false ),
626 ui.dragQueen->setPixmap( KIcon( QLatin1String(
"kleopatra") ).pixmap( 64, 64 ) );
627 registerField( QLatin1String(
"error"), ui.errorTB,
"plainText" );
628 registerField( QLatin1String(
"result"), ui.resultTB,
"plainText" );
629 registerField( QLatin1String(
"url"), ui.dragQueen,
"url" );
631 QLineEdit * le =
new QLineEdit(
this );
633 registerField( QLatin1String(
"fingerprint"), le );
636 void initializePage() {
637 const bool error = isError();
640 setTitle( i18nc(
"@title",
"Key Creation Failed") );
641 setSubTitle( i18n(
"Key pair creation failed. Please find details about the failure below.") );
643 setTitle( i18nc(
"@title",
"Key Pair Successfully Created") );
644 setSubTitle( i18n(
"Your new key pair was created successfully. Please find details on the result and some suggested next steps below.") );
647 ui.resultTB ->setVisible( !error );
648 ui.errorTB ->setVisible( error );
649 ui.dragQueen ->setVisible( !error && !pgp() );
650 ui.restartWizardPB ->setVisible( error );
651 ui.nextStepsGB ->setVisible( !error );
652 ui.saveRequestToFilePB ->setVisible( !pgp() );
653 ui.makeBackupPB ->setVisible( pgp() );
654 ui.createRevocationRequestPB->setVisible( pgp() &&
false );
656 #ifdef KDEPIM_MOBILE_UI
657 ui.sendCertificateByEMailPB ->setVisible(
false );
658 ui.sendRequestByEMailPB ->setVisible(
false );
659 ui.uploadToKeyserverPB ->setVisible(
false );
661 ui.sendCertificateByEMailPB ->setVisible( pgp() );
662 ui.sendRequestByEMailPB ->setVisible( !pgp() );
663 ui.uploadToKeyserverPB ->setVisible( pgp() );
666 if ( !error && !pgp() ) {
667 if ( signingAllowed() && !encryptionAllowed() )
668 successfullyCreatedSigningCertificate =
true;
669 else if ( !signingAllowed() && encryptionAllowed() )
670 successfullyCreatedEncryptionCertificate =
true;
672 successfullyCreatedEncryptionCertificate = successfullyCreatedSigningCertificate =
true;
675 ui.createSigningCertificatePB->setVisible( successfullyCreatedEncryptionCertificate && !successfullyCreatedSigningCertificate );
676 ui.createEncryptionCertificatePB->setVisible( successfullyCreatedSigningCertificate && !successfullyCreatedEncryptionCertificate );
681 connect( ui.restartWizardPB, SIGNAL(clicked()),
682 wizard(), SLOT(restart()) );
690 bool isError()
const {
691 return !ui.errorTB->toPlainText().isEmpty();
694 bool isComplete()
const {
700 return KeyCache::instance()->findByFingerprint( fingerprint().toLatin1().constData() );
704 void slotSaveRequestToFile() {
706 QLatin1String(
"imp"), i18n(
"PKCS#10 Requests (*.p10)") );
707 if ( fileName.isEmpty() )
709 if ( !fileName.endsWith( QLatin1String(
".p10" ), Qt::CaseInsensitive ) )
710 fileName += QLatin1String(
".p10");
711 QFile src( QUrl( url() ).toLocalFile() );
712 if ( !src.copy( fileName ) )
713 KMessageBox::error(
this,
715 "Could not copy temporary file <filename>%1</filename> "
716 "to file <filename>%2</filename>: <message>%3</message>",
717 src.fileName(), fileName, src.errorString() ),
718 i18nc(
"@title",
"Error Saving Request") );
720 KMessageBox::information(
this,
722 "<para>Successfully wrote request to <filename>%1</filename>.</para>"
723 "<para>You should now send the request to the Certification Authority (CA).</para>",
725 i18nc(
"@title",
"Request Saved" ) );
728 void slotSendRequestByEMail() {
731 const KConfigGroup config( KGlobal::config(),
"CertificateCreationWizard" );
732 invokeMailer( config.readEntry(
"CAEmailAddress" ),
733 i18n(
"Please process this certificate."),
734 i18n(
"Please process this certificate and inform the sender about the location to fetch the resulting certificate.\n\nThanks,\n"),
735 QUrl( url() ).toLocalFile() );
738 void slotSendCertificateByEMail() {
739 if ( !pgp() || exportCertificateCommand )
742 connect( cmd, SIGNAL(finished()), SLOT(slotSendCertificateByEMailContinuation()) );
743 cmd->
setOpenPGPFileName( tmpDir().absoluteFilePath( fingerprint() + QLatin1String(
".asc") ) );
745 exportCertificateCommand = cmd;
748 void slotSendCertificateByEMailContinuation() {
749 if ( !exportCertificateCommand )
753 kDebug() <<
"fileName" << fileName;
754 exportCertificateCommand = 0;
755 if ( fileName.isEmpty() )
757 invokeMailer( QString(),
758 i18n(
"My new OpenPGP certificate"),
759 i18n(
"Please find attached my new OpenPGP certificate."),
763 QByteArray ol_quote( QByteArray str ) {
765 return "\"\"" + str.replace(
'"',
"\\\"" ) +
"\"\"";
772 void invokeMailer(
const QString & to,
const QString & subject, QString body,
const QString & attachment ) {
773 kDebug() <<
"to:" << to <<
"subject:" << subject
774 <<
"body:" << body <<
"attachment:" << attachment;
779 body.replace( QLatin1Char(
'\n' ), QLatin1String(
"\r\n" ) ).remove( QLatin1String(
"\r\r" ) );
781 QByteArray encoded =
"mailto:?to=" + QUrl::toPercentEncoding( to )
782 +
"&subject=" + QUrl::toPercentEncoding( subject )
783 +
"&body=" + QUrl::toPercentEncoding( body ) ;
784 if ( !attachment.isEmpty() )
785 encoded +=
"&attach=" + ol_quote( QUrl::toPercentEncoding( QFileInfo( attachment ).absoluteFilePath() ) );
786 kDebug() <<
"openUrl" << QUrl::fromEncoded( encoded );
787 QDesktopServices::openUrl( QUrl::fromEncoded( encoded ) );
788 KMessageBox::information(
this,
790 "<para><application>Kleopatra</application> tried to send a mail via your default mail client.</para>"
791 "<para>Some mail clients are known not to support attachments when invoked this way.</para>"
792 "<para>If your mail client does not have an attachment, then drag the <application>Kleopatra</application> icon and drop it on the message compose window of your mail client.</para>"
793 "<para>If that does not work, either, save the request to a file, and then attach that.</para>"),
794 i18nc(
"@title",
"Sending Mail"),
795 QLatin1String(
"newcertificatewizard-mailto-troubles") );
798 void slotUploadCertificateToDirectoryServer() {
803 void slotBackupCertificate() {
808 void slotCreateRevocationRequest() {
812 void slotCreateSigningCertificate() {
813 if ( successfullyCreatedSigningCertificate )
815 toggleSignEncryptAndRestart();
818 void slotCreateEncryptionCertificate() {
819 if ( successfullyCreatedEncryptionCertificate )
821 toggleSignEncryptAndRestart();
825 void toggleSignEncryptAndRestart() {
828 if ( KMessageBox::warningContinueCancel(
831 "This operation will delete the certification request. "
832 "Please make sure that you have sent or saved it before proceeding." ),
833 i18nc(
"@title",
"Certification Request About To Be Deleted") ) != KMessageBox::Continue )
835 const bool sign = signingAllowed();
836 const bool encr = encryptionAllowed();
837 setField( QLatin1String(
"signingAllowed"), !sign );
838 setField( QLatin1String(
"encryptionAllowed"), !encr );
846 bool initialized : 1;
847 bool successfullyCreatedSigningCertificate : 1;
848 bool successfullyCreatedEncryptionCertificate : 1;
849 QPointer<ExportCertificateCommand> exportCertificateCommand;
854 class NewCertificateWizard::Private {
855 friend class ::Kleo::NewCertificateWizard;
856 friend class ::Kleo::NewCertificateUi::WizardPage;
861 tmp( QDir::temp().absoluteFilePath( QLatin1String(
"kleo-") ) ),
864 q->setWindowTitle( i18nc(
"@title",
"Certificate Creation Wizard") );
870 ChooseProtocolPage chooseProtocolPage;
871 EnterDetailsPage enterDetailsPage;
872 OverviewPage overviewPage;
873 KeyCreationPage keyCreationPage;
874 ResultPage resultPage;
877 : chooseProtocolPage( q ),
878 enterDetailsPage( q ),
880 keyCreationPage( q ),
889 q->
setOptions( DisabledBackButtonOnLastPage );
891 q->
setPage( ChooseProtocolPageId, &chooseProtocolPage );
892 q->
setPage( EnterDetailsPageId, &enterDetailsPage );
893 q->
setPage( OverviewPageId, &overviewPage );
894 q->
setPage( KeyCreationPageId, &keyCreationPage );
905 :
QWizard( p ),
d( new Private( this ) )
913 d->ui.chooseProtocolPage.setProtocol( proto );
918 return d->ui.chooseProtocolPage.protocol();
922 if ( attr == QLatin1String(
"NAME") )
924 if ( attr == QLatin1String(
"COMMENT") )
925 return i18n(
"Comment");
926 if ( attr == QLatin1String(
"EMAIL") )
927 return i18n(
"EMail");
932 if ( attr.isEmpty() )
934 const QString label = pgp ?
pgpLabel( attr ) : Kleo::DNAttributeMapper::instance()->name2label( attr ) ;
935 if ( !label.isEmpty() )
939 return i18nc(
"Format string for the labels in the \"Your Personal Data\" page",
940 "%1 (%2)", label, attr );
947 static QString attributeLabelWithColor(
const QString & attr,
bool pgp ) {
949 if ( result.isEmpty() )
957 return key.remove( QLatin1Char(
'!') );
961 QByteArray attrUtf8 = attr.toUtf8();
962 for (
unsigned int i = 0 ; i < numOidMaps ; ++i )
963 if ( qstricmp( attrUtf8, oidmap[i].
name ) == 0 )
964 return oidmap[i].oid;
968 QDir WizardPage::tmpDir()
const {
969 return wizard() ? QDir( wizard()->
d->tmp.name() ) : QDir::home() ;
972 void EnterDetailsPage::registerDialogPropertiesAsFields() {
974 const QMetaObject *
const mo = dialog.metaObject();
975 for (
unsigned int i = mo->propertyOffset(), end = i + mo->propertyCount() ; i != end ; ++i ) {
976 const QMetaProperty mp = mo->property( i );
978 registerField( QLatin1String(mp.name()), &dialog, mp.name(), SIGNAL(accepted()) );
983 void EnterDetailsPage::saveValues() {
984 Q_FOREACH(
const Line & line, lineList )
988 void EnterDetailsPage::clearForm() {
989 qDeleteAll( dynamicWidgets );
990 dynamicWidgets.clear();
996 ui.nameRequiredLB->hide();
1001 ui.emailRequiredLB->hide();
1003 ui.commentLE->hide();
1004 ui.commentLE->clear();
1005 ui.commentLB->hide();
1006 ui.commentRequiredLB->hide();
1008 ui.addEmailToDnCB->hide();
1012 const int idx = l->indexOf( w );
1014 l->getItemPosition( idx, &r, &c, &rs, &cs );
1018 static QLineEdit *
adjust_row( QGridLayout * l,
int row,
const QString & label,
const QString & preset,
QValidator * validator,
bool readonly,
bool required ) {
1021 assert( row < l->rowCount() );
1023 QLabel * lb = qobject_cast<QLabel*>( l->itemAtPosition( row, 0 )->widget() );
1025 QLineEdit * le = qobject_cast<QLineEdit*>( l->itemAtPosition( row, 1 )->widget() );
1027 QLabel * reqLB = qobject_cast<QLabel*>( l->itemAtPosition( row, 2 )->widget() );
1030 lb->setText( i18nc(
"interpunctation for labels",
"%1:", label ) );
1031 le->setText( preset );
1032 reqLB->setText( required ? i18n(
"(required)") : i18n(
"(optional)") );
1033 delete le->validator();
1035 if ( !validator->parent() )
1036 validator->setParent( le );
1037 le->setValidator( validator );
1040 le->setReadOnly( readonly && le->hasAcceptableInput() );
1052 const int row = l->rowCount();
1054 l->addWidget( w1 =
new QLabel( l->parentWidget() ), row, 0 );
1055 l->addWidget( w2 =
new QLineEdit( l->parentWidget() ), row, 1 );
1056 l->addWidget( w3 =
new QLabel( l->parentWidget() ), row, 2 );
1057 wl->push_back( w1 );
1058 wl->push_back( w2 );
1059 wl->push_back( w3 );
1063 void EnterDetailsPage::updateForm() {
1067 const KConfigGroup config( KGlobal::config(),
"CertificateCreationWizard" );
1069 QStringList attrOrder = config.readEntry( pgp() ?
"OpenPGPAttributeOrder" :
"DNAttributeOrder", QStringList() );
1070 if ( attrOrder.empty() ) {
1072 attrOrder << QLatin1String(
"NAME!") << QLatin1String(
"EMAIL!") << QLatin1String(
"COMMENT");
1074 attrOrder << QLatin1String(
"CN!") << QLatin1String(
"L") << QLatin1String(
"OU") << QLatin1String(
"O!") << QLatin1String(
"C!") << QLatin1String(
"EMAIL!");
1078 widgets.push_back( ui.nameLE );
1079 widgets.push_back( ui.emailLE );
1080 widgets.push_back( ui.commentLE );
1084 Q_FOREACH(
const QString & rawKey, attrOrder ) {
1085 const QString key = rawKey.trimmed().toUpper();
1087 if ( attr.isEmpty() )
1089 const QString preset = savedValues.value( attr, config.readEntry( attr, QString() ) );
1090 const bool required = key.endsWith( QLatin1Char(
'!') );
1091 const bool readonly = config.isEntryImmutable( attr );
1092 const QString label = config.readEntry( attr + QLatin1String(
"_label"),
1094 const QString regex = config.readEntry( attr + QLatin1String(
"_regex") );
1099 if ( attr == QLatin1String(
"EMAIL") ) {
1103 ui.addEmailToDnCB->show();
1104 }
else if ( attr == QLatin1String(
"NAME") || attr == QLatin1String(
"CN") ) {
1105 if ( ( pgp() && attr == QLatin1String(
"CN") ) || ( !pgp() && attr == QLatin1String(
"NAME") ) )
1110 }
else if ( attr == QLatin1String(
"COMMENT") ) {
1117 row =
add_row( ui.gridLayout, &dynamicWidgets );
1119 if ( !validator && !regex.isEmpty() )
1120 validator =
new QRegExpValidator( QRegExp( regex ), 0 );
1122 QLineEdit * le =
adjust_row( ui.gridLayout, row, label, preset, validator, readonly, required );
1124 const Line line = { key, label, regex, le };
1128 widgets.push_back( le );
1131 disconnect( le, SIGNAL(textChanged(QString)),
1132 this, SLOT(slotUpdateResultLabel()) );
1133 connect( le, SIGNAL(textChanged(QString)),
1134 this, SLOT(slotUpdateResultLabel()) );
1139 lineList = kdtools::copy< QVector<Line> >( lines );
1141 widgets.push_back( ui.resultLE );
1142 widgets.push_back( ui.addEmailToDnCB );
1143 widgets.push_back( ui.advancedPB );
1148 QString EnterDetailsPage::cmsDN()
const {
1150 for ( QVector<Line>::const_iterator it = lineList.begin(), end = lineList.end() ; it != end ; ++it ) {
1151 const QString text = it->edit->text().trimmed();
1152 if ( text.isEmpty() )
1155 if ( attr == QLatin1String(
"EMAIL") && !ui.addEmailToDnCB->isChecked() )
1158 attr = QString::fromUtf8( oid );
1159 dn.append( DN::Attribute( attr, text ) );
1164 QString EnterDetailsPage::pgpUserID()
const {
1166 ui.nameLE->text().trimmed(),
1167 ui.emailLE->text().trimmed(),
1168 ui.commentLE->text().trimmed() );
1172 QString text = le->text();
1173 int pos = le->cursorPosition();
1174 const QValidator *
const v = le->validator();
1175 return v && v->validate( text, pos ) == QValidator::Intermediate ;
1179 Q_FOREACH(
const Line & line, list ) {
1180 const QLineEdit * le = line.edit;
1183 const QString key = line.attr;
1184 kDebug() <<
"requirementsAreMet(): checking \"" << key <<
"\" against \"" << le->text() <<
"\":";
1185 if ( le->text().trimmed().isEmpty() ) {
1186 if ( key.endsWith(QLatin1Char(
'!')) ) {
1187 if ( line.regex.isEmpty() )
1188 error = i18nc(
"@info",
"<interface>%1</interface> is required, but empty.", line.label );
1190 error = i18nc(
"@info",
"<interface>%1</interface> is required, but empty.<nl/>"
1191 "Local Admin rule: <icode>%2</icode>", line.label, line.regex );
1195 if ( line.regex.isEmpty() )
1196 error = i18nc(
"@info",
"<interface>%1</interface> is incomplete.", line.label );
1198 error = i18nc(
"@info",
"<interface>%1</interface> is incomplete.<nl/>"
1199 "Local Admin rule: <icode>%2</icode>", line.label, line.regex );
1201 }
else if ( !le->hasAcceptableInput() ) {
1202 if ( line.regex.isEmpty() )
1203 error = i18nc(
"@info",
"<interface>%1</interface> is invalid.", line.label );
1205 error = i18nc(
"@info",
"<interface>%1</interface> is invalid.<nl/>"
1206 "Local Admin rule: <icode>%2</icode>", line.label, line.regex );
1209 kDebug() <<
"ok" << endl;
1214 bool EnterDetailsPage::isComplete()
const {
1217 ui.errorLB->setText( error );
1221 void EnterDetailsPage::slotAdvancedSettingsClicked() {
1225 QStringList KeyCreationPage::keyUsages()
const {
1227 if ( signingAllowed() )
1228 usages << QLatin1String(
"sign");
1229 if ( encryptionAllowed() && !
is_dsa( keyType() ) )
1230 usages << QLatin1String(
"encrypt");
1232 if ( certificationAllowed() )
1233 usages << QLatin1String(
"certify");
1234 if ( authenticationAllowed() )
1235 usages << QLatin1String(
"auth");
1239 QStringList OverviewPage::i18nKeyUsages()
const {
1241 if ( signingAllowed() )
1242 usages << i18n(
"Sign");
1243 if ( encryptionAllowed() && !
is_dsa( keyType() ) )
1244 usages << i18n(
"Encrypt");
1246 if ( certificationAllowed() )
1247 usages << i18n(
"Certify");
1248 if ( authenticationAllowed() )
1249 usages << i18n(
"Authenticate");
1253 QStringList KeyCreationPage::subkeyUsages()
const {
1255 if ( encryptionAllowed() &&
is_dsa( keyType() ) ) {
1256 assert( subkeyType() );
1257 assert(
is_elg( subkeyType() ) );
1258 usages << QLatin1String(
"encrypt");
1263 QStringList OverviewPage::i18nSubkeyUsages()
const {
1265 if ( encryptionAllowed() &&
is_dsa( keyType() ) ) {
1266 assert( subkeyType() );
1267 assert(
is_elg( subkeyType() ) );
1268 usages << i18n(
"Encrypt");
1273 QStringList OverviewPage::i18nCombinedKeyUsages()
const {
1274 return i18nSubkeyUsages() + i18nKeyUsages();
1278 template <
typename T=QString>
1283 Row(
const QString & k,
const T & v ) : key( k ), value( v ) {}
1285 template <
typename T>
1286 QTextStream & operator<<( QTextStream & s, const Row<T> & row ) {
1287 if ( row.key.isEmpty() )
1290 return s <<
"<tr><td>" << row.key <<
"</td><td>" << row.value <<
"</td></tr>";
1294 QString OverviewPage::i18nFormatGnupgKeyParms(
bool details )
const {
1296 QTextStream s( &result );
1299 s << Row< >( i18n(
"Name:"),
name() );
1300 s << Row< >( i18n(
"Email Address:"),
email() );
1302 if ( !comment().isEmpty() )
1303 s << Row< >( i18n(
"Comment:"), comment() );
1305 s << Row< >( i18n(
"Subject-DN:"), DN( dn() ).dn( QLatin1String(
",<br>") ) );
1308 s << Row< >( i18n(
"Key Type:"), QLatin1String(gpgme_pubkey_algo_name( static_cast<gpgme_pubkey_algo_t>( keyType() ) )) );
1309 if (
const unsigned int strength = keyStrength() )
1310 s << Row< >( i18n(
"Key Strength:"), i18np(
"1 bit",
"%1 bits", strength ) );
1312 s << Row< >( i18n(
"Key Strength:"), i18n(
"default") );
1313 s << Row< >( i18n(
"Certificate Usage:"), i18nCombinedKeyUsages().join(i18nc(
"separator for key usages",
", ")) );
1314 if (
const unsigned int subkey = subkeyType() ) {
1315 s << Row< >( i18n(
"Subkey Type:"), QLatin1String(gpgme_pubkey_algo_name( static_cast<gpgme_pubkey_algo_t>( subkey ) )) );
1316 if (
const unsigned int strength = subkeyStrength() )
1317 s << Row< >( i18n(
"Subkey Strength:"), i18np(
"1 bit",
"%1 bits", strength ) );
1319 s << Row< >( i18n(
"Subkey Strength:"), i18n(
"default") );
1320 s << Row< >( i18n(
"Subkey Usage:"), i18nSubkeyUsages().join(i18nc(
"separator for key usages",
", ")) );
1323 if ( pgp() && details && expiryDate().isValid() )
1324 s << Row< >( i18n(
"Valid Until:"), KGlobal::locale()->formatDate( expiryDate() ) );
1325 if ( !pgp() && details ) {
1326 Q_FOREACH(
const QString &
email, additionalEMailAddresses() )
1327 s << Row< >( i18n("Add. Email Address:"),email );
1328 Q_FOREACH( const QString & dns, dnsNames() )
1329 s << Row< >( i18n("DNS Name:"), dns );
1330 Q_FOREACH( const QString & uri, uris() )
1331 s << Row< >( i18n("URI:"), uri );
1337 return QString::fromLatin1( QUrl::toAce( dns ) );
1341 const int at = email.lastIndexOf( QLatin1Char(
'@') );
1344 return email.left( at + 1 ) +
encode_dns( email.mid( at + 1 ) );
1347 QString KeyCreationPage::createGnupgKeyParms()
const {
1349 QTextStream s( &result );
1350 s <<
"<GnupgKeyParms format=\"internal\">" << endl;
1352 s <<
"%ask-passphrase" << endl;
1353 s <<
"key-type: " << gpgme_pubkey_algo_name( static_cast<gpgme_pubkey_algo_t>( keyType() ) ) << endl;
1354 if (
const unsigned int strength = keyStrength() )
1355 s <<
"key-length: " << strength << endl;
1356 s <<
"key-usage: " << keyUsages().join(QLatin1String(
" ")) << endl;
1357 if (
const unsigned int subkey = subkeyType() ) {
1358 s <<
"subkey-type: " << gpgme_pubkey_algo_name( static_cast<gpgme_pubkey_algo_t>( subkey ) ) << endl;
1359 if (
const unsigned int strength = subkeyStrength() )
1360 s <<
"subkey-length: " << strength << endl;
1361 s <<
"subkey-usage: " << subkeyUsages().join(QLatin1String(
" ")) << endl;
1363 if ( pgp() && expiryDate().isValid() )
1364 s <<
"expire-date: " << expiryDate().toString( Qt::ISODate ) << endl;
1367 s <<
"name-real: " <<
name() << endl;
1368 if ( !comment().isEmpty() )
1369 s <<
"name-comment: " << comment() << endl;
1371 s <<
"name-dn: " << dn() << endl;
1372 Q_FOREACH(
const QString & email, additionalEMailAddresses() )
1374 Q_FOREACH( const QString & dns, dnsNames() )
1376 Q_FOREACH( const QString & uri, uris() )
1377 s << "
name-uri: " << uri << endl;
1379 s << "</GnupgKeyParms>" << endl;
1380 kDebug() << '\n' << result;
1386 for (
int i = 0, end = sizes.size() ; i != end ; ++i ) {
1387 cb.addItem( i < labels.size() && !labels[i].trimmed().isEmpty()
1389 ? i18ncp(
"%2: some admin-supplied text, %1: key size in bits",
"%2 (1 bit; default)",
"%2 (%1 bits; default)", -sizes[i], labels[i].trimmed() )
1390 : i18ncp(
"%2: some admin-supplied text, %1: key size in bits",
"%2 (1 bit)",
"%2 (%1 bits)", sizes[i], labels[i].trimmed() )
1392 ? i18ncp(
"%1: key size in bits",
"1 bit (default)",
"%1 bits (default)", -sizes[i] )
1393 : i18ncp(
"%1: key size in bits",
"1 bit",
"%1 bits", sizes[i] ),
1394 std::abs( sizes[i] ) );
1396 cb.setCurrentIndex( cb.count() - 1 );
1400 void AdvancedSettingsDialog::fillKeySizeComboBoxen() {
1402 const KConfigGroup config( KGlobal::config(),
"CertificateCreationWizard" );
1412 fill_combobox( *ui.rsaKeyStrengthCB, rsaKeySizes, rsaKeySizeLabels );
1413 fill_combobox( *ui.dsaKeyStrengthCB, dsaKeySizes, dsaKeySizeLabels );
1414 fill_combobox( *ui.elgKeyStrengthCB, elgKeySizes, elgKeySizeLabels );
1418 void AdvancedSettingsDialog::loadDefaultKeyType() {
1420 if ( protocol != CMS && protocol !=
OpenPGP )
1423 const KConfigGroup config( KGlobal::config(),
"CertificateCreationWizard" );
1426 const QString keyType = config.readEntry( entry ).trimmed().toUpper();
1428 if ( protocol ==
OpenPGP && keyType == QLatin1String(
"DSA") ) {
1429 setKeyType( GPGME_PK_DSA );
1431 }
else if ( protocol ==
OpenPGP && keyType == QLatin1String(
"DSA+ELG") ) {
1432 setKeyType( GPGME_PK_DSA );
1433 setSubkeyType( GPGME_PK_ELG_E );
1435 if ( !keyType.isEmpty() && keyType != QLatin1String(
"RSA") )
1436 kWarning() <<
"invalid value \"" << qPrintable( keyType )
1437 <<
"\" for entry \"[CertificateCreationWizard]"
1438 << qPrintable( entry ) <<
"\"";
1439 setKeyType( GPGME_PK_RSA );
1443 keyTypeImmutable = config.isEntryImmutable( entry );
1444 updateWidgetVisibility();
1447 void AdvancedSettingsDialog::updateWidgetVisibility() {
1450 if ( ui.tabWidget->indexOf( ui.personalTab ) != -1 )
1451 ui.tabWidget->removeTab( ui.tabWidget->indexOf( ui.personalTab ) );
1453 if ( ui.tabWidget->indexOf( ui.personalTab ) == -1 )
1454 ui.tabWidget->addTab( ui.personalTab, tr2i18n(
"Personal Details", 0 ) );
1456 ui.uidGB->setVisible( protocol ==
OpenPGP );
1457 ui.uidGB->setEnabled(
false );
1458 ui.uidGB->setToolTip( i18nc(
"@info:tooltip",
"Adding more than one User ID is not yet implemented.") );
1459 ui.emailGB->setVisible( protocol == CMS );
1460 ui.dnsGB->setVisible( protocol == CMS );
1461 ui.uriGB->setVisible( protocol == CMS );
1463 if ( keyTypeImmutable ) {
1464 ui.rsaRB->setEnabled(
false );
1465 ui.dsaRB->setEnabled(
false );
1466 ui.elgCB->setEnabled(
false );
1468 ui.rsaRB->setEnabled(
true );
1469 ui.dsaRB->setEnabled( protocol ==
OpenPGP );
1470 ui.elgCB->setEnabled( protocol ==
OpenPGP );
1472 ui.certificationCB->setVisible( protocol ==
OpenPGP );
1473 ui.authenticationCB->setVisible( protocol ==
OpenPGP );
1475 ui.certificationCB->setChecked(
true );
1476 ui.certificationCB->setEnabled(
false );
1478 if ( protocol == CMS ) {
1479 ui.encryptionCB->setEnabled(
true );
1481 ui.expiryDE->setVisible( protocol ==
OpenPGP );
1482 ui.expiryCB->setVisible( protocol ==
OpenPGP );
1483 slotKeyMaterialSelectionChanged();
1486 #include "moc_newcertificatewizard.cpp"
1487 #include "newcertificatewizard.moc"
QString openPGPFileName() const
static const char CMS_KEY_TYPE_ENTRY[]
QValidator * email(QObject *parent=0)
static void set_tab_order(const QList< QWidget * > &wl)
static void set_keysize(QComboBox *cb, unsigned int strength)
The QWizardPage class is the base class for wizard pages.
static std::string email(const UserID &uid)
static const char PGP_KEY_TYPE_ENTRY[]
#define FIELD(type, name)
static const char DSA_KEYSIZE_LABELS_ENTRY[]
static int add_row(QGridLayout *l, QList< QWidget * > *wl)
static const char * oidForAttributeName(const QString &attr)
static int row_index_of(QWidget *w, QGridLayout *l)
GpgME::Protocol protocol() const
NewCertificateWizard(QWidget *parent=0)
static bool is_elg(unsigned int algo)
QAbstractButton * button(WizardButton which) const
static bool is_dsa(unsigned int algo)
void setProtocol(GpgME::Protocol protocol)
static bool requirementsAreMet(const QVector< Line > &list, QString &error)
static QLineEdit * adjust_row(QGridLayout *l, int row, const QString &label, const QString &preset, QValidator *validator, bool readonly, bool required)
static void fill_combobox(QComboBox &cb, const QList< int > &sizes, const QStringList &labels)
QValidator * pgpComment(QObject *parent=0)
static const char ELG_KEYSIZE_LABELS_ENTRY[]
static unsigned int get_keysize(const QComboBox *cb)
static const char DSA_KEYSIZES_ENTRY[]
static bool is_algo(gpgme_pubkey_algo_t algo, KeyAlgo what)
static const char RSA_KEYSIZES_ENTRY[]
QString getSaveFileName(QWidget *parent=0, const QString &caption=QString(), const QString &dirID=QString(), const QString &filter=QString())
void setOpenPGPFileName(const QString &fileName)
static QString encode_dns(const QString &dns)
void setOptions(WizardOptions options)
static QString encode_email(const QString &email)
static boost::shared_ptr< const KeyCache > instance()
static QString attributeFromKey(QString key)
QValidator * pgpName(QObject *parent=0)
static QString pgpLabel(const QString &attr)
static bool has_intermediate_input(const QLineEdit *le)
static bool is_rsa(unsigned int algo)
static const char RSA_KEYSIZE_LABELS_ENTRY[]
static void force_set_checked(QAbstractButton *b, bool on)
void setPage(int id, QWizardPage *page)
The QWizard class provides a framework for wizards.
static QString attributeLabel(const QString &attr, bool pgp)
static const char ELG_KEYSIZES_ENTRY[]