diff options
Diffstat (limited to 'kopete/protocols/msn/dispatcher.cpp')
-rw-r--r-- | kopete/protocols/msn/dispatcher.cpp | 647 |
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" |