From 91ba38a1df42b56caa73babc90ffa4f674c000d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sl=C3=A1vek=20Banko?= Date: Tue, 10 Dec 2019 01:24:17 +0100 Subject: kopete: Restore the AIM protocol because a replacement AIM server was created. This reverts commits 036b0229db and dc34f9c391. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Slávek Banko --- kopete/protocols/oscar/liboscar/CMakeLists.txt | 2 +- kopete/protocols/oscar/liboscar/Makefile.am | 2 +- kopete/protocols/oscar/liboscar/aimlogintask.cpp | 254 +++++++++++++++++++++ kopete/protocols/oscar/liboscar/aimlogintask.h | 83 +++++++ kopete/protocols/oscar/liboscar/buddyicontask.cpp | 42 +++- kopete/protocols/oscar/liboscar/buddyicontask.h | 2 + .../oscar/liboscar/changevisibilitytask.h | 2 +- kopete/protocols/oscar/liboscar/client.cpp | 81 ++++++- kopete/protocols/oscar/liboscar/client.h | 22 ++ .../protocols/oscar/liboscar/clientreadytask.cpp | 35 ++- kopete/protocols/oscar/liboscar/connection.cpp | 5 + kopete/protocols/oscar/liboscar/connection.h | 1 + kopete/protocols/oscar/liboscar/logintask.cpp | 52 ++++- kopete/protocols/oscar/liboscar/logintask.h | 5 +- kopete/protocols/oscar/liboscar/oscartypes.h | 4 + kopete/protocols/oscar/liboscar/profiletask.cpp | 40 +++- kopete/protocols/oscar/liboscar/profiletask.h | 3 +- .../protocols/oscar/liboscar/sendmessagetask.cpp | 32 ++- .../oscar/liboscar/serverversionstask.cpp | 21 +- .../protocols/oscar/liboscar/tests/logintest.cpp | 1 + .../oscar/liboscar/tests/ssigrouptest.cpp | 1 + .../oscar/liboscar/tests/userinfotest.cpp | 1 + 22 files changed, 636 insertions(+), 55 deletions(-) create mode 100644 kopete/protocols/oscar/liboscar/aimlogintask.cpp create mode 100644 kopete/protocols/oscar/liboscar/aimlogintask.h (limited to 'kopete/protocols/oscar/liboscar') diff --git a/kopete/protocols/oscar/liboscar/CMakeLists.txt b/kopete/protocols/oscar/liboscar/CMakeLists.txt index 102ac0ff..6053541f 100644 --- a/kopete/protocols/oscar/liboscar/CMakeLists.txt +++ b/kopete/protocols/oscar/liboscar/CMakeLists.txt @@ -27,7 +27,7 @@ tde_add_library( oscar STATIC_PIC AUTOMOC inputprotocolbase.cpp coreprotocol.cpp flapprotocol.cpp snacprotocol.cpp transfer.cpp rtf.cc bytestream.cpp oscarclientstream.cpp safedelete.cpp stream.cpp oscarconnector.cpp - oscarbytestream.cpp buffer.cpp md5.c logintask.cpp + oscarbytestream.cpp buffer.cpp md5.c logintask.cpp aimlogintask.cpp icqlogintask.cpp closeconnectiontask.cpp rateclassmanager.cpp serverversionstask.cpp rateinfotask.cpp errortask.cpp locationrightstask.cpp profiletask.cpp blmlimitstask.cpp diff --git a/kopete/protocols/oscar/liboscar/Makefile.am b/kopete/protocols/oscar/liboscar/Makefile.am index 5a0e0d97..3759a85c 100644 --- a/kopete/protocols/oscar/liboscar/Makefile.am +++ b/kopete/protocols/oscar/liboscar/Makefile.am @@ -8,7 +8,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/kopete/libkopete $(all_includes) liboscar_la_SOURCES = oscarutils.cpp client.cpp task.cpp connector.cpp \ inputprotocolbase.cpp coreprotocol.cpp flapprotocol.cpp snacprotocol.cpp transfer.cpp rtf.cc \ bytestream.cpp oscarclientstream.cpp safedelete.cpp stream.cpp oscarconnector.cpp \ - oscarbytestream.cpp buffer.cpp md5.c logintask.cpp icqlogintask.cpp \ + oscarbytestream.cpp buffer.cpp md5.c logintask.cpp aimlogintask.cpp icqlogintask.cpp \ closeconnectiontask.cpp rateclassmanager.cpp serverversionstask.cpp rateinfotask.cpp \ errortask.cpp locationrightstask.cpp profiletask.cpp blmlimitstask.cpp \ servicesetuptask.cpp icbmparamstask.cpp ssimanager.cpp rateclass.cpp rateclass.h \ diff --git a/kopete/protocols/oscar/liboscar/aimlogintask.cpp b/kopete/protocols/oscar/liboscar/aimlogintask.cpp new file mode 100644 index 00000000..a371b0df --- /dev/null +++ b/kopete/protocols/oscar/liboscar/aimlogintask.cpp @@ -0,0 +1,254 @@ +/* + Kopete Oscar Protocol + aimlogintask.h - Handles logging into to the AIM service + + Copyright (c) 2004 Matt Rogers + + Kopete (c) 2002-2004 by the Kopete developers + + ************************************************************************* + * * + * 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 "aimlogintask.h" + +#include +#include +#include +#include "connection.h" +#include "oscartypes.h" +#include "oscarutils.h" +#include "transfer.h" + +#include "md5.h" + +using namespace Oscar; + +AimLoginTask::AimLoginTask( Task* parent ) + : Task ( parent ) +{ +} + +AimLoginTask::~AimLoginTask() +{ +} + +void AimLoginTask::onGo() +{ + //send Snac 17,06 + sendAuthStringRequest(); + //when we have the authKey, login + connect( this, TQT_SIGNAL( haveAuthKey() ), this, TQT_SLOT( sendLoginRequest() ) ); +} + +bool AimLoginTask::forMe( Transfer* transfer ) const +{ + SnacTransfer* st = dynamic_cast( transfer ); + + if (!st) + return false; + + if ( st && st->snacService() == 0x17 ) + { + WORD subtype = st->snacSubtype(); + switch ( subtype ) + { + case 0x0002: + case 0x0003: + case 0x0006: + case 0x0007: + return true; + break; + default: + return false; + break; + } + } + return false; +} + +const TQByteArray& AimLoginTask::cookie() const +{ + return m_cookie; +} + +const TQString& AimLoginTask::bosHost() const +{ + return m_bosHost; +} + +const TQString& AimLoginTask::bosPort() const +{ + return m_bosPort; +} + +bool AimLoginTask::take( Transfer* transfer ) +{ + if ( forMe( transfer ) ) + { + SnacTransfer* st = dynamic_cast( transfer ); + if (!st) + return false; + + WORD subtype = st->snacSubtype(); + switch ( subtype ) + { + case 0x0003: + setTransfer( transfer ); + handleLoginResponse(); + setTransfer( 0 ); + return true; + break; + case 0x0007: + setTransfer( transfer ); + processAuthStringReply(); + setTransfer( 0 ); + return true; + break; + default: + return false; + break; + } + + return false; + } + return false; +} + +void AimLoginTask::sendAuthStringRequest() +{ + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo + << "SEND CLI_AUTH_REQUEST, sending login request" << endl; + + FLAP f = { 0x02, 0, 0 }; + SNAC s = { 0x0017, 0x0006, 0x0000, client()->snacSequence() }; + + Buffer* outbuf = new Buffer; + outbuf->addTLV(0x0001, client()->userId().length(), client()->userId().latin1() ); + outbuf->addDWord(0x004B0000); // empty TLV 0x004B + outbuf->addDWord(0x005A0000); // empty TLV 0x005A + + Transfer* st = createTransfer( f, s, outbuf ); + send( st ); +} + +void AimLoginTask::processAuthStringReply() +{ + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Got the authorization key" << endl; + Buffer *inbuf = transfer()->buffer(); + WORD keylen = inbuf->getWord(); + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Key length is " << keylen << endl; + m_authKey.duplicate( inbuf->getBlock(keylen) ); + emit haveAuthKey(); +} + +void AimLoginTask::sendLoginRequest() +{ + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "SEND (CLI_MD5_LOGIN) sending AIM login" << endl; + + FLAP f = { 0x02, 0, 0 }; + SNAC s = { 0x0017, 0x0002, 0x0000, client()->snacSequence() }; + Buffer *outbuf = new Buffer; + const Oscar::ClientVersion* version = client()->version(); + + outbuf->addTLV(0x0001, client()->userId().length(), client()->userId().latin1()); + + TQByteArray digest( 17 ); //apparently MD5 digests are 16 bytes long + encodePassword( digest ); + digest[16] = '\0'; //do this so that addTLV sees a NULL-terminator + + outbuf->addTLV(0x0025, 16, digest); + outbuf->addTLV(0x0003, version->clientString.length(), version->clientString.latin1() ); + outbuf->addTLV16(0x0016, version->clientId ); + outbuf->addTLV16(0x0017, version->major ); + outbuf->addTLV16(0x0018, version->minor ); + outbuf->addTLV16(0x0019, version->point ); + outbuf->addTLV16(0x001a, version->build ); + outbuf->addDWord(0x00140004); //TLV type 0x0014, length 0x0004 + outbuf->addDWord( version->other ); //TLV data for type 0x0014 + outbuf->addTLV(0x000f, version->lang.length(), version->lang.latin1() ); + outbuf->addTLV(0x000e, version->country.length(), version->country.latin1() ); + + //if set, old-style buddy lists will not work... you will need to use SSI + outbuf->addTLV8(0x004a,0x01); + + Transfer *st = createTransfer( f, s, outbuf ); + send( st ); +} + +void AimLoginTask::handleLoginResponse() +{ + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "RECV SNAC 0x17, 0x07 - AIM Login Response" << endl; + + SnacTransfer* st = dynamic_cast ( transfer() ); + + if ( !st ) + { + setError( -1 , TQString() ); + return; + } + + TQValueList tlvList = st->buffer()->getTLVList(); + + TLV uin = findTLV( tlvList, 0x0001 ); + if ( uin ) + { + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "found TLV(1) [SN], SN=" << TQString( uin.data ) << endl; + } + + TLV err = findTLV( tlvList, 0x0008 ); + + if ( err ) + { + WORD errorNum = ( ( err.data[0] << 8 ) | err.data[1] ); + + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << k_funcinfo << "found TLV(8) [ERROR] error= " << + errorNum << endl; + Oscar::SNAC s = { 0, 0, 0, 0 }; + client()->fatalTaskError( s, errorNum ); + setError( errorNum, TQString() ); + return; //if there's an error, we'll need to disconnect anyways + } + + TLV server = findTLV( tlvList, 0x0005 ); + if ( server ) + { + TQString ip = TQString( server.data ); + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "found TLV(5) [SERVER] " << ip << endl; + int index = ip.find( ':' ); + m_bosHost = ip.left( index ); + ip.remove( 0 , index+1 ); //get rid of the colon and everything before it + m_bosPort = ip.left(4); //we only need 4 bytes + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "We should reconnect to server '" << m_bosHost << + "' on port " << m_bosPort << endl; + } + + TLV cookie = findTLV( tlvList, 0x0006 ); + if ( cookie ) + { + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "found TLV(6) [COOKIE]" << endl; + m_cookie.duplicate( cookie.data ); + setSuccess( 0, TQString() ); + } + tlvList.clear(); +} + +void AimLoginTask::encodePassword( TQByteArray& digest ) const +{ + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << endl; + md5_state_t state; + md5_init( &state ); + md5_append( &state, ( const md5_byte_t* ) m_authKey.data(), m_authKey.size() ); + md5_append( &state, ( const md5_byte_t* ) client()->password().latin1(), client()->password().length() ); + md5_append( &state, ( const md5_byte_t* ) AIM_MD5_STRING, strlen( AIM_MD5_STRING ) ); + md5_finish( &state, ( md5_byte_t* ) digest.data() ); +} + +//kate: indent-mode csands; tab-width 4; + +#include "aimlogintask.moc" diff --git a/kopete/protocols/oscar/liboscar/aimlogintask.h b/kopete/protocols/oscar/liboscar/aimlogintask.h new file mode 100644 index 00000000..82850a47 --- /dev/null +++ b/kopete/protocols/oscar/liboscar/aimlogintask.h @@ -0,0 +1,83 @@ +/* + Kopete Oscar Protocol + aimlogintask.h - Handles logging into to the AIM service + + Copyright (c) 2004 Matt Rogers + + Kopete (c) 2002-2004 by the Kopete developers + + ************************************************************************* + * * + * 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. * + * * + ************************************************************************* +*/ + +#ifndef _OSCAR_AIMLOGINTASK_H_ +#define _OSCAR_AIMLOGINTASK_H_ + +#include "task.h" + +using namespace Oscar; + +class AimLoginTask : public Task +{ +Q_OBJECT + +public: + AimLoginTask( Task* parent ); + ~AimLoginTask(); + bool take( Transfer* transfer ); + virtual void onGo(); + + //Protocol specific stuff + const TQByteArray& cookie() const; + const TQString& bosHost() const; + const TQString& bosPort() const; + +protected: + bool forMe( Transfer* transfer ) const; + +signals: + void haveAuthKey(); + +private: + //! Encodes a password using MD5 + void encodePassword( TQByteArray& digest ) const; + + //! Send SNAC 0x17, 0x06 + void sendAuthStringRequest(); + + //! Handle SNAC 0x17, 0x07 + void processAuthStringReply(); + + //! Handle SNAC 0x17, 0x03 + void handleLoginResponse(); + + //! Parse the error codes to generate a reason why sign-on failed + //Massive code duplication with CloseConnectionTask + bool parseDisconnectCode( int error, TQString& reason ); + +private slots: + //! Send SNAC 0x17, 0x02 + void sendLoginRequest(); + +private: + //! The authorization key to use when encoding the password + TQByteArray m_authKey; + + //! The all important connection cookie + TQByteArray m_cookie; + + //! The new BOS Host + TQString m_bosHost; + + //! The new BOS Port + TQString m_bosPort; + +}; + +#endif diff --git a/kopete/protocols/oscar/liboscar/buddyicontask.cpp b/kopete/protocols/oscar/liboscar/buddyicontask.cpp index 43e3e792..c7661481 100644 --- a/kopete/protocols/oscar/liboscar/buddyicontask.cpp +++ b/kopete/protocols/oscar/liboscar/buddyicontask.cpp @@ -69,7 +69,10 @@ void BuddyIconTask::onGo() if ( m_action == Receive ) { - sendICQBuddyIconRequest(); + if ( client()->isIcq() ) + sendICQBuddyIconRequest(); + else + sendAIMBuddyIconRequest(); } else sendIcon(); @@ -117,6 +120,8 @@ bool BuddyIconTask::take( Transfer* transfer ) setTransfer( transfer ); if ( st->snacSubtype() == 0x0003 ) handleUploadResponse(); + else if ( st->snacSubtype() == 0x0005 ) + handleAIMBuddyIconResponse(); else handleICQBuddyIconResponse(); @@ -152,6 +157,41 @@ void BuddyIconTask::handleUploadResponse() } +void BuddyIconTask::sendAIMBuddyIconRequest() +{ + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "requesting buddy icon for " << m_user << endl; + FLAP f = { 0x02, 0, 0 }; + m_seq = client()->snacSequence(); + SNAC s = { 0x0010, 0x0004, 0x0000, m_seq }; + Buffer* b = new Buffer; + + b->addBUIN( m_user.latin1() ); //TODO: check encoding + b->addByte( 0x01 ); + b->addWord( 0x0001 ); + b->addByte( m_hashType ); + b->addByte( m_hash.size() ); //MD5 Hash Size + b->addString( m_hash, m_hash.size() ); //MD5 Hash + Transfer* t = createTransfer( f, s, b ); + send( t ); +} + +void BuddyIconTask::handleAIMBuddyIconResponse() +{ + Buffer* b = transfer()->buffer(); + TQString user = b->getBUIN(); + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Receiving buddy icon for " << user << endl; + b->skipBytes(2); //unknown field. not used + BYTE iconType = b->getByte(); + Q_UNUSED( iconType ); + BYTE hashSize = b->getByte(); + TQByteArray iconHash; + iconHash.duplicate( b->getBlock(hashSize) ); + WORD iconSize = b->getWord(); + TQByteArray icon; + icon.duplicate( b->getBlock(iconSize) ); + emit haveIcon( user, icon ); +} + void BuddyIconTask::sendICQBuddyIconRequest() { kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "requesting buddy icon for " << m_user << endl; diff --git a/kopete/protocols/oscar/liboscar/buddyicontask.h b/kopete/protocols/oscar/liboscar/buddyicontask.h index 1a18aa45..c3b7c4f9 100644 --- a/kopete/protocols/oscar/liboscar/buddyicontask.h +++ b/kopete/protocols/oscar/liboscar/buddyicontask.h @@ -50,6 +50,8 @@ signals: private: void sendIcon(); void handleUploadResponse(); + void sendAIMBuddyIconRequest(); + void handleAIMBuddyIconResponse(); void sendICQBuddyIconRequest(); void handleICQBuddyIconResponse(); diff --git a/kopete/protocols/oscar/liboscar/changevisibilitytask.h b/kopete/protocols/oscar/liboscar/changevisibilitytask.h index 554645f4..0ec5ab04 100644 --- a/kopete/protocols/oscar/liboscar/changevisibilitytask.h +++ b/kopete/protocols/oscar/liboscar/changevisibilitytask.h @@ -24,7 +24,7 @@ /** * This class provides a way to change how the account user * appears on everybody else's contact list. It is used to - * implement the invisible online status in ICQ + * implement the invisible online status in ICQ and AIM * @author Matt Rogers */ class ChangeVisibilityTask : public Task diff --git a/kopete/protocols/oscar/liboscar/client.cpp b/kopete/protocols/oscar/liboscar/client.cpp index 2bae2155..7ed6c0d6 100644 --- a/kopete/protocols/oscar/liboscar/client.cpp +++ b/kopete/protocols/oscar/liboscar/client.cpp @@ -93,6 +93,7 @@ public: int stage; //Protocol specific data + bool isIcq; bool redirectRequested; TQValueList redirectionServices; WORD currentRedirect; @@ -145,6 +146,7 @@ Client::Client( TQObject* parent ) d = new ClientPrivate; d->tzoffset = 0; d->active = false; + d->isIcq = false; //default to AIM d->redirectRequested = false; d->currentRedirect = 0; d->connectAsStatus = 0x0; // default to online @@ -231,6 +233,30 @@ void Client::close() d->ssiManager->clear(); } +void Client::setStatus( AIMStatus status, const TQString &_message ) +{ + // AIM: you're away exactly when your away message isn't empty. + // can't use TQString() as a message either; ProfileTask + // interprets null as "don't change". + TQString message; + if ( status == Online ) + message = TQString::fromAscii(""); + else + { + if ( _message.isEmpty() ) + message = TQString::fromAscii(" "); + else + message = _message; + } + + Connection* c = d->connections.connectionForFamily( 0x0002 ); + if ( !c ) + return; + ProfileTask* pt = new ProfileTask( c->rootTask() ); + pt->setAwayMessage( message ); + pt->go( true ); +} + void Client::setStatus( DWORD status, const TQString &message ) { // remember the message to reply with, when requested @@ -372,20 +398,24 @@ void Client::serviceSetupFinished() { d->active = true; - setStatus( d->connectAsStatus, d->connectWithMessage ); + if ( isIcq() ) + setStatus( d->connectAsStatus, d->connectWithMessage ); d->ownStatusTask->go(); - //retrieve offline messages - Connection* c = d->connections.connectionForFamily( 0x0015 ); - if ( !c ) { - return; - } + if ( isIcq() ) + { + //retrieve offline messages + Connection* c = d->connections.connectionForFamily( 0x0015 ); + if ( !c ) { + return; + } - OfflineMessagesTask *offlineMsgTask = new OfflineMessagesTask( c->rootTask() ); - connect( offlineMsgTask, TQT_SIGNAL( receivedOfflineMessage(const Oscar::Message& ) ), - this, TQT_SIGNAL( messageReceived(const Oscar::Message& ) ) ); - offlineMsgTask->go( true ); + OfflineMessagesTask *offlineMsgTask = new OfflineMessagesTask( c->rootTask() ); + connect( offlineMsgTask, TQT_SIGNAL( receivedOfflineMessage(const Oscar::Message& ) ), + this, TQT_SIGNAL( messageReceived(const Oscar::Message& ) ) ); + offlineMsgTask->go( true ); + } emit haveSSIList(); emit loggedIn(); @@ -566,6 +596,16 @@ bool Client::isActive() const return d->active; } +bool Client::isIcq() const +{ + return d->isIcq; +} + +void Client::setIsIcq( bool isIcq ) +{ + d->isIcq = isIcq; +} + void Client::debug( const TQString& str ) { Q_UNUSED(str); @@ -813,6 +853,16 @@ void Client::setChatExchangeList( const TQValueList& exchanges ) d->exchanges = exchanges; } +void Client::requestAIMProfile( const TQString& contact ) +{ + d->userInfoTask->requestInfoFor( contact, UserInfoTask::Profile ); +} + +void Client::requestAIMAwayMessage( const TQString& contact ) +{ + d->userInfoTask->requestInfoFor( contact, UserInfoTask::AwayMessage ); +} + void Client::requestICQAwayMessage( const TQString& contact, ICQStatus contactStatus ) { kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "requesting away message for " << contact << endl; @@ -944,6 +994,17 @@ void Client::uinSearch( const TQString& uin ) ust->searchUserByUIN( uin ); } +void Client::updateProfile( const TQString& profile ) +{ + Connection* c = d->connections.connectionForFamily( 0x0002 ); + if ( !c ) { + return; + } + ProfileTask* pt = new ProfileTask( c->rootTask() ); + pt->setProfileText( profile ); + pt->go(true); +} + void Client::sendTyping( const TQString & contact, bool typing ) { Connection* c = d->connections.connectionForFamily( 0x0004 ); diff --git a/kopete/protocols/oscar/liboscar/client.h b/kopete/protocols/oscar/liboscar/client.h index f71a8333..71cf668a 100644 --- a/kopete/protocols/oscar/liboscar/client.h +++ b/kopete/protocols/oscar/liboscar/client.h @@ -68,6 +68,7 @@ public: FatalProtocolError = 3 }; + enum AIMStatus { Online = 0, Away }; enum ICQStatus { ICQOnline = 0, ICQAway, ICQNotAvailable, ICQOccupied, ICQDoNotDisturb, ICQFreeForChat }; /************* @@ -101,6 +102,8 @@ public: /** Logout and disconnect */ void close(); + /** Set our status for AIM */ + void setStatus( AIMStatus status, const TQString &message = TQString() ); /** Set our status for ICQ */ void setStatus( DWORD status, const TQString &message = TQString() ); @@ -237,6 +240,18 @@ public: */ TQValueList chatExchangeList() const; + /** + * Request the aim profile + * \param contact the contact to get info for + */ + void requestAIMProfile( const TQString& contact ); + + /** + * Request the aim away message + * \param contact the contact to get info for + */ + void requestAIMAwayMessage( const TQString& contact ); + /** * Add the icq away message request to queue * \param contact the contact to get info for @@ -258,6 +273,9 @@ public: //! Run a UIN search void uinSearch( const TQString& uin ); + //! Update the user's AIM profile + void updateProfile( const TQString& profile ); + //! Get buddy icon information for a person void requestBuddyIcon( const TQString& user, const TQByteArray& hash, BYTE hashType ); @@ -326,6 +344,10 @@ public: /** Change the current status message w/o changing status */ void setStatusMessage( const TQString &message ); + /** ICQ Settings */ + bool isIcq() const; + void setIsIcq( bool isIcq ); + /** Host's IP address */ TQCString ipAddress() const; diff --git a/kopete/protocols/oscar/liboscar/clientreadytask.cpp b/kopete/protocols/oscar/liboscar/clientreadytask.cpp index 6d1b07a7..3025a0d8 100644 --- a/kopete/protocols/oscar/liboscar/clientreadytask.cpp +++ b/kopete/protocols/oscar/liboscar/clientreadytask.cpp @@ -64,21 +64,38 @@ void ClientReadyTask::onGo() buffer->addWord( 0x0003 ); break; case 0x0013: - buffer->addWord( 0x0002 ); + buffer->addWord( client()->isIcq() ? 0x0002 : 0x0003 ); break; default: buffer->addWord( 0x0001 ); }; - - if ( i == 0x0002 ) { - buffer->addWord( 0x0101 ); + + if ( client()->isIcq() ) + { + if ( i == 0x0002 ) + buffer->addWord( 0x0101 ); + else + buffer->addWord( 0x0110 ); + + //always add 0x047B + buffer->addWord( 0x047B ); } - else { - buffer->addWord( 0x0110 ); + else //we're AIM so AOL has us do something completely different! *sigh* + { + switch( i ) + { + case 0x0008: + case 0x000B: + case 0x000C: + buffer->addWord( 0x0104 ); + buffer->addWord( 0x0001 ); + break; + default: + buffer->addWord( 0x0110 ); + buffer->addWord( 0x059B ); + break; + }; } - - //always add 0x047B - buffer->addWord( 0x047B ); } //send the damn thing so we can finally be finished diff --git a/kopete/protocols/oscar/liboscar/connection.cpp b/kopete/protocols/oscar/liboscar/connection.cpp index dc66aefa..16757785 100644 --- a/kopete/protocols/oscar/liboscar/connection.cpp +++ b/kopete/protocols/oscar/liboscar/connection.cpp @@ -154,6 +154,11 @@ TQString Connection::password() const return d->client->password(); } +bool Connection::isIcq() const +{ + return d->client->isIcq(); +} + Task* Connection::rootTask() const { return d->root; diff --git a/kopete/protocols/oscar/liboscar/connection.h b/kopete/protocols/oscar/liboscar/connection.h index 962c84c1..9a3cd861 100644 --- a/kopete/protocols/oscar/liboscar/connection.h +++ b/kopete/protocols/oscar/liboscar/connection.h @@ -143,6 +143,7 @@ public: TQString userId() const; TQString password() const; + bool isIcq() const; SSIManager* ssiManager() const; const Oscar::ClientVersion* version() const; RateClassManager* rateManager() const; diff --git a/kopete/protocols/oscar/liboscar/logintask.cpp b/kopete/protocols/oscar/liboscar/logintask.cpp index c3d568f9..73379e40 100644 --- a/kopete/protocols/oscar/liboscar/logintask.cpp +++ b/kopete/protocols/oscar/liboscar/logintask.cpp @@ -1,6 +1,6 @@ /* Kopete Oscar Protocol - logintask.cpp - Handles logging into to the ICQ service + logintask.cpp - Handles logging into to the AIM or ICQ service Copyright (c) 2004 Matt Rogers @@ -22,6 +22,7 @@ #include #include +#include "aimlogintask.h" #include "connection.h" #include "closeconnectiontask.h" #include "icqlogintask.h" @@ -39,26 +40,49 @@ StageOneLoginTask::StageOneLoginTask( Task* parent ) : Task ( parent ) { + m_aimTask = 0L; m_icqTask = 0L; m_closeTask = 0L; } StageOneLoginTask::~StageOneLoginTask() { + delete m_aimTask; delete m_icqTask; delete m_closeTask; } bool StageOneLoginTask::take( Transfer* transfer ) { - if ( forMe( transfer ) ) { - kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Starting ICQ login" << endl; - m_icqTask = new IcqLoginTask( client()->rootTask() ); - m_closeTask = new CloseConnectionTask( client()->rootTask() ); - - //connect finished signal - connect( m_closeTask, TQT_SIGNAL( finished() ), this, TQT_SLOT( closeTaskFinished() ) ); - m_icqTask->go( true ); + if ( forMe( transfer ) ) + { + if ( client()->isIcq() ) + { + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Starting ICQ login" << endl; + m_icqTask = new IcqLoginTask( client()->rootTask() ); + m_closeTask = new CloseConnectionTask( client()->rootTask() ); + + //connect finished signal + connect( m_closeTask, TQT_SIGNAL( finished() ), this, TQT_SLOT( closeTaskFinished() ) ); + m_icqTask->go( true ); + } + else + { + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Starting AIM login" << endl; + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Sending the FLAP version back" << endl; + + //send the flap version response + FLAP f = { 0x01, 0 , 0 }; + Buffer *outbuf = new Buffer; + outbuf->addDWord(0x00000001); //flap version + f.length = outbuf->length(); + Transfer* ft = createTransfer( f, outbuf ); + send( ft ); + + m_aimTask = new AimLoginTask( client()->rootTask() ); + connect( m_aimTask, TQT_SIGNAL( finished() ), this, TQT_SLOT( aimTaskFinished() ) ); + m_aimTask->go( true ); + } return true; } return false; @@ -74,6 +98,16 @@ void StageOneLoginTask::closeTaskFinished() setSuccess( m_closeTask->statusCode(), m_closeTask->statusString() ); } +void StageOneLoginTask::aimTaskFinished() +{ + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << endl; + m_cookie = m_aimTask->cookie(); + m_bosPort = m_aimTask->bosPort(); + m_bosServer = m_aimTask->bosHost(); + + setSuccess( m_aimTask->statusCode(), m_aimTask->statusString() ); +} + bool StageOneLoginTask::forMe( Transfer* transfer ) const { FlapTransfer* ft = dynamic_cast ( transfer ); diff --git a/kopete/protocols/oscar/liboscar/logintask.h b/kopete/protocols/oscar/liboscar/logintask.h index 626de7bb..3e1a21c5 100644 --- a/kopete/protocols/oscar/liboscar/logintask.h +++ b/kopete/protocols/oscar/liboscar/logintask.h @@ -1,6 +1,6 @@ /* Kopete Oscar Protocol - logintask.h - Handles logging into to the ICQ service + logintask.h - Handles logging into to the AIM or ICQ service Copyright (c) 2004 Matt Rogers @@ -23,6 +23,7 @@ #include "oscartypes.h" #include "task.h" +#include "aimlogintask.h" #include "icqlogintask.h" #include "closeconnectiontask.h" @@ -69,6 +70,7 @@ public: public slots: void closeTaskFinished(); + void aimTaskFinished(); protected: bool forMe( Transfer* transfer ) const; @@ -76,6 +78,7 @@ protected: private: //Tasks we want to control + AimLoginTask* m_aimTask; IcqLoginTask* m_icqTask; CloseConnectionTask* m_closeTask; diff --git a/kopete/protocols/oscar/liboscar/oscartypes.h b/kopete/protocols/oscar/liboscar/oscartypes.h index ffe76c30..4e13a509 100644 --- a/kopete/protocols/oscar/liboscar/oscartypes.h +++ b/kopete/protocols/oscar/liboscar/oscartypes.h @@ -27,6 +27,7 @@ //! Debug Areas const int OSCAR_RAW_DEBUG = 14151; const int OSCAR_GEN_DEBUG = 14150; +const int OSCAR_AIM_DEBUG = 14152; const int OSCAR_ICQ_DEBUG = 14153; namespace Oscar @@ -247,6 +248,9 @@ struct ClientVersion /* ICQ Version Characteristics */ const unsigned char ICQ_TCP_VERSION = 0x0008; + /* AIM Version Characteristics */ + const char AIM_MD5_STRING[] = "AOL Instant Messenger (SM)"; + /* SSI types */ const WORD ROSTER_CONTACT = 0x0000; // a normal contact const WORD ROSTER_GROUP = 0x0001; // a group of contacts diff --git a/kopete/protocols/oscar/liboscar/profiletask.cpp b/kopete/protocols/oscar/liboscar/profiletask.cpp index 4b2122a0..bc516fff 100644 --- a/kopete/protocols/oscar/liboscar/profiletask.cpp +++ b/kopete/protocols/oscar/liboscar/profiletask.cpp @@ -74,13 +74,39 @@ void ProfileTask::sendProfileUpdate() Buffer *buffer = new Buffer(); Buffer capBuf; - capBuf.addString( oscar_caps[CAP_ICQSERVERRELAY], 16 ); // we support type-2 messages - capBuf.addString( oscar_caps[CAP_UTF8], 16 ); // we can send/receive UTF encoded messages - capBuf.addString( oscar_caps[CAP_ISICQ], 16 ); // I think this is an icq client, but maybe I'm wrong - capBuf.addString( oscar_caps[CAP_KOPETE], 16 ); // we are the borg, resistance is futile - //capBuf.addString( oscar_caps[CAP_RTFMSGS], 16 ); // we do incoming RTF messages - capBuf.addString( oscar_caps[CAP_TYPING], 16 ); // we know you're typing something to us! - capBuf.addString( oscar_caps[CAP_BUDDYICON], 16 ); //can you take my picture? + if ( !m_profileText.isNull() && !client()->isIcq() ) + { + static const TQString defencoding = "text/aolrtf; charset=\"us-ascii\""; + buffer->addTLV(0x0001, defencoding.length(), defencoding.latin1()); + buffer->addTLV(0x0002, m_profileText.length(), m_profileText.local8Bit()); + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "setting profile = " << m_profileText << endl; + } + + if ( !m_awayMessage.isNull() && !client()->isIcq() ) + { + static const TQString defencoding = "text/aolrtf; charset=\"us-ascii\""; + buffer->addTLV(0x0003, defencoding.length(), defencoding.latin1()); + buffer->addTLV(0x0004, m_awayMessage.length(), m_awayMessage.local8Bit()); + kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "setting away message = " << m_awayMessage << endl; + } + + if ( client()->isIcq() ) + { + capBuf.addString( oscar_caps[CAP_ICQSERVERRELAY], 16 ); // we support type-2 messages + capBuf.addString( oscar_caps[CAP_UTF8], 16 ); // we can send/receive UTF encoded messages + capBuf.addString( oscar_caps[CAP_ISICQ], 16 ); // I think this is an icq client, but maybe I'm wrong + capBuf.addString( oscar_caps[CAP_KOPETE], 16 ); // we are the borg, resistance is futile + //capBuf.addString( oscar_caps[CAP_RTFMSGS], 16 ); // we do incoming RTF messages + capBuf.addString( oscar_caps[CAP_TYPING], 16 ); // we know you're typing something to us! + capBuf.addString( oscar_caps[CAP_BUDDYICON], 16 ); //can you take my picture? + } + else + { + capBuf.addString( oscar_caps[CAP_UTF8], 16 ); //we can send/receive UTF encoded messages + capBuf.addString( oscar_caps[CAP_KOPETE], 16 ); // we are the borg, resistance is futile + capBuf.addString( oscar_caps[CAP_TYPING], 16 ); // we know you're typing something to us! + capBuf.addString( oscar_caps[CAP_BUDDYICON], 16 ); //can you take my picture? + } //kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "adding capabilities, size=" << capBuf.length() << endl; buffer->addTLV(0x0005, capBuf.length(), capBuf.buffer()); diff --git a/kopete/protocols/oscar/liboscar/profiletask.h b/kopete/protocols/oscar/liboscar/profiletask.h index 69d1119e..a51075a5 100644 --- a/kopete/protocols/oscar/liboscar/profiletask.h +++ b/kopete/protocols/oscar/liboscar/profiletask.h @@ -21,7 +21,8 @@ #include "task.h" /** -Also takes care of updating the capabilities supported by the client (ICQ). +Task that sets the profile and away message on the server (AIM only). +Also takes care of updating the capabilities supported by the client (AIM and ICQ). The profile will be updated only if the profile text has been set non-null. The away message will be set only if the away message has been set non-null. diff --git a/kopete/protocols/oscar/liboscar/sendmessagetask.cpp b/kopete/protocols/oscar/liboscar/sendmessagetask.cpp index 0f9c8f5f..d95c17ed 100644 --- a/kopete/protocols/oscar/liboscar/sendmessagetask.cpp +++ b/kopete/protocols/oscar/liboscar/sendmessagetask.cpp @@ -98,9 +98,21 @@ void SendMessageTask::onGo() break; } - b->addDWord( 0x00030000 ); //empty TLV 3 to get an ack from the server + // Add the TLV to indicate if this is an autoresponse: 0x00040000 + // Right now, only supported for the AIM client, I'm not sure about ICQ + // For some reason you can't have both a 0x0004 and 0x0003 TLV in the same + // SNAC, if you do the AIM server complains + if ( !client()->isIcq() && (m_autoResponse == true) ) + { + TLV tlv4( 0x0004, 0, NULL); + b->addTLV( tlv4 ); + } + else + { + b->addDWord( 0x00030000 ); //empty TLV 3 to get an ack from the server + } - if ( m_message.type() != 2 && ! m_message.hasProperty( Oscar::Message::StatusMessageRequest ) ) { + if ( client()->isIcq() && m_message.type() != 2 && ! m_message.hasProperty( Oscar::Message::StatusMessageRequest ) ) { b->addDWord( 0x00060000 ); //empty TLV 6 to store message on the server if not online } } @@ -130,10 +142,18 @@ void SendMessageTask::addChannel1Data( Buffer* b ) { Buffer tlv2buffer; - //Send features TLV using data from pidgin. - tlv2buffer.addDWord( 0x05010002 ); //TLV 0x0501, length 2 - tlv2buffer.addWord( 0x0106 ); //TLV 0x0501 data - + //Send features TLV using data from pidgin. Features are different + //depending on whether we're ICQ or AIM + if ( client()->isIcq() ) + { + tlv2buffer.addDWord( 0x05010002 ); //TLV 0x0501, length 2 + tlv2buffer.addWord( 0x0106 ); //TLV 0x0501 data + } + else + { + tlv2buffer.addDWord( 0x05010004 ); //TLV 0x0501, length 4 + tlv2buffer.addDWord( 0x01010102 ); //TLV 0x0501 data. + } //we only send one message part. There's only one client that actually uses //them and it's quite old and infrequently used tlv2buffer.addWord( 0x0101 ); //add TLV(0x0101) also known as TLV(257) diff --git a/kopete/protocols/oscar/liboscar/serverversionstask.cpp b/kopete/protocols/oscar/liboscar/serverversionstask.cpp index 7d001ec3..336f3b02 100644 --- a/kopete/protocols/oscar/liboscar/serverversionstask.cpp +++ b/kopete/protocols/oscar/liboscar/serverversionstask.cpp @@ -115,6 +115,7 @@ void ServerVersionsTask::handleFamilies() void ServerVersionsTask::requestFamilyVersions() { + bool isIcq = client()->isIcq(); int listLength = m_familiesList.count(); FLAP f = { 0x02, 0, 0 }; @@ -124,18 +125,22 @@ void ServerVersionsTask::requestFamilyVersions() kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "SEND SNAC 0x01, 0x17 - Snac family versions we want" << endl; - for ( int i = 0; i < listLength; i++ ) { + for ( int i = 0; i < listLength; i++ ) + { outbuf->addWord( m_familiesList[i] ); - if ( m_familiesList[i] == 0x0001 ) { + if ( m_familiesList[i] == 0x0001 ) val = 0x0003; - } - else { - if ( m_familiesList[i] == 0x0013 ) { - val = 0x0004; // for ICQ2002 + else + { + if ( m_familiesList[i] == 0x0013 ) + { + if ( isIcq ) + val = 0x0004; // for ICQ2002 + else + val = 0x0003; } - else { + else val = 0x0001; - } } outbuf->addWord(val); diff --git a/kopete/protocols/oscar/liboscar/tests/logintest.cpp b/kopete/protocols/oscar/liboscar/tests/logintest.cpp index e344c3e1..d1025059 100644 --- a/kopete/protocols/oscar/liboscar/tests/logintest.cpp +++ b/kopete/protocols/oscar/liboscar/tests/logintest.cpp @@ -33,6 +33,7 @@ void LoginTest::slotDoTest() // connect to server tqDebug( "connecting to server "); + myClient->setIsIcq( true ); myClient->start( server, 5190, "userid", "password" ); myClient->connectToServer( myConnection, server, true ); connected = true; diff --git a/kopete/protocols/oscar/liboscar/tests/ssigrouptest.cpp b/kopete/protocols/oscar/liboscar/tests/ssigrouptest.cpp index 2f646ecf..410b6021 100644 --- a/kopete/protocols/oscar/liboscar/tests/ssigrouptest.cpp +++ b/kopete/protocols/oscar/liboscar/tests/ssigrouptest.cpp @@ -33,6 +33,7 @@ void LoginTest::slotDoTest() // connect to server tqDebug( "connecting to server "); + myClient->setIsIcq( true ); myClient->start( server, 5190, "userid", "password" ); myClient->connectToServer( myConnection, server, true ); TQTimer::singleShot( 10000, this, TQT_SLOT(runAddGroupTest() ) ); diff --git a/kopete/protocols/oscar/liboscar/tests/userinfotest.cpp b/kopete/protocols/oscar/liboscar/tests/userinfotest.cpp index d7ccac68..8d75b79d 100644 --- a/kopete/protocols/oscar/liboscar/tests/userinfotest.cpp +++ b/kopete/protocols/oscar/liboscar/tests/userinfotest.cpp @@ -33,6 +33,7 @@ void LoginTest::slotDoTest() // connect to server tqDebug( "connecting to server "); + myClient->setIsIcq( true ); myClient->start( server, 5190, "userid", "password" ); myClient->connectToServer( myConnection, server, true ); //TQObject::connect( myClient, TQT_SIGNAL( userIsOnline( const TQString& ) ), this, TQT_SLOT( runUserInfoTest())); -- cgit v1.2.1