From cb4a46e7fbe62d788e66ed6121c717a2d22a4d7c Mon Sep 17 00:00:00 2001 From: watcherhd Date: Thu, 21 Apr 2011 14:14:52 +0000 Subject: svn.miranda.im is moving to a new home! git-svn-id: http://miranda-plugins.googlecode.com/svn/trunk@7 e753b5eb-9565-29b2-b5c5-2cc6f99dfbcb --- miranda-wine/protocols/MSN/msn_ws.cpp | 324 ++++++++++++++++++++++++++++++++++ 1 file changed, 324 insertions(+) create mode 100644 miranda-wine/protocols/MSN/msn_ws.cpp (limited to 'miranda-wine/protocols/MSN/msn_ws.cpp') diff --git a/miranda-wine/protocols/MSN/msn_ws.cpp b/miranda-wine/protocols/MSN/msn_ws.cpp new file mode 100644 index 0000000..274b4be --- /dev/null +++ b/miranda-wine/protocols/MSN/msn_ws.cpp @@ -0,0 +1,324 @@ +/* +Plugin of Miranda IM for communicating with users of the MSN Messenger protocol. +Copyright (c) 2003-5 George Hazan. +Copyright (c) 2002-3 Richard Hughes (original version). + +Miranda IM: the free icq client for MS Windows +Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede + +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. +*/ + +#include "msn_global.h" + +static char sttGatewayHeader[] = + "POST %s HTTP/1.1\r\n" + "Accept: */*\r\n" + "Content-Type: text/xml; charset=utf-8\r\n" + "Content-Length: %d\r\n" + "User-Agent: %s\r\n" + "Host: %s\r\n" + "Connection: Keep-Alive\r\n" + "Cache-Control: no-cache\r\n\r\n"; + +//======================================================================================= + +int ThreadData::send( char* data, int datalen ) +{ + if ( this == NULL ) + return 0; + + NETLIBBUFFER nlb = { data, datalen, 0 }; + + mWaitPeriod = 60; + + if ( MyOptions.UseGateway && !( mType == SERVER_FILETRANS && mP2pSession != NULL )) { + mGatewayTimeout = 2; + + if ( !MyOptions.UseProxy ) { + TQueueItem* tNewItem = ( TQueueItem* )malloc( datalen + sizeof( void* ) + sizeof( int ) + 1 ); + tNewItem->datalen = datalen; + memcpy( tNewItem->data, data, datalen ); + tNewItem->data[datalen] = 0; + + TQueueItem* p = mFirstQueueItem; + if ( p != NULL ) { + while ( p->next != NULL ) + p = p->next; + + p ->next = tNewItem; + } + else mFirstQueueItem = tNewItem; + + tNewItem->next = NULL; + return TRUE; + } + + MSN_CallService( MS_NETLIB_SETPOLLINGTIMEOUT, WPARAM( s ), mGatewayTimeout ); + } + + int rlen = MSN_CallService( MS_NETLIB_SEND, ( WPARAM )s, ( LPARAM )&nlb ); + if ( rlen == SOCKET_ERROR ) { + // should really also check if sendlen is the same as datalen + MSN_DebugLog( "Send failed: %d", WSAGetLastError() ); + return FALSE; + } + + return TRUE; +} + +//======================================================================================= +// Receving data +//======================================================================================= + +int ThreadData::recv_dg( char* data, long datalen ) +{ + if ( mReadAheadBuffer != NULL ) { + int tBytesToCopy = ( datalen >= mEhoughData ) ? mEhoughData : datalen; + memcpy( data, mReadAheadBuffer, tBytesToCopy ); + mEhoughData -= tBytesToCopy; + if ( mEhoughData == 0 ) { + free( mReadAheadBuffer ); + mReadAheadBuffer = NULL; + } + else memmove( mReadAheadBuffer, mReadAheadBuffer + tBytesToCopy, mEhoughData ); + + return tBytesToCopy; + } + + bool bCanPeekMsg = true; + +LBL_RecvAgain: + int ret = 0; + { + NETLIBSELECT tSelect = {0}; + tSelect.cbSize = sizeof( tSelect ); + tSelect.dwTimeout = 1000; + tSelect.hReadConns[ 0 ] = ( HANDLE )s; + + for ( int i=0; i < mGatewayTimeout || !bCanPeekMsg; i++ ) { + if ( bCanPeekMsg ) { + TQueueItem* QI = mFirstQueueItem; + if ( QI != NULL ) + { + char szHttpPostUrl[300]; + getGatewayUrl( szHttpPostUrl, sizeof( szHttpPostUrl ), QI->datalen == 0 ); + + char* tBuffer = ( char* )alloca( QI->datalen+400 ); + int cbBytes = mir_snprintf( tBuffer, QI->datalen+400, sttGatewayHeader, + szHttpPostUrl, QI->datalen, MSN_USER_AGENT, mGatewayIP); + memcpy( tBuffer+cbBytes, QI->data, QI->datalen ); + cbBytes += QI->datalen; + tBuffer[ cbBytes ] = 0; + + NETLIBBUFFER nlb = { tBuffer, cbBytes, 0 }; + ret = MSN_CallService( MS_NETLIB_SEND, ( WPARAM )s, ( LPARAM )&nlb ); + if ( ret == SOCKET_ERROR ) { + MSN_DebugLog( "Send failed: %d", WSAGetLastError() ); + return 0; + } + + mFirstQueueItem = QI->next; + free( QI ); + + ret = 1; + break; + } } + + ret = MSN_CallService( MS_NETLIB_SELECT, 0, ( LPARAM )&tSelect ); + if ( ret != 0 ) + break; + // Timeout switchboard session if inactive + if ( !mIsMainThread && mJoinedCount <= 1 && --mWaitPeriod <= 0 ) + { + if (mJoinedCount == 0 || p2p_getFirstSession(mJoinedContacts[0]) == NULL) + { + MSN_DebugLog( "Dropping the idle switchboard due to the 60 sec timeout" ); + return 0; + } + else + mWaitPeriod = 60; + } + } + } + + bCanPeekMsg = false; + + if ( ret == 0 ) { + mGatewayTimeout += 2; + if ( mGatewayTimeout > 8 ) + mGatewayTimeout = 8; + + char szHttpPostUrl[300]; + getGatewayUrl( szHttpPostUrl, sizeof( szHttpPostUrl ), true ); + + char szCommand[ 400 ]; + int cbBytes = mir_snprintf( szCommand, sizeof( szCommand ), + sttGatewayHeader, szHttpPostUrl, 0, MSN_USER_AGENT, mGatewayIP); + + NETLIBBUFFER nlb = { szCommand, cbBytes, 0 }; + MSN_CallService( MS_NETLIB_SEND, ( WPARAM )s, ( LPARAM )&nlb ); + goto LBL_RecvAgain; + } + + NETLIBBUFFER nlb = { data, datalen, 0 }; + ret = MSN_CallService( MS_NETLIB_RECV, ( WPARAM )s, ( LPARAM )&nlb ); + if ( ret == 0 ) { + MSN_DebugLog( "Connection closed gracefully"); + return 0; + } + + if ( ret < 0 ) { + MSN_DebugLog( "Connection abortively closed, error %d", WSAGetLastError() ); + return ret; + } + + bCanPeekMsg = true; + + char* p = strstr( data, "\r\n" ); + if ( p == NULL ) { + MSN_DebugLog( "ACHTUNG! it's not a valid header: '%s'", data ); + goto LBL_RecvAgain; + } + + int status = 0; + sscanf( data, "HTTP/1.1 %d", &status ); + if ( status == 100 ) + goto LBL_RecvAgain; + + int tContentLength = 0, hdrLen; + { + MimeHeaders tHeaders; + const char* rest = tHeaders.readFromBuffer( p+2 ); + if ( *rest == '\r' ) + rest += 2; + + for ( int i=0; i < tHeaders.mCount; i++ ) + { + MimeHeader& H = tHeaders.mVals[i]; + + if ( stricmp( H.name, "X-MSN-Messenger" ) == 0 ) { + if ( strstr( H.value, "Session=close" ) != 0 ) { + return 0; + } + + processSessionData( H.value ); + } + + if ( stricmp( H.name, "Content-Length" ) == 0 ) + tContentLength = atol( H.value ); + } + + hdrLen = int( rest - data ); + } + + if ( tContentLength == 0 ) + goto LBL_RecvAgain; + else + { + mGatewayTimeout = 1; + mWaitPeriod = 60; + } + + ret -= hdrLen; + if ( ret <= 0 ) { + nlb.buf = data; + nlb.len = datalen; + ret = MSN_CallService( MS_NETLIB_RECV, ( WPARAM )s, ( LPARAM )&nlb ); + if ( ret <= 0 ) + return ret; + } + else memmove( data, data+hdrLen, ret ); + + if ( tContentLength > ret ) { + tContentLength -= ret; + + mReadAheadBuffer = ( char* )calloc( tContentLength+1, 1 ); + mReadAheadBuffer[ tContentLength ] = 0; + mEhoughData = tContentLength; + nlb.buf = mReadAheadBuffer; + + while ( tContentLength > 0 ) { + nlb.len = tContentLength; + int ret2 = MSN_CallService( MS_NETLIB_RECV, ( WPARAM )s, ( LPARAM )&nlb ); + if ( ret2 <= 0 ) + { free( mReadAheadBuffer ); + mReadAheadBuffer = NULL; + return ret2; + } + + tContentLength -= ret2; + nlb.buf += ret2; + } } + + return ret; +} + +int ThreadData::recv( char* data, long datalen ) +{ + if ( MyOptions.UseGateway && !MyOptions.UseProxy ) + if ( mType != SERVER_FILETRANS || mP2pSession == 0 ) + return recv_dg( data, datalen ); + + NETLIBBUFFER nlb = { data, datalen, 0 }; + +LBL_RecvAgain: + if ( !mIsMainThread && !MyOptions.UseGateway && !MyOptions.UseProxy ) { + mWaitPeriod = 60; + while ( --mWaitPeriod >= 0 ) { + NETLIBSELECT nls = { 0 }; + nls.cbSize = sizeof( nls ); + nls.dwTimeout = 1000; + nls.hReadConns[0] = s; + if ( MSN_CallService( MS_NETLIB_SELECT, 0, ( LPARAM )&nls ) != 0 ) + break; + } + + if ( mWaitPeriod < 0 && mJoinedCount <= 1 ) { + if (mJoinedCount == 0 || p2p_getFirstSession(mJoinedContacts[0]) == NULL) { + MSN_DebugLog( "Dropping the idle switchboard due to the 60 sec timeout" ); + return 0; + } + else mWaitPeriod = 60; + } } + + int ret = MSN_CallService( MS_NETLIB_RECV, ( WPARAM )s, ( LPARAM )&nlb ); + if ( ret == 0 ) { + MSN_DebugLog( "Connection closed gracefully" ); + return 0; + } + + if ( ret < 0 ) { + MSN_DebugLog( "Connection abortively closed, error %d", WSAGetLastError() ); + return ret; + } + + if ( MyOptions.UseGateway) + { + if ( ret == 1 && *data == 0 ) + { + int tOldTimeout = MSN_CallService( MS_NETLIB_SETPOLLINGTIMEOUT, WPARAM( s ), 2 ); + tOldTimeout += 2; + if ( tOldTimeout > 8 ) + tOldTimeout = 8; + + MSN_CallService( MS_NETLIB_SETPOLLINGTIMEOUT, WPARAM( s ), tOldTimeout ); + goto LBL_RecvAgain; + } + else MSN_CallService( MS_NETLIB_SETPOLLINGTIMEOUT, WPARAM( s ), 1 ); + } + + return ret; +} -- cgit v1.2.3