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

DownloadWithSources.cpp

Go to the documentation of this file.
00001 //
00002 // DownloadWithSources.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 "DownloadWithSources.h"
00027 #include "DownloadSource.h"
00028 #include "Network.h"
00029 #include "Neighbours.h"
00030 #include "Transfer.h"
00031 #include "QueryHit.h"
00032 #include "SourceURL.h"
00033 #include "Schema.h"
00034 #include "SchemaCache.h"
00035 #include "XML.h"
00036 #include "SHA.h"
00037 #include "MD4.h"
00038 #include "TigerTree.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 // CDownloadWithSources construction
00049 
00050 CDownloadWithSources::CDownloadWithSources()
00051 {
00052         m_pSourceFirst  = NULL;
00053         m_pSourceLast   = NULL;
00054         m_nSourceCount  = 0;
00055         m_pXML                  = NULL;
00056 }
00057 
00058 CDownloadWithSources::~CDownloadWithSources()
00059 {
00060         ClearSources();
00061         if ( m_pXML != NULL ) delete m_pXML;
00062 }
00063 
00065 // CDownloadWithSources list access
00066 
00067 int CDownloadWithSources::GetSourceCount(BOOL bNoPush, BOOL bSane) const
00068 {
00069         if ( ! bNoPush && ! bSane ) return m_nSourceCount;
00070         
00071         DWORD tNow = GetTickCount();
00072         int nCount = 0;
00073         
00074         for ( CDownloadSource* pSource = m_pSourceFirst ; pSource ; pSource = pSource->m_pNext )
00075         {
00076                 if ( ! bNoPush || ! pSource->m_bPushOnly )
00077                 {
00078                         if ( ! bSane ||
00079                                  pSource->m_tAttempt < tNow ||
00080                                  pSource->m_tAttempt - tNow <= 900000 )
00081                         {
00082                                 nCount++;
00083                         }
00084                 }
00085         }
00086         
00087         return nCount;
00088 }
00089 
00090 
00091 int CDownloadWithSources::GetBTSourceCount(BOOL bNoPush) const
00092 {
00093         DWORD tNow = GetTickCount();
00094         int nCount = 0;
00095         
00096         for ( CDownloadSource* pSource = m_pSourceFirst ; pSource ; pSource = pSource->m_pNext )
00097         {
00098                 if ( ( pSource->m_nProtocol == PROTOCOL_BT ) &&                                                                 // Only counting BT sources
00099                          ( pSource->m_tAttempt < tNow || pSource->m_tAttempt - tNow <= 900000 ) &&      // Don't count dead sources
00100                          ( ! pSource->m_bPushOnly || ! bNoPush ) )                                                                      // Push sources might not be counted
00101                 {
00102                         nCount++;
00103                 }
00104         }
00105         
00106         /*
00107         CString strT;
00108         strT.Format(_T("BT sources: %i"), nCount);
00109         theApp.Message( MSG_ERROR, strT );*/
00110         return nCount;
00111 }
00112 
00113 int CDownloadWithSources::GetED2KCompleteSourceCount() const
00114 {
00115 
00116         DWORD tNow = GetTickCount();
00117         int nCount = 0;
00118         
00119         for ( CDownloadSource* pSource = m_pSourceFirst ; pSource ; pSource = pSource->m_pNext )
00120         {
00121                 if ( ( ! pSource->m_bPushOnly ) && // Push sources can't be counted since you often cannot reach them
00122                          ( pSource->m_tAttempt < tNow || pSource->m_tAttempt - tNow <= 900000 ) &&      // This source is probably dead
00123                          ( pSource->m_nProtocol == PROTOCOL_ED2K ) && // Only counting ed2k sources
00124              ( pSource->m_oAvailable.empty() ) ) // Only counting complete sources
00125                         
00126                 {
00127                         nCount++;
00128                 }
00129         }
00130         
00131         /*
00132         CString strT;
00133         strT.Format(_T("Complete ed2k sources: %i"), nCount);
00134         theApp.Message( MSG_ERROR, strT );*/
00135         return nCount;
00136 }
00137 
00138 BOOL CDownloadWithSources::CheckSource(CDownloadSource* pCheck) const
00139 {
00140         for ( CDownloadSource* pSource = m_pSourceFirst ; pSource ; pSource = pSource->m_pNext )
00141         {
00142                 if ( pSource == pCheck ) return TRUE;
00143         }
00144         
00145         return FALSE;
00146 }
00147 
00149 // CDownloadWithSources clear
00150 
00151 void CDownloadWithSources::ClearSources()
00152 {
00153         for ( CDownloadSource* pSource = GetFirstSource() ; pSource ; )
00154         {
00155                 CDownloadSource* pNext = pSource->m_pNext;
00156                 delete pSource;
00157                 pSource = pNext;
00158         }
00159         
00160         m_pSourceFirst = m_pSourceLast = NULL;
00161         m_nSourceCount = 0;
00162         
00163         SetModified();
00164 }
00165 
00167 // CDownloadWithSources add a query-hit source
00168 
00169 BOOL CDownloadWithSources::AddSourceHit(CQueryHit* pHit, BOOL bForce)
00170 {
00171         BOOL bHash = FALSE;
00172         
00173         if ( ! bForce )
00174         {
00175                 if ( m_bSHA1 && pHit->m_bSHA1 )
00176                 {
00177                         if ( m_pSHA1 != pHit->m_pSHA1 ) return FALSE;
00178                         bHash = TRUE;
00179                 }
00180                 else if ( m_bTiger && pHit->m_bTiger )
00181                 {
00182                         if ( m_pTiger != pHit->m_pTiger ) return FALSE;
00183                         bHash = TRUE;
00184                 }
00185                 if ( m_bED2K && pHit->m_bED2K )
00186                 {
00187                         if ( m_pED2K != pHit->m_pED2K ) return FALSE;
00188                         bHash = TRUE;
00189                 }
00190                 if ( m_bBTH && pHit->m_bBTH )
00191                 {
00192                         if ( m_pBTH != pHit->m_pBTH ) return FALSE;
00193                         bHash = TRUE;
00194                 }
00195         }
00196         
00197         if ( ! bHash && ! bForce )
00198         {
00199                 if ( Settings.General.HashIntegrity ) return FALSE;
00200                 
00201                 if ( m_sRemoteName.IsEmpty() || pHit->m_sName.IsEmpty() ) return FALSE;
00202                 if ( m_nSize == SIZE_UNKNOWN || ! pHit->m_bSize ) return FALSE;
00203                 
00204                 if ( m_nSize != pHit->m_nSize ) return FALSE;
00205                 if ( m_sRemoteName.CompareNoCase( pHit->m_sName ) ) return FALSE;
00206         }
00207         
00208         if ( ! m_bSHA1 && pHit->m_bSHA1 )
00209         {
00210                 m_bSHA1 = TRUE;
00211                 m_pSHA1 = pHit->m_pSHA1;
00212         }
00213         if ( ! m_bTiger && pHit->m_bTiger )
00214         {
00215                 m_bTiger = TRUE;
00216                 m_pTiger = pHit->m_pTiger;
00217         }
00218         if ( ! m_bED2K && pHit->m_bED2K )
00219         {
00220                 m_bED2K = TRUE;
00221                 m_pED2K = pHit->m_pED2K;
00222         }
00223         
00224         if ( m_nSize == SIZE_UNKNOWN && pHit->m_bSize )
00225         {
00226                 m_nSize = pHit->m_nSize;
00227         }
00228         
00229         if ( m_sRemoteName.IsEmpty() && pHit->m_sName.GetLength() )
00230         {
00231                 m_sRemoteName = pHit->m_sName;
00232         }
00233         
00234         if ( Settings.Downloads.Metadata && m_pXML == NULL )
00235         {
00236                 if ( pHit->m_pXML != NULL && pHit->m_sSchemaPlural.GetLength() )
00237                 {
00238                         m_pXML = new CXMLElement( NULL, pHit->m_sSchemaPlural );
00239                         m_pXML->AddAttribute( _T("xmlns:xsi"), CXMLAttribute::xmlnsInstance );
00240                         m_pXML->AddAttribute( CXMLAttribute::schemaName, pHit->m_sSchemaURI );
00241                         m_pXML->AddElement( pHit->m_pXML->Clone() );
00242                         
00243                         if ( CSchema* pSchema = SchemaCache.Get( pHit->m_sSchemaURI ) )
00244                         {
00245                                 pSchema->Validate( m_pXML, TRUE );
00246                         }
00247                 }
00248         }
00249 
00250         /*
00251         if ( pHit->m_nProtocol == PROTOCOL_ED2K )
00252         {
00253                 Neighbours.FindDonkeySources( &pHit->m_pED2K,
00254                         (IN_ADDR*)pHit->m_pClientID.w, (WORD)pHit->m_pClientID.w[1] );
00255         }
00256         */
00257 
00258         // No URL, stop now with success
00259         if ( pHit->m_sURL.IsEmpty() ) return TRUE;
00260         
00261         return AddSourceInternal( new CDownloadSource( (CDownload*)this, pHit ) );
00262 }
00263 
00265 // CDownloadWithSources add miscellaneous sources
00266 
00267 BOOL CDownloadWithSources::AddSourceED2K(DWORD nClientID, WORD nClientPort, DWORD nServerIP, WORD nServerPort, GGUID* pGUID)
00268 {
00269         return AddSourceInternal( new CDownloadSource( (CDownload*)this, nClientID, nClientPort, nServerIP, nServerPort, pGUID ) );
00270 }
00271 
00272 BOOL CDownloadWithSources::AddSourceBT(SHA1* pGUID, IN_ADDR* pAddress, WORD nPort)
00273 {
00274         // Unreachable (Push) BT sources should never be added.
00275         if ( Network.IsFirewalledAddress( pAddress, Settings.Connection.IgnoreOwnIP ) )
00276                 return FALSE;
00277         
00278         // Check for own IP, in case IgnoreLocalIP is not set
00279         if ( ( Settings.Connection.IgnoreOwnIP ) && ( pAddress->S_un.S_addr == Network.m_pHost.sin_addr.S_un.S_addr ) ) 
00280                 return FALSE;
00281 
00282         return AddSourceInternal( new CDownloadSource( (CDownload*)this, pGUID, pAddress, nPort ) );
00283 }
00284 
00286 // CDownloadWithSources add a single URL source
00287 
00288 BOOL CDownloadWithSources::AddSourceURL(LPCTSTR pszURL, BOOL bURN, FILETIME* pLastSeen)
00289 {
00290         if ( pszURL == NULL ) return FALSE;
00291         if ( *pszURL == 0 ) return FALSE;
00292         
00293         BOOL bHashAuth = FALSE;
00294         CSourceURL pURL;
00295         
00296         if ( *pszURL == '@' )
00297         {
00298                 bHashAuth = TRUE;
00299                 pszURL++;
00300         }
00301         
00302         if ( ! pURL.Parse( pszURL ) ) return FALSE;
00303         
00304         if ( bURN )
00305         {
00306                 if ( pURL.m_pAddress.S_un.S_addr == Network.m_pHost.sin_addr.S_un.S_addr ) return FALSE;
00307                 if ( Network.IsFirewalledAddress( &pURL.m_pAddress, TRUE ) ) return FALSE;
00308         }
00309         
00310         if ( m_pFailedSources.Find( pszURL ) != NULL ) return FALSE;
00311         
00312         if ( pURL.m_bSHA1 && m_bSHA1 )
00313         {
00314                 if ( m_pSHA1 != pURL.m_pSHA1 ) return FALSE;
00315         }
00316         
00317         if ( m_sRemoteName.IsEmpty() && _tcslen( pszURL ) > 9 )
00318         {
00319                 m_sRemoteName = &pszURL[8];
00320                 
00321                 int nPos = m_sRemoteName.ReverseFind( '/' );
00322                 
00323                 if ( nPos >= 0 )
00324                 {
00325                         m_sRemoteName = m_sRemoteName.Mid( nPos + 1 ).SpanExcluding( _T("?") );
00326                         m_sRemoteName = CTransfer::URLDecode( m_sRemoteName );
00327                 }
00328                 else
00329                 {
00330                         m_sRemoteName.Empty();
00331                 }
00332                 
00333                 if ( m_sRemoteName.IsEmpty() ) m_sRemoteName = _T("default.htm");
00334         }
00335         
00336         return AddSourceInternal( new CDownloadSource( (CDownload*)this, pszURL, bURN, bHashAuth, pLastSeen ) );
00337 }
00338 
00340 // CDownloadWithSources add several URL sources
00341 
00342 int CDownloadWithSources::AddSourceURLs(LPCTSTR pszURLs, BOOL bURN)
00343 {
00344         CString strURLs( pszURLs );
00345         BOOL bQuote = FALSE;
00346         
00347         for ( int nScan = 0 ; nScan < strURLs.GetLength() ; nScan++ )
00348         {
00349                 if ( strURLs[ nScan ] == '\"' )
00350                 {
00351                         bQuote = ! bQuote;
00352                         strURLs.SetAt( nScan, ' ' );
00353                 }
00354                 else if ( strURLs[ nScan ] == ',' && bQuote )
00355                 {
00356                         strURLs.SetAt( nScan, '`' );
00357                 }
00358         }
00359         
00360         strURLs += ',';
00361         
00362     int nCount = 0;
00363         for ( ; ; )
00364         {
00365                 int nPos = strURLs.Find( ',' );
00366                 if ( nPos < 0 ) break;
00367                 
00368                 CString strURL  = strURLs.Left( nPos );
00369                 strURLs                 = strURLs.Mid( nPos + 1 );
00370                 strURL.TrimLeft();
00371                 
00372                 FILETIME tSeen = { 0, 0 };
00373                 BOOL bSeen = FALSE;
00374                 
00375                 if ( _tcsistr( strURL, _T("://") ) != NULL )
00376                 {
00377                         nPos = strURL.ReverseFind( ' ' );
00378                         
00379                         if ( nPos > 0 )
00380                         {
00381                                 CString strTime = strURL.Mid( nPos + 1 );
00382                                 strURL = strURL.Left( nPos );
00383                                 strURL.TrimRight();
00384                                 bSeen = TimeFromString( strTime, &tSeen );
00385                         }
00386                         
00387                         for ( int nScan = 0 ; nScan < strURL.GetLength() ; nScan++ )
00388                         {
00389                                 if ( strURL[ nScan ] == '`' ) strURL.SetAt( nScan, ',' );
00390                         }
00391                 }
00392                 else
00393                 {
00394                         nPos = strURL.Find( ':' );
00395                         if ( nPos < 1 ) continue;
00396                         
00397                         int nPort = 0;
00398                         _stscanf( strURL.Mid( nPos + 1 ), _T("%i"), &nPort );
00399                         strURL.Truncate( nPos );
00400                         USES_CONVERSION;
00401                         DWORD nAddress = inet_addr( T2CA( strURL ) );
00402                         strURL.Empty();
00403                         
00404                         if ( ! Network.IsFirewalledAddress( &nAddress, TRUE ) && nPort != 0 && nAddress != INADDR_NONE )
00405                         {
00406                                 if ( m_bSHA1 )
00407                                 {
00408                                         strURL.Format( _T("http://%s:%i/uri-res/N2R?%s"),
00409                                                 (LPCTSTR)CString( inet_ntoa( *(IN_ADDR*)&nAddress ) ),
00410                                                 nPort, (LPCTSTR)CSHA::HashToString( &m_pSHA1, TRUE ) );
00411                                 }
00412                         }
00413                 }
00414                 
00415                 if ( AddSourceURL( strURL, bURN, bSeen ? &tSeen : NULL ) ) nCount++;
00416         }
00417         
00418         return nCount;
00419 }
00420 
00422 // CDownloadWithSources internal source adder
00423 
00424 BOOL CDownloadWithSources::AddSourceInternal(CDownloadSource* pSource)
00425 {
00426         // Check/Reject if source is invalid
00427         if ( ! pSource->m_bPushOnly )
00428         {
00429                 // Reject invalid IPs (Sometimes ed2k sends invalid 0.x.x.x sources)
00430                 if ( pSource->m_pAddress.S_un.S_un_b.s_b1 == 0 )
00431                 {
00432                         delete pSource;
00433                         return FALSE;
00434                 }
00435 
00436                 // Reject if source is the local IP/port
00437                 if ( Network.m_pHost.sin_addr.S_un.S_addr == pSource->m_pAddress.S_un.S_addr )
00438                 {
00439                         if ( ( ( pSource->m_nServerPort == 0 ) && (Settings.Connection.InPort == pSource->m_nPort ) )
00440                                 || ( Settings.Connection.IgnoreOwnIP ) )
00441                         {       
00442                                 delete pSource;
00443                                 return FALSE;
00444                         }
00445                 }
00446         }
00447         else if ( pSource->m_nProtocol == PROTOCOL_ED2K )
00448         {
00449                 // Reject invalid server IPs (Sometimes ed2k sends invalid 0.x.x.x sources)
00450                 if ( pSource->m_pServerAddress.S_un.S_un_b.s_b1 == 0 )
00451                 {
00452                         delete pSource;
00453                         return FALSE;
00454                 }
00455         }
00456 
00457         // Check if GUID is valid (MLDonkey source exchange bug)
00458         if ( pSource->m_bGUID )
00459         {
00460                 if ( ( pSource->m_pGUID.w[0] == 0 ) && ( pSource->m_pGUID.w[1] == 0 ) && 
00461                          ( pSource->m_pGUID.w[2] == 0 ) && ( pSource->m_pGUID.w[3] == 0 ) )
00462                 {
00463                         // GUID appear to be null, so invalidate it to prevent duplicate sources
00464                         pSource->m_bGUID = FALSE;
00465                 }
00466         }
00467 
00468         for ( CDownloadSource* pExisting = m_pSourceFirst ; pExisting ; pExisting = pExisting->m_pNext )
00469         {       
00470                 if ( pExisting->Equals( pSource ) )
00471                 {
00472                         if ( pExisting->m_pTransfer != NULL ||
00473                                  ( pExisting->m_nProtocol == PROTOCOL_HTTP && pSource->m_nProtocol != PROTOCOL_HTTP ) )
00474                         {
00475                                 delete pSource;
00476                                 return FALSE;
00477                         }
00478                         else
00479                         {
00480                                 pSource->m_tAttempt = pExisting->m_tAttempt;
00481                                 pExisting->Remove( TRUE, FALSE );
00482                                 break;
00483                         }
00484                 }
00485         }
00486         
00487         m_nSourceCount ++;
00488 
00489         pSource->m_pPrev = m_pSourceLast;
00490         pSource->m_pNext = NULL;
00491                 
00492         if ( m_pSourceLast != NULL )
00493         {
00494                 m_pSourceLast->m_pNext = pSource;
00495                 m_pSourceLast = pSource;
00496         }
00497         else
00498         {
00499                 m_pSourceFirst = m_pSourceLast = pSource;
00500         }
00501         
00502         SetModified();
00503         
00504         return TRUE;
00505 }
00506 
00508 // CDownloadWithSources query for URLs
00509 
00510 CString CDownloadWithSources::GetSourceURLs(CStringList* pState, int nMaximum, PROTOCOLID nProtocol, CDownloadSource* pExcept)
00511 {
00512         CString strSources, strURL;
00513         
00514         for ( CDownloadSource* pSource = GetFirstSource() ; pSource ; pSource = pSource->m_pNext )
00515         {
00516                 if ( pSource != pExcept && pSource->m_bPushOnly == FALSE &&
00517                          pSource->m_nFailures == 0 && pSource->m_bReadContent &&
00518                          ( pSource->m_bSHA1 || pSource->m_bED2K ) &&
00519                          ( pState == NULL || pState->Find( pSource->m_sURL ) == NULL ) )
00520                 {
00521                         if ( pState != NULL ) pState->AddTail( pSource->m_sURL );
00522                         
00523                         
00524                         // Only return appropriate sources
00525                         if ( ( nProtocol == PROTOCOL_HTTP ) && ( pSource->m_nProtocol != PROTOCOL_HTTP ) ) continue;
00526                         if ( ( nProtocol == PROTOCOL_G1 ) && ( pSource->m_nGnutella != 1 ) ) continue;
00527 
00528                         //if ( bHTTP && pSource->m_nProtocol != PROTOCOL_HTTP ) continue;
00529                         
00530                         strURL = pSource->m_sURL;
00531                         Replace( strURL, _T(","), _T("%2C") );
00532                         
00533                         if ( strSources.GetLength() > 0 ) strSources += _T(", ");
00534                         strSources += strURL;
00535                         strSources += ' ';
00536                         strSources += TimeToString( &pSource->m_tLastSeen );
00537                         
00538                         if ( nMaximum == 1 ) break;
00539                         else if ( nMaximum > 1 ) nMaximum --;
00540                 }
00541         }
00542         
00543         if ( strSources.Find( _T("Zhttp://") ) >= 0 ) strSources.Empty();
00544         
00545         return strSources;
00546 }
00547 
00549 // CDownloadWithSources query hit handler
00550 
00551 BOOL CDownloadWithSources::OnQueryHits(CQueryHit* pHits)
00552 {
00553         for ( ; pHits ; pHits = pHits->m_pNext )
00554         {
00555                 if ( pHits->m_sURL.GetLength() ) AddSourceHit( pHits );
00556         }
00557 
00558         return TRUE;
00559 }
00560 
00562 // CDownloadWithSources remove overlapping sources
00563 
00564 void CDownloadWithSources::RemoveOverlappingSources(QWORD nOffset, QWORD nLength)
00565 {
00566         for ( CDownloadSource* pSource = GetFirstSource() ; pSource ; )
00567         {
00568                 CDownloadSource* pNext = pSource->m_pNext;
00569                 
00570                 if ( pSource->TouchedRange( nOffset, nLength ) )
00571                 {
00572                         theApp.Message( MSG_ERROR, IDS_DOWNLOAD_VERIFY_DROP,
00573                                 (LPCTSTR)CString( inet_ntoa( pSource->m_pAddress ) ),
00574                                 (LPCTSTR)pSource->m_sServer, (LPCTSTR)m_sRemoteName,
00575                                 nOffset, nOffset + nLength - 1 );
00576                         pSource->Remove( TRUE, TRUE );
00577                 }
00578                 
00579                 pSource = pNext;
00580         }
00581 }
00582 
00584 // CDownloadWithSources remove a source
00585 
00586 void CDownloadWithSources::RemoveSource(CDownloadSource* pSource, BOOL bBan)
00587 {
00588         if ( bBan && pSource->m_sURL.GetLength() )
00589         {
00590                 m_pFailedSources.AddTail( pSource->m_sURL );
00591         }
00592         
00593         ASSERT( m_nSourceCount > 0 );
00594         m_nSourceCount --;
00595         
00596         if ( pSource->m_pPrev != NULL )
00597                 pSource->m_pPrev->m_pNext = pSource->m_pNext;
00598         else
00599                 m_pSourceFirst = pSource->m_pNext;
00600         
00601         if ( pSource->m_pNext != NULL )
00602                 pSource->m_pNext->m_pPrev = pSource->m_pPrev;
00603         else
00604                 m_pSourceLast = pSource->m_pPrev;
00605         
00606         delete pSource;
00607         SetModified();
00608 }
00609 
00611 // CDownloadWithSources sort a source
00612 
00613 void CDownloadWithSources::SortSource(CDownloadSource* pSource, BOOL bTop)
00614 {
00615         ASSERT( m_nSourceCount > 0 );
00616         
00617         if ( pSource->m_pPrev != NULL )
00618                 pSource->m_pPrev->m_pNext = pSource->m_pNext;
00619         else
00620                 m_pSourceFirst = pSource->m_pNext;
00621         
00622         if ( pSource->m_pNext != NULL )
00623                 pSource->m_pNext->m_pPrev = pSource->m_pPrev;
00624         else
00625                 m_pSourceLast = pSource->m_pPrev;
00626         
00627         if ( ! bTop )
00628         {
00629                 pSource->m_pPrev = m_pSourceLast;
00630                 pSource->m_pNext = NULL;
00631                 
00632                 if ( m_pSourceLast != NULL )
00633                 {
00634                         m_pSourceLast->m_pNext = pSource;
00635                         m_pSourceLast = pSource;
00636                 }
00637                 else
00638                 {
00639                         m_pSourceFirst = m_pSourceLast = pSource;
00640                 }
00641         }
00642         else
00643         {
00644                 pSource->m_pPrev = NULL;
00645                 pSource->m_pNext = m_pSourceFirst;
00646                 
00647                 if ( m_pSourceFirst != NULL )
00648                 {
00649                         m_pSourceFirst->m_pPrev = pSource;
00650                         m_pSourceFirst = pSource;
00651                 }
00652                 else
00653                 {
00654                         m_pSourceFirst = m_pSourceLast = pSource;
00655                 }
00656         }
00657 }
00658 
00659 
00661 // CDownloadWithSources sort a source by state (Downloading, etc...)
00662 
00663 void CDownloadWithSources::SortSource(CDownloadSource* pSource)
00664 {
00665         ASSERT( m_nSourceCount > 0 );
00666 
00667         //Remove source from current position. (It's unsorted, and would interfere with sort)
00668         if ( pSource->m_pPrev != NULL )
00669                 pSource->m_pPrev->m_pNext = pSource->m_pNext;
00670         else
00671                 m_pSourceFirst = pSource->m_pNext;
00672         
00673         if ( pSource->m_pNext != NULL )
00674                 pSource->m_pNext->m_pPrev = pSource->m_pPrev;
00675         else
00676                 m_pSourceLast = pSource->m_pPrev;
00677         
00678 
00679 
00680         if ( ( m_pSourceFirst == NULL ) || ( m_pSourceLast == NULL ) )
00681         {       //Only one source
00682                 m_pSourceFirst = m_pSourceLast = pSource;
00683                 pSource->m_pNext = pSource->m_pPrev = NULL;
00684         }
00685         else
00686         {       //Sort sources
00687                 CDownloadSource* pCompare = m_pSourceFirst;
00688 
00689                 while ( ( pCompare != NULL ) && (pCompare->m_nSortOrder < pSource->m_nSortOrder) )
00690                         pCompare = pCompare->m_pNext; //Run through the sources to the correct position
00691 
00692                 
00693 
00694                 if ( pCompare == NULL )
00695                 {       //Source is last on list
00696                         m_pSourceLast->m_pNext = pSource;
00697                         pSource->m_pPrev = m_pSourceLast;
00698                         pSource->m_pNext = NULL;
00699                         m_pSourceLast = pSource;
00700                 }
00701                 else
00702                 {       //Insert source in front of current compare source
00703                         if ( pCompare->m_pPrev == NULL )
00704                                 m_pSourceFirst = pSource;
00705                         else
00706                                 pCompare->m_pPrev->m_pNext = pSource;
00707 
00708                         pSource->m_pNext = pCompare;
00709                         pSource->m_pPrev = pCompare->m_pPrev;
00710                         pCompare->m_pPrev= pSource;
00711                 }
00712 
00713         }
00714 }
00715 
00717 // CDownloadWithSources source colour selector
00718 
00719 #define SRC_COLOURS 6
00720 
00721 int CDownloadWithSources::GetSourceColour()
00722 {
00723         BOOL bTaken[SRC_COLOURS];
00724         ZeroMemory( bTaken, sizeof(BOOL) * SRC_COLOURS );
00725         int nFree = SRC_COLOURS;
00726         
00727         for ( CDownloadSource* pSource = GetFirstSource() ; pSource ; pSource = pSource->m_pNext )
00728         {
00729                 if ( pSource->m_nColour >= 0 )
00730                 {
00731                         if ( bTaken[ pSource->m_nColour ] == FALSE )
00732                         {
00733                                 bTaken[ pSource->m_nColour ] = TRUE;
00734                                 nFree--;
00735                         }
00736                 }
00737         }
00738         
00739         srand( GetTickCount() + (DWORD)this );
00740         
00741         if ( nFree == 0 ) return rand() % SRC_COLOURS;
00742         
00743         nFree = rand() % nFree;
00744         
00745         for ( int nColour = 0 ; nColour < SRC_COLOURS ; nColour++ )
00746         {
00747                 if ( bTaken[ nColour ] == FALSE )
00748                 {
00749                         if ( nFree-- == 0 ) return nColour;
00750                 }
00751         }
00752         
00753         return rand() % SRC_COLOURS;
00754 }
00755 
00757 // CDownloadWithSources serialize
00758 
00759 void CDownloadWithSources::Serialize(CArchive& ar, int nVersion)
00760 {
00761         CDownloadBase::Serialize( ar, nVersion );
00762         
00763         if ( ar.IsStoring() )
00764         {
00765                 ar.WriteCount( GetSourceCount() );
00766                 
00767                 for ( CDownloadSource* pSource = GetFirstSource() ; pSource ; pSource = pSource->m_pNext )
00768                 {
00769                         pSource->Serialize( ar, nVersion );
00770                 }
00771                 
00772                 ar.WriteCount( m_pXML != NULL ? 1 : 0 );
00773                 if ( m_pXML ) m_pXML->Serialize( ar );
00774         }
00775         else
00776         {
00777                 for ( int nSources = ar.ReadCount() ; nSources ; nSources-- )
00778                 {
00779                         // Create new source
00780                         CDownloadSource* pSource = new CDownloadSource( (CDownload*)this );
00781                         
00782                         // Add to the list
00783                         m_nSourceCount ++;
00784                         pSource->m_pPrev = m_pSourceLast;
00785                         pSource->m_pNext = NULL;
00786                         
00787                         if ( m_pSourceLast != NULL )
00788                         {
00789                                 m_pSourceLast->m_pNext = pSource;
00790                                 m_pSourceLast = pSource;
00791                         }
00792                         else
00793                         {
00794                                 m_pSourceFirst = m_pSourceLast = pSource;
00795                         }
00796 
00797                         // Load details from disk
00798                         pSource->Serialize( ar, nVersion );
00799 
00800                         // Extract ed2k client ID from url (m_pAddress) because it wasn't saved
00801                         if ( ( !pSource->m_nPort ) && ( _tcsnicmp( pSource->m_sURL, _T("ed2kftp://"), 10 ) == 0 )  )
00802                         {
00803                                 CString strURL = pSource->m_sURL.Mid(10);
00804                                 if ( strURL.GetLength())
00805                                         _stscanf( strURL, _T("%lu"), &pSource->m_pAddress.S_un.S_addr );
00806                         }
00807                 }
00808                 
00809                 if ( ar.ReadCount() )
00810                 {
00811                         m_pXML = new CXMLElement();
00812                         m_pXML->Serialize( ar );
00813                 }
00814         }
00815 }

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