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

BitziDownloader.cpp

Go to the documentation of this file.
00001 //
00002 // BitziDownloader.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 "Library.h"
00026 #include "SharedFile.h"
00027 #include "SHA.h"
00028 #include "XML.h"
00029 #include "Schema.h"
00030 #include "SchemaCache.h"
00031 #include "BitziDownloader.h"
00032 #include "DlgBitziDownload.h"
00033 
00034 #ifdef _DEBUG
00035 #undef THIS_FILE
00036 static char THIS_FILE[]=__FILE__;
00037 #define new DEBUG_NEW
00038 #endif
00039 
00040 
00042 // CBitziDownloader construction
00043 
00044 CBitziDownloader::CBitziDownloader()
00045 {
00046         m_pDlg                  = NULL;
00047         m_hThread               = NULL;
00048         m_hInternet             = NULL;
00049         m_hSession              = NULL;
00050         m_hRequest              = NULL;
00051         m_bFinished             = FALSE;
00052         m_nDelay                = 0;
00053         m_nFailures             = 0;
00054         m_pXML                  = NULL;
00055 }
00056 
00057 CBitziDownloader::~CBitziDownloader()
00058 {
00059         Stop();
00060 
00061         if ( m_pXML ) delete m_pXML;
00062         m_pXML = NULL;
00063 }
00064 
00066 // CBitziDownloader file list
00067 
00068 void CBitziDownloader::AddFile(DWORD nIndex)
00069 {
00070         CSingleLock pLock( &m_pSection, TRUE );
00071         m_pFiles.AddTail( (LPVOID)nIndex );
00072 }
00073 
00074 int CBitziDownloader::GetFileCount()
00075 {
00076         CSingleLock pLock( &m_pSection, TRUE );
00077         return m_pFiles.GetCount();
00078 }
00079 
00081 // CBitziDownloader start
00082 
00083 BOOL CBitziDownloader::Start(CBitziDownloadDlg* pDlg)
00084 {
00085         if ( m_hInternet != NULL ) return FALSE;
00086 
00087         CString strAgent = Settings.SmartAgent();
00088 
00089         m_hInternet = InternetOpen( strAgent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0 );
00090         if ( ! m_hInternet ) return FALSE;
00091 
00092         m_hSession      = NULL;
00093         m_hRequest      = NULL;
00094         m_pDlg          = pDlg;
00095         m_bFinished     = FALSE;
00096         m_nDelay        = 0;
00097         m_nFailures     = 0;
00098 
00099         CWinThread* pThread = AfxBeginThread( ThreadStart, this, THREAD_PRIORITY_NORMAL );
00100         m_hThread = pThread->m_hThread;
00101 
00102         return TRUE;
00103 }
00104 
00106 // CBitziDownloader stop
00107 
00108 void CBitziDownloader::Stop()
00109 {
00110         if ( m_hSession != NULL ) InternetCloseHandle( m_hSession );
00111         m_hSession = NULL;
00112 
00113         if ( m_hInternet ) InternetCloseHandle( m_hInternet );
00114         m_hInternet = NULL;
00115 
00116         if ( m_hThread == NULL ) return;
00117 
00118     int nAttempt = 5;
00119         for ( ; nAttempt > 0 ; nAttempt-- )
00120         {
00121                 DWORD nCode;
00122 
00123                 if ( ! GetExitCodeThread( m_hThread, &nCode ) ) break;
00124                 if ( nCode != STILL_ACTIVE ) break;
00125                 Sleep( 100 );
00126         }
00127 
00128         if ( nAttempt == 0 )
00129         {
00130                 TerminateThread( m_hThread, 0 );
00131                 theApp.Message( MSG_DEBUG, _T("WARNING: Terminating CBitziDownloader thread.") );
00132                 Sleep( 100 );
00133         }
00134 
00135         m_hThread       = NULL;
00136         m_pDlg          = NULL;
00137 }
00138 
00140 // CBitziDownloader working flag
00141 
00142 BOOL CBitziDownloader::IsWorking()
00143 {
00144         return ( m_hThread != NULL ) && ! m_bFinished;
00145 }
00146 
00148 // CBitziDownloader thread bootstrap
00149 
00150 UINT CBitziDownloader::ThreadStart(LPVOID pParam)
00151 {
00152         CBitziDownloader* pClass = (CBitziDownloader*)pParam;
00153         pClass->OnRun();
00154         return 0;
00155 }
00156 
00158 // CBitziDownloader thread run
00159 
00160 void CBitziDownloader::OnRun()
00161 {
00162         while ( m_hInternet != NULL )
00163         {
00164                 m_pSection.Lock();
00165 
00166                 if ( m_pFiles.IsEmpty() )
00167                 {
00168                         m_pSection.Unlock();
00169                         break;
00170                 }
00171 
00172                 m_nFileIndex = (DWORD)m_pFiles.RemoveHead();
00173 
00174                 m_pSection.Unlock();
00175 
00176                 m_pDlg->OnNextFile( m_nFileIndex );
00177 
00178                 if ( BuildRequest() )
00179                 {
00180                         m_pDlg->OnRequesting( m_nFileIndex, m_sFileName );
00181 
00182                         if ( ExecuteRequest() )
00183                         {
00184                                 if ( DecodeResponse() )
00185                                 {
00186                                         m_pDlg->OnSuccess( m_nFileIndex );
00187                                 }
00188                                 else
00189                                 {
00190                                         if ( m_hInternet == NULL ) break;
00191                                         m_pDlg->OnFailure( m_nFileIndex, _T("Not Found") );
00192                                 }
00193                         }
00194                         else if ( ++m_nFailures >= 3 )
00195                         {
00196                                 if ( m_hInternet == NULL ) break;
00197                                 m_pDlg->OnFailure( m_nFileIndex, _T("Aborting") );
00198                                 break;
00199                         }
00200                         else
00201                         {
00202                                 if ( m_hInternet == NULL ) break;
00203 
00204                                 if ( m_hRequest != NULL ) InternetCloseHandle( m_hRequest );
00205                                 m_hRequest = NULL;
00206 
00207                                 m_pDlg->OnFailure( m_nFileIndex, _T("Failed") );
00208 
00209                                 Sleep( 1000 );
00210                         }
00211                 }
00212 
00213                 m_pDlg->OnFinishedFile( m_nFileIndex );
00214 
00215                 if ( m_hRequest != NULL ) InternetCloseHandle( m_hRequest );
00216                 m_hRequest = NULL;
00217 
00218                 m_sResponse.Empty();
00219 
00220                 if ( m_pXML ) delete m_pXML;
00221                 m_pXML = NULL;
00222 
00223                 Sleep( min( m_nDelay, DWORD(500) ) );
00224         }
00225 
00226         if ( m_hSession != NULL && ! m_bFinished ) InternetCloseHandle( m_hSession );
00227         m_hSession = NULL;
00228 
00229         m_bFinished = TRUE;
00230 }
00231 
00233 // CBitziDownloader request builder
00234 
00235 BOOL CBitziDownloader::BuildRequest()
00236 {
00237         {
00238                 CQuickLock oLock( Library.m_pSection );
00239                 CLibraryFile* pFile = Library.LookupFile( m_nFileIndex );
00240 
00241                 if ( ! pFile ) return FALSE;
00242 
00243                 m_sFileName = pFile->m_sName;
00244                 m_sFileHash.Empty();
00245 
00246                 if ( pFile->m_bSHA1 ) m_sFileHash = CSHA::HashToString( &pFile->m_pSHA1 );
00247 
00248         }
00249 
00250         if ( m_sFileHash.IsEmpty() ) return FALSE;
00251 
00252         m_sURL = Settings.Library.BitziXML;
00253         Replace( m_sURL, _T("(SHA1)"), m_sFileHash );
00254 
00255         return TRUE;
00256 }
00257 
00259 // CBitziDownloader request executer
00260 
00261 BOOL CBitziDownloader::ExecuteRequest()
00262 {
00263         DWORD nTime = GetTickCount();
00264 
00265         int nPos, nPort = INTERNET_DEFAULT_HTTP_PORT;
00266         CString strHost, strPath;
00267 
00268         strHost = m_sURL;
00269         nPos = strHost.Find( _T("http://") );
00270         if ( nPos != 0 ) return FALSE;
00271         strHost = strHost.Mid( 7 );
00272         nPos = strHost.Find( '/' );
00273         if ( nPos < 0 ) return FALSE;
00274         strPath = strHost.Mid( nPos );
00275         strHost = strHost.Left( nPos );
00276         nPos = strHost.Find( ':' );
00277 
00278         if ( nPos > 0 )
00279         {
00280                 _stscanf( strHost.Mid( nPos + 1 ), _T("%i"), &nPort );
00281                 strHost = strHost.Left( nPos );
00282         }
00283 
00284         if ( m_hSession == NULL )
00285         {
00286                 m_hSession = InternetConnect( m_hInternet, strHost, nPort,
00287                         NULL, NULL, INTERNET_SERVICE_HTTP , 0, 0 );
00288                 if ( m_hSession == NULL ) return FALSE;
00289         }
00290 
00291         m_hRequest = HttpOpenRequest( m_hSession, _T("GET"), strPath, NULL, NULL, NULL,
00292                 INTERNET_FLAG_KEEP_CONNECTION|INTERNET_FLAG_NO_COOKIES, 0 );
00293 
00294         if ( m_hRequest == NULL )
00295         {
00296                 if ( m_hSession != NULL ) InternetCloseHandle( m_hSession );
00297 
00298                 m_hSession = InternetConnect( m_hInternet, strHost, nPort,
00299                         NULL, NULL, INTERNET_SERVICE_HTTP , 0, 0 );
00300 
00301                 if ( m_hSession == NULL ) return FALSE;
00302 
00303                 m_hRequest = HttpOpenRequest( m_hSession, _T("GET"), strPath, NULL, NULL, NULL,
00304                         INTERNET_FLAG_KEEP_CONNECTION|INTERNET_FLAG_NO_COOKIES, 0 );
00305 
00306                 if ( m_hRequest == NULL ) return FALSE;
00307         }
00308 
00309         if ( ! HttpSendRequest( m_hRequest, NULL, 0, NULL, 0 ) ) return FALSE;
00310 
00311         TCHAR szStatusCode[32];
00312         DWORD nStatusCode = 0, nStatusLen = 32;
00313 
00314         if ( ! HttpQueryInfo( m_hRequest, HTTP_QUERY_STATUS_CODE, szStatusCode,
00315                 &nStatusLen, NULL ) ) return FALSE;
00316 
00317         _stscanf( szStatusCode, _T("%u"), &nStatusCode );
00318         if ( nStatusCode < 200 || nStatusCode > 299 ) return FALSE;
00319 
00320         LPBYTE pResponse = NULL;
00321         DWORD nRemaining, nResponse = 0;
00322 
00323         while ( InternetQueryDataAvailable( m_hRequest, &nRemaining, 0, 0 ) && nRemaining > 0 )
00324         {
00325                 pResponse = (LPBYTE)realloc( pResponse, nResponse + nRemaining );
00326                 InternetReadFile( m_hRequest, pResponse + nResponse, nRemaining, &nRemaining );
00327                 nResponse += nRemaining;
00328         }
00329 
00330         if ( nRemaining )
00331         {
00332                 free( pResponse );
00333                 return FALSE;
00334         }
00335 
00336         m_sResponse.Empty();
00337 
00338         LPTSTR pszResponse = m_sResponse.GetBuffer( nResponse );
00339         for ( nStatusCode = 0 ; nStatusCode < nResponse ; nStatusCode++ )
00340                 pszResponse[ nStatusCode ] = (TCHAR)pResponse[ nStatusCode ];
00341         m_sResponse.ReleaseBuffer( nResponse );
00342 
00343         free( pResponse );
00344 
00345         if ( m_hRequest != NULL ) InternetCloseHandle( m_hRequest );
00346         m_hRequest = NULL;
00347 
00348         m_nDelay = ( GetTickCount() - nTime ) * 2;
00349 
00350         return TRUE;
00351 }
00352 
00354 // CBitziDownloader request decoder
00355 
00356 BOOL CBitziDownloader::DecodeResponse()
00357 {
00358         if ( m_pXML ) delete m_pXML;
00359 
00360         m_pXML = CXMLElement::FromString( m_sResponse, TRUE );
00361         if ( m_pXML == NULL ) return FALSE;
00362 
00363         for ( POSITION pos = SchemaCache.GetIterator() ; pos ; )
00364         {
00365                 CSchema* pSchema = SchemaCache.GetNext( pos );
00366 
00367                 if ( pSchema->m_sBitziTest.GetLength() && LookupValue( pSchema->m_sBitziTest ).GetLength() )
00368                 {
00369                         CXMLElement* pMetadata = ImportData( pSchema );
00370 
00371                         if ( pMetadata == NULL ) return FALSE;
00372 
00373                         return SubmitMetaData( pMetadata );
00374                 }
00375         }
00376 
00377         return FALSE;
00378 }
00379 
00381 // CBitziDownloader value lookup
00382 
00383 CString CBitziDownloader::LookupValue(LPCTSTR pszPath)
00384 {
00385         CString strName, strPath( pszPath );
00386         CXMLElement* pXML = m_pXML;
00387         BOOL bFirst = TRUE;
00388 
00389         while ( strPath.GetLength() )
00390         {
00391                 strName = strPath.SpanExcluding( _T("/") );
00392                 strPath = strPath.Mid( strName.GetLength() );
00393 
00394                 if ( strPath.IsEmpty() )
00395                 {
00396                         return pXML->GetAttributeValue( strName, NULL );
00397                 }
00398 
00399                 if ( bFirst )
00400                 {
00401                         bFirst = FALSE;
00402                         if ( strName.CompareNoCase( pXML->GetName() ) ) pXML = NULL;
00403                 }
00404                 else
00405                 {
00406                         pXML = pXML->GetElementByName( strName );
00407                 }
00408 
00409                 if ( ! pXML )
00410                 {
00411                         strName.Empty();
00412                         return strName;
00413                 }
00414 
00415                 strPath = strPath.Mid( 1 );
00416         }
00417 
00418         strName.Empty();
00419         if ( pXML ) strName = pXML->GetValue();
00420 
00421         return strName;
00422 }
00423 
00425 // CBitziDownloader import data
00426 
00427 CXMLElement* CBitziDownloader::ImportData(CSchema* pSchema)
00428 {
00429         CXMLElement* pRoot      = pSchema->Instantiate( TRUE );
00430         CXMLElement* pXML       = pRoot->AddElement( pSchema->m_sSingular );
00431         int nCount = 0;
00432 
00433         for ( POSITION pos = pSchema->m_pBitziMap.GetHeadPosition() ; pos ; )
00434         {
00435                 CSchemaBitzi* pMap = (CSchemaBitzi*)pSchema->m_pBitziMap.GetNext( pos );
00436 
00437                 CString strValue = LookupValue( pMap->m_sFrom );
00438                 if ( strValue.IsEmpty() ) continue;
00439 
00440                 if ( pMap->m_nFactor )
00441                 {
00442                         double nValue;
00443 
00444                         if ( _stscanf( strValue, _T("%lf"), &nValue ) == 1 )
00445                         {
00446                                 nValue *= pMap->m_nFactor;
00447 
00448                                 if ( nValue == (double)( (int)nValue ) )
00449                                 {
00450                                         strValue.Format( _T("%i"), (int)nValue );
00451                                 }
00452                                 else
00453                                 {
00454                                         strValue.Format( _T("%f"), nValue );
00455                                 }
00456                         }
00457                 }
00458 
00459                 pXML->AddAttribute( pMap->m_sTo, strValue );
00460                 nCount++;
00461         }
00462 
00463         if ( nCount ) return pRoot;
00464         delete pRoot;
00465 
00466         return NULL;
00467 }
00468 
00470 // CBitziDownloader submit metadata
00471 
00472 BOOL CBitziDownloader::SubmitMetaData(CXMLElement* pXML)
00473 {
00474         CQuickLock oLock( Library.m_pSection );
00475 
00476         CLibraryFile* pFile = Library.LookupFile( m_nFileIndex );
00477 
00478         if ( pFile == NULL )
00479         {
00480                 delete pXML;
00481                 return FALSE;
00482         }
00483 
00484         if ( pFile->m_pMetadata != NULL ) MergeMetaData( pXML, pFile->m_pMetadata );
00485 
00486         BOOL bSuccess = pFile->SetMetadata( pXML );
00487 
00488         delete pXML;
00489 
00490         return bSuccess;
00491 }
00492 
00494 // CBitziDownloader metadata merge
00495 
00496 BOOL CBitziDownloader::MergeMetaData(CXMLElement* pOutput, CXMLElement* pInput)
00497 {
00498         if ( ! pOutput || ! pInput ) return FALSE;
00499 
00500         pOutput = pOutput->GetFirstElement();
00501 
00502         if ( ! pOutput || pOutput->GetName() != pInput->GetName() ) return FALSE;
00503 
00504         for ( POSITION pos = pInput->GetElementIterator() ; pos ; )
00505         {
00506                 CXMLElement* pElement   = pInput->GetNextElement( pos );
00507                 CXMLElement* pTarget    = pOutput->GetElementByName( pElement->GetName() );
00508 
00509                 if ( pTarget == NULL ) pOutput->AddElement( pElement->Clone() );
00510         }
00511 
00512         for ( POSITION pos = pInput->GetAttributeIterator() ; pos ; )
00513         {
00514                 CXMLAttribute* pAttribute       = pInput->GetNextAttribute( pos );
00515                 CXMLAttribute* pTarget          = pOutput->GetAttribute( pAttribute->GetName() );
00516 
00517                 if ( pTarget == NULL ) pOutput->AddAttribute( pAttribute->Clone() );
00518         }
00519 
00520         return TRUE;
00521 }

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