Find a reprinted copy of the MSN P2P protocol. Save it. There is another URL that is invalid.
/*
Msnp2p. cpp-MSN P2P protocol
Copyright (c) 2003 by Olivier goffart <ogoffart@tiscalinet.be>
**************************************** *********************************
**
* This program is free software; you can redistribute it and/or modify *
* It under the terms of the GNU General Public License as published *
* The Free Software Foundation; either version 2 of the license, or *
* (At your option) any later version .*
**
**************************************** *********************************
*/
# Include "msnp2p. H"
# Include <stdlib. h>
// QT
# Include <qregexp. h>
# Include <qfile. h>
// KDE
# Include <kdebug. h>
# Include <kmdcodec. h>
# Include <ktempfile. h>
# Include <krun. h>
# Include <klocale. h>
# Include <kglobal. h>
# Include <kdeversion. h>
# Include <kstandarddirs. h>
Msnp2p: msnp2p (qobject * parent, const char * name)
: Qobject (parent, name)
{
M_file = 0l;
M_sfile = 0l;
M_msgidentifier = 0;
M_sessionid = 0;
M_totaldatasize = 0;
M_offset = 0;
}
Msnp2p ::~ Msnp2p ()
{
Delete m_file;
Delete m_sfile;
}
Void msnp2p: slotreadmessage (const qbytearray & MSG)
{
Qstring messageheader = qcstring (msg. Data (), (msg. Find ('\ 0') =-1 )? MSG. Size (): MSG. Find ('\ 0 '));
Qregexp rx ("Content-Type: [A-Za-z0-9 $! */\-] *) ");
Rx. Search (messageheader );
Qstring type = Rx. CAP (1 );
If (type = "application/x-msnmsgrp2p ")
{< br> // get the starting position of the 48-bytes bunary header
unsigned int startbinheader = 0;
bool justcr = false;
while (startbinheader {< br> If (MSG. data () [startbinheader] = '\ R')
startbinheader ++;
If (MSG. data () [startbinheader] = '\ n')
{< br> If (justcr) break;
else justcr = true;
}< br> else justcr = false;
startbinheader ++;
}< br> startbinheader ++;
If (! Justcr | startbinheader + 48> MSG. Size () return; // No binary header, or not long enough, todo: Error Handling
// read some interesting field from the binary header
unsigned int datamessagesize = (INT) (unsigned char) (MSG. data () [startbinheader + 24]) + (INT) (unsigned char) MSG. data () [startbinheader + 25]) * 256;
unsigned int totalsize = (INT) (unsigned char) (MSG. data () [startbinheader + 16]) + (INT) (unsigned char) MSG. data () [startbinheader + 17]) * 256 + (INT) (unsigned char) MSG. data () [startbinheader + 18]) * 256*256 + (INT) (unsigned char) MSG. data () [startbinheader + 19]) * 256*256*256;
unsigned int dataoffset = (INT) (unsigned char) (MSG. data () [startbinheader + 8]) + (INT) (unsigned char) MSG. data () [startbinheader + 9]) * 256 + (INT) (unsigned char) MSG. data () [startbinheader + 10]) * 256*256 + (INT) (unsigned char) MSG. data () [startbinheader + 11]) * 256*256*256;
If (datamessagesize = 0)
{
Kddebug (14140) <"msnp2p: slotreadmessage: I do not care, it's a ack-flag =" <(INT) (unsigned char) (MSG. data () [startbinheader + 28]) <Endl;
Return;
}
If (msg. Size () <startbinheader + 48 + datamessagesize)
{
// The message's size is shorter than the announced size
// Todo error handling
Return;
}
Qstring datamessage = qcstring (msg. Data () + startbinheader + 48), datamessagesize );
If (m_msghandle.isempty ())
{// If these addresses were not previusly set, get it, They shoshould be provided in the first message at last.
Qregexp rx ("to: <msnmsgr :( [^>] *)> ");
If (RX. Search (datamessage )! =-1)
M_myhandle = Rx. CAP (1 );
RX = qregexp ("from: <msnmsgr :( [^>] *)> ");
If (RX. Search (datamessage )! =-1)
M_msghandle = Rx. CAP (1 );
}
// Send the ACK if needed
If (dataoffset + datamessagesize> = totalsize)
Sendp2pack (msg. Data () + startbinheader ));
If (m_file) // we are already downloading something to this file
{
M_file-> file ()-> writeblock (msg. Data () + startbinheader + 48), datamessagesize );
If (dataoffset + datamessagesize> = totalsize) // The file is complete
{
M_file-> close ();
/* // Todo: show the file in a better way
# If kde_is_version (3,1, 90)
Krun: runurl (m_file-> name (), "image/PNG", true );
# Else
Krun: runurl (m_file-> name (), "image/PNG ");
# Endif
Delete m_file ;*/
Emit filereceived (m_file, m_obj );
M_file = 0;
// send the bye message
qcstring datamessage = qstring (
"Bye msnmsgr: "+ m_msghandle +" msnslp/1.0 \ r \ n "
" to: \ r \ n "
" from: \ r \ n "
" via: msnslp/1.0/TLP; branch = {A0D624A6-6C0C-4283-A9E0-BC97B4B46D32} \ r \ n "
" CSeq: 0 \ r \ n "
" Call-ID: {"+ m_calrent.upper () + "} \ r \ n"
"Max-forwards: 0 \ r \ n"
"Content-Type: application/X-msnmsgr-sessionclosebody \ r \ n "
" Content-Length: 3 \ r \ n "). utf8 ();
sendp2pmessage (datamessage);
// deletelater ();
}< BR >}< br> else
{< br> kddebug (14141) <"msnp2p: slotreadmessage: datamessage: "
If (msg. Data () [startbinheader + 48] = '\ 0 ')
{// This can be only the data preparaion message. Prepare to download
M_file = new ktempfile (locatelocal ("tmp", "msnpicture-"), ". PNG ");
M_file-> setautodelete (true );
}
Else if (datamessage. Contains ("invite "))
{
// Parse the message to get some info for replying with the 200 OK message
Qregexp rx ("; branch =\{ ([0-9a-f \-] *) \\}\ r \ n ");
Rx. Search (datamessage );
Qstring branch = Rx. CAP (1 );
RX = qregexp ("Call-ID :\{ ([0-9a-f \-] *) \\}\ r \ n ");
Rx. Search (datamessage );
Qstring callid = Rx. CAP (1 );
RX = qregexp ("sessionid: ([0-9] *) \ r \ n ");
Rx. Search (datamessage );
Unsigned long int sessid = Rx. CAP (1). touint ();
RX = qregexp ("appid: ([0-9] *) \ r \ n ");
Rx. Search (datamessage );
Unsigned long int appid = Rx. CAP (1). touint ();
If (appid = 1) // ask for a MSN picture, or emoticon, currently, we always send the display picture
{
Qstring content = "sessionid:" + qstring: Number (sessid );
Qcstring datamessage = qstring (
"Msnslp/1.0 200 OK \ r \ n"
"To: <msnmsgr:" + m_msghandle + "> \ r \ n"
"From: <msnmsgr:" + m_myhandle + "> \ r \ n"
"Via: msnslp/1.0/TLP; branch = {" + branch + "} \ r \ n"
"CSeq: 1 \ r \ n"
"Call-ID: {" + callid + "} \ r \ n"
"Max-forwards: 0 \ r \ n"
"Content-Type: Application/X-msnmsgr-sessionreqbody \ r \ n"
"Content-Length:" + qstring: Number (content. Length () + 5) + "\ r \ n"
"\ R \ n" + content + "\ r \ n"). utf8 (); // \ 0
Sendp2pmessage (datamessage );
// Send the data preparation message
M_sessionid = sessid;
Qbytearray initm (4 );
Initm. Fill ('\ 0 ');
Sendp2pmessage (initm );
// Prepare to send the file
M_sfile = new qfile (locatelocal ("appdata", "msnpicture-" + m_myhandle.lower (). Replace (qregexp ("[./~] "),"-") +". PNG "));
If (! M_sfile-> open (io_readonly) {/* error? */}
M_totaldatasize = m_sfile-> size ();
Qtimer: singleshot (10, this, slot (slotsenddata (); // go for upload
}
Else
{
Qcstring datamessage = qstring (
"Msnslp/1.0 500 internal error \ r \ n"
"To: <msnmsgr:" + m_msghandle + "> \ r \ n"
"From: <msnmsgr:" + m_myhandle + "> \ r \ n"
"Via: msnslp/1.0/TLP; branch = {" + branch + "} \ r \ n"
"CSeq: 1 \ r \ n"
"Call-ID: {" + callid + "} \ r \ n"
"Max-forwards: 0 \ r \ n"
"Content-Type: NULL \ r \ n"
"Content-Length: 0 \ r \ n"). utf8 (); // \ 0
Sendp2pmessage (datamessage );
}
}
Else if (datamessage. Contains ("bye "))
{
// Deletelater ();
}
}
}
Else
{
// Kddebug (14140) <"msnswitchboardsocket: slotreadmessage: unknown type '" <type <Endl;
}
}
Void msnp2p: requestdisplaypicture (const qstring & myhandle, const qstring & msghandle, qstring msnobject)
{
// Reset some field
/* M_file = 0l;
M_sfile = 0l;
M_msgidentifier = 0;
M_sessionid = 0;
M_totaldatasize = 0;
M_offset = 0 ;*/
M_sessionid = 0;
M_myhandle = myhandle;
M_msghandle = msghandle;
M_obj = msnobject;
Msnobject = qstring: fromutf8 (kcodecs: base64encode (msnobject. utf8 ()));
Msnobject. Replace ("=", qstring: NULL );
Unsigned long int sessid = rand () % 0xffffff00 + 4;
Qstring branch = qstring: Number (unsigned long INT) rand () % 0 xaaff + 0x1111, 16) + qstring: Number (unsigned long INT) rand () % 0 xaaff + 0x1111, 16) + "-" + qstring: Number (unsigned long INT) rand () % 0 xaaff + 0x1111, 16) + "-" + qstring: Number (unsigned long INT) rand () % 0 xaaff + 0x1111, 16) + "-" + qstring :: number (RAND () % 0 xaaff + 0x1111, 16) + "-" + qstring: Number (unsigned long INT) rand () % 0 xaaff + 0x1111, 16) + qstring: Number (unsigned long INT) rand () % 0 xaaff + 0x1111, 16) + qstring :: number (unsigned long INT) rand () % 0 xaaff + 0x1111, 16 );
M_callid = qstring: Number (unsigned long INT) rand () % 0 xaaff + 0x1111, 16) + qstring: Number (unsigned long INT) rand () % 0 xaaff + 0x1111, 16) + "-" + qstring: Number (unsigned long INT) rand () % 0 xaaff + 0x1111, 16) + "-" + qstring: Number (unsigned long INT) rand () % 0 xaaff + 0x1111, 16) + "-" + qstring :: number (RAND () % 0 xaaff + 0x1111, 16) + "-" + qstring: Number (unsigned long INT) rand () % 0 xaaff + 0x1111, 16) + qstring: Number (unsigned long INT) rand () % 0 xaaff + 0x1111, 16) + qstring :: number (unsigned long INT) rand () % 0 xaaff + 0x1111, 16 );;
Qstring content = "EUF-GUID: {A4268EEC-FEC5-49E5-95C3-F126696BDBF6} \ r \ n"
"Sessionid:" + qstring: Number (sessid) + "\ r \ n"
"Appid: 1 \ r \ n"
"Context:" + msnobject;
Qcstring datamessage = qstring (
"Invite msnmsgr:" + msghandle + "msnslp/1.0 \ r \ n"
"To: <msnmsgr:" + msghandle + "> \ r \ n"
"From: <msnmsgr:" + myhandle + "> \ r \ n"
"Via: msnslp/1.0/TLP; branch = {" + branch. Upper () + "} \ r \ n"
"CSeq: 0 \ r \ n"
"Call-ID: {" + m_cal0000.upper () + "} \ r \ n"
"Max-forwards: 0 \ r \ n"
"Content-Type: Application/X-msnmsgr-sessionreqbody \ r \ n"
"Content-Length:" + qstring: Number (content. Length () + 5) + "\ r \ n"
"\ R \ n" + content + "\ r \ n"). utf8 (); // \ 0
Sendp2pmessage (datamessage );
}
Void msnp2p: sendp2pmessage (const qbytearray & datamessage)
{
If (m_sessionid = 0)
Kddebugging (14141) <k_funcinfo <qcstring (datamessage. Data (), datamessage. Size () <Endl;
Qcstring messageheader = qstring (
"Mime-version: 1.0 \ r \ n"
"Content-Type: Application/x-msnmsgrp2p \ r \ n"
P2P-Dest: "+ m_msghandle +" \ r \ n "). utf8 ();
Qbytearray binheader (48 );
Binheader. Fill ('\ 0'); // fill with 0 for starting
If (m_msgidentifier = 0)
M_msgidentifier = rand () % 0x0ffffff0 + 4;
Else if (m_offset = 0)
M_msgidentifier ++;
// Sessionid
Binheader [0] = (char) (m_sessionid % 256 );
Binheader [1] = (char) (unsigned long INT) (m_sessionid/256) % 256 );
Binheader [2] = (char) (unsigned long INT) (m_sessionid/(256*256) % 256 );
Binheader [3] = (char) (unsigned long INT) (m_sessionid/(256*256*256) % 256 );
// Messageid
Binheader [4] = (char) (m_msgidentifier % 256 );
Binheader [5] = (char) (unsigned long INT) (m_msgidentifier/256) % 256 );
Binheader [6] = (char) (unsigned long INT) (m_msgidentifier/(256*256) % 256 );
Binheader [7] = (char) (unsigned long INT) (m_msgidentifier/(256*256*256) % 256 );
// Offset
Binheader [8] = (char) (m_offset % 256 );
Binheader [9] = (char) (unsigned long INT) (m_offset/256) % 256 );
Binheader [10] = (char) (unsigned long INT) (m_offset/(256*256) % 256 );
Binheader [11] = (char) (unsigned long INT) (m_offset/(256*256*256) % 256 );
Unsigned int size = datamessage. Size ();
If (m_totaldatasize) // It's a splitted message
{
Binheader [16] = (char) (m_totaldatasize % 256 );
Binheader [17] = (char) (unsigned long INT) (m_totaldatasize/256) % 256 );
Binheader [18] = (char) (unsigned long INT) (m_totaldatasize/(256*256) % 256 );
Binheader [19] = (char) (unsigned long INT) (m_totaldatasize/(256*256*256) % 256 );
// Update offset
M_offset + = size;
If (m_offset> = m_totaldatasize)
{// Message completely sent, reset values
M_offset = 0;
M_totaldatasize = 0;
}
}
Else // not a splitted message, the total size is the current size
{
Binheader [16] = (char) Size: % 256;
Binheader [17] = (INT) size/256;
}
// Message Size
Binheader [24] = (char) size = 256;
Binheader [25] = (INT) size/256;
// Ack sessionid
/* Binheader [32] = (char) (RAND () % 256 );
Binheader [33] = (char) (RAND () % 256 );
Binheader [34] = (char) (RAND () % 256 );
Binheader [35] = (char) (RAND () % 256 );*/
Binheader [32] = 0xde;
Binheader [33] = 0xc7;
Binheader [34] = 0x07;
Binheader [35] = 0x14;
// Merge all in a unique message
Qbytearray data (messageheader. Length () + binheader. Size () + datamessage. Size () + 4 );
For (unsigned int f = 0; F <messageheader. Length (); F ++)
Data [f] = messageheader [f];
For (unsigned int f = 0; F <binheader. Size (); F ++)
Data [messageheader. Length () + F] = binheader [f];
For (unsigned int f = 0; F <datamessage. Size (); F ++)
Data [messageheader. Length () + binheader. Size () + F] = datamessage [f];
For (unsigned int f = 0; F <4; F ++) // footer
Data [messageheader. Length () + binheader. Size () + datamessage. Size () + F] = '\ 0 ';
If (m_sessionid! = 0)
{// Then, the footer ends with \ 1
Data [messageheader. Length () + binheader. Size () + datamessage. Size () + 3] = '\ 1 ';
}
// Send the message
Emit sendcommand ("MSG", "D", true, Data, true );
}
Void msnp2p: sendp2pack (const char * originalheader)
{
Qcstring messageheader = qstring (
"Mime-version: 1.0 \ r \ n"
"Content-Type: Application/x-msnmsgrp2p \ r \ n"
P2P-Dest: "+ m_msghandle +" \ r \ n "). utf8 ();
Qbytearray binheader (48 );
Binheader. Fill ('\ 0'); // fill with 0 for starting
// Sessionid
Binheader [0] = originalheader [0];
Binheader [1] = originalheader [1];
Binheader [2] = originalheader [2];
Binheader [3] = originalheader [3];
// Messageid
Bool a = false;
If (m_msgidentifier = 0)
{
M_msgidentifier = rand () % 0xfffffe00 + 10;
A = true;
}
Else
M_msgidentifier ++;
Binheader [4] = (char) (m_msgidentifier % 256 );
Binheader [5] = (char) (unsigned long INT) (m_msgidentifier/256) % 256 );
Binheader [6] = (char) (unsigned long INT) (m_msgidentifier/(256*256) % 256 );
Binheader [7] = (char) (unsigned long INT) (m_msgidentifier/(256*256*256) % 256 );
If ()
M_msgidentifier-= 4;
// Total size
Binheader [16] = originalheader [16];
Binheader [17] = originalheader [17];
Binheader [18] = originalheader [18];
Binheader [19] = originalheader [19];
Binheader [20] = originalheader [20];
Binheader [21] = originalheader [21];
Binheader [22] = originalheader [22];
Binheader [23] = originalheader [23];
// Flag
Binheader [28] = (char) 0x02;
// Ack sessionid
Binheader [32] = originalheader [4];
Binheader [33] = originalheader [5];
Binheader [34] = originalheader [6];
Binheader [35] = originalheader [7];
// Ack unique ID
Binheader [36] = originalheader [32];
Binheader [37] = originalheader [33];
Binheader [38] = originalheader [34];
Binheader [39] = originalheader [35];
// Ack data size
Binheader [40] = originalheader [16];
Binheader [41] = originalheader [17];
Binheader [42] = originalheader [18];
Binheader [43] = originalheader [19];
Binheader [44] = originalheader [20];
Binheader [45] = originalheader [21];
Binheader [46] = originalheader [22];
Binheader [47] = originalheader [23];
Qbytearray data (messageheader. Length () + binheader. Size () + 4 );
For (unsigned int f = 0; F <messageheader. Length (); F ++)
Data [f] = messageheader [f];
For (unsigned int f = 0; F <binheader. Size (); F ++) // If binheader is a qcstring, it ends with \ 0, which is OK
Data [messageheader. Length () + F] = binheader [f];
For (unsigned int f = 0; F <4; F ++)
Data [messageheader. Length () + binheader. Size () + F] = '\ 0 ';
Emit sendcommand ("MSG", "D", true, Data, true );
}
Void msnp2p: slotsenddata ()
{
If (! M_sfile)
Return;
Char data [1200];
Int bytesread = m_sfile-& gt; readblock (data, 1200 );
Qbytearray databa (bytesread );
For (INT f = 0; F <bytesread; F ++)
Databa [f] = data [f];
// Kddebug (14140) <"msnp2p: slotsenddata: offset = "<m_offset <" size = "<bytesread <" totalsize = "<m_totaldatasize <" sent = "<m_offset + bytesread <Endl;
Sendp2pmessage (databa );
If (m_totaldatasize = 0) // This has been reseted bacause the file is completely send
{
// Kddebug (14140) <"msnp2p: slotsenddata: Finished! Wait for the bye message "<Endl;
Delete m_sfile;
M_sfile = 0l;
M_sessionid = 0;
}
Else
Qtimer: singleshot (10, this, slot (slotsenddata ()));
}
# Include "msnp2p. MOC"