summaryrefslogtreecommitdiffstats
path: root/kopete/protocols/msn/msnnotifysocket.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kopete/protocols/msn/msnnotifysocket.cpp')
-rw-r--r--kopete/protocols/msn/msnnotifysocket.cpp1309
1 files changed, 1309 insertions, 0 deletions
diff --git a/kopete/protocols/msn/msnnotifysocket.cpp b/kopete/protocols/msn/msnnotifysocket.cpp
new file mode 100644
index 00000000..e31e0257
--- /dev/null
+++ b/kopete/protocols/msn/msnnotifysocket.cpp
@@ -0,0 +1,1309 @@
+/*
+ msnnotifysocket.cpp - Notify Socket for the MSN Protocol
+
+ Copyright (c) 2002 by Duncan Mac-Vicar Prett <duncan@kde.org>
+ Copyright (c) 2002-2003 by Martijn Klingens <klingens@kde.org>
+ Copyright (c) 2002-2005 by Olivier Goffart <ogoffart at kde.org>
+ Copyright (c) 2005 by Michaël Larouche <michael.larouche@kdemail.net>
+ Copyright (c) 2005 by Gregg Edghill <gregg.edghill@gmail.com>
+
+ Kopete (c) 2002-2005 by the Kopete developers <kopete-devel@kde.org>
+
+ Portions 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 "msnnotifysocket.h"
+#include "msncontact.h"
+#include "msnaccount.h"
+#include "msnsecureloginhandler.h"
+#include "msnchallengehandler.h"
+
+#include <qdatetime.h>
+#include <qregexp.h>
+#include <qdom.h>
+
+#include <kdebug.h>
+#include <kdeversion.h>
+#include <klocale.h>
+#include <kmdcodec.h>
+#include <kmessagebox.h>
+#include <kstandarddirs.h>
+#include <ktempfile.h>
+#include <krun.h>
+#include <kio/job.h>
+#include <qfile.h>
+#include <kconfig.h>
+#include <knotification.h>
+
+#include "kopeteuiglobal.h"
+#include "kopeteglobal.h"
+
+#include <ctime>
+
+
+MSNNotifySocket::MSNNotifySocket( MSNAccount *account, const QString& /*msnId*/, const QString &password )
+: MSNSocket( account )
+{
+ m_newstatus = MSNProtocol::protocol()->NLN;
+ m_secureLoginHandler=0L;
+ m_challengeHandler = 0L;
+
+ m_isHotmailAccount=false;
+ m_ping=false;
+ m_disconnectReason=Kopete::Account::Unknown;
+
+ m_account = account;
+ m_password=password;
+ QObject::connect( this, SIGNAL( blockRead( const QByteArray & ) ),
+ this, SLOT( slotReadMessage( const QByteArray & ) ) );
+ m_keepaliveTimer = 0L;
+ m_isLogged = false;
+}
+
+MSNNotifySocket::~MSNNotifySocket()
+{
+ delete m_secureLoginHandler;
+ delete m_challengeHandler;
+
+ kdDebug(14140) << k_funcinfo << endl;
+}
+
+void MSNNotifySocket::doneConnect()
+{
+// kdDebug( 14140 ) << k_funcinfo << "Negotiating server protocol version" << endl;
+ sendCommand( "VER", "MSNP11 MSNP10 CVR0" );
+}
+
+
+void MSNNotifySocket::disconnect()
+{
+ m_isLogged = false;
+ if( m_disconnectReason==Kopete::Account::Unknown )
+ m_disconnectReason=Kopete::Account::Manual;
+ if( onlineStatus() == Connected )
+ sendCommand( "OUT", QString::null, false );
+
+ if( m_keepaliveTimer )
+ m_keepaliveTimer->stop();
+
+ // the socket is not connected yet, so I should force the signals
+ if ( onlineStatus() == Disconnected || onlineStatus() == Connecting )
+ emit socketClosed();
+ else
+ MSNSocket::disconnect();
+}
+
+void MSNNotifySocket::handleError( uint code, uint id )
+{
+ kdDebug(14140) << k_funcinfo << endl;
+
+ QString handle;
+ if(m_tmpHandles.contains(id))
+ handle=m_tmpHandles[id];
+
+ QString msg;
+ MSNSocket::ErrorType type;
+ // See http://www.hypothetic.org/docs/msn/basics.php for a
+ // description of all possible error codes.
+ // TODO: Add support for all of these!
+ switch( code )
+ {
+ case 201:
+ case 205:
+ case 208:
+ {
+ msg = i18n( "<qt>The MSN user '%1' does not exist.<br>Please check the MSN ID.</qt>" ).arg( handle );
+ type = MSNSocket::ErrorServerError;
+ break;
+ }
+ case 207:
+ case 218:
+ case 540:
+ {
+ msg = i18n( "<qt>An internal error occurred in the MSN plugin.<br>"
+ "MSN Error: %1<br>"
+ "please send us a detailed bug report "
+ "at kopete-devel@kde.org containing the raw debug output on the "
+ "console (in gzipped format, as it is probably a lot of output.)" ).arg(code);
+ type = MSNSocket::ErrorServerError;
+ break;
+ }
+ case 209:
+ {
+ if(handle==m_account->accountId())
+ {
+ msg = i18n( "Unable to change your display name.\n"
+ "Please ensure your display is not too long and does not contains censored words." );
+ type = MSNSocket::ErrorServerError;
+ }
+ /*else
+ {
+ QString msg = i18n( "You are trying to change the display name of a user who has not "
+ "confirmed his or her email address;\n"
+ "the contact was not renamed on the server." );
+ KMessageBox::queuedMessageBox( Kopete::UI::Global::mainWidget(), KMessageBox::Error, msg, i18n( "MSN Plugin" ) );
+ }*/
+ break;
+ }
+ case 210:
+ {
+ msg = i18n("Your contact list is full; you cannot add any new contacts.");
+ type = MSNSocket::ErrorServerError;
+ break;
+ }
+ case 215:
+ {
+ msg = i18n( "<qt>The user '%1' already exists in this group on the MSN server;<br>"
+ "if Kopete does not show the user, please send us a detailed bug report "
+ "at kopete-devel@kde.org containing the raw debug output on the "
+ "console (in gzipped format, as it is probably a lot of output.)</qt>" ).arg(handle);
+ type = MSNSocket::ErrorInformation;
+ break;
+ }
+ case 216:
+ {
+ //This might happen is you rename an user if he is not in the contactlist
+ //currently, we just iniore;
+ //TODO: try to don't rename user not in the list
+ //actualy, the bug is in MSNChatSession::slotUserJoined()
+ break;
+ }
+ case 219:
+ {
+ msg = i18n( "The user '%1' seems to already be blocked or allowed on the server." ).arg(handle);
+ type = MSNSocket::ErrorServerError;
+ break;
+ }
+ case 223:
+ {
+ msg = i18n( "You have reached the maximum number of groups:\n"
+ "MSN does not support more than 30 groups." );
+ type = MSNSocket::ErrorServerError;
+ break;
+ }
+ case 224:
+ case 225:
+ case 230:
+ {
+ msg = i18n("Kopete is trying to perform an operation on a group or a contact that does not exists on the server.\n"
+ "This might happen if the Kopete contact list and the MSN-server contact list are not correctly synchronized; if this is the case, you probably should send a bug report.");
+ type = MSNSocket::ErrorServerError;
+ break;
+ }
+
+ case 229:
+ {
+ msg = i18n("The group name is too long; it has not been changed on the MSN server.");
+ type = MSNSocket::ErrorServerError;
+ break;
+ }
+ case 710:
+ {
+ msg = i18n( "You cannot open a Hotmail inbox because you do not have an MSN account with a valid "
+ "Hotmail or MSN mailbox." );
+ type = MSNSocket::ErrorServerError;
+ break;
+ }
+ case 715:
+ {
+ /*
+ //if(handlev==m_account->accountId())
+ QString msg = i18n( "Your email address has not been verified with the MSN server.\n"
+ "You should have received a mail with a link to confirm your email address.\n"
+ "Some functions will be restricted if you do not confirm your email address." );
+ KMessageBox::queuedMessageBox( Kopete::UI::Global::mainWidget(), KMessageBox::Sorry, msg, i18n( "MSN Plugin" ) );//TODO don't show again
+ */
+ break;
+ }
+ case 800:
+ {
+ //This happen when too much commends are sent to the server.
+ //the command will not be executed, too bad.
+ // ignore it for now, as we don't really know what command it was.
+ /* QString msg = i18#n( "You are trying to change your status, or your display name too rapidly.\n"
+ "This might happen if you added yourself to your own contact list." );
+ KMessageBox::queuedMessageBox( Kopete::UI::Global::mainWidget(), KMessageBox::Sorry, msg, i18n( "MSN Plugin" ) );
+ //FIXME: try to fix this problem*/
+ break;
+ }
+ case 911:
+ m_disconnectReason=Kopete::Account::BadPassword;
+ disconnect();
+ break;
+ case 913:
+ {
+ msg = i18n( "You can not send messages when you are offline or when you are invisible." );
+ type = MSNSocket::ErrorServerError;
+ break;
+ }
+ case 923:
+ {
+ msg = i18n( "You are trying to perform an action you are not allowed to perform in 'kid mode'." );
+ type = MSNSocket::ErrorServerError;
+ break;
+ }
+
+ default:
+ MSNSocket::handleError( code, id );
+ break;
+ }
+
+ if( !msg.isEmpty() )
+ emit errorMessage( type, msg );
+}
+
+void MSNNotifySocket::parseCommand( const QString &cmd, uint id, const QString &data )
+{
+ //kdDebug(14140) << "MSNNotifySocket::parseCommand: Command: " << cmd << endl;
+
+ if ( cmd == "VER" )
+ {
+ sendCommand( "CVR", "0x0409 winnt 5.1 i386 MSNMSGR 7.0.0816 MSMSGS " + m_account->accountId() );
+/*
+ struct utsname utsBuf;
+ uname ( &utsBuf );
+
+ sendCommand( "CVR", i18n( "MS Local code, see http://www.microsoft.com/globaldev/reference/oslocversion.mspx", "0x0409" ) +
+ " " + escape( utsBuf.sysname ) + " " + escape( utsBuf.release ) + " " + escape( utsBuf.machine ) + " Kopete " +
+ escape( kapp->aboutData()->version() ) + " Kopete " + m_msnId );
+*/
+ }
+ else if ( cmd == "CVR" ) //else if ( cmd == "INF" )
+ {
+ sendCommand( "USR", "TWN I " + m_account->accountId() );
+ }
+ else if( cmd == "USR" ) //// here follow the auth processus
+ {
+ if( data.section( ' ', 1, 1 ) == "S" )
+ {
+ m_secureLoginHandler = new MSNSecureLoginHandler(m_account->accountId(), m_password, data.section( ' ' , 2 , 2 ));
+
+ QObject::connect(m_secureLoginHandler, SIGNAL(loginFailed()), this, SLOT(sslLoginFailed()));
+ QObject::connect(m_secureLoginHandler, SIGNAL(loginBadPassword()), this, SLOT(sslLoginIncorrect()));
+ QObject::connect(m_secureLoginHandler, SIGNAL(loginSuccesful(QString )), this, SLOT(sslLoginSucceeded(QString )));
+
+ m_secureLoginHandler->login();
+ }
+ else
+ {
+ // Successful authentication.
+ m_disconnectReason=Kopete::Account::Unknown;
+
+ // Synchronize with the server.
+ QString lastSyncTime, lastChange;
+
+ if(m_account->contacts().count() > 1)
+ {
+ // Retrieve the last synchronization timestamp, and last change timestamp.
+ lastSyncTime = m_account->configGroup()->readEntry("lastsynctime", "0");
+ lastChange = m_account->configGroup()->readEntry("lastchange", "0");
+ }
+ else
+ {
+ //the contactliust has maybe being removed, force to sync
+ //(the only contact is myself)
+ lastSyncTime="0";
+ lastChange="0";
+ }
+
+ sendCommand( "SYN", lastChange + " " + lastSyncTime);
+ // Get client features.
+ if(!useHttpMethod()) {
+ sendCommand( "GCF", "Shields.xml");
+ // We are connected start to ping
+ slotSendKeepAlive();
+ }
+ }
+ }
+ else if( cmd == "LST" )
+ {
+ // MSNP11 changed command. Now it's:
+ // LST N=passport@hotmail.com F=Display%20Name C=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 13 xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
+ // But can be
+ // LST N=passport@hotmail.com 10
+ QString publicName, contactGuid, groups;
+ uint lists;
+
+ QRegExp regex("N=([^ ]+)(?: F=([^ ]+))?(?: C=([0-9a-fA-F]{8}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{12}))? (\\d+)\\s?((?:[0-9a-fA-F]{8}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{12},?)*)$");
+ regex.search(data);
+
+ // Capture passport email.
+ m_tmpLastHandle = regex.cap(1);
+ // Capture public name.
+ publicName = unescape( regex.cap(2) );
+ // Capture contact guid.
+ contactGuid = regex.cap(3);
+ // Capture list enum type.
+ lists = regex.cap(4).toUInt();
+ // Capture contact group(s) guid(s)
+ groups = regex.cap(5);
+
+// kdDebug(14140) << k_funcinfo << " msnId: " << m_tmpLastHandle << " publicName: " << publicName << " contactGuid: " << contactGuid << " list: " << lists << " groupGuid: " << groups << endl;
+
+ // handle, publicName, Contact GUID, lists, Group GUID
+ emit contactList( m_tmpLastHandle , publicName, contactGuid, lists, groups );
+ }
+ else if( cmd == "GCF" )
+ {
+ m_configFile = data.section(' ', 0, 0);
+ readBlock( data.section( ' ', 1, 1 ).toUInt() );
+ }
+ else if( cmd == "MSG" )
+ {
+ readBlock( data.section( ' ', 2, 2 ).toUInt() );
+ }
+ else if( cmd == "ILN" || cmd == "NLN" )
+ {
+ // status handle publicName strangeNumber MSNOBJECT
+ MSNContact *c = static_cast<MSNContact*>( m_account->contacts()[ data.section( ' ', 1, 1 ) ] );
+ if( c && c->contactId() != m_account->accountId() )
+ {
+ QString publicName=unescape( data.section( ' ', 2, 2 ) );
+ if ( (publicName!=c->contactId() || c->hasProperty(Kopete::Global::Properties::self()->nickName().key()) ) &&
+ publicName!=c->property( Kopete::Global::Properties::self()->nickName()).value().toString() )
+
+ changePublicName(publicName,c->contactId());
+ QString obj=unescape(data.section( ' ', 4, 4 ));
+ c->setObject( obj );
+ c->setOnlineStatus( convertOnlineStatus( data.section( ' ', 0, 0 ) ) );
+ c->setClientFlags(data.section( ' ', 3, 3 ).toUInt());
+ }
+ }
+ else if( cmd == "UBX" )
+ {
+ m_tmpLastHandle = data.section(' ', 0, 0);
+ uint length = data.section( ' ', 1, 1 ).toUInt();
+ if(length > 0) {
+ readBlock( length );
+ }
+ }
+ else if( cmd == "UUX" )
+ {
+ // UUX is sended to acknowledge that the server has received and processed the personal Message.
+ // if the result is 0, set the myself() contact personalMessage.
+ if( data.section(' ', 0, 0) == QString::fromUtf8("0") )
+ m_account->myself()->setProperty(MSNProtocol::protocol()->propPersonalMessage, m_propertyPersonalMessage);
+ }
+ else if( cmd == "FLN" )
+ {
+ MSNContact *c = static_cast<MSNContact*>( m_account->contacts()[ data.section( ' ', 0, 0 ) ] );
+ if( c && c->contactId() != m_account->accountId() )
+ {
+ c->setOnlineStatus( MSNProtocol::protocol()->FLN );
+ c->removeProperty( MSNProtocol::protocol()->propClient );
+ }
+ }
+ else if( cmd == "XFR" )
+ {
+ QString stype=data.section( ' ', 0, 0 );
+ if( stype=="SB" ) //switchboard connection (chat)
+ {
+ // Address, AuthInfo
+ emit startChat( data.section( ' ', 1, 1 ), data.section( ' ', 3, 3 ) );
+ }
+ else if( stype=="NS" ) //notifysocket ; Got our notification server
+ { //we are connecting and we receive the initial NS, or the msn server encounter a problem, and we are switching to another switchboard
+ QString host = data.section( ' ', 1, 1 );
+ QString server = host.section( ':', 0, 0 );
+ uint port = host.section( ':', 1, 1 ).toUInt();
+ setOnlineStatus( Connected );
+ emit receivedNotificationServer( server, port );
+ disconnect();
+ }
+
+ }
+ else if( cmd == "RNG" )
+ {
+ // SessionID, Address, AuthInfo, handle, publicName
+ emit invitedToChat( QString::number( id ), data.section( ' ', 0, 0 ), data.section( ' ', 2, 2 ),
+ data.section( ' ', 3, 3 ), unescape( data.section( ' ', 4, 4 ) ) );
+ }
+ else if( cmd == "ADC" )
+ {
+ QString msnId, list, publicName, contactGuid, groupGuid;
+
+ // Retrieve the list parameter (FL/AL/BL/RL)
+ list = data.section( ' ', 0, 0 );
+
+ // Examples of received data
+ // ADC TrID xL N=example@passport.com
+ // ADC TrID FL C=contactGuid groupdGuid
+ // ADC TrID RL N=example@passport.com F=friednly%20name
+ // ADC TrID FL N=ex@pas.com F=My%20Name C=contactGuid
+ // Thanks Gregg for that complex RegExp.
+ QRegExp regex("(?:N=([^ ]+))?(?: F=([^ ]+))?(?: C=([0-9a-fA-F]{8}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{12}))?\\s?((?:[0-9a-fA-F]{8}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{12},?)*)$");
+ regex.search( data.section( ' ', 1 ) );
+
+ // Capture passport email.
+ msnId = regex.cap(1);
+ // Capture public name.
+ publicName = unescape( regex.cap(2) );
+ // Capture contact guid.
+ contactGuid = regex.cap(3);
+ // Capture contact group(s) guid(s)
+ groupGuid = regex.cap(4);
+
+// kdDebug(14140) << k_funcinfo << list << " msnId: " << msnId << " publicName: " << publicName << " contactGuid: " << contactGuid << " groupGuid: " << groupGuid << endl;
+
+ // handle, list, publicName, contactGuid, groupGuid
+ emit contactAdded( msnId, list, publicName, contactGuid, groupGuid );
+ }
+ else if( cmd == "REM" ) // someone is removed from a list
+ {
+ QString handle, list, contactGuid, groupGuid;
+ list = data.section( ' ', 0, 0 );
+ if( list == "FL" )
+ {
+ // Removing a contact
+ if( data.contains( ' ' ) < 2 )
+ {
+ contactGuid = data.section( ' ', 1, 1 );
+ }
+ // Removing a contact from a group
+ else if( data.contains( ' ' ) < 3 )
+ {
+ contactGuid = data.section( ' ', 1, 1 );
+ groupGuid = data.section( ' ', 2, 2 );
+ }
+ }
+ else
+ {
+ handle = data.section( ' ', 1, 1);
+ }
+
+ // handle, list, contactGuid, groupGuid
+ emit contactRemoved( handle, list, contactGuid, groupGuid );
+
+ }
+ else if( cmd == "OUT" )
+ {
+ if( data.section( ' ', 0, 0 ) == "OTH" )
+ {
+ m_disconnectReason=Kopete::Account::OtherClient;
+ }
+ disconnect();
+ }
+ else if( cmd == "CHG" )
+ {
+ QString status = data.section( ' ', 0, 0 );
+ setOnlineStatus( Connected );
+ emit statusChanged( convertOnlineStatus( status ) );
+ }
+ else if( cmd == "SBP" )
+ {
+ QString contactGuid, type, publicName;
+ contactGuid = data.section( ' ', 0, 0 );
+ type = data.section( ' ', 1, 1 );
+ if(type == "MFN" )
+ {
+ publicName = unescape( data.section( ' ', 2, 2 ) );
+ MSNContact *c = m_account->findContactByGuid( contactGuid );
+ if(c != 0L)
+ {
+ c->setProperty( Kopete::Global::Properties::self()->nickName(), publicName );
+ }
+ }
+ }
+ else if( cmd == "LSG" )
+ {
+ // New Format: LSG Friends xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
+ // groupDisplayName, groupGuid
+ emit groupListed( unescape( data.section( ' ', 0, 0 ) ), data.section( ' ', 1, 1) );
+ }
+ else if( cmd == "ADG" )
+ {
+ // groupName, groupGuid
+ emit groupAdded( unescape( data.section( ' ', 0, 0 ) ),
+ data.section( ' ', 1, 1 ) );
+ }
+ else if( cmd == "REG" )
+ {
+ // groupGuid, groupName
+ emit groupRenamed( data.section( ' ', 0, 0 ), unescape( data.section( ' ', 1, 1 ) ) );
+ }
+ else if( cmd == "RMG" )
+ {
+ // groupGuid
+ emit groupRemoved( data.section( ' ', 1, 1 ) );
+ }
+ else if( cmd == "CHL" )
+ {
+ m_challengeHandler = new MSNChallengeHandler("CFHUR$52U_{VIX5T", "PROD0101{0RM?UBW");
+ // Compute the challenge response hash, and send the response.
+ QString chlResponse = m_challengeHandler->computeHash(data.section(' ', 0, 0));
+ sendCommand("QRY", m_challengeHandler->productId(), true, chlResponse.utf8());
+ // Dispose of the challenge handler.
+ m_challengeHandler->deleteLater();
+ m_challengeHandler = 0L;
+ }
+ else if( cmd == "SYN" )
+ {
+ // Retrieve the last synchronization timestamp known to the server.
+ QString lastSyncTime = data.section( ' ', 1, 1 );
+ QString lastChange = data.section( ' ', 0, 0 );
+ if( lastSyncTime != m_account->configGroup()->readEntry("lastsynctime") ||
+ lastChange != m_account->configGroup()->readEntry("lastchange") )
+ {
+ // If the server timestamp and the local timestamp are different,
+ // prepare to receive the contact list.
+ emit newContactList(); // remove all contacts datas, msn sends a new contact list
+ m_account->configGroup()->writeEntry( "lastsynctime" , lastSyncTime);
+ m_account->configGroup()->writeEntry( "lastchange", lastChange);
+ }else
+ kdDebug(14140) << k_funcinfo << "Contact list up-to-date." << endl;
+
+ // set the status
+ setStatus( m_newstatus );
+ }
+ else if( cmd == "BPR" )
+ {
+ MSNContact *c = static_cast<MSNContact*>( m_account->contacts()[ m_tmpLastHandle ] );
+ if( c )
+ c->setInfo(data.section( ' ', 0, 0 ),unescape(data.section( ' ', 1, 1 )));
+ }
+ else if( cmd == "PRP" )
+ {
+ MSNContact *c = static_cast<MSNContact*>( m_account->myself() );
+ if( c )
+ {
+ QString type = data.section( ' ', 0, 0 );
+ QString prpData = unescape( data.section( ' ', 1, 1 ) ); //SECURITY????????
+ c->setInfo( type, prpData );
+ m_account->configGroup()->writeEntry( type, prpData );
+ }
+ }
+ else if( cmd == "BLP" )
+ {
+ if( id > 0 ) //FROM BLP
+ {
+ m_account->configGroup()->writeEntry( "serial" , data.section( ' ', 0, 0 ) );
+ m_account->configGroup()->writeEntry( "BLP" , data.section( ' ', 1, 1 ) );
+ }
+ else //FROM SYN
+ m_account->configGroup()->writeEntry( "BLP" , data.section( ' ', 0, 0 ) );
+ }
+ else if( cmd == "QRY" )
+ {
+ // Do nothing
+ }
+ else if( cmd == "QNG" )
+ {
+ //this is a reply from a ping
+ m_ping=false;
+
+ // id is the timeout in fact, and we remove 5% of it
+ if( m_keepaliveTimer )
+ m_keepaliveTimer->start( id * 950, true );
+ kdDebug( 14140 ) << k_funcinfo << "timerTimeout=" << id << "sec"<< endl;
+ }
+ else if( cmd == "URL" )
+ {
+ // URL 6 /cgi-bin/HoTMaiL https://loginnet.passport.com/ppsecure/md5auth.srf?lc=1033 2
+ //example of reply: URL 10 /cgi-bin/HoTMaiL https://msnialogin.passport.com/ppsecure/md5auth.srf?lc=1036 3
+ QString from_action_url = data.section( ' ', 1, 1 );
+ QString rru = data.section( ' ', 0, 0 );
+ QString id = data.section( ' ', 2, 2 );
+
+ //write the tmp file
+ QString UserID=m_account->accountId();
+
+ time_t actualTime;
+ time(&actualTime);
+ QString sl = QString::number( ( unsigned long ) actualTime - m_loginTime.toULong() );
+
+ QString md5this( m_MSPAuth + sl + m_password );
+ KMD5 md5( md5this.utf8() );
+
+ QString hotmailRequest = "<html>\n"
+ "<head>\n"
+ "<noscript>\n"
+ "<meta http-equiv=Refresh content=\"0; url=http://www.hotmail.com\">\n"
+ "</noscript>\n"
+ "</head>\n"
+ "<body onload=\"document.pform.submit(); \">\n"
+ "<form name=\"pform\" action=\"" + from_action_url + "\" method=\"POST\">\n"
+ "<input type=\"hidden\" name=\"mode\" value=\"ttl\">\n"
+ "<input type=\"hidden\" name=\"login\" value=\"" + UserID.left( UserID.find('@') ) + "\">\n"
+ "<input type=\"hidden\" name=\"username\" value=\"" + UserID + "\">\n"
+ "<input type=\"hidden\" name=\"sid\" value=\"" + m_sid + "\">\n"
+ "<input type=\"hidden\" name=\"kv\" value=\"" + m_kv + "\">\n"
+ "<input type=\"hidden\" name=\"id\" value=\""+ id +"\">\n"
+ "<input type=\"hidden\" name=\"sl\" value=\"" + sl +"\">\n"
+ "<input type=\"hidden\" name=\"rru\" value=\"" + rru + "\">\n"
+ "<input type=\"hidden\" name=\"auth\" value=\"" + m_MSPAuth + "\">\n"
+ "<input type=\"hidden\" name=\"creds\" value=\"" + QString::fromLatin1( md5.hexDigest() ) + "\">\n"
+ "<input type=\"hidden\" name=\"svc\" value=\"mail\">\n"
+ "<input type=\"hidden\" name=\"js\" value=\"yes\">\n"
+ "</form></body>\n</html>\n";
+
+ KTempFile tmpMailFile( locateLocal( "tmp", "kopetehotmail-" ), ".html" );
+ *tmpMailFile.textStream() << hotmailRequest;
+ tmpMailFile.file()->flush();
+
+ KRun::runURL( KURL::fromPathOrURL( tmpMailFile.name() ), "text/html" , true );
+
+ }
+ else if ( cmd == "NOT" )
+ {
+ kdDebug( 14140 ) << k_funcinfo << "Received NOT command, issueing read block for '" << id << " more bytes" << endl;
+ readBlock( id );
+ }
+ else
+ {
+ // Let the base class handle the rest
+ //MSNSocket::parseCommand( cmd, id, data );
+ kdDebug( 14140 ) << k_funcinfo << "Unimplemented command '" << cmd << " " << id << " " << data << "' from server!" << endl;
+ }
+}
+
+
+void MSNNotifySocket::sslLoginFailed()
+{
+ m_disconnectReason=Kopete::Account::InvalidHost;
+ disconnect();
+}
+
+void MSNNotifySocket::sslLoginIncorrect()
+{
+ m_disconnectReason=Kopete::Account::BadPassword;
+ disconnect();
+}
+
+void MSNNotifySocket::sslLoginSucceeded(QString ticket)
+{
+ sendCommand("USR" , "TWN S " + ticket);
+
+ m_secureLoginHandler->deleteLater();
+ m_secureLoginHandler = 0L;
+}
+
+void MSNNotifySocket::slotMSNAlertUnwanted()
+{
+ // user not interested .. clean up the list of actions
+ m_msnAlertURLs.clear();
+}
+
+void MSNNotifySocket::slotMSNAlertLink(unsigned int action)
+{
+ // index into our action list and pull out the URL that was clicked ..
+ KURL tempURLForLaunch(m_msnAlertURLs[action-1]);
+
+ KRun* urlToRun = new KRun(tempURLForLaunch);
+}
+
+void MSNNotifySocket::slotOpenInbox()
+{
+ sendCommand("URL", "INBOX" );
+}
+
+void MSNNotifySocket::sendMail(const QString &email)
+{
+ sendCommand("URL", QString("COMPOSE " + email).utf8() );
+}
+
+bool MSNNotifySocket::setUseHttpMethod(bool useHttp)
+{
+ bool ret = MSNSocket::setUseHttpMethod( useHttp );
+
+ if( useHttpMethod() ) {
+ if( m_keepaliveTimer ) {
+ delete m_keepaliveTimer;
+ m_keepaliveTimer = 0L;
+ }
+ }
+ else {
+ if( !m_keepaliveTimer ) {
+ m_keepaliveTimer = new QTimer( this, "m_keepaliveTimer" );
+ QObject::connect( m_keepaliveTimer, SIGNAL( timeout() ), SLOT( slotSendKeepAlive() ) );
+ }
+ }
+
+ return ret;
+}
+
+void MSNNotifySocket::slotReadMessage( const QByteArray &bytes )
+{
+ QString msg = QString::fromUtf8(bytes, bytes.size());
+
+ if(msg.contains("text/x-msmsgsinitialmdatanotification"))
+ {
+ //Mail-Data: <MD><E><I>301</I><IU>1</IU><O>4</O><OU>2</OU></E><Q><QTM>409600</QTM><QNM>204800</QNM></Q></MD>
+ // MD - Mail Data
+ // E - email
+ // I - initial mail
+ // IU - initial unread
+ // O - other mail
+ // OU - other unread.
+ QRegExp regex("<MD><E><I>(\\d+)?</I>(?:<IU>(\\d+)?</IU>)<O>(\\d+)?</O><OU>(\\d+)?</OU></E><Q>.*</Q></MD>");
+ regex.search(msg);
+
+ bool unread;
+ // Retrieve the number of unread email messages.
+ mailCount = regex.cap(2).toUInt(&unread);
+ if(unread && mailCount > 0)
+ {
+ // If there are new email message available, raise the unread email event.
+ QObject::connect(KNotification::event( "msn_mail", i18n( "You have one unread message in your MSN inbox.",
+ "You have %n unread messages in your MSN inbox.", mailCount ), 0 , 0 , i18n( "Open Inbox..." ) ),
+ SIGNAL(activated(unsigned int ) ) , this, SLOT( slotOpenInbox() ) );
+ }
+ }
+ else if(msg.contains("text/x-msmsgsactivemailnotification"))
+ {
+ //this sends the server if mails are deleted
+ QString m = msg.right(msg.length() - msg.find("Message-Delta:") );
+ m = m.left(msg.find("\r\n"));
+ mailCount = mailCount - m.right(m.length() -m.find(" ")-1).toUInt();
+ }
+ else if(msg.contains("text/x-msmsgsemailnotification"))
+ {
+ //this sends the server if a new mail has arrived
+ QRegExp rx("From-Addr: ([A-Za-z0-9@._\\-]*)");
+ rx.search(msg);
+ QString m=rx.cap(1);
+
+ mailCount++;
+
+ //TODO: it is also possible to get the subject (but warning about the encoding)
+ QObject::connect(KNotification::event( "msn_mail",i18n( "You have one new email from %1 in your MSN inbox." ).arg(m),
+ 0 , 0 , i18n( "Open Inbox..." ) ),
+ SIGNAL(activated(unsigned int ) ) , this, SLOT( slotOpenInbox() ) );
+ }
+ else if(msg.contains("text/x-msmsgsprofile"))
+ {
+ //Hotmail profile
+ if(msg.contains("MSPAuth:"))
+ {
+ QRegExp rx("MSPAuth: ([A-Za-z0-9$!*]*)");
+ rx.search(msg);
+ m_MSPAuth=rx.cap(1);
+ }
+ if(msg.contains("sid:"))
+ {
+ QRegExp rx("sid: ([0-9]*)");
+ rx.search(msg);
+ m_sid=rx.cap(1);
+ }
+ if(msg.contains("kv:"))
+ {
+ QRegExp rx("kv: ([0-9]*)");
+ rx.search(msg);
+ m_kv=rx.cap(1);
+ }
+ if(msg.contains("LoginTime:"))
+ {
+ QRegExp rx("LoginTime: ([0-9]*)");
+ rx.search(msg);
+ m_loginTime=rx.cap(1);
+ }
+ else //IN MSNP9 there are no logintime it seems, so set it manualy
+ {
+ time_t actualTime;
+ time(&actualTime);
+ m_loginTime=QString::number((unsigned long)actualTime);
+ }
+ if(msg.contains("EmailEnabled:"))
+ {
+ QRegExp rx("EmailEnabled: ([0-9]*)");
+ rx.search(msg);
+ m_isHotmailAccount = (rx.cap(1).toUInt() == 1);
+ emit hotmailSeted(m_isHotmailAccount);
+ }
+ if(msg.contains("ClientIP:"))
+ {
+ QRegExp rx("ClientIP: ([0-9.]*)");
+ rx.search(msg);
+ m_localIP = rx.cap(1);
+ }
+
+ // We are logged when we receive the initial profile from Hotmail.
+ m_isLogged = true;
+ }
+ else if (msg.contains("NOTIFICATION"))
+ {
+ // MSN alert (i.e. NOTIFICATION) [for docs see http://www.hypothetic.org/docs/msn/client/notification.php]
+ // format of msg is as follows:
+ //
+ // <NOTIFICATION ver="2" id="1342902633" siteid="199999999" siteurl="http://alerts.msn.com">
+ // <TO pid="0x0006BFFD:0x8582C0FB" name="example@passport.com"/>
+ // <MSG pri="1" id="1342902633">
+ // <SUBSCR url="http://g.msn.com/3ALMSNTRACKING/199999999ToastChange?http://alerts.msn.com/Alerts/MyAlerts.aspx?strela=1"/>
+ // <ACTION url="http://g.msn.com/3ALMSNTRACKING/199999999ToastAction?http://alerts.msn.com/Alerts/MyAlerts.aspx?strela=1"/>
+ // <BODY lang="3076" icon="">
+ // <TEXT>utf8-encoded text</TEXT>
+ // </BODY>
+ // </MSG>
+ // </NOTIFICATION>
+
+ // MSN sends out badly formed XML .. fix it for them (thanks MS!)
+ QString notificationDOMAsString(msg);
+
+ QRegExp rx( "&(?!amp;)" ); // match ampersands but not &amp;
+ notificationDOMAsString.replace(rx, "&amp;");
+ QDomDocument alertDOM;
+ alertDOM.setContent(notificationDOMAsString);
+
+ QDomNodeList msgElements = alertDOM.elementsByTagName("MSG");
+ for (uint i = 0 ; i < msgElements.count() ; i++)
+ {
+ QString subscString;
+ QString actionString;
+ QString textString;
+
+ QDomNode msgDOM = msgElements.item(i);
+
+ QDomNodeList msgChildren = msgDOM.childNodes();
+ for (uint i = 0 ; i < msgChildren.length() ; i++) {
+ QDomNode child = msgChildren.item(i);
+ QDomElement element = child.toElement();
+ if (element.tagName() == "SUBSCR")
+ {
+ QDomAttr subscElementURLAttribute;
+ if (element.hasAttribute("url"))
+ {
+ subscElementURLAttribute = element.attributeNode("url");
+ subscString = subscElementURLAttribute.value();
+ }
+ }
+ else if (element.tagName() == "ACTION")
+ {
+ // process ACTION node to pull out URL the alert is tied to
+ QDomAttr actionElementURLAttribute;
+ if (element.hasAttribute("url"))
+ {
+ actionElementURLAttribute = element.attributeNode("url");
+ actionString = actionElementURLAttribute.value();
+ }
+ }
+ else if (element.tagName() == "BODY")
+ {
+ // process BODY node to get the text of the alert
+ QDomNodeList textElements = element.elementsByTagName("TEXT");
+ if (textElements.count() >= 1)
+ {
+ QDomElement textElement = textElements.item(0).toElement();
+ textString = textElement.text();
+ }
+ }
+
+
+ }
+
+// kdDebug( 14140 ) << "subscString " << subscString << " actionString " << actionString << " textString " << textString << endl;
+ // build an internal list of actions ... we'll need to index into this list when we receive an event
+ QStringList actions;
+ actions.append(i18n("More Information"));
+ m_msnAlertURLs.append(actionString);
+
+ actions.append(i18n("Manage Subscription"));
+ m_msnAlertURLs.append(subscString);
+
+ // Don't do any MSN alerts notification for new blog updates
+ if( subscString != QString::fromLatin1("s.htm") && actionString != QString::fromLatin1("a.htm") )
+ {
+ KNotification* notification = KNotification::event("msn_alert", textString, 0L, 0L, actions);
+ QObject::connect(notification, SIGNAL(activated(unsigned int)), this, SLOT(slotMSNAlertLink(unsigned int)));
+ QObject::connect(notification, SIGNAL(closed()), this, SLOT(slotMSNAlertUnwanted()));
+ }
+ } // end for each MSG tag
+ }
+
+ if(!m_configFile.isNull())
+ {
+ // TODO Get client features.
+ }
+
+ if(!m_tmpLastHandle.isNull())
+ {
+ QString personalMessage, currentMedia;
+ QDomDocument psm;
+ if( psm.setContent(msg) )
+ {
+ // Get the first child of the xml "document";
+ QDomElement psmElement = psm.documentElement().firstChild().toElement();
+
+ while( !psmElement.isNull() )
+ {
+ if(psmElement.tagName() == QString::fromUtf8("PSM"))
+ {
+ personalMessage = psmElement.text();
+ kdDebug(14140) << k_funcinfo << "Personnal Message received: " << personalMessage << endl;
+ }
+ else if(psmElement.tagName() == QString::fromUtf8("CurrentMedia"))
+ {
+ if( !psmElement.text().isEmpty() )
+ {
+ kdDebug(14140) << k_funcinfo << "XML CurrentMedia: " << psmElement.text() << endl;
+ currentMedia = processCurrentMedia( psmElement.text() );
+ }
+ }
+ psmElement = psmElement.nextSibling().toElement();
+ }
+
+ MSNContact *contact = static_cast<MSNContact*>(m_account->contacts()[ m_tmpLastHandle ]);
+ if(contact)
+ {
+ contact->setProperty(MSNProtocol::protocol()->propPersonalMessage, currentMedia.isEmpty() ? personalMessage : currentMedia);
+ }
+ }
+ m_tmpLastHandle = QString::null;
+ }
+}
+
+QString MSNNotifySocket::processCurrentMedia( const QString &mediaXmlElement )
+{
+ /*
+ The value of the CurrentMedia tag you can think of like an array
+ seperated by "\0" characters (literal backslash followed by zero, not NULL).
+
+ The elements of this "array" are as follows:
+
+ * Application - This is the app you are using. Usually empty
+ * Type - This is the type of PSM, either “Music”, “Games” or “Office”
+ * Enabled - This is a boolean value (0/1) to enable/disable
+ * Format - A formatter string ala .Net; For example, “{0} - {1}”
+ * First line - The first line (Matches {0} in the Format)
+ * Second line - The second line (Matches {1} in the Format)
+ * Third line - The third line (Matches {2} in the Format)
+
+ There is probably no limit to the number of lines unless you go over the maximum length of the tag.
+
+ Example of currentMedia xml tag:
+ <CurrentMedia>\0Music\01\0{0} - {1}\0 Song Title\0Song Artist\0Song Album\0\0</CurrentMedia>
+ <CurrentMedia>\0Games\01\0Playing {0}\0Game Name\0</CurrentMedia>
+ <CurrentMedia>\0Office\01\0Office Message\0Office App Name\0</CurrentMedia>
+
+ From http://msnpiki.msnfanatic.com/index.php/MSNP11:Changes
+ */
+ QString application, type, format, currentMedia;
+ bool enabled=false, test;
+ // \0 is textual, it's the "array" separator.
+ QStringList argumentLists = QStringList::split(QString::fromUtf8("\\0"), mediaXmlElement, true);
+
+ // Retrive the "stable" array elements.
+ application = argumentLists[0];
+ type = argumentLists[1];
+ enabled = argumentLists[2].toInt(&test);
+ format = argumentLists[3];
+
+ // Get the formatter strings
+ QStringList formatterStrings;
+ QStringList::ConstIterator it;
+ for( it = argumentLists.at(4); it != argumentLists.end(); ++it )
+ {
+ formatterStrings.append( *it );
+ }
+
+ // Replace the formatter in the format string.
+ currentMedia = format;
+ for(uint i=0; i<formatterStrings.size(); i++)
+ {
+ currentMedia = currentMedia.replace(QString("{%1}").arg(i), formatterStrings[i]);
+ }
+
+ if( type == QString::fromUtf8("Music") )
+ {
+ // the "♫" is encoded in utf8 (and should be in utf8)
+ currentMedia = i18n("Now Listening: ♫ %1 ♫").arg(currentMedia);
+ }
+
+ kdDebug(1414) << "Current Media received: " << currentMedia << endl;
+
+ return currentMedia;
+}
+
+void MSNNotifySocket::addGroup(const QString& groupName)
+{
+ // escape spaces
+ sendCommand( "ADG", escape( groupName ) );
+}
+
+void MSNNotifySocket::renameGroup( const QString& groupName, const QString& groupGuid )
+{
+ // escape spaces
+ sendCommand( "REG", groupGuid + " " + escape( groupName ) );
+}
+
+void MSNNotifySocket::removeGroup( const QString& groupGuid )
+{
+ sendCommand( "RMG", groupGuid );
+}
+
+void MSNNotifySocket::addContact( const QString &handle, int list, const QString& publicName, const QString& contactGuid, const QString& groupGuid )
+{
+ QString args;
+ switch( list )
+ {
+ case MSNProtocol::FL:
+ {
+ // Adding the contact to a group
+ if( !contactGuid.isEmpty() )
+ {
+ args = QString("FL C=%1 %2").arg( contactGuid ).arg( groupGuid );
+ kdDebug(14140) << k_funcinfo << "In adding contact to a group" << endl;
+ }
+ // Adding a new contact
+ else
+ {
+ args = QString("FL N=%1 F=%2").arg( handle ).arg( escape( publicName ) );
+ kdDebug(14140) << k_funcinfo << "In adding contact to a new contact" << endl;
+ }
+ break;
+ }
+ case MSNProtocol::AL:
+ args = QString("AL N=%1").arg( handle );
+ break;
+ case MSNProtocol::BL:
+ args = QString("BL N=%1").arg( handle );
+ break;
+ case MSNProtocol::RL:
+ args = QString("RL N=%1").arg( handle );
+ break;
+ default:
+ kdDebug(14140) << k_funcinfo <<"WARNING! Unknown list " << list << "!" << endl;
+ return;
+ }
+ unsigned int id=sendCommand( "ADC", args );
+ m_tmpHandles[id]=handle;
+}
+
+void MSNNotifySocket::removeContact( const QString &handle, int list, const QString& contactGuid, const QString& groupGuid )
+{
+ QString args;
+ switch( list )
+ {
+ case MSNProtocol::FL:
+ args = "FL " + contactGuid;
+ // Removing a contact from a group
+ if( !groupGuid.isEmpty() )
+ args += " " + groupGuid;
+ break;
+ case MSNProtocol::AL:
+ args = "AL " + handle;
+ break;
+ case MSNProtocol::BL:
+ args = "BL " + handle;
+ break;
+ case MSNProtocol::PL:
+ args = "PL " + handle;
+ break;
+ default:
+ kdDebug(14140) <<k_funcinfo << "WARNING! Unknown list " << list << "!" << endl;
+ return;
+ }
+ unsigned int id=sendCommand( "REM", args );
+ m_tmpHandles[id]=handle;
+}
+
+void MSNNotifySocket::setStatus( const Kopete::OnlineStatus &status )
+{
+// kdDebug( 14140 ) << k_funcinfo << statusToString( status ) << endl;
+
+ if( onlineStatus() == Disconnected )
+ m_newstatus = status;
+ else
+ sendCommand( "CHG", statusToString( status ) + " " + m_account->myselfClientId() + " " + escape(m_account->pictureObject()) );
+}
+
+void MSNNotifySocket::changePublicName( const QString &publicName, const QString &handle )
+{
+ QString tempPublicName = publicName;
+
+ //The maximum length is 387. but with utf8 or encodage, each character may be triple
+ // 387/3 = 129 so we make sure the lenght is not logner than 129 char, even if
+ // it's possible to have longer nicks.
+ if( escape(publicName).length() > 129 )
+ {
+ tempPublicName = publicName.left(129);
+ }
+
+ if( handle.isNull() )
+ {
+ unsigned int id = sendCommand( "PRP", "MFN " + escape( tempPublicName ) );
+ m_tmpHandles[id] = m_account->accountId();
+ }
+ else
+ {
+ MSNContact *currentContact = static_cast<MSNContact *>(m_account->contacts()[handle]);
+ if(currentContact && !currentContact->guid().isEmpty() )
+ {
+ // FIXME if there is not guid server disconnects.
+ unsigned int id = sendCommand( "SBP", currentContact->guid() + " MFN " + escape( tempPublicName ) );
+ m_tmpHandles[id] = handle;
+ }
+ }
+}
+
+void MSNNotifySocket::changePersonalMessage( MSNProtocol::PersonalMessageType type, const QString &personalMessage )
+{
+ QString tempPersonalMessage;
+ QString xmlCurrentMedia;
+
+ // Only espace and cut the personalMessage is the type is normal.
+ if(type == MSNProtocol::PersonalMessageNormal)
+ {
+ tempPersonalMessage = personalMessage;
+ //Magic number : 129 characters
+ if( escape(personalMessage).length() > 129 )
+ {
+ // We cut. for now.
+ tempPersonalMessage = personalMessage.left(129);
+ }
+ }
+
+ QDomDocument xmlMessage;
+ xmlMessage.appendChild( xmlMessage.createElement( "Data" ) );
+
+ QDomElement psm = xmlMessage.createElement("PSM");
+ psm.appendChild( xmlMessage.createTextNode( tempPersonalMessage ) );
+ xmlMessage.documentElement().appendChild( psm );
+
+ QDomElement currentMedia = xmlMessage.createElement("CurrentMedia");
+
+ /* Example of currentMedia xml tag:
+ <CurrentMedia>\0Music\01\0{0} - {1}\0 Song Title\0Song Artist\0Song Album\0\0</CurrentMedia>
+ <CurrentMedia>\0Games\01\0Playing {0}\0Game Name\0</CurrentMedia>
+ <CurrentMedia>\0Office\01\0Office Message\0Office App Name\0</CurrentMedia>
+ */
+ switch(type)
+ {
+ case MSNProtocol::PersonalMessageMusic:
+ {
+ xmlCurrentMedia = "\\0Music\\01\\0";
+ QStringList mediaList = QStringList::split(";", personalMessage);
+ QString formatterArguments;
+ if( !mediaList[0].isEmpty() ) // Current Track
+ {
+ xmlCurrentMedia += "{0}";
+ formatterArguments += QString("%1\\0").arg(mediaList[0]);
+ }
+ if( !mediaList[1].isEmpty() ) // Current Artist
+ {
+ xmlCurrentMedia += " - {1}";
+ formatterArguments += QString("%1\\0").arg(mediaList[1]);
+ }
+ if( !mediaList[2].isEmpty() ) // Current Album
+ {
+ xmlCurrentMedia += " ({2})";
+ formatterArguments += QString("%1\\0").arg(mediaList[2]);
+ }
+ xmlCurrentMedia += "\\0" + formatterArguments + "\\0";
+ break;
+ }
+ default:
+ break;
+ }
+
+ currentMedia.appendChild( xmlMessage.createTextNode( xmlCurrentMedia ) );
+
+ // Set the status message for myself, check if currentMedia is empty, for either using the normal or Music personal
+ m_propertyPersonalMessage = xmlCurrentMedia.isEmpty() ? tempPersonalMessage : processCurrentMedia( currentMedia.text() );
+
+ xmlMessage.documentElement().appendChild( currentMedia );
+
+ unsigned int id = sendCommand("UUX","",true, xmlMessage.toString().utf8(), false);
+ m_tmpHandles[id] = m_account->accountId();
+
+}
+
+void MSNNotifySocket::changePhoneNumber( const QString &key, const QString &data )
+{
+ sendCommand( "PRP", key + " " + escape ( data ) );
+}
+
+
+void MSNNotifySocket::createChatSession()
+{
+ sendCommand( "XFR", "SB" );
+}
+
+QString MSNNotifySocket::statusToString( const Kopete::OnlineStatus &status ) const
+{
+ if( status == MSNProtocol::protocol()->NLN )
+ return "NLN";
+ else if( status == MSNProtocol::protocol()->BSY )
+ return "BSY";
+ else if( status == MSNProtocol::protocol()->BRB )
+ return "BRB";
+ else if( status == MSNProtocol::protocol()->AWY )
+ return "AWY";
+ else if( status == MSNProtocol::protocol()->PHN )
+ return "PHN";
+ else if( status == MSNProtocol::protocol()->LUN )
+ return "LUN";
+ else if( status == MSNProtocol::protocol()->FLN )
+ return "FLN";
+ else if( status == MSNProtocol::protocol()->HDN )
+ return "HDN";
+ else if( status == MSNProtocol::protocol()->IDL )
+ return "IDL";
+ else
+ {
+ kdWarning( 14140 ) << k_funcinfo << "Unknown status " << status.internalStatus() << "!" << endl;
+ return "UNK";
+ }
+}
+
+void MSNNotifySocket::slotSendKeepAlive()
+{
+ //we did not received the previous QNG
+ if(m_ping)
+ {
+ m_disconnectReason=Kopete::Account::ConnectionReset;
+ disconnect();
+ /*KMessageBox::queuedMessageBox( Kopete::UI::Global::mainWidget(), KMessageBox::Information,
+ i18n( "The connection with the MSN network has been lost." ) , i18n ("MSN Plugin") );*/
+ return;
+ }
+ else
+ {
+ // Send a dummy command to fake activity. This makes sure MSN doesn't
+ // disconnect you when the notify socket is idle.
+ sendCommand( "PNG" , QString::null , false );
+ m_ping=true;
+ }
+
+ //at least 90 second has been ellapsed since the last messages
+ // we shouldn't receive error from theses command anymore
+ m_tmpHandles.clear();
+}
+
+Kopete::OnlineStatus MSNNotifySocket::convertOnlineStatus( const QString &status )
+{
+ if( status == "NLN" )
+ return MSNProtocol::protocol()->NLN;
+ else if( status == "FLN" )
+ return MSNProtocol::protocol()->FLN;
+ else if( status == "HDN" )
+ return MSNProtocol::protocol()->HDN;
+ else if( status == "PHN" )
+ return MSNProtocol::protocol()->PHN;
+ else if( status == "LUN" )
+ return MSNProtocol::protocol()->LUN;
+ else if( status == "BRB" )
+ return MSNProtocol::protocol()->BRB;
+ else if( status == "AWY" )
+ return MSNProtocol::protocol()->AWY;
+ else if( status == "BSY" )
+ return MSNProtocol::protocol()->BSY;
+ else if( status == "IDL" )
+ return MSNProtocol::protocol()->IDL;
+ else
+ return MSNProtocol::protocol()->UNK;
+}
+
+
+#include "msnnotifysocket.moc"
+
+// vim: set noet ts=4 sts=4 sw=4:
+