📄 querysearch.cpp
字号:
//
// QuerySearch.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 "QuerySearch.h"
#include "Network.h"
#include "Datagrams.h"
#include "G1Packet.h"
#include "G2Packet.h"
#include "EDPacket.h"
#include "Schema.h"
#include "SchemaCache.h"
#include "QueryHashTable.h"
#include "GGEP.h"
#include "XML.h"
#include "SHA.h"
#include "MD5.h"
#include "ED2K.h"
#include "TigerTree.h"
#include "WndSearch.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// CQuerySearch construction
CQuerySearch::CQuerySearch(BOOL bGUID)
{
if ( bGUID ) Network.CreateID( &m_pGUID );
m_pSchema = NULL;
m_pXML = NULL;
m_nMinSize = 0x0000000000000000;
m_nMaxSize = 0xFFFFFFFFFFFFFFFF;
m_bSHA1 = FALSE;
m_bTiger = FALSE;
m_bED2K = FALSE;
m_bBTH = FALSE;
m_bWantURL = TRUE;
m_bWantDN = TRUE;
m_bWantXML = TRUE;
m_bWantCOM = TRUE;
m_bWantPFS = TRUE;
m_bAndG1 = Settings.Gnutella1.EnableToday;
m_bUDP = FALSE;
m_nKey = 0;
m_bFirewall = FALSE;
m_nWords = 0;
m_pWordPtr = NULL;
m_pWordLen = NULL;
}
CQuerySearch::CQuerySearch(CQuerySearch* pCopy)
{
m_pGUID = pCopy->m_pGUID;
m_sSearch = pCopy->m_sSearch;
m_pSchema = pCopy->m_pSchema;
m_pXML = pCopy->m_pXML ? pCopy->m_pXML->Clone() : NULL;
m_nMinSize = pCopy->m_nMinSize;
m_nMaxSize = pCopy->m_nMaxSize;
m_bSHA1 = pCopy->m_bSHA1;
if ( m_bSHA1 ) m_pSHA1 = pCopy->m_pSHA1;
m_bTiger = pCopy->m_bTiger;
if ( m_bTiger ) m_pTiger = pCopy->m_pTiger;
m_bED2K = pCopy->m_bED2K;
if ( m_bED2K ) m_pED2K = pCopy->m_pED2K;
m_bBTH = pCopy->m_bBTH;
if ( m_bBTH ) m_pBTH = pCopy->m_pBTH;
m_bWantURL = pCopy->m_bWantURL;
m_bWantDN = pCopy->m_bWantDN;
m_bWantXML = pCopy->m_bWantXML;
m_bWantCOM = pCopy->m_bWantCOM;
m_bWantPFS = pCopy->m_bWantPFS;
m_bAndG1 = pCopy->m_bAndG1;
m_bUDP = pCopy->m_bUDP;
m_nKey = pCopy->m_nKey;
if ( m_bUDP ) m_pEndpoint = pCopy->m_pEndpoint;
m_nWords = 0;
m_pWordPtr = NULL;
m_pWordLen = NULL;
}
CQuerySearch::~CQuerySearch()
{
if ( m_pXML ) delete m_pXML;
if ( m_pWordPtr ) delete [] m_pWordPtr;
if ( m_pWordLen ) delete [] m_pWordLen;
}
//////////////////////////////////////////////////////////////////////
// CQuerySearch to G1 packet
CG1Packet* CQuerySearch::ToG1Packet()
{
CG1Packet* pPacket = CG1Packet::New( G1_PACKET_QUERY,
min( Settings.Gnutella1.SearchTTL, 4 ), &m_pGUID );
WORD nFlags = G1_QF_TAG | G1_QF_BIN_HASH | G1_QF_DYNAMIC;
if ( ! Network.IsListening() ) nFlags |= G1_QF_FIREWALLED;
if ( m_bWantXML ) nFlags |= G1_QF_XML;
pPacket->WriteShortLE( nFlags );
CString strExtra;
if ( m_sSearch.GetLength() )
{
pPacket->WriteString( m_sSearch );
}
else if ( m_pSchema != NULL && m_pXML != NULL )
{
strExtra = m_pSchema->GetIndexedWords( m_pXML->GetFirstElement() );
pPacket->WriteString( strExtra );
strExtra.Empty();
}
else
{
pPacket->WriteByte( 0 );
}
if ( m_bSHA1 )
{
strExtra = CSHA::HashToString( &m_pSHA1, TRUE );
}
else if ( m_bTiger )
{
strExtra = CTigerNode::HashToString( &m_pTiger, TRUE );
}
else if ( m_bED2K )
{
strExtra = CED2K::HashToString( &m_pED2K, TRUE );
}
else
{
strExtra = _T("urn:");
}
if ( m_pXML )
{
if ( strExtra.GetLength() ) strExtra += '\x1C';
strExtra += m_pXML->ToString( TRUE );
}
pPacket->WriteString( strExtra );
return pPacket;
}
//////////////////////////////////////////////////////////////////////
// CQuerySearch to G2 packet
CG2Packet* CQuerySearch::ToG2Packet(SOCKADDR_IN* pUDP, DWORD nKey)
{
CG2Packet* pPacket = CG2Packet::New( G2_PACKET_QUERY, TRUE );
if ( pUDP )
{
pPacket->WritePacket( "UDP", nKey ? 10 : 6 );
pPacket->WriteLongLE( pUDP->sin_addr.S_un.S_addr );
pPacket->WriteShortBE( htons( pUDP->sin_port ) );
if ( nKey ) pPacket->WriteLongBE( nKey );
}
if ( m_bTiger && m_bSHA1 )
{
pPacket->WritePacket( "URN", sizeof(SHA1) + sizeof(TIGEROOT) + 3 );
pPacket->WriteString( "bp" );
pPacket->Write( &m_pSHA1, sizeof(SHA1) );
pPacket->Write( &m_pTiger, sizeof(TIGEROOT) );
}
else if ( m_bSHA1 )
{
pPacket->WritePacket( "URN", sizeof(SHA1) + 5 );
pPacket->WriteString( "sha1" );
pPacket->Write( &m_pSHA1, sizeof(SHA1) );
}
else if ( m_bTiger )
{
pPacket->WritePacket( "URN", sizeof(TIGEROOT) + 4 );
pPacket->WriteString( "ttr" );
pPacket->Write( &m_pTiger, sizeof(TIGEROOT) );
}
else if ( m_bED2K )
{
pPacket->WritePacket( "URN", sizeof(MD4) + 5 );
pPacket->WriteString( "ed2k" );
pPacket->Write( &m_pED2K, sizeof(MD4) );
}
if ( m_bBTH )
{
pPacket->WritePacket( "URN", sizeof(SHA1) + 5 );
pPacket->WriteString( "btih" );
pPacket->Write( &m_pBTH, sizeof(SHA1) );
}
if ( m_sSearch.GetLength() )
{
pPacket->WritePacket( "DN", pPacket->GetStringLen( m_sSearch ) );
pPacket->WriteString( m_sSearch, FALSE );
}
if ( m_pXML != NULL )
{
CString strXML;
if ( true )
{
if ( CXMLElement* pBody = m_pXML->GetFirstElement() )
strXML = pBody->ToString();
}
else
{
strXML = m_pXML->ToString( TRUE );
}
pPacket->WritePacket( "MD", pPacket->GetStringLen( strXML ) );
pPacket->WriteString( strXML, FALSE );
}
if ( m_nMinSize != 0 || m_nMaxSize != SIZE_UNKNOWN )
{
if ( m_nMinSize < 0xFFFFFFFF && ( m_nMaxSize < 0xFFFFFFFF || m_nMaxSize == SIZE_UNKNOWN ) )
{
pPacket->WritePacket( "SZR", 8 );
pPacket->WriteLongBE( (DWORD)m_nMinSize );
pPacket->WriteLongBE( m_nMaxSize == SIZE_UNKNOWN ? 0xFFFFFFFF : (DWORD)m_nMaxSize );
}
else
{
pPacket->WritePacket( "SZR", 16 );
pPacket->WriteInt64( m_nMinSize );
pPacket->WriteInt64( m_nMaxSize );
}
}
if ( ! m_bWantURL || ! m_bWantDN || ! m_bWantXML || ! m_bWantCOM || ! m_bWantPFS )
{
pPacket->WritePacket( "I",
( m_bWantURL ? 4 : 0 ) + ( m_bWantDN ? 3 : 0 ) + ( m_bWantXML ? 3 : 0 ) +
( m_bWantCOM ? 4 : 0 ) + ( m_bWantPFS ? 4 : 0 ) );
if ( m_bWantURL ) pPacket->WriteString( "URL" );
if ( m_bWantDN ) pPacket->WriteString( "DN" );
if ( m_bWantXML ) pPacket->WriteString( "MD" );
if ( m_bWantCOM ) pPacket->WriteString( "COM" );
if ( m_bWantPFS ) pPacket->WriteString( "PFS" );
}
if ( m_bAndG1 ) pPacket->WritePacket( "G1", 0 );
pPacket->WriteByte( 0 );
pPacket->Write( &m_pGUID, sizeof(GGUID) );
return pPacket;
}
//////////////////////////////////////////////////////////////////////
// CQuerySearch to ED2K packet
CEDPacket* CQuerySearch::ToEDPacket(BOOL bUDP)
{
CEDPacket* pPacket = NULL;
CString strWords = m_pSchema->GetIndexedWords( m_pXML->GetFirstElement() );
if ( m_bED2K && ! m_bWantDN )
{
pPacket = CEDPacket::New( bUDP ? ED2K_C2SG_GETSOURCES : ED2K_C2S_GETSOURCES );
pPacket->Write( &m_pED2K, sizeof(MD4) );
}
else if ( m_bBTH )
{
// BitTorrent searches prohibited unless they are GETSOURCES above
}
else if ( m_sSearch.GetLength() > 0 || strWords.GetLength() > 0 )
{
pPacket = CEDPacket::New( bUDP ? ED2K_C2SG_SEARCHREQUEST : ED2K_C2S_SEARCHREQUEST );
if ( m_nMinSize > 0 || m_nMaxSize < SIZE_UNKNOWN )
{
pPacket->WriteByte( 0 );
pPacket->WriteByte( 0 );
pPacket->WriteByte( 0 );
pPacket->WriteByte( 0 );
pPacket->WriteByte( 3 );
pPacket->WriteLongLE( (DWORD)m_nMinSize );
pPacket->WriteByte( 1 );
pPacket->WriteShortLE( 1 );
pPacket->WriteByte( ED2K_FT_FILESIZE );
pPacket->WriteByte( 3 );
pPacket->WriteLongLE( (DWORD)min( m_nMaxSize, 0xFFFFFFFF ) );
pPacket->WriteByte( 2 );
pPacket->WriteShortLE( 1 );
pPacket->WriteByte( ED2K_FT_FILESIZE );
}
pPacket->WriteByte( 1 );
pPacket->WriteEDString( m_sSearch.GetLength() ? m_sSearch : strWords );
}
return pPacket;
}
//////////////////////////////////////////////////////////////////////
// CQuerySearch from packet root
CQuerySearch* CQuerySearch::FromPacket(CPacket* pPacket, SOCKADDR_IN* pEndpoint)
{
CQuerySearch* pSearch = new CQuerySearch( FALSE );
if ( pPacket->m_nProtocol == PROTOCOL_G1 )
{
if ( pSearch->ReadG1Packet( (CG1Packet*)pPacket ) ) return pSearch;
}
else if ( pPacket->m_nProtocol == PROTOCOL_G2 )
{
if ( ((CG2Packet*)pPacket)->IsType( G2_PACKET_QUERY_WRAP ) )
{
if ( pSearch->ReadG1Packet( (CG1Packet*)pPacket ) ) return pSearch;
}
else
{
if ( pSearch->ReadG2Packet( (CG2Packet*)pPacket, pEndpoint ) ) return pSearch;
}
}
delete pSearch;
return NULL;
}
//////////////////////////////////////////////////////////////////////
// CQuerySearch from G1 packet
BOOL CQuerySearch::ReadG1Packet(CPacket* pPacket)
{
CString strData;
m_bWantCOM = m_bWantPFS = FALSE;
if ( pPacket->m_nProtocol == PROTOCOL_G2 )
{
GNUTELLAPACKET pG1;
if ( ! ((CG2Packet*)pPacket)->SeekToWrapped() ) return NULL;
pPacket->Read( &pG1, sizeof(pG1) );
m_pGUID = pG1.m_pGUID;
}
else
{
m_pGUID = ((CG1Packet*)pPacket)->m_pGUID;
}
if ( pPacket->GetRemaining() < 4 ) return FALSE;
WORD nFlags = pPacket->ReadShortLE();
if ( nFlags & G1_QF_TAG )
{
m_bFirewall = 0 != ( nFlags & G1_QF_FIREWALLED );
m_bWantXML = 0 != ( nFlags & G1_QF_XML );
}
m_sSearch = pPacket->ReadString();
if ( pPacket->GetRemaining() >= 1 )
{
strData = pPacket->ReadString();
if ( strData.GetLength() > 1024 ) strData.Empty();
}
LPCTSTR pszData = strData;
LPCTSTR pszEnd = pszData + _tcslen( pszData );
int nIterations = 0;
while ( *pszData && pszData < pszEnd )
{
if ( nIterations++ > 4 ) break;
if ( (BYTE)*pszData == GGEP_MAGIC )
{
if ( ! Settings.Gnutella1.EnableGGEP ) break;
CGGEPBlock pGGEP;
pGGEP.ReadFromString( pszData );
if ( CGGEPItem* pItem = pGGEP.Find( _T("H"), 21 ) )
{
if ( pItem->m_pBuffer[0] > 0 && pItem->m_pBuffer[0] < 3 )
{
CopyMemory( &m_pSHA1, &pItem->m_pBuffer[1], 20 );
m_bSHA1 = TRUE;
}
if ( pItem->m_pBuffer[0] == 2 && pItem->m_nLength >= 24 + 20 + 1 )
{
CopyMemory( &m_pTiger, &pItem->m_pBuffer[21], 24 );
m_bTiger = TRUE;
}
}
else if ( CGGEPItem* pItem = pGGEP.Find( _T("u") ) )
{
strData = pItem->ToString();
m_bSHA1 |= CSHA::HashFromURN( strData, &m_pSHA1 );
m_bTiger |= CTigerNode::HashFromURN( strData, &m_pTiger );
m_bED2K |= CED2K::HashFromURN( strData, &m_pED2K );
}
break;
}
LPCTSTR pszSep = _tcschr( pszData, 0x1C );
int nLength = ( pszSep && *pszSep == 0x1C ) ? pszSep - pszData : _tcslen( pszData );
if ( ! _istalnum( *pszData ) ) nLength = 0;
if ( nLength >= 4 && _tcsncmp( pszData, _T("urn:"), 4 ) == 0 )
{
m_bSHA1 |= CSHA::HashFromURN( pszData, &m_pSHA1 );
m_bTiger |= CTigerNode::HashFromURN( pszData, &m_pTiger );
m_bED2K |= CED2K::HashFromURN( pszData, &m_pED2K );
}
else if ( nLength > 5 && _tcsncmp( pszData, _T("<?xml"), 5 ) == 0 )
{
m_pXML = CXMLElement::FromString( pszData, TRUE );
if ( m_pXML == NULL ) continue;
CString strSchemaURI = m_pXML->GetAttributeValue( CXMLAttribute::schemaName, NULL );
m_pSchema = SchemaCache.Get( strSchemaURI );
}
if ( pszSep && *pszSep == 0x1C ) pszData = pszSep + 1;
else break;
}
m_bAndG1 = TRUE;
return CheckValid();
}
//////////////////////////////////////////////////////////////////////
// CQuerySearch from G2 packet
BOOL CQuerySearch::ReadG2Packet(CG2Packet* pPacket, SOCKADDR_IN* pEndpoint)
{
if ( ! pPacket->m_bCompound ) return FALSE;
CHAR szType[9];
DWORD nLength;
m_bAndG1 = FALSE;
while ( pPacket->ReadPacket( szType, nLength ) )
{
DWORD nOffset = pPacket->m_nPosition + nLength;
if ( strcmp( szType, "QKY" ) == 0 && nLength >= 4 )
{
if ( m_pEndpoint.sin_addr.S_un.S_addr == 0 && pEndpoint != NULL )
m_pEndpoint = *pEndpoint;
m_bUDP = ! Network.IsFirewalledAddress( &m_pEndpoint.sin_addr );
m_nKey = pPacket->ReadLongBE();
DWORD* pZero = (DWORD*)( pPacket->m_pBuffer + pPacket->m_nPosition - 4 );
*pZero = 0;
}
else if ( strcmp( szType, "UDP" ) == 0 && nLength >= 6 )
{
m_pEndpoint.sin_addr.S_un.S_addr = pPacket->ReadLongLE();
m_pEndpoint.sin_port = htons( pPacket->ReadShortBE() );
if ( m_pEndpoint.sin_addr.S_un.S_addr == 0 && pEndpoint != NULL )
m_pEndpoint = *pEndpoint;
m_bUDP = ! Network.IsFirewalledAddress( &m_pEndpoint.sin_addr );
if ( m_bUDP ) m_pEndpoint.sin_family = PF_INET;
if ( nLength >= 10 )
{
m_nKey = pPacket->ReadLongBE();
DWORD* pZero = (DWORD*)( pPacket->m_pBuffer + pPacket->m_nPosition - 4 );
*pZero = 0;
}
}
else if ( strcmp( szType, "I" ) == 0 )
{
m_bWantURL = m_bWantDN = m_bWantXML = m_bWantCOM = m_bWantPFS = FALSE;
while ( nLength > 0 )
{
CString str = pPacket->ReadString( nLength );
nLength -= str.GetLength() + 1;
if ( str == _T("URL") ) m_bWantURL = TRUE;
else if ( str == _T("DN") ) m_bWantDN = TRUE;
else if ( str == _T("SZ") ) m_bWantDN = TRUE; // Hack
else if ( str == _T("MD") ) m_bWantXML = TRUE;
else if ( str == _T("COM") ) m_bWantCOM = TRUE;
else if ( str == _T("PFS") ) m_bWantPFS = TRUE;
}
}
else if ( strcmp( szType, "URN" ) == 0 )
{
CString strURN = pPacket->ReadString( nLength );
if ( strURN.GetLength() + 1 >= (int)nLength ) return FALSE;
nLength -= strURN.GetLength() + 1;
if ( nLength >= 20 && strURN == _T("sha1") )
{
m_bSHA1 = TRUE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -