• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdenetwork
  • Sitemap
  • Contact Us
 

kopete/libkopete

kabcpersistence.cpp

Go to the documentation of this file.
00001 /*
00002     addressbooklink.cpp - Manages operations involving the KDE Address Book
00003 
00004     Copyright (c) 2005 Will Stephenson <wstephenson@kde.org>
00005 
00006     Kopete    (c) 2002-2004 by the Kopete developers  <kopete-devel@kde.org>
00007 
00008     *************************************************************************
00009     *                                                                       *
00010     * This library is free software; you can redistribute it and/or         *
00011     * modify it under the terms of the GNU Lesser General Public            *
00012     * License as published by the Free Software Foundation; either          *
00013     * version 2 of the License, or (at your option) any later version.      *
00014     *                                                                       *
00015     *************************************************************************
00016 */
00017 
00018 #include <qstring.h>
00019 #include <qtimer.h>
00020 
00021 #include <kabc/addressbook.h>
00022 #include <kabc/addressee.h>
00023 #include <kabc/resource.h>
00024 #include <kabc/stdaddressbook.h>
00025 
00026 // UI related includes used for importing from KABC
00027 #include <kdialog.h>
00028 #include <klocale.h>
00029 #include <kmessagebox.h>
00030 #include "accountselector.h"
00031 #include "kopeteuiglobal.h"
00032 
00033 #include "kopeteaccount.h"
00034 #include "kopeteaccountmanager.h"
00035 #include "kopetecontact.h"
00036 #include "kopetemetacontact.h"
00037 #include "kopetepluginmanager.h"
00038 #include "kopeteprotocol.h"
00039 
00040 #include "kabcpersistence.h"
00041 
00042 namespace Kopete
00043 {
00044 
00048 static QString unionContents( QString arg1, QString arg2 )
00049 {
00050     QChar separator( 0xE000 );
00051     QStringList outList = arg1.split( separator, QString::SkipEmptyParts );
00052     QStringList arg2List = arg2.split( separator, QString::SkipEmptyParts );
00053     for ( QStringList::iterator it = arg2List.begin(); it != arg2List.end(); ++it )
00054         if ( !outList.contains( *it ) )
00055             outList.append( *it );
00056     QString out = outList.join( QString( separator ) );
00057     return out;
00058 }
00059 
00060 class KABCPersistence::Private
00061 {
00062 public:
00063     Private() 
00064      : addrBookWritePending(false)
00065     {}
00066     QList<KABC::Resource *> pendingResources;
00067     bool addrBookWritePending;
00068 
00069     // FIXME: Try to remove that static variable !
00070     static KABC::AddressBook* s_addressBook;
00071 };
00072 
00073 KABC::AddressBook* KABCPersistence::Private::s_addressBook = 0L;
00074 
00075 KABCPersistence::KABCPersistence( QObject * parent, const char * name ) : QObject( parent)
00076 {
00077     setObjectName( name );
00078     d = new Private;
00079 }
00080 
00081 KABCPersistence::~KABCPersistence()
00082 {
00083     delete d;
00084 }
00085 
00086 KABCPersistence *KABCPersistence::self()
00087 {
00088     static KABCPersistence s;
00089     return &s;
00090 }
00091 
00092 KABC::AddressBook* KABCPersistence::addressBook()
00093 {
00094     if ( Private::s_addressBook == 0L )
00095     {
00096         Private::s_addressBook = KABC::StdAddressBook::self();
00097         KABC::StdAddressBook::setAutomaticSave( false );
00098     }
00099     return Private::s_addressBook;
00100 }
00101 
00102 void KABCPersistence::write( MetaContact * mc )
00103 {
00104     // Save any changes in each contact's addressBookFields to KABC
00105     KABC::AddressBook* ab = addressBook();
00106 
00107     kDebug( 14010 ) << "looking up Addressee for " << mc->displayName() << "...";
00108     // Look up the address book entry
00109     KABC::Addressee theAddressee = ab->findByUid( mc->metaContactId() );
00110     // Check that if addressee is not deleted or if the link is spurious
00111     // (inherited from Kopete < 0.8, where all metacontacts had random ids)
00112     if ( theAddressee.isEmpty() )
00113     {
00114         // not found in currently enabled addressbooks - may be in a disabled resource...
00115         return;
00116     }
00117     else
00118     {
00119         // collate the instant messaging data to be inserted into the address book
00120         QMap<QString, QStringList> addressMap;
00121         QList<Contact *> contacts = mc->contacts();
00122         QListIterator<Contact *> cIt( contacts );
00123         while ( cIt.hasNext() )
00124         {
00125             Contact * c = cIt.next();
00126             QStringList addresses = addressMap[ c->protocol()->addressBookIndexField() ];
00127             addresses.append( c->contactId() );
00128             addressMap.insert( c->protocol()->addressBookIndexField(), addresses );
00129         }
00130 
00131         // insert a custom field for each protocol
00132         QMap<QString, QStringList>::ConstIterator it = addressMap.begin();
00133         for ( ; it != addressMap.end(); ++it )
00134         {
00135             // read existing data for this key
00136             QString currentCustomForProtocol = theAddressee.custom( it.key(), QLatin1String( "All" ) );
00137             // merge without duplicating
00138             QString toWrite = unionContents( currentCustomForProtocol, it.value().join( QString( QChar( 0xE000 ) ) ) );
00139             // Note if nothing ends up in the KABC data, this is because insertCustom does nothing if any param is empty.
00140             kDebug( 14010 ) << "Writing: " << it.key() << ", " << "All" << ", " << toWrite;
00141             theAddressee.insertCustom( it.key(), QLatin1String( "All" ), toWrite );
00142             QString check = theAddressee.custom( it.key(), QLatin1String( "All" ) );
00143         }
00144         ab->insertAddressee( theAddressee );
00145         writeAddressBook( theAddressee.resource() );
00146         //theAddressee.dump();
00147     }
00148 
00149 /*          // Wipe out the existing addressBook entries
00150             d->addressBook.clear();
00151     // This causes each Kopete::Protocol subclass to serialise its contacts' data into the metacontact's plugin data and address book data
00152             emit aboutToSave(this);
00153 
00154             kDebug( 14010 ) << "...FOUND ONE!";
00155     // Store address book fields
00156             QMap<QString, QMap<QString, QString> >::ConstIterator appIt = d->addressBook.begin();
00157             for( ; appIt != d->addressBook.end(); ++appIt )
00158             {
00159                 QMap<QString, QString>::ConstIterator addrIt = appIt.data().begin();
00160                 for( ; addrIt != appIt.data().end(); ++addrIt )
00161                 {
00162             // read existing data for this key
00163                     QString currentCustom = theAddressee.custom( appIt.key(), addrIt.key() );
00164             // merge without duplicating
00165                     QString toWrite = unionContents( currentCustom, addrIt.data() );
00166             // write the result
00167             // Note if nothing ends up in the KABC data, this is because insertCustom does nothing if any param is empty.
00168                     kDebug( 14010 ) << "Writing: " << appIt.key() << ", " << addrIt.key() << ", " << toWrite;
00169                     theAddressee.insertCustom( appIt.key(), addrIt.key(), toWrite );
00170                 }
00171             }
00172             ab->insertAddressee( theAddressee );
00173             writeAddressBook();
00174         }*/
00175 }
00176 
00177 void KABCPersistence::writeAddressBook( KABC::Resource * res)
00178 {
00179     if ( !d->pendingResources.count( res ) )
00180         d->pendingResources.append( res );
00181     if ( !d->addrBookWritePending )
00182     {
00183         d->addrBookWritePending = true;
00184         QTimer::singleShot( 2000, this, SLOT( slotWriteAddressBook() ) );
00185     }
00186 }
00187 
00188 void KABCPersistence::slotWriteAddressBook()
00189 {
00190     //kDebug(  14010 ) ;
00191     KABC::AddressBook* ab = addressBook();
00192     QListIterator<KABC::Resource *> it( d->pendingResources );
00193     while ( it.hasNext() )
00194     {
00195         //kDebug(  14010 )  << "Writing resource " << it.current()->resourceName();
00196         KABC::Ticket *ticket = ab->requestSaveTicket( it.next() );
00197         if ( !ticket )
00198             kWarning( 14010 ) << "WARNING: Resource is locked by other application!";
00199         else
00200         {
00201             if ( !ab->save( ticket ) )
00202             {
00203                 kWarning( 14010 ) << "ERROR: Saving failed!";
00204                 ab->releaseSaveTicket( ticket );
00205             }
00206         }
00207         //kDebug( 14010 ) << "Finished writing KABC";
00208     }
00209     d->pendingResources.clear();
00210     d->addrBookWritePending = false;
00211 }
00212 
00213 void KABCPersistence::removeKABC( MetaContact *)
00214 {
00215 /*  // remove any data this KMC has written to the KDE address book
00216     // Save any changes in each contact's addressBookFields to KABC
00217     KABC::AddressBook* ab = addressBook();
00218 
00219     // Wipe out the existing addressBook entries
00220     d->addressBook.clear();
00221     // This causes each Kopete::Protocol subclass to serialise its contacts' data into the metacontact's plugin data and address book data
00222     emit aboutToSave(this);
00223 
00224     // If the metacontact is linked to a kabc entry
00225     if ( !d->metaContactId.isEmpty() )
00226     {
00227         //kDebug( 14010 ) << "looking up Addressee for " << displayName() << "...";
00228         // Look up the address book entry
00229         KABC::Addressee theAddressee = ab->findByUid( metaContactId() );
00230 
00231         if ( theAddressee.isEmpty() )
00232         {
00233             // remove the link
00234             //kDebug( 14010 ) << "...not found.";
00235             d->metaContactId.clear();
00236         }
00237         else
00238         {
00239             //kDebug( 14010 ) << "...FOUND ONE!";
00240             // Remove address book fields
00241             QMap<QString, QMap<QString, QString> >::ConstIterator appIt = d->addressBook.begin();
00242             for( ; appIt != d->addressBook.end(); ++appIt )
00243             {
00244                 QMap<QString, QString>::ConstIterator addrIt = appIt.data().begin();
00245                 for( ; addrIt != appIt.data().end(); ++addrIt )
00246                 {
00247                     // FIXME: This assumes Kopete is the only app writing these fields
00248                     kDebug( 14010 ) << "Removing: " << appIt.key() << ", " << addrIt.key();
00249                     theAddressee.removeCustom( appIt.key(), addrIt.key() );
00250                 }
00251             }
00252             ab->insertAddressee( theAddressee );
00253 
00254             writeAddressBook();
00255         }
00256     }
00257 //  kDebug(14010) << kBacktrace();*/
00258 }
00259 
00260 bool KABCPersistence::syncWithKABC( MetaContact * mc )
00261 {
00262     kDebug(14010) ;
00263     bool contactAdded = false;
00264     // check whether the dontShowAgain was checked
00265         KABC::AddressBook* ab = addressBook();
00266         KABC::Addressee addr  = ab->findByUid( mc->metaContactId() );
00267 
00268         if ( !addr.isEmpty() ) // if we are associated with KABC
00269         {
00270 // load the set of addresses from KABC
00271         QStringList customs = addr.customs();
00272 
00273         QStringList::ConstIterator it;
00274         for ( it = customs.begin(); it != customs.end(); ++it )
00275         {
00276             QString app, name, value;
00277             splitField( *it, app, name, value );
00278             kDebug( 14010 ) << "app=" << app << " name=" << name << " value=" << value;
00279 
00280             if ( app.startsWith( QLatin1String( "messaging/" ) ) )
00281             {
00282                 if ( name == QLatin1String( "All" ) )
00283                 {
00284                     kDebug( 14010 ) << " syncing \"" << app << ":" << name << " with contact list ";
00285                     // Get the protocol name from the custom field
00286                     // by chopping the 'messaging/' prefix from the custom field app name
00287                     QString protocolName = app.right( app.length() - 10 );
00288                     // munge Jabber hack
00289                     if ( protocolName == QLatin1String( "xmpp" ) )
00290                         protocolName = QLatin1String( "jabber" );
00291 
00292                     // Check Kopete supports it
00293                     Protocol * proto = dynamic_cast<Protocol*>( PluginManager::self()->loadPlugin( QLatin1String( "kopete_" ) + protocolName ) );
00294                     if ( !proto )
00295                     {
00296                         KMessageBox::queuedMessageBox( Kopete::UI::Global::mainWidget(), KMessageBox::Sorry,
00297                                                                                      i18n( "<qt>\"%1\" is not supported by Kopete.</qt>", protocolName ),
00298                                                                                      i18n( "Could Not Sync with KDE Address Book" )  );
00299                         continue;
00300                     }
00301 
00302                     // See if we need to add each contact in this protocol
00303                     QStringList addresses = value.split( QChar( 0xE000 ), QString::SkipEmptyParts );
00304                     QStringList::iterator end = addresses.end();
00305                     for ( QStringList::iterator it = addresses.begin(); it != end; ++it )
00306                     {
00307                         // check whether each one is present in Kopete
00308                         // Is it in the contact list?
00309                         // First discard anything after an 0xE120, this is used by IRC to separate nick and server group name, but
00310                         // IRC doesn't support this properly yet, so the user will have to select an appropriate account manually
00311                         int separatorPos = (*it).indexOf( QChar( 0xE120 ) );
00312                         if ( separatorPos != -1 )
00313                             *it = (*it).left( separatorPos );
00314 
00315                         Kopete::MetaContact *otherMc = 0;
00316                         foreach( Kopete::Account *act, Kopete::AccountManager::self()->accounts() )
00317                         {
00318                             if( act->protocol() != proto )
00319                                 continue;
00320                             Kopete::Contact *c= act->contacts()[*it];
00321                             if(c)
00322                             {
00323                                 otherMc=c->metaContact();
00324                                 break;
00325                             }
00326                         }
00327 
00328                         if ( otherMc ) // Is it in another metacontact?
00329                         {
00330                             // Is it already in this metacontact? If so, we needn't do anything
00331                             if ( otherMc == mc )
00332                             {
00333                                 kDebug( 14010 ) << *it << " already a child of this metacontact.";
00334                                 continue;
00335                             }
00336                             kDebug( 14010 ) << *it << " already exists in OTHER metacontact, move here?";
00337                             // find the Kopete::Contact and attempt to move it to this metacontact.
00338                             otherMc->findContact( proto->pluginId(), QString(), *it )->setMetaContact( mc );
00339                         }
00340                         else
00341                         {
00342                             // if not, prompt to add it
00343                             kDebug( 14010 ) << proto->pluginId() << "://" << *it << " was not found in the contact list.  Prompting to add...";
00344                             if ( KMessageBox::Yes == KMessageBox::questionYesNo( Kopete::UI::Global::mainWidget(),
00345                                      i18n( "<qt>An address was added to this contact by another application.<br />Would you like to use it in Kopete?<br /><b>Protocol:</b> %1<br /><b>Address:</b> %2</qt>", proto->displayName(), *it ), i18n( "Import Address From Address Book" ), KGuiItem( i18n("Use") ), KGuiItem( i18n("Do Not Use") ), QLatin1String( "ImportFromKABC" ) ) )
00346                             {
00347                                 // Check the accounts for this protocol are all connected
00348                                 // Most protocols do not allow you to add contacts while offline
00349                                 // Would be better to have a virtual bool Kopete::Account::readyToAddContact()
00350                                 int accountcount=0;
00351                                 bool allAccountsConnected = true;
00352                                 Kopete::Account *chosen = 0;
00353                                 foreach( Kopete::Account *act, Kopete::AccountManager::self()->accounts() )
00354                                 {
00355                                     if( act->protocol() == proto) 
00356                                     {
00357                                         accountcount++;
00358                                         if(!act->isConnected())
00359                                         {
00360                                             allAccountsConnected=false;
00361                                             break;
00362                                         }
00363                                         chosen=act;
00364                                     }
00365                                 }
00366 
00367                                 if ( !allAccountsConnected )
00368                                 {
00369                                     KMessageBox::queuedMessageBox( Kopete::UI::Global::mainWidget(), KMessageBox::Sorry,
00370                                             i18n( "<qt>One or more of your accounts using %1 are offline.  Most systems have to be connected to add contacts.  Please connect these accounts and try again.</qt>", protocolName ),
00371                                             i18n( "Not Connected" )  );
00372                                     continue;
00373                                 }
00374 
00375                                 // we have got a contact to add, our accounts are connected, so add it.
00376                                 // Do we need to choose an account
00377                                 if ( accountcount > 1 )
00378                                 {   // if we have >1 account in this protocol, prompt for the protocol.
00379                                     KDialog *chooser = new KDialog(0);
00380                                     chooser->setCaption( i18n("Choose Account") );
00381                                     chooser->setButtons( KDialog::Ok | KDialog::Cancel );
00382 
00383                                     AccountSelector *accSelector = new AccountSelector(proto, chooser);
00384                                     accSelector->setObjectName( QLatin1String("accSelector") );
00385                                     chooser->setMainWidget(accSelector);
00386                                     if ( chooser->exec() == QDialog::Rejected )
00387                                         continue;
00388                                     chosen = accSelector->selectedItem();
00389 
00390                                     delete chooser;
00391                                 }
00392                                 else if ( accountcount == 0 )
00393                                 {
00394                                     KMessageBox::queuedMessageBox( Kopete::UI::Global::mainWidget(), KMessageBox::Sorry,
00395                                             i18n( "<qt>You do not have an account configured for <b>%1</b> yet.  Please create an account, connect it, and try again.</qt>", protocolName ),
00396                                             i18n( "No Account Found" )  );
00397                                     continue;
00398                                 }
00399 
00400                                 // add the contact to the chosen account
00401                                 if ( chosen )
00402                                 {
00403                                     kDebug( 14010 ) << "Adding " << *it << " to " << chosen->accountId();
00404                                     if ( chosen->addContact( *it, mc ) )
00405                                         contactAdded = true;
00406                                     else
00407                                         KMessageBox::queuedMessageBox( Kopete::UI::Global::mainWidget(), KMessageBox::Sorry,
00408                                             i18n( "<qt>It was not possible to add the contact.</qt>" ),
00409                                             i18n( "Could Not Add Contact") ) ;
00410                                 }
00411                             }
00412                             else
00413                                 kDebug( 14010 ) << " user declined to add " << *it << " to contact list ";
00414                         }
00415                     }
00416                     kDebug( 14010 ) << " all " << addresses.count() << " contacts in " << proto->pluginId() << " checked ";
00417                 }
00418                 else
00419                     kDebug( 14010 ) << "not interested in name=" << name;
00420 
00421             }
00422             else
00423                 kDebug( 14010 ) << "not interested in app=" << app;
00424         }
00425     }
00426     return contactAdded;
00427     return false;
00428 }
00429 
00430 // FIXME: Remove when IM address API is in KABC (KDE 4)
00431 void KABCPersistence::splitField( const QString &str, QString &app, QString &name, QString &value )
00432 {
00433     int colon = str.indexOf( ':' );
00434     if ( colon != -1 ) {
00435         QString tmp = str.left( colon );
00436         value = str.mid( colon + 1 );
00437 
00438         int dash = tmp.indexOf( '-' );
00439         if ( dash != -1 ) {
00440             app = tmp.left( dash );
00441             name = tmp.mid( dash + 1 );
00442         }
00443     }
00444 }
00445 
00446 } // end namespace Kopete
00447 
00448         // dump addressbook contents
00449 
00450 #include "kabcpersistence.moc"

kopete/libkopete

Skip menu "kopete/libkopete"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdenetwork

Skip menu "kdenetwork"
  • kget
  • kopete
  •   kopete
  •   libkopete
  •       libpapillon
  • krfb
Generated for kdenetwork by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal