summaryrefslogtreecommitdiffstats
path: root/kopete/protocols/msn/dispatcher.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kopete/protocols/msn/dispatcher.cpp')
-rw-r--r--kopete/protocols/msn/dispatcher.cpp647
1 files changed, 0 insertions, 647 deletions
diff --git a/kopete/protocols/msn/dispatcher.cpp b/kopete/protocols/msn/dispatcher.cpp
deleted file mode 100644
index 70d43a14..00000000
--- a/kopete/protocols/msn/dispatcher.cpp
+++ /dev/null
@@ -1,647 +0,0 @@
-/*
- dispatcher.cpp - msn p2p protocol
-
- Copyright (c) 2003-2005 by Olivier Goffart <ogoffart@ kde.org>
- Copyright (c) 2005 by Gregg Edghill <gregg.edghill@gmail.com>
-
- *************************************************************************
- * *
- * 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 "dispatcher.h"
-#include "incomingtransfer.h"
-#include "outgoingtransfer.h"
-
-#if MSN_WEBCAM
-#include "webcam.h"
-#endif
-
-using P2P::Dispatcher;
-using P2P::Message;
-using P2P::TransferContext;
-using P2P::IncomingTransfer;
-using P2P::OutgoingTransfer;
-
-#include "msnswitchboardsocket.h"
-
-// Kde includes
-#include <kdebug.h>
-#include <kmdcodec.h>
-#include <kstandarddirs.h>
-#include <tdetempfile.h>
-
-// TQt includes
-#include <tqdatastream.h>
-#include <tqfile.h>
-#include <tqregexp.h>
-#include <tqtextcodec.h>
-#include <tqtextstream.h>
-
-// Kopete includes
-#include <kopetechatsession.h> // Just for getting the contact
-#include <kopeteaccount.h>
-#include <kopetetransfermanager.h>
-
-#include <stdlib.h>
-
-Dispatcher::Dispatcher(TQObject *parent, const TQString& contact, const TQStringList &ip)
- : TQObject(parent) , m_contact(contact) , m_callbackChannel(0l) , m_ip(ip)
-{}
-
-Dispatcher::~Dispatcher()
-{
- kdDebug(14140) << k_funcinfo << endl;
-
- if(m_callbackChannel)
- {
- delete m_callbackChannel;
- m_callbackChannel = 0l;
- }
-}
-
-void Dispatcher::detach(TransferContext* transfer)
-{
- m_sessions.remove(transfer->m_sessionId);
- transfer->deleteLater();
-}
-
-TQString Dispatcher::localContact()
-{
- return m_contact;
-}
-
-void Dispatcher::requestDisplayIcon(const TQString& from, const TQString& msnObject)
-{
- TQ_UINT32 sessionId = rand()%0xFFFFFF00 + 4;
- TransferContext* current =
- new IncomingTransfer(from, this, sessionId);
-
- current->m_branch = P2P::Uid::createUid();
- current->m_callId = P2P::Uid::createUid();
- current->setType(P2P::UserDisplayIcon);
- current->m_object = msnObject;
- // Add the transfer to the list.
- m_sessions.insert(sessionId, current);
-
- kdDebug(14140) << k_funcinfo << "Requesting, " << msnObject << endl;
-
- TQString context = TQString::fromUtf8(KCodecs::base64Encode(msnObject.utf8()));
- // NOTE remove the \0 character automatically
- // appended to a TQCString.
- context.replace("=", TQString());
- TQString content =
- "EUF-GUID: {A4268EEC-FEC5-49E5-95C3-F126696BDBF6}\r\n"
- "SessionID: " + TQString::number(sessionId) + "\r\n"
- "AppID: 1\r\n"
- "Context: " + context + "\r\n"
- "\r\n";
- // Send the sending client an invitation message.
- current->sendMessage(INVITE, content);
-}
-
-void Dispatcher::sendFile(const TQString& path, TQ_INT64 fileSize, const TQString& to)
-{
- // Create a new transfer context that will handle
- // the file transfer.
- TQ_UINT32 sessionId = rand()%0xFFFFFF00 + 4;
- TransferContext *current =
- new OutgoingTransfer(to, this, sessionId);
- current->m_branch = P2P::Uid::createUid();
- current->m_callId = P2P::Uid::createUid();
- current->setType(P2P::File);
- // Add the transfer to the list.
- m_sessions.insert(sessionId, current);
-
- // Set the transfer context file.
- current->m_file = new TQFile(path);
- // Create the file context data.
- TQString context;
-
- TQByteArray header(638);
- header.fill('\0');
- TQDataStream writer(header, IO_WriteOnly);
- writer.setByteOrder(TQDataStream::LittleEndian);
-
- // Write the header length to the stream.
- writer << (TQ_INT32)638;
- // Write client version to the stream.
- writer << (TQ_INT32)3;
- // Write the file size to the stream.
- writer << fileSize;
- // Write the file transfer flag to the stream.
- // TODO support file preview. For now disable file preview.
- writer << (TQ_INT32)1;
- // Write the file name in utf-16 to the stream.
- TQTextStream ts(header, IO_WriteOnly);
- ts.setEncoding(TQTextStream::RawUnicode);
- ts.device()->at(20);
- ts << path.section('/', -1);
- // NOTE Background Sharing base64 [540..569]
- // TODO add support for background sharing.
- // Write file exchange type to the stream.
- // NOTE File - 0xFFFFFFFF
- // NOTE Background Sharing - 0xFFFFFFFE
- writer.device()->at(570);
- writer << (TQ_UINT32)0xFFFFFFFF;
-
- // Encode the file context header to base64 encoding.
- context = TQString::fromUtf8(KCodecs::base64Encode(header));
-
- // Send an INVITE message to the recipient.
- TQString content = "EUF-GUID: {5D3E02AB-6190-11D3-BBBB-00C04F795683}\r\n"
- "SessionID: " + TQString::number(sessionId) + "\r\n"
- "AppID: 2\r\n"
- "Context: " + context + "\r\n"
- "\r\n";
- current->sendMessage(INVITE, content);
-}
-
-void Dispatcher::sendImage(const TQString& /*fileName*/, const TQString& /*to*/)
-{
-// TODO kdDebug(14140) << k_funcinfo << endl;
-// TQFile imageFile(fileName);
-// if(!imageFile.open(IO_ReadOnly))
-// {
-// kdDebug(14140) << k_funcinfo << "Error opening image file."
-// << endl;
-// return;
-// }
-//
-// OutgoingTransfer *outbound =
-// new OutgoingTransfer(to, this, 64);
-//
-// outbound->sendImage(imageFile.readAll());
-}
-
-#if MSN_WEBCAM
-void Dispatcher::startWebcam(const TQString &/*myHandle*/, const TQString &msgHandle, bool wantToReceive)
-{
- TQ_UINT32 sessionId = rand()%0xFFFFFF00 + 4;
- Webcam::Who who= wantToReceive ? Webcam::wViewer : Webcam::wProducer;
- TransferContext* current =
- new Webcam(who, msgHandle, this, sessionId);
-
- current->m_branch = P2P::Uid::createUid();
- current->m_callId = P2P::Uid::createUid();
- current->setType(P2P::WebcamType);
- // Add the transfer to the list.
- m_sessions.insert(sessionId, current);
-
- // {4BD96FC0-AB17-4425-A14A-439185962DC8} <- i want to show you my webcam
- // {1C9AA97E-9C05-4583-A3BD-908A196F1E92} <- i want to see your webcam
- TQString GUID= (who==Webcam::wProducer) ? "4BD96FC0-AB17-4425-A14A-439185962DC8" : "1C9AA97E-9C05-4583-A3BD-908A196F1E92" ;
-
- TQString content="EUF-GUID: {"+GUID+"}\r\n"
- "SessionID: "+ TQString::number(sessionId)+"\r\n"
- "AppID: 4\r\n"
- "Context: ewBCADgAQgBFADcAMABEAEUALTQBFADIAQwBBAC0ANAA0ADAAMAAtAEEARTQAwADMALQA4ADgARgBGADgANTQBCADkARgA0AEUAOAB9AA==\r\n\r\n";
-
- // context is the base64 of the utf16 of {B8BE70DE-E2CA-4400-AE03-88FF85B9F4E8}
-
- current->sendMessage( INVITE , content );
-}
-#endif
-
-
-
-void Dispatcher::slotReadMessage(const TQString &from, const TQByteArray& stream)
-{
- P2P::Message receivedMessage =
- m_messageFormatter.readMessage(stream);
-
- receivedMessage.source = from;
-
- if(receivedMessage.contentType == "application/x-msnmsgrp2p")
- {
- if((receivedMessage.header.dataSize == 0)/* && ((receivedMessage.header.flag & 0x02) == 0x02)*/)
- {
- TransferContext *current = 0l;
- TQMap<TQ_UINT32, TransferContext*>::Iterator it = m_sessions.begin();
- for(; it != m_sessions.end(); it++)
- {
- if(receivedMessage.header.ackSessionIdentifier == it.data()->m_identifier){
- current = it.data();
- break;
- }
- }
-
- if(current){
- // Inform the transfer object of the acknowledge.
- current->m_ackSessionIdentifier = receivedMessage.header.identifier;
- current->m_ackUniqueIdentifier = receivedMessage.header.ackSessionIdentifier;
- current->acknowledged();
- }
- else
- {
- kdDebug(14140) << k_funcinfo
- << "no transfer context with identifier, "
- << receivedMessage.header.ackSessionIdentifier
- << endl;
- }
- return;
- }
-
- if(m_messageBuffer.contains(receivedMessage.header.identifier))
- {
- kdDebug(14140) << k_funcinfo
- << TQString("retrieving buffered messsage, %1").arg(receivedMessage.header.identifier)
- << endl;
-
- // The message was split, try to reconstruct the message
- // with this received piece.
- Message bufferedMessage = m_messageBuffer[receivedMessage.header.identifier];
- // Remove the buffered message.
- m_messageBuffer.remove(receivedMessage.header.identifier);
-
- bufferedMessage.body.resize(bufferedMessage.body.size() + receivedMessage.header.dataSize);
- for(TQ_UINT32 i=0; i < receivedMessage.header.dataSize; i++){
- // Add the remaining message data to the buffered message.
- bufferedMessage.body[receivedMessage.header.dataOffset + i] = receivedMessage.body[i];
- }
- bufferedMessage.header.dataSize += receivedMessage.header.dataSize;
- bufferedMessage.header.dataOffset = 0;
-
- receivedMessage = bufferedMessage;
- }
-
- // Dispatch the received message.
- dispatch(receivedMessage);
- }
-}
-
-void Dispatcher::dispatch(const P2P::Message& message)
-
-{
- TransferContext *messageHandler = 0l;
-
- if(message.header.sessionId > 0)
- {
- if(m_sessions.contains(message.header.sessionId)){
- messageHandler = m_sessions[message.header.sessionId];
- }
- }
- else
- {
- TQString body =
- TQCString(message.body.data(), message.header.dataSize);
- TQRegExp regex("SessionID: ([0-9]*)\r\n");
- if(regex.search(body) > 0)
- {
- TQ_UINT32 sessionId = regex.cap(1).toUInt();
- if(m_sessions.contains(sessionId)){
- // Retrieve the message handler associated with the specified session Id.
- messageHandler = m_sessions[sessionId];
- }
- }
- else
- {
- // Otherwise, try to retrieve the message handler
- // based on the acknowlegded unique identifier.
- if(m_sessions.contains(message.header.ackUniqueIdentifier)){
- messageHandler =
- m_sessions[message.header.ackUniqueIdentifier];
- }
-
- if(!messageHandler)
- {
- // If the message handler still has not been found,
- // try to retrieve the handler based on the call id.
- regex = TQRegExp("Call-ID: \\{([0-9A-F\\-]*)\\}\r\n");
- regex.search(body);
- TQString callId = regex.cap(1);
-
- TransferContext *current = 0l;
- TQMap<TQ_UINT32, TransferContext*>::Iterator it = m_sessions.begin();
- for(; it != m_sessions.end(); it++)
- {
- current = it.data();
- if(current->m_callId == callId){
- messageHandler = current;
- break;
- }
- }
- }
- }
- }
-
- if(messageHandler){
- // Process the received message using the
- // retrieved registered handler.
- messageHandler->m_ackSessionIdentifier = message.header.identifier;
- messageHandler->m_ackUniqueIdentifier = message.header.ackSessionIdentifier;
- messageHandler->processMessage(message);
- }
- else
- {
- // There are no objects registered, with the retrieved session Id,
- // to handle the received message; default to this dispatcher.
-
- if(message.header.totalDataSize > message.header.dataOffset + message.header.dataSize)
- {
- // The entire message has not been received;
- // buffer the recevied portion of the original message.
- kdDebug(14140) << k_funcinfo
- << TQString("Buffering messsage, %1").arg(message.header.identifier)
- << endl;
- m_messageBuffer.insert(message.header.identifier, message);
- return;
- }
-
- TQString body =
- TQCString(message.body.data(), message.header.dataSize);
- kdDebug(14140) << k_funcinfo << "received, " << body << endl;
-
- if(body.startsWith("INVITE"))
- {
- // Retrieve the branch, call id, and session id.
- // These fields will be used later on in the p2p
- // transaction.
- TQRegExp regex(";branch=\\{([0-9A-F\\-]*)\\}\r\n");
- regex.search(body);
- TQString branch = regex.cap(1);
- regex = TQRegExp("Call-ID: \\{([0-9A-F\\-]*)\\}\r\n");
- regex.search(body);
- TQString callId = regex.cap(1);
- regex = TQRegExp("SessionID: ([0-9]*)\r\n");
- regex.search(body);
- TQString sessionId = regex.cap(1);
- // Retrieve the contact that requested the session.
- regex = TQRegExp("From: <msnmsgr:([^>]*)>");
- regex.search(body);
- TQString from = regex.cap(1);
- // Retrieve the application identifier which
- // is used to determine what type of session
- // is being requested.
- regex = TQRegExp("AppID: ([0-9]*)\r\n");
- regex.search(body);
- TQ_UINT32 applicationId = regex.cap(1).toUInt();
-
- if(applicationId == 1 || applicationId == 11 || applicationId == 12 )
- { //the AppID is 12 since Messenger 7.5
- // A contact has requested a session to download
- // a display icon (User Display Icon or CustomEmotion).
-
- regex = TQRegExp("Context: ([0-9a-zA-Z+/=]*)");
- regex.search(body);
- TQCString msnobj;
-
- // Decode the msn object from base64 encoding.
- KCodecs::base64Decode(regex.cap(1).utf8() , msnobj);
- kdDebug(14140) << k_funcinfo << "Contact requested, "
- << msnobj << endl;
-
- // Create a new transfer context that will handle
- // the user display icon transfer.
- TransferContext *current =
- new OutgoingTransfer(from, this, sessionId.toUInt());
- current->m_branch = branch;
- current->m_callId = callId;
- current->setType(P2P::UserDisplayIcon);
- // Add the transfer to the list.
- m_sessions.insert(sessionId.toUInt(), current);
-
- // Determine the display icon being requested.
- TQString fileName = objectList.contains(msnobj)
- ? objectList[msnobj]
- : m_pictureUrl;
- TQFile *source = new TQFile(fileName);
- // Try to open the source file for reading.
- // If an error occurs, send an internal
- // error message to the recipient.
- if(!source->open(IO_ReadOnly))
- {
- current->error();
- return;
- }
-
- current->m_file = source;
- // Acknowledge the session request.
- current->acknowledge(message);
-
- current->m_ackSessionIdentifier = message.header.identifier;
- current->m_ackUniqueIdentifier = message.header.ackSessionIdentifier;
- // Send a 200 OK message to the recipient.
- TQString content = TQString("SessionID: %1\r\n\r\n").arg(sessionId);
- current->sendMessage(OK, content);
- }
- else if(applicationId == 2)
- {
- // A contact has requested a session to
- // send a file.
-
- kdDebug(14140) << k_funcinfo << "File transfer invitation." << endl;
-
- // Create a new transfer context that will handle
- // the file transfer.
- TransferContext *transfer =
- new IncomingTransfer(from, this, sessionId.toUInt());
- transfer->m_branch = branch;
- transfer->m_callId = callId;
- transfer->setType(P2P::File);
- // Add the transfer to the list.
- m_sessions.insert(sessionId.toUInt(), transfer);
-
- regex = TQRegExp("Context: ([0-9a-zA-Z+/=]*)");
- regex.search(body);
- TQByteArray context;
-
- // Decode the file context from base64 encoding.
- KCodecs::base64Decode(regex.cap(1).utf8(), context);
- TQDataStream reader(context, IO_ReadOnly);
- reader.setByteOrder(TQDataStream::LittleEndian);
- //Retrieve the file info from the context field.
- // File Size [8..15] Int64
- reader.device()->at(8);
- TQ_INT64 fileSize;
- reader >> fileSize;
- // Flag [15..18] Int32
- // 0x00 File transfer with preview data.
- // 0x01 File transfer without preview data.
- // 0x02 Background sharing.
- TQ_INT32 flag;
- reader >> flag;
- kdDebug(14140) << flag << endl;
- // FileName UTF16 (Unicode) [19..539]
- TQByteArray bytes(520);
- reader.readRawBytes(bytes.data(), bytes.size());
- TQTextStream ts(bytes, IO_ReadOnly);
- ts.setEncoding(TQTextStream::Unicode);
- TQString fileName;
- fileName = ts.readLine().utf8();
-
- emit incomingTransfer(from, fileName, fileSize);
-
- kdDebug(14140) <<
- TQString("%1, %2 bytes.").arg(fileName, TQString::number(fileSize))
- << endl
- << endl;
-
- // Get the contact that is sending the file.
- Kopete::Contact *contact = getContactByAccountId(from);
-
- if(contact)
- {
- // Acknowledge the file invitation message.
- transfer->acknowledge(message);
-
- transfer->m_ackSessionIdentifier = message.header.identifier;
- transfer->m_ackUniqueIdentifier = message.header.ackSessionIdentifier;
-
- TQObject::connect(Kopete::TransferManager::transferManager(), TQT_SIGNAL(accepted(Kopete::Transfer*, const TQString&)), transfer, TQT_SLOT(slotTransferAccepted(Kopete::Transfer*, const TQString&)));
- TQObject::connect(Kopete::TransferManager::transferManager(), TQT_SIGNAL(refused(const Kopete::FileTransferInfo&)), transfer, TQT_SLOT(slotTransferRefused(const Kopete::FileTransferInfo&)));
-
- // Show the file transfer accept/decline dialog.
- Kopete::TransferManager::transferManager()->askIncomingTransfer(contact, fileName, fileSize, TQString(), sessionId);
- }
- else
- {
- kdWarning(14140) << fileName << " from " << from
- << " has failed; could not retrieve contact from contact list."
- << endl;
- transfer->m_ackSessionIdentifier = message.header.identifier;
- transfer->m_ackUniqueIdentifier = message.header.ackSessionIdentifier;
- transfer->sendMessage(ERROR);
- }
- }
- else if(applicationId == 4)
- {
-#if MSN_WEBCAM
- regex = TQRegExp("EUF-GUID: \\{([0-9a-zA-Z\\-]*)\\}");
- regex.search(body);
- TQString GUID=regex.cap(1);
-
- kdDebug(14140) << k_funcinfo << "webcam " << GUID << endl;
-
- Webcam::Who who;
- if(GUID=="4BD96FC0-AB17-4425-A14A-439185962DC8")
- { //that mean "I want to send MY webcam"
- who=Webcam::wViewer;
- }
- else if(GUID=="1C9AA97E-9C05-4583-A3BD-908A196F1E92")
- { //that mean "I want YOU to send YOUR webcam"
- who=Webcam::wProducer;
- }
- else
- { //unknown GUID
- //current->error();
- kdWarning(14140) << k_funcinfo << "Unknown GUID " << GUID << endl;
- return;
- }
-
- TransferContext *current = new P2P::Webcam(who, from, this, sessionId.toUInt());
- current->m_branch = branch;
- current->m_callId = callId;
-
- // Add the transfer to the list.
- m_sessions.insert(sessionId.toUInt(), current);
- // Acknowledge the session request.
- current->acknowledge(message);
- TQTimer::singleShot(0,current, TQT_SLOT(askIncommingInvitation()) );
-#endif
- }
- }
- else if(message.header.sessionId == 64)
- {
- // A contact has sent an inkformat (handwriting) gif.
- // NOTE The entire message body is UTF16 encoded.
- TQString body = "";
- for (TQ_UINT32 i=0; i < message.header.totalDataSize; i++){
- if (message.body[i] != TQChar('\0')){
- body += TQChar(message.body[i]);
- }
- }
-
- TQRegExp regex("Content-Type: ([A-Za-z0-9$!*/\\-]*)");
- regex.search(body);
- TQString contentType = regex.cap(1);
-
- if(contentType == "image/gif")
- {
- IncomingTransfer transfer(message.source, this, message.header.sessionId);
- transfer.acknowledge(message);
-
- regex = TQRegExp("base64:([0-9a-zA-Z+/=]*)");
- regex.search(body);
- TQString base64 = regex.cap(1);
- TQByteArray image;
-// Convert from base64 encoding to byte array.
- KCodecs::base64Decode(base64.utf8(), image);
-// Create a temporary file to store the image data.
- KTempFile *ink = new KTempFile(locateLocal("tmp", "inkformatgif-" ), ".gif");
- ink->setAutoDelete(true);
-// Save the image data to disk.
- ink->file()->writeBlock(image);
- ink->file()->close();
- displayIconReceived(ink, "inkformatgif");
- ink = 0l;
- }
- }
- }
-}
-
-void Dispatcher::messageAcknowledged(unsigned int correlationId, bool fullReceive)
-{
- if(fullReceive)
- {
- TransferContext *current = 0l;
- TQMap<TQ_UINT32, TransferContext*>::Iterator it = m_sessions.begin();
- for(; it != m_sessions.end(); it++)
- {
- current = it.data();
- if(current->m_transactionId == correlationId)
- {
- // Inform the transfer object of the acknowledge.
- current->readyWrite();
- break;
- }
- }
- }
-}
-
-Kopete::Contact* Dispatcher::getContactByAccountId(const TQString& accountId)
-{
- Kopete::Contact *contact = 0l;
- if(parent())
- {
- // Retrieve the contact from the current chat session context.
- Kopete::ChatSession *session = dynamic_cast<Kopete::ChatSession*>(parent()->parent());
- if(session)
- {
- contact = session->account()->contacts()[accountId];
- session->setCanBeDeleted(false);
- }
- }
- return contact;
-}
-
-Dispatcher::CallbackChannel::CallbackChannel(MSNSwitchBoardSocket *switchboard)
-{
- m_switchboard = switchboard;
-}
-
-Dispatcher::CallbackChannel::~CallbackChannel()
-{}
-
-TQ_UINT32 Dispatcher::CallbackChannel::send(const TQByteArray& stream)
-{
- return m_switchboard->sendCommand("MSG", "D", true, stream, true);
-}
-
-Dispatcher::CallbackChannel* Dispatcher::callbackChannel()
-{
- if(m_callbackChannel == 0l){
- MSNSwitchBoardSocket *callback = dynamic_cast<MSNSwitchBoardSocket *>(parent());
- if(callback == 0l) return 0l;
- m_callbackChannel = new Dispatcher::CallbackChannel(callback);
- }
-
- return m_callbackChannel;
-}
-
-#include "dispatcher.moc"