You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdenetwork/kopete/libkopete/kopeteaccountmanager.cpp

441 lines
12 KiB

/*
kopeteaccountmanager.cpp - Kopete Account Manager
Copyright (c) 2002-2003 by Martijn Klingens <klingens@kde.org>
Copyright (c) 2003-2004 by Olivier Goffart <ogoffart @ kde.org>
Kopete (c) 2002-2004 by the Kopete developers <kopete-devel@kde.org>
*************************************************************************
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
*************************************************************************
*/
#include "kopeteaccountmanager.h"
#include <tqapplication.h>
#include <tqregexp.h>
#include <tqtimer.h>
#include <kconfig.h>
#include <kdebug.h>
#include <kglobal.h>
#include <kplugininfo.h>
#include "kopeteaccount.h"
#include "kopeteaway.h"
#include "kopeteprotocol.h"
#include "kopetecontact.h"
#include "kopetecontactlist.h"
#include "kopetepluginmanager.h"
#include "kopeteonlinestatus.h"
#include "kopeteonlinestatusmanager.h"
#include "kopetemetacontact.h"
#include "kopetegroup.h"
namespace Kopete {
class AccountManager::Private
{
public:
class AccountPtrList : public TQPtrList<Account>
{
protected:
int compareItems( AccountPtrList::Item a, AccountPtrList::Item b )
{
uint priority1 = static_cast<Account*>(a)->priority();
uint priority2 = static_cast<Account*>(b)->priority();
if( a==b ) //two account are equal only if they are equal :-)
return 0; // remember than an account can be only once on the list, but two account may have the same priority when loading
else if( priority1 > priority2 )
return 1;
else
return -1;
}
} accounts;
};
AccountManager * AccountManager::s_self = 0L;
AccountManager * AccountManager::self()
{
if ( !s_self )
s_self = new AccountManager;
return s_self;
}
AccountManager::AccountManager()
: TQObject( tqApp, "KopeteAccountManager" )
{
d = new Private;
}
AccountManager::~AccountManager()
{
s_self = 0L;
delete d;
}
bool AccountManager::isAnyAccountConnected()
{
for ( TQPtrListIterator<Account> it( d->accounts ); it.current(); ++it )
{
if(it.current()->isConnected())
return true;
}
return false;
}
void AccountManager::connectAll()
{
for ( TQPtrListIterator<Account> it( d->accounts ); it.current(); ++it )
if(!it.current()->excludeConnect())
it.current()->connect();
}
void AccountManager::setAvailableAll( const TQString &awayReason )
{
Away::setGlobalAway( false );
bool anyConnected = isAnyAccountConnected();
for ( TQPtrListIterator<Account> it( d->accounts ); it.current(); ++it )
{
if ( anyConnected )
{
if ( it.current()->isConnected() )
it.current()->setAway( false, awayReason );
}
else
if(!it.current()->excludeConnect())
it.current()->connect();
}
}
void AccountManager::disconnectAll()
{
for ( TQPtrListIterator<Account> it( d->accounts ); it.current(); ++it )
it.current()->disconnect();
}
void AccountManager::setAwayAll( const TQString &awayReason, bool away )
{
Away::setGlobalAway( true );
bool anyConnected = isAnyAccountConnected();
for ( TQPtrListIterator<Account> it( d->accounts ); it.current(); ++it )
{
// FIXME: ICQ's invisible online should be set to invisible away
Contact *self = it.current()->myself();
bool isInvisible = self && self->onlinetqStatus().status() == OnlineStatus::Invisible;
if ( anyConnected )
{
if ( it.current()->isConnected() && !isInvisible )
it.current()->setAway( away, awayReason );
}
else
{
if ( !it.current()->excludeConnect() && !isInvisible )
it.current()->setAway( away, awayReason );
}
}
}
void AccountManager::setOnlineStatus( uint category , const TQString& awayMessage, uint flags )
{
OnlineStatusManager::Categories katgor=(OnlineStatusManager::Categories)category;
bool anyConnected = isAnyAccountConnected();
for ( TQPtrListIterator<Account> it( d->accounts ); it.current(); ++it )
{
Account *account = it.current();
Kopete::OnlineStatus status = OnlineStatusManager::self()->onlinetqStatus(account->protocol() , katgor);
if ( anyConnected )
{
if ( account->isConnected() || ( (flags & ConnectIfOffline) && !account->excludeConnect() ) )
account->setOnlineStatus( status , awayMessage );
}
else
{
if ( !account->excludeConnect() )
account->setOnlineStatus( status , awayMessage );
}
}
}
TQColor AccountManager::guessColor( Protocol *protocol ) const
{
// In a perfect wold, we should check if the color is actually not used by the account.
// Anyway, this is not really required, It would be a difficult job for about nothing more.
// -- Olivier
int protocolCount = 0;
for ( TQPtrListIterator<Account> it( d->accounts ); it.current(); ++it )
{
if ( it.current()->protocol()->pluginId() == protocol->pluginId() )
protocolCount++;
}
// let's figure a color
TQColor color;
switch ( protocolCount % 7 )
{
case 0:
color = TQColor();
break;
case 1:
color = TQt::red;
break;
case 2:
color = TQt::green;
break;
case 3:
color = TQt::blue;
break;
case 4:
color = TQt::yellow;
break;
case 5:
color = TQt::magenta;
break;
case 6:
color = TQt::cyan;
break;
}
return color;
}
Account* AccountManager::registerAccount( Account *account )
{
if( !account || d->accounts.tqcontains( account ) )
return account;
if( account->accountId().isEmpty() )
{
account->deleteLater();
return 0L;
}
// If this account already exists, do nothing
for ( TQPtrListIterator<Account> it( d->accounts ); it.current(); ++it )
{
if ( ( account->protocol() == it.current()->protocol() ) && ( account->accountId() == it.current()->accountId() ) )
{
account->deleteLater();
return 0L;
}
}
d->accounts.append( account );
d->accounts.sort();
// Connect to the account's status changed signal
connect(account->myself(), TQT_SIGNAL(onlineStatusChanged(Kopete::Contact *,
const Kopete::OnlineStatus &, const Kopete::OnlineStatus &)),
this, TQT_SLOT(slotAccountOnlineStatusChanged(Kopete::Contact *,
const Kopete::OnlineStatus &, const Kopete::OnlineStatus &)));
connect(account, TQT_SIGNAL(accountDestroyed(const Kopete::Account *)) , this, TQT_SLOT( unregisterAccount(const Kopete::Account *) ));
emit accountRegistered( account );
return account;
}
void AccountManager::unregisterAccount( const Account *account )
{
kdDebug( 14010 ) << k_funcinfo << "Unregistering account " << account->accountId() << endl;
d->accounts.remove( account );
emit accountUnregistered( account );
}
const TQPtrList<Account>& AccountManager::accounts() const
{
return d->accounts;
}
TQDict<Account> AccountManager::accounts( const Protocol *protocol ) const
{
TQDict<Account> dict;
for ( TQPtrListIterator<Account> it( d->accounts ); it.current(); ++it )
{
if ( it.current()->protocol() == protocol && !it.current()->accountId().isNull() )
dict.insert( it.current()->accountId(), it.current() );
}
return dict;
}
Account * AccountManager::findAccount( const TQString &protocolId, const TQString &accountId )
{
for ( TQPtrListIterator<Account> it( d->accounts ); it.current(); ++it )
{
if ( it.current()->protocol()->pluginId() == protocolId && it.current()->accountId() == accountId )
return it.current();
}
return 0L;
}
void AccountManager::removeAccount( Account *account )
{
if(!account->removeAccount())
return;
Protocol *protocol = account->protocol();
KConfigGroup *configgroup = account->configGroup();
// Clean up the contact list
TQDictIterator<Kopete::Contact> it( account->contacts() );
for ( ; it.current(); ++it )
{
Contact* c = it.current();
MetaContact* mc = c->metaContact();
if ( mc == ContactList::self()->myself() )
continue;
mc->removeContact( c );
c->deleteLater();
if ( mc->contacts().count() == 0 ) //we can delete the metacontact
{
//get the first group and it's members
Group* group = mc->groups().first();
TQPtrList<MetaContact> groupMembers = group->members();
ContactList::self()->removeMetaContact( mc );
if ( groupMembers.count() == 1 && groupMembers.tqfindRef( mc ) != -1 )
ContactList::self()->removeGroup( group );
}
}
// Clean up the account list
d->accounts.remove( account );
// Clean up configuration
configgroup->deleteGroup();
configgroup->sync();
delete account;
if ( accounts( protocol ).isEmpty() )
{
// FIXME: pluginId() should return the internal name and not the class name, so
// we can get rid of this hack - Olivier/Martijn
TQString protocolName = protocol->pluginId().remove( TQString::tqfromLatin1( "Protocol" ) ).lower();
PluginManager::self()->setPluginEnabled( protocolName, false );
PluginManager::self()->unloadPlugin( protocolName );
}
}
void AccountManager::save()
{
//kdDebug( 14010 ) << k_funcinfo << endl;
d->accounts.sort();
for ( TQPtrListIterator<Account> it( d->accounts ); it.current(); ++it )
{
KConfigBase *config = it.current()->configGroup();
config->writeEntry( "Protocol", it.current()->protocol()->pluginId() );
config->writeEntry( "AccountId", it.current()->accountId() );
}
KGlobal::config()->sync();
}
void AccountManager::load()
{
connect( PluginManager::self(), TQT_SIGNAL( pluginLoaded( Kopete::Plugin * ) ),
this, TQT_SLOT( slotPluginLoaded( Kopete::Plugin * ) ) );
// Iterate over all groups that start with "Account_" as those are accounts
// and load the required protocols if the account is enabled.
// Don't try to optimize duplicate calls out, the plugin queue is smart enough
// (and fast enough) to handle that without adding complexity here
KConfig *config = KGlobal::config();
TQStringList accountGroups = config->groupList().grep( TQRegExp( TQString::tqfromLatin1( "^Account_" ) ) );
for ( TQStringList::Iterator it = accountGroups.begin(); it != accountGroups.end(); ++it )
{
config->setGroup( *it );
TQString protocol = config->readEntry( "Protocol" );
if ( protocol.endsWith( TQString::tqfromLatin1( "Protocol" ) ) )
protocol = TQString::tqfromLatin1( "kopete_" ) + protocol.lower().remove( TQString::tqfromLatin1( "protocol" ) );
if ( config->readBoolEntry( "Enabled", true ) )
PluginManager::self()->loadPlugin( protocol, PluginManager::LoadAsync );
}
}
void AccountManager::slotPluginLoaded( Plugin *plugin )
{
Protocol* protocol = dynamic_cast<Protocol*>( plugin );
if ( !protocol )
return;
// Iterate over all groups that start with "Account_" as those are accounts
// and parse them if they are from this protocol
KConfig *config = KGlobal::config();
TQStringList accountGroups = config->groupList().grep( TQRegExp( TQString::tqfromLatin1( "^Account_" ) ) );
for ( TQStringList::Iterator it = accountGroups.begin(); it != accountGroups.end(); ++it )
{
config->setGroup( *it );
if ( config->readEntry( "Protocol" ) != protocol->pluginId() )
continue;
// There's no GUI for this, but developers may want to disable an account.
if ( !config->readBoolEntry( "Enabled", true ) )
continue;
TQString accountId = config->readEntry( "AccountId" );
if ( accountId.isEmpty() )
{
kdWarning( 14010 ) << k_funcinfo <<
"Not creating account for empty accountId." << endl;
continue;
}
kdDebug( 14010 ) << k_funcinfo <<
"Creating account for '" << accountId << "'" << endl;
Account *account = 0L;
account = registerAccount( protocol->createNewAccount( accountId ) );
if ( !account )
{
kdWarning( 14010 ) << k_funcinfo <<
"Failed to create account for '" << accountId << "'" << endl;
continue;
}
}
}
void AccountManager::slotAccountOnlineStatusChanged(Contact *c,
const OnlineStatus &oldtqStatus, const OnlineStatus &newtqStatus)
{
Account *account = c->account();
if (!account)
return;
//kdDebug(14010) << k_funcinfo << endl;
emit accountOnlineStatusChanged(account, oldtqStatus, newtqStatus);
}
} //END namespace Kopete
#include "kopeteaccountmanager.moc"
// vim: set noet ts=4 sts=4 sw=4:
// kate: tab-width 4; indent-mode csands;