00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "StdAfx.h"
00023 #include "Shareaza.h"
00024 #include "Settings.h"
00025 #include "QuerySearch.h"
00026 #include "Network.h"
00027 #include "Datagrams.h"
00028 #include "G1Packet.h"
00029 #include "G2Packet.h"
00030 #include "EDPacket.h"
00031
00032 #include "Schema.h"
00033 #include "SchemaCache.h"
00034 #include "QueryHashTable.h"
00035 #include "GGEP.h"
00036 #include "XML.h"
00037 #include "SHA.h"
00038 #include "MD5.h"
00039 #include "ED2K.h"
00040 #include "TigerTree.h"
00041
00042 #include "WndSearch.h"
00043
00044 #include "Download.h"
00045 #include "Downloads.h"
00046 #include "Transfers.h"
00047
00048 #ifdef _DEBUG
00049 #undef THIS_FILE
00050 static char THIS_FILE[]=__FILE__;
00051 #define new DEBUG_NEW
00052 #endif
00053
00054
00056
00057
00058 CQuerySearch::CQuerySearch(BOOL bGUID)
00059 {
00060 if ( bGUID ) Network.CreateID( m_pGUID );
00061
00062 m_pSchema = NULL;
00063 m_pXML = NULL;
00064 m_nMinSize = 0x0000000000000000;
00065 m_nMaxSize = 0xFFFFFFFFFFFFFFFF;
00066
00067 m_bSHA1 = FALSE;
00068 m_bTiger = FALSE;
00069 m_bED2K = FALSE;
00070 m_bBTH = FALSE;
00071
00072 m_bSimilarSearch= FALSE;
00073
00074 m_bWantURL = TRUE;
00075 m_bWantDN = TRUE;
00076 m_bWantXML = TRUE;
00077 m_bWantCOM = TRUE;
00078 m_bWantPFS = TRUE;
00079 m_bAndG1 = Settings.Gnutella1.EnableToday;
00080
00081 m_bUDP = FALSE;
00082 m_nKey = 0;
00083 m_bFirewall = FALSE;
00084
00085 m_nWords = 0;
00086 m_pWordPtr = NULL;
00087 m_pWordLen = NULL;
00088 }
00089
00090 CQuerySearch::CQuerySearch(CQuerySearch* pCopy)
00091 {
00092 m_pGUID = pCopy->m_pGUID;
00093
00094 m_sSearch = pCopy->m_sSearch;
00095 m_pSchema = pCopy->m_pSchema;
00096 m_pXML = pCopy->m_pXML ? pCopy->m_pXML->Clone() : NULL;
00097 m_nMinSize = pCopy->m_nMinSize;
00098 m_nMaxSize = pCopy->m_nMaxSize;
00099
00100 m_bSHA1 = pCopy->m_bSHA1;
00101 if ( m_bSHA1 ) m_pSHA1 = pCopy->m_pSHA1;
00102 m_bTiger = pCopy->m_bTiger;
00103 if ( m_bTiger ) m_pTiger = pCopy->m_pTiger;
00104 m_bED2K = pCopy->m_bED2K;
00105 if ( m_bED2K ) m_pED2K = pCopy->m_pED2K;
00106 m_bBTH = pCopy->m_bBTH;
00107 if ( m_bBTH ) m_pBTH = pCopy->m_pBTH;
00108 m_bSimilarSearch = FALSE;
00109
00110 m_bWantURL = pCopy->m_bWantURL;
00111 m_bWantDN = pCopy->m_bWantDN;
00112 m_bWantXML = pCopy->m_bWantXML;
00113 m_bWantCOM = pCopy->m_bWantCOM;
00114 m_bWantPFS = pCopy->m_bWantPFS;
00115 m_bAndG1 = pCopy->m_bAndG1;
00116
00117 m_bUDP = pCopy->m_bUDP;
00118 m_nKey = pCopy->m_nKey;
00119 if ( m_bUDP ) m_pEndpoint = pCopy->m_pEndpoint;
00120
00121 m_nWords = 0;
00122 m_pWordPtr = NULL;
00123 m_pWordLen = NULL;
00124 }
00125
00126 CQuerySearch::~CQuerySearch()
00127 {
00128 if ( m_pXML ) delete m_pXML;
00129
00130 if ( m_pWordPtr ) delete [] m_pWordPtr;
00131 if ( m_pWordLen ) delete [] m_pWordLen;
00132 }
00133
00135
00136
00137 CG1Packet* CQuerySearch::ToG1Packet()
00138 {
00139 CG1Packet* pPacket = CG1Packet::New( G1_PACKET_QUERY,
00140 min( Settings.Gnutella1.SearchTTL, DWORD(4) ), &m_pGUID );
00141
00142 WORD nFlags = G1_QF_TAG | G1_QF_BIN_HASH | G1_QF_DYNAMIC;
00143 if ( ! Network.IsListening() ) nFlags |= G1_QF_FIREWALLED;
00144 if ( m_bWantXML ) nFlags |= G1_QF_XML;
00145 pPacket->WriteShortLE( nFlags );
00146
00147 CString strExtra;
00148
00149 if ( m_sSearch.GetLength() )
00150 {
00151 if ( Settings.Gnutella1.QuerySearchUTF8 )
00152 {
00153 pPacket->WriteStringUTF8( m_sSearch );
00154 }
00155 else
00156 {
00157 pPacket->WriteString( m_sSearch );
00158 }
00159 }
00160 else if ( m_pSchema != NULL && m_pXML != NULL )
00161 {
00162 strExtra = m_pSchema->GetIndexedWords( m_pXML->GetFirstElement() );
00163 pPacket->WriteString( strExtra );
00164 strExtra.Empty();
00165 }
00166 else
00167 {
00168 pPacket->WriteByte( 0 );
00169 }
00170
00171 if ( m_bSHA1 )
00172 {
00173 strExtra = CSHA::HashToString( &m_pSHA1, TRUE );
00174 }
00175 else if ( m_bTiger )
00176 {
00177 strExtra = CTigerNode::HashToString( &m_pTiger, TRUE );
00178 }
00179 else if ( m_bED2K )
00180 {
00181 strExtra = CED2K::HashToString( &m_pED2K, TRUE );
00182 }
00183 else
00184 {
00185 strExtra = _T("urn:");
00186 }
00187
00188 if ( m_pXML )
00189 {
00190 if ( strExtra.GetLength() ) strExtra += '\x1C';
00191 strExtra += m_pXML->ToString( TRUE );
00192 }
00193
00194 pPacket->WriteString( strExtra );
00195
00196 return pPacket;
00197 }
00198
00200
00201
00202 CG2Packet* CQuerySearch::ToG2Packet(SOCKADDR_IN* pUDP, DWORD nKey)
00203 {
00204 CG2Packet* pPacket = CG2Packet::New( G2_PACKET_QUERY, TRUE );
00205
00206 if ( pUDP )
00207 {
00208 pPacket->WritePacket( "UDP", nKey ? 10 : 6 );
00209 pPacket->WriteLongLE( pUDP->sin_addr.S_un.S_addr );
00210 pPacket->WriteShortBE( htons( pUDP->sin_port ) );
00211 if ( nKey ) pPacket->WriteLongBE( nKey );
00212 }
00213
00214 if ( m_bTiger && m_bSHA1 )
00215 {
00216 pPacket->WritePacket( "URN", sizeof(SHA1) + sizeof(TIGEROOT) + 3 );
00217 pPacket->WriteString( "bp" );
00218 pPacket->Write( &m_pSHA1, sizeof(SHA1) );
00219 pPacket->Write( &m_pTiger, sizeof(TIGEROOT) );
00220 }
00221 else if ( m_bSHA1 )
00222 {
00223 pPacket->WritePacket( "URN", sizeof(SHA1) + 5 );
00224 pPacket->WriteString( "sha1" );
00225 pPacket->Write( &m_pSHA1, sizeof(SHA1) );
00226 }
00227 else if ( m_bTiger )
00228 {
00229 pPacket->WritePacket( "URN", sizeof(TIGEROOT) + 4 );
00230 pPacket->WriteString( "ttr" );
00231 pPacket->Write( &m_pTiger, sizeof(TIGEROOT) );
00232 }
00233 else if ( m_bED2K )
00234 {
00235 pPacket->WritePacket( "URN", sizeof(MD4) + 5 );
00236 pPacket->WriteString( "ed2k" );
00237 pPacket->Write( &m_pED2K, sizeof(MD4) );
00238 }
00239
00240 if ( m_bBTH )
00241 {
00242 pPacket->WritePacket( "URN", sizeof(SHA1) + 5 );
00243 pPacket->WriteString( "btih" );
00244 pPacket->Write( &m_pBTH, sizeof(SHA1) );
00245 }
00246
00247 if ( m_sSearch.GetLength() )
00248 {
00249 pPacket->WritePacket( "DN", pPacket->GetStringLen( m_sSearch ) );
00250 pPacket->WriteString( m_sSearch, FALSE );
00251 }
00252
00253 if ( m_pXML != NULL )
00254 {
00255 CString strXML;
00256
00257 if ( true )
00258 {
00259 if ( CXMLElement* pBody = m_pXML->GetFirstElement() )
00260 strXML = pBody->ToString();
00261 }
00262 else
00263 {
00264 strXML = m_pXML->ToString( TRUE );
00265 }
00266
00267 pPacket->WritePacket( "MD", pPacket->GetStringLen( strXML ) );
00268 pPacket->WriteString( strXML, FALSE );
00269 }
00270
00271 if ( m_nMinSize != 0 || m_nMaxSize != SIZE_UNKNOWN )
00272 {
00273 if ( m_nMinSize < 0xFFFFFFFF && ( m_nMaxSize < 0xFFFFFFFF || m_nMaxSize == SIZE_UNKNOWN ) )
00274 {
00275 pPacket->WritePacket( "SZR", 8 );
00276 pPacket->WriteLongBE( (DWORD)m_nMinSize );
00277 pPacket->WriteLongBE( m_nMaxSize == SIZE_UNKNOWN ? 0xFFFFFFFF : (DWORD)m_nMaxSize );
00278 }
00279 else
00280 {
00281 pPacket->WritePacket( "SZR", 16 );
00282 pPacket->WriteInt64( m_nMinSize );
00283 pPacket->WriteInt64( m_nMaxSize );
00284 }
00285 }
00286
00287 if ( ! m_bWantURL || ! m_bWantDN || ! m_bWantXML || ! m_bWantCOM || ! m_bWantPFS )
00288 {
00289 pPacket->WritePacket( "I",
00290 ( m_bWantURL ? 4 : 0 ) + ( m_bWantDN ? 3 : 0 ) + ( m_bWantXML ? 3 : 0 ) +
00291 ( m_bWantCOM ? 4 : 0 ) + ( m_bWantPFS ? 4 : 0 ) );
00292
00293 if ( m_bWantURL ) pPacket->WriteString( "URL" );
00294 if ( m_bWantDN ) pPacket->WriteString( "DN" );
00295 if ( m_bWantXML ) pPacket->WriteString( "MD" );
00296 if ( m_bWantCOM ) pPacket->WriteString( "COM" );
00297 if ( m_bWantPFS ) pPacket->WriteString( "PFS" );
00298 }
00299
00300
00301
00302 pPacket->WriteByte( 0 );
00303 pPacket->Write( &m_pGUID, sizeof(GGUID) );
00304
00305 return pPacket;
00306 }
00307
00309
00310
00311 CEDPacket* CQuerySearch::ToEDPacket(BOOL bUDP, DWORD nServerFlags)
00312 {
00313 BOOL bUTF8, bGetS2;
00314
00315 CEDPacket* pPacket = NULL;
00316
00317 CString strWords = m_pSchema->GetIndexedWords( m_pXML->GetFirstElement() );
00318
00319
00320 if ( bUDP )
00321 {
00322 bUTF8 = nServerFlags & ED2K_SERVER_UDP_UNICODE;
00323 bGetS2 = nServerFlags & ED2K_SERVER_UDP_GETSOURCES2;
00324 }
00325 else
00326 {
00327 bUTF8 = nServerFlags & ED2K_SERVER_TCP_UNICODE;
00328 bGetS2 = nServerFlags & ED2K_SERVER_TCP_GETSOURCES2;
00329 }
00330
00331 if ( m_bED2K )
00332 {
00333 if( m_bWantDN && Settings.eDonkey.MagnetSearch )
00334 {
00335
00336 pPacket = CEDPacket::New( bUDP ? ED2K_C2SG_SEARCHREQUEST : ED2K_C2S_SEARCHREQUEST );
00337 pPacket->WriteByte( 1 );
00338 pPacket->WriteEDString( _T("magnet:?xt=ed2k:") + CED2K::HashToString( &m_pED2K ), bUTF8 );
00339 }
00340 else
00341 {
00342
00343
00344
00345 if ( ( bGetS2 ) && ( m_nMinSize == m_nMaxSize ) && ( m_nMaxSize < 0xFFFFFFFF ) )
00346 {
00347
00348
00349
00350 pPacket = CEDPacket::New( bUDP ? ED2K_C2SG_GETSOURCES2 : ED2K_C2S_GETSOURCES );
00351
00352 pPacket->Write( &m_pED2K, sizeof(MD4) );
00353 pPacket->WriteLongLE( (DWORD)m_nMaxSize );
00354
00355 WriteHashesToEDPacket( pPacket, bUDP );
00356
00357 }
00358 else
00359 {
00360
00361 pPacket = CEDPacket::New( bUDP ? ED2K_C2SG_GETSOURCES : ED2K_C2S_GETSOURCES );
00362 pPacket->Write( &m_pED2K, sizeof(MD4) );
00363 }
00364 }
00365 }
00366 else if ( m_bBTH )
00367 {
00368
00369 }
00370 else if ( m_sSearch.GetLength() > 0 || strWords.GetLength() > 0 )
00371 {
00372 pPacket = CEDPacket::New( bUDP ? ED2K_C2SG_SEARCHREQUEST : ED2K_C2S_SEARCHREQUEST );
00373
00374 if ( m_nMinSize > 0 || m_nMaxSize < 0xFFFFFFFF )
00375 {
00376
00377 pPacket->WriteByte( 0 );
00378 pPacket->WriteByte( 0 );
00379
00380 pPacket->WriteByte( 0 );
00381 pPacket->WriteByte( 0 );
00382
00383
00384 pPacket->WriteByte( 3 );
00385 pPacket->WriteLongLE( (DWORD)m_nMinSize );
00386 pPacket->WriteByte( 1 );
00387 pPacket->WriteShortLE( 1 );
00388 pPacket->WriteByte( ED2K_FT_FILESIZE );
00389
00390
00391 pPacket->WriteByte( 3 );
00392 pPacket->WriteLongLE( (DWORD)min( m_nMaxSize, QWORD(0xFFFFFFFF) ) );
00393 pPacket->WriteByte( 2 );
00394 pPacket->WriteShortLE( 1 );
00395 pPacket->WriteByte( ED2K_FT_FILESIZE );
00396 }
00397
00398 if ( ( m_pSchema == NULL ) || ( ! m_pSchema->m_sDonkeyType.GetLength() ) )
00399 {
00400
00401
00402 pPacket->WriteByte( 1 );
00403
00404 if ( ( m_bSimilarSearch ) && ( ! bUDP ) && ( nServerFlags & ED2K_SERVER_TCP_RELATEDSEARCH ) )
00405 {
00406
00407 CString strSearch;
00408 strSearch.Format( _T("related::%s"), (LPCTSTR)CED2K::HashToString( &m_pSimilarED2K ) );
00409 pPacket->WriteEDString( strSearch, bUTF8 );
00410 }
00411 else
00412 {
00413
00414 pPacket->WriteEDString( m_sSearch.GetLength() ? m_sSearch : strWords, bUTF8 );
00415 }
00416 }
00417 else
00418 {
00419
00420 pPacket->WriteByte( 0 );
00421 pPacket->WriteByte( 0 );
00422
00423
00424 pPacket->WriteByte( 1 );
00425 pPacket->WriteEDString( m_sSearch.GetLength() ? m_sSearch : strWords, bUTF8 );
00426
00427
00428 pPacket->WriteByte( 2 );
00429 pPacket->WriteEDString( m_pSchema->m_sDonkeyType, bUTF8 );
00430 pPacket->WriteShortLE( 1 );
00431 pPacket->WriteByte( ED2K_FT_FILETYPE );
00432 }
00433 }
00434
00435 return pPacket;
00436 }
00437
00438 BOOL CQuerySearch::WriteHashesToEDPacket( CEDPacket* pPacket, BOOL bUDP )
00439 {
00440 ASSERT ( pPacket != NULL );
00441 ASSERT ( pPacket->m_nType == bUDP ? ED2K_C2SG_GETSOURCES2 : ED2K_C2S_GETSOURCES );
00442
00443 CSingleLock pLock( &Transfers.m_pSection );
00444 if ( ! pLock.Lock( 250 ) ) return FALSE;
00445
00446 int nFiles = 1;
00447 DWORD tNow = GetTickCount();
00448
00449
00450 for ( POSITION pos = Downloads.GetIterator() ; pos ; )
00451 {
00452 CDownload* pDownload = Downloads.GetNext( pos );
00453
00454
00455 if ( pDownload->m_bED2K &&
00456 pDownload->IsTrying() &&
00457 pDownload->m_nSize < 0xFFFFFFFF &&
00458 pDownload->IsCompleted() == FALSE &&
00459 pDownload->NeedHashset() == FALSE &&
00460 pDownload->m_pED2K != m_pED2K )
00461 {
00462
00463 DWORD tNextQuery = bUDP ? pDownload->m_tLastED2KGlobal + Settings.eDonkey.QueryFileThrottle : pDownload->m_tLastED2KLocal + Settings.eDonkey.QueryFileThrottle;
00464 if ( tNow > tNextQuery )
00465 {
00466
00467 int nSources = pDownload->GetSourceCount( FALSE, TRUE );
00468 if ( nSources < ( Settings.Downloads.SourcesWanted / 4 ) )
00469 {
00470 BOOL bFewSources = nSources < Settings.Downloads.MinSources;
00471 BOOL bDataStarve = ( tNow > pDownload->m_tReceived ? tNow - pDownload->m_tReceived : 0 ) > Settings.Downloads.StarveTimeout * 1000;
00472
00473 if ( ( bFewSources ) || ( bDataStarve ) || ( nFiles < 10 ) )
00474 {
00475
00476 pPacket->Write( &pDownload->m_pED2K, sizeof(MD4) );
00477 pPacket->WriteLongLE( (DWORD)pDownload->m_nSize );
00478 if ( bUDP )
00479 pDownload->m_tLastED2KGlobal = tNow;
00480 else
00481 pDownload->m_tLastED2KLocal = tNow;
00482 nFiles ++;
00483 if ( nFiles >= ED2K_MAXFILESINPACKET ) return TRUE;
00484 }
00485 }
00486 }
00487 }
00488 }
00489
00490 return TRUE;
00491 }
00492
00494
00495
00496 CQuerySearch* CQuerySearch::FromPacket(CPacket* pPacket, SOCKADDR_IN* pEndpoint)
00497 {
00498 CQuerySearch* pSearch = new CQuerySearch( FALSE );
00499
00500 if ( pPacket->m_nProtocol == PROTOCOL_G1 )
00501 {
00502 if ( pSearch->ReadG1Packet( (CG1Packet*)pPacket ) ) return pSearch;
00503 }
00504 else if ( pPacket->m_nProtocol == PROTOCOL_G2 )
00505 {
00506 if ( ((CG2Packet*)pPacket)->IsType( G2_PACKET_QUERY_WRAP ) )
00507 {
00508
00509 theApp.Message( MSG_DEBUG, _T("CQuerySearch::FromPacket dropping obsolete wrapped packet") );
00510 }
00511 else
00512 {
00513 if ( pSearch->ReadG2Packet( (CG2Packet*)pPacket, pEndpoint ) ) return pSearch;
00514 }
00515 }
00516
00517 delete pSearch;
00518
00519 return NULL;
00520 }
00521
00523
00524
00525 BOOL CQuerySearch::ReadG1Packet(CPacket* pPacket)
00526 {
00527 CString strData;
00528 m_bWantCOM = m_bWantPFS = FALSE;
00529
00530 if ( pPacket->m_nProtocol == PROTOCOL_G2 )
00531 {
00532 GNUTELLAPACKET pG1;
00533 if ( ! ((CG2Packet*)pPacket)->SeekToWrapped() ) return NULL;
00534 pPacket->Read( &pG1, sizeof(pG1) );
00535 m_pGUID = pG1.m_pGUID;
00536 }
00537 else
00538 {
00539 m_pGUID = ((CG1Packet*)pPacket)->m_pGUID;
00540 }
00541
00542 if ( pPacket->GetRemaining() < 4 ) return FALSE;
00543
00544 WORD nFlags = pPacket->ReadShortLE();
00545
00546 if ( nFlags & G1_QF_TAG )
00547 {
00548 m_bFirewall = 0 != ( nFlags & G1_QF_FIREWALLED );
00549 m_bWantXML = 0 != ( nFlags & G1_QF_XML );
00550 }
00551
00552 if ( Settings.Gnutella1.QuerySearchUTF8 )
00553 {
00554 m_sSearch = pPacket->ReadStringUTF8();
00555 }
00556 else
00557 {
00558 m_sSearch = pPacket->ReadString();
00559 }
00560
00561 if ( pPacket->GetRemaining() >= 1 )
00562 {
00563 strData = pPacket->ReadString();
00564 if ( strData.GetLength() > 1024 ) strData.Empty();
00565 }
00566
00567 LPCTSTR pszData = strData;
00568 LPCTSTR pszEnd = pszData + _tcslen( pszData );
00569 int nIterations = 0;
00570
00571 while ( *pszData && pszData < pszEnd )
00572 {
00573 if ( nIterations++ > 4 ) break;
00574
00575 if ( (BYTE)*pszData == GGEP_MAGIC )
00576 {
00577 if ( ! Settings.Gnutella1.EnableGGEP ) break;
00578
00579 CGGEPBlock pGGEP;
00580 pGGEP.ReadFromString( pszData );
00581
00582 if ( CGGEPItem* pItem = pGGEP.Find( _T("H"), 21 ) )
00583 {
00584 if ( pItem->m_pBuffer[0] > 0 && pItem->m_pBuffer[0] < 3 )
00585 {
00586 CopyMemory( &m_pSHA1, &pItem->m_pBuffer[1], 20 );
00587 m_bSHA1 = TRUE;
00588 }
00589 if ( pItem->m_pBuffer[0] == 2 && pItem->m_nLength >= 24 + 20 + 1 )
00590 {
00591 CopyMemory( &m_pTiger, &pItem->m_pBuffer[21], 24 );
00592 m_bTiger = TRUE;
00593 }
00594 }
00595 else if ( CGGEPItem* pItem = pGGEP.Find( _T("u") ) )
00596 {
00597 strData = pItem->ToString();
00598
00599 m_bSHA1 |= CSHA::HashFromURN( strData, &m_pSHA1 );
00600 m_bTiger |= CTigerNode::HashFromURN( strData, &m_pTiger );
00601 m_bED2K |= CED2K::HashFromURN( strData, &m_pED2K );
00602 }
00603
00604 break;
00605 }
00606
00607 LPCTSTR pszSep = _tcschr( pszData, 0x1C );
00608 int nLength = ( pszSep && *pszSep == 0x1C ) ? pszSep - pszData : _tcslen( pszData );
00609
00610 if ( ! _istalnum( *pszData ) ) nLength = 0;
00611
00612 if ( nLength >= 4 && _tcsncmp( pszData, _T("urn:"), 4 ) == 0 )
00613 {
00614 m_bSHA1 |= CSHA::HashFromURN( pszData, &m_pSHA1 );
00615 m_bTiger |= CTigerNode::HashFromURN( pszData, &m_pTiger );
00616 m_bED2K |= CED2K::HashFromURN( pszData, &m_pED2K );
00617 }
00618 else if ( nLength > 5 && _tcsncmp( pszData, _T("<?xml"), 5 ) == 0 )
00619 {
00620 m_pXML = CXMLElement::FromString( pszData, TRUE );
00621
00622 if ( m_pXML == NULL ) continue;
00623
00624 CString strSchemaURI = m_pXML->GetAttributeValue( CXMLAttribute::schemaName, NULL );
00625 m_pSchema = SchemaCache.Get( strSchemaURI );
00626 }
00627
00628 if ( pszSep && *pszSep == 0x1C ) pszData = pszSep + 1;
00629 else break;
00630 }
00631
00632 m_bAndG1 = TRUE;
00633 return CheckValid();
00634 }
00635
00637
00638
00639 BOOL CQuerySearch::ReadG2Packet(CG2Packet* pPacket, SOCKADDR_IN* pEndpoint)
00640 {
00641 if ( ! pPacket->m_bCompound ) return FALSE;
00642
00643 CHAR szType[9];
00644 DWORD nLength;
00645
00646 m_bAndG1 = FALSE;
00647
00648 while ( pPacket->ReadPacket( szType, nLength ) )
00649 {
00650 DWORD nOffset = pPacket->m_nPosition + nLength;
00651
00652 if ( strcmp( szType, "QKY" ) == 0 && nLength >= 4 )
00653 {
00654 if ( m_pEndpoint.sin_addr.S_un.S_addr == 0 && pEndpoint != NULL )
00655 m_pEndpoint = *pEndpoint;
00656 m_bUDP = ! Network.IsFirewalledAddress( &m_pEndpoint.sin_addr );
00657
00658 m_nKey = pPacket->ReadLongBE();
00659 DWORD* pZero = (DWORD*)( pPacket->m_pBuffer + pPacket->m_nPosition - 4 );
00660 *pZero = 0;
00661 }
00662 else if ( strcmp( szType, "UDP" ) == 0 && nLength >= 6 )
00663 {
00664 m_pEndpoint.sin_addr.S_un.S_addr = pPacket->ReadLongLE();
00665 m_pEndpoint.sin_port = htons( pPacket->ReadShortBE() );
00666
00667 if ( m_pEndpoint.sin_addr.S_un.S_addr == 0 && pEndpoint != NULL )
00668 m_pEndpoint = *pEndpoint;
00669 m_bUDP = ! Network.IsFirewalledAddress( &m_pEndpoint.sin_addr );
00670 if ( m_bUDP ) m_pEndpoint.sin_family = PF_INET;
00671
00672 if ( nLength >= 10 )
00673 {
00674 m_nKey = pPacket->ReadLongBE();
00675 DWORD* pZero = (DWORD*)( pPacket->m_pBuffer + pPacket->m_nPosition - 4 );
00676 *pZero = 0;
00677 }
00678 }
00679 else if ( strcmp( szType, "I" ) == 0 )
00680 {
00681 m_bWantURL = m_bWantDN = m_bWantXML = m_bWantCOM = m_bWantPFS = FALSE;
00682
00683 while ( nLength > 0 )
00684 {
00685 CString str = pPacket->ReadString( nLength );
00686 nLength -= str.GetLength() + 1;
00687
00688 if ( str == _T("URL") ) m_bWantURL = TRUE;
00689 else if ( str == _T("DN") ) m_bWantDN = TRUE;
00690 else if ( str == _T("SZ") ) m_bWantDN = TRUE;
00691 else if ( str == _T("MD") ) m_bWantXML = TRUE;
00692 else if ( str == _T("COM") ) m_bWantCOM = TRUE;
00693 else if ( str == _T("PFS") ) m_bWantPFS = TRUE;
00694 }
00695 }
00696 else if ( strcmp( szType, "URN" ) == 0 )
00697 {
00698 CString strURN = pPacket->ReadString( nLength );
00699 if ( strURN.GetLength() + 1 >= (int)nLength ) return FALSE;
00700 nLength -= strURN.GetLength() + 1;
00701
00702 if ( nLength >= 20 && strURN == _T("sha1") )
00703 {
00704 m_bSHA1 = TRUE;
00705 pPacket->Read( &m_pSHA1, sizeof(SHA1) );
00706 }
00707 else if ( nLength >= 44 && ( strURN == _T("bp") || strURN == _T("bitprint") ) )
00708 {
00709 m_bSHA1 = TRUE;
00710 pPacket->Read( &m_pSHA1, sizeof(SHA1) );
00711 m_bTiger = TRUE;
00712 pPacket->Read( &m_pTiger, sizeof(TIGEROOT) );
00713 }
00714 else if ( nLength >= 24 && ( strURN == _T("ttr") || strURN == _T("tree:tiger/") ) )
00715 {
00716 m_bTiger = TRUE;
00717 pPacket->Read( &m_pTiger, sizeof(TIGEROOT) );
00718 }
00719 else if ( nLength >= 16 && strURN == _T("ed2k") )
00720 {
00721 m_bED2K = TRUE;
00722 pPacket->Read( &m_pED2K, sizeof(MD4) );
00723 }
00724 else if ( nLength >= 20 && strURN == _T("btih") )
00725 {
00726 m_bBTH = TRUE;
00727 pPacket->Read( &m_pBTH, sizeof(SHA1) );
00728 }
00729 }
00730 else if ( strcmp( szType, "DN" ) == 0 )
00731 {
00732 m_sSearch = pPacket->ReadString( nLength );
00733 }
00734 else if ( strcmp( szType, "MD" ) == 0 )
00735 {
00736 CString strXML = pPacket->ReadString( nLength );
00737
00738 m_pXML->Delete();
00739 m_pXML = CXMLElement::FromString( strXML );
00740 m_pSchema = NULL;
00741
00742 if ( m_pXML != NULL )
00743 {
00744 if ( CXMLAttribute *pURI = m_pXML->GetAttribute( CXMLAttribute::schemaName ) )
00745 {
00746 m_pSchema = SchemaCache.Get( pURI->GetValue() );
00747 }
00748 else if ( m_pSchema = SchemaCache.Guess( m_pXML->GetName() ) )
00749 {
00750 CXMLElement* pRoot = m_pSchema->Instantiate( TRUE );
00751 pRoot->AddElement( m_pXML );
00752 m_pXML = pRoot;
00753 }
00754 }
00755 }
00756 else if ( strcmp( szType, "SZR" ) == 0 )
00757 {
00758 if ( nLength == 8 )
00759 {
00760 m_nMinSize = pPacket->ReadLongBE();
00761 m_nMaxSize = pPacket->ReadLongBE();
00762 if ( m_nMaxSize == 0xFFFFFFFF ) m_nMaxSize = SIZE_UNKNOWN;
00763 }
00764 else if ( nLength == 16 )
00765 {
00766 m_nMinSize = pPacket->ReadInt64();
00767 m_nMaxSize = pPacket->ReadInt64();
00768 }
00769 }
00770 else if ( strcmp( szType, "G1" ) == 0 )
00771 {
00772 m_bAndG1 = TRUE;
00773 }
00774
00775 pPacket->m_nPosition = nOffset;
00776 }
00777
00778 if ( pPacket->GetRemaining() < 16 ) return FALSE;
00779
00780 pPacket->Read( &m_pGUID, sizeof(GGUID) );
00781
00782 return CheckValid();
00783 }
00784
00786
00787
00788 BOOL CQuerySearch::CheckValid()
00789 {
00790 DWORD nCount, nValidWords = 0, nValidCharacters = 0;
00791 BOOL bExtendedSearch = FALSE;
00792 CString strLastWord;
00793
00794 BuildWordList();
00795
00796
00797 if ( m_bSHA1 || m_bTiger || m_bED2K || m_bBTH ) return TRUE;
00798
00799
00800 if ( m_nWords == 0 ) return FALSE;
00801
00802
00803 if ( ( m_pWordLen ) && ( m_pWordLen[0] >= 2 ) )
00804 {
00805 if ( ( (DWORD)m_pWordPtr[0][0] > 20000 ) && ( (DWORD)m_pWordPtr[0][1] > 20000 ) )
00806 {
00807 bExtendedSearch = TRUE;
00808 }
00809 }
00810
00811
00812 for ( nCount = 0 ; nCount < m_nWords ; nCount++ )
00813 {
00814 if ( _tcsnicmp( m_pWordPtr[nCount], _T("mp3"), m_pWordLen[nCount] ) == 0 ||
00815 _tcsnicmp( m_pWordPtr[nCount], _T("ogg"), m_pWordLen[nCount] ) == 0 ||
00816
00817 _tcsnicmp( m_pWordPtr[nCount], _T("jpg"), m_pWordLen[nCount] ) == 0 ||
00818 _tcsnicmp( m_pWordPtr[nCount], _T("gif"), m_pWordLen[nCount] ) == 0 ||
00819 _tcsnicmp( m_pWordPtr[nCount], _T("png"), m_pWordLen[nCount] ) == 0 ||
00820 _tcsnicmp( m_pWordPtr[nCount], _T("bmp"), m_pWordLen[nCount] ) == 0 ||
00821
00822 _tcsnicmp( m_pWordPtr[nCount], _T("mpg"), m_pWordLen[nCount] ) == 0 ||
00823 _tcsnicmp( m_pWordPtr[nCount], _T("avi"), m_pWordLen[nCount] ) == 0 ||
00824 _tcsnicmp( m_pWordPtr[nCount], _T("mkv"), m_pWordLen[nCount] ) == 0 ||
00825 _tcsnicmp( m_pWordPtr[nCount], _T("wmv"), m_pWordLen[nCount] ) == 0 ||
00826 _tcsnicmp( m_pWordPtr[nCount], _T("mov"), m_pWordLen[nCount] ) == 0 ||
00827 _tcsnicmp( m_pWordPtr[nCount], _T("ogm"), m_pWordLen[nCount] ) == 0 ||
00828
00829 _tcsnicmp( m_pWordPtr[nCount], _T("exe"), m_pWordLen[nCount] ) == 0 ||
00830 _tcsnicmp( m_pWordPtr[nCount], _T("zip"), m_pWordLen[nCount] ) == 0 ||
00831 _tcsnicmp( m_pWordPtr[nCount], _T("rar"), m_pWordLen[nCount] ) == 0 ||
00832 _tcsnicmp( m_pWordPtr[nCount], _T("iso"), m_pWordLen[nCount] ) == 0 ||
00833 _tcsnicmp( m_pWordPtr[nCount], _T("bin"), m_pWordLen[nCount] ) == 0 ||
00834 _tcsnicmp( m_pWordPtr[nCount], _T("cue"), m_pWordLen[nCount] ) == 0 ||
00835
00836 _tcsnicmp( m_pWordPtr[nCount], _T("dvd"), m_pWordLen[nCount] ) == 0 ||
00837 _tcsnicmp( m_pWordPtr[nCount], _T("mpeg"), m_pWordLen[nCount] ) == 0 ||
00838 _tcsnicmp( m_pWordPtr[nCount], _T("divx"), m_pWordLen[nCount] ) == 0 ||
00839 _tcsnicmp( m_pWordPtr[nCount], _T("xvid"), m_pWordLen[nCount] ) == 0 ||
00840
00841 _tcsnicmp( m_pWordPtr[nCount], _T("xxx"), m_pWordLen[nCount] ) == 0 ||
00842 _tcsnicmp( m_pWordPtr[nCount], _T("sex"), m_pWordLen[nCount] ) == 0 ||
00843 _tcsnicmp( m_pWordPtr[nCount], _T("fuck"), m_pWordLen[nCount] ) == 0 ||
00844
00845 _tcsicmp( m_pWordPtr[nCount], _T("torrent") ) == 0 )
00846 {
00847
00848 }
00849 else
00850 {
00851
00852
00853
00854 if ( nCount == 0 )
00855 {
00856
00857 nValidWords++;
00858 nValidCharacters += m_pWordLen[nCount];
00859 }
00860 else if ( _tcsnicmp( m_pWordPtr[nCount], strLastWord.GetString(), m_pWordLen[nCount] ) != 0 )
00861 {
00862
00863 nValidWords++;
00864 nValidCharacters += m_pWordLen[nCount];
00865 }
00866
00867 strLastWord = m_pWordPtr[nCount];
00868 }
00869 }
00870
00871
00872 if ( ( nValidWords == 0 ) || ( nValidCharacters == 0) ) return FALSE;
00873
00874
00875 if ( bExtendedSearch )
00876 {
00877 if ( nValidCharacters < 2 ) return FALSE;
00878 }
00879 else if ( m_pSchema != NULL )
00880 {
00881 if ( nValidCharacters < 3 ) return FALSE;
00882 }
00883 else
00884 {
00885 if ( nValidCharacters < 4 ) return FALSE;
00886 }
00887
00888 return TRUE;
00889 }
00890
00892
00893
00894 BOOL CQuerySearch::Match(LPCTSTR pszFilename, QWORD nSize, LPCTSTR pszSchemaURI, CXMLElement* pXML, SHA1* pSHA1, TIGEROOT* pTiger, MD4* pED2K)
00895 {
00896 if ( nSize < m_nMinSize || nSize > m_nMaxSize ) return FALSE;
00897
00898 if ( m_bSHA1 )
00899 {
00900 return pSHA1 != NULL && ( m_pSHA1 == *pSHA1 );
00901 }
00902 else if ( m_bTiger )
00903 {
00904 return pTiger != NULL && ( m_pTiger == *pTiger );
00905 }
00906 else if ( m_bED2K )
00907 {
00908 return pED2K != NULL && ( memcmp( &m_pED2K, pED2K, sizeof(MD4) ) == 0 );
00909 }
00910
00911 if ( pszSchemaURI && *pszSchemaURI && pXML )
00912 {
00913 TRISTATE bResult = MatchMetadata( pszSchemaURI, pXML );
00914 if ( bResult != TS_UNKNOWN ) return ( bResult == TS_TRUE );
00915 if ( m_sSearch.GetLength() > 0 )
00916 {
00917 if ( MatchMetadataShallow( pszSchemaURI, pXML ) )
00918 {
00919
00920
00921 int nMinusPos = -1;
00922 BOOL bNegative = FALSE;
00923 if ( m_sSearch.GetLength() > 1 )
00924 {
00925 while ( !bNegative )
00926 {
00927 nMinusPos = m_sSearch.Find( '-', nMinusPos + 1 );
00928 if ( nMinusPos != -1 )
00929 bNegative = ( _istalnum( m_sSearch.GetAt( nMinusPos + 1 ) ) != 0 );
00930 else break;
00931 }
00932 }
00933 if ( bNegative )
00934 return WordMatch( pszFilename, m_sSearch );
00935 else return TRUE;
00936 }
00937 }
00938 }
00939
00940
00941 if ( m_bSimilarSearch )
00942 return TRUE;
00943 else
00944 return m_sSearch.GetLength() && WordMatch( pszFilename, m_sSearch );
00945 }
00946
00947 TRISTATE CQuerySearch::MatchMetadata(LPCTSTR pszSchemaURI, CXMLElement* pXML)
00948 {
00949 if ( ! m_pSchema || ! m_pXML ) return TS_UNKNOWN;
00950 if ( ! pszSchemaURI || ! *pszSchemaURI || ! pXML ) return TS_UNKNOWN;
00951 if ( ! m_pSchema->CheckURI( pszSchemaURI ) ) return TS_FALSE;
00952
00953 CXMLElement* pRoot = m_pXML->GetFirstElement();
00954 int nCount = 0;
00955
00956 for ( POSITION pos = m_pSchema->GetMemberIterator() ; pos ; )
00957 {
00958 CSchemaMember* pMember = m_pSchema->GetNextMember( pos );
00959
00960 CString strSearch = pMember->GetValueFrom( pRoot );
00961 CString strTarget = pMember->GetValueFrom( pXML );
00962
00963 if ( strSearch.GetLength() )
00964 {
00965 if ( strTarget.GetLength() )
00966 {
00967 if ( pMember->m_bNumeric )
00968 {
00969 if ( ! NumberMatch( strTarget, strSearch ) ) return TS_FALSE;
00970 }
00971 else
00972 {
00973 if ( ! WordMatch( strTarget, strSearch ) ) return TS_FALSE;
00974 }
00975
00976 nCount++;
00977 }
00978 else
00979 {
00980 return TS_FALSE;
00981 }
00982 }
00983 }
00984
00985 return ( nCount > 0 ) ? TS_TRUE : TS_UNKNOWN;
00986 }
00987
00988 BOOL CQuerySearch::MatchMetadataShallow(LPCTSTR pszSchemaURI, CXMLElement* pXML)
00989 {
00990 if ( ! pXML || m_sSearch.IsEmpty() ) return FALSE;
00991
00992 if ( CSchema* pSchema = SchemaCache.Get( pszSchemaURI ) )
00993 {
00994 for ( POSITION pos = pSchema->GetMemberIterator() ; pos ; )
00995 {
00996 CSchemaMember* pMember = pSchema->GetNextMember( pos );
00997
00998 if ( pMember->m_bSearched )
00999 {
01000 CString strTarget = pMember->GetValueFrom( pXML, _T(""), FALSE );
01001 if ( WordMatch( strTarget, m_sSearch ) ) return TRUE;
01002 }
01003 }
01004 }
01005 else
01006 {
01007 for ( POSITION pos = pXML->GetAttributeIterator() ; pos ; )
01008 {
01009 CXMLAttribute* pAttribute = pXML->GetNextAttribute( pos );
01010
01011 CString strTarget = pAttribute->GetValue();
01012
01013 if ( WordMatch( strTarget, m_sSearch ) ) return TRUE;
01014 }
01015 }
01016
01017 return FALSE;
01018 }
01019
01020 BOOL CQuerySearch::WordMatch(LPCTSTR pszString, LPCTSTR pszFind)
01021 {
01022 LPCTSTR pszWord = pszFind;
01023 LPCTSTR pszPtr = pszFind;
01024 BOOL bQuote = FALSE;
01025 BOOL bNegate = FALSE;
01026 BOOL bSpace = TRUE;
01027 int nCount = 0;
01028
01029 for ( ; *pszPtr ; pszPtr++ )
01030 {
01031 if ( ( bQuote && *pszPtr == '\"' ) || ( ! bQuote && ( *pszPtr <= ' ' || *pszPtr == '\t' || *pszPtr == '-' || *pszPtr == '\"' ) ) )
01032 {
01033 if ( pszWord < pszPtr )
01034 {
01035 if ( bNegate )
01036 {
01037 if ( _tcsnistr( pszString, pszWord, pszPtr - pszWord ) ) return FALSE;
01038 }
01039 else
01040 {
01041 if ( ! _tcsnistr( pszString, pszWord, pszPtr - pszWord ) ) return FALSE;
01042 }
01043
01044 nCount++;
01045 }
01046
01047 pszWord = pszPtr + 1;
01048
01049 if ( *pszPtr == '\"' )
01050 {
01051 bQuote = ! bQuote;
01052 bSpace = TRUE;
01053 }
01054 else if ( *pszPtr == '-' && pszPtr[1] != ' ' && bSpace && ! bQuote )
01055 {
01056 bNegate = TRUE;
01057 bSpace = FALSE;
01058 }
01059 else
01060 {
01061 bSpace = ( *pszPtr == ' ' );
01062 }
01063
01064 if ( bNegate && ! bQuote && *pszPtr != '-' ) bNegate = FALSE;
01065 }
01066 else
01067 {
01068 bSpace = FALSE;
01069 }
01070 }
01071
01072 if ( pszWord < pszPtr )
01073 {
01074 if ( bNegate )
01075 {
01076 if ( _tcsnistr( pszString, pszWord, pszPtr - pszWord ) ) return FALSE;
01077 }
01078 else
01079 {
01080 if ( ! _tcsnistr( pszString, pszWord, pszPtr - pszWord ) ) return FALSE;
01081 }
01082
01083 nCount++;
01084 }
01085
01086 return nCount > 0;
01087 }
01088
01089 BOOL CQuerySearch::NumberMatch(const CString& strValue, const CString& strRange)
01090 {
01091 double nValue, nMinimum, nMaximum;
01092
01093 if ( _stscanf( strValue, _T("%lf"), &nValue ) != 1 ) return FALSE;
01094
01095 int nPos = strRange.Find( '-' );
01096
01097 if ( nPos < 0 )
01098 {
01099 return _stscanf( strRange, _T("%lf"), &nMinimum ) == 1 && nValue == nMinimum;
01100 }
01101 else if ( nPos == 0 )
01102 {
01103 return _stscanf( (LPCTSTR)strRange + 1, _T("%lf"), &nMaximum ) && nValue <= nMaximum;
01104 }
01105 else if ( nPos == strRange.GetLength() - 1 )
01106 {
01107 return _stscanf( strRange, _T("%lf"), &nMinimum ) && nValue >= nMinimum;
01108 }
01109 else
01110 {
01111 if ( _stscanf( strRange.Left( nPos ), _T("%lf"), &nMinimum ) != 1 ||
01112 _stscanf( strRange.Mid( nPos + 1 ), _T("%lf"), &nMaximum ) != 1 ) return FALSE;
01113 return nValue >= nMinimum && nValue <= nMaximum;
01114 }
01115 }
01116
01118
01119
01120 void CQuerySearch::BuildWordList()
01121 {
01122 m_nWords = 0;
01123
01124 m_sSearch.Trim();
01125 ToLower( m_sSearch );
01126
01127
01128 Replace( m_sSearch, _T("\x03C3 "), _T("\x03C2 ") );
01129
01130 BOOL bHash = FALSE;
01131
01132 if ( 0 == _tcsncmp( m_sSearch, _T("magnet:?"), 8 ) )
01133 {
01134 int nURN = m_sSearch.Find( _T("urn:") );
01135
01136 if ( nURN > 0 )
01137 {
01138 m_sSearch = m_sSearch.Mid( nURN );
01139 bHash = TRUE;
01140 }
01141 }
01142
01143 if ( bHash || 0 == _tcsncmp( m_sSearch, _T("urn:"), 4 ) )
01144 {
01145 if ( ! m_bSHA1 )
01146 {
01147 if ( CSHA::HashFromURN( m_sSearch, &m_pSHA1 ) )
01148 {
01149 m_bSHA1 = TRUE;
01150 bHash = TRUE;
01151 }
01152 }
01153
01154 if ( ! m_bTiger )
01155 {
01156 if ( CTigerNode::HashFromURN( m_sSearch, &m_pTiger ) )
01157 {
01158 m_bTiger = TRUE;
01159 bHash = TRUE;
01160 }
01161 }
01162
01163 if ( ! m_bED2K )
01164 {
01165 if ( CED2K::HashFromURN( m_sSearch, &m_pED2K ) )
01166 {
01167 m_bED2K = TRUE;
01168 bHash = TRUE;
01169 }
01170 }
01171
01172 if ( bHash ) m_sSearch.Empty();
01173 }
01174
01175 AddStringToWordList( m_sSearch );
01176
01177 if ( m_pXML == NULL ) return;
01178
01179 if ( CXMLElement* pXML = m_pXML->GetFirstElement() )
01180 {
01181 if ( m_pSchema != NULL )
01182 {
01183 for ( POSITION pos = m_pSchema->GetMemberIterator() ; pos ; )
01184 {
01185 CSchemaMember* pMember = m_pSchema->GetNextMember( pos );
01186
01187 if ( pMember->m_bIndexed )
01188 {
01189 if ( CXMLAttribute* pAttribute = pXML->GetAttribute( pMember->m_sName ) )
01190 {
01191 CharLower( pAttribute->m_sValue.GetBuffer() );
01192 pAttribute->m_sValue.ReleaseBuffer();
01193 AddStringToWordList( pAttribute->m_sValue );
01194 }
01195 }
01196 }
01197 }
01198 else
01199 {
01200 for ( POSITION pos = pXML->GetAttributeIterator() ; pos ; )
01201 {
01202 CXMLAttribute* pAttribute = pXML->GetNextAttribute( pos );
01203 CharLower( pAttribute->m_sValue.GetBuffer() );
01204 pAttribute->m_sValue.ReleaseBuffer();
01205 AddStringToWordList( pAttribute->m_sValue );
01206 }
01207 }
01208 }
01209 }
01210
01211 void CQuerySearch::AddStringToWordList(LPCTSTR pszString)
01212 {
01213 if ( ! *pszString ) return;
01214
01215 LPCTSTR pszWord = pszString;
01216 LPCTSTR pszPtr = pszString;
01217 BOOL bQuote = FALSE;
01218 BOOL bNegate = FALSE;
01219 BOOL bSpace = TRUE;
01220
01221 for ( ; *pszPtr ; pszPtr++ )
01222 {
01223 if ( IsCharacter( *pszPtr ) )
01224 {
01225 bSpace = FALSE;
01226 }
01227 else
01228 {
01229 if ( ! bNegate && pszWord + 1 < pszPtr && IsWord( pszWord, 0, pszPtr - pszWord ) )
01230 {
01231 if ( ( m_nWords & 0x1F ) == 0 )
01232 {
01233 LPCTSTR* pWordPtr = new LPCTSTR[ ( m_nWords | 0x1F ) + 1 ];
01234 DWORD* pWordLen = new DWORD[ ( m_nWords | 0x1F ) + 1 ];
01235 if ( m_pWordPtr )
01236 {
01237 CopyMemory( pWordPtr, m_pWordPtr, 4 * m_nWords );
01238 CopyMemory( pWordLen, m_pWordLen, 4 * m_nWords );
01239 delete [] m_pWordPtr;
01240 delete [] m_pWordLen;
01241 }
01242 m_pWordPtr = pWordPtr;
01243 m_pWordLen = pWordLen;
01244 }
01245
01246 m_pWordPtr[ m_nWords ] = pszWord;
01247 m_pWordLen[ m_nWords ] = pszPtr - pszWord;
01248 m_nWords++;
01249 }
01250
01251 pszWord = pszPtr + 1;
01252
01253 if ( *pszPtr == '\"' )
01254 {
01255 bQuote = ! bQuote;
01256 bSpace = TRUE;
01257 }
01258 else if ( *pszPtr == '-' && pszPtr[1] != ' ' && bSpace && ! bQuote )
01259 {
01260 bNegate = TRUE;
01261 bSpace = FALSE;
01262 }
01263 else
01264 {
01265 bSpace = ( *pszPtr == ' ' );
01266 }
01267
01268 if ( bNegate && ! bQuote && *pszPtr != '-' ) bNegate = FALSE;
01269 }
01270 }
01271
01272 if ( ! bNegate && pszWord + 1 < pszPtr && IsWord( pszWord, 0, pszPtr - pszWord ) )
01273 {
01274 if ( ( m_nWords & 0x1F ) == 0 )
01275 {
01276 LPCTSTR* pWordPtr = new LPCTSTR[ ( m_nWords | 0x1F ) + 1 ];
01277 DWORD* pWordLen = new DWORD[ ( m_nWords | 0x1F ) + 1 ];
01278 if ( m_pWordPtr )
01279 {
01280 CopyMemory( pWordPtr, m_pWordPtr, 4 * m_nWords );
01281 CopyMemory( pWordLen, m_pWordLen, 4 * m_nWords );
01282 delete [] m_pWordPtr;
01283 delete [] m_pWordLen;
01284 }
01285 m_pWordPtr = pWordPtr;
01286 m_pWordLen = pWordLen;
01287 }
01288
01289 m_pWordPtr[ m_nWords ] = pszWord;
01290 m_pWordLen[ m_nWords ] = pszPtr - pszWord;
01291 m_nWords++;
01292 }
01293 }
01294
01296
01297
01298 void CQuerySearch::Serialize(CArchive& ar)
01299 {
01300 int nVersion = 6;
01301 CString strURI;
01302
01303 if ( ar.IsStoring() )
01304 {
01305 ar << nVersion;
01306
01307 ar.Write( &m_pGUID, sizeof(GGUID) );
01308
01309 ar << m_sSearch;
01310
01311 ar << m_bSHA1;
01312 if ( m_bSHA1 ) ar.Write( &m_pSHA1, sizeof(SHA1) );
01313 ar << m_bTiger;
01314 if ( m_bTiger ) ar.Write( &m_pTiger, sizeof(TIGEROOT) );
01315 ar << m_bED2K;
01316 if ( m_bED2K ) ar.Write( &m_pED2K, sizeof(MD4) );
01317 ar << m_bBTH;
01318 if ( m_bBTH ) ar.Write( &m_pBTH, sizeof(SHA1) );
01319
01320 if ( m_pSchema != NULL && m_pXML != NULL )
01321 {
01322 ar << m_pSchema->m_sURI;
01323 m_pXML->Serialize( ar );
01324 }
01325 else
01326 {
01327 ar << strURI;
01328 }
01329
01330 ar << m_bWantURL;
01331 ar << m_bWantDN;
01332 ar << m_bWantXML;
01333 ar << m_bWantCOM;
01334 ar << m_bWantPFS;
01335 }
01336 else
01337 {
01338 ar >> nVersion;
01339 if ( nVersion < 4 ) AfxThrowUserException();
01340
01341 ar.Read( &m_pGUID, sizeof(GGUID) );
01342
01343 ar >> m_sSearch;
01344
01345 ar >> m_bSHA1;
01346 if ( m_bSHA1 ) ar.Read( &m_pSHA1, sizeof(SHA1) );
01347 ar >> m_bTiger;
01348 if ( m_bTiger ) ar.Read( &m_pTiger, sizeof(TIGEROOT) );
01349 ar >> m_bED2K;
01350 if ( m_bED2K ) ar.Read( &m_pED2K, sizeof(MD4) );
01351 if ( nVersion >= 6 ) ar >> m_bBTH;
01352 if ( m_bBTH ) ar.Read( &m_pBTH, sizeof(SHA1) );
01353
01354 ar >> strURI;
01355
01356 if ( strURI.GetLength() )
01357 {
01358 m_pSchema = SchemaCache.Get( strURI );
01359 m_pXML = new CXMLElement();
01360 m_pXML->Serialize( ar );
01361 }
01362
01363 if ( nVersion >= 5 )
01364 {
01365 ar >> m_bWantURL;
01366 ar >> m_bWantDN;
01367 ar >> m_bWantXML;
01368 ar >> m_bWantCOM;
01369 ar >> m_bWantPFS;
01370 }
01371
01372 BuildWordList();
01373 }
01374 }
01375
01377
01378
01379 CSearchWnd* CQuerySearch::OpenWindow()
01380 {
01381 if ( this != NULL && CheckValid() )
01382 {
01383 return new CSearchWnd( this );
01384 }
01385 else
01386 {
01387 return NULL;
01388 }
01389 }