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 "LocalSearch.h"
00026
00027 #include "Library.h"
00028 #include "LibraryFolders.h"
00029 #include "SharedFile.h"
00030 #include "SharedFolder.h"
00031 #include "AlbumFolder.h"
00032
00033 #include "QuerySearch.h"
00034 #include "GProfile.h"
00035 #include "Network.h"
00036 #include "Neighbours.h"
00037 #include "Neighbour.h"
00038 #include "Datagrams.h"
00039 #include "G1Packet.h"
00040 #include "G2Packet.h"
00041 #include "Buffer.h"
00042 #include "ZLib.h"
00043 #include "GGEP.h"
00044 #include "BTClients.h"
00045
00046 #include "Transfers.h"
00047 #include "Downloads.h"
00048 #include "Download.h"
00049 #include "Uploads.h"
00050 #include "UploadQueue.h"
00051 #include "UploadQueues.h"
00052
00053 #include "XML.h"
00054 #include "Schema.h"
00055 #include "SchemaCache.h"
00056
00057 #include "SHA.h"
00058 #include "TigerTree.h"
00059 #include "ED2K.h"
00060
00061 #ifdef _DEBUG
00062 #undef THIS_FILE
00063 static char THIS_FILE[]=__FILE__;
00064 #define new DEBUG_NEW
00065 #endif
00066
00067
00069
00070
00071 CLocalSearch::CLocalSearch(CQuerySearch* pSearch, CNeighbour* pNeighbour, BOOL bWrapped)
00072 {
00073 m_pSearch = pSearch;
00074 m_pNeighbour = pNeighbour;
00075 m_pEndpoint = NULL;
00076 m_pBuffer = NULL;
00077 m_nTTL = Settings.Gnutella1.MaximumTTL - 3;
00078 m_nProtocol = pNeighbour->m_nProtocol;
00079 m_bWrapped = bWrapped;
00080 m_pPacket = NULL;
00081
00082 if ( m_bWrapped ) m_nProtocol = PROTOCOL_G1;
00083 }
00084
00085 CLocalSearch::CLocalSearch(CQuerySearch* pSearch, SOCKADDR_IN* pEndpoint)
00086 {
00087 m_pSearch = pSearch;
00088 m_pNeighbour = NULL;
00089 m_pEndpoint = pEndpoint;
00090 m_pBuffer = NULL;
00091 m_nTTL = Settings.Gnutella1.MaximumTTL - 3;
00092 m_nProtocol = PROTOCOL_G2;
00093 m_bWrapped = FALSE;
00094 m_pPacket = NULL;
00095 }
00096
00097 CLocalSearch::CLocalSearch(CQuerySearch* pSearch, CBuffer* pBuffer, PROTOCOLID nProtocol)
00098 {
00099 m_pSearch = pSearch;
00100 m_pNeighbour = NULL;
00101 m_pEndpoint = NULL;
00102 m_pBuffer = pBuffer;
00103 m_nTTL = Settings.Gnutella1.MaximumTTL - 3;
00104 m_nProtocol = nProtocol;
00105 m_bWrapped = FALSE;
00106 m_pPacket = NULL;
00107 }
00108
00109 CLocalSearch::~CLocalSearch()
00110 {
00111 GetXMLString();
00112 }
00113
00115
00116
00117 int CLocalSearch::Execute(int nMaximum)
00118 {
00119 if ( m_pBuffer == NULL )
00120 {
00121 if ( UploadQueues.GetQueueRemaining() == 0 ) return 0;
00122 }
00123
00124 if ( nMaximum < 0 ) nMaximum = Settings.Gnutella.MaxHits;
00125
00126 if ( m_pSearch )
00127 {
00128 m_pGUID = m_pSearch->m_pGUID;
00129 }
00130 else
00131 {
00132 Network.CreateID( m_pGUID );
00133 }
00134
00135 int nCount = ExecuteSharedFiles( nMaximum );
00136
00137 if ( m_pSearch != NULL && m_pSearch->m_bWantPFS && m_nProtocol == PROTOCOL_G2 )
00138 {
00139 if ( nMaximum == 0 || nCount < nMaximum )
00140 {
00141 nCount += ExecutePartialFiles( nMaximum ? nMaximum - nCount : 0 );
00142 }
00143 }
00144
00145 return nCount;
00146 }
00147
00149
00150
00151 int CLocalSearch::ExecuteSharedFiles(int nMaximum)
00152 {
00153 CQuickLock oLock( Library.m_pSection );
00154 CPtrList* pFiles = Library.Search( m_pSearch, nMaximum );
00155 if ( pFiles == NULL ) return 0;
00156
00157 int nHits = pFiles->GetCount();
00158
00159 while ( pFiles->GetCount() )
00160 {
00161 int nInThisPacket = min( pFiles->GetCount(), (int)Settings.Gnutella.HitsPerPacket );
00162
00163 CreatePacket( nInThisPacket );
00164
00165 int nHitB = 0;
00166 for ( int nHitA = 0 ; nHitA < nInThisPacket ; nHitA++ )
00167 {
00168 CLibraryFile* pFile = (CLibraryFile*)pFiles->RemoveHead();
00169 if ( AddHit( pFile, nHitB ) ) nHitB ++;
00170 }
00171
00172 WriteTrailer();
00173 if ( nHitB > 0 ) DispatchPacket(); else DestroyPacket();
00174 }
00175
00176 delete pFiles;
00177
00178 return nHits;
00179 }
00180
00182
00183
00184 BOOL CLocalSearch::AddHit(CLibraryFile* pFile, int nIndex)
00185 {
00186 ASSERT( m_pPacket != NULL );
00187
00188 if ( m_nProtocol == PROTOCOL_G1 )
00189 {
00190 if ( ! Settings.Gnutella1.EnableToday )
00191 {
00192 theApp.Message( MSG_ERROR, _T("CLocalSearch::AddHit() dropping G1 hit G1- network not enabled ") );
00193 return FALSE;
00194 }
00195 if ( ! AddHitG1( pFile, nIndex ) ) return FALSE;
00196 }
00197 else
00198 {
00199 if ( ! AddHitG2( pFile, nIndex ) ) return FALSE;
00200 }
00201
00202 return TRUE;
00203 }
00204
00205 BOOL CLocalSearch::AddHitG1(CLibraryFile* pFile, int nIndex)
00206 {
00207
00208 if ( ! pFile->IsAvailable() ) return FALSE;
00209
00210
00211 if ( UploadQueues.QueueRank( PROTOCOL_HTTP, pFile ) > Settings.Gnutella1.HitQueueLimit ) return FALSE;
00212
00213
00214
00215
00216
00217 m_pPacket->WriteLongLE( pFile->m_nIndex );
00218 m_pPacket->WriteLongLE( (DWORD)min( pFile->GetSize(), QWORD(0xFFFFFFFF) ) );
00219 if ( Settings.Gnutella1.QueryHitUTF8 )
00220 {
00221 m_pPacket->WriteStringUTF8( pFile->m_sName );
00222 }
00223 else
00224 {
00225 m_pPacket->WriteString( pFile->m_sName );
00226 }
00227
00228 if ( pFile->m_bSHA1 )
00229 {
00230 CString strHash = CSHA::HashToString( &pFile->m_pSHA1, TRUE );
00231 m_pPacket->WriteString( strHash );
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243 }
00244 else if ( pFile->m_bTiger )
00245 {
00246 CString strHash = CTigerNode::HashToString( &pFile->m_pTiger, TRUE );
00247 m_pPacket->WriteString( strHash );
00248 }
00249 else if ( pFile->m_bED2K )
00250 {
00251 CString strHash = CED2K::HashToString( &pFile->m_pED2K, TRUE );
00252 m_pPacket->WriteString( strHash );
00253 }
00254 else
00255 {
00256 m_pPacket->WriteByte( 0 );
00257 }
00258
00259 if ( pFile->m_pSchema != NULL && pFile->m_pMetadata != NULL && ( m_pSearch == NULL || m_pSearch->m_bWantXML ) )
00260 {
00261 AddMetadata( pFile->m_pSchema, pFile->m_pMetadata, nIndex );
00262 }
00263
00264 return TRUE;
00265 }
00266
00267 BOOL CLocalSearch::AddHitG2(CLibraryFile* pFile, int nIndex)
00268 {
00269 CG2Packet* pPacket = (CG2Packet*)m_pPacket;
00270 CString strMetadata, strComment;
00271 BOOL bCollection = FALSE;
00272 BOOL bPreview = FALSE;
00273 DWORD nGroup = 0;
00274
00275
00276
00277 if ( pFile->m_bTiger && pFile->m_bSHA1 )
00278 {
00279 nGroup += 5 + 3 + sizeof(SHA1) + sizeof(TIGEROOT);
00280 }
00281 else if ( pFile->m_bTiger )
00282 {
00283 nGroup += 5 + 4 + sizeof(TIGEROOT);
00284 }
00285 else if ( pFile->m_bSHA1 )
00286 {
00287 nGroup += 5 + 5 + sizeof(SHA1);
00288 }
00289
00290 if ( pFile->m_bED2K )
00291 {
00292 nGroup += 5 + 5 + sizeof(MD4);
00293 }
00294
00295 if ( m_pSearch == NULL || m_pSearch->m_bWantDN )
00296 {
00297 if ( pFile->GetSize() <= 0xFFFFFFFF )
00298 {
00299 nGroup += 8 + pPacket->GetStringLen( pFile->m_sName );
00300 }
00301 else
00302 {
00303 nGroup += 4 + 8;
00304 nGroup += 4 + pPacket->GetStringLen( pFile->m_sName );
00305 }
00306
00307 if ( LPCTSTR pszType = _tcsrchr( pFile->m_sName, '.' ) )
00308 {
00309 if ( _tcsicmp( pszType, _T(".co") ) == 0 ||
00310 _tcsicmp( pszType, _T(".collection") ) == 0 )
00311 {
00312 if ( ! pFile->m_bBogus )
00313 {
00314 nGroup += 2 + 7;
00315 bCollection = TRUE;
00316 }
00317 }
00318 }
00319 }
00320
00321 if ( pFile->IsAvailable() && ( m_pSearch == NULL || m_pSearch->m_bWantURL ) )
00322 {
00323 nGroup += 5;
00324 if ( pFile->m_pSources.GetCount() ) nGroup += 7;
00325
00326 if ( Settings.Uploads.SharePreviews )
00327 {
00328 if ( pFile->m_bCachedPreview ||
00329 _tcsistr( pFile->m_sName, _T(".jpg") ) ||
00330 _tcsistr( pFile->m_sName, _T(".png") ) )
00331 {
00332 bPreview = TRUE;
00333 }
00334 }
00335
00336 if ( bPreview ) nGroup += 5;
00337 }
00338
00339 if ( pFile->m_pMetadata != NULL && ( m_pSearch == NULL || m_pSearch->m_bWantXML ) )
00340 {
00341 strMetadata = pFile->m_pMetadata->ToString();
00342 int nMetadata = pPacket->GetStringLen( strMetadata );
00343 nGroup += 4 + nMetadata;
00344 if ( nMetadata > 0xFF )
00345 {
00346 nGroup ++;
00347 if ( nMetadata > 0xFFFF ) nGroup ++;
00348 }
00349 }
00350
00351 if ( m_pSearch == NULL || m_pSearch->m_bWantCOM )
00352 {
00353 if ( pFile->m_nRating > 0 || pFile->m_sComments.GetLength() > 0 )
00354 {
00355 if ( pFile->m_nRating > 0 )
00356 {
00357 strComment.Format( _T("<comment rating=\"%i\">"), pFile->m_nRating - 1 );
00358 CXMLNode::ValueToString( pFile->m_sComments, strComment );
00359 if ( strComment.GetLength() > 2048 ) strComment = strComment.Left( 2048 );
00360 strComment += _T("</comment>");
00361 }
00362 else
00363 {
00364 strComment = _T("<comment>");
00365 CXMLNode::ValueToString( pFile->m_sComments, strComment );
00366 if ( strComment.GetLength() > 2048 ) strComment = strComment.Left( 2048 );
00367 strComment += _T("</comment>");
00368 }
00369
00370 Replace( strComment, _T("\r\n"), _T("{n}") );
00371 int nComment = pPacket->GetStringLen( strComment );
00372 nGroup += 5 + nComment;
00373 if ( nComment > 0xFF )
00374 {
00375 nGroup ++;
00376 if ( nComment > 0xFFFF ) nGroup ++;
00377 }
00378 }
00379
00380 if ( pFile->m_bBogus ) nGroup += 7;
00381 }
00382 else
00383 {
00384 if ( ! pFile->IsAvailable() ) return FALSE;
00385 }
00386
00387 if ( m_pSearch == NULL ) nGroup += 8;
00388
00389 nGroup += 4;
00390
00391
00392
00393 pPacket->WritePacket( "H", nGroup, TRUE );
00394
00395 if ( pFile->m_bTiger && pFile->m_bSHA1 )
00396 {
00397 pPacket->WritePacket( "URN", 3 + sizeof(SHA1) + sizeof(TIGEROOT) );
00398 pPacket->WriteString( "bp" );
00399 pPacket->Write( &pFile->m_pSHA1, sizeof(SHA1) );
00400 pPacket->Write( &pFile->m_pTiger, sizeof(TIGEROOT) );
00401 }
00402 else if ( pFile->m_bTiger )
00403 {
00404 pPacket->WritePacket( "URN", 4 + sizeof(TIGEROOT) );
00405 pPacket->WriteString( "ttr" );
00406 pPacket->Write( &pFile->m_pTiger, sizeof(TIGEROOT) );
00407 }
00408 else if ( pFile->m_bSHA1 )
00409 {
00410 pPacket->WritePacket( "URN", 5 + sizeof(SHA1) );
00411 pPacket->WriteString( "sha1" );
00412 pPacket->Write( &pFile->m_pSHA1, sizeof(SHA1) );
00413 }
00414
00415 if ( pFile->m_bED2K )
00416 {
00417 pPacket->WritePacket( "URN", 5 + sizeof(MD4) );
00418 pPacket->WriteString( "ed2k" );
00419 pPacket->Write( &pFile->m_pED2K, sizeof(MD4) );
00420 }
00421
00422 if ( m_pSearch == NULL || m_pSearch->m_bWantDN )
00423 {
00424 if ( pFile->GetSize() <= 0xFFFFFFFF )
00425 {
00426 pPacket->WritePacket( "DN", pPacket->GetStringLen( pFile->m_sName ) + 4 );
00427 pPacket->WriteLongBE( (DWORD)pFile->GetSize() );
00428 pPacket->WriteString( pFile->m_sName, FALSE );
00429 }
00430 else
00431 {
00432 pPacket->WritePacket( "SZ", 8 );
00433 pPacket->WriteInt64( pFile->GetSize() );
00434 pPacket->WritePacket( "DN", pPacket->GetStringLen( pFile->m_sName ) );
00435 pPacket->WriteString( pFile->m_sName, FALSE );
00436 }
00437
00438 if ( bCollection ) pPacket->WritePacket( "COLLECT", 0 );
00439 }
00440
00441 {
00442 CSingleLock pQueueLock( &UploadQueues.m_pSection, TRUE );
00443
00444 CUploadQueue* pQueue = UploadQueues.SelectQueue( PROTOCOL_HTTP, pFile );
00445 pPacket->WritePacket( "G", 1 );
00446 pPacket->WriteByte( pQueue ? pQueue->m_nIndex + 1 : 0 );
00447 }
00448
00449 if ( pFile->IsAvailable() && ( m_pSearch == NULL || m_pSearch->m_bWantURL ) )
00450 {
00451 pPacket->WritePacket( "URL", 0 );
00452
00453 if ( int nCount = pFile->m_pSources.GetCount() )
00454 {
00455 pPacket->WritePacket( "CSC", 2 );
00456 pPacket->WriteShortBE( (WORD)nCount );
00457 }
00458
00459 if ( bPreview )
00460 {
00461 pPacket->WritePacket( "PVU", 0 );
00462 }
00463 }
00464
00465 if ( strMetadata.GetLength() )
00466 {
00467 pPacket->WritePacket( "MD", pPacket->GetStringLen( strMetadata ) );
00468 pPacket->WriteString( strMetadata, FALSE );
00469 }
00470
00471 if ( m_pSearch == NULL || m_pSearch->m_bWantCOM )
00472 {
00473 if ( strComment.GetLength() )
00474 {
00475 pPacket->WritePacket( "COM", pPacket->GetStringLen( strComment ) );
00476 pPacket->WriteString( strComment, FALSE );
00477 }
00478
00479 if ( pFile->m_bBogus ) pPacket->WritePacket( "BOGUS", 0 );
00480 }
00481
00482 if ( m_pSearch == NULL )
00483 {
00484 pPacket->WritePacket( "ID", 4 );
00485 pPacket->WriteLongBE( pFile->m_nIndex );
00486 }
00487
00488 return TRUE;
00489 }
00490
00492
00493
00494 int CLocalSearch::ExecutePartialFiles(int nMaximum)
00495 {
00496 ASSERT( m_nProtocol == PROTOCOL_G2 );
00497 ASSERT( m_pSearch != NULL );
00498
00499 if ( m_pSearch->m_bTiger == FALSE && m_pSearch->m_bSHA1 == FALSE &&
00500 m_pSearch->m_bED2K == FALSE && m_pSearch->m_bBTH == FALSE ) return 0;
00501
00502 CSingleLock pLock( &Transfers.m_pSection );
00503 if ( ! pLock.Lock( 50 ) ) return 0;
00504
00505 int nCount = 0;
00506 m_pPacket = NULL;
00507
00508 for ( POSITION pos = Downloads.GetIterator() ; pos ; )
00509 {
00510 CDownload* pDownload = Downloads.GetNext( pos );
00511
00512 if ( ! pDownload->IsShared() ) continue;
00513
00514 if ( ( m_pSearch->m_bTiger && pDownload->m_bTiger && m_pSearch->m_pTiger == pDownload->m_pTiger )
00515 || ( m_pSearch->m_bSHA1 && pDownload->m_bSHA1 && m_pSearch->m_pSHA1 == pDownload->m_pSHA1 )
00516 || ( m_pSearch->m_bED2K && pDownload->m_bED2K && m_pSearch->m_pED2K == pDownload->m_pED2K )
00517 || ( m_pSearch->m_bBTH && pDownload->m_bBTH && m_pSearch->m_pBTH == pDownload->m_pBTH ) )
00518 {
00519 if ( pDownload->m_bBTH || pDownload->IsStarted() )
00520 {
00521 if ( m_pPacket == NULL ) CreatePacketG2();
00522 AddHit( pDownload, nCount++ );
00523 }
00524 }
00525 }
00526
00527 if ( m_pPacket != NULL )
00528 {
00529 WriteTrailerG2();
00530 DispatchPacket();
00531 }
00532
00533 return nCount;
00534 }
00535
00537
00538
00539 void CLocalSearch::AddHit(CDownload* pDownload, int nIndex)
00540 {
00541 ASSERT( m_pPacket != NULL );
00542 CG2Packet* pPacket = (CG2Packet*)m_pPacket;
00543 DWORD nGroup = 2 + 4 + 4;
00544 CString strURL;
00545
00546 if ( pDownload->m_bTiger && pDownload->m_bSHA1 )
00547 {
00548 nGroup += 5 + 3 + sizeof(SHA1) + sizeof(TIGEROOT);
00549 }
00550 else if ( pDownload->m_bSHA1 )
00551 {
00552 nGroup += 5 + 5 + sizeof(SHA1);
00553 }
00554 else if ( pDownload->m_bTiger )
00555 {
00556 nGroup += 5 + 4 + sizeof(TIGEROOT);
00557 }
00558
00559 if ( pDownload->m_bED2K )
00560 {
00561 nGroup += 5 + 5 + sizeof(MD4);
00562 }
00563
00564 if ( pDownload->m_bBTH )
00565 {
00566 nGroup += 5 + 5 + sizeof(SHA1);
00567 }
00568
00569 if ( m_pSearch->m_bWantDN )
00570 {
00571 nGroup += 8 + pPacket->GetStringLen( pDownload->m_sRemoteName );
00572 }
00573
00574 if ( m_pSearch->m_bWantURL )
00575 {
00576 nGroup += 5;
00577
00578
00579
00580 if ( m_pSearch->m_bBTH && pDownload->m_pTorrent.IsAvailable() && Network.m_pHost.sin_addr.S_un.S_addr != 0 )
00581 {
00582 strURL.Format( _T("btc://%s:%i/%s/%s/"),
00583 (LPCTSTR)CString( inet_ntoa( Network.m_pHost.sin_addr ) ),
00584 htons( Network.m_pHost.sin_port ),
00585 (LPCTSTR)CSHA::HashToString( &pDownload->m_pPeerID ),
00586 (LPCTSTR)CSHA::HashToString( &pDownload->m_pBTH ) );
00587 nGroup += pPacket->GetStringLen( strURL );
00588 }
00589 }
00590
00591 pPacket->WritePacket( "H", nGroup, TRUE );
00592
00593 if ( pDownload->m_bTiger && pDownload->m_bSHA1 )
00594 {
00595 pPacket->WritePacket( "URN", 3 + sizeof(SHA1) + sizeof(TIGEROOT) );
00596 pPacket->WriteString( "bp" );
00597 pPacket->Write( &pDownload->m_pSHA1, sizeof(SHA1) );
00598 pPacket->Write( &pDownload->m_pTiger, sizeof(TIGEROOT) );
00599 }
00600 else if ( pDownload->m_bTiger )
00601 {
00602 pPacket->WritePacket( "URN", 4 + sizeof(TIGEROOT) );
00603 pPacket->WriteString( "ttr" );
00604 pPacket->Write( &pDownload->m_pTiger, sizeof(TIGEROOT) );
00605 }
00606 else if ( pDownload->m_bSHA1 )
00607 {
00608 pPacket->WritePacket( "URN", 5 + sizeof(SHA1) );
00609 pPacket->WriteString( "sha1" );
00610 pPacket->Write( &pDownload->m_pSHA1, sizeof(SHA1) );
00611 }
00612
00613 if ( pDownload->m_bED2K )
00614 {
00615 pPacket->WritePacket( "URN", 5 + sizeof(MD4) );
00616 pPacket->WriteString( "ed2k" );
00617 pPacket->Write( &pDownload->m_pED2K, sizeof(MD4) );
00618 }
00619
00620 if ( pDownload->m_bBTH )
00621 {
00622 pPacket->WritePacket( "URN", 5 + sizeof(SHA1) );
00623 pPacket->WriteString( "btih" );
00624 pPacket->Write( &pDownload->m_pBTH, sizeof(SHA1) );
00625 }
00626
00627 if ( m_pSearch->m_bWantDN )
00628 {
00629 if ( pDownload->m_nSize <= 0xFFFFFFFF )
00630 {
00631 pPacket->WritePacket( "DN", pPacket->GetStringLen( pDownload->m_sRemoteName ) + 4 );
00632 pPacket->WriteLongBE( (DWORD)pDownload->m_nSize );
00633 pPacket->WriteString( pDownload->m_sRemoteName, FALSE );
00634 }
00635 else
00636 {
00637 pPacket->WritePacket( "SZ", 8 );
00638 pPacket->WriteInt64( pDownload->m_nSize );
00639 pPacket->WritePacket( "DN", pPacket->GetStringLen( pDownload->m_sRemoteName ) );
00640 pPacket->WriteString( pDownload->m_sRemoteName, FALSE );
00641 }
00642 }
00643
00644 if ( m_pSearch->m_bWantURL )
00645 {
00646 if ( strURL.GetLength() > 0 )
00647 {
00648 pPacket->WritePacket( "URL", pPacket->GetStringLen( strURL ) );
00649 pPacket->WriteString( strURL, FALSE );
00650 }
00651 else
00652 {
00653 pPacket->WritePacket( "URL", 0 );
00654 }
00655 }
00656
00657 QWORD nComplete = pDownload->GetVolumeComplete();
00658
00659 if ( nComplete <= 0xFFFFFFFF )
00660 {
00661 pPacket->WritePacket( "PART", 4 );
00662 pPacket->WriteLongBE( (DWORD)nComplete );
00663 }
00664 else
00665 {
00666 pPacket->WritePacket( "PART", 8 );
00667 pPacket->WriteInt64( nComplete );
00668 }
00669 }
00670
00672
00673
00674 void CLocalSearch::CreatePacket(int nCount)
00675 {
00676 ASSERT( m_pPacket == NULL );
00677
00678 if ( m_nProtocol == PROTOCOL_G1 )
00679 CreatePacketG1( nCount );
00680 else
00681 CreatePacketG2();
00682
00683 if ( m_pSchemas.GetCount() ) GetXMLString();
00684 }
00685
00686 void CLocalSearch::CreatePacketG1(int nCount)
00687 {
00688 m_pPacket = CG1Packet::New( G1_PACKET_HIT, m_nTTL, &m_pGUID );
00689
00690 m_pPacket->WriteByte( nCount );
00691 m_pPacket->WriteShortLE( htons( Network.m_pHost.sin_port ) );
00692 m_pPacket->WriteLongLE( Network.m_pHost.sin_addr.S_un.S_addr );
00693
00694 if ( Uploads.m_bStable )
00695 {
00696 m_pPacket->WriteLongLE( Uploads.m_nBestSpeed * 8 / 1024 );
00697 }
00698 else
00699 {
00700 m_pPacket->WriteLongLE( Settings.Connection.OutSpeed );
00701 }
00702 }
00703
00704 void CLocalSearch::CreatePacketG2()
00705 {
00706 CG2Packet* pPacket = CG2Packet::New( G2_PACKET_HIT, TRUE );
00707 m_pPacket = pPacket;
00708
00709 pPacket->WritePacket( "GU", 16 );
00710 GGUID tmp( MyProfile.GUID );
00711 pPacket->Write( &tmp, sizeof(GGUID) );
00712
00713 if ( TRUE )
00714 {
00715 pPacket->WritePacket( "NA", 6 );
00716 pPacket->WriteLongLE( Network.m_pHost.sin_addr.S_un.S_addr );
00717 pPacket->WriteShortBE( htons( Network.m_pHost.sin_port ) );
00718 }
00719
00720 pPacket->WritePacket( "V", 4 );
00721 pPacket->WriteString( SHAREAZA_VENDOR_A, FALSE );
00722
00723 if ( ! Network.IsStable() || ! Datagrams.IsStable() )
00724 {
00725 pPacket->WritePacket( "FW", 0 );
00726 }
00727
00728 {
00729 CSingleLock pNetLock( &Network.m_pSection );
00730
00731 if ( pNetLock.Lock( 50 ) )
00732 {
00733 for ( POSITION pos = Neighbours.GetIterator() ; pos ; )
00734 {
00735 CNeighbour* pNeighbour = Neighbours.GetNext( pos );
00736
00737 if ( pNeighbour->m_nNodeType != ntLeaf &&
00738 pNeighbour->m_nProtocol == PROTOCOL_G2 )
00739 {
00740 pPacket->WritePacket( "NH", 6 );
00741 pPacket->WriteLongLE( pNeighbour->m_pHost.sin_addr.S_un.S_addr );
00742 pPacket->WriteShortBE( htons( pNeighbour->m_pHost.sin_port ) );
00743 }
00744 }
00745 }
00746 }
00747
00748 if ( ! Uploads.m_bStable ) pPacket->WritePacket( "UNSTA", 0 );
00749
00750 CSingleLock pQueueLock( &UploadQueues.m_pSection );
00751 int nQueue = 1;
00752
00753 if ( pQueueLock.Lock() )
00754 {
00755 for ( POSITION pos = UploadQueues.GetIterator() ; pos ; nQueue++ )
00756 {
00757 CUploadQueue* pQueue = UploadQueues.GetNext( pos );
00758 pPacket->WritePacket( "HG", ( 4 + 7 ) + 2, TRUE );
00759 pPacket->WritePacket( "SS", 7 );
00760 pPacket->WriteShortBE( pQueue->GetQueuedCount() + pQueue->GetTransferCount() );
00761 pPacket->WriteByte( pQueue->GetTransferCount( TRUE ) );
00762 pPacket->WriteLongBE( pQueue->GetPredictedBandwidth() * 8 / 1024 );
00763 pPacket->WriteByte( 0 );
00764 pPacket->WriteByte( nQueue );
00765 }
00766
00767 pQueueLock.Unlock();
00768 }
00769
00770 CString strNick = MyProfile.GetNick();
00771 if ( strNick.GetLength() > 32 ) strNick = strNick.Left( 32 );
00772
00773 if ( strNick.GetLength() )
00774 {
00775 int nNick = pPacket->GetStringLen( strNick );
00776 pPacket->WritePacket( "UPRO", nNick + 6, TRUE );
00777 pPacket->WritePacket( "NICK", nNick );
00778 pPacket->WriteString( strNick, FALSE );
00779 }
00780
00781 if ( Settings.Community.ServeProfile ) pPacket->WritePacket( "BUP", 0 );
00782 if ( Settings.Community.ServeFiles ) pPacket->WritePacket( "BH", 0 );
00783 if ( Settings.Community.ChatEnable ) pPacket->WritePacket( "PCH", 0 );
00784 }
00785
00787
00788
00789 void CLocalSearch::AddMetadata(CSchema* pSchema, CXMLElement* pXML, int nIndex)
00790 {
00791 ASSERT( pSchema != NULL );
00792 ASSERT( pXML != NULL );
00793 ASSERT( pXML->GetParent() == NULL );
00794
00795 CXMLElement* pGroup;
00796
00797 if ( ! m_pSchemas.Lookup( pSchema, (void*&)pGroup ) )
00798 {
00799 pGroup = pSchema->Instantiate();
00800 m_pSchemas.SetAt( pSchema, pGroup );
00801 }
00802
00803 CString strIndex;
00804 strIndex.Format( _T("%lu"), nIndex );
00805
00806 pXML->AddAttribute( _T("index"), strIndex );
00807 pGroup->AddElement( pXML );
00808 }
00809
00811
00812
00813 CString CLocalSearch::GetXMLString()
00814 {
00815 CString strXML;
00816
00817 for ( POSITION pos1 = m_pSchemas.GetStartPosition() ; pos1 ; )
00818 {
00819 CXMLElement* pGroup;
00820 CSchema* pSchema;
00821
00822 m_pSchemas.GetNextAssoc( pos1, (void*&)pSchema, (void*&)pGroup );
00823
00824 strXML += _T("<?xml version=\"1.0\"?>\r\n");
00825 pGroup->ToString( strXML, TRUE );
00826
00827 for ( POSITION pos2 = pGroup->GetElementIterator() ; pos2 ; )
00828 {
00829 CXMLElement* pChild = pGroup->GetNextElement( pos2 );
00830 pChild->DeleteAttribute( _T("index") );
00831 pChild->Detach();
00832 }
00833
00834 delete pGroup;
00835 }
00836
00837 m_pSchemas.RemoveAll();
00838
00839 return strXML;
00840 }
00841
00843
00844
00845 void CLocalSearch::WriteTrailer()
00846 {
00847 ASSERT( m_pPacket != NULL );
00848
00849 if ( m_nProtocol == PROTOCOL_G1 )
00850 WriteTrailerG1();
00851 else
00852 WriteTrailerG2();
00853 }
00854
00855 void CLocalSearch::WriteTrailerG1()
00856 {
00857 m_pPacket->WriteString( SHAREAZA_VENDOR_T, FALSE );
00858
00859 BYTE nFlags[2] = { 0, 0 };
00860
00861 nFlags[0] |= G1_QHD_BUSY|G1_QHD_STABLE|G1_QHD_SPEED;
00862 nFlags[1] |= G1_QHD_PUSH;
00863
00864 if ( ! Network.IsListening() ) nFlags[0] |= G1_QHD_PUSH;
00865 if ( Uploads.m_bStable ) nFlags[1] |= G1_QHD_STABLE;
00866 if ( Uploads.m_bStable ) nFlags[1] |= G1_QHD_SPEED;
00867 if ( ! UploadQueues.IsTransferAvailable() ) nFlags[1] |= G1_QHD_BUSY;
00868
00869 if ( Settings.Community.ServeFiles && Settings.Gnutella1.EnableGGEP )
00870 {
00871 nFlags[0] |= G1_QHD_GGEP;
00872 nFlags[1] |= G1_QHD_GGEP;
00873 }
00874
00875 CString strXML = GetXMLString();
00876 DWORD nCompressed = 0;
00877 BYTE* pCompressed = NULL;
00878
00879 m_pPacket->WriteByte( strXML.IsEmpty() ? 2 : 4 );
00880 m_pPacket->WriteByte( nFlags[0] );
00881 m_pPacket->WriteByte( nFlags[1] );
00882
00883 LPSTR pszXML = NULL;
00884 int nXML = 0;
00885
00886 if ( strXML.GetLength() > 0 )
00887 {
00888 nXML = WideCharToMultiByte( CP_ACP, 0, strXML, -1, NULL, 0, NULL, NULL );
00889 pszXML = new CHAR[ nXML ];
00890 WideCharToMultiByte( CP_ACP, 0, strXML, -1, pszXML, nXML, NULL, NULL );
00891 if ( nXML > 0 ) nXML --;
00892
00893 pCompressed = CZLib::Compress( pszXML, nXML, &nCompressed );
00894
00895 if ( nCompressed + 9 < (DWORD)nXML + 11 && pCompressed != NULL )
00896 {
00897 m_pPacket->WriteShortLE( (WORD)( nCompressed + 9 + 1 ) );
00898 }
00899 else
00900 {
00901 m_pPacket->WriteShortLE( nXML + 11 + 1 );
00902 if ( pCompressed != NULL ) delete [] pCompressed;
00903 pCompressed = NULL;
00904 }
00905 }
00906
00907 m_pPacket->WriteByte( Settings.Community.ChatEnable ? 1 : 0 );
00908
00909 if ( Settings.Community.ServeFiles && Settings.Gnutella1.EnableGGEP )
00910 {
00911 m_pPacket->WriteByte( GGEP_MAGIC );
00912 m_pPacket->WriteByte( GGEP_HDR_LAST | 2 );
00913 m_pPacket->WriteByte( 'B' );
00914 m_pPacket->WriteByte( 'H' );
00915 m_pPacket->WriteByte( GGEP_LEN_LAST );
00916 }
00917
00918 if ( pCompressed != NULL )
00919 {
00920 m_pPacket->Write( "{deflate}", 9 );
00921 m_pPacket->Write( pCompressed, nCompressed );
00922 m_pPacket->WriteByte( 0 );
00923 delete [] pCompressed;
00924 }
00925 else if ( pszXML != NULL )
00926 {
00927 m_pPacket->Write( "{plaintext}", 11 );
00928 m_pPacket->Write( pszXML, nXML );
00929 }
00930
00931 if ( pszXML != NULL ) delete [] pszXML;
00932
00933 GGUID tmp( MyProfile.GUID );
00934 m_pPacket->Write( &tmp, sizeof(GGUID) );
00935 }
00936
00937 void CLocalSearch::WriteTrailerG2()
00938 {
00939 CG2Packet* pPacket = (CG2Packet*)m_pPacket;
00940
00941 pPacket->WriteByte( 0 );
00942 pPacket->WriteByte( 0 );
00943 pPacket->Write( &m_pGUID, sizeof(GGUID) );
00944 }
00945
00947
00948
00949 void CLocalSearch::DispatchPacket()
00950 {
00951 ASSERT( m_pPacket != NULL );
00952
00953 if ( m_pNeighbour != NULL )
00954 {
00955 if ( m_bWrapped )
00956 {
00957
00958 theApp.Message( MSG_DEFAULT, _T("CLocalSearch::DispatchPacket() Wrapped query hit created") );
00959
00960
00961 CG2Packet* pG2 = CG2Packet::New( G2_PACKET_HIT_WRAP, (CG1Packet*)m_pPacket );
00962 m_pPacket->Release();
00963 m_pPacket = pG2;
00964 }
00965
00966 m_pNeighbour->Send( m_pPacket, FALSE, TRUE );
00967 }
00968
00969 if ( m_pEndpoint != NULL )
00970 {
00971 Datagrams.Send( m_pEndpoint, (CG2Packet*)m_pPacket, FALSE );
00972 }
00973
00974 if ( m_pBuffer != NULL )
00975 {
00976 m_pPacket->ToBuffer( m_pBuffer );
00977 }
00978
00979 m_pPacket->Release();
00980 m_pPacket = NULL;
00981 }
00982
00983 void CLocalSearch::DestroyPacket()
00984 {
00985 if ( m_pPacket != NULL )
00986 {
00987 m_pPacket->Release();
00988 m_pPacket = NULL;
00989 }
00990 }
00991
00993
00994
00995 void CLocalSearch::WriteVirtualTree()
00996 {
00997 CSingleLock oLock( &Library.m_pSection );
00998 if ( oLock.Lock( 100 ) )
00999 {
01000 m_pPacket = AlbumToPacket( Library.GetAlbumRoot() );
01001 oLock.Unlock();
01002 if ( m_pPacket != NULL ) DispatchPacket();
01003 }
01004
01005 if ( oLock.Lock( 100 ) )
01006 {
01007 m_pPacket = FoldersToPacket();
01008 oLock.Unlock();
01009 if ( m_pPacket != NULL ) DispatchPacket();
01010 }
01011 }
01012
01013 CG2Packet* CLocalSearch::AlbumToPacket(CAlbumFolder* pFolder)
01014 {
01015 if ( pFolder == NULL ) return NULL;
01016
01017 if ( pFolder->m_pSchema != NULL && pFolder->m_pSchema->m_bPrivate ) return NULL;
01018 if ( pFolder->GetSharedCount() == 0 ) return NULL;
01019
01020 CG2Packet* pPacket = CG2Packet::New( "VF", TRUE );
01021
01022 if ( pFolder->m_pSchema != NULL )
01023 {
01024 CXMLElement* pXML = pFolder->m_pSchema->Instantiate( TRUE );
01025
01026 if ( pFolder->m_pXML != NULL )
01027 {
01028 pXML->AddElement( pFolder->m_pXML->Clone() );
01029 }
01030 else
01031 {
01032 CXMLElement* pBody = pXML->AddElement( pFolder->m_pSchema->m_sSingular );
01033 pBody->AddAttribute( pFolder->m_pSchema->GetFirstMemberName(), pFolder->m_sName );
01034 }
01035
01036 CString strXML = pXML->ToString();
01037 delete pXML;
01038
01039 pPacket->WritePacket( "MD", pPacket->GetStringLen( strXML ) );
01040 pPacket->WriteString( strXML, FALSE );
01041 }
01042
01043 for ( POSITION pos = pFolder->GetFolderIterator() ; pos ; )
01044 {
01045 if ( CG2Packet* pChild = AlbumToPacket( pFolder->GetNextFolder( pos ) ) )
01046 {
01047 pPacket->WritePacket( pChild );
01048 pChild->Release();
01049 }
01050 }
01051
01052 pPacket->WritePacket( "FILES", pFolder->GetFileCount() * 4 );
01053
01054 for ( POSITION pos = pFolder->GetFileIterator() ; pos ; )
01055 {
01056 CLibraryFile* pFile = pFolder->GetNextFile( pos );
01057 pPacket->WriteLongBE( pFile->m_nIndex );
01058 }
01059
01060 return pPacket;
01061 }
01062
01063 CG2Packet* CLocalSearch::FoldersToPacket()
01064 {
01065 CG2Packet* pPacket = CG2Packet::New( "PF", TRUE );
01066
01067 for ( POSITION pos = LibraryFolders.GetFolderIterator() ; pos ; )
01068 {
01069 if ( CG2Packet* pChild = FolderToPacket( LibraryFolders.GetNextFolder( pos ) ) )
01070 {
01071 pPacket->WritePacket( pChild );
01072 pChild->Release();
01073 }
01074 }
01075
01076 return pPacket;
01077 }
01078
01079 CG2Packet* CLocalSearch::FolderToPacket(CLibraryFolder* pFolder)
01080 {
01081 if ( pFolder == NULL ) return NULL;
01082
01083 if ( pFolder->GetSharedCount() == 0 ) return NULL;
01084
01085 CG2Packet* pPacket = CG2Packet::New( "PF", TRUE );
01086
01087 pPacket->WritePacket( "DN", pPacket->GetStringLen( pFolder->m_sName ) );
01088 pPacket->WriteString( pFolder->m_sName, FALSE );
01089
01090 for ( POSITION pos = pFolder->GetFolderIterator() ; pos ; )
01091 {
01092 if ( CG2Packet* pChild = FolderToPacket( pFolder->GetNextFolder( pos ) ) )
01093 {
01094 pPacket->WritePacket( pChild );
01095 pChild->Release();
01096 }
01097 }
01098
01099 pPacket->WritePacket( "FILES", pFolder->GetFileCount() * 4 );
01100
01101 for ( POSITION pos = pFolder->GetFileIterator() ; pos ; )
01102 {
01103 CLibraryFile* pFile = pFolder->GetNextFile( pos );
01104 pPacket->WriteLongBE( pFile->m_nIndex );
01105 }
01106
01107 return pPacket;
01108 }