kaddressbook

vcard_xxport.cpp

00001 /*
00002     This file is part of KAddressbook.
00003     Copyright (c) 2003 Tobias Koenig <tokoe@kde.org>
00004 
00005     This program is free software; you can redistribute it and/or modify
00006     it under the terms of the GNU General Public License as published by
00007     the Free Software Foundation; either version 2 of the License, or
00008     (at your option) any later version.
00009 
00010     This program is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00013     GNU General Public License for more details.
00014 
00015     You should have received a copy of the GNU General Public License
00016     along with this program; if not, write to the Free Software
00017     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00018 
00019     As a special exception, permission is given to link this program
00020     with any edition of Qt, and distribute the resulting executable,
00021     without including the source code for Qt in the source distribution.
00022 */
00023 
00024 #include <tqcheckbox.h>
00025 #include <tqfile.h>
00026 #include <tqfont.h>
00027 #include <tqlabel.h>
00028 #include <tqlayout.h>
00029 #include <tqpushbutton.h>
00030 
00031 #include <kabc/vcardconverter.h>
00032 #include <kdialogbase.h>
00033 #include <kfiledialog.h>
00034 #include <kio/netaccess.h>
00035 #include <klocale.h>
00036 #include <kmessagebox.h>
00037 #include <ktempfile.h>
00038 #include <kurl.h>
00039 #include <kapplication.h>
00040 #include <libkdepim/addresseeview.h>
00041 
00042 #include "config.h" // ??
00043 
00044 #include "gpgmepp/context.h"
00045 #include "gpgmepp/data.h"
00046 #include "gpgmepp/key.h"
00047 #include "qgpgme/dataprovider.h"
00048 
00049 #include "xxportmanager.h"
00050 
00051 #include "vcard_xxport.h"
00052 
00053 K_EXPORT_KADDRESSBOOK_XXFILTER( libkaddrbk_vcard_xxport, VCardXXPort )
00054 
00055 class VCardViewerDialog : public KDialogBase
00056 {
00057   public:
00058     VCardViewerDialog( const KABC::Addressee::List &list,
00059                        TQWidget *parent, const char *name = 0 );
00060 
00061     KABC::Addressee::List contacts() const;
00062 
00063   protected:
00064     void slotUser1();
00065     void slotUser2();
00066     void slotApply();
00067     void slotCancel();
00068 
00069   private:
00070     void updateView();
00071 
00072     KPIM::AddresseeView *mView;
00073 
00074     KABC::Addressee::List mContacts;
00075     KABC::Addressee::List::Iterator mIt;
00076 };
00077 
00078 class VCardExportSelectionDialog : public KDialogBase
00079 {
00080   public:
00081     VCardExportSelectionDialog( TQWidget *parent, const char *name = 0 );
00082     ~VCardExportSelectionDialog();
00083 
00084     bool exportPrivateFields() const;
00085     bool exportBusinessFields() const;
00086     bool exportOtherFields() const;
00087     bool exportEncryptionKeys() const;
00088 
00089   private:
00090     TQCheckBox *mPrivateBox;
00091     TQCheckBox *mBusinessBox;
00092     TQCheckBox *mOtherBox;
00093     TQCheckBox *mEncryptionKeys;
00094 };
00095 
00096 VCardXXPort::VCardXXPort( KABC::AddressBook *ab, TQWidget *parent, const char *name )
00097   : KAB::XXPort( ab, parent, name )
00098 {
00099   createImportAction( i18n( "Import vCard..." ) );
00100   createExportAction( i18n( "Export vCard 2.1..." ), "v21" );
00101   createExportAction( i18n( "Export vCard 3.0..." ), "v30" );
00102 }
00103 
00104 bool VCardXXPort::exportContacts( const KABC::AddresseeList &addrList, const TQString &data )
00105 {
00106   KABC::VCardConverter converter;
00107   KURL url;
00108   KABC::AddresseeList list;
00109 
00110   list = filterContacts( addrList );
00111 
00112   bool ok = true;
00113   if ( list.isEmpty() ) {
00114     return ok;
00115   } else if ( list.count() == 1 ) {
00116     url = KFileDialog::getSaveURL( list[ 0 ].givenName() + "_" + list[ 0 ].familyName() + ".vcf" );
00117     if ( url.isEmpty() )
00118       return true;
00119 
00120     if ( data == "v21" )
00121 #if defined(KABC_VCARD_ENCODING_FIX)
00122       ok = doExport( url, converter.createVCardsRaw( list, KABC::VCardConverter::v2_1 ) );
00123     else
00124       ok = doExport( url, converter.createVCardsRaw( list, KABC::VCardConverter::v3_0 ) );
00125 #else
00126       ok = doExport( url, converter.createVCards( list, KABC::VCardConverter::v2_1 ) );
00127     else
00128       ok = doExport( url, converter.createVCards( list, KABC::VCardConverter::v3_0 ) );
00129 #endif
00130   } else {
00131     TQString msg = i18n( "You have selected a list of contacts, shall they be "
00132                         "exported to several files?" );
00133 
00134     switch ( KMessageBox::questionYesNo( parentWidget(), msg, TQString::null, i18n("Export to Several Files"), i18n("Export to One File") ) ) {
00135       case KMessageBox::Yes: {
00136         KURL baseUrl = KFileDialog::getExistingURL();
00137         if ( baseUrl.isEmpty() )
00138           return true;
00139 
00140         KABC::AddresseeList::ConstIterator it;
00141         uint counter = 0;
00142         for ( it = list.begin(); it != list.end(); ++it ) {
00143           TQString testUrl;
00144           if ( (*it).givenName().isEmpty() && (*it).familyName().isEmpty() )
00145             testUrl = baseUrl.url() + "/" + (*it).organization();
00146           else
00147             testUrl = baseUrl.url() + "/" + (*it).givenName() + "_" + (*it).familyName();
00148 
00149           if ( KIO::NetAccess::exists( testUrl + (counter == 0 ? "" : TQString::number( counter )) + ".vcf", false, parentWidget() ) ) {
00150             counter++;
00151             url = testUrl + TQString::number( counter ) + ".vcf";
00152           } else
00153             url = testUrl + ".vcf";
00154 
00155           bool tmpOk;
00156           KABC::AddresseeList tmpList;
00157           tmpList.append( *it );
00158 
00159           if ( data == "v21" )
00160 #if defined(KABC_VCARD_ENCODING_FIX)
00161             tmpOk = doExport( url, converter.createVCardsRaw( tmpList, KABC::VCardConverter::v2_1 ) );
00162           else
00163             tmpOk = doExport( url, converter.createVCardsRaw( tmpList, KABC::VCardConverter::v3_0 ) );
00164 #else
00165             tmpOk = doExport( url, converter.createVCards( tmpList, KABC::VCardConverter::v2_1 ) );
00166           else
00167             tmpOk = doExport( url, converter.createVCards( tmpList, KABC::VCardConverter::v3_0 ) );
00168 #endif
00169           ok = ok && tmpOk;
00170         }
00171         break;
00172       }
00173       case KMessageBox::No:
00174       default: {
00175         url = KFileDialog::getSaveURL( "addressbook.vcf" );
00176         if ( url.isEmpty() )
00177           return true;
00178 
00179         if ( data == "v21" )
00180 #if defined(KABC_VCARD_ENCODING_FIX)
00181           ok = doExport( url, converter.createVCardsRaw( list, KABC::VCardConverter::v2_1 ) );
00182         else
00183           ok = doExport( url, converter.createVCardsRaw( list, KABC::VCardConverter::v3_0 ) );
00184 #else
00185           ok = doExport( url, converter.createVCards( list, KABC::VCardConverter::v2_1 ) );
00186         else
00187           ok = doExport( url, converter.createVCards( list, KABC::VCardConverter::v3_0 ) );
00188 #endif
00189       }
00190     }
00191   }
00192 
00193   return ok;
00194 }
00195 
00196 KABC::AddresseeList VCardXXPort::importContacts( const TQString& ) const
00197 {
00198   TQString fileName;
00199   KABC::AddresseeList addrList;
00200   KURL::List urls;
00201 
00202   if ( !XXPortManager::importData.isEmpty() ) {
00203 #if defined(KABC_VCARD_ENCODING_FIX)
00204     TQCString data = XXPortManager::importData.ascii();
00205     addrList = parseVCard( data );
00206 #else
00207     addrList = parseVCard( XXPortManager::importData );
00208 #endif
00209   } else {
00210     if ( XXPortManager::importURL.isEmpty() )
00211       urls = KFileDialog::getOpenURLs( TQString::null, "*.vcf|vCards", parentWidget(),
00212                                        i18n( "Select vCard to Import" ) );
00213     else
00214       urls.append( XXPortManager::importURL );
00215 
00216     if ( urls.count() == 0 )
00217       return addrList;
00218 
00219     TQString caption( i18n( "vCard Import Failed" ) );
00220     bool anyFailures = false;
00221     KURL::List::Iterator it;
00222     for ( it = urls.begin(); it != urls.end(); ++it ) {
00223       if ( KIO::NetAccess::download( *it, fileName, parentWidget() ) ) {
00224 
00225         TQFile file( fileName );
00226 
00227         if ( file.open( IO_ReadOnly ) ) {
00228 #if defined(KABC_VCARD_ENCODING_FIX)
00229           TQByteArray data = file.readAll();
00230           file.close();
00231           if ( data.size() > 0 )
00232             addrList += parseVCard( data );
00233 #else
00234           TQByteArray rawData = file.readAll();
00235           file.close();
00236           if ( rawData.size() > 0 ) {
00237 
00238             TQString vCardText;
00239 
00240             // With version 3.0, vCards are encoded with UTF-8 by default. Otherwise, use fromLatin1()
00241             // and hope that are fields are encoded correctly.
00242             if ( TQString::fromLatin1( rawData ).lower().contains( "version:3.0" ) ) {
00243               vCardText = TQString::fromUtf8( rawData );
00244             } else {
00245               vCardText = TQString::fromLatin1( rawData );
00246             }
00247             addrList += parseVCard( vCardText );
00248           }
00249 #endif
00250           KIO::NetAccess::removeTempFile( fileName );
00251         } else {
00252           TQString text = i18n( "<qt>When trying to read the vCard, there was an error opening the file '%1': %2</qt>" );
00253           text = text.arg( (*it).url() );
00254           text = text.arg( kapp->translate( "TQFile",
00255                                             file.errorString().latin1() ) );
00256           KMessageBox::error( parentWidget(), text, caption );
00257           anyFailures = true;
00258         }
00259       } else {
00260         TQString text = i18n( "<qt>Unable to access vCard: %1</qt>" );
00261         text = text.arg( KIO::NetAccess::lastErrorString() );
00262         KMessageBox::error( parentWidget(), text, caption );
00263         anyFailures = true;
00264       }
00265     }
00266 
00267     if ( !XXPortManager::importURL.isEmpty() ) { // a vcard was passed via cmd
00268       if ( addrList.isEmpty() ) {
00269         if ( anyFailures && urls.count() > 1 )
00270           KMessageBox::information( parentWidget(),
00271                                     i18n( "No contacts were imported, due to errors with the vCards." ) );
00272         else if ( !anyFailures )
00273           KMessageBox::information( parentWidget(), i18n( "The vCard does not contain any contacts." ) );
00274       } else {
00275         VCardViewerDialog dlg( addrList, parentWidget() );
00276         dlg.exec();
00277         addrList = dlg.contacts();
00278       }
00279     }
00280   }
00281 
00282   return addrList;
00283 }
00284 
00285 #if defined(KABC_VCARD_ENCODING_FIX)
00286 KABC::AddresseeList VCardXXPort::parseVCard( const TQByteArray &data ) const
00287 {
00288   KABC::VCardConverter converter;
00289 
00290   return converter.parseVCardsRaw( data.data() );
00291 }
00292 
00293 bool VCardXXPort::doExport( const KURL &url, const TQByteArray &data )
00294 {
00295   if( TQFileInfo(url.path()).exists() ) {
00296     if(KMessageBox::questionYesNo( parentWidget(), i18n("Do you want to overwrite file \"%1\"").arg( url.path()) ) == KMessageBox::No)
00297       return false;
00298   }
00299   KTempFile tmpFile;
00300   tmpFile.setAutoDelete( true );
00301 
00302   tmpFile.file()->writeBlock( data.data(), data.size() );
00303   tmpFile.close();
00304 
00305   return KIO::NetAccess::upload( tmpFile.name(), url, parentWidget() );
00306 }
00307 #else
00308 KABC::AddresseeList VCardXXPort::parseVCard( const TQString &data ) const
00309 {
00310   KABC::VCardConverter converter;
00311 
00312   return converter.parseVCards( data );
00313 }
00314 
00315 bool VCardXXPort::doExport( const KURL &url, const TQString &data )
00316 {
00317   if( TQFileInfo(url.path()).exists() ) {
00318     if(KMessageBox::questionYesNo( parentWidget(), i18n("Do you want to overwrite file \"%1\"").arg( url.path()) ) == KMessageBox::No)
00319       return false;
00320   }
00321   KTempFile tmpFile;
00322   tmpFile.setAutoDelete( true );
00323 
00324   TQTextStream stream( tmpFile.file() );
00325   stream.setEncoding( TQTextStream::UnicodeUTF8 );
00326 
00327   stream << data;
00328   tmpFile.close();
00329 
00330   return KIO::NetAccess::upload( tmpFile.name(), url, parentWidget() );
00331 }
00332 #endif
00333 
00334 KABC::AddresseeList VCardXXPort::filterContacts( const KABC::AddresseeList &addrList )
00335 {
00336   KABC::AddresseeList list;
00337 
00338   if ( addrList.isEmpty() )
00339     return addrList;
00340 
00341   VCardExportSelectionDialog dlg( parentWidget() );
00342   if ( !dlg.exec() )
00343     return list;
00344 
00345   KABC::AddresseeList::ConstIterator it;
00346   for ( it = addrList.begin(); it != addrList.end(); ++it ) {
00347     KABC::Addressee addr;
00348 
00349     addr.setUid( (*it).uid() );
00350     addr.setFormattedName( (*it).formattedName() );
00351     addr.setPrefix( (*it).prefix() );
00352     addr.setGivenName( (*it).givenName() );
00353     addr.setAdditionalName( (*it).additionalName() );
00354     addr.setFamilyName( (*it).familyName() );
00355     addr.setSuffix( (*it).suffix() );
00356     addr.setNickName( (*it).nickName() );
00357     addr.setMailer( (*it).mailer() );
00358     addr.setTimeZone( (*it).timeZone() );
00359     addr.setGeo( (*it).geo() );
00360     addr.setProductId( (*it).productId() );
00361     addr.setSortString( (*it).sortString() );
00362     addr.setUrl( (*it).url() );
00363     addr.setSecrecy( (*it).secrecy() );
00364     addr.setSound( (*it).sound() );
00365     addr.setEmails( (*it).emails() );
00366     addr.setCategories( (*it).categories() );
00367 
00368     if ( dlg.exportPrivateFields() ) {
00369       addr.setBirthday( (*it).birthday() );
00370       addr.setNote( (*it).note() );
00371       addr.setPhoto( (*it).photo() );
00372     }
00373 
00374     if ( dlg.exportBusinessFields() ) {
00375       addr.setTitle( (*it).title() );
00376       addr.setRole( (*it).role() );
00377       addr.setOrganization( (*it).organization() );
00378 
00379       addr.setLogo( (*it).logo() );
00380 
00381       KABC::PhoneNumber::List phones = (*it).phoneNumbers( KABC::PhoneNumber::Work );
00382       KABC::PhoneNumber::List::Iterator phoneIt;
00383       for ( phoneIt = phones.begin(); phoneIt != phones.end(); ++phoneIt )
00384         addr.insertPhoneNumber( *phoneIt );
00385 
00386       KABC::Address::List addresses = (*it).addresses( KABC::Address::Work );
00387       KABC::Address::List::Iterator addrIt;
00388       for ( addrIt = addresses.begin(); addrIt != addresses.end(); ++addrIt )
00389         addr.insertAddress( *addrIt );
00390     }
00391 
00392     KABC::PhoneNumber::List phones = (*it).phoneNumbers();
00393     KABC::PhoneNumber::List::Iterator phoneIt;
00394     for ( phoneIt = phones.begin(); phoneIt != phones.end(); ++phoneIt ) {
00395       int type = (*phoneIt).type();
00396 
00397       if ( type & KABC::PhoneNumber::Home && dlg.exportPrivateFields() )
00398         addr.insertPhoneNumber( *phoneIt );
00399       else if ( type & KABC::PhoneNumber::Work && dlg.exportBusinessFields() )
00400         addr.insertPhoneNumber( *phoneIt );
00401       else if ( dlg.exportOtherFields() )
00402         addr.insertPhoneNumber( *phoneIt );
00403     }
00404 
00405     KABC::Address::List addresses = (*it).addresses();
00406     KABC::Address::List::Iterator addrIt;
00407     for ( addrIt = addresses.begin(); addrIt != addresses.end(); ++addrIt ) {
00408       int type = (*addrIt).type();
00409 
00410       if ( type & KABC::Address::Home && dlg.exportPrivateFields() )
00411         addr.insertAddress( *addrIt );
00412       else if ( type & KABC::Address::Work && dlg.exportBusinessFields() )
00413         addr.insertAddress( *addrIt );
00414       else if ( dlg.exportOtherFields() )
00415         addr.insertAddress( *addrIt );
00416     }
00417 
00418     if ( dlg.exportOtherFields() )
00419       addr.setCustoms( (*it).customs() );
00420 
00421     if ( dlg.exportEncryptionKeys() ) {
00422       addKey( addr, KABC::Key::PGP );
00423       addKey( addr, KABC::Key::X509 );
00424     }
00425 
00426     list.append( addr );
00427   }
00428 
00429   return list;
00430 }
00431 
00432 void VCardXXPort::addKey( KABC::Addressee &addr, KABC::Key::Types type )
00433 {
00434   TQString fingerprint = addr.custom( "KADDRESSBOOK",
00435                                      (type == KABC::Key::PGP ? "OPENPGPFP" : "SMIMEFP") );
00436   if ( fingerprint.isEmpty() )
00437     return;
00438 
00439   GpgME::Context * context = GpgME::Context::createForProtocol( GpgME::Context::OpenPGP );
00440   if ( !context ) {
00441     kdError() << "No context available" << endl;
00442     return;
00443   }
00444 
00445   context->setArmor( false );
00446   context->setTextMode( false );
00447 
00448   QGpgME::QByteArrayDataProvider dataProvider;
00449   GpgME::Data dataObj( &dataProvider );
00450   GpgME::Error error = context->exportPublicKeys( fingerprint.latin1(), dataObj );
00451   delete context;
00452 
00453   if ( error ) {
00454     kdError() << error.asString() << endl;
00455     return;
00456   }
00457 
00458   KABC::Key key;
00459   key.setType( type );
00460   key.setBinaryData( dataProvider.data() );
00461 
00462   addr.insertKey( key );
00463 }
00464 
00465 // ---------- VCardViewer Dialog ---------------- //
00466 
00467 VCardViewerDialog::VCardViewerDialog( const KABC::Addressee::List &list,
00468                                       TQWidget *parent, const char *name )
00469   : KDialogBase( Plain, i18n( "Import vCard" ), Yes | No | Apply | Cancel, Yes,
00470                  parent, name, true, true, KStdGuiItem::no(), KStdGuiItem::yes() ),
00471     mContacts( list )
00472 {
00473   TQFrame *page = plainPage();
00474   TQVBoxLayout *layout = new TQVBoxLayout( page, marginHint(), spacingHint() );
00475 
00476   TQLabel *label = new TQLabel( i18n( "Do you want to import this contact in your address book?" ), page );
00477   TQFont font = label->font();
00478   font.setBold( true );
00479   label->setFont( font );
00480   layout->addWidget( label );
00481 
00482   mView = new KPIM::AddresseeView( page );
00483   mView->enableLinks( 0 );
00484   mView->setVScrollBarMode( TQScrollView::Auto );
00485   layout->addWidget( mView );
00486 
00487   setButtonText( Apply, i18n( "Import All..." ) );
00488 
00489   mIt = mContacts.begin();
00490 
00491   updateView();
00492 }
00493 
00494 KABC::Addressee::List VCardViewerDialog::contacts() const
00495 {
00496   return mContacts;
00497 }
00498 
00499 void VCardViewerDialog::updateView()
00500 {
00501   mView->setAddressee( *mIt );
00502 
00503   KABC::Addressee::List::Iterator it = mIt;
00504   actionButton( Apply )->setEnabled( (++it) != mContacts.end() );
00505 }
00506 
00507 void VCardViewerDialog::slotUser1()
00508 {
00509   mIt = mContacts.remove( mIt );
00510 
00511   if ( mIt == mContacts.end() )
00512     slotApply();
00513 
00514   updateView();
00515 }
00516 
00517 void VCardViewerDialog::slotUser2()
00518 {
00519   mIt++;
00520 
00521   if ( mIt == mContacts.end() )
00522     slotApply();
00523 
00524   updateView();
00525 }
00526 
00527 void VCardViewerDialog::slotApply()
00528 {
00529   TQDialog::accept();
00530 }
00531 
00532 void VCardViewerDialog::slotCancel()
00533 {
00534   mContacts.clear();
00535   TQDialog::accept();
00536 }
00537 
00538 // ---------- VCardExportSelection Dialog ---------------- //
00539 
00540 VCardExportSelectionDialog::VCardExportSelectionDialog( TQWidget *parent,
00541                                                         const char *name )
00542   : KDialogBase( Plain, i18n( "Select vCard Fields" ), Ok | Cancel, Ok,
00543                  parent, name, true, true )
00544 {
00545   TQFrame *page = plainPage();
00546 
00547   TQVBoxLayout *layout = new TQVBoxLayout( page, marginHint(), spacingHint() );
00548 
00549   TQLabel *label = new TQLabel( i18n( "Select the fields which shall be exported in the vCard." ), page );
00550   layout->addWidget( label );
00551 
00552   mPrivateBox = new TQCheckBox( i18n( "Private fields" ), page );
00553   layout->addWidget( mPrivateBox );
00554 
00555   mBusinessBox = new TQCheckBox( i18n( "Business fields" ), page );
00556   layout->addWidget( mBusinessBox );
00557 
00558   mOtherBox = new TQCheckBox( i18n( "Other fields" ), page );
00559   layout->addWidget( mOtherBox );
00560 
00561   mEncryptionKeys = new TQCheckBox( i18n( "Encryption keys" ), page );
00562   layout->addWidget( mEncryptionKeys );
00563 
00564   KConfig config( "kaddressbookrc" );
00565   config.setGroup( "XXPortVCard" );
00566 
00567   mPrivateBox->setChecked( config.readBoolEntry( "ExportPrivateFields", true ) );
00568   mBusinessBox->setChecked( config.readBoolEntry( "ExportBusinessFields", false ) );
00569   mOtherBox->setChecked( config.readBoolEntry( "ExportOtherFields", false ) );
00570   mEncryptionKeys->setChecked( config.readBoolEntry( "ExportEncryptionKeys", false ) );
00571 }
00572 
00573 VCardExportSelectionDialog::~VCardExportSelectionDialog()
00574 {
00575   KConfig config( "kaddressbookrc" );
00576   config.setGroup( "XXPortVCard" );
00577 
00578   config.writeEntry( "ExportPrivateFields", mPrivateBox->isChecked() );
00579   config.writeEntry( "ExportBusinessFields", mBusinessBox->isChecked() );
00580   config.writeEntry( "ExportOtherFields", mOtherBox->isChecked() );
00581   config.writeEntry( "ExportEncryptionKeys", mEncryptionKeys->isChecked() );
00582 }
00583 
00584 bool VCardExportSelectionDialog::exportPrivateFields() const
00585 {
00586   return mPrivateBox->isChecked();
00587 }
00588 
00589 bool VCardExportSelectionDialog::exportBusinessFields() const
00590 {
00591   return mBusinessBox->isChecked();
00592 }
00593 
00594 bool VCardExportSelectionDialog::exportOtherFields() const
00595 {
00596   return mOtherBox->isChecked();
00597 }
00598 
00599 bool VCardExportSelectionDialog::exportEncryptionKeys() const
00600 {
00601   return mEncryptionKeys->isChecked();
00602 }
00603 
00604 #include "vcard_xxport.moc"