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.
530 lines
16 KiB
530 lines
16 KiB
/*
|
|
icqaccount.cpp - ICQ Account Class
|
|
|
|
Copyright (c) 2002 by Chris TenHarmsel <tenharmsel@staticmethod.net>
|
|
Copyright (c) 2004 by Richard Smith <kde@metafoo.co.uk>
|
|
Kopete (c) 2002-2004 by the Kopete developers <kopete-devel@kde.org>
|
|
|
|
*************************************************************************
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
*************************************************************************
|
|
*/
|
|
|
|
#include <tqfile.h>
|
|
|
|
#include <kconfig.h>
|
|
#include <kdebug.h>
|
|
#include <klocale.h>
|
|
#include <kpopupmenu.h>
|
|
#include <kmdcodec.h>
|
|
#include <kmessagebox.h>
|
|
|
|
#include "kopeteawayaction.h"
|
|
#include "kopetemessage.h"
|
|
#include "kopetecontactlist.h"
|
|
#include "kopeteuiglobal.h"
|
|
|
|
#include "client.h"
|
|
#include "icquserinfo.h"
|
|
#include "oscarsettings.h"
|
|
#include "oscarutils.h"
|
|
#include "ssimanager.h"
|
|
|
|
#include "icqcontact.h"
|
|
#include "icqprotocol.h"
|
|
#include "icqaccount.h"
|
|
|
|
#include "oscarvisibilitydialog.h"
|
|
|
|
ICQMyselfContact::ICQMyselfContact( ICQAccount *acct ) : OscarMyselfContact( acct )
|
|
{
|
|
TQObject::connect( acct->engine(), TQT_SIGNAL( loggedIn() ), this, TQT_SLOT( fetchShortInfo() ) );
|
|
TQObject::connect( acct->engine(), TQT_SIGNAL( receivedIcqShortInfo( const TQString& ) ),
|
|
this, TQT_SLOT( receivedShortInfo( const TQString& ) ) );
|
|
}
|
|
|
|
void ICQMyselfContact::userInfoUpdated()
|
|
{
|
|
DWORD extendedStatus = details().extendedStatus();
|
|
kdDebug( OSCAR_ICQ_DEBUG ) << k_funcinfo << "extendedStatus is " << TQString::number( extendedStatus, 16 ) << endl;
|
|
ICQ::Presence presence = ICQ::Presence::fromOscarStatus( extendedStatus & 0xffff );
|
|
setOnlineStatus( presence.toOnlineStatus() );
|
|
setProperty( Kopete::Global::Properties::self()->awayMessage(), static_cast<ICQAccount*>( account() )->engine()->statusMessage() );
|
|
}
|
|
|
|
void ICQMyselfContact::receivedShortInfo( const TQString& contact )
|
|
{
|
|
if ( Oscar::normalize( contact ) != Oscar::normalize( contactId() ) )
|
|
return;
|
|
|
|
ICQShortInfo shortInfo = static_cast<ICQAccount*>( account() )->engine()->getShortInfo( contact );
|
|
if ( !shortInfo.nickname.isEmpty() )
|
|
{
|
|
setProperty( Kopete::Global::Properties::self()->nickName(), static_cast<ICQAccount*>( account() )->defaultCodec()->toUnicode( shortInfo.nickname ) );
|
|
}
|
|
}
|
|
|
|
void ICQMyselfContact::fetchShortInfo()
|
|
{
|
|
static_cast<ICQAccount*>( account() )->engine()->requestShortInfo( contactId() );
|
|
}
|
|
|
|
ICQAccount::ICQAccount(Kopete::Protocol *parent, TQString accountID, const char *name)
|
|
: OscarAccount(parent, accountID, name, true)
|
|
{
|
|
kdDebug(14152) << k_funcinfo << accountID << ": Called."<< endl;
|
|
setMyself( new ICQMyselfContact( this ) );
|
|
myself()->setOnlineStatus( ICQ::Presence( ICQ::Presence::Offline, ICQ::Presence::Visible ).toOnlineStatus() );
|
|
|
|
m_visibilityDialog = 0;
|
|
|
|
TQString nickName = configGroup()->readEntry("NickName", TQString());
|
|
mWebAware = configGroup()->readBoolEntry( "WebAware", false );
|
|
mHideIP = configGroup()->readBoolEntry( "HideIP", true );
|
|
mInitialStatusMessage = TQString();
|
|
|
|
TQObject::connect( Kopete::ContactList::self(), TQT_SIGNAL( globalIdentityChanged( const TQString&, const TQVariant& ) ),
|
|
this, TQT_SLOT( slotGlobalIdentityChanged( const TQString&, const TQVariant& ) ) );
|
|
|
|
TQObject::connect( this, TQT_SIGNAL( buddyIconChanged() ), this, TQT_SLOT( slotBuddyIconChanged() ) );
|
|
|
|
//setIgnoreUnknownContacts(pluginData(protocol(), "IgnoreUnknownContacts").toUInt() == 1);
|
|
|
|
/* FIXME: need to do this when web aware or hide ip change
|
|
if(isConnected() && (oldhideip != mHideIP || oldwebaware != mWebAware))
|
|
{
|
|
kdDebug(14153) << k_funcinfo <<
|
|
"sending status to reflect HideIP and WebAware settings" << endl;
|
|
//setStatus(mStatus, TQString());
|
|
}*/
|
|
}
|
|
|
|
ICQAccount::~ICQAccount()
|
|
{
|
|
}
|
|
|
|
ICQProtocol* ICQAccount::protocol()
|
|
{
|
|
return static_cast<ICQProtocol*>(OscarAccount::protocol());
|
|
}
|
|
|
|
|
|
ICQ::Presence ICQAccount::presence()
|
|
{
|
|
return ICQ::Presence::fromOnlineStatus( myself()->onlineStatus() );
|
|
}
|
|
|
|
|
|
KActionMenu* ICQAccount::actionMenu()
|
|
{
|
|
KActionMenu* actionMenu = Kopete::Account::actionMenu();
|
|
|
|
actionMenu->popupMenu()->insertSeparator();
|
|
|
|
KToggleAction* actionInvisible =
|
|
new KToggleAction( i18n( "In&visible" ),
|
|
ICQ::Presence( presence().type(), ICQ::Presence::Invisible ).toOnlineStatus().iconFor( this ),
|
|
0, this, TQT_SLOT( slotToggleInvisible() ), this );
|
|
actionInvisible->setChecked( presence().visibility() == ICQ::Presence::Invisible );
|
|
actionMenu->insert( actionInvisible );
|
|
|
|
actionMenu->popupMenu()->insertSeparator();
|
|
actionMenu->insert( new KToggleAction( i18n( "Set Visibility..." ), 0, 0,
|
|
this, TQT_SLOT( slotSetVisiblility() ), this,
|
|
"ICQAccount::mActionSetVisibility") );
|
|
//actionMenu->insert( new KToggleAction( i18n( "Send &SMS..." ), 0, 0, this, TQT_SLOT( slotSendSMS() ), this, "ICQAccount::mActionSendSMS") );
|
|
|
|
return actionMenu;
|
|
}
|
|
|
|
|
|
void ICQAccount::connectWithPassword( const TQString &password )
|
|
{
|
|
if ( password.isNull() )
|
|
return;
|
|
|
|
kdDebug(14153) << k_funcinfo << "accountId='" << accountId() << "'" << endl;
|
|
|
|
Kopete::OnlineStatus status = initialStatus();
|
|
if ( status == Kopete::OnlineStatus() &&
|
|
status.status() == Kopete::OnlineStatus::Unknown )
|
|
//use default online in case of invalid online status for connecting
|
|
status = Kopete::OnlineStatus( Kopete::OnlineStatus::Online );
|
|
ICQ::Presence pres = ICQ::Presence::fromOnlineStatus( status );
|
|
bool accountIsOffline = ( presence().type() == ICQ::Presence::Offline ||
|
|
myself()->onlineStatus() == protocol()->statusManager()->connectingStatus() );
|
|
|
|
if ( accountIsOffline )
|
|
{
|
|
myself()->setOnlineStatus( protocol()->statusManager()->connectingStatus() );
|
|
TQString icqNumber = accountId();
|
|
kdDebug(14153) << k_funcinfo << "Logging in as " << icqNumber << endl ;
|
|
TQString server = configGroup()->readEntry( "Server", TQString::fromLatin1( "login.oscar.aol.com" ) );
|
|
uint port = configGroup()->readNumEntry( "Port", 5190 );
|
|
Connection* c = setupConnection( server, port );
|
|
|
|
//set up the settings for the account
|
|
Oscar::Settings* oscarSettings = engine()->clientSettings();
|
|
oscarSettings->setWebAware( configGroup()->readBoolEntry( "WebAware", false ) );
|
|
oscarSettings->setHideIP( configGroup()->readBoolEntry( "HideIP", true ) );
|
|
//FIXME: also needed for the other call to setStatus (in setPresenceTarget)
|
|
DWORD status = pres.toOscarStatus();
|
|
|
|
if ( !mHideIP )
|
|
status |= ICQ::StatusCode::SHOWIP;
|
|
if ( mWebAware )
|
|
status |= ICQ::StatusCode::WEBAWARE;
|
|
|
|
engine()->setStatus( status, mInitialStatusMessage );
|
|
updateVersionUpdaterStamp();
|
|
engine()->start( server, port, accountId(), password );
|
|
engine()->connectToServer( c, server, true /* doAuth */ );
|
|
|
|
mInitialStatusMessage = TQString();
|
|
}
|
|
}
|
|
|
|
void ICQAccount::disconnected( DisconnectReason reason )
|
|
{
|
|
kdDebug(14153) << k_funcinfo << "Attempting to set status offline" << endl;
|
|
ICQ::Presence presOffline = ICQ::Presence( ICQ::Presence::Offline, presence().visibility() );
|
|
myself()->setOnlineStatus( presOffline.toOnlineStatus() );
|
|
|
|
TQDictIterator<Kopete::Contact> it( contacts() );
|
|
for( ; it.current(); ++it )
|
|
{
|
|
OscarContact* oc = dynamic_cast<OscarContact*>( it.current() );
|
|
if ( oc )
|
|
{
|
|
if ( oc->ssiItem().waitingAuth() )
|
|
oc->setOnlineStatus( protocol()->statusManager()->waitingForAuth() );
|
|
else
|
|
oc->setOnlineStatus( ICQ::Presence( ICQ::Presence::Offline, ICQ::Presence::Visible ).toOnlineStatus() );
|
|
}
|
|
}
|
|
|
|
OscarAccount::disconnected( reason );
|
|
}
|
|
|
|
|
|
void ICQAccount::slotToggleInvisible()
|
|
{
|
|
using namespace ICQ;
|
|
setInvisible( (presence().visibility() == Presence::Visible) ? Presence::Invisible : Presence::Visible );
|
|
}
|
|
|
|
void ICQAccount::slotSetVisiblility()
|
|
{
|
|
if( !isConnected() )
|
|
{
|
|
KMessageBox::sorry( Kopete::UI::Global::mainWidget(),
|
|
i18n("You must be online to set users visibility."),
|
|
i18n("ICQ Plugin") );
|
|
return;
|
|
}
|
|
|
|
if ( !m_visibilityDialog )
|
|
{
|
|
m_visibilityDialog = new OscarVisibilityDialog( engine(), Kopete::UI::Global::mainWidget() );
|
|
TQObject::connect( m_visibilityDialog, TQT_SIGNAL( closing() ),
|
|
this, TQT_SLOT( slotVisibilityDialogClosed() ) );
|
|
|
|
//add all contacts;
|
|
OscarVisibilityDialog::ContactMap contactMap;
|
|
//temporary map for faster lookup of contactId
|
|
TQMap<TQString, TQString> revContactMap;
|
|
|
|
TQValueList<Oscar::SSI> contactList = engine()->ssiManager()->contactList();
|
|
TQValueList<Oscar::SSI>::const_iterator it, cEnd = contactList.constEnd();
|
|
|
|
for ( it = contactList.constBegin(); it != cEnd; ++it )
|
|
{
|
|
TQString contactId = ( *it ).name();
|
|
|
|
OscarContact* oc = dynamic_cast<OscarContact*>( contacts()[( *it ).name()] );
|
|
if ( oc )
|
|
{ //for better orientation in lists use nickName and icq number
|
|
TQString screenName( "%1 (%2)" );
|
|
screenName = screenName.arg( oc->nickName(), contactId);
|
|
contactMap.insert( screenName, contactId );
|
|
revContactMap.insert( contactId, screenName );
|
|
}
|
|
else
|
|
{
|
|
contactMap.insert( contactId, contactId );
|
|
revContactMap.insert( contactId, contactId );
|
|
}
|
|
}
|
|
m_visibilityDialog->addContacts( contactMap );
|
|
|
|
//add contacts from visible list
|
|
TQStringList tmpList;
|
|
|
|
contactList = engine()->ssiManager()->visibleList();
|
|
cEnd = contactList.constEnd();
|
|
|
|
for ( it = contactList.constBegin(); it != cEnd; ++it )
|
|
tmpList.append( revContactMap[( *it ).name()] );
|
|
|
|
m_visibilityDialog->addVisibleContacts( tmpList );
|
|
|
|
//add contacts from invisible list
|
|
tmpList.clear();
|
|
|
|
contactList = engine()->ssiManager()->invisibleList();
|
|
cEnd = contactList.constEnd();
|
|
|
|
for ( it = contactList.constBegin(); it != cEnd; ++it )
|
|
tmpList.append( revContactMap[( *it ).name()] );
|
|
|
|
m_visibilityDialog->addInvisibleContacts( tmpList );
|
|
|
|
m_visibilityDialog->resize( 550, 350 );
|
|
m_visibilityDialog->show();
|
|
}
|
|
else
|
|
{
|
|
m_visibilityDialog->raise();
|
|
}
|
|
}
|
|
|
|
void ICQAccount::slotVisibilityDialogClosed()
|
|
{
|
|
m_visibilityDialog->delayedDestruct();
|
|
m_visibilityDialog = 0L;
|
|
}
|
|
|
|
void ICQAccount::setAway( bool away, const TQString &awayReason )
|
|
{
|
|
kdDebug(14153) << k_funcinfo << "account='" << accountId() << "'" << endl;
|
|
if ( away )
|
|
setPresenceType( ICQ::Presence::Away, awayReason );
|
|
else
|
|
setPresenceType( ICQ::Presence::Online );
|
|
}
|
|
|
|
|
|
void ICQAccount::setInvisible( ICQ::Presence::Visibility vis )
|
|
{
|
|
ICQ::Presence pres = presence();
|
|
if ( vis == pres.visibility() )
|
|
return;
|
|
|
|
kdDebug(14153) << k_funcinfo << "changing invisible setting to " << (int)vis << endl;
|
|
setPresenceTarget( ICQ::Presence( pres.type(), vis ) );
|
|
}
|
|
|
|
void ICQAccount::setPresenceType( ICQ::Presence::Type type, const TQString &message )
|
|
{
|
|
ICQ::Presence pres = presence();
|
|
kdDebug(14153) << k_funcinfo << "new type=" << (int)type << ", old type=" << (int)pres.type() << ", new message=" << message << endl;
|
|
//setAwayMessage(awayMessage);
|
|
setPresenceTarget( ICQ::Presence( type, pres.visibility() ), message );
|
|
}
|
|
|
|
void ICQAccount::setPresenceTarget( const ICQ::Presence &newPres, const TQString &message )
|
|
{
|
|
bool targetIsOffline = (newPres.type() == ICQ::Presence::Offline);
|
|
bool accountIsOffline = ( presence().type() == ICQ::Presence::Offline ||
|
|
myself()->onlineStatus() == protocol()->statusManager()->connectingStatus() );
|
|
|
|
if ( targetIsOffline )
|
|
{
|
|
OscarAccount::disconnect();
|
|
// allow toggling invisibility when offline
|
|
myself()->setOnlineStatus( newPres.toOnlineStatus() );
|
|
}
|
|
else if ( accountIsOffline )
|
|
{
|
|
mInitialStatusMessage = message;
|
|
OscarAccount::connect( newPres.toOnlineStatus() );
|
|
}
|
|
else
|
|
{
|
|
engine()->setStatus( newPres.toOscarStatus(), message );
|
|
}
|
|
}
|
|
|
|
|
|
void ICQAccount::setOnlineStatus( const Kopete::OnlineStatus& status, const TQString& reason )
|
|
{
|
|
if ( status.status() == Kopete::OnlineStatus::Invisible )
|
|
{
|
|
// called from outside, i.e. not by our custom action menu entry...
|
|
|
|
if ( presence().type() == ICQ::Presence::Offline )
|
|
{
|
|
// ...when we are offline go online invisible.
|
|
setPresenceTarget( ICQ::Presence( ICQ::Presence::Online, ICQ::Presence::Invisible ) );
|
|
}
|
|
else
|
|
{
|
|
// ...when we are not offline set invisible.
|
|
setInvisible( ICQ::Presence::Invisible );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
setPresenceType( ICQ::Presence::fromOnlineStatus( status ).type(), reason );
|
|
}
|
|
}
|
|
|
|
|
|
OscarContact *ICQAccount::createNewContact( const TQString &contactId, Kopete::MetaContact *parentContact, const SSI& ssiItem )
|
|
{
|
|
ICQContact* contact = new ICQContact( this, contactId, parentContact, TQString(), ssiItem );
|
|
if ( !ssiItem.alias().isEmpty() )
|
|
contact->setProperty( Kopete::Global::Properties::self()->nickName(), ssiItem.alias() );
|
|
|
|
if ( isConnected() )
|
|
contact->loggedIn();
|
|
|
|
return contact;
|
|
}
|
|
|
|
TQString ICQAccount::sanitizedMessage( const TQString& message )
|
|
{
|
|
return Kopete::Message::escape( message );
|
|
}
|
|
|
|
|
|
void ICQAccount::slotGlobalIdentityChanged( const TQString& key, const TQVariant& value )
|
|
{
|
|
//do something with the photo
|
|
kdDebug(14153) << k_funcinfo << "Global identity changed" << endl;
|
|
kdDebug(14153) << k_funcinfo << "key: " << key << endl;
|
|
kdDebug(14153) << k_funcinfo << "value: " << value << endl;
|
|
|
|
if( !configGroup()->readBoolEntry("ExcludeGlobalIdentity", false) )
|
|
{
|
|
if ( key == Kopete::Global::Properties::self()->nickName().key() )
|
|
{
|
|
//edit ssi item to change alias (if possible)
|
|
}
|
|
|
|
if ( key == Kopete::Global::Properties::self()->photo().key() )
|
|
{
|
|
setBuddyIcon( value.toString() );
|
|
}
|
|
}
|
|
}
|
|
|
|
void ICQAccount::slotBuddyIconChanged()
|
|
{
|
|
// need to disconnect because we could end up with many connections
|
|
TQObject::disconnect( engine(), TQT_SIGNAL( iconServerConnected() ), this, TQT_SLOT( slotBuddyIconChanged() ) );
|
|
if ( !engine()->isActive() )
|
|
{
|
|
TQObject::connect( engine(), TQT_SIGNAL( iconServerConnected() ), this, TQT_SLOT( slotBuddyIconChanged() ) );
|
|
return;
|
|
}
|
|
|
|
TQString photoPath = myself()->property( Kopete::Global::Properties::self()->photo() ).value().toString();
|
|
|
|
SSIManager* ssi = engine()->ssiManager();
|
|
Oscar::SSI item = ssi->findItemForIconByRef( 1 );
|
|
|
|
if ( photoPath.isEmpty() )
|
|
{
|
|
if ( item )
|
|
{
|
|
kdDebug(14153) << k_funcinfo << "Removing icon hash item from ssi" << endl;
|
|
Oscar::SSI s(item);
|
|
|
|
//remove hash and alias
|
|
TQValueList<TLV> tList( item.tlvList() );
|
|
TLV t = Oscar::findTLV( tList, 0x00D5 );
|
|
if ( t )
|
|
tList.remove( t );
|
|
|
|
t = Oscar::findTLV( tList, 0x0131 );
|
|
if ( t )
|
|
tList.remove( t );
|
|
|
|
item.setTLVList( tList );
|
|
//s is old, item is new. modification will occur
|
|
engine()->modifySSIItem( s, item );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TQFile iconFile( photoPath );
|
|
iconFile.open( IO_ReadOnly );
|
|
|
|
KMD5 iconHash;
|
|
iconHash.update( *TQT_TQIODEVICE(&iconFile) );
|
|
kdDebug(14153) << k_funcinfo << "hash is :" << iconHash.hexDigest() << endl;
|
|
|
|
//find old item, create updated item
|
|
if ( !item )
|
|
{
|
|
kdDebug(14153) << k_funcinfo << "no existing icon hash item in ssi. creating new" << endl;
|
|
|
|
TLV t;
|
|
t.type = 0x00D5;
|
|
t.data.resize( 18 );
|
|
t.data[0] = 0x01;
|
|
t.data[1] = 0x10;
|
|
memcpy(t.data.data() + 2, iconHash.rawDigest(), 16);
|
|
t.length = t.data.size();
|
|
|
|
//alias, it's always empty
|
|
TLV t2;
|
|
t2.type = 0x0131;
|
|
t2.length = 0;
|
|
|
|
TQValueList<Oscar::TLV> list;
|
|
list.append( t );
|
|
list.append( t2 );
|
|
|
|
Oscar::SSI s( "1", 0, ssi->nextContactId(), ROSTER_BUDDYICONS, list );
|
|
|
|
//item is a non-valid ssi item, so the function will add an item
|
|
kdDebug(14153) << k_funcinfo << "setting new icon item" << endl;
|
|
engine()->modifySSIItem( item, s );
|
|
}
|
|
else
|
|
{ //found an item
|
|
Oscar::SSI s(item);
|
|
kdDebug(14153) << k_funcinfo << "modifying old item in ssi." << endl;
|
|
TQValueList<TLV> tList( item.tlvList() );
|
|
|
|
TLV t = Oscar::findTLV( tList, 0x00D5 );
|
|
if ( t )
|
|
tList.remove( t );
|
|
else
|
|
t.type = 0x00D5;
|
|
|
|
t.data.resize( 18 );
|
|
t.data[0] = 0x01;
|
|
t.data[1] = 0x10;
|
|
memcpy(t.data.data() + 2, iconHash.rawDigest(), 16);
|
|
t.length = t.data.size();
|
|
tList.append( t );
|
|
|
|
//add empty alias
|
|
t = Oscar::findTLV( tList, 0x0131 );
|
|
if ( !t )
|
|
{
|
|
t.type = 0x0131;
|
|
t.length = 0;
|
|
tList.append( t );
|
|
}
|
|
|
|
item.setTLVList( tList );
|
|
//s is old, item is new. modification will occur
|
|
engine()->modifySSIItem( s, item );
|
|
}
|
|
iconFile.close();
|
|
}
|
|
}
|
|
|
|
#include "icqaccount.moc"
|
|
|
|
//kate: tab-width 4; indent-mode csands;
|