summaryrefslogtreecommitdiffstats
path: root/kopete/protocols/oscar/icq/icqaccount.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kopete/protocols/oscar/icq/icqaccount.cpp')
-rw-r--r--kopete/protocols/oscar/icq/icqaccount.cpp529
1 files changed, 529 insertions, 0 deletions
diff --git a/kopete/protocols/oscar/icq/icqaccount.cpp b/kopete/protocols/oscar/icq/icqaccount.cpp
new file mode 100644
index 00000000..9a071442
--- /dev/null
+++ b/kopete/protocols/oscar/icq/icqaccount.cpp
@@ -0,0 +1,529 @@
+/*
+ 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 <qfile.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 )
+{
+ QObject::connect( acct->engine(), SIGNAL( loggedIn() ), this, SLOT( fetchShortInfo() ) );
+ QObject::connect( acct->engine(), SIGNAL( receivedIcqShortInfo( const QString& ) ),
+ this, SLOT( receivedShortInfo( const QString& ) ) );
+}
+
+void ICQMyselfContact::userInfoUpdated()
+{
+ DWORD extendedStatus = details().extendedStatus();
+ kdDebug( OSCAR_ICQ_DEBUG ) << k_funcinfo << "extendedStatus is " << QString::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 QString& 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, QString 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;
+
+ QString nickName = configGroup()->readEntry("NickName", QString::null);
+ mWebAware = configGroup()->readBoolEntry( "WebAware", false );
+ mHideIP = configGroup()->readBoolEntry( "HideIP", true );
+ mInitialStatusMessage = QString::null;
+
+ QObject::connect( Kopete::ContactList::self(), SIGNAL( globalIdentityChanged( const QString&, const QVariant& ) ),
+ this, SLOT( slotGlobalIdentityChanged( const QString&, const QVariant& ) ) );
+
+ QObject::connect( this, SIGNAL( buddyIconChanged() ), this, 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, QString::null);
+ }*/
+}
+
+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, 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, SLOT( slotSetVisiblility() ), this,
+ "ICQAccount::mActionSetVisibility") );
+ //actionMenu->insert( new KToggleAction( i18n( "Send &SMS..." ), 0, 0, this, SLOT( slotSendSMS() ), this, "ICQAccount::mActionSendSMS") );
+
+ return actionMenu;
+}
+
+
+void ICQAccount::connectWithPassword( const QString &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() );
+ QString icqNumber = accountId();
+ kdDebug(14153) << k_funcinfo << "Logging in as " << icqNumber << endl ;
+ QString server = configGroup()->readEntry( "Server", QString::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 = QString::null;
+ }
+}
+
+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() );
+
+ QDictIterator<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() );
+ QObject::connect( m_visibilityDialog, SIGNAL( closing() ),
+ this, SLOT( slotVisibilityDialogClosed() ) );
+
+ //add all contacts;
+ OscarVisibilityDialog::ContactMap contactMap;
+ //temporary map for faster lookup of contactId
+ QMap<QString, QString> revContactMap;
+
+ QValueList<Oscar::SSI> contactList = engine()->ssiManager()->contactList();
+ QValueList<Oscar::SSI>::const_iterator it, cEnd = contactList.constEnd();
+
+ for ( it = contactList.constBegin(); it != cEnd; ++it )
+ {
+ QString contactId = ( *it ).name();
+
+ OscarContact* oc = dynamic_cast<OscarContact*>( contacts()[( *it ).name()] );
+ if ( oc )
+ { //for better orientation in lists use nickName and icq number
+ QString 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
+ QStringList 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 QString &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 QString &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 QString &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 QString& 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 QString &contactId, Kopete::MetaContact *parentContact, const SSI& ssiItem )
+{
+ ICQContact* contact = new ICQContact( this, contactId, parentContact, QString::null, ssiItem );
+ if ( !ssiItem.alias().isEmpty() )
+ contact->setProperty( Kopete::Global::Properties::self()->nickName(), ssiItem.alias() );
+
+ if ( isConnected() )
+ contact->loggedIn();
+
+ return contact;
+}
+
+QString ICQAccount::sanitizedMessage( const QString& message )
+{
+ return Kopete::Message::escape( message );
+}
+
+
+void ICQAccount::slotGlobalIdentityChanged( const QString& key, const QVariant& 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
+ QObject::disconnect( engine(), SIGNAL( iconServerConnected() ), this, SLOT( slotBuddyIconChanged() ) );
+ if ( !engine()->isActive() )
+ {
+ QObject::connect( engine(), SIGNAL( iconServerConnected() ), this, SLOT( slotBuddyIconChanged() ) );
+ return;
+ }
+
+ QString 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
+ QValueList<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
+ {
+ QFile iconFile( photoPath );
+ iconFile.open( IO_ReadOnly );
+
+ KMD5 iconHash;
+ iconHash.update( 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;
+
+ QValueList<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;
+ QValueList<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;