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

Downloads.cpp

Go to the documentation of this file.
00001 //
00002 // Downloads.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 "Downloads.h"
00026 #include "Download.h"
00027 #include "Transfers.h"
00028 #include "Transfer.h"
00029 #include "DownloadGroups.h"
00030 #include "DownloadTransfer.h"
00031 #include "DownloadTransferED2K.h"
00032 #include "DownloadTransferBT.h"
00033 #include "UploadQueues.h"
00034 
00035 #include "Buffer.h"
00036 #include "EDClient.h"
00037 #include "QueryHit.h"
00038 #include "MatchObjects.h"
00039 #include "ShareazaURL.h"
00040 
00041 #include "SHA.h"
00042 #include "ED2K.h"
00043 #include "TigerTree.h"
00044 
00045 #include "WndMain.h"
00046 
00047 #ifdef _DEBUG
00048 #undef THIS_FILE
00049 static char THIS_FILE[]=__FILE__;
00050 #define new DEBUG_NEW
00051 #endif
00052 
00053 CDownloads Downloads;
00054 
00055 
00057 // CDownloads construction
00058 
00059 CDownloads::CDownloads()
00060 {
00061         m_nLimitGeneric                 = Settings.Bandwidth.Downloads;
00062         m_nLimitDonkey                  = Settings.Bandwidth.Downloads;
00063         m_nTransfers                    = 0;
00064         m_nBandwidth                    = 0;
00065         m_nRunCookie                    = 0;
00066         m_bClosing                              = FALSE;
00067         m_tLastConnect                  = 0;
00068 }
00069 
00070 CDownloads::~CDownloads()
00071 {
00072 }
00073 
00075 // CDownloads add an empty download (privilaged)
00076 
00077 CDownload* CDownloads::Add()
00078 {
00079         CDownload* pDownload = new CDownload();
00080         m_pList.AddTail( pDownload );
00081         return pDownload;
00082 }
00083 
00085 // CDownloads add download from a hit or from a file
00086 
00087 CDownload* CDownloads::Add(CQueryHit* pHit, BOOL bAddToHead)
00088 {
00089         CSingleLock pLock( &Transfers.m_pSection, TRUE );
00090         
00091         CDownload* pDownload = NULL;
00092         
00093         if ( pDownload == NULL && pHit->m_bSHA1 )
00094                 pDownload = FindBySHA1( &pHit->m_pSHA1 );
00095         if ( pDownload == NULL && pHit->m_bTiger )
00096                 pDownload = FindByTiger( &pHit->m_pTiger );
00097         if ( pDownload == NULL && pHit->m_bED2K )
00098                 pDownload = FindByED2K( &pHit->m_pED2K );
00099         
00100         if ( pDownload != NULL )
00101         {
00102                 theApp.Message( MSG_DOWNLOAD, IDS_DOWNLOAD_ALREADY, (LPCTSTR)pHit->m_sName );
00103                 
00104                 pDownload->AddSourceHit( pHit );
00105                 pDownload->Resume();
00106         }
00107         else
00108         {
00109                 pDownload = new CDownload();
00110                 pDownload->AddSourceHit( pHit, TRUE );
00111 
00112                 if ( bAddToHead ) m_pList.AddHead( pDownload );
00113                 else m_pList.AddTail( pDownload );
00114                 
00115                 theApp.Message( MSG_DOWNLOAD, IDS_DOWNLOAD_ADDED,
00116                         (LPCTSTR)pDownload->GetDisplayName(), pDownload->GetSourceCount() );
00117 
00118                 if( pDownload->m_bSHA1 ) pDownload->m_bSHA1Trusted = TRUE;
00119                 else if( pDownload->m_bED2K ) pDownload->m_bED2KTrusted = TRUE;
00120         }
00121 
00122         pHit->m_bDownload = TRUE;
00123         
00124         DownloadGroups.Link( pDownload );
00125         Transfers.StartThread();
00126 
00127         if ( ( (pDownload->GetSourceCount() == 0 ) || ( pDownload->m_bED2K && ! pDownload->m_bSHA1 ) ) 
00128          &&( (GetTryingCount() < Settings.Downloads.MaxFiles ) || ( bAddToHead ) ) )
00129         {
00130                 pDownload->SetStartTimer();
00131         }
00132         
00133         
00134         return pDownload;
00135 }
00136 
00137 CDownload* CDownloads::Add(CMatchFile* pFile, BOOL bAddToHead)
00138 {
00139         CSingleLock pLock( &Transfers.m_pSection, TRUE );
00140         
00141         CDownload* pDownload = NULL;
00142         
00143         if ( pDownload == NULL && pFile->m_bSHA1 )
00144                 pDownload = FindBySHA1( &pFile->m_pSHA1 );
00145         if ( pDownload == NULL && pFile->m_bTiger )
00146                 pDownload = FindByTiger( &pFile->m_pTiger );
00147         if ( pDownload == NULL && pFile->m_bED2K )
00148                 pDownload = FindByED2K( &pFile->m_pED2K );
00149         
00150         if ( pDownload != NULL )
00151         {
00152                 theApp.Message( MSG_DOWNLOAD, IDS_DOWNLOAD_ALREADY, (LPCTSTR)pFile->m_pHits->m_sName );
00153                 
00154                 for ( CQueryHit* pHit = pFile->m_pHits ; pHit ; pHit = pHit->m_pNext )
00155                 {
00156                         pDownload->AddSourceHit( pHit );
00157 
00158                         // Send any reviews to the download, so they can be viewed later
00159                         if ( pHit->m_nRating || ! pHit->m_sComments.IsEmpty() )
00160                         {
00161                                 pDownload->AddReview( &pHit->m_pAddress, 2, pHit->m_nRating, pHit->m_sNick, pHit->m_sComments );
00162                         }
00163                 }
00164                 
00165                 pDownload->Resume();
00166         }
00167         else
00168         {
00169                 pDownload = new CDownload();
00170                 if ( bAddToHead ) m_pList.AddHead( pDownload );
00171                 else m_pList.AddTail( pDownload );
00172                 
00173                 if ( pFile->m_pBest != NULL )
00174                 {
00175                         pDownload->AddSourceHit( pFile->m_pBest, TRUE );
00176                 }
00177                 
00178                 for ( CQueryHit* pHit = pFile->m_pHits ; pHit ; pHit = pHit->m_pNext )
00179                 {
00180                         if ( pHit != pFile->m_pBest )
00181                         {
00182                                 pDownload->AddSourceHit( pHit, TRUE );
00183                         }
00184 
00185                         // Send any reviews to the download, so they can be viewed later
00186                         if ( pHit->m_nRating || ! pHit->m_sComments.IsEmpty() )
00187                         {
00188                                 pDownload->AddReview( &pHit->m_pAddress, 2, pHit->m_nRating, pHit->m_sNick, pHit->m_sComments );
00189                         }
00190                 }
00191                 
00192                 theApp.Message( MSG_DOWNLOAD, IDS_DOWNLOAD_ADDED,
00193                         (LPCTSTR)pDownload->GetDisplayName(), pDownload->GetSourceCount() );
00194 
00195                 if( pDownload->m_bSHA1 ) pDownload->m_bSHA1Trusted = TRUE;
00196                 else if( pDownload->m_bED2K ) pDownload->m_bED2KTrusted = TRUE;
00197         }
00198         
00199         pFile->m_bDownload = TRUE;
00200         
00201         DownloadGroups.Link( pDownload );
00202         Transfers.StartThread();
00203         
00204         if ( ( (pDownload->GetSourceCount() == 0 ) ||
00205                    ( pDownload->m_bED2K && ! pDownload->m_bSHA1 )) &&
00206                    (GetTryingCount() < Settings.Downloads.MaxFiles ) )
00207         {
00208                 pDownload->FindMoreSources();
00209                 pDownload->SetStartTimer();
00210         }
00211         
00212         return pDownload;
00213 }
00214 
00216 // CDownloads add download from a URL
00217 
00218 CDownload* CDownloads::Add(CShareazaURL* pURL)
00219 {
00220         if ( pURL->m_nAction != CShareazaURL::uriDownload &&
00221                  pURL->m_nAction != CShareazaURL::uriSource ) return NULL;
00222         
00223         CSingleLock pLock( &Transfers.m_pSection, TRUE );
00224         CDownload* pDownload = NULL;
00225         
00226         if ( pDownload == NULL && pURL->m_bSHA1 )
00227                 pDownload = FindBySHA1( &pURL->m_pSHA1 );
00228         if ( pDownload == NULL && pURL->m_bTiger )
00229                 pDownload = FindByTiger( &pURL->m_pTiger );
00230         if ( pDownload == NULL && pURL->m_bED2K )
00231                 pDownload = FindByED2K( &pURL->m_pED2K );
00232         if ( pDownload == NULL && pURL->m_bBTH )
00233                 pDownload = FindByBTH( &pURL->m_pBTH );
00234         
00235         if ( pDownload != NULL )
00236         {
00237                 theApp.Message( MSG_DOWNLOAD, IDS_DOWNLOAD_ALREADY,
00238                         (LPCTSTR)pDownload->GetDisplayName() );
00239                 
00240                 if ( pURL->m_sURL.GetLength() ) pDownload->AddSourceURLs( pURL->m_sURL, FALSE );
00241                 
00242                 return pDownload;
00243         }
00244         
00245         pDownload = new CDownload();
00246         
00247         if ( pURL->m_bSHA1 )
00248         {
00249                 pDownload->m_bSHA1                      = TRUE;
00250                 pDownload->m_pSHA1                      = pURL->m_pSHA1;
00251                 pDownload->m_bSHA1Trusted       = TRUE;
00252         }
00253         if ( pURL->m_bTiger )
00254         {
00255                 pDownload->m_bTiger                     = TRUE;
00256                 pDownload->m_pTiger                     = pURL->m_pTiger;
00257                 pDownload->m_bTigerTrusted      = TRUE;
00258         }
00259         if ( pURL->m_bMD5 )
00260         {
00261                 pDownload->m_bMD5                       = TRUE;
00262                 pDownload->m_pMD5                       = pURL->m_pMD5;
00263                 pDownload->m_bMD5Trusted        = TRUE;
00264         }
00265         if ( pURL->m_bED2K )
00266         {
00267                 pDownload->m_bED2K                      = TRUE;
00268                 pDownload->m_pED2K                      = pURL->m_pED2K;
00269                 pDownload->m_bED2KTrusted       = TRUE;
00270                 pDownload->Share( TRUE );
00271         }
00272         if ( pURL->m_bBTH )
00273         {
00274                 pDownload->m_bBTH                       = TRUE;
00275                 pDownload->m_pBTH                       = pURL->m_pBTH;
00276                 pDownload->m_bBTHTrusted        = TRUE;
00277                 pDownload->Share( TRUE );
00278         }
00279         
00280         if ( pURL->m_sName.GetLength() )
00281         {
00282                 pDownload->m_sRemoteName = pURL->m_sName;
00283         }
00284         
00285         if ( pURL->m_bSize )
00286         {
00287                 pDownload->m_nSize = pURL->m_nSize;
00288         }
00289         
00290         if ( pURL->m_sURL.GetLength() )
00291         {
00292                 if ( ! pDownload->AddSourceURLs( pURL->m_sURL, FALSE ) )
00293                 {
00294                         if ( pURL->m_nAction == CShareazaURL::uriSource )
00295                         {
00296                                 delete pDownload;
00297                                 return NULL;
00298                         }
00299                 }
00300         }
00301         
00302         pDownload->SetTorrent( pURL->m_pTorrent );
00303         
00304         m_pList.AddTail( pDownload );
00305         
00306         theApp.Message( MSG_DOWNLOAD, IDS_DOWNLOAD_ADDED,
00307                 (LPCTSTR)pDownload->GetDisplayName(), pDownload->GetSourceCount() );
00308         
00309         if( (  pDownload->m_bBTH && ( GetTryingCount(TRUE)  < Settings.BitTorrent.DownloadTorrents ) ) ||
00310                 ( !pDownload->m_bBTH && ( GetTryingCount(FALSE) < Settings.Downloads.MaxFiles ) ) )
00311         {
00312                 pDownload->SetStartTimer();
00313                 if ( pURL->m_nAction != CShareazaURL::uriSource )
00314                         pDownload->FindMoreSources();
00315         }
00316         
00317         DownloadGroups.Link( pDownload );
00318         Transfers.StartThread();
00319         
00320         return pDownload;
00321 }
00322 
00324 // CDownloads commands
00325 
00326 void CDownloads::PauseAll()
00327 {
00328         CSingleLock pLock( &Transfers.m_pSection, TRUE );
00329         
00330         for ( POSITION pos = GetIterator() ; pos ; )
00331         {
00332                 GetNext( pos )->Pause();
00333         }
00334 }
00335 
00336 void CDownloads::ClearCompleted()
00337 {
00338         CSingleLock pLock( &Transfers.m_pSection, TRUE );
00339         
00340         for ( POSITION pos = GetIterator() ; pos ; )
00341         {
00342                 CDownload* pDownload = GetNext( pos );
00343                 if ( ( pDownload->IsCompleted() ) && ( !pDownload->IsSeeding() ) ) pDownload->Remove();
00344         }
00345 }
00346 
00347 void CDownloads::ClearPaused()
00348 {
00349         CSingleLock pLock( &Transfers.m_pSection, TRUE );
00350 
00351         for ( POSITION pos = GetIterator() ; pos ; )
00352         {
00353                 CDownload* pDownload = GetNext( pos );
00354                 if ( pDownload->IsPaused() ) pDownload->Remove();
00355         }
00356 }
00357 
00358 void CDownloads::Clear(BOOL bShutdown)
00359 {
00360         CSingleLock pLock( &Transfers.m_pSection, TRUE );
00361         m_bClosing = TRUE;
00362         
00363         for ( POSITION pos = GetIterator() ; pos ; )
00364         {
00365                 Remove( GetNext( pos ) );
00366         }
00367         
00368         m_pList.RemoveAll();
00369         m_bClosing = bShutdown;
00370 }
00371 
00372 void CDownloads::CloseTransfers()
00373 {
00374         CSingleLock pLock( &Transfers.m_pSection, TRUE );
00375         
00376         m_bClosing = TRUE;
00377         
00378         for ( POSITION pos = GetIterator() ; pos ; )
00379         {
00380                 GetNext( pos )->CloseTransfers();
00381         }
00382         
00383         m_bClosing = FALSE;
00384         m_nTransfers = 0;
00385         m_nBandwidth = 0;
00386 }
00387 
00389 // CDownloads list access
00390 
00391 int CDownloads::GetSeedCount() const
00392 {
00393         int nCount = 0;
00394         
00395         for ( POSITION pos = GetIterator() ; pos ; )
00396         {
00397                 CDownload* pDownload = GetNext( pos );
00398                 
00399                 if ( pDownload->IsSeeding() )
00400                         nCount++;               //Manually seeded Torrent
00401                 else if ( pDownload->IsCompleted() && pDownload->m_bBTH && pDownload->IsFullyVerified() )
00402                         nCount++;               //Torrent that has completed
00403         }
00404         
00405         return nCount;
00406 }
00407 
00408 int CDownloads::GetActiveTorrentCount() const
00409 {
00410         int nCount = 0;
00411         
00412         for ( POSITION pos = GetIterator() ; pos ; )
00413         {
00414                 CDownload* pDownload = GetNext( pos );
00415                 
00416                 if ( pDownload->IsDownloading() && pDownload->m_bBTH &&
00417                         ! pDownload->IsSeeding()        && ! pDownload->IsCompleted() &&
00418                         ! pDownload->IsMoving()         && ! pDownload->IsPaused() )
00419                                 nCount++;
00420         }
00421         
00422         return nCount;
00423 }
00424 
00425 int CDownloads::GetCount(BOOL bActiveOnly) const
00426 {
00427         if ( ! bActiveOnly ) return m_pList.GetCount();
00428         
00429         int nCount = 0;
00430         
00431         for ( POSITION pos = GetIterator() ; pos ; )
00432         {
00433                 CDownload* pDownload = GetNext( pos );
00434                 
00435                 if ( ! pDownload->IsMoving() && ! pDownload->IsPaused() &&
00436                          pDownload->GetSourceCount( TRUE ) > 0 )
00437                                 nCount++;
00438         }
00439         
00440         return nCount;
00441 }
00442 
00443 int CDownloads::GetTransferCount() const
00444 {
00445         int nCount = 0;
00446         
00447         for ( POSITION pos = GetIterator() ; pos ; )
00448         {
00449                 nCount += GetNext( pos )->GetTransferCount();
00450         }
00451         
00452         return nCount;
00453 }
00454 
00455 int CDownloads::GetTryingCount(BOOL bTorrentsOnly) const
00456 {
00457         int nCount = 0;
00458         
00459         for ( POSITION pos = GetIterator() ; pos ; )
00460         {
00461                 CDownload* pDownload = GetNext( pos );
00462                 
00463                 if ( ( pDownload->IsTrying() ) && ( ! pDownload->IsCompleted() ) && ( ! pDownload->IsPaused() ) )
00464                 {
00465                         if ( ( pDownload->m_bBTH ) || ( ! bTorrentsOnly ) )
00466                                 nCount++;
00467                 }
00468         }
00469         
00470         return nCount;
00471 }
00472 
00473 int CDownloads::GetConnectingTransferCount() const
00474 {
00475         int nCount = 0;
00476         
00477         for ( POSITION pos = GetIterator() ; pos ; )
00478         {
00479                 CDownload* pDownload = GetNext( pos );
00480                 
00481                 nCount += pDownload->GetTransferCount( dtsConnecting );
00482         }
00483         
00484         return nCount;
00485 }
00486 
00487 void CDownloads::Remove(CDownload* pDownload)
00488 {
00489         POSITION pos = m_pList.Find( pDownload );
00490         if ( pos != NULL ) m_pList.RemoveAt( pos );
00491         delete pDownload;
00492 }
00493 
00495 // CDownloads find by pointer or hash
00496 
00497 BOOL CDownloads::Check(CDownloadSource* pSource) const
00498 {
00499         for ( POSITION pos = GetIterator() ; pos ; )
00500         {
00501                 if ( GetNext( pos )->CheckSource( pSource ) ) return TRUE;
00502         }
00503         return FALSE;
00504 }
00505 
00506 BOOL CDownloads::CheckActive(CDownload* pDownload, int nScope) const
00507 {
00508         for ( POSITION pos = GetReverseIterator() ; pos && nScope > 0 ; )
00509         {
00510                 CDownload* pTest = GetPrevious( pos );
00511                 BOOL bActive = pTest->IsPaused() == FALSE && pTest->IsCompleted() == FALSE;
00512                 
00513                 if ( pDownload == pTest ) return bActive;
00514                 if ( bActive ) nScope--;
00515         }
00516         
00517         return FALSE;
00518 }
00519 
00520 CDownload* CDownloads::FindByURN(LPCTSTR pszURN, BOOL bSharedOnly) const
00521 {
00522         CDownload* pDownload;
00523         TIGEROOT pTiger;
00524         SHA1 pSHA1;
00525         MD4 pED2K;
00526         
00527         if ( CSHA::HashFromURN( pszURN, &pSHA1 ) )
00528         {
00529                 if ( pDownload = FindBySHA1( &pSHA1, bSharedOnly ) ) return pDownload;
00530         }
00531         
00532         if ( CTigerNode::HashFromURN( pszURN, &pTiger ) )
00533         {
00534                 if ( pDownload = FindByTiger( &pTiger, bSharedOnly ) ) return pDownload;
00535         }
00536         
00537         if ( CED2K::HashFromURN( pszURN, &pED2K ) )
00538         {
00539                 if ( pDownload = FindByED2K( &pED2K, bSharedOnly ) ) return pDownload;
00540         }
00541         
00542         return NULL;
00543 }
00544 
00545 CDownload* CDownloads::FindBySHA1(const SHA1* pSHA1, BOOL bSharedOnly) const
00546 {
00547         for ( POSITION pos = GetIterator() ; pos ; )
00548         {
00549                 CDownload* pDownload = GetNext( pos );
00550                 if ( pDownload->m_bSHA1 && pDownload->m_pSHA1 == *pSHA1 )
00551                 {
00552                         if ( ! bSharedOnly || ( pDownload->IsShared() && pDownload->IsStarted() ) )
00553                                 return pDownload;
00554                 }
00555         }
00556         
00557         return NULL;
00558 }
00559 
00560 CDownload* CDownloads::FindByTiger(const TIGEROOT* pTiger, BOOL bSharedOnly) const
00561 {
00562         for ( POSITION pos = GetIterator() ; pos ; )
00563         {
00564                 CDownload* pDownload = GetNext( pos );
00565                 if ( pDownload->m_bTiger && pDownload->m_pTiger == *pTiger )
00566                 {
00567                         if ( ! bSharedOnly || ( pDownload->IsShared() && pDownload->IsStarted() ) )
00568                                 return pDownload;
00569                 }
00570         }
00571         
00572         return NULL;
00573 }
00574 
00575 CDownload* CDownloads::FindByED2K(const MD4* pED2K, BOOL bSharedOnly) const
00576 {
00577         for ( POSITION pos = GetIterator() ; pos ; )
00578         {
00579                 CDownload* pDownload = GetNext( pos );
00580                 if ( pDownload->m_bED2K && pDownload->m_pED2K == *pED2K )
00581                 {
00582                         if ( ! bSharedOnly || ( pDownload->IsShared() && pDownload->IsStarted() )
00583                                 && ( pDownload->m_nSize > ED2K_PART_SIZE || pDownload->IsCompleted() ) )
00584                                 return pDownload;
00585                 }
00586         }
00587         
00588         return NULL;
00589 }
00590 
00591 CDownload* CDownloads::FindByBTH(const SHA1* pBTH, BOOL bSharedOnly) const
00592 {
00593         for ( POSITION pos = GetIterator() ; pos ; )
00594         {
00595                 CDownload* pDownload = GetNext( pos );
00596                 if ( pDownload->m_bBTH && pDownload->m_pBTH == *pBTH )
00597                 {
00598                         if ( ! bSharedOnly || ( pDownload->IsShared() ) )
00599                                 return pDownload;
00600                 }
00601         }
00602         
00603         return NULL;
00604 }
00605 
00606 
00608 // CDownloads serialization ID
00609 
00610 CDownload* CDownloads::FindBySID(DWORD nSerID) const
00611 {
00612         for ( POSITION pos = GetIterator() ; pos ; )
00613         {
00614                 CDownload* pDownload = GetNext( pos );
00615                 if ( pDownload->m_nSerID == nSerID ) return pDownload;
00616         }
00617         
00618         return NULL;
00619 }
00620 
00621 DWORD CDownloads::GetFreeSID()
00622 {
00623         for ( ;; )
00624         {
00625                 DWORD nSerID    = ( rand() & 0xFF ) + ( ( rand() & 0xFF ) << 8 )
00626                                                 + ( ( rand() & 0xFF ) << 16 ) + ( ( rand() & 0xFF ) << 24 );
00627                 
00628                 for ( POSITION pos = GetIterator() ; pos ; )
00629                 {
00630                         CDownload* pDownload = GetNext( pos );
00631                         if ( pDownload->m_nSerID == nSerID ) { nSerID = 0; break; }
00632                 }
00633                 
00634                 if ( nSerID ) return nSerID;
00635         }
00636         
00637         ASSERT( FALSE );
00638         return 0;
00639 }
00640 
00642 // CDownloads ordering
00643 
00644 BOOL CDownloads::Move(CDownload* pDownload, int nDelta)
00645 {
00646         CSingleLock pLock( &Transfers.m_pSection, TRUE );
00647         
00648         POSITION posMe = m_pList.Find( pDownload );
00649         if ( posMe == NULL ) return FALSE;
00650         
00651         POSITION posOther = posMe;
00652         
00653         if ( nDelta < 0 )
00654                 m_pList.GetPrev( posOther );
00655         else
00656                 m_pList.GetNext( posOther );
00657         
00658         if ( posOther == NULL) return FALSE;
00659         
00660         if ( nDelta < 0 )
00661                 m_pList.InsertBefore( posOther, pDownload );
00662         else
00663                 m_pList.InsertAfter( posOther, pDownload );
00664         m_pList.RemoveAt( posMe );
00665         
00666         DownloadGroups.IncBaseCookie();
00667         
00668         return TRUE;
00669 }
00670 
00671 BOOL CDownloads::Swap(CDownload* p1, CDownload*p2)
00672 {
00673         CSingleLock pLock( &Transfers.m_pSection, TRUE );
00674         
00675         POSITION pos1 = m_pList.Find( p1 );
00676         if (pos1 == NULL) return FALSE;
00677         
00678         POSITION pos2 = m_pList.Find( p2 );     
00679         if (pos2 == NULL) return FALSE;
00680         
00681         m_pList.InsertAfter(pos2, p1 );
00682         m_pList.RemoveAt( pos2);        
00683         m_pList.InsertAfter(pos1, p2 );
00684         m_pList.RemoveAt( pos1 );       
00685         return TRUE;
00686 }
00687 
00688 BOOL CDownloads::Reorder(CDownload* pDownload, CDownload* pBefore)
00689 {
00690         CSingleLock pLock( &Transfers.m_pSection, TRUE );
00691         
00692         POSITION pos1 = m_pList.Find( pDownload );
00693         if ( pos1 == NULL ) return FALSE;
00694         
00695         if ( pBefore != NULL )
00696         {
00697                 POSITION pos2 = m_pList.Find( pBefore );
00698                 if ( pos2 == NULL || pos1 == pos2 ) return FALSE;
00699                 m_pList.RemoveAt( pos1 );
00700                 m_pList.InsertBefore( pos2, pDownload );
00701         }
00702         else
00703         {
00704                 m_pList.RemoveAt( pos1 );
00705                 m_pList.AddTail( pDownload );
00706         }
00707         
00708         DownloadGroups.IncBaseCookie();
00709         
00710         return TRUE;
00711 }
00712 
00714 // CDownloads find amount downloaded from a user
00715 
00716 QWORD CDownloads::GetAmountDownloadedFrom(IN_ADDR* pAddress)
00717 {
00718         QWORD nTotal = 0;
00719 
00720         if ( pAddress == NULL ) return 0;
00721 
00722         for ( POSITION pos = GetIterator() ; pos ; )
00723         {
00724                 CDownload* pDownload = GetNext( pos );
00725 
00726                 nTotal += pDownload->GetAmountDownloadedFrom(pAddress);
00727         }
00728         return nTotal;
00729 }
00730 
00732 // CDownloads bandwidth
00733 
00734 DWORD CDownloads::GetBandwidth() const
00735 {
00736         DWORD nTotal = 0;
00737         for ( POSITION pos = GetIterator() ; pos ; )
00738         {
00739                 nTotal += GetNext( pos )->GetMeasuredSpeed();
00740         }
00741         return nTotal;
00742 }
00743 
00745 // CDownloads limiting tests
00746 
00747 void CDownloads::UpdateAllows(BOOL bNew)
00748 {
00749         int nDownloads  = 0;
00750         int nTransfers  = 0;
00751         
00752         if ( bNew ) m_tLastConnect = GetTickCount();
00753         
00754         for ( POSITION pos = GetIterator() ; pos ; )
00755         {
00756                 CDownload* pDownload = GetNext( pos );
00757                 int nTemp = pDownload->GetTransferCount();
00758                 
00759                 if ( nTemp )
00760                 {
00761                         nDownloads ++;
00762                         nTransfers += nTemp;
00763                 }
00764         }
00765         
00766         m_bAllowMoreDownloads = nDownloads < Settings.Downloads.MaxFiles;
00767         m_bAllowMoreTransfers = nTransfers < Settings.Downloads.MaxTransfers;
00768 }
00769 
00770 BOOL CDownloads::AllowMoreDownloads() const
00771 {
00772         int nCount = 0;
00773 
00774         for ( POSITION pos = GetIterator() ; pos ; )
00775         {
00776                 if ( GetNext( pos )->GetTransferCount() ) nCount++;
00777         }
00778         
00779         return nCount < Settings.Downloads.MaxFiles;
00780 }
00781 
00782 BOOL CDownloads::AllowMoreTransfers(IN_ADDR* pAddress) const
00783 {
00784         int nCount = 0, nLimit = 0;
00785         
00786         for ( POSITION pos = GetIterator() ; pos ; )
00787         {
00788                 nCount += GetNext( pos )->GetTransferCount( dtsCountAll, pAddress );
00789         }
00790         
00791         if ( pAddress == NULL ) return nCount < Settings.Downloads.MaxTransfers;
00792         
00793         if ( m_pHostLimits.Lookup( (LPVOID)pAddress->S_un.S_addr, (void*&)nLimit ) )
00794         {
00795                 return ( nCount < nLimit );
00796         }
00797         else
00798         {
00799                 return ( nCount == 0 );
00800         }
00801 }
00802 
00803 void CDownloads::SetPerHostLimit(IN_ADDR* pAddress, int nLimit)
00804 {
00805         m_pHostLimits.SetAt( (LPVOID)pAddress->S_un.S_addr, (LPVOID)nLimit );
00806 }
00807 
00809 // CDownloads disk space helper
00810 
00811 BOOL CDownloads::IsSpaceAvailable(QWORD nVolume, int nPath)
00812 {
00813         QWORD nMargin = 10485760;
00814         
00815         if ( HINSTANCE hKernel = GetModuleHandle( _T("KERNEL32.DLL") ) )
00816         {
00817                  BOOL (WINAPI *pfnGetDiskFreeSpaceEx)(LPCTSTR, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER); 
00818 #ifdef UNICODE
00819                 (FARPROC&)pfnGetDiskFreeSpaceEx = GetProcAddress( hKernel, "GetDiskFreeSpaceExW" );
00820 #else
00821                 (FARPROC&)pfnGetDiskFreeSpaceEx = GetProcAddress( hKernel, "GetDiskFreeSpaceExA" );
00822 #endif  
00823                 if ( pfnGetDiskFreeSpaceEx != NULL )
00824                 {
00825                         ULARGE_INTEGER nFree, nNull;
00826                         
00827                         if ( ( ! nPath || nPath == dlPathIncomplete ) && (*pfnGetDiskFreeSpaceEx)( Settings.Downloads.IncompletePath, &nFree, &nNull, &nNull ) )
00828                         {
00829                                 if ( nFree.QuadPart < nVolume + nMargin ) return FALSE;
00830                         }
00831 
00832                         if ( ( ! nPath || nPath == dlPathComplete ) && (*pfnGetDiskFreeSpaceEx)( Settings.Downloads.CompletePath, &nFree, &nNull, &nNull ) )
00833                         {
00834                                 if ( nFree.QuadPart < nVolume + nMargin ) return FALSE;
00835                         }
00836 
00837                         return TRUE;
00838                 }
00839         }
00840 
00841         DWORD nSPC, nBPS, nFree, nTotal;
00842         if ( ! nPath || nPath == dlPathIncomplete )
00843         {
00844                 CString str = Settings.Downloads.IncompletePath.SpanExcluding( _T("\\") ) + '\\';
00845         
00846                 if ( GetDiskFreeSpace( str, &nSPC, &nBPS, &nFree, &nTotal ) )
00847                 {
00848                         QWORD nBytes = (QWORD)nSPC * (QWORD)nBPS * (QWORD)nFree;
00849                         if ( nBytes < nVolume + nMargin ) return FALSE;
00850                 }
00851         }
00852 
00853         if ( ! nPath || nPath == dlPathComplete )
00854         {
00855                 CString str = Settings.Downloads.CompletePath.SpanExcluding( _T("\\") ) + '\\';
00856         
00857                 if ( GetDiskFreeSpace( str, &nSPC, &nBPS, &nFree, &nTotal ) )
00858                 {
00859                         QWORD nBytes = (QWORD)nSPC * (QWORD)nBPS * (QWORD)nFree;
00860                         if ( nBytes < nVolume + nMargin ) return FALSE;
00861                 }
00862         }
00863 
00864         return TRUE;
00865 }
00866 
00868 // CDownloads run callback (threaded)
00869 
00870 void CDownloads::OnRun()
00871 {
00872         DWORD nActiveDownloads          = 0;    // Number of downloads that are doing something
00873         DWORD nActiveTransfers          = 0;    // Number of transfers that are in the downloading state
00874         DWORD nTotalTransfers           = 0;    // Total transfers
00875         DWORD nTotalBandwidth           = 0;    // Total bandwidth in use
00876         DWORD nRunningTransfers         = 0;    // Number of transfers that are downloading and transfering data
00877         DWORD nRunningED2KTransfers     = 0;    // Number of ed2k transfers that are downloading and transfering data
00878         DWORD nTotalED2KBandwidth       = 0;    // Total ed2k bandwidth in use.
00879 
00880         {
00881                 CTransfers::Lock oLock;
00882 
00883                 m_nValidation = 0;
00884                 ++m_nRunCookie;
00885                 
00886                 for ( POSITION pos = GetIterator(); pos; )
00887                 {
00888                         CDownload* pDownload = GetNext( pos );
00889                         pDownload->m_nRunCookie = m_nRunCookie;
00890                         pDownload->OnRun();
00891                         
00892                         int nTemp = 0;
00893                         
00894                         for ( CDownloadTransfer* pTransfer = pDownload->GetFirstTransfer() ; pTransfer ; pTransfer = pTransfer->m_pDlNext )
00895                         {
00896                                 if ( pTransfer->m_nProtocol == PROTOCOL_ED2K )
00897                                 {
00898                                         CDownloadTransferED2K* pED2K = (CDownloadTransferED2K*)pTransfer;
00899                                         if ( pED2K->m_pClient == NULL || pED2K->m_pClient->m_bConnected == FALSE ) continue;
00900                                         if ( pTransfer->m_nState == dtsQueued ) continue;
00901                                 }
00902                                 else if ( pTransfer->m_nProtocol == PROTOCOL_BT )
00903                                 {
00904                                         CDownloadTransferBT* pBT = (CDownloadTransferBT*)pTransfer;
00905                                         if ( pBT->m_nState == dtsTorrent && pBT->m_bChoked ) continue;
00906                                 }
00907                                 
00908                                 nTemp ++;
00909                                 
00910                                 if ( pTransfer->m_nState == dtsDownloading )
00911                                 {
00912                                         DWORD nSpeed = pTransfer->GetMeasuredSpeed();
00913                                         nTotalBandwidth += nSpeed;
00914                                         nActiveTransfers ++;
00915                                         if ( nSpeed > 32 ) nRunningTransfers ++; 
00916 
00917                                         if ( pTransfer->m_nProtocol == PROTOCOL_ED2K ) 
00918                                         {
00919                                                 nTotalED2KBandwidth += nSpeed;
00920                                                 if ( nSpeed > 32 ) nRunningED2KTransfers ++;
00921                                         }
00922                                 }
00923                         }
00924                         
00925                         if ( nTemp )
00926                         {
00927                                 nActiveDownloads ++;
00928                                 nTotalTransfers += nTemp;
00929                         }
00930                 }
00931         }
00932 
00933         m_nTransfers = nActiveTransfers;
00934         m_nBandwidth = nTotalBandwidth;
00935         
00936         m_bAllowMoreDownloads = nActiveDownloads < (DWORD)Settings.Downloads.MaxFiles;
00937         m_bAllowMoreTransfers = nTotalTransfers < (DWORD)Settings.Downloads.MaxTransfers;
00938         
00939         // Transfers that are not managing at least 32 bytes/sec are not counted when averaging limits
00940         if ( nRunningTransfers > 0 )
00941         {
00942                 m_nLimitGeneric = Settings.Bandwidth.Downloads / nRunningTransfers;
00943                 m_nLimitDonkey = m_nLimitGeneric;
00944                 if ( UploadQueues.IsDonkeyRatioActive() )
00945                 {
00946                         // Use either the minimum we have reserved, or the current upload allocation, whichever is greater.
00947                         DWORD nDonkeyLimit = max( UploadQueues.GetMinimumDonkeyBandwidth(), UploadQueues.GetCurrentDonkeyBandwidth() );
00948                 
00949                         if ( nDonkeyLimit < 10240 )
00950                         {
00951                                 // ED2K 3:1 ratio if you aren't uploading at 10KB/s
00952                                 nDonkeyLimit *= 3;      
00953 
00954                                 // Because this is a per-source limit, we should check overall usage as well.
00955                                 if ( nTotalED2KBandwidth > ( nDonkeyLimit / 2 ) )
00956                                 {
00957                                         // We're getting close to the ed2k ratio, so we need to limit some sources.
00958 
00959                                         if ( nRunningED2KTransfers > 0 )
00960                                                 m_nLimitDonkey = nDonkeyLimit / nRunningED2KTransfers;
00961                                         else 
00962                                                 m_nLimitDonkey = nDonkeyLimit;
00963 
00964                                 }
00965 
00966                                 // Make sure we have not set the ed2k limit higher than the general limit
00967                                 if ( m_nLimitGeneric ) m_nLimitDonkey = min( m_nLimitGeneric, m_nLimitDonkey );
00968                         }
00969                 }
00970         }
00971         else
00972         {
00973                 m_nLimitGeneric = m_nLimitDonkey = Settings.Bandwidth.Downloads;
00974         }
00975         
00976         DownloadGroups.Save( FALSE );
00977 }
00978 
00980 // CDownloads query hit handler
00981 
00982 void CDownloads::OnQueryHits(CQueryHit* pHits)
00983 {
00984         CSingleLock pLock( &Transfers.m_pSection );
00985         
00986         if ( ! pLock.Lock( 50 ) ) return;
00987         
00988         for ( POSITION pos = GetIterator() ; pos ; )
00989         {
00990                 CDownload* pDownload = GetNext( pos );
00991                 if ( pDownload->IsMoving() == FALSE ) pDownload->OnQueryHits( pHits );
00992         }       
00993 }
00994 
00996 // CDownloads push handler
00997 
00998 BOOL CDownloads::OnPush(GGUID* pGUID, CConnection* pConnection)
00999 {
01000         CSingleLock pLock( &Transfers.m_pSection );
01001         if ( ! pLock.Lock( 250 ) ) return FALSE;
01002         
01003         for ( POSITION pos = GetIterator() ; pos ; )
01004         {
01005                 CDownload* pDownload = GetNext( pos );
01006                 if ( pDownload->OnAcceptPush( pGUID, pConnection ) ) return TRUE;
01007         }
01008         
01009         return FALSE;
01010 }
01011 
01013 // CDownloads eDonkey2000 callback handler
01014 
01015 BOOL CDownloads::OnDonkeyCallback(CEDClient* pClient, CDownloadSource* pExcept)
01016 {
01017         CSingleLock pLock( &Transfers.m_pSection );
01018         if ( ! pLock.Lock( 250 ) ) return FALSE;
01019         
01020         if ( m_bClosing ) return FALSE;
01021         
01022         for ( POSITION pos = GetIterator() ; pos ; )
01023         {
01024                 CDownload* pDownload = GetNext( pos );
01025                 if ( pDownload->OnDonkeyCallback( pClient, pExcept ) ) return TRUE;
01026         }
01027         
01028         return FALSE;
01029 }
01030 
01032 // CDownloads verification handler
01033 
01034 void CDownloads::OnVerify(LPCTSTR pszPath, BOOL bVerified)
01035 {
01036         CSingleLock pLock( &Transfers.m_pSection );
01037         if ( ! pLock.Lock( 500 ) ) return;
01038         
01039         for ( POSITION pos = GetIterator() ; pos ; )
01040         {
01041                 if ( GetNext( pos )->OnVerify( pszPath, bVerified ) ) break;
01042         }       
01043 }
01044 
01046 // CDownloads load and save
01047 
01048 void CDownloads::Load()
01049 {
01050         CSingleLock pLock( &Transfers.m_pSection, TRUE );
01051         WIN32_FIND_DATA pFind;
01052         CString strPath;
01053         HANDLE hSearch;
01054         
01055         PurgeDeletes();
01056         PurgePreviews();
01057         
01058         DownloadGroups.CreateDefault();
01059         LoadFromCompoundFiles();
01060         
01061         strPath = Settings.Downloads.IncompletePath + _T("\\*.sd");
01062         hSearch = FindFirstFile( strPath, &pFind );
01063         
01064         if ( hSearch != INVALID_HANDLE_VALUE )
01065         {
01066                 do
01067                 {
01068                         CDownload* pDownload = new CDownload();
01069                         
01070                         strPath.Format( _T("%s\\%s"), (LPCTSTR)Settings.Downloads.IncompletePath, pFind.cFileName );
01071                         
01072                         if ( pDownload->Load( strPath ) )
01073                         {
01074                                 m_pList.AddTail( pDownload );
01075                         }
01076                         else
01077                         {
01078                                 theApp.Message( MSG_ERROR, _T("Error loading %s"), strPath );
01079                                 pDownload->ClearSources();
01080                                 delete pDownload;
01081                         }
01082                 }
01083                 while ( FindNextFile( hSearch, &pFind ) );
01084                 
01085                 FindClose( hSearch );
01086         }
01087         
01088         Save( FALSE );
01089         DownloadGroups.Load();
01090         Transfers.StartThread();
01091 }
01092 
01093 void CDownloads::Save(BOOL bForce)
01094 {
01095         CSingleLock pLock( &Transfers.m_pSection, TRUE );
01096         
01097         for ( POSITION pos = GetIterator() ; pos ; )
01098         {
01099                 CDownload* pDownload = GetNext( pos );
01100                 if ( bForce || pDownload->m_nCookie != pDownload->m_nSaveCookie ) pDownload->Save( TRUE );
01101         }
01102 }
01103 
01105 // CDownloads load all the old compound file formats
01106 
01107 void CDownloads::LoadFromCompoundFiles()
01108 {
01109         if ( LoadFromCompoundFile( Settings.Downloads.IncompletePath + _T("\\Shareaza Downloads.dat") ) )
01110         {
01111                 // Good
01112         }
01113         else if ( LoadFromCompoundFile( Settings.Downloads.IncompletePath + _T("\\Shareaza Downloads.bak") ) )
01114         {
01115                 // Good
01116         }
01117         else if ( LoadFromTimePair() )
01118         {
01119                 // Good
01120         }
01121         
01122         DeleteFile( Settings.Downloads.IncompletePath + _T("\\Shareaza Downloads.dat") );
01123         DeleteFile( Settings.Downloads.IncompletePath + _T("\\Shareaza Downloads.bak") );
01124         DeleteFile( Settings.Downloads.IncompletePath + _T("\\Shareaza.dat") );
01125         DeleteFile( Settings.Downloads.IncompletePath + _T("\\Shareaza1.dat") );
01126         DeleteFile( Settings.Downloads.IncompletePath + _T("\\Shareaza2.dat") );
01127 }
01128 
01129 BOOL CDownloads::LoadFromCompoundFile(LPCTSTR pszFile)
01130 {
01131         CFile pFile;
01132         
01133         if ( ! pFile.Open( pszFile, CFile::modeRead ) ) return FALSE;
01134         
01135         CArchive ar( &pFile, CArchive::load );
01136         
01137         try
01138         {
01139                 SerializeCompound( ar );
01140         }
01141         catch ( CException* pException )
01142         {
01143                 pException->Delete();
01144                 Clear();
01145                 return FALSE;
01146         }
01147         
01148         return TRUE;
01149 }
01150 
01151 BOOL CDownloads::LoadFromTimePair()
01152 {
01153         FILETIME pFileTime1 = { 0, 0 }, pFileTime2 = { 0, 0 };
01154         CFile pFile1, pFile2;
01155         BOOL bFile1, bFile2;
01156         CString strFile;
01157         
01158         strFile = Settings.Downloads.IncompletePath + _T("\\Shareaza");
01159         bFile1  = pFile1.Open( strFile + _T("1.dat"), CFile::modeRead );
01160         bFile2  = pFile2.Open( strFile + _T("2.dat"), CFile::modeRead );
01161         
01162         if ( bFile1 || bFile2 )
01163         {
01164                 if ( bFile1 ) bFile1 = pFile1.Read( &pFileTime1, sizeof(FILETIME) ) == sizeof(FILETIME);
01165                 if ( bFile2 ) bFile2 = pFile2.Read( &pFileTime2, sizeof(FILETIME) ) == sizeof(FILETIME);
01166         }
01167         else
01168         {
01169                 if ( ! pFile1.Open( strFile + _T(".dat"), CFile::modeRead ) ) return FALSE;
01170                 pFileTime1.dwHighDateTime++;
01171         }
01172         
01173         CFile* pNewest = ( CompareFileTime( &pFileTime1, &pFileTime2 ) >= 0 ) ? &pFile1 : &pFile2;
01174         
01175         try
01176         {
01177                 CArchive ar( pNewest, CArchive::load );
01178                 SerializeCompound( ar );
01179                 ar.Close();
01180         }
01181         catch ( CException* pException )
01182         {
01183                 pException->Delete();
01184                 Clear();
01185                 
01186                 if ( pNewest == &pFile1 && bFile2 )
01187                         pNewest = &pFile2;
01188                 else if ( pNewest == &pFile2 && bFile1 )
01189                         pNewest = &pFile1;
01190                 else
01191                         pNewest = NULL;
01192 
01193                 if ( pNewest != NULL )
01194                 {
01195                         try
01196                         {
01197                                 CArchive ar( pNewest, CArchive::load );
01198                                 SerializeCompound( ar );
01199                                 ar.Close();
01200                         }
01201                         catch ( CException* pException )
01202                         {
01203                                 pException->Delete();
01204                                 Clear();
01205                                 return FALSE;
01206                         }
01207                 }
01208         }
01209         
01210         return TRUE;
01211 }
01212 
01213 void CDownloads::SerializeCompound(CArchive& ar)
01214 {
01215         ASSERT( ar.IsLoading() );
01216         
01217         int nVersion;
01218         ar >> nVersion;
01219         if ( nVersion < 4 ) return;
01220         
01221         for ( int nCount = ar.ReadCount() ; nCount > 0 ; nCount-- )
01222         {
01223                 CDownload* pDownload = new CDownload();
01224                 m_pList.AddTail( pDownload );
01225                 pDownload->Serialize( ar, nVersion );
01226         }
01227 }
01228 
01230 // CDownloads left over file purge operations
01231 
01232 void CDownloads::PurgeDeletes()
01233 {
01234         CStringList pRemove;
01235         HKEY hKey = NULL;
01236         
01237         if ( ERROR_SUCCESS != RegOpenKeyEx( HKEY_CURRENT_USER,
01238                 _T("Software\\Shareaza\\Shareaza\\Delete"), 0, KEY_ALL_ACCESS, &hKey ) ) return;
01239         
01240         for ( DWORD nIndex = 0 ; nIndex < 1000 ; nIndex ++ )
01241         {
01242                 DWORD nPath = MAX_PATH*2;
01243                 TCHAR szPath[MAX_PATH*2];
01244                 
01245                 if ( ERROR_SUCCESS != RegEnumValue( hKey, nIndex, szPath, &nPath, NULL,
01246                         NULL, NULL, NULL ) ) break;
01247                 
01248                 if ( GetFileAttributes( szPath ) == 0xFFFFFFFF || DeleteFile( szPath ) )
01249                 {
01250                         pRemove.AddTail( szPath );
01251                 }
01252         }
01253         
01254         while ( ! pRemove.IsEmpty() )
01255         {
01256                 RegDeleteValue( hKey, pRemove.RemoveHead() );
01257         }
01258         
01259         RegCloseKey( hKey );
01260 }
01261 
01262 void CDownloads::PurgePreviews()
01263 {
01264         WIN32_FIND_DATA pFind;
01265         HANDLE hSearch;
01266         CString strPath;
01267         
01268         strPath = Settings.Downloads.IncompletePath + _T("\\Preview of *.*");
01269         hSearch = FindFirstFile( strPath, &pFind );
01270         if ( hSearch == INVALID_HANDLE_VALUE ) return;
01271         
01272         do
01273         {
01274                 if ( _tcsnicmp( pFind.cFileName, _T("Preview of "), 11 ) == 0 )
01275                 {
01276                         strPath = Settings.Downloads.IncompletePath + '\\' + pFind.cFileName;
01277                         DeleteFile( strPath );
01278                 }
01279         }
01280         while ( FindNextFile( hSearch, &pFind ) );
01281         
01282         FindClose( hSearch );
01283 }

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