Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

QuerySearch.cpp

Go to the documentation of this file.
00001 //
00002 // QuerySearch.cpp
00003 //
00004 // Copyright (c) Shareaza Development Team, 2002-2005.
00005 // This file is part of SHAREAZA (www.shareaza.com)
00006 //
00007 // Shareaza is free software; you can redistribute it
00008 // and/or modify it under the terms of the GNU General Public License
00009 // as published by the Free Software Foundation; either version 2 of
00010 // the License, or (at your option) any later version.
00011 //
00012 // Shareaza is distributed in the hope that it will be useful,
00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 // GNU General Public License for more details.
00016 //
00017 // You should have received a copy of the GNU General Public License
00018 // along with Shareaza; if not, write to the Free Software
00019 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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 // CQuerySearch construction
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 // CQuerySearch to G1 packet
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 ) //Support UTF-8 Query
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 // CQuerySearch to G2 packet
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         //if ( m_bAndG1 ) pPacket->WritePacket( "G1", 0 );
00301         
00302         pPacket->WriteByte( 0 );
00303         pPacket->Write( &m_pGUID, sizeof(GGUID) );
00304         
00305         return pPacket;
00306 }
00307 
00309 // CQuerySearch to ED2K packet
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                         // We need the size- do a search by magnet (hash)
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                         // Don't need the size- use GETSOURCES
00343 
00344                         // For newer servers, send the file size if it's valid (and not over 4GB)
00345                         if ( ( bGetS2 ) && ( m_nMinSize == m_nMaxSize ) && ( m_nMaxSize < 0xFFFFFFFF ) )
00346                         {
00347                                 // theApp.Message( MSG_DEBUG, ( _T("Creating multi-hash capable GetSources2 for: ") + CED2K::HashToString( &m_pED2K ) ) );
00348 
00349                                 // Newer server, send size as well as hash
00350                                 pPacket = CEDPacket::New( bUDP ? ED2K_C2SG_GETSOURCES2 : ED2K_C2S_GETSOURCES );
00351                                 // Add the hash/size this packet is for
00352                                 pPacket->Write( &m_pED2K, sizeof(MD4) );
00353                                 pPacket->WriteLongLE( (DWORD)m_nMaxSize );
00354                                 // Add any other hashes that need to be searched for.
00355                                 WriteHashesToEDPacket( pPacket, bUDP );
00356 
00357                         }
00358                         else
00359                         {
00360                                 // Old style GetSources, with no size attached
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                 // BitTorrent searches prohibited unless they are GETSOURCES above
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                         // Add size limits to search (if available)
00377                         pPacket->WriteByte( 0 );                // Boolean AND (min/max) / (name/type)
00378                         pPacket->WriteByte( 0 );
00379                         
00380                         pPacket->WriteByte( 0 );                // Boolean AND (Min/Max)
00381                         pPacket->WriteByte( 0 );
00382                         
00383                         // Size limit (min)
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                         // Size limit (max)
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                         // ed2k search without file type
00401                         // Name / Key Words
00402                         pPacket->WriteByte( 1 );        
00403                         // Check if this is a "search for similar files"
00404                         if ( ( m_bSimilarSearch ) && ( ! bUDP ) && ( nServerFlags & ED2K_SERVER_TCP_RELATEDSEARCH ) )
00405                         {
00406                                 // This is a search for similar files
00407                                 CString strSearch;
00408                                 strSearch.Format( _T("related::%s"), (LPCTSTR)CED2K::HashToString( &m_pSimilarED2K ) );
00409                                 pPacket->WriteEDString( strSearch, bUTF8 );
00410                         }
00411                         else
00412                         {
00413                                 // Regular search
00414                                 pPacket->WriteEDString( m_sSearch.GetLength() ? m_sSearch : strWords, bUTF8 );
00415                         }
00416                 }
00417                 else
00418                 {       
00419                         // ed2k search including file type
00420                         pPacket->WriteByte( 0 );                // Boolean AND (name/type)
00421                         pPacket->WriteByte( 0 );
00422 
00423                         // Name / Key Words
00424                         pPacket->WriteByte( 1 );                
00425                         pPacket->WriteEDString( m_sSearch.GetLength() ? m_sSearch : strWords, bUTF8 );
00426 
00427                         // Metadata (file type)
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; // There's one hash in the packet to begin with
00447         DWORD tNow = GetTickCount();
00448 
00449         // Run through all active downloads
00450         for ( POSITION pos = Downloads.GetIterator() ; pos ; )
00451         {
00452                 CDownload* pDownload = Downloads.GetNext( pos );
00453                 
00454                 // Basic check
00455                 if ( pDownload->m_bED2K &&                                      // Must have an ed2k hash
00456                          pDownload->IsTrying() &&                               // Must be active
00457                          pDownload->m_nSize < 0xFFFFFFFF &&             // Must have a valid size
00458                          pDownload->IsCompleted() == FALSE &&   // Must not be complete
00459                          pDownload->NeedHashset() == FALSE &&   // Must have hashset
00460                          pDownload->m_pED2K != m_pED2K )                // Must not be already added to packet
00461                 {
00462                         // If a download is allowed to ask for more sources
00463                         DWORD tNextQuery = bUDP ? pDownload->m_tLastED2KGlobal + Settings.eDonkey.QueryFileThrottle : pDownload->m_tLastED2KLocal + Settings.eDonkey.QueryFileThrottle;
00464                         if ( tNow > tNextQuery )
00465                         {
00466                                 // If we want more sources for this file
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                                                 // Add the hash/size for this download
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 // CQuerySearch from packet root
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                         //if ( pSearch->ReadG1Packet( (CG1Packet*)pPacket ) ) return pSearch;
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 // CQuerySearch from G1 packet
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 ) //Support UTF-8 Query
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 // CQuerySearch from G2 packet
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;       // Hack
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 // CQuerySearch validity check
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         // Searches by hash are okay
00797         if ( m_bSHA1 || m_bTiger || m_bED2K || m_bBTH ) return TRUE;
00798 
00799         // Search without any terms and no hash is invalid
00800         if ( m_nWords == 0 ) return FALSE;
00801 
00802         // Check if it's an "extended search" (Using a character set with many symbols)
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         // Check we aren't just searching for broad terms-  set counters, etc
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                         // Common term. Don't count it.
00848                 }
00849                 else
00850                 {
00851                         // Valid search term.
00852 
00853                         // Check if user has duplicated terms
00854                         if ( nCount == 0 )
00855                         {
00856                                 // This is the first word- never a duplicate
00857                                 nValidWords++;
00858                                 nValidCharacters += m_pWordLen[nCount];
00859                         }
00860                         else if ( _tcsnicmp( m_pWordPtr[nCount], strLastWord.GetString(),  m_pWordLen[nCount] ) != 0 )
00861                         {
00862                                 // Valid search term, not duplicated. Add to the count of valid words/characters.
00863                                 nValidWords++;
00864                                 nValidCharacters += m_pWordLen[nCount];
00865                         }
00866                         // Update "last word" variable
00867                         strLastWord = m_pWordPtr[nCount];
00868                 }
00869         }
00870 
00871         // Check we have some valid terms to search on
00872         if ( ( nValidWords == 0 ) || ( nValidCharacters == 0) ) return FALSE;
00873 
00874         // Check we have a reasonable amount of characters to search on
00875         if ( bExtendedSearch )                                                                          // Searching for Chinese characters (2)
00876         {
00877                 if ( nValidCharacters < 2 ) return FALSE;
00878         }
00879         else if ( m_pSchema != NULL )                                                           // Search has schema (3)
00880         {
00881                 if ( nValidCharacters < 3 ) return FALSE;
00882         }
00883         else                                                                                                            // No schema (4)
00884         {
00885                 if ( nValidCharacters < 4 ) return FALSE;
00886         }
00887 
00888         return TRUE;
00889 }
00890 
00892 // CQuerySearch matching
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                                 // only return WordMatch when negative terms are used
00920                                 // otherwise, prefer metadata over file name.
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         // If it's a search for similar files, the text doesn't have to match
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 // CQuerySearch word list builder
01119 
01120 void CQuerySearch::BuildWordList()
01121 {
01122         m_nWords = 0;
01123         
01124         m_sSearch.Trim();
01125         ToLower( m_sSearch );
01126         // temporarily solution for last greek sigma fix
01127         // the phrase can contain punctuation marks and it won't work
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 // CQuerySearch serialization
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 // CQuerySearch open window
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 }

Generated on Thu Dec 15 10:39:46 2005 for Shareaza 2.2.1.0 by  doxygen 1.4.2