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

kopete/libkopete

kopeteprotocol.cpp

Go to the documentation of this file.
00001 /*
00002     kopeteprotocol.cpp - Kopete Protocol
00003 
00004     Copyright (c) 2002      by Duncan Mac-Vicar Prett <duncan@kde.org>
00005     Copyright (c) 2002-2003 by Martijn Klingens       <klingens@kde.org>
00006     Copyright (c) 2002-2005 by Olivier Goffart        <ogoffart@kde.org>
00007 
00008     Kopete    (c) 2002-2004 by the Kopete developers  <kopete-devel@kde.org>
00009 
00010     *************************************************************************
00011     *                                                                       *
00012     * This library is free software; you can redistribute it and/or         *
00013     * modify it under the terms of the GNU Lesser General Public            *
00014     * License as published by the Free Software Foundation; either          *
00015     * version 2 of the License, or (at your option) any later version.      *
00016     *                                                                       *
00017     *************************************************************************
00018 */
00019 
00020 #include "kopeteprotocol.h"
00021 
00022 #include <kdebug.h>
00023 #include <kaction.h>
00024 #include <klocale.h>
00025 #include <kjob.h>
00026 
00027 #include "kopeteaccountmanager.h"
00028 #include "kopeteaccount.h"
00029 #include "kopetecontact.h"
00030 #include "kopeteglobal.h"
00031 #include "kopeteproperty.h"
00032 #include "kopetemetacontact.h"
00033 
00034 namespace Kopete
00035 {
00036 
00037 class Protocol::Private
00038 {
00039 public:
00040     bool unloading;
00041     Protocol::Capabilities capabilities;
00042     /*
00043      * Make sure we always have a lastSeen and a fullname property as long as
00044      * a protocol is loaded
00045      */
00046     PropertyTmpl mStickLastSeen;
00047     PropertyTmpl mStickFullName;
00048 
00049     Kopete::OnlineStatus accountNotConnectedStatus;
00050 };
00051 
00052 Protocol::Protocol( const KComponentData &instance, QObject *parent )
00053 : Plugin( instance, parent )
00054 {
00055     d = new Private;
00056     d->mStickLastSeen = Global::Properties::self()->lastSeen();
00057     d->mStickFullName = Global::Properties::self()->fullName();
00058     d->unloading = false;
00059     d->accountNotConnectedStatus = Kopete::OnlineStatus( Kopete::OnlineStatus::Unknown, 0, this, Kopete::OnlineStatus::AccountOffline, QStringList(QString::fromLatin1( "account_offline_overlay" )), i18n( "Account Offline" ) );
00060 }
00061 
00062 Protocol::~Protocol()
00063 {
00064     // Remove all active accounts
00065     foreach( Account *a , AccountManager::self()->accounts() )
00066     {
00067         if( a->protocol() == this )
00068         {
00069             kWarning( 14010 ) << "Deleting protocol with existing accounts! Did the account unloading go wrong?  account: " 
00070                     << a->accountId() << endl;
00071         
00072             delete a;
00073         }
00074     }
00075     delete d;
00076 }
00077 
00078 Protocol::Capabilities Protocol::capabilities() const
00079 {
00080     return d->capabilities;
00081 }
00082 
00083 void Protocol::setCapabilities( Protocol::Capabilities capabilities )
00084 {
00085     d->capabilities = capabilities;
00086 }
00087 
00088 
00089 Kopete::OnlineStatus Protocol::accountOfflineStatus() const
00090 {
00091     return d->accountNotConnectedStatus;
00092 }
00093 
00094 void Protocol::slotAccountOnlineStatusChanged( Contact *self )
00095 {//slot connected in aboutToUnload
00096     if ( !self || !self->account() || self->account()->isConnected())
00097         return;
00098     // some protocols change status several times during shutdown.  We should only call deleteLater() once
00099     disconnect( self, 0, this, 0 );
00100 
00101     connect( self->account(), SIGNAL(destroyed( )),
00102         this, SLOT( slotAccountDestroyed( ) ) );
00103 
00104     self->account()->deleteLater();
00105 }
00106 
00107 void Protocol::slotAccountDestroyed( )
00108 {
00109     foreach( Account *a , AccountManager::self()->accounts() )
00110     {
00111         if( a->protocol() == this )
00112         {
00113             //all accounts has not been deleted yet
00114             return;
00115         }
00116     }
00117 
00118     // While at this point we are still in a stack trace from the destroyed
00119     // account it's safe to emit readyForUnload already, because it uses a
00120     // deleteLater rather than a delete for exactly this reason, to keep the
00121     // API managable
00122     emit( readyForUnload() );
00123 }
00124 
00125 void Protocol::aboutToUnload()
00126 {
00127 
00128     d->unloading = true;
00129 
00130     int accountcountcount=0;
00131     // Disconnect all accounts
00132     foreach( Account *a , AccountManager::self()->accounts() )
00133     {
00134         if( a->protocol() == this )
00135         {
00136             accountcountcount++;
00137             
00138             if ( a->myself() && a->myself()->isOnline() )
00139             {
00140                 kDebug( 14010 ) << a->accountId() <<
00141                         " is still connected, disconnecting..." << endl;
00142 
00143                 QObject::connect( a->myself(),
00144                                   SIGNAL( onlineStatusChanged( Kopete::Contact *, const Kopete::OnlineStatus &, const Kopete::OnlineStatus & ) ),
00145                                   this, SLOT( slotAccountOnlineStatusChanged( Kopete::Contact * ) ) );
00146                 a->disconnect();
00147             }
00148             else
00149             {
00150                 // Remove account, it's already disconnected
00151                 kDebug( 14010 ) << a->accountId() <<
00152                         " is already disconnected, deleting..." << endl;
00153 
00154                 QObject::connect( a, SIGNAL( destroyed( ) ),
00155                                   this, SLOT( slotAccountDestroyed( ) ) );
00156                 a->deleteLater();
00157             }
00158         }
00159     }
00160 
00161     if( accountcountcount > 0 )
00162     {
00163         //no accounts in there anymore ,   we can unload safelly
00164         emit readyForUnload();
00165     }
00166 }
00167 
00168 
00169 
00170 void Protocol::slotMetaContactAboutToSave( MetaContact *metaContact )
00171 {
00172     QMap<QString, QString> serializedData, sd;
00173     QMap<QString, QString> addressBookData, ad;
00174     QMap<QString, QString>::Iterator it;
00175 
00176     //kDebug( 14010 ) << "Protocol::metaContactAboutToSave: protocol " << pluginId() << ": serializing " << metaContact->displayName();
00177 
00178     QListIterator<Contact *> cit(metaContact->contacts());
00179     while ( cit.hasNext() )
00180     {
00181         Contact *c = cit.next();
00182         if( c->protocol()->pluginId() != pluginId() )
00183             continue;
00184 
00185         sd.clear();
00186         ad.clear();
00187 
00188         // Preset the contactId and displayName, if the plugin doesn't want to save
00189         // them, or use its own format, it can call clear() on the provided list
00190         sd[ QString::fromLatin1( "contactId" ) ] =   c->contactId();
00191         //TODO(nick) remove
00192         sd[ QString::fromLatin1( "displayName" ) ] = c->property(Global::Properties::self()->nickName()).value().toString();
00193         if(c->account())
00194             sd[ QString::fromLatin1( "accountId" ) ] = c->account()->accountId();
00195 
00196         // If there's an index field preset it too
00197         QString index = c->protocol()->addressBookIndexField();
00198         if( !index.isEmpty() )
00199             ad[ index ] = c->contactId();
00200 
00201         c->serializeProperties( sd );
00202         c->serialize( sd, ad );
00203 
00204         // Merge the returned fields with what we already (may) have
00205         for( it = sd.begin(); it != sd.end(); ++it )
00206         {
00207             // The Unicode chars E000-F800 are non-printable and reserved for
00208             // private use in applications. For more details, see also
00209             // http://www.unicode.org/charts/PDF/UE000.pdf.
00210             // Inside libkabc the use of QChar( 0xE000 ) has been standardized
00211             // as separator for the string lists, use this also for the 'normal'
00212             // serialized data.
00213             if( serializedData.contains( it.key() ) )
00214                 serializedData[ it.key() ] = serializedData[ it.key() ] + QChar( 0xE000 ) + it.value();
00215             else
00216                 serializedData[ it.key() ] = it.value();
00217         }
00218 
00219         for( it = ad.begin(); it != ad.end(); ++it )
00220         {
00221             if( addressBookData.contains( it.key() ) )
00222                 addressBookData[ it.key() ] = addressBookData[ it.key() ] + QChar( 0xE000 ) + it.value();
00223             else
00224                 addressBookData[ it.key() ] = it.value();
00225         }
00226     }
00227 
00228     // Pass all returned fields to the contact list
00229     //if( !serializedData.isEmpty() ) //even if we are empty, that mean there are no contact, so remove old value
00230     metaContact->setPluginData( this, serializedData );
00231 
00232     for( it = addressBookData.begin(); it != addressBookData.end(); ++it )
00233     {
00234         //kDebug( 14010 ) << "Protocol::metaContactAboutToSave: addressBookData: key: " << it.key() << ", data: " << it.data();
00235         // FIXME: This is a terrible hack to check the key name for the phrase "messaging/"
00236         //        to indicate what app name to use, but for now it's by far the easiest
00237         //        way to get this working.
00238         //        Once all this is in CVS and the actual storage in libkabc is working
00239         //        we can devise a better API, but with the constantly changing
00240         //        requirements every time I learn more about kabc I'd better no touch
00241         //        the API yet - Martijn
00242         if( it.key().startsWith( QString::fromLatin1( "messaging/" ) ) )
00243         {
00244             metaContact->setAddressBookField( this, it.key(), QString::fromLatin1( "All" ), it.value() );
00245 //          kDebug(14010) << "metaContact->setAddressBookField( " << this << ", " << it.key() << ", \"All\", " << it.data() << " );";
00246         }
00247         else
00248             metaContact->setAddressBookField( this, QString::fromLatin1( "kopete" ), it.key(), it.value() );
00249     }
00250 }
00251 
00252 void Protocol::deserialize( MetaContact *metaContact, const QMap<QString, QString> &data )
00253 {
00254     /*kDebug( 14010 ) << "Protocol::deserialize: protocol " <<
00255         pluginId() << ": deserializing " << metaContact->displayName() << endl;*/
00256     
00257     QMap<QString, QStringList> serializedData;
00258     QMap<QString, QStringList::Iterator> serializedDataIterators;
00259     QMap<QString, QString>::ConstIterator it;
00260     for( it = data.begin(); it != data.end(); ++it )
00261     {
00262         serializedData[ it.key() ] = it.value().split( QChar( 0xE000 ), QString::KeepEmptyParts );
00263         serializedDataIterators[ it.key() ] = serializedData[ it.key() ].begin();
00264     }
00265 
00266     int count = serializedData[QString::fromLatin1("contactId")].count();
00267 
00268     // Prepare the independent entries to pass to the plugin's implementation
00269     for( int i = 0; i < count ; i++ )
00270     {
00271         QMap<QString, QString> sd;
00272 #ifdef __GNUC__
00273 #warning  write this properly
00274 #endif
00275 #if 0   
00276         QMap<QString, QStringList::Iterator>::Iterator serializedDataIt;
00277         for( serializedDataIt = serializedDataIterators.begin(); serializedDataIt != serializedDataIterators.end(); ++serializedDataIt )
00278         {
00279             sd[ serializedDataIt.key() ] = *( serializedDataIt.data() );
00280             ++( serializedDataIt.data() );
00281         }
00282         
00283 #else
00284         QMap<QString, QStringList>::Iterator serializedDataIt;
00285         QMap<QString, QStringList>::Iterator serializedDataItEnd = serializedData.end();
00286         for( serializedDataIt = serializedData.begin(); serializedDataIt != serializedDataItEnd; ++serializedDataIt )
00287         {
00288             QStringList sl=serializedDataIt.value();
00289             if(sl.count()>i)
00290                 sd[ serializedDataIt.key() ] = sl[i];
00291         }
00292     
00293     
00294 #endif
00295 
00296         const QString& accountId=sd[ QString::fromLatin1( "accountId" ) ];
00297         // myself was allowed in the contact list in old version of kopete.
00298         // But if one keep it on the contact list now, it may conflict witht he myself metacontact.
00299         // So ignore it
00300         if(accountId == sd[ QString::fromLatin1( "contactId" ) ] )
00301         {
00302             kDebug( 14010 ) << "Myself contact was on the contactlist.xml for account " << accountId << ".  Ignore it";
00303             continue;
00304         }
00305 
00306         // FIXME: This code almost certainly breaks when having more than
00307         //        one contact in a meta contact. There are solutions, but
00308         //        they are all hacky and the API needs revision anyway (see
00309         //        FIXME a few lines below :), so I'm not going to add that
00310         //        for now.
00311         //        Note that even though it breaks, the current code will
00312         //        never notice, since none of the plugins use the address
00313         //        book data in the deserializer yet, only when serializing.
00314         //        - Martijn
00315         QMap<QString, QString> ad;
00316         
00317 
00318 #if 0
00319         QStringList kabcFields = addressBookFields();
00320         for( QStringList::Iterator fieldIt = kabcFields.begin(); fieldIt != kabcFields.end(); ++fieldIt )
00321         {
00322             // FIXME: This hack is even more ugly, and has the same reasons as the similar
00323             //        hack in the serialize code.
00324             //        Once this code is actually capable of talking to kabc this hack
00325             //        should be removed ASAP! - Martijn
00326             if( ( *fieldIt ).startsWith( QString::fromLatin1( "messaging/" ) ) )
00327                 ad[ *fieldIt ] = metaContact->addressBookField( this, *fieldIt, QString::fromLatin1( "All" ) );
00328             else
00329                 ad[ *fieldIt ] = metaContact->addressBookField( this, QString::fromLatin1( "kopete" ), *fieldIt );
00330         }
00331         // Check if we have an account id. If not we're deserializing a Kopete 0.6 contact
00332         // (our our config is corrupted). Pick the first available account there. This
00333         // might not be what you want for corrupted accounts, but it's correct for people
00334         // who migrate from 0.6, as there's only one account in that case
00335         if( accountId.isNull() )
00336         {
00337             Q3Dict<Account> accounts = AccountManager::self()->accounts( this );
00338             if ( accounts.count() > 0 )
00339             {
00340                 sd[ QString::fromLatin1( "accountId" ) ] = Q3DictIterator<Account>( accounts ).currentKey();
00341             }
00342             else
00343             {
00344                 kWarning( 14010 ) <<
00345                     "No account available and account not set in " \
00346                     "contactlist.xml either!" << endl
00347                     << "Not deserializing this contact." << endl;
00348                 return;
00349             }
00350         }
00351 #endif
00352 
00353 
00354         Contact *c = deserializeContact( metaContact, sd, ad );
00355         if (c) // should never be null but I do not like crashes
00356             c->deserializeProperties( sd );
00357     }
00358 }
00359 
00360 Contact *Protocol::deserializeContact(
00361     MetaContact * metaContact,
00362     const QMap<QString, QString> & serializedData,
00363     const QMap<QString, QString> & addressBookData )
00364 {
00365     Q_UNUSED( metaContact )
00366     Q_UNUSED( serializedData )
00367     Q_UNUSED( addressBookData )
00368     /* Default implementation does nothing */
00369     return 0;
00370 }
00371 
00372 KJob *Protocol::createProtocolTask(const QString &taskType)
00373 {
00374     // Default implementation does nothing
00375     Q_UNUSED( taskType )
00376     return 0;
00377 }
00378 
00379 bool Protocol::validatePassword( const QString & password ) const
00380 {
00381     Q_UNUSED( password )
00382     return true;
00383 }
00384 
00385 } //END namespace Kopete
00386 
00387 #include "kopeteprotocol.moc"
00388 

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