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 "Download.h"
00026 #include "Downloads.h"
00027 #include "DownloadTask.h"
00028 #include "DownloadSource.h"
00029 #include "DownloadTransfer.h"
00030 #include "DownloadGroups.h"
00031 #include "Uploads.h"
00032
00033 #include "Library.h"
00034 #include "LibraryBuilder.h"
00035 #include "LibraryHistory.h"
00036 #include "FragmentedFile.h"
00037 #include "BTTrackerRequest.h"
00038 #include "XML.h"
00039
00040 #ifdef _DEBUG
00041 #undef THIS_FILE
00042 static char THIS_FILE[]=__FILE__;
00043 #define new DEBUG_NEW
00044 #endif
00045
00046
00048
00049
00050 CDownload::CDownload()
00051 {
00052 m_nSerID = Downloads.GetFreeSID();
00053 m_bExpanded = Settings.Downloads.AutoExpand;
00054 m_bSelected = FALSE;
00055 m_bVerify = TS_UNKNOWN;
00056
00057 m_nRunCookie = 0;
00058 m_nSaveCookie = 0;
00059 m_nGroupCookie = 0;
00060
00061 m_bPaused = FALSE;
00062 m_bBoosted = FALSE;
00063 m_bShared = Settings.Uploads.SharePartials;
00064 m_bComplete = FALSE;
00065 m_tCompleted = 0;
00066 m_tSaved = 0;
00067 m_tBegan = 0;
00068
00069 m_bDownloading = FALSE;
00070
00071 DownloadGroups.Link( this );
00072 }
00073
00074 CDownload::~CDownload()
00075 {
00076 if ( m_pTask != NULL ) m_pTask->Abort();
00077 DownloadGroups.Unlink( this );
00078
00079 if ( m_pTorrent.m_nFiles > 1 && m_bComplete )
00080 {
00081 CloseTransfers();
00082 CloseTorrentUploads();
00083 Uploads.OnRename( m_sLocalName, NULL );
00084 if ( ! ::DeleteFile( m_sLocalName ) )
00085 theApp.WriteProfileString( _T("Delete"), m_sLocalName, _T("") );
00086 }
00087 }
00088
00090
00091
00092 void CDownload::Pause()
00093 {
00094 if ( m_bComplete || m_bPaused ) return;
00095
00096 theApp.Message( MSG_DOWNLOAD, IDS_DOWNLOAD_PAUSED, (LPCTSTR)GetDisplayName() );
00097
00098 StopTrying();
00099
00100 m_bPaused = TRUE;
00101 }
00102
00104
00105
00106 void CDownload::Resume()
00107 {
00108 if ( m_bComplete ) return;
00109 if ( ! m_bPaused )
00110 {
00111 if ( ( m_tBegan == 0 ) && ( GetSourceCount() < 2 ) ) FindMoreSources();
00112 SetStartTimer();
00113 return;
00114 }
00115
00116 theApp.Message( MSG_DOWNLOAD, IDS_DOWNLOAD_RESUMED, (LPCTSTR)GetDisplayName() );
00117
00118 if ( m_pFile != NULL )
00119 {
00120 for ( CDownloadSource* pSource = GetFirstSource() ; pSource ; pSource = pSource->m_pNext )
00121 {
00122 pSource->OnResume();
00123 }
00124 }
00125
00126 m_bPaused = FALSE;
00127 m_bDiskFull = FALSE;
00128 m_tReceived = GetTickCount();
00129 m_bTorrentTrackerError = FALSE;
00130 m_nTorrentTrackerErrors = 0;
00131
00132 if( m_bBTH )
00133 {
00134 if ( Downloads.GetTryingCount( TRUE ) < Settings.BitTorrent.DownloadTorrents )
00135 SetStartTimer();
00136 }
00137 else
00138 {
00139 if ( Downloads.GetTryingCount( FALSE ) < ( Settings.Downloads.MaxFiles + Settings.Downloads.MaxFileSearches ) )
00140 SetStartTimer();
00141 }
00142
00143 SetModified();
00144 CloseTorrentUploads();
00145 }
00146
00148
00149
00150 void CDownload::Remove(BOOL bDelete)
00151 {
00152 CloseTorrentUploads();
00153 CloseTransfers();
00154 CloseFile();
00155
00156 if ( m_pTask != NULL )
00157 {
00158 m_pTask->Abort();
00159 ASSERT( m_pTask == NULL );
00160 }
00161
00162 if ( bDelete || ! IsCompleted() )
00163 {
00164 theApp.Message( MSG_DOWNLOAD, IDS_DOWNLOAD_REMOVE, (LPCTSTR)GetDisplayName() );
00165 }
00166
00167 DeleteFile( bDelete );
00168 DeletePreviews();
00169
00170 ::DeleteFile( m_sLocalName + _T(".sd") );
00171
00172 Downloads.Remove( this );
00173 }
00174
00176
00177
00178 void CDownload::Boost()
00179 {
00180 if ( m_pFile == NULL || m_bBoosted ) return;
00181
00182 theApp.Message( MSG_SYSTEM, IDS_DOWNLOAD_BOOST, (LPCTSTR)GetDisplayName() );
00183
00184 for ( CDownloadTransfer* pTransfer = GetFirstTransfer() ; pTransfer ; pTransfer = pTransfer->m_pDlNext )
00185 {
00186 pTransfer->Boost();
00187 }
00188
00189 m_bBoosted = TRUE;
00190 SetModified();
00191 }
00192
00194
00195
00196 void CDownload::Share(BOOL bShared)
00197 {
00198 m_bShared = bShared;
00199 SetModified();
00200 }
00201
00203
00204
00205 BOOL CDownload::Rename(LPCTSTR pszName)
00206 {
00207 if ( m_sRemoteName == pszName ) return FALSE;
00208 m_sRemoteName = pszName;
00209 SetModified();
00210 return TRUE;
00211 }
00212
00214
00215
00216 void CDownload::StopTrying()
00217 {
00218 if ( m_bComplete ) return;
00219 m_tBegan = 0;
00220 m_bDownloading = FALSE;
00221
00222 if ( m_bBTH ) CloseTorrent();
00223 CloseTransfers();
00224 CloseFile();
00225 StopSearch();
00226 SetModified();
00227 }
00228
00230
00231
00232 void CDownload::SetStartTimer()
00233 {
00234 m_tBegan = GetTickCount();
00235 SetModified();
00236 }
00237
00239
00240
00241 DWORD CDownload::GetStartTimer() const
00242 {
00243 return( m_tBegan );
00244 }
00245
00247
00248
00249 BOOL CDownload::IsStarted() const
00250 {
00251 return ( GetVolumeComplete() > 0 );
00252 }
00253
00254 BOOL CDownload::IsPaused() const
00255 {
00256 return m_bPaused;
00257 }
00258
00259 BOOL CDownload::IsDownloading() const
00260 {
00261 return m_bDownloading;
00262 }
00263
00264 BOOL CDownload::IsMoving() const
00265 {
00266 return ( m_pFile == NULL );
00267 }
00268
00269 BOOL CDownload::IsCompleted() const
00270 {
00271 return m_bComplete;
00272 }
00273
00274 BOOL CDownload::IsBoosted() const
00275 {
00276 return m_bBoosted;
00277 }
00278
00279 BOOL CDownload::IsTrying() const
00280 {
00281 return ( m_tBegan != 0 );
00282 }
00283
00284 BOOL CDownload::IsShared() const
00285 {
00286 return m_bShared || m_bBTH || Settings.eDonkey.EnableToday;
00287 }
00288
00290
00291
00292 void CDownload::OnRun()
00293 {
00294 DWORD tNow = GetTickCount();
00295 BOOL bDownloading = FALSE;
00296
00297 if ( ! m_bPaused )
00298 {
00299 if ( m_bDiskFull ) Pause();
00300 else if ( IsTrying() )
00301 {
00302
00303
00304 if ( ( ! m_bComplete ) && ( tNow - GetStartTimer() ) > ( 3 * 60 * 60 * 1000 ) )
00305 {
00306
00307 DWORD tHoursToTry = min ( ( GetSourceCount() + 49 ) / 50 , 9 ) + Settings.Downloads.StarveGiveUp;
00308
00309 if ( ( tNow - m_tReceived ) > ( tHoursToTry * 60 * 60 * 1000 ) )
00310 {
00311
00312 if( m_bBTH )
00313 {
00314 if( Downloads.GetTryingCount( TRUE ) >= Settings.BitTorrent.DownloadTorrents )
00315 {
00316 StopTrying();
00317 return;
00318 }
00319 }
00320 else
00321 {
00322 if( Downloads.GetTryingCount( FALSE ) >= ( Settings.Downloads.MaxFiles + Settings.Downloads.MaxFileSearches ) )
00323 {
00324 StopTrying();
00325 return;
00326 }
00327 }
00328 }
00329 }
00330
00331
00332 if ( RunTorrent( tNow ) )
00333 {
00334 RunSearch( tNow );
00335
00336 if ( m_bSeeding )
00337 {
00338 RunValidation( TRUE );
00339 }
00340 else if ( m_pFile != NULL )
00341 {
00342 RunValidation( FALSE );
00343
00344 if ( RunFile( tNow ) )
00345 {
00346 if ( ValidationCanFinish() ) OnDownloaded();
00347 }
00348 else
00349 {
00350 if ( CheckTorrentRatio() ) StartTransfersIfNeeded( tNow );
00351 }
00352 }
00353 else if ( m_pFile == NULL && ! m_bComplete && m_pTask == NULL )
00354 {
00355 OnDownloaded();
00356 }
00357 }
00358
00359
00360 if( GetTransferCount() > 0 ) bDownloading = TRUE;
00361
00362 }
00363 else if ( ! m_bComplete )
00364 {
00365 if( m_bBTH )
00366 {
00367 if( Downloads.GetTryingCount( TRUE ) < Settings.BitTorrent.DownloadTorrents )
00368 SetStartTimer();
00369 }
00370 else
00371 {
00372
00373 if( Downloads.GetTryingCount( FALSE ) < ( Settings.Downloads.MaxFiles + Settings.Downloads.MaxFileSearches ) )
00374 SetStartTimer();
00375 }
00376 }
00377 }
00378
00379
00380 m_bDownloading = bDownloading;
00381
00382
00383 if ( tNow - m_tSaved >=
00384 ( m_nSourceCount > 20 ? 5 * Settings.Downloads.SaveInterval : Settings.Downloads.SaveInterval ) )
00385 {
00386 if ( m_pFile != NULL && m_pFile->Flush() )
00387 {
00388 m_tSaved = tNow;
00389 }
00390
00391 if ( m_nCookie != m_nSaveCookie )
00392 {
00393 Save();
00394 m_tSaved = tNow;
00395 }
00396 }
00397 }
00398
00400
00401
00402 void CDownload::OnDownloaded()
00403 {
00404 ASSERT( m_bComplete == FALSE );
00405
00406 theApp.Message( MSG_DOWNLOAD, IDS_DOWNLOAD_COMPLETED, (LPCTSTR)GetDisplayName() );
00407 m_tCompleted = GetTickCount();
00408 m_bDownloading = FALSE;
00409
00410 CloseTransfers();
00411
00412 if ( m_pFile != NULL )
00413 {
00414 m_pFile->Close();
00415 delete m_pFile;
00416 m_pFile = NULL;
00417 AppendMetadata();
00418 }
00419
00420 ASSERT( m_pTask == NULL );
00421 m_pTask = new CDownloadTask( this, CDownloadTask::dtaskCopySimple );
00422
00423 SetModified();
00424 }
00425
00427
00428
00429 void CDownload::OnTaskComplete(CDownloadTask* pTask)
00430 {
00431 ASSERT( m_pTask == pTask );
00432 m_pTask = NULL;
00433
00434 if ( pTask->WasAborted() ) return;
00435
00436 if ( pTask->m_nTask == CDownloadTask::dtaskAllocate )
00437 {
00438
00439 }
00440 else
00441 {
00442 OnMoved( pTask );
00443 }
00444 }
00445
00447
00448
00449 void CDownload::OnMoved(CDownloadTask* pTask)
00450 {
00451 CString strLocalName = m_sLocalName;
00452 ASSERT( m_pFile == NULL );
00453
00454 if ( pTask->m_bSuccess )
00455 {
00456 m_sLocalName = pTask->m_sFilename;
00457
00458 theApp.Message( MSG_DOWNLOAD, IDS_DOWNLOAD_MOVED,
00459 (LPCTSTR)GetDisplayName(), (LPCTSTR)m_sLocalName );
00460
00461 if ( m_pXML != NULL && Settings.Downloads.Metadata )
00462 WriteMetadata( pTask->m_sPath );
00463 }
00464 else
00465 {
00466 theApp.Message( MSG_ERROR, IDS_DOWNLOAD_CANT_MOVE,
00467 (LPCTSTR)GetDisplayName(), (LPCTSTR)pTask->m_sPath );
00468
00469 if ( m_pTorrent.IsAvailable() )
00470 {
00471 m_bDiskFull = TRUE;
00472 return;
00473 }
00474 }
00475
00476 m_bComplete = TRUE;
00477 m_tCompleted = GetTickCount();
00478
00479 ::DeleteFile( strLocalName + _T(".sd") );
00480
00481 if ( m_nTorrentBlock > 0 && m_nTorrentSuccess >= m_nTorrentBlock )
00482 {
00483 CBTTrackerRequest::SendCompleted( this );
00484 }
00485
00486 LibraryBuilder.RequestPriority( m_sLocalName );
00487
00488 if ( m_bSHA1 || m_bED2K )
00489 {
00490 LibraryHistory.Add( m_sLocalName, m_bSHA1 ? &m_pSHA1 : NULL,
00491 m_bED2K ? &m_pED2K : NULL, GetSourceURLs( NULL, 0, PROTOCOL_NULL, NULL ) );
00492 }
00493 else
00494 {
00495 LibraryHistory.Add( m_sLocalName, NULL, NULL, NULL );
00496 }
00497
00498 ClearSources();
00499 SetModified();
00500
00501 if ( IsFullyVerified() ) OnVerify( m_sLocalName, TRUE );
00502 }
00503
00505
00506
00507 BOOL CDownload::OnVerify(LPCTSTR pszPath, BOOL bVerified)
00508 {
00509 if ( m_bVerify != TS_UNKNOWN ) return FALSE;
00510 if ( m_pFile != NULL ) return FALSE;
00511
00512 if ( pszPath != (LPCTSTR)m_sLocalName &&
00513 m_sLocalName.CompareNoCase( pszPath ) != 0 ) return FALSE;
00514
00515 m_bVerify = bVerified ? TS_TRUE : TS_FALSE;
00516 SetModified();
00517
00518 return TRUE;
00519 }
00520
00522
00523
00524 BOOL CDownload::Load(LPCTSTR pszName)
00525 {
00526 BOOL bSuccess = FALSE;
00527 CFile pFile;
00528
00529 m_sLocalName = pszName;
00530 m_sLocalName = m_sLocalName.Left( m_sLocalName.GetLength() - 3 );
00531
00532 if ( pFile.Open( m_sLocalName + _T(".sd"), CFile::modeRead ) )
00533 {
00534 try
00535 {
00536 CArchive ar( &pFile, CArchive::load );
00537 Serialize( ar, 0 );
00538 bSuccess = TRUE;
00539 }
00540 catch ( CException* pException )
00541 {
00542 pException->Delete();
00543 }
00544
00545 pFile.Close();
00546 }
00547
00548 if ( ! bSuccess && pFile.Open( m_sLocalName + _T(".sd.sav"), CFile::modeRead ) )
00549 {
00550 try
00551 {
00552 CArchive ar( &pFile, CArchive::load );
00553 Serialize( ar, 0 );
00554 bSuccess = TRUE;
00555 }
00556 catch ( CException* pException )
00557 {
00558 pException->Delete();
00559 }
00560
00561 pFile.Close();
00562 if ( bSuccess ) Save();
00563 }
00564
00565 m_nSaveCookie = m_nCookie;
00566
00567 return bSuccess;
00568 }
00569
00570 BOOL CDownload::Save(BOOL bFlush)
00571 {
00572 CFile pFile;
00573
00574 m_nSaveCookie = m_nCookie;
00575 m_tSaved = GetTickCount();
00576
00577 if ( m_bComplete ) return TRUE;
00578
00579 GenerateLocalName();
00580 ::DeleteFile( m_sLocalName + _T(".sd.sav") );
00581
00582 if ( ! pFile.Open( m_sLocalName + _T(".sd.sav"),
00583 CFile::modeReadWrite|CFile::modeCreate|CFile::osWriteThrough ) ) return FALSE;
00584
00585 {
00586 BYTE pBuffer[ 65536 ];
00587 CArchive ar( &pFile, CArchive::store, sizeof( pBuffer ), pBuffer );
00588 Serialize( ar, 0 );
00589 ar.Close();
00590 }
00591
00592 if ( Settings.Downloads.FlushSD || bFlush ) pFile.Flush();
00593 pFile.SeekToBegin();
00594 CHAR szID[3] = { 0, 0, 0 };
00595 pFile.Read( szID, 3 );
00596 pFile.Close();
00597
00598 if ( szID[0] == 'S' && szID[1] == 'D' && szID[2] == 'L' )
00599 {
00600 ::DeleteFile( m_sLocalName + _T(".sd") );
00601 MoveFile( m_sLocalName + _T(".sd.sav"), m_sLocalName + _T(".sd") );
00602 return TRUE;
00603 }
00604 else
00605 {
00606 ::DeleteFile( m_sLocalName + _T(".sd.sav") );
00607 return FALSE;
00608 }
00609 }
00610
00612
00613
00614 #define DOWNLOAD_SER_VERSION 32
00615
00616 void CDownload::Serialize(CArchive& ar, int nVersion)
00617 {
00618 ASSERT( ! m_bComplete );
00619
00620 if ( nVersion == 0 )
00621 {
00622 nVersion = DOWNLOAD_SER_VERSION;
00623
00624 if ( ar.IsStoring() )
00625 {
00626 ar.Write( "SDL", 3 );
00627 ar << nVersion;
00628 }
00629 else
00630 {
00631 CHAR szID[3];
00632 ar.Read( szID, 3 );
00633 if ( strncmp( szID, "SDL", 3 ) ) AfxThrowUserException();
00634 ar >> nVersion;
00635 if ( nVersion <= 0 || nVersion > DOWNLOAD_SER_VERSION ) AfxThrowUserException();
00636 }
00637 }
00638 else if ( nVersion < 11 && ar.IsLoading() )
00639 {
00640 SerializeOld( ar, nVersion );
00641 return;
00642 }
00643
00644 CDownloadWithExtras::Serialize( ar, nVersion );
00645
00646 if ( ar.IsStoring() )
00647 {
00648 ar << m_bExpanded;
00649 ar << m_bPaused;
00650 ar << m_bBoosted;
00651 ar << m_bShared;
00652
00653 ar << m_nSerID;
00654 }
00655 else
00656 {
00657 ar >> m_bExpanded;
00658 ar >> m_bPaused;
00659 ar >> m_bBoosted;
00660 if ( nVersion >= 14 ) ar >> m_bShared;
00661 if ( nVersion >= 26 ) ar >> m_nSerID;
00662
00663 DownloadGroups.Link( this );
00664 }
00665 }
00666
00667 void CDownload::SerializeOld(CArchive& ar, int nVersion)
00668 {
00669 ASSERT( ar.IsLoading() );
00670
00671 ar >> m_sLocalName;
00672 ar >> m_sRemoteName;
00673
00674 DWORD nSize;
00675 ar >> nSize;
00676 m_nSize = nSize;
00677
00678 ar >> m_bSHA1;
00679 if ( m_bSHA1 ) ar.Read( &m_pSHA1, sizeof(SHA1) );
00680
00681 ar >> m_bPaused;
00682 ar >> m_bExpanded;
00683 if ( nVersion >= 6 ) ar >> m_bBoosted;
00684
00685 m_pFile->Serialize( ar, nVersion );
00686 GenerateLocalName();
00687
00688 for ( int nSources = ar.ReadCount() ; nSources ; nSources-- )
00689 {
00690 CDownloadSource* pSource = new CDownloadSource( this );
00691 pSource->Serialize( ar, nVersion );
00692 AddSourceInternal( pSource );
00693 }
00694
00695 if ( nVersion >= 3 && ar.ReadCount() )
00696 {
00697 m_pXML = new CXMLElement();
00698 m_pXML->Serialize( ar );
00699 }
00700 }