diff options
Diffstat (limited to 'miranda-wine/protocols/MSN/msn_ws.cpp')
-rw-r--r-- | miranda-wine/protocols/MSN/msn_ws.cpp | 324 |
1 files changed, 324 insertions, 0 deletions
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;
+}
|