2 kopeteaccountmanager.cpp - Kopete Account Manager
4 Copyright (c) 2002-2003 by Martijn Klingens <klingens@kde.org>
5 Copyright (c) 2003-2004 by Olivier Goffart <ogoffart@kde.org>
7 Kopete (c) 2002-2004 by the Kopete developers <kopete-devel@kde.org>
9 *************************************************************************
11 * This library is free software; you can redistribute it and/or *
12 * modify it under the terms of the GNU Lesser General Public *
13 * License as published by the Free Software Foundation; either *
14 * version 2 of the License, or (at your option) any later version. *
16 *************************************************************************
19 #include "kopeteaccountmanager.h"
21 #include <QtGui/QApplication>
22 #include <QtCore/QRegExp>
23 #include <QtCore/QTimer>
24 #include <QtCore/QHash>
26 #include <ksharedconfig.h>
29 #include <kplugininfo.h>
30 #include <kconfiggroup.h>
31 #include <solid/networking.h>
33 #include "kopeteaccount.h"
34 #include "kopetebehaviorsettings.h"
35 #include "kopeteprotocol.h"
36 #include "kopetecontact.h"
37 #include "kopetecontactlist.h"
38 #include "kopeteidentitymanager.h"
39 #include "kopetepluginmanager.h"
40 #include "kopeteonlinestatus.h"
41 #include "kopeteonlinestatusmanager.h"
42 #include "kopetemetacontact.h"
43 #include "kopetegroup.h"
44 #include "kopetestatusmanager.h"
48 static int compareAccountsByPriority( Account
*a
, Account
*b
)
50 uint priority1
= a
->priority();
51 uint priority2
= b
->priority();
53 if( a
==b
) //two account are equal only if they are equal :-)
54 return 0; // remember than an account can be only once on the list, but two account may have the same priority when loading
55 else if( priority1
> priority2
)
61 class AccountManager::Private
64 QList
<Account
*> accounts
;
67 AccountManager
* AccountManager::s_self
= 0L;
69 AccountManager
* AccountManager::self()
72 s_self
= new AccountManager
;
78 AccountManager::AccountManager()
81 setObjectName( "KopeteAccountManager" );
83 connect( Solid::Networking::notifier(), SIGNAL(shouldConnect()), this, SLOT( networkConnected() ) );
84 connect( Solid::Networking::notifier(), SIGNAL(shouldDisconnect()), this, SLOT( networkDisconnected() ) );
88 AccountManager::~AccountManager()
95 bool AccountManager::isAnyAccountConnected() const
97 foreach( Account
*a
, d
->accounts
)
99 if( a
->isConnected() )
106 void AccountManager::setOnlineStatus( uint category
, const Kopete::StatusMessage
&statusMessage
, uint flags
)
108 kDebug() << "category: " << category
;
109 OnlineStatusManager::Categories categories
110 = (OnlineStatusManager::Categories
)category
;
111 bool onlyChangeConnectedAccounts
= isAnyAccountConnected();
113 foreach( Account
*account
, d
->accounts
)
115 Kopete::OnlineStatus status
= OnlineStatusManager::self()->onlineStatus( account
->protocol(), categories
);
116 // Going offline is always respected
117 if ( category
& Kopete::OnlineStatusManager::Offline
) {
118 account
->setOnlineStatus( status
, statusMessage
);
122 if ( onlyChangeConnectedAccounts
) {
123 if ( account
->isConnected() || ( (flags
& ConnectIfOffline
) && !account
->excludeConnect() ) )
124 account
->setOnlineStatus( status
, statusMessage
);
127 if ( !account
->excludeConnect() )
128 account
->setOnlineStatus( status
, statusMessage
);
131 // mark ourselves as globally away if appropriate
132 Kopete::StatusManager::self()->setGlobalStatus( category
, statusMessage
);
135 void AccountManager::setStatusMessage(const QString
&message
)
137 foreach( Account
*account
, d
->accounts
)
139 account
->setStatusMessage(message
);
143 QColor
AccountManager::guessColor( Protocol
*protocol
) const
145 // In a perfect wold, we should check if the color is actually not used by the account.
146 // Anyway, this is not really required, It would be a difficult job for about nothing more.
148 int protocolCount
= 0;
150 for ( QListIterator
<Account
*> it( d
->accounts
); it
.hasNext(); )
152 Account
*a
= it
.next();
153 if ( a
->protocol()->pluginId() == protocol
->pluginId() )
157 // let's figure a color
159 switch ( protocolCount
% 7 )
187 Account
* AccountManager::registerAccount( Account
*account
)
189 if( !account
|| d
->accounts
.contains( account
) )
192 if( account
->accountId().isEmpty() )
194 account
->deleteLater();
198 // If this account already exists, do nothing
199 QListIterator
<Account
*> it( d
->accounts
);
200 while ( it
.hasNext() )
202 Account
*curracc
= it
.next();
203 if ( ( account
->protocol() == curracc
->protocol() ) && ( account
->accountId() == curracc
->accountId() ) )
205 account
->deleteLater();
210 d
->accounts
.append( account
);
211 qSort( d
->accounts
.begin(), d
->accounts
.end(), compareAccountsByPriority
);
213 // Connect to the account's status changed signal
214 connect(account
->myself(), SIGNAL(onlineStatusChanged(Kopete::Contact
*,
215 const Kopete::OnlineStatus
&, const Kopete::OnlineStatus
&)),
216 this, SLOT(slotAccountOnlineStatusChanged(Kopete::Contact
*,
217 const Kopete::OnlineStatus
&, const Kopete::OnlineStatus
&)));
219 connect(account
, SIGNAL(accountDestroyed(const Kopete::Account
*)) , this, SLOT( unregisterAccount(const Kopete::Account
*) ));
221 emit
accountRegistered( account
);
225 void AccountManager::unregisterAccount( const Account
*account
)
227 kDebug( 14010 ) << "Unregistering account " << account
->accountId();
228 d
->accounts
.removeAll( const_cast<Account
*>(account
) );
229 emit
accountUnregistered( account
);
232 const QList
<Account
*>& AccountManager::accounts() const
237 QList
<Account
*> AccountManager::accounts( Protocol
* protocol
) const
239 QList
<Account
*> protocolAccounts
;
240 foreach( Account
* acct
, d
->accounts
)
242 if ( acct
->protocol() == protocol
)
243 protocolAccounts
.append( acct
);
245 return protocolAccounts
;
248 Account
* AccountManager::findAccount( const QString
&protocolId
, const QString
&accountId
)
250 for ( QListIterator
<Account
*> it( d
->accounts
); it
.hasNext(); )
252 Account
*a
= it
.next();
253 if ( a
->protocol()->pluginId() == protocolId
&& a
->accountId() == accountId
)
259 void AccountManager::removeAccount( Account
*account
)
261 if(!account
->removeAccount())
264 Protocol
*protocol
= account
->protocol();
266 KConfigGroup
*configgroup
= account
->configGroup();
268 // Clean up the contact list
269 const QHash
<QString
, Kopete::Contact
*> contactList
= account
->contacts();
270 QHash
<QString
, Kopete::Contact
*>::ConstIterator it
, itEnd
= contactList
.constEnd();
272 for ( it
= contactList
.constBegin(); it
!= itEnd
; ++it
)
274 Contact
* c
= it
.value();
275 MetaContact
* mc
= c
->metaContact();
276 if ( mc
== ContactList::self()->myself() )
278 mc
->removeContact( c
);
280 if ( mc
->contacts().count() == 0 ) //we can delete the metacontact
282 //get the first group and it's members
283 Group
* group
= mc
->groups().first();
284 MetaContact::List groupMembers
= group
->members();
285 ContactList::self()->removeMetaContact( mc
);
286 if ( groupMembers
.count() == 1 && groupMembers
.indexOf( mc
) != -1 )
287 ContactList::self()->removeGroup( group
);
291 // Clean up the account list
292 d
->accounts
.removeAll( account
);
294 // Clean up configuration
295 configgroup
->deleteGroup();
300 foreach( Account
*account
, d
->accounts
)
302 if( account
->protocol() == protocol
)
305 //there is nomore account from the protocol, we can unload it
307 // FIXME: pluginId() should return the internal name and not the class name, so
308 // we can get rid of this hack - Olivier/Martijn
309 QString protocolName
= protocol
->pluginId().remove( QString::fromLatin1( "Protocol" ) ).toLower();
311 PluginManager::self()->setPluginEnabled( protocolName
, false );
312 PluginManager::self()->unloadPlugin( protocolName
);
315 void AccountManager::save()
318 qSort( d
->accounts
.begin(), d
->accounts
.end(), compareAccountsByPriority
);
320 for ( QListIterator
<Account
*> it( d
->accounts
); it
.hasNext(); )
322 Account
*a
= it
.next();
323 KConfigGroup
*config
= a
->configGroup();
325 config
->writeEntry( "Protocol", a
->protocol()->pluginId() );
326 config
->writeEntry( "AccountId", a
->accountId() );
329 KGlobal::config()->sync();
332 void AccountManager::load()
334 connect( PluginManager::self(), SIGNAL( pluginLoaded( Kopete::Plugin
* ) ),
335 this, SLOT( slotPluginLoaded( Kopete::Plugin
* ) ) );
337 // Iterate over all groups that start with "Account_" as those are accounts
338 // and load the required protocols if the account is enabled.
339 // Don't try to optimize duplicate calls out, the plugin queue is smart enough
340 // (and fast enough) to handle that without adding complexity here
341 KSharedConfig::Ptr config
= KGlobal::config();
342 QStringList accountGroups
= config
->groupList().filter( QRegExp( QString::fromLatin1( "^Account_" ) ) );
343 for ( QStringList::Iterator it
= accountGroups
.begin(); it
!= accountGroups
.end(); ++it
)
345 KConfigGroup
cg( config
, *it
);
347 QString protocol
= cg
.readEntry( "Protocol", QString() );
348 if ( protocol
.endsWith( QString::fromLatin1( "Protocol" ) ) )
349 protocol
= QString::fromLatin1( "kopete_" ) + protocol
.toLower().remove( QString::fromLatin1( "protocol" ) );
351 if ( cg
.readEntry( "Enabled", true ) )
352 PluginManager::self()->loadPlugin( protocol
, PluginManager::LoadAsync
);
356 void AccountManager::slotPluginLoaded( Plugin
*plugin
)
358 Protocol
* protocol
= dynamic_cast<Protocol
*>( plugin
);
362 // Iterate over all groups that start with "Account_" as those are accounts
363 // and parse them if they are from this protocol
364 KSharedConfig::Ptr config
= KGlobal::config();
365 QStringList accountGroups
= config
->groupList().filter( QRegExp( QString::fromLatin1( "^Account_" ) ) );
366 for ( QStringList::Iterator it
= accountGroups
.begin(); it
!= accountGroups
.end(); ++it
)
368 KConfigGroup
cg( config
, *it
);
370 if ( cg
.readEntry( "Protocol" ) != protocol
->pluginId() )
373 // There's no GUI for this, but developers may want to disable an account.
374 if ( !cg
.readEntry( "Enabled", true ) )
377 QString accountId
= cg
.readEntry( "AccountId", QString() );
378 if ( accountId
.isEmpty() )
381 "Not creating account for empty accountId." << endl
;
386 "Creating account for '" << accountId
<< "'" << endl
;
388 Account
*account
= 0L;
389 account
= registerAccount( protocol
->createNewAccount( accountId
) );
393 "Failed to create account for '" << accountId
<< "'" << endl
;
396 // the account's Identity must be set here instead of in the Kopete::Account ctor, because there the
397 // identity cannot pick up any state set in the derived Account ctor
398 Identity
*identity
= Kopete::IdentityManager::self()->findIdentity( account
->configGroup()->readEntry("Identity", QString()) );
399 // if the identity was not found, use the default one which will for sure exist
400 // FIXME: get rid of this, the account's identity should always exist at this point
403 kWarning( 14010 ) << "No identity for account " << accountId
<< ": falling back to default";
404 identity
= Kopete::IdentityManager::self()->defaultIdentity();
406 account
->setIdentity( identity
);
410 void AccountManager::slotAccountOnlineStatusChanged(Contact
*c
,
411 const OnlineStatus
&oldStatus
, const OnlineStatus
&newStatus
)
413 Account
*account
= c
->account();
418 emit
accountOnlineStatusChanged(account
, oldStatus
, newStatus
);
421 void AccountManager::networkConnected()
423 if ( Kopete::BehaviorSettings::self()->autoConnect() )
424 setOnlineStatus( Kopete::OnlineStatusManager::Online
, QString(), ConnectIfOffline
);
427 void AccountManager::networkDisconnected()
429 setOnlineStatus( Kopete::OnlineStatusManager::Offline
);
432 } //END namespace Kopete
434 #include "kopeteaccountmanager.moc"
435 // vim: set noet ts=4 sts=4 sw=4:
436 // kate: tab-width 4; indent-mode csands;