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 "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
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
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
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
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
00141
00142 BOOL CBitziDownloader::IsWorking()
00143 {
00144 return ( m_hThread != NULL ) && ! m_bFinished;
00145 }
00146
00148
00149
00150 UINT CBitziDownloader::ThreadStart(LPVOID pParam)
00151 {
00152 CBitziDownloader* pClass = (CBitziDownloader*)pParam;
00153 pClass->OnRun();
00154 return 0;
00155 }
00156
00158
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
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
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
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
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
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
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
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 }