summaryrefslogtreecommitdiffstats
path: root/kopete/protocols/msn/msnswitchboardsocket.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kopete/protocols/msn/msnswitchboardsocket.cpp')
-rw-r--r--kopete/protocols/msn/msnswitchboardsocket.cpp1142
1 files changed, 0 insertions, 1142 deletions
diff --git a/kopete/protocols/msn/msnswitchboardsocket.cpp b/kopete/protocols/msn/msnswitchboardsocket.cpp
deleted file mode 100644
index 77b7b550..00000000
--- a/kopete/protocols/msn/msnswitchboardsocket.cpp
+++ /dev/null
@@ -1,1142 +0,0 @@
-/*
- msnswitchboardsocket.cpp - switch board connection socket
-
- Copyright (c) 2002 by Martijn Klingens <klingens@kde.org>
- Copyright (c) 2002-2006 by Olivier Goffart <ogoffart@ kde.org>
- Kopete (c) 2002-2005 by the Kopete developers <kopete-devel@kde.org>
-
- Portions of this code are taken from KMerlin,
- (c) 2001 by Olaf Lueg <olueg@olsd.de>
-
- *************************************************************************
- * *
- * 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 "msnswitchboardsocket.h"
-
-#include <stdlib.h>
-#include <time.h>
-#include <cmath>
-
-// qt
-#include <tqstylesheet.h>
-#include <tqregexp.h>
-#include <tqimage.h>
-#include <tqtimer.h>
-#include <tqfile.h>
-#include <tqfileinfo.h>
-
-// kde
-#include <kdebug.h>
-#include <tdemessagebox.h>
-#include <tdeapplication.h>
-#include <tdeaboutdata.h>
-#include <tdetempfile.h>
-#include <tdeconfig.h>
-#include <kmdcodec.h>
-#include <kstandarddirs.h>
-#include <tdetempfile.h>
-
-// for the display picture
-#include <msncontact.h>
-#include "msnnotifysocket.h"
-
-//kopete
-#include "msnaccount.h"
-#include "msnprotocol.h"
-#include "kopetemessage.h"
-#include "kopetecontact.h"
-#include "kopeteuiglobal.h"
-#include "kopeteemoticons.h"
-//#include "kopeteaccountmanager.h"
-//#include "kopeteprotocol.h"
-
-#include "sha1.h"
-
-#include "dispatcher.h"
-using P2P::Dispatcher;
-
-MSNSwitchBoardSocket::MSNSwitchBoardSocket( MSNAccount *account , TQObject *parent )
-: MSNSocket( parent )
-{
- m_account = account;
- m_recvIcons=0;
- m_emoticonTimer=0L;
- m_chunks=0;
- m_clientcapsSent=false;
- m_dispatcher = 0l;
- m_keepAlive = 0l;
- m_keepAliveNb=0;
-}
-
-MSNSwitchBoardSocket::~MSNSwitchBoardSocket()
-{
- kdDebug(14140) << k_funcinfo << endl;
-
- TQMap<TQString , TQPair<TQString , KTempFile*> >::Iterator it;
- for ( it = m_emoticons.begin(); it != m_emoticons.end(); ++it )
- {
- delete it.data().second;
- }
-}
-
-void MSNSwitchBoardSocket::connectToSwitchBoard(TQString ID, TQString address, TQString auth)
-{
- // we need these for the handshake later on (when we're connected)
- m_ID = ID;
- m_auth = auth;
-
- TQString server = address.left( address.find( ":" ) );
- uint port = address.right( address.length() - address.findRev( ":" ) - 1 ).toUInt();
-
- TQObject::connect( this, TQT_SIGNAL( blockRead( const TQByteArray & ) ),
- this, TQT_SLOT(slotReadMessage( const TQByteArray & ) ) );
-
- TQObject::connect( this, TQT_SIGNAL( onlineStatusChanged( MSNSocket::OnlineStatus ) ),
- this, TQT_SLOT( slotOnlineStatusChanged( MSNSocket::OnlineStatus ) ) );
-
- TQObject::connect( this, TQT_SIGNAL( socketClosed( ) ),
- this, TQT_SLOT( slotSocketClosed( ) ) );
-
- connect( server, port );
-}
-
-void MSNSwitchBoardSocket::handleError( uint code, uint id )
-{
- kdDebug(14140) << k_funcinfo << endl;
-
- TQString msg;
- MSNSocket::ErrorType type;
-
- switch( code )
- {
- case 208:
- {
- msg = i18n( "Invalid user:\n"
- "this MSN user does not exist; please check the MSN ID." );
- type = MSNSocket::ErrorServerError;
-
- userLeftChat(m_msgHandle , i18n("user never joined"));
- break;
- }
- case 215:
- {
- msg = i18n( "The user %1 is already in this chat." ).arg( m_msgHandle );
- type = MSNSocket::ErrorServerError;
-
- //userLeftChat(m_msgHandle , i18n("user was twice in this chat") ); //(the user shouln't join there
- break;
- }
- case 216:
- {
- msg = i18n( "The user %1 is online but has blocked you:\nyou can not talk to this user." ).arg( m_msgHandle );
- type = MSNSocket::ErrorInformation;
-
- userLeftChat(m_msgHandle, i18n("user blocked you"));
- break;
- }
- case 217:
- {
- // TODO: we need to know the nickname instead of the handle.
- msg = i18n( "The user %1 is currently not signed in.\n" "Messages will not be delivered." ).arg( m_msgHandle );
- type = MSNSocket::ErrorServerError;
-
- userLeftChat(m_msgHandle, i18n("user disconnected"));
- break;
- }
- case 713:
- {
- TQString msg = i18n( "You are trying to invite too many contacts to this chat at the same time" ).arg( m_msgHandle );
- type = MSNSocket::ErrorInformation;
-
- userLeftChat(m_msgHandle, i18n("user blocked you"));
- break;
- }
- case 911:
- {
- msg = i18n("Kopete MSN plugin has trouble authenticating with switchboard server.");
- type = MSNSocket::ErrorServerError;
-
- break;
- }
- default:
- MSNSocket::handleError( code, id );
- break;
- }
-
- if( !msg.isEmpty() )
- emit errorMessage( type, msg );
-}
-
-void MSNSwitchBoardSocket::parseCommand( const TQString &cmd, uint id ,
- const TQString &data )
-{
- if( cmd == "NAK" )
- {
- emit msgAcknowledgement(id, false); // msg was not accepted
- }
- else if( cmd == "ACK" )
- {
- emit msgAcknowledgement(id, true); // msg has received
- }
- else if( cmd == "JOI" )
- {
- // new user joins the chat, update user in chat list
- TQString handle = data.section( ' ', 0, 0 );
- TQString screenname = unescape(data.section( ' ', 1, 1 ));
- if( !m_chatMembers.contains( handle ) )
- m_chatMembers.append( handle );
- emit userJoined( handle, screenname, false );
- }
- else if( cmd == "IRO" )
- {
- // we have joined a multi chat session- this are the users in this chat
- TQString handle = data.section( ' ', 2, 2 );
- if( !m_chatMembers.contains( handle ) )
- m_chatMembers.append( handle );
-
- TQString screenname = unescape(data.section( ' ', 3, 3));
- emit userJoined( handle, screenname, true );
- }
- else if( cmd == "USR" )
- {
- slotInviteContact(m_msgHandle);
- }
- else if( cmd == "BYE" )
- {
- // some has disconnect from chat, update user in chat list
- cleanQueue(); //in case some message are waiting their emoticons, never mind, send them
-
- TQString handle = data.section( ' ', 0, 0 ).replace( "\r\n" , "" );
- userLeftChat( handle, (data.section( ' ', 1, 1 ) == "1" ) ? i18n("timeout") : TQString() );
- }
- else if( cmd == "MSG" )
- {
- TQString len = data.section( ' ', 2, 2 );
-
- // we need to know who's sending is the block...
- m_msgHandle = data.section( ' ', 0, 0 );
-
- /*//This is WRONG! the displayName is never updated on the switchboeardsocket
- //so we can't trust it.
- //that's why the official client does not uptade alaws the nickname immediately.
- if(m_account->contacts()[ m_msgHandle ])
- {
- TQString displayName=data.section( ' ', 1, 1 );
- if(m_account->contacts()[ m_msgHandle ]->displayName() != displayName)
- m_account->contacts()[ m_msgHandle ]->rename(displayName);
- }*/
-
- readBlock(len.toUInt());
- }
-}
-
-void MSNSwitchBoardSocket::slotReadMessage( const TQByteArray &bytes )
-{
- TQString msg = TQString::fromUtf8(bytes, bytes.size());
-
- TQRegExp rx("Content-Type: ([A-Za-z0-9/\\-]*)");
- rx.search(msg);
- TQString type=rx.cap(1);
-
- rx=TQRegExp("User-Agent: ([A-Za-z0-9./\\-]*)");
- rx.search(msg);
- TQString clientStr=rx.cap(1);
-
- if( !clientStr.isNull() && !m_msgHandle.isNull())
- {
- Kopete::Contact *c=m_account->contacts()[m_msgHandle];
- if(c)
- c->setProperty( MSNProtocol::protocol()->propClient , clientStr );
- }
-
- // incoming message for File-transfer
- if( type== "text/x-msmsgsinvite" )
- {
- emit invitation(m_msgHandle,msg);
- }
- else if( type== "text/x-msmsgscontrol" )
- {
- TQString message;
- message = msg.right( msg.length() - msg.findRev( " " ) - 1 );
- message = message.replace( "\r\n" ,"" );
- emit receivedTypingMsg( message.lower(), true );
- }
- else if(type == "text/x-msnmsgr-datacast")
- {
- if(msg.contains("ID:"))
- {
- TQRegExp rx("ID: ([0-9]*)");
- rx.search(msg);
- uint dataCastId = rx.cap(1).toUInt();
- if( dataCastId == 1 )
- {
- kdDebug(14140) << k_funcinfo << "Received a nudge !" << endl;
- emit nudgeReceived(m_msgHandle);
- }
- }
- }
- else if(type=="text/plain" /* || type.isEmpty()*/ )
- {
- // Some MSN Clients (like CCMSN) don't like to stick to the rules.
- // In case of CCMSN, it doesn't send what the content type is when
- // sending a text message. So if it's not supplied, we'll just
- // assume its that.
-
- TQColor fontColor;
- TQFont font;
-
- if ( msg.contains( "X-MMS-IM-Format" ) )
- {
- TQString fontName;
- TQString fontInfo;
- TQString color;
-
- rx=TQRegExp("X-MMS-IM-Format: ([^\r\n]*)");
- rx.search(msg);
- fontInfo =rx.cap(1);
-
- color = parseFontAttr(fontInfo, "CO");
-
- // FIXME: this is so BAAAAAAAAAAAAD :(
- if (!color.isEmpty() && color.toInt(0,16)!=0)
- {
- if ( color.length() == 2) // only #RR (red color) given
- fontColor.setRgb(
- color.mid(0,2).toInt(0,16),
- 0,
- 0);
- else if ( color.length() == 4) // #GGRR (green, red) given.
- {
- fontColor.setRgb(
- color.mid(2,2).toInt(0,16),
- color.mid(0,2).toInt(0,16),
- 0);
- }
- else if ( color.length() == 6) // full #BBGGRR given
- {
- fontColor.setRgb(
- color.mid(4,2).toInt(0, 16),
- color.mid(2,2).toInt(0,16),
- color.mid(0,2).toInt(0,16));
- }
- }
-
- fontName = parseFontAttr(fontInfo, "FN").replace( "%20" , " " );
-
- // Some clients like Trillian and Kopete itself send a font
- // name of 'MS Serif' since MS changed the server to
- // _require_ a font name specified in june 2002.
- // MSN's own client defaults to 'MS Sans Serif', which also
- // has issues.
- // Handle 'MS Serif' and 'MS Sans Serif' as an empty font name
- if( !fontName.isEmpty() && fontName != "MS Serif" && fontName != "MS Sans Serif" )
- {
- TQString ef=parseFontAttr( fontInfo, "EF" );
-
- font = TQFont( fontName,
- parseFontAttr( fontInfo, "PF" ).toInt(), // font size
- ef.contains( 'B' ) ? TQFont::Bold : TQFont::Normal,
- ef.contains( 'I' ) );
- font.setUnderline(ef.contains( 'U' ));
- font.setStrikeOut(ef.contains( 'S' ));
- }
- }
-
- TQPtrList<Kopete::Contact> others;
- others.append( m_account->myself() );
- TQStringList::iterator it2;
- for( it2 = m_chatMembers.begin(); it2 != m_chatMembers.end(); ++it2 )
- {
- if( *it2 != m_msgHandle )
- others.append( m_account->contacts()[ *it2 ] );
- }
-
- TQString message=msg.right( msg.length() - msg.find("\r\n\r\n") - 4 );
-
- //Stupid MSN PLUS colors code. message with incorrect charactere are not showed correctly in the chatwindow.
- //TODO: parse theses one to show the color too in Kopete
- message.replace("\3","").replace("\4","").replace("\2","").replace("\5","").replace("\6","").replace("\7","");
-
- if(!m_account->contacts()[m_msgHandle])
- {
- //this may happens if the contact has been deleted.
- kdDebug(14140) << k_funcinfo <<"WARNING: contact is null, adding it" <<endl;
- if( !m_chatMembers.contains( m_msgHandle ) )
- m_chatMembers.append( m_msgHandle );
- emit userJoined( m_msgHandle , m_msgHandle , false);
- }
-
- Kopete::Message kmsg( m_account->contacts()[ m_msgHandle ], others,
- message,
- Kopete::Message::Inbound , Kopete::Message::PlainText );
-
- kmsg.setFg( fontColor );
- kmsg.setFont( font );
-
- rx=TQRegExp("Chunks: ([0-9]*)");
- rx.search(msg);
- unsigned int chunks=rx.cap(1).toUInt();
- rx=TQRegExp("Chunk: ([0-9]*)");
- rx.search(msg);
- unsigned int chunk=rx.cap(1).toUInt();
-
- if(chunk != 0 && !m_msgQueue.isEmpty())
- {
- TQString msg=m_msgQueue.last().plainBody();
- m_msgQueue.pop_back(); //removes the last item
- kmsg.setBody( msg+ message, Kopete::Message::PlainText );
- }
-
- if(chunk == 0 )
- m_chunks=chunks;
- else if(chunk+1 >= m_chunks)
- m_chunks=0;
-
- if ( m_recvIcons > 0 || m_chunks > 0)
- { //Some custom emoticons are waiting to be received. so append the message to the queue
- //Or the message has not been fully received, so same thing
- kdDebug(14140) << k_funcinfo << "Message not fully received => append to queue. Emoticon left: " << m_recvIcons << " chunks: " << chunk+1 << " of " << m_chunks <<endl;
- m_msgQueue.append( kmsg );
- if(!m_emoticonTimer) //to be sure no message will be lost, we will appends message to
- { // the queue in 15 secondes even if we have not received emoticons
- m_emoticonTimer=new TQTimer(this);
- TQObject::connect(m_emoticonTimer , TQT_SIGNAL(timeout()) , this, TQT_SLOT(cleanQueue()));
- m_emoticonTimer->start( 15000 , true );
- }
- }
- else
- emit msgReceived( parseCustomEmoticons( kmsg ) );
-
- }
- else if( type== "text/x-mms-emoticon" || type== "text/x-mms-animemoticon")
- {
- // TODO remove Displatcher.
- TDEConfig *config = TDEGlobal::config();
- config->setGroup( "MSN" );
- if ( config->readBoolEntry( "useCustomEmoticons", true ) )
- {
- TQRegExp rx("([^\\s]*)[\\s]*(<msnobj [^>]*>)");
- rx.setMinimal(true);
- int pos = rx.search(msg);
- while( pos != -1)
- {
- TQString msnobj=rx.cap(2);
- TQString txt=rx.cap(1);
- kdDebug(14140) << k_funcinfo << "emoticon: " << txt << " msnobj: " << msnobj<< endl;
-
- if( !m_emoticons.contains(msnobj) || !m_emoticons[msnobj].second )
- {
- m_emoticons.insert(msnobj, tqMakePair(txt,(KTempFile*)0L));
- MSNContact *c=static_cast<MSNContact*>(m_account->contacts()[m_msgHandle]);
- if(!c)
- return;
-
- // we are receiving emoticons, so delay message display until received signal
- m_recvIcons++;
- PeerDispatcher()->requestDisplayIcon(m_msgHandle, msnobj);
- }
- pos=rx.search(msg, pos+rx.matchedLength());
- }
- }
- }
- else if( type== "application/x-msnmsgrp2p" )
- {
- PeerDispatcher()->slotReadMessage(m_msgHandle, bytes);
- }
- else if( type == "text/x-clientcaps" )
- {
- rx=TQRegExp("Client-Name: ([A-Za-z0-9.$!*/% \\-]*)");
- rx.search(msg);
- clientStr=unescape( rx.cap(1) );
-
- if( !clientStr.isNull() && !m_msgHandle.isNull())
- {
- Kopete::Contact *c=m_account->contacts()[m_msgHandle];
- if(c)
- c->setProperty( MSNProtocol::protocol()->propClient , clientStr );
- }
-
- if(!m_clientcapsSent)
- {
- TDEConfig *config = TDEGlobal::config();
- config->setGroup( "MSN" );
-
- TQString JabberID;
- if(config->readBoolEntry("SendJabber", true))
- JabberID=config->readEntry("JabberAccount");
-
- if(!JabberID.isEmpty())
- JabberID="JabberID: "+JabberID +"\r\n";
-
- if( config->readBoolEntry("SendClientInfo", true) || !JabberID.isEmpty())
- {
-
- TQCString message = TQString( "MIME-Version: 1.0\r\n"
- "Content-Type: text/x-clientcaps\r\n"
- "Client-Name: Kopete/"+escape(kapp->aboutData()->version())+"\r\n"
- +JabberID+
- "\r\n" ).utf8();
-
- TQString args = "U";
- sendCommand( "MSG", args, true, message );
- }
- m_clientcapsSent=true;
- }
-
-
- }
- else if(type == "image/gif" || msg.contains("Message-ID:"))
- {
- // Incoming inkformatgif.
- TQRegExp regex("Message-ID: \\{([0-9A-F\\-]*)\\}");
- regex.search(msg);
- TQString messageId = regex.cap(1);
- regex = TQRegExp("Chunks: (\\d+)");
- regex.search(msg);
- TQString chunks = regex.cap(1);
- regex = TQRegExp("Chunk: (\\d+)");
- regex.search(msg);
- TQString chunk = regex.cap(1);
-
- if(!messageId.isNull())
- {
- bool valid = true;
- // Retrieve the nmber of data chunks.
- TQ_UINT32 numberOfChunks = chunks.toUInt(&valid);
- if(valid && (numberOfChunks > 1))
- {
- regex = TQRegExp("base64:([0-9a-zA-Z+/=]+)");
- regex.search(msg);
- // Retrieve the first chunk of the ink format gif.
- TQString base64 = regex.cap(1);
- // More chunks are expected, buffer the chunk received.
- InkMessage inkMessage;
- inkMessage.chunks = numberOfChunks;
- inkMessage.data += base64;
- m_inkMessageBuffer.insert(messageId, inkMessage);
- }
- }
- else
- {
- // There is only one chunk of data.
- regex = TQRegExp("base64:([0-9a-zA-Z+/=]*)");
- regex.search(msg);
- // Retrieve the base64 encoded ink data.
- TQString data = regex.cap(1);
- DispatchInkMessage(data);
- }
-
- if(!messageId.isNull())
- {
- if(m_inkMessageBuffer.contains(messageId))
- {
- if(chunks.isNull())
- {
- InkMessage inkMessage = m_inkMessageBuffer[messageId];
- inkMessage.data += msg.section("\r\n\r\n", -1);
- if(inkMessage.chunks == chunk.toUInt() + 1)
- {
- DispatchInkMessage(inkMessage.data);
- // Remove the ink message from the buffer.
- m_inkMessageBuffer.remove(messageId);
- }
- }
- }
- }
- }
- else
- {
- kdDebug(14140) << k_funcinfo <<" Unknown type '" << type << "' message: \n"<< msg <<endl;
- }
-}
-
-void MSNSwitchBoardSocket::DispatchInkMessage(const TQString& base64String)
-{
- TQByteArray image;
- // Convert from base64 encoded string to byte array.
- KCodecs::base64Decode(base64String.utf8() , image);
- KTempFile *inkImage = new KTempFile(locateLocal( "tmp", "inkformatgif-" ), ".gif");
- inkImage->setAutoDelete(true);
- inkImage->file()->writeBlock(image.data(), image.size());
- inkImage->file()->close();
-
- slotEmoticonReceived(inkImage , "inkformatgif");
- inkImage = 0l;
-}
-
-void MSNSwitchBoardSocket::sendTypingMsg( bool isTyping )
-{
- if( !isTyping )
- return;
-
- if ( onlineStatus() != Connected || m_chatMembers.empty())
- {
- //we are not yet in a chat.
- //if we send that command now, we may get disconnected.
- return;
- }
-
-
- TQCString message = TQString( "MIME-Version: 1.0\r\n"
- "Content-Type: text/x-msmsgscontrol\r\n"
- "TypingUser: " + m_myHandle + "\r\n"
- "\r\n" ).utf8();
-
- // Length is appended by sendCommand()
- TQString args = "U";
- sendCommand( "MSG", args, true, message );
-}
-
-// this Invites an Contact
-void MSNSwitchBoardSocket::slotInviteContact(const TQString &handle)
-{
- m_msgHandle=handle;
- sendCommand( "CAL", handle );
-}
-//
-// Send a custum emoticon
-//
-int MSNSwitchBoardSocket::sendCustomEmoticon(const TQString &name, const TQString &filename)
-{
- TQString picObj;
-
- //try to find it in the cache.
- const TQMap<TQString, TQString> objectList = PeerDispatcher()->objectList;
- for (TQMap<TQString,TQString>::ConstIterator it = objectList.begin(); it != objectList.end(); ++it )
- {
- if(it.data() == filename)
- {
- picObj=it.key();
- break;
- }
- }
-
- if(picObj.isNull())
- { //if not found in the cache, generate the picture object
- TQFileInfo fi(filename);
- // open the icon file
- TQFile pictFile(fi.filePath());
- if (pictFile.open(IO_ReadOnly)) {
-
- TQByteArray ar = pictFile.readAll();
- pictFile.close();
-
- TQString sha1d = TQString(KCodecs::base64Encode(SHA1::hash(ar)));
- TQString size = TQString::number( pictFile.size() );
- TQString all = "Creator" + m_account->accountId() + "Size" + size + "Type2Location" + fi.fileName() + "FriendlyAAA=SHA1D" + sha1d;
- TQString sha1c = TQString(KCodecs::base64Encode(SHA1::hashString(all.utf8())));
- picObj = "<msnobj Creator=\"" + m_account->accountId() + "\" Size=\"" + size + "\" Type=\"2\" Location=\""+ fi.fileName() + "\" Friendly=\"AAA=\" SHA1D=\""+sha1d+ "\" SHA1C=\""+sha1c+"\"/>";
-
- PeerDispatcher()->objectList.insert(picObj, filename);
- }
- else
- return 0;
- }
-
- TQString msg = "MIME-Version: 1.0\r\n"
- "Content-Type: text/x-mms-emoticon\r\n"
- "\r\n" +
- name + "\t" + picObj + "\t\r\n";
-
- return sendCommand("MSG", "A", true, msg.utf8());
-
-}
-
-// this sends a short message to the server
-int MSNSwitchBoardSocket::sendMsg( const Kopete::Message &msg )
-{
- if ( onlineStatus() != Connected || m_chatMembers.empty())
- {
-// m_messagesQueue.append(msg);
- return -1;
- }
-
-#if 0 //this is to test webcam
- if(msg.plainBody().contains("/webcam"))
- {
- PeerDispatcher()->startWebcam( m_myHandle , m_msgHandle);
- return -3;
- }
-#endif
-
- TDEConfig *config = TDEGlobal::config();
- config->setGroup( "MSN" );
- if ( config->readBoolEntry( "exportEmoticons", false ) )
- {
- TQMap<TQString, TQStringList> emap = Kopete::Emoticons::self()->emoticonAndPicList();
-
- // Check the list for any custom emoticons
- for (TQMap<TQString, TQStringList>::const_iterator itr = emap.begin(); itr != emap.end(); itr++)
- {
- for ( TQStringList::const_iterator itr2 = itr.data().constBegin(); itr2 != itr.data().constEnd(); ++itr2 )
- {
- if ( msg.plainBody().contains( *itr2 ) )
- sendCustomEmoticon( *itr2, itr.key() );
- }
- }
- }
-
- if( msg.format() & Kopete::Message::RichText )
- {
- TQRegExp regex("^\\s*<img src=\"([^>\"]+)\"[^>]*>\\s*$");
- if(regex.search(msg.escapedBody()) != -1)
- {
- // FIXME why are we sending the images.. the contact should request them.
- PeerDispatcher()->sendImage(regex.cap(1), m_msgHandle);
- return -3;
- }
- }
-
- // User-Agent is not a official flag, but PIDGIN has it
- TQString UA;
- if( config->readBoolEntry("SendClientInfo", true) )
- {
- UA="User-Agent: Kopete/"+escape(kapp->aboutData()->version())+"\r\n";
- }
-
- TQString head =
- "MIME-Version: 1.0\r\n"
- "Content-Type: text/plain; charset=UTF-8\r\n"
- +UA+
- "X-MMS-IM-Format: ";
-
- if(msg.font() != TQFont() )
- {
- //It's verry strange that if the font name is bigger than 31 char, the _server_ close the socket and don't deliver the message.
- // the real question is why ? my guess is that MS patched the server because a bug in their client, but that's just a guess.
- // - Olivier 06-2005
- head += "FN=" + escape( msg.font().family().left(31));
- head += "; EF=";
- if(msg.font().bold())
- head += "B";
- if(msg.font().italic())
- head += "I";
- if(msg.font().strikeOut())
- head += "S";
- if(msg.font().underline())
- head += "U";
- head += "; ";
- }
- else head+="FN=; EF=; ";
- /*
- * I don't know what to set by default, so i decided to set nothing. CF Bug 82734
- * (but don't forgeto to add an empty FN= and EF= , or webmessenger will break. (CF Bug 102371) )
- else head+="FN=MS%20Serif; EF=; ";
- */
-
- // Color support
- if (msg.fg().isValid())
- {
- TQString colorCode = TQColor(msg.fg().blue(),msg.fg().green(),msg.fg().red()).name().remove(0,1); //colors aren't sent in RGB but in BGR (O.G.)
- head += "CO=" + colorCode;
- }
- else
- {
- head += "CO=0";
- }
-
- head += "; CS=0; PF=0";
- if (msg.plainBody().isRightToLeft())
- head += "; RL=1";
- head += "\r\n";
-
- TQString message= msg.plainBody().replace( "\n" , "\r\n" );
-
- //-- Check if the message isn't too big, TODO: do that at the libkopete level.
- int len_H=head.utf8().length(); // != head.length() because i need the size in butes and
- int len_M=message.utf8().length(); // some utf8 char may be longer than one byte
- if( len_H+len_M >= 1660 ) //1664 is the maximum size of messages allowed by the server
- {
- //We will certenly split the message in several ones.
- //It's possible to made the opposite client join them, as explained in this MS Word document
- //http://www.bot-depot.com/forums/index.php?act=Attach&type=post&id=35110
-
- head+="Message-ID: {7B7B34E6-7A8D-44FF-926C-1799156B58"+TQString::number( rand()%10)+TQString::number( rand()%10)+"}\r\n";
- int len_H=head.utf8().length()+ 14; //14 is the size of "Chunks: x"
- //this is the size of each part of the message (excluding the header)
- int futurmessages_size=1400; //1400 is a common good size
- //int futurmessages_size=1664-len_H;
-
- int nb=(int)ceil((float)(len_M)/(float)(futurmessages_size));
-
- if(KMessageBox::warningContinueCancel(0L /* FIXME: we should try to find a parent somewere*/ ,
- i18n("The message you are trying to send is too long; it will be split into %1 messages.").arg(nb) ,
- i18n("Message too big - MSN Plugin" ), KStdGuiItem::cont() , "SendLongMessages" )
- == KMessageBox::Continue )
- {
- int place=0;
- int result;
- int chunk=0;
- do
- {
- TQString m=message.mid(place, futurmessages_size);
- place += futurmessages_size;
-
- //make sure the size is not too big because of utf8
- int d=m.utf8().length() + len_H -1664;
- if( d > 0 )
- {//it contains some utf8 chars, so we strip the string a bit.
- m=m.left( futurmessages_size - d );
- place -= d;
- }
-
- //try to snip on space if possible
- int len=m.length();
- d=0;
- while(d<200 && !m[len-d].isSpace() )
- d++;
- if(d<200)
- {
- m=m.left(len-d);
- place -= d;
- }
- TQString chunk_str;
- if(chunk==0)
- chunk_str="Chunks: "+TQString::number(nb)+"\r\n";
- else if(chunk<nb)
- chunk_str="Chunk: "+TQString::number(chunk)+"\r\n";
- else
- {
- kdDebug(14140) << k_funcinfo <<"The message is slit in more than initially estimated" <<endl;
- }
- result=sendCommand( "MSG", "A", true, (head+chunk_str+"\r\n"+m).utf8() );
- chunk++;
- }
- while(place < len_M) ;
-
- while(chunk<nb)
- {
- kdDebug(14140) << k_funcinfo <<"The message is plit in less than initially estimated. Sending empty message to complete" <<endl;
- TQString chunk_str="Chunk: "+TQString::number(chunk);
- sendCommand( "MSG", "A", true, (head+chunk_str+"\r\n").utf8() );
- chunk++;
- }
- return result;
- }
- return -2; //the message hasn't been sent.
- }
-
- if(!m_keepAlive)
- {
- m_keepAliveNb=20;
- m_keepAlive=new TQTimer(this);
- TQObject::connect(m_keepAlive, TQT_SIGNAL(timeout()) , this , TQT_SLOT(slotKeepAliveTimer()));
- m_keepAlive->start(50*1000);
- }
-
-
- return sendCommand( "MSG", "A", true, (head+"\r\n"+message).utf8() );
-}
-
-void MSNSwitchBoardSocket::slotSocketClosed( )
-{
- for( TQStringList::Iterator it = m_chatMembers.begin(); it != m_chatMembers.end(); ++it )
- {
- emit userLeft( (*it), i18n("connection closed"));
- }
-
- // we have lost the connection, send a message to chatwindow (this will not displayed)
-// emit switchBoardIsActive(false);
- emit switchBoardClosed( );
-}
-
-void MSNSwitchBoardSocket::slotCloseSession()
-{
- sendCommand( "OUT", TQString(), false );
- disconnect();
-}
-
-// Check if we are connected. If so, then send the handshake.
-void MSNSwitchBoardSocket::slotOnlineStatusChanged( MSNSocket::OnlineStatus status )
-{
- if (status == Connected)
- {
- TQCString command;
- TQString args;
-
- if( !m_ID ) // we're inviting
- {
- command = "USR";
- args = m_myHandle + " " + m_auth;
- }
- else // we're invited
- {
- command = "ANS";
- args = m_myHandle + " " + m_auth + " " + m_ID;
- }
- sendCommand( command, args );
-
- if(!m_keepAlive)
- {
- m_keepAliveNb=20;
- m_keepAlive=new TQTimer(this);
- TQObject::connect(m_keepAlive, TQT_SIGNAL(timeout()) , this , TQT_SLOT(slotKeepAliveTimer()));
- m_keepAlive->start(50*1000);
- }
- }
-}
-
-void MSNSwitchBoardSocket::userLeftChat(const TQString& handle , const TQString &reason)
-{
- emit userLeft( handle, reason );
-
- if( m_chatMembers.contains( handle ) )
- m_chatMembers.remove( handle );
-
- if(m_chatMembers.isEmpty())
- disconnect();
-}
-
-void MSNSwitchBoardSocket::requestDisplayPicture()
-{
- MSNContact *contact = static_cast<MSNContact*>(m_account->contacts()[m_msgHandle]);
- if(!contact) return;
-
- PeerDispatcher()->requestDisplayIcon(m_msgHandle, contact->object());
-}
-
-void MSNSwitchBoardSocket::slotEmoticonReceived( KTempFile *file, const TQString &msnObj )
-{
- kdDebug(14141) << k_funcinfo << msnObj << endl;
-
- if(m_emoticons.contains(msnObj))
- { //it's an emoticon
- m_emoticons[msnObj].second=file;
-
- if( m_recvIcons > 0 )
- m_recvIcons--;
- kdDebug(14140) << k_funcinfo << "emoticons received queue is now: " << m_recvIcons << endl;
-
- if ( m_recvIcons <= 0 )
- cleanQueue();
- }
- else if(msnObj == "inkformatgif")
- {
- TQString msg=i18n("<img src=\"%1\" alt=\"Typewrited message\" />" ).arg( file->name() );
-
- kdDebug(14140) << k_funcinfo << file->name() <<endl;
-
- m_typewrited.append(file);
- m_typewrited.setAutoDelete(true);
-
- TQPtrList<Kopete::Contact> others;
- others.append( m_account->myself() );
-
- TQStringList::iterator it2;
- for( it2 = m_chatMembers.begin(); it2 != m_chatMembers.end(); ++it2 )
- {
- if( *it2 != m_msgHandle )
- others.append( m_account->contacts()[ *it2 ] );
- }
-
- if(!m_account->contacts()[m_msgHandle])
- {
- //this may happens if the contact has been deleted.
- kdDebug(14140) << k_funcinfo <<"WARNING: contact is null, adding it" <<endl;
- if( !m_chatMembers.contains( m_msgHandle ) )
- m_chatMembers.append( m_msgHandle );
- emit userJoined( m_msgHandle , m_msgHandle , false);
- }
-
- Kopete::Message kmsg( m_account->contacts()[ m_msgHandle ], others,
- msg, Kopete::Message::Inbound , Kopete::Message::RichText );
-
- emit msgReceived( kmsg );
- }
- else //if it is not an emoticon,
- { // it's certenly the displaypicture.
- MSNContact *c=static_cast<MSNContact*>(m_account->contacts()[m_msgHandle]);
- if(c && c->object()==msnObj)
- c->setDisplayPicture(file);
- else
- delete file;
- }
-}
-
-void MSNSwitchBoardSocket::slotIncomingFileTransfer(const TQString& from, const TQString& /*fileName*/, TQ_INT64 /*fileSize*/)
-{
- TQPtrList<Kopete::Contact> others;
- others.append( m_account->myself() );
- TQStringList::iterator it2;
- for( it2 = m_chatMembers.begin(); it2 != m_chatMembers.end(); ++it2 )
- {
- if( *it2 != m_msgHandle )
- others.append( m_account->contacts()[ *it2 ] );
- }
-
- if(!m_account->contacts()[m_msgHandle])
- {
- //this may happens if the contact has been deleted.
- kdDebug(14140) << k_funcinfo <<"WARNING: contact is null, adding it" <<endl;
- if( !m_chatMembers.contains( m_msgHandle ) )
- m_chatMembers.append( m_msgHandle );
- emit userJoined( m_msgHandle , m_msgHandle , false);
- }
- TQString invite = "Incoming file transfer.";
- Kopete::Message msg =
- Kopete::Message(m_account->contacts()[from], others, invite, Kopete::Message::Internal, Kopete::Message::PlainText);
- emit msgReceived(msg);
-}
-
-void MSNSwitchBoardSocket::cleanQueue()
-{
- if(m_emoticonTimer)
- {
- m_emoticonTimer->stop();
- m_emoticonTimer->deleteLater();
- m_emoticonTimer=0L;
- }
- kdDebug(14141) << k_funcinfo << m_msgQueue.count() << endl;
-
- TQValueList<const Kopete::Message>::Iterator it_msg;
- for ( it_msg = m_msgQueue.begin(); it_msg != m_msgQueue.end(); ++it_msg )
- {
- Kopete::Message kmsg = (*it_msg);
- emit msgReceived( parseCustomEmoticons( kmsg ) );
- }
- m_msgQueue.clear();
-}
-
-Kopete::Message &MSNSwitchBoardSocket::parseCustomEmoticons(Kopete::Message &kmsg)
-{
- TQString message=kmsg.escapedBody();
- TQMap<TQString , TQPair<TQString , KTempFile*> >::Iterator it;
- for ( it = m_emoticons.begin(); it != m_emoticons.end(); ++it )
- {
- TQString es=TQStyleSheet::escape(it.data().first);
- KTempFile *f=it.data().second;
- if(message.contains(es) && f)
- {
- TQString imgPath = f->name();
- TQImage iconImage(imgPath);
- /* We don't use a comple algoritm (like the one in the #if) because the msn client shows
- * emoticons like that. So, in that case, we show like the MSN client */
- #if 0
- TQString em = TQRegExp::escape( es );
- message.replace( TQRegExp(TQString::fromLatin1( "(^|[\\W\\s]|%1)(%2)(?!\\w)" ).arg(em).arg(em)),
- TQString::fromLatin1("\\1<img align=\"center\" width=\"") +
- #endif
- //match any occurence which is not in a html tag.
- message.replace( TQRegExp(TQString::fromLatin1("%1(?![^><]*>)").arg(TQRegExp::escape(es))),
- TQString::fromLatin1("<img align=\"center\" width=\"") +
- TQString::number(iconImage.width()) +
- TQString::fromLatin1("\" height=\"") +
- TQString::number(iconImage.height()) +
- TQString::fromLatin1("\" src=\"") + imgPath +
- TQString::fromLatin1("\" title=\"") + es +
- TQString::fromLatin1("\" alt=\"") + es +
- TQString::fromLatin1( "\"/>" ) );
- kmsg.setBody(message, Kopete::Message::RichText);
- }
- }
- return kmsg;
-}
-
-int MSNSwitchBoardSocket::sendNudge()
-{
- TQCString message = TQString( "MIME-Version: 1.0\r\n"
- "Content-Type: text/x-msnmsgr-datacast\r\n"
- "\r\n"
- "ID: 1\r\n"
- "\r\n\r\n" ).utf8();
-
- TQString args = "U";
- return sendCommand( "MSG", args, true, message );
-}
-
-
-
-// FIXME: This is nasty... replace with a regexp or so.
-TQString MSNSwitchBoardSocket::parseFontAttr(TQString str, TQString attr)
-{
- TQString tmp;
- int pos1=0, pos2=0;
-
- pos1 = str.find(attr + "=");
-
- if (pos1 == -1)
- return "";
-
- pos2 = str.find(";", pos1+3);
-
- if (pos2 == -1)
- tmp = str.mid(pos1+3, str.length() - pos1 - 3);
- else
- tmp = str.mid(pos1+3, pos2 - pos1 - 3);
-
- return tmp;
-}
-
-Dispatcher* MSNSwitchBoardSocket::PeerDispatcher()
-{
- if(!m_dispatcher)
- {
- // Create a new msnslp dispatcher to handle
- // all peer to peer requests.
- TQStringList ip;
- if(m_account->notifySocket())
- {
- ip << m_account->notifySocket()->localIP();
- if(m_account->notifySocket()->localIP() != m_account->notifySocket()->getLocalIP())
- ip << m_account->notifySocket()->getLocalIP();
- }
- m_dispatcher = new Dispatcher(this, m_account->accountId(),ip );
-
-// TQObject::connect(this, TQT_SIGNAL(blockRead(const TQByteArray&)), m_dispatcher, TQT_SLOT(slotReadMessage(const TQByteArray&)));
-// TQObject::connect(m_dispatcher, TQT_SIGNAL(sendCommand(const TQString&, const TQString&, bool, const TQByteArray&, bool)), this, TQT_SLOT(sendCommand(const TQString&, const TQString&, bool, const TQByteArray&, bool)));
- TQObject::connect(m_dispatcher, TQT_SIGNAL(incomingTransfer(const TQString&, const TQString&, TQ_INT64)), this, TQT_SLOT(slotIncomingFileTransfer(const TQString&, const TQString&, TQ_INT64)));
- TQObject::connect(m_dispatcher, TQT_SIGNAL(displayIconReceived(KTempFile *, const TQString&)), this, TQT_SLOT(slotEmoticonReceived( KTempFile *, const TQString&)));
- TQObject::connect(this, TQT_SIGNAL(msgAcknowledgement(unsigned int, bool)), m_dispatcher, TQT_SLOT(messageAcknowledged(unsigned int, bool)));
- m_dispatcher->m_pictureUrl = m_account->pictureUrl();
- }
- return m_dispatcher;
-}
-
-void MSNSwitchBoardSocket::slotKeepAliveTimer( )
-{
- /*
- This is a workaround against the bug 113425
- The problem: the P2P::Webcam class is parent of us, and when we get deleted, it get deleted.
- the correct solution would be to change that.
- The second problem: after one minute of inactivity, the official client close the chat socket.
- the workaround: we simulate the activity by sending small packet each 50 seconds
- the nice side effect: the "xxx has closed the chat" is now meaningfull
- the bad side effect: some switchboard connection may be maintained for really long time!
- */
-
- if ( onlineStatus() != Connected || m_chatMembers.empty())
- {
- //we are not yet in a chat.
- //if we send that command now, we may get disconnected.
- return;
- }
-
-
- TQCString message = TQString( "MIME-Version: 1.0\r\n"
- "Content-Type: text/x-keepalive\r\n"
- "\r\n" ).utf8();
-
- // Length is appended by sendCommand()
- TQString args = "U";
- sendCommand( "MSG", args, true, message );
-
- m_keepAliveNb--;
- if(m_keepAliveNb <= 0)
- {
- m_keepAlive->deleteLater();
- m_keepAlive=0L;
- }
-}
-
-#include "msnswitchboardsocket.moc"
-
-// vim: set noet ts=4 sts=4 sw=4:
-