2010-09-24 08:48:01 -05:00
/*
* notificationserver . cpp
* libmsn
*
* Created by Mark Rowe on Mon Mar 22 2004.
* Refactored by Tiago Salem Herrmann on 08 / 2007.
* Copyright ( c ) 2004 Mark Rowe . All rights reserved .
* Copyright ( c ) 2007 Tiago Salem Herrmann . All rights reserved
*
* 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 .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
2012-02-25 21:35:45 -06:00
# include <config.h>
# include <notificationserver.h>
# include <errorcodes.h>
# include <externals.h>
# include <md5.h>
# include <util.h>
# include <soap.h>
2010-09-24 08:48:01 -05:00
# include <algorithm>
# include <cctype>
# include <cassert>
# ifndef WIN32
# include <unistd.h>
# include <sys/socket.h>
# include <sys/ioctl.h>
# include <net/if.h>
# include <arpa/inet.h>
# else
# include <io.h>
# endif
# include <stdio.h>
# include <string.h>
# include <map>
# include "xmlParser.h"
namespace MSN
{
std : : map < std : : string , void ( NotificationServerConnection : : * ) ( std : : vector < std : : string > & ) > NotificationServerConnection : : commandHandlers ;
std : : map < std : : string , void ( NotificationServerConnection : : * ) ( std : : vector < std : : string > & , std : : string , std : : string ) > NotificationServerConnection : : messageHandlers ;
NotificationServerConnection : : NotificationServerConnection ( Passport username_ , std : : string password_ , Callbacks & cb_ )
: Connection ( ) , auth ( username_ , password_ ) , myPassport ( username_ ) , m_clientId ( 0 ) , externalCallbacks ( cb_ ) , _connectionState ( NS_DISCONNECTED ) , generatingLockkey ( false ) , removingOIM ( false ) , bplSetting ( ' B ' )
{
msnobj . setCreator ( username_ ) ;
registerHandlers ( ) ;
}
NotificationServerConnection : : ~ NotificationServerConnection ( )
{
if ( this - > connectionState ( ) ! = NS_DISCONNECTED )
this - > disconnect ( ) ;
}
Connection * NotificationServerConnection : : connectionWithSocket ( void * sock )
{
if ( this - > sock = = sock )
return this ;
std : : vector < SwitchboardServerConnection * > & list = _switchboardConnections ;
std : : vector < SwitchboardServerConnection * > : : iterator i = list . begin ( ) ;
for ( ; i ! = list . end ( ) ; i + + )
{
Connection * c = ( * i ) - > connectionWithSocket ( sock ) ;
if ( c )
return c ;
}
std : : vector < Soap * > & list2 = _SoapConnections ;
std : : vector < Soap * > : : iterator d = list2 . begin ( ) ;
for ( ; d ! = list2 . end ( ) ; d + + )
{
if ( ( * d ) - > sock = = sock )
return ( * d ) ;
}
return NULL ;
}
SwitchboardServerConnection * NotificationServerConnection : : switchboardWithOnlyUser ( Passport username )
{
if ( this - > connectionState ( ) > = NS_CONNECTED )
{
std : : vector < SwitchboardServerConnection * > & list = _switchboardConnections ;
std : : vector < SwitchboardServerConnection * > : : iterator i = list . begin ( ) ;
for ( ; i ! = list . end ( ) ; i + + )
{
if ( ( * i ) - > users . size ( ) = = 1 & &
* ( ( * i ) - > users . begin ( ) ) = = username )
return * i ;
}
}
return NULL ;
}
const std : : vector < SwitchboardServerConnection * > & NotificationServerConnection : : switchboardConnections ( )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
return _switchboardConnections ;
}
void NotificationServerConnection : : addSwitchboardConnection ( SwitchboardServerConnection * c )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
_switchboardConnections . push_back ( c ) ;
}
void NotificationServerConnection : : addSoapConnection ( Soap * s )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
_SoapConnections . push_back ( s ) ;
}
void NotificationServerConnection : : removeSwitchboardConnection ( SwitchboardServerConnection * c )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
std : : vector < SwitchboardServerConnection * > : : iterator it ;
for ( it = _switchboardConnections . begin ( ) ; it ! = _switchboardConnections . end ( ) ; it + + )
{
if ( ( * it ) = = c )
{
_switchboardConnections . erase ( it ) ;
return ;
}
}
}
void NotificationServerConnection : : removeSoapConnection ( Soap * s )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
std : : vector < Soap * > : : iterator it ;
for ( it = _SoapConnections . begin ( ) ; it ! = _SoapConnections . end ( ) ; it + + )
{
if ( ( * it ) = = s )
{
_SoapConnections . erase ( it ) ;
return ;
}
}
}
void NotificationServerConnection : : addCallback ( NotificationServerCallback callback ,
int trid , void * data )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTING ) ;
this - > callbacks [ trid ] = std : : make_pair ( callback , data ) ;
}
void NotificationServerConnection : : removeCallback ( int trid )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTING ) ;
this - > callbacks . erase ( trid ) ;
}
void NotificationServerConnection : : registerHandlers ( )
{
if ( commandHandlers . size ( ) = = 0 )
{
commandHandlers [ " OUT " ] = & NotificationServerConnection : : handle_OUT ;
commandHandlers [ " RML " ] = & NotificationServerConnection : : handle_RML ;
commandHandlers [ " BLP " ] = & NotificationServerConnection : : handle_BLP ;
commandHandlers [ " CHG " ] = & NotificationServerConnection : : handle_CHG ;
commandHandlers [ " CHL " ] = & NotificationServerConnection : : handle_CHL ;
commandHandlers [ " ILN " ] = & NotificationServerConnection : : handle_ILN ;
commandHandlers [ " NLN " ] = & NotificationServerConnection : : handle_NLN ;
commandHandlers [ " FLN " ] = & NotificationServerConnection : : handle_FLN ;
commandHandlers [ " MSG " ] = & NotificationServerConnection : : handle_MSG ;
commandHandlers [ " PRP " ] = & NotificationServerConnection : : handle_PRP ;
commandHandlers [ " UBX " ] = & NotificationServerConnection : : handle_UBX ;
commandHandlers [ " GCF " ] = & NotificationServerConnection : : handle_GCF ;
commandHandlers [ " ADL " ] = & NotificationServerConnection : : handle_ADL ;
commandHandlers [ " UBN " ] = & NotificationServerConnection : : handle_UBN ;
commandHandlers [ " FQY " ] = & NotificationServerConnection : : handle_FQY ;
}
if ( messageHandlers . size ( ) = = 0 )
{
messageHandlers [ " text/x-msmsgsinitialemailnotification " ] = & NotificationServerConnection : : message_initial_email_notification ;
messageHandlers [ " text/x-msmsgsinitialmdatanotification " ] = & NotificationServerConnection : : message_initialmdatanotification ;
messageHandlers [ " text/x-msmsgsemailnotification " ] = & NotificationServerConnection : : message_email_notification ;
messageHandlers [ " text/x-msmsgsprofile " ] = & NotificationServerConnection : : message_msmsgsprofile ;
messageHandlers [ " text/x-msmsgsoimnotification " ] = & NotificationServerConnection : : message_oimnotification ;
}
}
void NotificationServerConnection : : dispatchCommand ( std : : vector < std : : string > & args )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
std : : map < std : : string , void ( NotificationServerConnection : : * ) ( std : : vector < std : : string > & ) > : : iterator i = commandHandlers . find ( args [ 0 ] ) ;
if ( i ! = commandHandlers . end ( ) )
( this - > * commandHandlers [ args [ 0 ] ] ) ( args ) ;
}
void NotificationServerConnection : : disconnectNS ( )
{
std : : ostringstream buf_ ;
buf_ < < " OUT \r \n " ;
if ( this - > write ( buf_ ) ! = buf_ . str ( ) . size ( ) )
return ;
disconnect ( ) ;
}
void NotificationServerConnection : : handle_OUT ( std : : vector < std : : string > & args )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
if ( args . size ( ) > 1 )
{
if ( args [ 1 ] = = " OTH " )
{
this - > myNotificationServer ( ) - > externalCallbacks . showError ( this , " You have logged onto MSN twice at once. Your MSN session will now terminate. " ) ;
}
else if ( args [ 1 ] = = " SSD " )
{
this - > myNotificationServer ( ) - > externalCallbacks . showError ( this , " This MSN server is going down for maintenance. Your MSN session will now terminate. " ) ;
} else {
this - > myNotificationServer ( ) - > externalCallbacks . showError ( this , ( std : : string ( " The MSN server has terminated the connection with an unknown reason code. Please report this code: " ) +
args [ 1 ] ) . c_str ( ) ) ;
}
}
this - > disconnect ( ) ;
}
void NotificationServerConnection : : handle_RML ( std : : vector < std : : string > & args )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
int msglen ;
std : : string msg ;
if ( args [ 2 ] ! = " OK " & & args [ 2 ] ! = " OK " )
return ; // TODO - raise an error
msglen = decimalFromString ( args [ 2 ] ) ;
msg = this - > readBuffer . substr ( 0 , msglen ) ;
this - > readBuffer = this - > readBuffer . substr ( msglen ) ;
XMLNode rml_data = XMLNode : : parseString ( msg . c_str ( ) ) ;
int nDomains = rml_data . nChildNode ( " d " ) ;
for ( int i = 0 ; i < nDomains ; i + + )
{
XMLNode domain = rml_data . getChildNode ( " d " , i ) ;
std : : string domain_name = domain . getAttribute ( " n " , 0 ) ;
int nContacts = domain . nChildNode ( " c " ) ;
for ( int j = 0 ; j < nContacts ; j + + )
{
XMLNode contact = domain . getChildNode ( " c " , j ) ;
std : : string contact_name = contact . getAttribute ( " n " , 0 ) ;
MSN : : ContactList list_number = ( MSN : : ContactList ) decimalFromString ( contact . getAttribute ( " l " , 0 ) ) ;
// type is 1 for normal contact, 4 for mobile phone
// TODO - use this value
//int type = decimalFromString(contact.getAttribute("t",0));
MSN : : Passport passport ( contact_name + " @ " + domain_name ) ;
this - > myNotificationServer ( ) - > externalCallbacks . removedListEntry ( this , list_number , passport ) ;
}
}
}
void NotificationServerConnection : : handle_BLP ( std : : vector < std : : string > & args )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
this - > myNotificationServer ( ) - > externalCallbacks . gotBLP ( this , args [ 3 ] [ 0 ] ) ;
}
void NotificationServerConnection : : handle_CHG ( std : : vector < std : : string > & args )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
this - > myNotificationServer ( ) - > externalCallbacks . changedStatus ( this , buddyStatusFromString ( args [ 2 ] ) ) ;
}
void NotificationServerConnection : : handle_CHL ( std : : vector < std : : string > & args )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
std : : ostringstream buf_ ;
buf_ < < " QRY " < < this - > trID + + < < " " < < szClientID < < " 32 \r \n " ;
if ( write ( buf_ ) ! = buf_ . str ( ) . size ( ) )
return ;
char b [ 33 ] ;
memset ( & b , 0 , 33 ) ;
DoMSNP11Challenge ( args [ 2 ] . c_str ( ) , b ) ;
// send the md5
std : : string a ( b ) ;
write ( a , false ) ;
}
void NotificationServerConnection : : handle_ILN ( std : : vector < std : : string > & args )
{
this - > assertConnectionStateIs ( NS_CONNECTED ) ;
if ( args . size ( ) > 7 )
this - > myNotificationServer ( ) - > externalCallbacks . buddyChangedStatus ( this , args [ 3 ] , decodeURL ( args [ 5 ] ) , buddyStatusFromString ( args [ 2 ] ) , decimalFromString ( args [ 6 ] ) , decodeURL ( args [ 7 ] ) ) ;
else
this - > myNotificationServer ( ) - > externalCallbacks . buddyChangedStatus ( this , args [ 3 ] , decodeURL ( args [ 5 ] ) , buddyStatusFromString ( args [ 2 ] ) , decimalFromString ( args [ 6 ] ) , " " ) ;
}
void NotificationServerConnection : : handle_NLN ( std : : vector < std : : string > & args )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
if ( args . size ( ) > 6 )
this - > myNotificationServer ( ) - > externalCallbacks . buddyChangedStatus ( this , args [ 2 ] , decodeURL ( args [ 4 ] ) , buddyStatusFromString ( args [ 1 ] ) , decimalFromString ( args [ 5 ] ) , decodeURL ( args [ 6 ] ) ) ;
else
this - > myNotificationServer ( ) - > externalCallbacks . buddyChangedStatus ( this , args [ 2 ] , decodeURL ( args [ 4 ] ) , buddyStatusFromString ( args [ 1 ] ) , decimalFromString ( args [ 5 ] ) , " " ) ;
}
void NotificationServerConnection : : handle_FLN ( std : : vector < std : : string > & args )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
this - > myNotificationServer ( ) - > externalCallbacks . buddyOffline ( this , args [ 1 ] ) ;
}
void NotificationServerConnection : : handle_UBN ( std : : vector < std : : string > & args )
{
// TODO - UBN is a way to exchange data through notification server
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
int msglen ;
std : : string msg ;
msglen = decimalFromString ( args [ 3 ] ) ;
msg = this - > readBuffer . substr ( 0 , msglen ) ;
this - > readBuffer = this - > readBuffer . substr ( msglen ) ;
}
void NotificationServerConnection : : handle_FQY ( std : : vector < std : : string > & args )
{
// TODO - I dont know what it means yet
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
int msglen ;
std : : string msg ;
msglen = decimalFromString ( args [ 2 ] ) ;
msg = this - > readBuffer . substr ( 0 , msglen ) ;
this - > readBuffer = this - > readBuffer . substr ( msglen ) ;
}
void NotificationServerConnection : : callback_URL ( std : : vector < std : : string > & args , int trid , void * data )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
char b [ 33 ] ;
MSN : : hotmailInfo info ;
info . rru = args [ 2 ] ;
info . url = args [ 3 ] ;
info . id = args [ 4 ] ;
info . sl = toStr ( time ( NULL ) - decimalFromString ( login_time ) ) ;
info . MSPAuth = MSPAuth ;
info . sid = sid ;
info . kv = kv ;
// calculate creds
std : : string creds_tmp = MSPAuth + info . sl + this - > auth . password ;
memset ( & b , 0 , 33 ) ;
md5_state_t state ;
md5_byte_t digest [ 16 ] ;
int di ;
md5_init ( & state ) ;
md5_append ( & state , ( const md5_byte_t * ) creds_tmp . c_str ( ) , creds_tmp . size ( ) ) ;
md5_finish ( & state , digest ) ;
// convert to string
for ( di = 0 ; di < 16 ; + + di )
sprintf ( & b [ 2 * di ] , " %02x " , digest [ di ] ) ;
std : : string creds ( b ) ;
info . creds = creds ;
this - > myNotificationServer ( ) - > externalCallbacks . gotInboxUrl ( this , info ) ;
}
void NotificationServerConnection : : handle_MSG ( std : : vector < std : : string > & args )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
int msglen ;
std : : string msg ;
std : : string mime ;
std : : string body ;
size_t tmp ;
msglen = decimalFromString ( args [ 3 ] ) ;
msg = this - > readBuffer . substr ( 0 , msglen ) ;
this - > readBuffer = this - > readBuffer . substr ( msglen ) ;
body = msg . substr ( msg . find ( " \r \n \r \n " ) + 4 ) ;
mime = msg . substr ( 0 , msg . size ( ) - body . size ( ) ) ;
std : : string contentType ;
Message : : Headers headers = Message : : Headers ( mime ) ;
contentType = headers [ " Content-Type " ] ;
if ( ( tmp = contentType . find ( " ; charset " ) ) ! = std : : string : : npos )
contentType = contentType . substr ( 0 , tmp ) ;
std : : map < std : : string , void ( NotificationServerConnection : : * ) ( std : : vector < std : : string > & , std : : string , std : : string ) > : : iterator i = messageHandlers . find ( contentType ) ;
if ( i ! = messageHandlers . end ( ) )
( this - > * ( messageHandlers [ contentType ] ) ) ( args , mime , body ) ;
}
void NotificationServerConnection : : message_initial_email_notification ( std : : vector < std : : string > & args , std : : string mime , std : : string body )
{
std : : string unreadInbox ;
std : : string unreadFolder ;
int unreadInboxCount = 0 , unreadFolderCount = 0 ;
// Initial email notifications body is a set of MIME headers
Message : : Headers headers = Message : : Headers ( body ) ;
unreadInbox = headers [ " Inbox-Unread " ] ;
unreadFolder = headers [ " Folders-Unread " ] ;
if ( ! unreadInbox . empty ( ) )
unreadInboxCount = decimalFromString ( unreadInbox ) ;
if ( ! unreadFolder . empty ( ) )
unreadFolderCount = decimalFromString ( unreadFolder ) ;
// this->myNotificationServer()->externalCallbacks.gotInitialEmailNotification(this, unreadInboxCount, unreadFolderCount);
}
void NotificationServerConnection : : message_email_notification ( std : : vector < std : : string > & args , std : : string mime , std : : string body )
{
// New email notifications body is a set of MIME headers
Message : : Headers headers = Message : : Headers ( body ) ;
std : : string from = headers [ " From-Addr " ] ;
std : : string subject = headers [ " Subject " ] ;
this - > myNotificationServer ( ) - > externalCallbacks . gotNewEmailNotification ( this , from , subject ) ;
}
void NotificationServerConnection : : message_msmsgsprofile ( std : : vector < std : : string > & args , std : : string mime , std : : string body )
{
direct_connection = false ;
Message : : Headers headers = Message : : Headers ( mime ) ;
server_reported_ip = headers [ " ClientIP " ] ;
server_reported_port = headers [ " ClientPort " ] ;
login_time = headers [ " LoginTime " ] ;
MSPAuth = headers [ " MSPAuth " ] ;
sid = headers [ " sid " ] ;
kv = headers [ " kv " ] ;
if ( login_time . empty ( ) ) //IN MSNP9 there is no logintime it seems, so set it manualy
{
time_t actualTime ;
std : : stringstream os ;
time ( & actualTime ) ;
os < < actualTime ;
login_time = os . str ( ) ;
}
this - > myNotificationServer ( ) - > externalCallbacks . gotNewConnection ( this ) ;
// TODO - test portability to windows and mac, probably solved by ifdefs,
// or with an external callback to user application
// search on local machine the ip reported by the server
/* int s = socket (PF_INET, SOCK_STREAM, 0);
for ( int i = 1 ; ; i + + )
{
struct ifreq ifr ;
struct sockaddr_in * sin = ( struct sockaddr_in * ) & ifr . ifr_addr ;
char * ip ;
ifr . ifr_ifindex = i ;
if ( ioctl ( s , SIOCGIFNAME , & ifr ) < 0 )
break ;
if ( ioctl ( s , SIOCGIFADDR , & ifr ) < 0 )
continue ;
ip = inet_ntoa ( sin - > sin_addr ) ;
std : : string ip2 ( ip ) ;
if ( ip2 = = server_reported_ip )
direct_connection = true ;
}
close ( s ) ;
*/
}
void NotificationServerConnection : : message_initialmdatanotification ( std : : vector < std : : string > & args , std : : string mime , std : : string body )
{
Message : : Headers headers = Message : : Headers ( body ) ;
std : : string maildata = headers [ " Mail-Data " ] ;
XMLNode domTree = XMLNode : : parseString ( maildata . c_str ( ) ) ;
//Mail-Data: <MD><E><I>2</I><IU>1</IU><O>1</O><OU>0</OU></E><Q><QTM>409600</QTM><QNM>204800</QNM></Q></MD>
//Mail-Data: <MD><E><I>3</I><IU>2</IU><O>2</O><OU>0</OU></E><Q><QTM>409600</QTM><QNM>204800</QNM></Q></MD>
//Mail-Data: <MD><E><I>3</I><IU>1</IU><O>2</O><OU>0</OU></E><Q><QTM>409600</QTM><QNM>204800</QNM></Q></MD>
//empty inbox
//Mail-Data: <MD><E><I>0</I><IU>0</IU><O>5</O><OU>0</OU></E><Q><QTM>409600</QTM><QNM>204800</QNM></Q></MD>
int emails = domTree . nChildNode ( " E " ) ;
if ( emails )
{
XMLNode curr_element = domTree . getChildNode ( " E " , 0 ) ;
int inbox_msgs = decimalFromString ( curr_element . getChildNode ( " I " ) . getText ( ) ) ;
int inbox_unread = decimalFromString ( curr_element . getChildNode ( " IU " ) . getText ( ) ) ;
int other_folders = decimalFromString ( curr_element . getChildNode ( " O " ) . getText ( ) ) ;
int other_folders_unread = decimalFromString ( curr_element . getChildNode ( " OU " ) . getText ( ) ) ;
this - > myNotificationServer ( ) - > externalCallbacks . gotInitialEmailNotification ( this , inbox_msgs , inbox_unread , other_folders , other_folders_unread ) ;
}
// try to get OIM information
message_oimnotification ( args , mime , body ) ;
}
void NotificationServerConnection : : message_oimnotification ( std : : vector < std : : string > & args , std : : string mime , std : : string body )
{
Message : : Headers headers = Message : : Headers ( body ) ;
std : : string maildata = headers [ " Mail-Data " ] ;
if ( maildata = = " too-large " )
{
// more than 25 OIM's
// request OIM list through soap
Soap * soapConnection = new Soap ( * this , this - > sitesToAuthList ) ;
soapConnection - > getMailData ( ) ;
return ;
}
// process maildata
gotMailData ( maildata ) ;
}
void NotificationServerConnection : : gotSoapMailData ( Soap & soapConnection , std : : string maildata )
{
gotMailData ( maildata ) ;
}
void NotificationServerConnection : : gotMailData ( std : : string maildata )
{
std : : vector < eachOIM > messages ;
XMLNode domTree = XMLNode : : parseString ( maildata . c_str ( ) ) ;
int oims = domTree . nChildNode ( " M " ) ;
if ( oims )
{
for ( int i = 0 ; i < oims ; i + + )
{
eachOIM temp_oim ;
XMLNode curr_element = domTree . getChildNode ( " M " , i ) ;
temp_oim . from = curr_element . getChildNode ( " E " ) . getText ( ) ;
temp_oim . id = curr_element . getChildNode ( " I " ) . getText ( ) ;
temp_oim . fromFN = curr_element . getChildNode ( " N " ) . getText ( ) ;
std : : vector < std : : string > friendlyName ;
// if we do not have '?', it is just the email
if ( temp_oim . fromFN . find ( " ? " ) ! = std : : string : : npos )
{
friendlyName = splitString ( temp_oim . fromFN , " ? " ) ;
// TODO - handle the encoding (friendlyName[1])
if ( friendlyName [ 2 ] = = " B " )
{
temp_oim . fromFN = b64_decode ( friendlyName [ 3 ] . c_str ( ) ) ;
}
if ( friendlyName [ 2 ] = = " Q " )
{
// Quoted-Printable, is similar to URL encoding,
// but uses "=" instead of "%".
std : : string change = friendlyName [ 3 ] ;
// changes the = by %
for ( unsigned int a = 0 ; a < change . length ( ) ; a + + )
if ( change [ a ] = = ' = ' ) change [ a ] = ' % ' ;
temp_oim . fromFN = decodeURL ( change ) ;
}
}
messages . push_back ( temp_oim ) ;
}
this - > myNotificationServer ( ) - > externalCallbacks . gotOIMList ( this , messages ) ;
}
domTree . deleteNodeContent ( ' Y ' ) ;
}
void NotificationServerConnection : : handle_RNG ( std : : vector < std : : string > & args )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
SwitchboardServerConnection : : AuthData auth = SwitchboardServerConnection : : AuthData ( this - > auth . username ,
args [ 1 ] ,
args [ 4 ] ) ;
SwitchboardServerConnection * newSBconn = new SwitchboardServerConnection ( auth , * this ) ;
this - > addSwitchboardConnection ( newSBconn ) ;
std : : pair < std : : string , int > server_address = splitServerAddress ( args [ 2 ] ) ;
newSBconn - > connect ( server_address . first , server_address . second ) ;
}
void NotificationServerConnection : : handle_PRP ( std : : vector < std : : string > & args )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
if ( this - > _connectionState = = NS_SYNCHRONISING )
{
this - > myNotificationServer ( ) - > externalCallbacks . gotFriendlyName ( this , decodeURL ( args [ 3 ] ) ) ;
this - > myDisplayName = decodeURL ( args [ 3 ] ) ;
this - > myNotificationServer ( ) - > externalCallbacks . connectionReady ( this ) ;
// the initial process ends here
this - > setConnectionState ( NS_CONNECTED ) ;
return ;
}
if ( args [ 2 ] = = " MFN " ) //when you set manually your FriendlyName
{
this - > myNotificationServer ( ) - > externalCallbacks . gotFriendlyName ( this , decodeURL ( args [ 3 ] ) ) ;
this - > myDisplayName = decodeURL ( args [ 3 ] ) ;
} // TODO - Implement other PRP commands: MBE WWE
}
void NotificationServerConnection : : handle_GCF ( std : : vector < std : : string > & args )
{
int msglen ;
std : : string msg ;
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
// we do not use it so far. throw it away
msglen = decimalFromString ( args [ 2 ] ) ;
msg = this - > readBuffer . substr ( 0 , msglen ) ;
this - > readBuffer = this - > readBuffer . substr ( msglen ) ;
}
void NotificationServerConnection : : handle_ADL ( std : : vector < std : : string > & args )
{
int msglen ;
std : : string msg ;
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
if ( args [ 2 ] = = " OK " & & ( this - > _connectionState = = NS_SYNCHRONISING ) )
{
if ( adl_packets . empty ( ) )
{
// no more adl packets to send!
// now you need the change the nickname and set the status
// to complete the initial connection process
// it is not possible to use setFriendlyName
// because we cannot send soap requests at this time
std : : ostringstream buf_ ;
if ( this - > myDisplayName . empty ( ) )
this - > myDisplayName = myPassport ;
if ( server_email_verified ! = " 0 " )
{
// our email is verified
buf_ < < " PRP " < < this - > trID + + < < " MFN " < < encodeURL ( this - > myDisplayName ) < < " \r \n " ;
write ( buf_ ) ;
}
else
{
// not verified, so we cant change our displayName
this - > myNotificationServer ( ) - > externalCallbacks . connectionReady ( this ) ;
// the initial process ends here
this - > setConnectionState ( NS_CONNECTED ) ;
}
return ;
}
else
{
// send each adl packet at a time
std : : string adl_payload = adl_packets . front ( ) ;
adl_packets . pop_front ( ) ;
std : : ostringstream buf_ ;
buf_ < < " ADL " < < this - > trID + + < < " " < < adl_payload . length ( ) < < " \r \n " ;
buf_ < < adl_payload ;
if ( write ( buf_ ) ! = buf_ . str ( ) . size ( ) )
return ;
}
}
// I reach here when ADL has payload
msglen = decimalFromString ( args [ 2 ] ) ;
msg = this - > readBuffer . substr ( 0 , msglen ) ;
this - > readBuffer = this - > readBuffer . substr ( msglen ) ;
// ADL 0 70
// <ml><d n="domain.com"><c n="foo.bar" t="1" l="8" f="fName" /></d></ml>
//
XMLNode adl_data = XMLNode : : parseString ( msg . c_str ( ) ) ;
int nDomains = adl_data . nChildNode ( " d " ) ;
for ( int i = 0 ; i < nDomains ; i + + )
{
XMLNode domain = adl_data . getChildNode ( " d " , i ) ;
std : : string domain_name = domain . getAttribute ( " n " , 0 ) ;
int nContacts = domain . nChildNode ( " c " ) ;
for ( int j = 0 ; j < nContacts ; j + + )
{
XMLNode contact = domain . getChildNode ( " c " , j ) ;
std : : string contact_name = contact . getAttribute ( " n " , 0 ) ;
std : : string fname = contact . getAttribute ( " f " , 0 ) ;
MSN : : ContactList list_number = ( MSN : : ContactList ) decimalFromString ( contact . getAttribute ( " l " , 0 ) ) ;
// type is 1 for wlm contacts, 4 for mobile phone, 32 for yahoo? (or any kind of email contact)
int type = decimalFromString ( contact . getAttribute ( " t " , 0 ) ) ;
if ( type = = 32 )
return ;
MSN : : Passport passport ( contact_name + " @ " + domain_name ) ;
this - > myNotificationServer ( ) - > externalCallbacks . addedListEntry ( this , list_number , passport , fname ) ;
}
}
}
void NotificationServerConnection : : handle_UBX ( std : : vector < std : : string > & args )
{
int msglen ;
personalInfo pInfo ;
std : : string msg , media , psm ;
MSN : : Passport fromPassport = args [ 1 ] ;
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
msglen = decimalFromString ( args [ 3 ] ) ;
msg = this - > readBuffer . substr ( 0 , msglen ) ;
this - > readBuffer = this - > readBuffer . substr ( msglen ) ;
// some buggy clients send no data in UBX command
if ( msg . length ( ) < 10 ) return ;
XMLNode ubx_data = XMLNode : : parseString ( msg . c_str ( ) ) ;
const char * a = ubx_data . getChildNode ( " PSM " ) . getText ( ) ;
if ( a )
{
psm = a ;
pInfo . PSM = psm ;
}
const char * m = ubx_data . getChildNode ( " CurrentMedia " ) . getText ( ) ;
if ( m )
{
media = m ;
// the splitString will drop the first NULL position.
// we need it to keep the order of the following fields.
std : : vector < std : : string > media1 = splitString ( media , " \\ 0 " ) ;
if ( media1 . size ( ) > = 4 ) // at least 4 fields. Type, Enabled, format, data
{ // if we have some field, so ...
int i = 0 ;
if ( media . find ( " \\ 0 " ) = = 0 )
{ // if starts with \0 there is no
// App field. It is optional.
pInfo . mediaApp = " " ;
}
else
{
pInfo . mediaApp = media1 [ i + + ] ;
}
pInfo . mediaType = media1 [ i + + ] ;
pInfo . mediaIsEnabled = decimalFromString ( media1 [ i + + ] ) ;
if ( pInfo . mediaIsEnabled )
{
pInfo . mediaFormat = media1 [ i + + ] ;
for ( unsigned int b = i ; b < media1 . size ( ) ; b + + )
{
pInfo . mediaLines . push_back ( media1 [ i + + ] ) ;
}
}
}
}
this - > myNotificationServer ( ) - > externalCallbacks . buddyChangedPersonalInfo ( this , fromPassport , pInfo ) ;
}
void NotificationServerConnection : : setState ( BuddyStatus state , uint clientID )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
std : : ostringstream buf_ ;
std : : string xml ;
if ( msnobj . getMSNObjectXMLByType ( 3 , xml ) )
buf_ < < " CHG " < < this - > trID + + < < " " < <
buddyStatusToString ( state ) < < " " < < unsignedToStr ( clientID ) < < " " < < encodeURL ( xml ) < < " \r \n " ;
else
buf_ < < " CHG " < < this - > trID + + < < " " < < buddyStatusToString ( state ) < < " " < < unsignedToStr ( clientID ) < < " \r \n " ;
write ( buf_ ) ;
}
void NotificationServerConnection : : setBLP ( char setting )
{
if ( setting ! = ' A ' | | setting ! = ' B ' )
return ;
if ( this - > _connectionState = = NS_CONNECTED )
{
std : : ostringstream buf_ ;
this - > bplSetting = setting ;
buf_ < < " BLP " < < this - > trID + + < < " " < < setting < < " L \r \n " ;
write ( buf_ ) ;
}
else
{
this - > bplSetting = setting ;
}
}
void NotificationServerConnection : : setFriendlyName ( std : : string friendlyName , bool updateServer ) throw ( std : : runtime_error )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
if ( friendlyName . empty ( ) )
return ;
if ( friendlyName . size ( ) > 387 )
throw std : : runtime_error ( " Friendly name too long! " ) ;
if ( updateServer )
{
// update nickname on server
Soap * soapConnection = new Soap ( * this , this - > sitesToAuthList ) ;
soapConnection - > changeDisplayName ( friendlyName ) ;
}
else
{
this - > myDisplayName = friendlyName ;
std : : ostringstream buf_ ;
buf_ < < " PRP " < < this - > trID + + < < " MFN " < < encodeURL ( friendlyName ) < < " \r \n " ;
write ( buf_ ) ;
}
}
void NotificationServerConnection : : setPersonalStatus ( personalInfo pInfo )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
std : : string tempMedia ;
XMLNode data = XMLNode : : createXMLTopNode ( " Data " ) ;
XMLNode PSM = XMLNode : : createXMLTopNode ( " PSM " ) ;
XMLNode CurrentMedia = XMLNode : : createXMLTopNode ( " CurrentMedia " ) ;
XMLNode MachineGuid = XMLNode : : createXMLTopNode ( " MachineGuid " ) ;
PSM . addText ( pInfo . PSM . c_str ( ) ) ;
if ( pInfo . mediaIsEnabled )
{
tempMedia = pInfo . mediaApp + " \\ 0 " +
pInfo . mediaType + " \\ 0 " +
toStr ( pInfo . mediaIsEnabled ) + " \\ 0 " +
pInfo . mediaFormat + " \\ 0 " ;
std : : vector < std : : string > : : iterator i = pInfo . mediaLines . begin ( ) ;
for ( ; i ! = pInfo . mediaLines . end ( ) ; i + + )
{
tempMedia + = ( * i ) ;
tempMedia + = " \\ 0 " ;
}
}
CurrentMedia . addText ( tempMedia . c_str ( ) ) ;
data . addChild ( PSM ) ;
data . addChild ( CurrentMedia ) ;
char * payload1 = data . createXMLString ( false ) ;
std : : string payload ( payload1 ) ;
free ( payload1 ) ;
std : : ostringstream buf_ ;
buf_ < < " UUX " < < this - > trID + + < < " " < < payload . length ( ) < < " \r \n " ;
buf_ < < payload ;
write ( buf_ ) ;
}
void NotificationServerConnection : : blockContact ( Passport buddyName )
{
Soap * soapConnection = new Soap ( * this , this - > sitesToAuthList ) ;
soapConnection - > removeContactFromList ( buddyName , LST_AL ) ;
soapConnection = new Soap ( * this , this - > sitesToAuthList ) ;
soapConnection - > addContactToList ( buddyName , LST_BL ) ;
}
void NotificationServerConnection : : unblockContact ( Passport buddyName )
{
Soap * soapConnection = new Soap ( * this , this - > sitesToAuthList ) ;
soapConnection - > removeContactFromList ( buddyName , LST_BL ) ;
soapConnection = new Soap ( * this , this - > sitesToAuthList ) ;
soapConnection - > addContactToList ( buddyName , LST_AL ) ;
}
void NotificationServerConnection : : addToAddressBook ( Passport buddyName , std : : string displayName )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
Soap * soapConnection = new Soap ( * this , this - > sitesToAuthList ) ;
soapConnection - > addContactToAddressBook ( buddyName , displayName ) ;
}
void NotificationServerConnection : : enableContactOnAddressBook ( std : : string contactId , std : : string passport )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
Soap * soapConnection = new Soap ( * this , this - > sitesToAuthList ) ;
soapConnection - > enableContactOnAddressBook ( contactId , passport , this - > myDisplayName ) ;
}
void NotificationServerConnection : : disableContactOnAddressBook ( std : : string contactId , std : : string passport )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
Soap * soapConnection = new Soap ( * this , this - > sitesToAuthList ) ;
soapConnection - > disableContactFromAddressBook ( contactId , passport ) ;
}
void NotificationServerConnection : : delFromAddressBook ( std : : string contactId , std : : string passport )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
std : : vector < std : : string > passport2 = splitString ( passport , " @ " ) ;
std : : string user = passport2 [ 0 ] ;
std : : string domain = passport2 [ 1 ] ;
Soap * soapConnection = new Soap ( * this , this - > sitesToAuthList ) ;
soapConnection - > delContactFromAddressBook ( contactId , passport ) ;
}
void NotificationServerConnection : : addToList ( MSN : : ContactList list , Passport buddyName )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
Soap * soapConnection = new Soap ( * this , this - > sitesToAuthList ) ;
soapConnection - > addContactToList ( buddyName , list ) ;
}
void NotificationServerConnection : : removeFromList ( MSN : : ContactList list , Passport buddyName )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
Soap * soapConnection = new Soap ( * this , this - > sitesToAuthList ) ;
soapConnection - > removeContactFromList ( buddyName , list ) ;
}
void NotificationServerConnection : : addToGroup ( std : : string groupId , std : : string contactId )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
Soap * soapConnection = new Soap ( * this , this - > sitesToAuthList ) ;
soapConnection - > addContactToGroup ( groupId , contactId ) ;
}
void NotificationServerConnection : : removeFromGroup ( std : : string groupId , std : : string contactId )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
Soap * soapConnection = new Soap ( * this , this - > sitesToAuthList ) ;
soapConnection - > delContactFromGroup ( groupId , contactId ) ;
}
void NotificationServerConnection : : addGroup ( std : : string groupName )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
Soap * soapConnection = new Soap ( * this , this - > sitesToAuthList ) ;
soapConnection - > addGroup ( groupName ) ;
}
void NotificationServerConnection : : removeGroup ( std : : string groupID )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
Soap * soapConnection = new Soap ( * this , this - > sitesToAuthList ) ;
soapConnection - > delGroup ( groupID ) ;
}
void NotificationServerConnection : : renameGroup ( std : : string groupID , std : : string newGroupName )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
Soap * soapConnection = new Soap ( * this , this - > sitesToAuthList ) ;
soapConnection - > renameGroup ( groupID , newGroupName ) ;
}
void NotificationServerConnection : : synchronizeContactList ( std : : string lastChange )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
this - > assertConnectionStateIsNot ( NS_SYNCHRONISING ) ;
// we are synchronizing through soap requests now
this - > setConnectionState ( NS_SYNCHRONISING ) ;
listInfo = new ListSyncInfo ( lastChange ) ;
if ( ! listInfo )
return ; // TODO - raise an error
if ( ! lastChange . length ( ) ) lastChange = " 0 " ;
listInfo - > lastChange = lastChange ;
Soap * soapConnection ;
soapConnection = new Soap ( * this , this - > sitesToAuthList ) ;
soapConnection - > getLists ( listInfo ) ;
}
void NotificationServerConnection : : gotLists ( Soap & soapConnection )
{
if ( ! listInfo )
return ; // TODO - raise an error
Soap * soapConnection1 ;
soapConnection1 = new Soap ( * this , this - > sitesToAuthList ) ;
// ask for Address book
soapConnection1 - > getAddressBook ( this - > listInfo ) ;
}
void NotificationServerConnection : : gotAddressBook ( Soap & soapConnection )
{
// TODO - sorry, I dont have choice. I need this here because the initial setFriendlyName
// is called by handle_ADL(), which does not have access to info variable.
this - > myDisplayName = listInfo - > myDisplayName ;
std : : ostringstream buf_ ;
// TODO - see what is the user choice: BL or AL
// A value of 'AL' indicates that users that are neither on the client's Allow List or Buddy List will be allowed to see the client's online status and open a switchboard session with the client. A value of 'BL' indicates that these users will see the client as offline and will not be allowed to open a switchboard session.
// http://msnpiki.msnfanatic.com/index.php/Command:BLP
buf_ < < " BLP " < < this - > trID < < " " < < this - > bplSetting < < " L \r \n " ;
if ( write ( buf_ ) ! = buf_ . str ( ) . size ( ) )
return ;
this - > addCallback ( & NotificationServerConnection : : callback_initialBPL , this - > trID + + , ( void * ) NULL ) ;
}
void NotificationServerConnection : : callback_initialBPL ( std : : vector < std : : string > & args , int trid , void * data )
{
this - > assertConnectionStateIs ( NS_SYNCHRONISING ) ;
this - > removeCallback ( trid ) ;
this - > myNotificationServer ( ) - > externalCallbacks . gotBuddyListInfo ( this , this - > listInfo ) ;
delete this - > listInfo ;
}
void NotificationServerConnection : : completeConnection ( std : : map < std : : string , int > & allContacts , void * info )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
// FIXME - handle the errors
std : : map < std : : string , std : : vector < std : : string > > domains ;
std : : string tempADL ;
// contains which number is. (i.e. 1 for FL, 2 for AL, 4 for BL) or the sum
std : : map < std : : string , int > tempList ;
std : : map < std : : string , int > : : iterator i ;
for ( i = allContacts . begin ( ) ; i ! = allContacts . end ( ) ; i + + )
{
std : : vector < std : : string > parts = splitString ( ( * i ) . first , " @ " ) ;
if ( tempList [ ( * i ) . first ] = = 0 )
domains [ parts [ 1 ] ] . push_back ( parts [ 0 ] ) ;
// it does not allow LST_AL and LST_BL, as the server will refuse with a 241 error
int privacyListMask = MSN : : LST_AL | MSN : : LST_BL ;
if ( ( ( * i ) . second & privacyListMask ) = = privacyListMask )
tempList [ ( * i ) . first ] = ( * i ) . second & ~ MSN : : LST_AL ;
else
tempList [ ( * i ) . first ] = ( * i ) . second ;
}
// deleting buddy information
std : : map < std : : string , MSN : : Buddy * > : : iterator d = listInfo - > contactList . begin ( ) ;
for ( d ; d ! = listInfo - > contactList . end ( ) ; d + + )
{
delete ( * d ) . second ;
}
// adding domains and users to xml:
// The max payload of ADL command is about 7500 bytes.
// so the code below should do that.
// not using xmlParser due to the complex algorithm
// TODO - What to do when there are no contacts?
std : : map < std : : string , std : : vector < std : : string > > : : iterator cur = domains . begin ( ) ;
tempADL = " " ;
// for each domain
for ( ; cur ! = domains . end ( ) ; cur + + )
{
do
{
tempADL + = " <d n= \" " + ( * cur ) . first + " \" > " ;
// for each user
while ( domains [ ( * cur ) . first ] . size ( ) ! = 0 )
{
std : : string a ( ( * cur ) . second [ 0 ] + " @ " + ( * cur ) . first ) ;
tempADL + = " <c n= \" " + ( * cur ) . second [ 0 ] + " \" l= \" " + toStr ( tempList [ a ] ) + " \" t= \" 1 \" /> " ;
( * cur ) . second . erase ( ( * cur ) . second . begin ( ) ) ;
if ( tempADL . length ( ) > 7400 )
break ;
}
tempADL + = " </d> " ;
if ( tempADL . length ( ) > 7400 )
{
adl_packets . push_back ( " <ml l= \" 1 \" > " + tempADL + " </ml> " ) ;
tempADL = " " ;
}
} while ( domains [ ( * cur ) . first ] . size ( ) ! = 0 ) ;
}
adl_packets . push_back ( " <ml l= \" 1 \" > " + tempADL + " </ml> " ) ;
// send the first one
std : : string adl_payload = adl_packets . front ( ) ;
adl_packets . pop_front ( ) ;
std : : ostringstream buf_ ;
buf_ < < " ADL " < < this - > trID + + < < " " < < adl_payload . length ( ) < < " \r \n " ;
buf_ < < adl_payload ;
if ( write ( buf_ ) ! = buf_ . str ( ) . size ( ) )
return ;
}
void NotificationServerConnection : : sendPing ( )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
std : : string a ( " PNG \r \n " ) ;
write ( a ) ;
}
void NotificationServerConnection : : requestSwitchboardConnection ( const void * tag )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
SwitchboardServerConnection : : AuthData * auth = new SwitchboardServerConnection : : AuthData ( this - > auth . username , tag ) ;
std : : ostringstream buf_ ;
buf_ < < " XFR " < < this - > trID < < " SB \r \n " ;
if ( write ( buf_ ) ! = buf_ . str ( ) . size ( ) )
return ;
this - > addCallback ( & NotificationServerConnection : : callback_TransferToSwitchboard , this - > trID + + , ( void * ) auth ) ;
}
template < class _Tp >
class _sameUserName
{
Buddy buddy ;
public :
_sameUserName ( const _Tp & __u ) : buddy ( __u ) { } ;
bool operator ( ) ( const _Tp & __x ) { return __x . userName = = buddy . userName ; }
} ;
void NotificationServerConnection : : socketConnectionCompleted ( )
{
this - > assertConnectionStateIs ( NS_CONNECTING ) ;
this - > setConnectionState ( NS_CONNECTED ) ;
Connection : : socketConnectionCompleted ( ) ;
// If an error occurs in Connection::socketConnectionCompleted, we
// will be disconnected before we get here.
if ( this - > connectionState ( ) ! = NS_DISCONNECTED )
{
this - > myNotificationServer ( ) - > externalCallbacks . unregisterSocket ( this - > sock ) ;
this - > myNotificationServer ( ) - > externalCallbacks . registerSocket ( this - > sock , 1 , 0 , false ) ;
}
}
void NotificationServerConnection : : connect ( const std : : string & hostname , unsigned int port )
{
this - > assertConnectionStateIs ( NS_DISCONNECTED ) ;
connectinfo * info = new connectinfo ( this - > auth . username , this - > auth . password ) ;
this - > info = info ;
if ( ( this - > sock = this - > myNotificationServer ( ) - > externalCallbacks . connectToServer ( hostname , port , & this - > connected ) ) = = NULL )
{
this - > myNotificationServer ( ) - > externalCallbacks . showError ( this , " Could not connect to MSN server " ) ;
this - > myNotificationServer ( ) - > externalCallbacks . closingConnection ( this ) ;
return ;
}
this - > setConnectionState ( NS_CONNECTING ) ;
this - > myNotificationServer ( ) - > externalCallbacks . registerSocket ( this - > sock , 0 , 1 , false ) ;
if ( this - > connected )
this - > socketConnectionCompleted ( ) ;
std : : ostringstream buf_ ;
buf_ < < " VER " < < this - > trID < < " MSNP15 CVR0 \r \n " ;
if ( this - > write ( buf_ ) ! = buf_ . str ( ) . size ( ) )
return ;
this - > addCallback ( & NotificationServerConnection : : callback_NegotiateCVR , this - > trID + + , ( void * ) info ) ;
}
void NotificationServerConnection : : connect ( const std : : string & hostname , unsigned int port , const Passport & username , const std : : string & password )
{
this - > auth . username = username ;
this - > auth . password = password ;
this - > connect ( hostname , port ) ;
}
void NotificationServerConnection : : disconnect ( )
{
if ( this - > connectionState ( ) = = NS_DISCONNECTED )
return ;
std : : vector < SwitchboardServerConnection * > list = _switchboardConnections ;
std : : vector < SwitchboardServerConnection * > : : iterator i = list . begin ( ) ;
for ( ; i ! = list . end ( ) ; + + i )
{
delete * i ;
}
std : : vector < Soap * > list2 = _SoapConnections ;
std : : vector < Soap * > : : iterator d = list2 . begin ( ) ;
for ( ; d ! = list2 . end ( ) ; + + d )
{
delete * d ;
}
this - > callbacks . clear ( ) ;
this - > sitesToAuthList . erase ( sitesToAuthList . begin ( ) , sitesToAuthList . end ( ) ) ;
SentQueuedOIMs . erase ( SentQueuedOIMs . begin ( ) , SentQueuedOIMs . end ( ) ) ;
this - > setConnectionState ( NS_DISCONNECTED ) ;
this - > myNotificationServer ( ) - > externalCallbacks . closingConnection ( this ) ;
Connection : : disconnect ( ) ;
}
void NotificationServerConnection : : disconnectForTransfer ( )
{
this - > assertConnectionStateIsNot ( NS_DISCONNECTED ) ;
this - > myNotificationServer ( ) - > externalCallbacks . unregisterSocket ( this - > sock ) ;
this - > myNotificationServer ( ) - > externalCallbacks . closeSocket ( this - > sock ) ;
this - > setConnectionState ( NS_DISCONNECTED ) ;
}
void NotificationServerConnection : : handleIncomingData ( )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
while ( this - > isWholeLineAvailable ( ) )
{
std : : vector < std : : string > args = this - > getLine ( ) ;
if ( ! args . size ( ) ) continue ;
if ( args [ 0 ] = = " MSG " | | args [ 0 ] = = " NOT " | |
args [ 0 ] = = " IPG " | | args [ 0 ] = = " GCF " | |
args [ 0 ] = = " UBX " | | args [ 0 ] = = " ADL " | |
args [ 0 ] = = " RML " )
{
int dataLength ;
if ( args [ 0 ] = = " MSG " | | args [ 0 ] = = " UBX " )
dataLength = decimalFromString ( args [ 3 ] ) ;
else if ( args [ 0 ] = = " GCF " | | args [ 0 ] = = " ADL " | | args [ 0 ] = = " RML " )
dataLength = decimalFromString ( args [ 2 ] ) ;
else
dataLength = decimalFromString ( args [ 1 ] ) ;
if ( this - > readBuffer . find ( " \r \n " ) + 2 + dataLength > this - > readBuffer . size ( ) )
return ;
}
this - > readBuffer = this - > readBuffer . substr ( this - > readBuffer . find ( " \r \n " ) + 2 ) ;
int trid = 0 ;
if ( args . size ( ) > = 6 & & args [ 0 ] = = " XFR " & & args [ 2 ] = = " NS " )
{
// XFR TrID NS NotificationServerIP:Port 0 ThisServerIP:Port
// 0 1 2 3 4 5
this - > callbacks . clear ( ) ; // delete the callback data
this - > disconnectForTransfer ( ) ;
std : : pair < std : : string , int > server_address = splitServerAddress ( args [ 3 ] ) ;
this - > connect ( server_address . first , server_address . second ) ;
return ;
}
if ( args . size ( ) > = 7 & & args [ 0 ] = = " RNG " )
{
// RNG SessionID SwitchboardServerIP:Port CKI AuthString InvitingUser InvitingDisplayName
// 0 1 2 3 4 5 6
this - > handle_RNG ( args ) ;
return ;
}
if ( args . size ( ) > = 2 & & args [ 0 ] = = " QNG " )
{
// QNG seconds
// 0 1
// ping response, ignore
return ;
}
if ( ( args . size ( ) > = 3 & & args [ 0 ] = = " LST " ) | |
( args . size ( ) > = 2 & & ( args [ 0 ] = = " GTC " ) ) | |
( args . size ( ) > = 3 & & ( args [ 0 ] = = " BPR " | | args [ 0 ] = = " LSG " ) )
)
{
// LST N=UserName F=FriendlyName C=GUID param groupID
// 0 1 2 3 4 5
//
// or
// (GTC|BLP) [TrID] [ListVersion] Setting
// 0 1 2 4
if ( this - > synctrid )
{
trid = this - > synctrid ;
}
else
{
trid = decimalFromString ( args [ 1 ] ) ;
}
}
else if ( args . size ( ) > 1 )
{
try
{
trid = decimalFromString ( args [ 1 ] ) ;
}
catch ( . . . )
{
}
}
if ( ! this - > callbacks . empty ( ) & & trid > = 0 )
{
if ( this - > callbacks . find ( trid ) ! = this - > callbacks . end ( ) )
{
( this - > * ( this - > callbacks [ trid ] . first ) ) ( args , trid , this - > callbacks [ trid ] . second ) ;
continue ;
}
}
if ( isdigit ( args [ 0 ] [ 0 ] ) )
this - > showError ( decimalFromString ( args [ 0 ] ) ) ;
else
this - > dispatchCommand ( args ) ;
}
}
void NotificationServerConnection : : callback_NegotiateCVR ( std : : vector < std : : string > & args , int trid , void * data )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
connectinfo * info = ( connectinfo * ) data ;
this - > removeCallback ( trid ) ;
if ( args . size ( ) > = 3 & & args [ 0 ] ! = " VER " | | args [ 2 ] ! = " MSNP15 " ) // if either *differs*...
{
this - > myNotificationServer ( ) - > externalCallbacks . showError ( NULL , " Protocol negotiation failed " ) ;
this - > disconnect ( ) ;
return ;
}
std : : ostringstream buf_ ;
buf_ < < " CVR " < < this - > trID < < " 0x0409 winnt 5.1 i386 MSG80BETA 8.1.0178.00 MSMSGS " < < info - > username < < " \r \n " ;
if ( this - > write ( buf_ ) ! = buf_ . str ( ) . size ( ) )
return ;
this - > addCallback ( & NotificationServerConnection : : callback_RequestUSR , this - > trID + + , ( void * ) data ) ;
}
void NotificationServerConnection : : callback_TransferToSwitchboard ( std : : vector < std : : string > & args , int trid , void * data )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
SwitchboardServerConnection : : AuthData * auth = static_cast < SwitchboardServerConnection : : AuthData * > ( data ) ;
this - > removeCallback ( trid ) ;
if ( args [ 0 ] ! = " XFR " )
{
this - > showError ( decimalFromString ( args [ 0 ] ) ) ;
this - > disconnect ( ) ;
delete auth ;
return ;
}
auth - > cookie = args [ 5 ] ;
auth - > sessionID = " " ;
SwitchboardServerConnection * newconn = new SwitchboardServerConnection ( * auth , * this ) ;
this - > addSwitchboardConnection ( newconn ) ;
std : : pair < std : : string , int > server_address = splitServerAddress ( args [ 3 ] ) ;
newconn - > connect ( server_address . first , server_address . second ) ;
delete auth ;
}
void NotificationServerConnection : : callback_RequestUSR ( std : : vector < std : : string > & args , int trid , void * data )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
connectinfo * info = ( connectinfo * ) data ;
this - > removeCallback ( trid ) ;
if ( args . size ( ) > 1 & & args [ 0 ] ! = " CVR " ) // if*differs*...
{
this - > myNotificationServer ( ) - > externalCallbacks . showError ( NULL , " Protocol negotiation failed " ) ;
this - > disconnect ( ) ;
return ;
}
std : : ostringstream buf_ ;
buf_ < < " USR " < < this - > trID < < " SSO I " < < info - > username < < " \r \n " ;
if ( this - > write ( buf_ ) ! = buf_ . str ( ) . size ( ) )
return ;
this - > addCallback ( & NotificationServerConnection : : callback_PassportAuthentication , this - > trID + + , ( void * ) data ) ;
}
void NotificationServerConnection : : callback_PassportAuthentication ( std : : vector < std : : string > & args , int trid , void * data )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
connectinfo * info ;
info = ( connectinfo * ) data ;
this - > removeCallback ( trid ) ;
if ( isdigit ( args [ 0 ] [ 0 ] ) )
{
this - > showError ( decimalFromString ( args [ 0 ] ) ) ;
this - > disconnect ( ) ;
return ;
}
if ( args . size ( ) > = 4 & & args [ 4 ] . empty ( ) ) {
this - > disconnect ( ) ;
return ;
}
this - > myNotificationServer ( ) - > externalCallbacks . getSecureHTTPProxy ( ) ;
Soap * soapConnection = new Soap ( * this ) ;
this - > mdi = args [ 5 ] ;
soapConnection - > setMBI ( args [ 4 ] ) ;
soapConnection - > getTickets ( info - > username , info - > password , args [ 4 ] ) ;
delete info ;
info = NULL ;
}
void NotificationServerConnection : : gotTickets ( Soap & soapConnection , std : : vector < MSN : : Soap : : sitesToAuth > sitesToAuthList )
{
std : : ostringstream buf_ ;
this - > sitesToAuthList = sitesToAuthList ;
std : : string token = sitesToAuthList [ 1 ] . BinarySecurityToken ;
std : : string binarysecret = sitesToAuthList [ 1 ] . BinarySecret ;
this - > token = token ;
buf_ < < " USR " < < this - > trID < < " SSO S " < < token < < " " < < mdi_encrypt ( binarysecret , mdi ) < < " \r \n " ;
if ( this - > write ( buf_ ) ! = buf_ . str ( ) . size ( ) )
return ;
this - > addCallback ( & NotificationServerConnection : : callback_AuthenticationComplete , this - > trID + + , NULL ) ;
}
void NotificationServerConnection : : callback_AuthenticationComplete ( std : : vector < std : : string > & args , int trid , void * data )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
this - > removeCallback ( trid ) ;
if ( isdigit ( args [ 0 ] [ 0 ] ) )
{
this - > showError ( decimalFromString ( args [ 0 ] ) ) ;
this - > disconnect ( ) ;
return ;
}
server_email_verified = args [ 4 ] ;
}
void NotificationServerConnection : : get_oim ( std : : string id , bool markAsRead )
{
Soap * soapConnection = new Soap ( * this , this - > sitesToAuthList ) ;
soapConnection - > getOIM ( id , markAsRead ) ;
}
void NotificationServerConnection : : delete_oim ( std : : string id )
{
if ( this - > removingOIM )
{
DeletedQueuedOIMs . push_back ( id ) ;
return ;
}
this - > removingOIM = true ;
Soap * soapConnection = new Soap ( * this , this - > sitesToAuthList ) ;
soapConnection - > deleteOIM ( id ) ;
}
void NotificationServerConnection : : send_oim ( Soap : : OIM oim )
{
// do not generate two lockkeys at the same time
if ( this - > generatingLockkey )
{
SentQueuedOIMs . push_back ( oim ) ;
return ;
}
Soap * soapConnection = new Soap ( * this , this - > sitesToAuthList ) ;
SentQueuedOIMs . push_back ( oim ) ;
this - > generatingLockkey = true ;
soapConnection - > generateLockkey ( oim ) ;
}
void NotificationServerConnection : : gotOIM ( Soap & soapConnection , bool success , std : : string id , std : : string message )
{
this - > myNotificationServer ( ) - > externalCallbacks . gotOIM ( this , success , id , message ) ;
}
void NotificationServerConnection : : gotOIMLockkey ( Soap & soapConnection , std : : string lockkey )
{
this - > lockkey = lockkey ;
this - > generatingLockkey = false ;
if ( this - > lockkey . empty ( ) )
{
std : : vector < Soap : : OIM > : : iterator i = SentQueuedOIMs . begin ( ) ;
for ( ; i ! = SentQueuedOIMs . end ( ) ; i + + )
{
this - > myNotificationServer ( ) - > externalCallbacks . gotOIMSendConfirmation ( this , false , ( * i ) . id ) ;
}
SentQueuedOIMs . erase ( SentQueuedOIMs . begin ( ) , SentQueuedOIMs . end ( ) ) ;
return ;
}
sendQueuedOIMs ( ) ;
}
void NotificationServerConnection : : gotOIMDeleteConfirmation ( Soap & soapConnection , std : : string id , bool deleted )
{
this - > myNotificationServer ( ) - > externalCallbacks . gotOIMDeleteConfirmation ( this , deleted , id ) ;
if ( this - > DeletedQueuedOIMs . empty ( ) )
{
removingOIM = false ;
return ;
}
else
{
Soap * soapConnection = new Soap ( * this , this - > sitesToAuthList ) ;
soapConnection - > deleteOIM ( DeletedQueuedOIMs . back ( ) ) ;
DeletedQueuedOIMs . pop_back ( ) ;
}
}
void NotificationServerConnection : : gotOIMSendConfirmation ( Soap & soapConnection , int id , bool sent )
{
if ( ! sent )
this - > lockkey . clear ( ) ;
this - > myNotificationServer ( ) - > externalCallbacks . gotOIMSendConfirmation ( this , sent , id ) ;
}
void NotificationServerConnection : : sendQueuedOIMs ( )
{
std : : vector < Soap : : OIM > : : iterator i = SentQueuedOIMs . begin ( ) ;
for ( ; i ! = SentQueuedOIMs . end ( ) ; i + + )
{
Soap * soapConnection = new Soap ( * this , this - > sitesToAuthList ) ;
soapConnection - > sendOIM ( ( * i ) , this - > lockkey ) ;
}
SentQueuedOIMs . erase ( SentQueuedOIMs . begin ( ) , SentQueuedOIMs . end ( ) ) ;
}
bool NotificationServerConnection : : change_DisplayPicture ( std : : string filename )
{
msnobj . delMSNObjectByType ( 3 ) ;
if ( ! filename . empty ( ) )
msnobj . addMSNObject ( filename , 3 ) ;
return true ;
}
void NotificationServerConnection : : gotChangeDisplayNameConfirmation ( Soap & soapConnection , std : : string displayName , bool changed )
{
if ( changed )
{
this - > myDisplayName = displayName ;
// server update OK, now change to the current session
std : : ostringstream buf_ ;
buf_ < < " PRP " < < this - > trID + + < < " MFN " < < encodeURL ( displayName ) < < " \r \n " ;
write ( buf_ ) ;
}
// TODO - raise an error if not changed
}
void NotificationServerConnection : : gotAddContactToGroupConfirmation ( Soap & soapConnection , bool added , std : : string newVersion , std : : string groupId , std : : string contactId )
{
this - > myNotificationServer ( ) - > externalCallbacks . addedContactToGroup ( this , added , groupId , contactId ) ;
}
void NotificationServerConnection : : gotDelContactFromGroupConfirmation ( Soap & soapConnection , bool removed , std : : string newVersion , std : : string groupId , std : : string contactId )
{
this - > myNotificationServer ( ) - > externalCallbacks . removedContactFromGroup ( this , removed , groupId , contactId ) ;
}
void NotificationServerConnection : : gotAddGroupConfirmation ( Soap & soapConnection , bool added , std : : string newVersion , std : : string groupName , std : : string groupId )
{
this - > myNotificationServer ( ) - > externalCallbacks . addedGroup ( this , added , groupName , groupId ) ;
}
void NotificationServerConnection : : gotDelGroupConfirmation ( Soap & soapConnection , bool removed , std : : string newVersion , std : : string groupId )
{
this - > myNotificationServer ( ) - > externalCallbacks . removedGroup ( this , removed , groupId ) ;
}
void NotificationServerConnection : : gotRenameGroupConfirmation ( Soap & soapConnection , bool renamed , std : : string newVersion , std : : string newGroupName , std : : string groupId )
{
this - > myNotificationServer ( ) - > externalCallbacks . renamedGroup ( this , renamed , newGroupName , groupId ) ;
}
void NotificationServerConnection : : gotAddContactToAddressBookConfirmation ( Soap & soapConnection , bool added , std : : string newVersion , std : : string passport , std : : string displayName , std : : string guid )
{
this - > myNotificationServer ( ) - > externalCallbacks . addedContactToAddressBook ( this , added , passport , displayName , guid ) ;
if ( added )
{
std : : vector < std : : string > passport2 = splitString ( passport , " @ " ) ;
std : : string user = passport2 [ 0 ] ;
std : : string domain = passport2 [ 1 ] ;
// TODO - use xmlParser
std : : string payload3 ( " <ml><d n= \" " + domain + " \" ><c n= \" " + user + " \" l= \" 2 \" t= \" 1 \" /></d></ml> " ) ;
std : : ostringstream buf_3 ;
buf_3 < < " ADL " < < this - > trID + + < < " " < < payload3 . length ( ) < < " \r \n " ;
buf_3 < < payload3 ;
write ( buf_3 ) ;
std : : string payload2 ( " <ml><d n= \" " + domain + " \" ><c n= \" " + user + " \" l= \" 1 \" t= \" 1 \" /></d></ml> " ) ;
std : : ostringstream buf_2 ;
buf_2 < < " ADL " < < this - > trID + + < < " " < < payload2 . length ( ) < < " \r \n " ;
buf_2 < < payload2 ;
write ( buf_2 ) ;
// the official client sends FQY
std : : string payload4 ( " <ml l= \" 2 \" ><d n= \" " + domain + " \" ><c n= \" " + user + " \" /></d></ml> " ) ;
std : : ostringstream buf_4 ;
buf_4 < < " FQY " < < this - > trID + + < < " " < < payload4 . length ( ) < < " \r \n " ;
buf_4 < < payload4 ;
write ( buf_4 ) ;
}
}
void NotificationServerConnection : : gotDelContactFromAddressBookConfirmation ( Soap & soapConnection , bool removed , std : : string newVersion , std : : string contactId , std : : string passport )
{
this - > myNotificationServer ( ) - > externalCallbacks . removedContactFromAddressBook ( this , removed , contactId , passport ) ;
if ( removed )
{
std : : vector < std : : string > passport2 = splitString ( passport , " @ " ) ;
std : : string user = passport2 [ 0 ] ;
std : : string domain = passport2 [ 1 ] ;
// TODO - use xmlParser
std : : string payload2 ( " <ml><d n= \" " + domain + " \" ><c n= \" " + user + " \" l= \" 1 \" t= \" 1 \" /></d></ml> " ) ;
std : : ostringstream buf_2 ;
buf_2 < < " RML " < < this - > trID + + < < " " < < payload2 . length ( ) < < " \r \n " ;
buf_2 < < payload2 ;
write ( buf_2 ) ;
}
}
void NotificationServerConnection : : gotEnableContactOnAddressBookConfirmation ( Soap & soapConnection , bool disabled , std : : string newVersion , std : : string contactId , std : : string passport )
{
this - > myNotificationServer ( ) - > externalCallbacks . enabledContactOnAddressBook ( this , disabled , contactId , passport ) ;
if ( disabled )
{
std : : vector < std : : string > passport2 = splitString ( passport , " @ " ) ;
std : : string user = passport2 [ 0 ] ;
std : : string domain = passport2 [ 1 ] ;
// TODO - use xmlParser
std : : string payload3 ( " <ml><d n= \" " + domain + " \" ><c n= \" " + user + " \" l= \" 1 \" t= \" 1 \" /></d></ml> " ) ;
std : : ostringstream buf_3 ;
buf_3 < < " ADL " < < this - > trID + + < < " " < < payload3 . length ( ) < < " \r \n " ;
buf_3 < < payload3 ;
write ( buf_3 ) ;
}
}
void NotificationServerConnection : : gotDisableContactOnAddressBookConfirmation ( Soap & soapConnection , bool disabled , std : : string newVersion , std : : string contactId , std : : string passport )
{
this - > myNotificationServer ( ) - > externalCallbacks . disabledContactOnAddressBook ( this , disabled , contactId ) ;
if ( disabled )
{
std : : vector < std : : string > passport2 = splitString ( passport , " @ " ) ;
std : : string user = passport2 [ 0 ] ;
std : : string domain = passport2 [ 1 ] ;
// TODO - use xmlParser
std : : string payload2 ( " <ml><d n= \" " + domain + " \" ><c n= \" " + user + " \" l= \" 1 \" t= \" 1 \" /></d></ml> " ) ;
std : : ostringstream buf_2 ;
buf_2 < < " RML " < < this - > trID + + < < " " < < payload2 . length ( ) < < " \r \n " ;
buf_2 < < payload2 ;
write ( buf_2 ) ;
}
}
void NotificationServerConnection : : gotAddContactToListConfirmation ( Soap & soapConnection , bool added , std : : string newVersion , std : : string passport , MSN : : ContactList list )
{
if ( added )
{
std : : vector < std : : string > passport2 = splitString ( passport , " @ " ) ;
std : : string user = passport2 [ 0 ] ;
std : : string domain = passport2 [ 1 ] ;
// TODO - use xmlParser
std : : string payload2 ( " <ml><d n= \" " + domain + " \" ><c n= \" " + user + " \" l= \" " + toStr ( list ) + " \" t= \" 1 \" /></d></ml> " ) ;
std : : ostringstream buf_2 ;
buf_2 < < " ADL " < < this - > trID + + < < " " < < payload2 . length ( ) < < " \r \n " ;
buf_2 < < payload2 ;
write ( buf_2 ) ;
this - > myNotificationServer ( ) - > externalCallbacks . addedListEntry ( this , list , passport , " " ) ;
}
}
void NotificationServerConnection : : gotDelContactFromListConfirmation ( Soap & soapConnection , bool deleted , std : : string newVersion , std : : string passport , MSN : : ContactList list )
{
if ( deleted )
{
std : : vector < std : : string > passport2 = splitString ( passport , " @ " ) ;
std : : string user = passport2 [ 0 ] ;
std : : string domain = passport2 [ 1 ] ;
// TODO - use XMLParser
std : : string payload ( " <ml><d n= \" " + domain + " \" ><c n= \" " + user + " \" l= \" " + toStr ( list ) + " \" t= \" 1 \" /></d></ml> " ) ;
std : : ostringstream buf_ ;
buf_ < < " RML " < < this - > trID + + < < " " < < payload . length ( ) < < " \r \n " ;
buf_ < < payload ;
write ( buf_ ) ;
this - > myNotificationServer ( ) - > externalCallbacks . removedListEntry ( this , list , passport ) ;
}
}
void NotificationServerConnection : : setCapabilities ( uint m_clientId )
{
this - > m_clientId = m_clientId ;
}
void NotificationServerConnection : : getInboxUrl ( )
{
this - > assertConnectionStateIsAtLeast ( NS_CONNECTED ) ;
std : : ostringstream buf_ ;
buf_ < < " URL " < < this - > trID < < " INBOX \r \n " ;
write ( buf_ ) ;
this - > addCallback ( & NotificationServerConnection : : callback_URL , this - > trID + + , NULL ) ;
}
}