⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chatsession.cpp

📁 著名的下载软件核心Shareaza
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//
// ChatSession.cpp
//
// Copyright (c) Shareaza Development Team, 2002-2004.
// This file is part of SHAREAZA (www.shareaza.com)
//
// Shareaza 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.
//
// Shareaza 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 Shareaza; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//

#include "StdAfx.h"
#include "Shareaza.h"
#include "Settings.h"
#include "ChatCore.h"
#include "ChatSession.h"
#include "GProfile.h"
#include "G2Packet.h"
#include "Network.h"
#include "Buffer.h"
#include "XML.h"

#include "ChatWindows.h"
#include "CtrlChatFrame.h"
#include "CtrlPrivateChatFrame.h"
// #include "CtrlPublicChatFrame.h"

typedef unsigned int UINT_PTR;
#include <mmsystem.h>

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif


//////////////////////////////////////////////////////////////////////
// CChatSession construction

CChatSession::CChatSession(CChatFrame* pFrame)
{
	m_bGUID		= FALSE;
	
	m_nState	= cssNull;
	m_bG2		= FALSE;
	m_bOld		= FALSE;
	m_bMustPush	= FALSE;
	m_tPushed	= 0;
	m_pProfile	= NULL;
	
	m_pWndPrivate	= NULL;
	m_pWndPublic	= NULL;
	
	if ( pFrame != NULL )
	{
		m_pWndPrivate = ( pFrame->IsKindOf( RUNTIME_CLASS(CPrivateChatFrame) ) )
			? reinterpret_cast<CPrivateChatFrame*>(pFrame) : NULL;
//		m_pWndPublic = ( pFrame->IsKindOf( RUNTIME_CLASS(CPublicChatFrame) ) )
//			? reinterpret_cast<CPublicChatFrame*>(pFrame) : NULL;
	}
	
	ChatCore.Add( this );
}

CChatSession::~CChatSession()
{
	ASSERT( m_hSocket == INVALID_SOCKET );
	
	if ( m_pProfile != NULL ) delete m_pProfile;
	
	ChatCore.Remove( this );
}

//////////////////////////////////////////////////////////////////////
// CChatSession setup

void CChatSession::Setup(GGUID* pGUID, SOCKADDR_IN* pHost, BOOL bMustPush)
{
	CSingleLock pLock( &ChatCore.m_pSection, TRUE );
	
	if ( pGUID != NULL )
	{
		m_bGUID = TRUE;
		m_pGUID = *pGUID;
	}
	
	m_pHost		= *pHost;
	m_bMustPush	= bMustPush;
	
	m_sUserNick = inet_ntoa( m_pHost.sin_addr );
}

//////////////////////////////////////////////////////////////////////
// CChatSession connect

BOOL CChatSession::Connect()
{
	CSingleLock pLock( &ChatCore.m_pSection, TRUE );
	
	if ( m_nState > cssNull ) return FALSE;
	
	if ( m_bMustPush )
	{
		if ( ! SendPush( FALSE ) )
		{
			StatusMessage( 1, IDS_CHAT_CANT_PUSH, (LPCTSTR)CString( inet_ntoa( m_pHost.sin_addr ) ) );
			return FALSE;
		}
	}
	else
	{
		if ( CConnection::ConnectTo( &m_pHost ) )
		{
			ChatCore.Add( this );
			StatusMessage( 0, IDS_CHAT_CONNECTING_TO, (LPCTSTR)m_sAddress );
		}
		else
		{
			StatusMessage( 1, IDS_CHAT_CANT_CONNECT, (LPCTSTR)m_sAddress );
			return FALSE;
		}
	}
	
	m_nState = cssConnecting;
	
	return TRUE;
}

TRISTATE CChatSession::GetConnectedState() const
{
	if ( m_nState == cssNull ) return TS_FALSE;
	if ( m_nState == cssActive ) return TS_TRUE;
	return TS_UNKNOWN;
}

//////////////////////////////////////////////////////////////////////
// CChatSession attach to (accept) an incoming connection

void CChatSession::AttachTo(CConnection* pConnection)
{
	CConnection::AttachTo( pConnection );
	
	m_nState = cssRequest1;
	ChatCore.Add( this );
}

//////////////////////////////////////////////////////////////////////
// CChatSession push functionality

BOOL CChatSession::SendPush(BOOL bAutomatic)
{
	if ( ! m_bGUID ) return FALSE;
	
	if ( Network.SendPush( &m_pGUID, 0 ) )
	{
		m_nState = cssNull;
		CConnection::Close();
		
		m_tConnected = m_tPushed = GetTickCount();
		StatusMessage( 0, IDS_CHAT_PUSH_SENT, (LPCTSTR)CString( inet_ntoa( m_pHost.sin_addr ) ) );
		
		return TRUE;
	}
	else
	{
		return FALSE;
	}
}

BOOL CChatSession::OnPush(GGUID* pGUID, CConnection* pConnection)
{
	if ( m_tPushed == 0 ) return FALSE;
	if ( ! m_bGUID || m_pGUID != *pGUID ) return FALSE;
	if ( m_nState > cssConnecting ) return FALSE;
	
	if ( m_nState > cssNull ) Close();
	
	CConnection::AttachTo( pConnection );
	
	StatusMessage( 0, IDS_CHAT_PUSH_DONE, (LPCTSTR)m_sAddress );
	ChatCore.Add( this );
	OnConnected();
	
	return TRUE;
}

//////////////////////////////////////////////////////////////////////
// CChatSession close

void CChatSession::Close()
{
	CSingleLock pLock( &ChatCore.m_pSection );
	pLock.Lock( 250 );
	
	if ( m_nState != cssNull )
	{
		m_nState = cssNull;
		StatusMessage( 0, IDS_CHAT_CLOSED );
		StatusMessage( 0, 0 );
	}
	
	CConnection::Close();
	
	if ( m_pWndPrivate == NULL && m_pWndPublic == NULL ) delete this;
}

//////////////////////////////////////////////////////////////////////
// CChatSession connection handler

BOOL CChatSession::OnConnected()
{
	CConnection::OnConnected();
	
	StatusMessage( 0, IDS_CHAT_CONNECTED );
	
	m_pOutput->Print( "CHAT CONNECT/0.2\r\n" );
	m_pOutput->Print( "Accept: text/plain,application/x-gnutella2\r\n" );
	m_pOutput->Print( "User-Agent: " );
	m_pOutput->Print( Settings.SmartAgent( Settings.General.UserAgent ) );
	m_pOutput->Print( "\r\n" );
	if ( m_bInitiated ) SendMyAddress();
	m_pOutput->Print( "\r\n" );
	
	m_nState		= cssRequest2;
	m_tConnected	= GetTickCount();
	
	OnWrite();
	
	return TRUE;
}

//////////////////////////////////////////////////////////////////////
// CChatSession disconnection handler

void CChatSession::OnDropped(BOOL bError)
{
	if ( m_hSocket == INVALID_SOCKET ) return;
	
	if ( m_nState == cssConnecting )
	{
		StatusMessage( 1, IDS_CHAT_CANT_CONNECT, (LPCTSTR)m_sAddress );
		if ( m_tPushed == 0 && SendPush( TRUE ) ) return;
	}
	else
	{
		StatusMessage( 1, IDS_CHAT_DROPPED, (LPCTSTR)m_sAddress );
	}
	
	Close();
}

//////////////////////////////////////////////////////////////////////
// CChatSession run handler

BOOL CChatSession::OnRun()
{
	if ( m_nState > cssNull && m_nState < cssActive )
	{
		DWORD nDelay = GetTickCount() - m_tConnected;
		
		if ( nDelay >= ( m_nState == cssConnecting ?
			Settings.Connection.TimeoutConnect : Settings.Connection.TimeoutHandshake ) )
		{
			theApp.Message( MSG_ERROR, IDS_HANDSHAKE_TIMEOUT, (LPCTSTR)m_sAddress );
			Close();
			return FALSE;
		}
	}
	
	return TRUE;
}

//////////////////////////////////////////////////////////////////////
// CChatSession read handler

BOOL CChatSession::OnRead()
{
	CConnection::OnRead();
	
	switch ( m_nState )
	{
	case cssRequest1:
	case cssRequest2:
	case cssRequest3:
		return ReadHandshake();
	case cssHeaders1:
	case cssHeaders2:
	case cssHeaders3:
		return ReadHeaders();
	case cssHandshake:
	case cssActive:
		if ( m_bG2 )
			return ReadPackets();
		else
			return ReadText();
	}
	
	return TRUE;
}

//////////////////////////////////////////////////////////////////////
// CChatSession handshake processer

BOOL CChatSession::ReadHandshake()
{
	CString strLine;
	
	if ( ! m_pInput->ReadLine( strLine ) ) return TRUE;
	if ( strLine.IsEmpty() ) return TRUE;
	
	theApp.Message( MSG_DEBUG, _T("CHAT HANDSHAKE: %s: %s"),
		(LPCTSTR)m_sAddress, (LPCTSTR)strLine );
	
	m_bOld = strLine.Find( _T("/0.1") ) > 0;
	
	if ( StartsWith( strLine, _T("CHAT CONNECT/") ) && m_nState == cssRequest1 )
	{
		m_nState = cssHeaders1;
		return TRUE;
	}
	else if ( StartsWith( strLine, _T("CHAT/") ) )
	{
		if ( _tcsistr( strLine, _T("200 OK") ) )
		{
			if ( m_nState == cssRequest2 )
			{
				m_nState = cssHeaders2;
				return TRUE;
			}
			else if ( m_nState == cssRequest3 )
			{
				m_nState = cssHeaders3;
				return TRUE;
			}
		}
		else
		{
			// Rejected
		}
	}
	
	StatusMessage( 1, IDS_CHAT_PRIVATE_REFUSED, (LPCTSTR)m_sAddress );
	Close();
	
	return FALSE;
}

//////////////////////////////////////////////////////////////////////
// CChatSession header processer

BOOL CChatSession::OnHeaderLine(CString& strHeader, CString& strValue)
{
	theApp.Message( MSG_DEBUG, _T("CHAT HEADER: %s: %s: %s"),
		(LPCTSTR)m_sAddress, (LPCTSTR)strHeader, (LPCTSTR)strValue );
	
	if ( strHeader.CompareNoCase( _T("User-Agent") ) == 0 )
	{
		m_sUserAgent = strValue;
	}
	else if ( strHeader.CompareNoCase( _T("Accept") ) == 0 )
	{
		m_bG2 |= ( strValue.Find( _T("application/x-gnutella2") ) >= 0 );
	}
	else if ( strHeader.CompareNoCase( _T("X-Nickname") ) == 0 )
	{
		m_sUserNick = strValue;
	}
	else if (	strHeader.CompareNoCase( _T("X-My-Address") ) == 0 ||
				strHeader.CompareNoCase( _T("Listen-IP") ) == 0 ||
				strHeader.CompareNoCase( _T("Node") ) == 0 )
	{
		int nColon = strValue.Find( ':' );
		
		if ( ! m_bInitiated && nColon > 0 )
		{
			int nPort = GNUTELLA_DEFAULT_PORT;
			
			if ( _stscanf( strValue.Mid( nColon + 1 ), _T("%lu"), &nPort ) == 1 && nPort != 0 )
			{
				m_pHost.sin_port = htons( nPort );
			}
		}
	}
	
	return TRUE;
}

BOOL CChatSession::OnHeadersComplete()
{
	if ( m_nState != cssHeaders3 )
	{
		m_pOutput->Print( "CHAT/0.2 200 OK\r\n" );
		
		if ( m_bG2 )
		{
			m_pOutput->Print( "Accept: application/x-gnutella2\r\n" );
			m_pOutput->Print( "Content-Type: application/x-gnutella2\r\n" );
		}
		else if ( MyProfile.IsValid() )
		{
			m_pOutput->Print( "X-Nickname: " );
			m_pOutput->Print( MyProfile.GetNick() );
			m_pOutput->Print( "\r\n" );
		}
		
		m_pOutput->Print( "User-Agent: " );
		m_pOutput->Print( Settings.SmartAgent( Settings.General.UserAgent ) );
		m_pOutput->Print( "\r\n" );
		m_pOutput->Print( "\r\n" );
		
		OnWrite();
	}
	
	if ( m_nState == cssHeaders1 )
	{
		// Sent second handshake
		m_nState = cssRequest3;
		return TRUE;
	}
	else if ( m_nState == cssHeaders2 )
	{
		// Sent third handshake
		m_nState = cssHandshake;
		return OnEstablished();
	}
	else if ( m_nState == cssHeaders3 )
	{
		// Connected
		m_nState = cssHandshake;
		return OnEstablished();
	}
	
	ASSERT( FALSE );
	return FALSE;
}

//////////////////////////////////////////////////////////////////////
// CChatSession startup

BOOL CChatSession::OnEstablished()
{
	m_tConnected = GetTickCount();
	
	if ( m_bG2 )
	{
		StatusMessage( 0, IDS_CHAT_HANDSHAKE_G2 );
		Send( CG2Packet::New( G2_PACKET_PROFILE_CHALLENGE ) );
	}
	else
	{
		m_nState = cssActive;
		StatusMessage( 2, IDS_CHAT_HANDSHAKE_G1, m_bOld ? _T("0.1") : _T("0.2") );
		if ( m_pWndPrivate != NULL ) m_pWndPrivate->OnProfileReceived();
		StatusMessage( 0, 0 );
		PostOpenWindow();
	}
	
	return TRUE;
}

//////////////////////////////////////////////////////////////////////
// CChatSession text interface

void CChatSession::Print(LPCTSTR pszString)
{
	ASSERT( ! m_bG2 );
	ASSERT( m_nState >= cssHandshake );
	
	m_pOutput->Print( pszString );
	OnWrite();
}

BOOL CChatSession::ReadText()
{
	CString strLine;
	
	while ( m_pInput->ReadLine( strLine ) )

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -