summaryrefslogtreecommitdiffstats
path: root/kopete/protocols/oscar/liboscar/chatservicetask.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kopete/protocols/oscar/liboscar/chatservicetask.cpp')
-rw-r--r--kopete/protocols/oscar/liboscar/chatservicetask.cpp359
1 files changed, 359 insertions, 0 deletions
diff --git a/kopete/protocols/oscar/liboscar/chatservicetask.cpp b/kopete/protocols/oscar/liboscar/chatservicetask.cpp
new file mode 100644
index 00000000..9d07afe8
--- /dev/null
+++ b/kopete/protocols/oscar/liboscar/chatservicetask.cpp
@@ -0,0 +1,359 @@
+// Kopete Oscar Protocol - chat service task
+
+// Copyright (C) 2005 Matt Rogers <mattr@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.1 of the License, or (at your option) any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301 USA
+
+
+#include "chatservicetask.h"
+
+#include <qstring.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <qtextcodec.h>
+
+#include "connection.h"
+#include "transfer.h"
+#include "buffer.h"
+#include "oscartypes.h"
+
+ChatServiceTask::ChatServiceTask( Task* parent, Oscar::WORD exchange, const QString& room )
+ : Task( parent ), m_encoding( "us-ascii" )
+{
+ m_exchange = exchange;
+ m_room = room;
+}
+
+ChatServiceTask::~ChatServiceTask()
+{
+
+}
+
+void ChatServiceTask::setMessage( const Oscar::Message& msg )
+{
+ m_message = msg;
+}
+
+void ChatServiceTask::setEncoding( const QCString& enc )
+{
+ m_encoding = enc;
+}
+
+void ChatServiceTask::onGo()
+{
+ if ( !m_message )
+ {
+ setSuccess( true, QString::null );
+ return;
+ }
+
+ kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "sending '" << m_message.textArray() << "' to the "
+ << m_room << " room" << endl;
+ Buffer* b = new Buffer();
+ b->addDWord( KApplication::random() ); //use kapp since it's convenient
+ b->addDWord( KApplication::random() );
+ b->addWord( 0x0003 ); //this be message channel 3 mateys! arrr!!
+ b->addDWord( 0x00010000 ); //TLV 1 - this means it's a public message
+ b->addDWord( 0x00060000 ); //TLV 6 - enables the server sending you your message back
+
+ Buffer tlv5;
+ TLV type2, type3, type1;
+
+ type2.type = 0x0002;
+ type2.length = 0x0008;
+ type2.data = m_encoding;
+
+ type3.type = 0x0003;
+ type3.length = 0x0002;
+ type3.data = QCString( "en" ); //hardcode for right now. don't know that we can do others
+
+ type1.type = 0x0001;
+ type1.length = m_message.textArray().size();
+ type1.data = m_message.textArray();
+ tlv5.addWord( 0x0005 );
+ tlv5.addWord( 12 + type1.length + type2.length + type3.length );
+ tlv5.addTLV( type1 );
+ tlv5.addTLV( type2 );
+ tlv5.addTLV( type3 );
+
+ b->addString( tlv5.buffer(), tlv5.length() );
+
+ FLAP f = { 0x02, 0, 0 };
+ SNAC s = { 0x000E, 0x0005, 0x0000, client()->snacSequence() };
+ Transfer* t = createTransfer( f, s, b );
+ send( t );
+ setSuccess( true );
+}
+
+bool ChatServiceTask::forMe( const Transfer* t ) const
+{
+ const SnacTransfer* st = dynamic_cast<const SnacTransfer*>( t );
+ if ( !st )
+ return false;
+
+ if ( st->snacService() != 0x000E )
+ return false;
+
+ switch ( st->snacSubtype() )
+ {
+ case 0x0003:
+ case 0x0002:
+ case 0x0006:
+ case 0x0009:
+ case 0x0004:
+ return true;
+ break;
+ default:
+ return false;
+ break;
+ }
+
+ return true;
+}
+
+bool ChatServiceTask::take( Transfer* t )
+{
+ if ( !forMe( t ) )
+ return false;
+
+ SnacTransfer* st = dynamic_cast<SnacTransfer*>( t );
+ if ( !st )
+ return false;
+
+ setTransfer( t );
+
+ switch ( st->snacSubtype() )
+ {
+ case 0x0002:
+ kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "Parse room info" << endl;
+ parseRoomInfo();
+ break;
+ case 0x0003:
+ kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "user joined notification" << endl;
+ parseJoinNotification();
+ break;
+ case 0x0004:
+ kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "user left notification" << endl;
+ parseLeftNotification();
+ break;
+ case 0x0006:
+ kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "message from room to client" << endl;
+ parseChatMessage();
+ break;
+ case 0x0009:
+ kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "chat error or data" << endl;
+ break;
+ };
+
+ setSuccess( 0, QString::null );
+ setTransfer( 0 );
+ return true;
+}
+
+void ChatServiceTask::parseRoomInfo()
+{
+ WORD instance;
+ BYTE detailLevel;
+ Buffer* b = transfer()->buffer();
+
+ m_exchange = b->getWord();
+ QByteArray cookie( b->getBlock( b->getByte() ) );
+ instance = b->getWord();
+
+ detailLevel = b->getByte();
+
+ //skip the tlv count, we don't care. Buffer::getTLVList() handles this all
+ //correctly anyways
+ b->skipBytes( 2 );
+
+ QValueList<Oscar::TLV> tlvList = b->getTLVList();
+ QValueList<Oscar::TLV>::iterator it = tlvList.begin();
+ QValueList<Oscar::TLV>::iterator itEnd = tlvList.end();
+ for ( ; it != itEnd; ++it )
+ {
+ switch ( ( *it ).type )
+ {
+ case 0x006A:
+ m_internalRoom = QString( ( *it ).data );
+ kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "room name: " << m_room << endl;
+ break;
+ case 0x006F:
+ kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "num occupants: " << ( *it ).data << endl;
+ break;
+ case 0x0073:
+ kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "occupant list" << endl;
+ break;
+ case 0x00C9:
+ kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "flags" << endl;
+ break;
+ case 0x00CA: //creation time
+ case 0x00D1: //max message length
+ case 0x00D3: //room description
+ case 0x00D6: //encoding 1
+ case 0x00D7: //language 1
+ case 0x00D8: //encoding 2
+ case 0x00D9: //language 2
+ case 0x00DA: //maximum visible message length
+ kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "unhandled TLV type " << ( *it ).type << endl;
+ break;
+ default:
+ kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "unknown TLV type " << ( *it ).type << endl;
+ break;
+ }
+ }
+}
+
+void ChatServiceTask::parseJoinNotification()
+{
+ Buffer* b = transfer()->buffer();
+ while ( b->length() > 0 )
+ {
+ QString sender( b->getBUIN() );
+ kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "user name:" << sender << endl;
+ WORD warningLevel = b->getWord();
+ WORD numTLVs = b->getWord();
+ for ( int i = 0; i < numTLVs; i++ )
+ {
+ TLV t = b->getTLV();
+ switch ( t.type )
+ {
+ case 0x0001:
+ kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "user class: " << t.data << endl;
+ break;
+ case 0x000F:
+ kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "idle time: " << t.data << endl;
+ break;
+ case 0x0003:
+ kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "signon: " << t.data << endl;
+ break;
+ }
+ }
+ kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "emitted userJoinedChat" << endl;
+ emit userJoinedChat( m_exchange, m_room, sender );
+ }
+
+}
+
+void ChatServiceTask::parseLeftNotification()
+{
+ Buffer* b = transfer()->buffer();
+ while ( b->length() > 0 )
+ {
+ QString sender( b->getBUIN() );
+ kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "user name:" << sender << endl;
+ WORD warningLevel = b->getWord();
+ WORD numTLVs = b->getWord();
+ for ( int i = 0; i < numTLVs; i++ )
+ {
+ TLV t = b->getTLV();
+ switch ( t.type )
+ {
+ case 0x0001:
+ kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "user class: " << t.data << endl;
+ break;
+ case 0x000F:
+ kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "idle time: " << t.data << endl;
+ break;
+ case 0x0003:
+ kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "signon: " << t.data << endl;
+ break;
+ }
+ }
+ emit userLeftChat( m_exchange, m_room, sender );
+ }
+}
+
+void ChatServiceTask::parseChatMessage()
+{
+ kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "have new chat room message" << endl;
+ Buffer* b = transfer()->buffer();
+ bool whisper = true, reflection = false;
+ QByteArray language, encoding, message;
+ QString sender;
+ QByteArray icbmCookie( b->getBlock( 8 ) );
+ b->skipBytes( 2 ); //message channel always 0x03
+ QValueList<Oscar::TLV> chatTLVs = b->getTLVList();
+ QValueList<Oscar::TLV>::iterator it, itEnd = chatTLVs.end();
+ for ( it = chatTLVs.begin(); it != itEnd; ++it )
+ {
+ switch ( ( *it ).type )
+ {
+ case 0x0001: //if present, message was sent to the room
+ whisper = false;
+ break;
+ case 0x0006: //enable reflection
+ reflection = true;
+ break;
+ case 0x0005: //the good stuff - the actual message
+ {
+ kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "parsing the message" << endl;
+ //oooh! look! more TLVS! i love those!
+ Buffer b( ( *it ).data );
+ while ( b.length() >= 4 )
+ {
+ TLV t = b.getTLV();
+ switch( t.type )
+ {
+ case 0x0003:
+ language = t.data;
+ kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "language: " << language << endl;
+ break;
+ case 0x0002:
+ encoding = t.data;
+ kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "encoding: " << encoding << endl;
+ break;
+ case 0x0001:
+ message = t.data;
+ kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "message: " << message << endl;
+ break;
+ }
+ }
+ }
+ break;
+ case 0x0003: //user info
+ {
+ Buffer b( ( *it ).data );
+ sender = QString( b.getBUIN() );
+ kdDebug(OSCAR_RAW_DEBUG) << k_funcinfo << "got user info. sender is " << sender << endl;
+ }
+ break;
+
+ }
+ }
+
+ QTextCodec* codec = QTextCodec::codecForName( encoding );
+ if ( ! codec )
+ codec = QTextCodec::codecForMib( 4 );
+ QString msgText( codec->toUnicode( message ) );
+ Oscar::Message omessage;
+ omessage.setReceiver( client()->userId() );
+ omessage.setSender( sender );
+ omessage.setTimestamp( QDateTime::currentDateTime() );
+ omessage.setText( Oscar::Message::UTF8, msgText );
+ omessage.setType( 0x03 );
+ omessage.setExchange( m_exchange );
+ omessage.setChatRoom( m_room );
+ emit newChatMessage( omessage );
+}
+
+void ChatServiceTask::parseChatError()
+{
+
+}
+
+
+#include "chatservicetask.moc"
+