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> 
   57#include <tdeapplication.h> 
   60#include <kurlrequester.h> 
   61#include <kdcopservicestarter.h> 
   62#include <dcopclient.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> 
   79static const unsigned int keyLengths[] = {
 
   80  1024, 1532, 2048, 3072, 4096
 
   82static const unsigned int numKeyLengths = 
sizeof keyLengths / 
sizeof *keyLengths;
 
   84static 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 + 
':';
 
  102static TQString attributeFromKey( TQString key ) {
 
  103  return key.remove( 
'!' );
 
  106static bool availForMod( 
const TQLineEdit * le ) {
 
  107  return le && le->isEnabled();
 
  117CertificateWizardImpl::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] ) );
 
  144static 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;
 
  169void CertificateWizardImpl::slotEnablePersonalDataPageExit() {
 
  170  setNextEnabled( personalDataPage, requirementsAreMet( _attrPairList ) );
 
  177CertificateWizardImpl::~CertificateWizardImpl()
 
  182static 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;
 
  193void 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 );
 
  268void 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 );
 
  291void CertificateWizardImpl::slotHelpClicked()
 
  293  tdeApp->invokeHelp( 
"newcert" );
 
  296void 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() ); 
 
  335void 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();
 
  379bool CertificateWizardImpl::sendToCA()
 const {
 
  380  return sendToCARB->isChecked();
 
  383TQString CertificateWizardImpl::caEMailAddress()
 const {
 
  384  return caEmailED->text().stripWhiteSpace();
 
  387void 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() );
 
  401KURL CertificateWizardImpl::saveFileUrl()
 const {
 
  402  return KURL::fromPathOrURL( storeUR->url().stripWhiteSpace() );
 
  405void 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();
 
  423static const char* 
const dcopObjectId = 
"KMailIface";
 
  427void 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 ( !tdeApp->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( tdeApp->dcopClient()->findObject( dcopService, dcopObjectId, 
"", TQByteArray(), dummy, dummy ) );
 
  450      kdWarning() << 
"Error loading " << dcopService << endl;
 
  453  DCOPClient* dcopClient = tdeApp->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();
 
  471void 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 );
 
  504void CertificateWizardImpl::slotUploadResult( TDEIO::Job* job )
 
  506  if ( job->error() ) {
 
  507    job->showErrorDialog();
 
  508    setFinishEnabled( finishPage, 
true );
 
  511    CertificateWizard::accept();
 
  515#include "certificatewizardimpl.moc"