aboutsummaryrefslogtreecommitdiff
path: root/Src/Components/wac_downloadManager
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Components/wac_downloadManager')
-rw-r--r--Src/Components/wac_downloadManager/BackgroundDownloader.cpp128
-rw-r--r--Src/Components/wac_downloadManager/BackgroundDownloader.h14
-rw-r--r--Src/Components/wac_downloadManager/DownloadCallbackT.h71
-rw-r--r--Src/Components/wac_downloadManager/api__wac_downloadManager.h40
-rw-r--r--Src/Components/wac_downloadManager/main.cpp69
-rw-r--r--Src/Components/wac_downloadManager/main.h37
-rw-r--r--Src/Components/wac_downloadManager/resource.h14
-rw-r--r--Src/Components/wac_downloadManager/version.rc239
-rw-r--r--Src/Components/wac_downloadManager/wac_downloadManager.cpp872
-rw-r--r--Src/Components/wac_downloadManager/wac_downloadManager.h318
-rw-r--r--Src/Components/wac_downloadManager/wac_downloadManager.rc76
-rw-r--r--Src/Components/wac_downloadManager/wac_downloadManager.vcxproj209
-rw-r--r--Src/Components/wac_downloadManager/wac_downloadManager.vcxproj.filters118
-rw-r--r--Src/Components/wac_downloadManager/wac_downloadManager_Headers.h9
-rw-r--r--Src/Components/wac_downloadManager/wac_downloadManager_api.cpp1
-rw-r--r--Src/Components/wac_downloadManager/wac_downloadManager_api.h274
-rw-r--r--Src/Components/wac_downloadManager/wac_downloadManager_factory.cpp88
-rw-r--r--Src/Components/wac_downloadManager/wac_downloadManager_factory.h37
-rw-r--r--Src/Components/wac_downloadManager/wac_downloadManager_global.h16
-rw-r--r--Src/Components/wac_downloadManager/wac_download_http_receiver.cpp64
-rw-r--r--Src/Components/wac_downloadManager/wac_download_http_receiver.h48
-rw-r--r--Src/Components/wac_downloadManager/wac_download_http_receiver_api.cpp1
-rw-r--r--Src/Components/wac_downloadManager/wac_download_http_receiver_api.h237
-rw-r--r--Src/Components/wac_downloadManager/wac_download_http_receiver_factory.cpp82
-rw-r--r--Src/Components/wac_downloadManager/wac_download_http_receiver_factory.h33
25 files changed, 2895 insertions, 0 deletions
diff --git a/Src/Components/wac_downloadManager/BackgroundDownloader.cpp b/Src/Components/wac_downloadManager/BackgroundDownloader.cpp
new file mode 100644
index 00000000..a0731ebc
--- /dev/null
+++ b/Src/Components/wac_downloadManager/BackgroundDownloader.cpp
@@ -0,0 +1,128 @@
+#include "BackgroundDownloader.h"
+#include "../../Components\wac_network/wac_network_http_receiver_api.h"
+
+#include "api__wac_downloadManager.h"
+
+#include "api/service/waservicefactory.h"
+
+#include "../nu/AutoChar.h"
+
+#include <strsafe.h>
+
+#define HTTP_BUFFER_SIZE 32768
+// {C0A565DC-0CFE-405a-A27C-468B0C8A3A5C}
+static const GUID internetConfigGroupGUID =
+{ 0xc0a565dc, 0xcfe, 0x405a, { 0xa2, 0x7c, 0x46, 0x8b, 0xc, 0x8a, 0x3a, 0x5c } };
+
+
+static void SetUserAgent( api_httpreceiver *http )
+{
+ char agent[ 256 ];
+ StringCchPrintfA( agent, 256, "User-Agent: %S/%S", WASABI_API_APP->main_getAppName(), WASABI_API_APP->main_getVersionNumString() );
+ http->addheader( agent );
+}
+
+static int FeedHTTP( api_httpreceiver *http, Downloader::DownloadCallback &callback, void *userData, bool *noData )
+{
+ char downloadedData[ HTTP_BUFFER_SIZE ];
+ int result = 0;
+ int downloadSize = http->get_bytes( downloadedData, HTTP_BUFFER_SIZE );
+ if ( downloadSize )
+ {
+ result = callback( userData, downloadedData, downloadSize );
+ *noData = false;
+ }
+ else
+ *noData = true;
+
+ return result;
+}
+
+static void RunDownload( api_httpreceiver *http, Downloader::DownloadCallback &callback, void *userData )
+{
+ int ret;
+ bool noData;
+ do
+ {
+ Sleep( 50 );
+ ret = http->run();
+ if ( FeedHTTP( http, callback, userData, &noData ) != 0 )
+ return;
+ } while ( ret == HTTPRECEIVER_RUN_OK );
+
+ // finish off the data
+ do
+ {
+ if ( FeedHTTP( http, callback, userData, &noData ) != 0 )
+ return;
+ } while ( !noData );
+}
+
+
+bool Downloader::Download( const char *url, Downloader::DownloadCallback &callback, void *userdata, uint64_t startPosition )
+{
+ api_httpreceiver *http = 0;
+
+ waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid( httpreceiverGUID );
+ if ( sf )
+ http = (api_httpreceiver *)sf->getInterface();
+
+ if ( !http )
+ return false;
+
+ int use_proxy = 1;
+ bool proxy80 = AGAVE_API_CONFIG->GetBool( internetConfigGroupGUID, L"proxy80", false );
+ if ( proxy80 && strstr( url, ":" ) && ( !strstr( url, ":80/" ) && strstr( url, ":80" ) != ( url + strlen( url ) - 3 ) ) )
+ use_proxy = 0;
+
+ const wchar_t *proxy = use_proxy ? AGAVE_API_CONFIG->GetString( internetConfigGroupGUID, L"proxy", 0 ) : 0;
+
+ http->AllowCompression();
+ http->open( API_DNS_AUTODNS, HTTP_BUFFER_SIZE, ( proxy && proxy[ 0 ] ) ? (const char *)AutoChar( proxy ) : NULL );
+
+ if ( startPosition > 0 )
+ {
+ char temp[ 128 ];
+ StringCchPrintfA( temp, 128, "Range: bytes=%d-", startPosition );
+ http->addheader( temp );
+ }
+
+ SetUserAgent( http );
+ http->connect( url );
+
+ int ret;
+
+ do
+ {
+ Sleep( 10 );
+
+ ret = http->run();
+ if ( ret == -1 ) // connection failed
+ break;
+
+ // ---- check our reply code ----
+ int replycode = http->getreplycode();
+ switch ( replycode )
+ {
+ case 0:
+ case 100:
+ break;
+ case 200:
+ {
+ RunDownload( http, callback, userdata );
+
+ sf->releaseInterface( http );
+
+ return true;
+ }
+ break;
+ default:
+ sf->releaseInterface( http );
+ return false;
+ }
+ } while ( ret == HTTPRECEIVER_RUN_OK );
+
+ sf->releaseInterface( http );
+
+ return false;
+}
diff --git a/Src/Components/wac_downloadManager/BackgroundDownloader.h b/Src/Components/wac_downloadManager/BackgroundDownloader.h
new file mode 100644
index 00000000..9a1a3f48
--- /dev/null
+++ b/Src/Components/wac_downloadManager/BackgroundDownloader.h
@@ -0,0 +1,14 @@
+#ifndef NULLSOFT_WAC_DOWNLOAD_MANAGER_BACKGROUND_DOWNLOADER_H
+#define NULLSOFT_WAC_DOWNLOAD_MANAGER_BACKGROUND_DOWNLOADER_H
+
+#include "bfc/platform/types.h"
+
+class Downloader
+{
+public:
+ typedef int ( *DownloadCallback )( void *userdata, void *buffer, size_t bufferSize );
+ bool Download( const char *url, DownloadCallback &callback, void *userdata, uint64_t startPosition = 0 );
+
+};
+
+#endif // !NULLSOFT_WAC_DOWNLOAD_MANAGER_BACKGROUND_DOWNLOADER_H
diff --git a/Src/Components/wac_downloadManager/DownloadCallbackT.h b/Src/Components/wac_downloadManager/DownloadCallbackT.h
new file mode 100644
index 00000000..f0d46f6a
--- /dev/null
+++ b/Src/Components/wac_downloadManager/DownloadCallbackT.h
@@ -0,0 +1,71 @@
+#ifndef NULLSOFT_WAC_DOWNLOAD_MANAGER_DOWNLOADCALLBACKT_H
+#define NULLSOFT_WAC_DOWNLOAD_MANAGER_DOWNLOADCALLBACKT_H
+
+#include "wac_downloadManager_api.h"
+
+#define WIN32_LEAN_AND_MEAN
+
+//#include <windows.h> // for InterlockedIncrememt/Decrement
+#include <atomic>
+
+/* DownloadCallbackT is reference counted for you. if you don't like that, inherit from ifc_downloadManagerCallback yourself */
+template <class T>
+class DownloadCallbackT : public ifc_downloadManagerCallback
+{
+public:
+ size_t AddRef()
+ {
+ return _ref_count.fetch_add( 1 );
+ }
+
+ size_t Release()
+ {
+ if (_ref_count.load() == 0 )
+ return _ref_count.load();
+
+ LONG l_ref_count = _ref_count.fetch_sub( 1 );
+ if ( !l_ref_count )
+ delete( static_cast<T *>( this ) );
+
+ return l_ref_count;
+ }
+
+protected:
+ DownloadCallbackT() {}
+
+ void OnFinish( DownloadToken token ) { Release(); }
+ void OnTick( DownloadToken token ) {}
+ void OnError( DownloadToken token, int error ) { Release(); }
+ void OnCancel( DownloadToken token ) { Release(); }
+ void OnConnect( DownloadToken token ) {}
+ void OnInit( DownloadToken token ) {}
+ void OnData( DownloadToken token, void *data, size_t datalen ) {}
+
+ int GetSource(wchar_t *source, size_t source_cch) { return 1;}
+ int GetTitle(wchar_t *title, size_t title_cch) { return 1;}
+ int GetLocation(wchar_t *location, size_t location_cch) { return 1;}
+
+#define CBCLASS T
+#define CBCLASST DownloadCallbackT<T>
+ START_DISPATCH_INLINE;
+ CBT(ADDREF, AddRef);
+ CBT(RELEASE, Release);
+ VCBT(IFC_DOWNLOADMANAGERCALLBACK_ONFINISH, OnFinish);
+ VCBT(IFC_DOWNLOADMANAGERCALLBACK_ONTICK, OnTick);
+ VCBT(IFC_DOWNLOADMANAGERCALLBACK_ONERROR, OnError);
+ VCBT(IFC_DOWNLOADMANAGERCALLBACK_ONCANCEL, OnCancel);
+ VCBT(IFC_DOWNLOADMANAGERCALLBACK_ONCONNECT, OnConnect);
+ VCBT(IFC_DOWNLOADMANAGERCALLBACK_ONINIT, OnInit);
+ VCBT(IFC_DOWNLOADMANAGERCALLBACK_ONDATA, OnData);
+ CBT( IFC_DOWNLOADMANAGERCALLBACK_GETSOURCE, GetSource);
+ CBT( IFC_DOWNLOADMANAGERCALLBACK_GETTITLE, GetTitle);
+ CBT( IFC_DOWNLOADMANAGERCALLBACK_GETLOCATION, GetLocation);
+ END_DISPATCH;
+#undef CBCLASS
+#undef CBCLASST
+
+private:
+ std::atomic<std::size_t> _ref_count;
+};
+
+#endif // !NULLSOFT_WAC_DOWNLOAD_MANAGER_DOWNLOADCALLBACKT_H
diff --git a/Src/Components/wac_downloadManager/api__wac_downloadManager.h b/Src/Components/wac_downloadManager/api__wac_downloadManager.h
new file mode 100644
index 00000000..241b148c
--- /dev/null
+++ b/Src/Components/wac_downloadManager/api__wac_downloadManager.h
@@ -0,0 +1,40 @@
+#ifndef NULLSOFT_WAC_DOWNLOAD_MANAGER_API_H
+#define NULLSOFT_WAC_DOWNLOAD_MANAGER_API_H
+
+#include "api/service/api_service.h"
+
+#include "api/application/api_application.h"
+#define WASABI_API_APP applicationApi
+
+#include "../Agave/Config/api_config.h"
+
+#include "../nu/threadpool/api_threadpool.h"
+extern api_threadpool *threadPoolApi;
+#define WASABI_API_THREADPOOL threadPoolApi
+
+
+template <class api_T>
+static void ServiceBuild( api_T *&api_t, GUID factoryGUID_t )
+{
+ if ( WASABI_API_SVC )
+ {
+ waServiceFactory *factory = WASABI_API_SVC->service_getServiceByGuid( factoryGUID_t );
+ if ( factory )
+ api_t = reinterpret_cast<api_T *>( factory->getInterface() );
+ }
+}
+
+template <class api_T>
+static void ServiceRelease( api_T *api_t, GUID factoryGUID_t )
+{
+ if ( WASABI_API_SVC && api_t )
+ {
+ waServiceFactory *factory = WASABI_API_SVC->service_getServiceByGuid( factoryGUID_t );
+ if ( factory )
+ factory->releaseInterface( api_t );
+ }
+
+ api_t = NULL;
+}
+
+#endif // !NULLSOFT_WAC_DOWNLOAD_MANAGER_API_H \ No newline at end of file
diff --git a/Src/Components/wac_downloadManager/main.cpp b/Src/Components/wac_downloadManager/main.cpp
new file mode 100644
index 00000000..7038b540
--- /dev/null
+++ b/Src/Components/wac_downloadManager/main.cpp
@@ -0,0 +1,69 @@
+#include "main.h"
+
+//#include "wac_download_http_receiver_factory.h"
+
+#include "wac_downloadManager.h"
+
+#include "bfc/platform/export.h"
+
+static Singleton2<api_downloadManager, DownloadManager> dlMgrFactory;
+static DownloadManager dlMgr;
+
+//static wa::Components::WAC_DownloadsFactory _wac_download_factory;
+static wa::Components::WAC_DownloadManager_Component _wac_downloadManager_Component;
+
+//wa::Factory::WAC_DownloadMabager_HTTPReceiver_Factory _wac_downloadManager_http_receiver_service;
+
+api_service *WASABI_API_SVC = 0;
+api_application *WASABI_API_APP = 0;
+api_config *AGAVE_API_CONFIG = 0;
+api_threadpool *WASABI_API_THREADPOOL = 0;
+
+
+void wa::Components::WAC_DownloadManager_Component::RegisterServices( api_service *p_service )
+{
+ WASABI_API_SVC = p_service;
+
+ ServiceBuild( WASABI_API_APP, applicationApiServiceGuid );
+ ServiceBuild( AGAVE_API_CONFIG, AgaveConfigGUID );
+ ServiceBuild( WASABI_API_THREADPOOL, ThreadPoolGUID );
+
+
+ dlMgrFactory.Register( &dlMgr );
+
+ //WASABI_API_SVC->service_register( &_wac_downloadManager_http_receiver_service );
+}
+
+void wa::Components::WAC_DownloadManager_Component::DeregisterServices( api_service *p_service )
+{
+ Q_UNUSED( p_service )
+
+ ServiceRelease( WASABI_API_APP, applicationApiServiceGuid );
+ ServiceRelease( AGAVE_API_CONFIG, AgaveConfigGUID );
+
+ dlMgr.Kill();
+ dlMgrFactory.Deregister();
+
+ ServiceRelease( WASABI_API_THREADPOOL, ThreadPoolGUID );
+
+ //p_service->service_deregister( &_wac_downloadManager_http_receiver_service );
+}
+
+
+extern "C" WAC_DOWNLOAD_MANAGER_EXPORT ifc_wa5component * GetWinamp5SystemComponent()
+{
+ return &_wac_downloadManager_Component;
+}
+
+
+#ifdef CBCLASS
+#undef CBCLASS
+#endif
+
+#define CBCLASS wa::Components::WAC_DownloadManager_Component
+START_DISPATCH;
+VCB( API_WA5COMPONENT_REGISTERSERVICES, RegisterServices )
+CB( API_WA5COMPONENT_REGISTERSERVICES_SAFE_MODE, RegisterServicesSafeModeOk )
+VCB( API_WA5COMPONENT_DEREEGISTERSERVICES, DeregisterServices )
+END_DISPATCH;
+#undef CBCLASS
diff --git a/Src/Components/wac_downloadManager/main.h b/Src/Components/wac_downloadManager/main.h
new file mode 100644
index 00000000..dc80f120
--- /dev/null
+++ b/Src/Components/wac_downloadManager/main.h
@@ -0,0 +1,37 @@
+#ifndef NULLSOFT_WAC_DOWNLOAD_MANAGER_MAIN_H
+#define NULLSOFT_WAC_DOWNLOAD_MANAGER_MAIN_H
+
+#include "wac_downloadManager_global.h"
+
+#include "api__wac_downloadManager.h"
+
+//#include "wac_downloadManager.h"
+//#include "wac_download_http_receiver.h"
+
+#include "bfc/dispatch.h"
+
+#include "../../Winamp/Singleton.h"
+#include "../../Agave/Component/ifc_wa5component.h"
+
+
+namespace wa
+{
+ namespace Components
+ {
+ class WAC_DownloadManager_Component : public ifc_wa5component
+ {
+ public:
+ WAC_DownloadManager_Component() {}
+
+ void RegisterServices( api_service *service );
+ int RegisterServicesSafeModeOk() { return 1; }
+
+ void DeregisterServices( api_service *service );
+
+ protected:
+ RECVS_DISPATCH;
+ };
+ }
+}
+
+#endif // !NULLSOFT_WAC_DOWNLOAD_MANAGER_MAIN_H \ No newline at end of file
diff --git a/Src/Components/wac_downloadManager/resource.h b/Src/Components/wac_downloadManager/resource.h
new file mode 100644
index 00000000..528c5d4a
--- /dev/null
+++ b/Src/Components/wac_downloadManager/resource.h
@@ -0,0 +1,14 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by wac_network.rc
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/Src/Components/wac_downloadManager/version.rc2 b/Src/Components/wac_downloadManager/version.rc2
new file mode 100644
index 00000000..b62ac19b
--- /dev/null
+++ b/Src/Components/wac_downloadManager/version.rc2
@@ -0,0 +1,39 @@
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+#include "../../Winamp/buildType.h"
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 0,1,0,0
+ PRODUCTVERSION WINAMP_PRODUCTVER
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "Winamp SA"
+ VALUE "FileDescription", "Winamp 5.x System Component"
+ VALUE "FileVersion", STR_WINAMP_PRODUCTVER
+ VALUE "InternalName", "wac_downloadManager.w5s"
+ VALUE "LegalCopyright", "Copyright © 2007-2022 Winamp SA"
+ VALUE "LegalTrademarks", "Nullsoft and Winamp are trademarks of Winamp SA"
+ VALUE "OriginalFilename", "wac_downloadManager.w5s"
+ VALUE "ProductName", "Winamp downloadManager Service"
+ VALUE "ProductVersion", STR_WINAMP_PRODUCTVER
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/Src/Components/wac_downloadManager/wac_downloadManager.cpp b/Src/Components/wac_downloadManager/wac_downloadManager.cpp
new file mode 100644
index 00000000..aa3e7ae9
--- /dev/null
+++ b/Src/Components/wac_downloadManager/wac_downloadManager.cpp
@@ -0,0 +1,872 @@
+#include <string.h>
+#include <strsafe.h>
+
+#include <iostream>
+#include <cstdio>
+
+#include <QtCore/qglobal.h>
+
+#include <QWebEngineProfile>
+#include <QtWebEngineWidgets/QtWebEngineWidgets>
+#include <QWebEnginePage>
+#include <QWebEngineSettings>
+
+#include "api__wac_downloadManager.h"
+
+#include "wac_downloadManager.h"
+#include "wac_download_http_receiver_api.h"
+
+#include "..\wac_network\wac_network_http_receiver_api.h"
+
+#include "api/service/waservicefactory.h"
+
+#include "../nu/threadname.h"
+#include "../nu/AutoChar.h"
+#include "../nu/threadpool/timerhandle.hpp"
+
+#include "..\WAT\WAT.h"
+
+#include "..\Winamp\buildType.h"
+
+static const GUID internetConfigGroupGUID =
+{
+ 0xc0a565dc, 0xcfe, 0x405a, { 0xa2, 0x7c, 0x46, 0x8b, 0xc, 0x8a, 0x3a, 0x5c }
+};
+
+#define DOWNLOAD_TIMEOUT_MS 60000 // 60 second timeout
+#define DOWNLOAD_SLEEP_MS 50
+#define DOWNLOAD_BUFFER_SIZE 1310720 // gives a maximum download rate of 25 mb/sec per file
+
+
+/**********************************************************************************
+ **********************************************************************************/
+
+
+/**********************************************************************************
+ * PUBLIC *
+ **********************************************************************************/
+wa::Components::WAC_DownloadData::WAC_DownloadData( api_wac_download_manager_http_receiver *p_http, const char *p_url, int p_flags, ifc_downloadManagerCallback *p_callback )
+{
+ _http = p_http;
+
+ strcpy_s( this->_url, 1024, p_url );
+
+ _flags = p_flags;
+ _callback = p_callback;
+
+ if ( _callback )
+ _callback->AddRef();
+
+ _hFile = INVALID_HANDLE_VALUE;
+ _filepath[ 0 ] = 0;
+ _fileext = 0;
+
+ int download_method = ( api_downloadManager::DOWNLOADEX_MASK_DOWNLOADMETHOD & _flags );
+ switch ( download_method )
+ {
+ case api_downloadManager::DOWNLOADEX_TEMPFILE:
+ {
+ wchar_t temppath[ MAX_PATH - 14 ] = { 0 }; // MAX_PATH-14 'cause MSDN said so
+ GetTempPathW( MAX_PATH - 14, temppath );
+ GetTempFileNameW( temppath, L"wdl", 0, _filepath );
+ _hFile = CreateFileW( _filepath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_ALWAYS, 0, 0 );
+ }
+ break;
+ case api_downloadManager::DOWNLOADEX_CALLBACK:
+ if ( _callback )
+ _callback->GetLocation( _filepath, MAX_PATH );
+ break;
+ }
+
+
+
+ _source[ 0 ] = 0;
+ _title[ 0 ] = 0;
+
+ if ( _flags & api_downloadManager::DOWNLOADEX_CALLBACK )
+ {
+ if ( _callback )
+ {
+ _callback->GetSource( _source, 1024 );
+ _callback->GetTitle( _title, 1024 );
+ }
+ }
+
+ _connectionStart = _lastDownloadTick = GetTickCount();
+ _last_status = HTTP_RECEIVER_STATUS_ERROR;
+ _pending = ( _flags & api_downloadManager::DOWNLOADEX_PENDING ) > 0;
+}
+
+wa::Components::WAC_DownloadData::~WAC_DownloadData()
+{
+ ServiceRelease( _http, httpreceiverGUID2 );
+
+ _http = NULL;
+
+ if ( _fileext )
+ delete _fileext;
+
+ int download_method = ( api_downloadManager::DOWNLOADEX_MASK_DOWNLOADMETHOD & _flags );
+ if ( download_method == api_downloadManager::DOWNLOADEX_TEMPFILE && _filepath[ 0 ] )
+ DeleteFileW( _filepath );
+
+ if ( _callback )
+ _callback->Release();
+
+ _callback = NULL;
+}
+
+
+void wa::Components::WAC_DownloadData::Retain()
+{
+ this->_refCount.fetch_add( 1 );
+}
+
+void wa::Components::WAC_DownloadData::Release()
+{
+ if ( this->_refCount.fetch_sub( 1 ) == 0 )
+ delete this;
+}
+
+
+void wa::Components::WAC_DownloadData::Close( ifc_downloadManagerCallback **callbackCopy )
+{
+ if ( _hFile != INVALID_HANDLE_VALUE )
+ CloseHandle( _hFile );
+
+ _hFile = INVALID_HANDLE_VALUE;
+
+ if ( callbackCopy != NULL )
+ {
+ *callbackCopy = _callback;
+ if ( _callback != NULL )
+ _callback->AddRef();
+ }
+ else if ( _callback != NULL )
+ {
+ _callback->Release();
+ _callback = NULL;
+ }
+
+ // don't want to close http here, because someone might still want to get the headers out of it
+}
+
+bool wa::Components::WAC_DownloadData::getExtention()
+{
+ if ( _fileext && *_fileext )
+ return _fileext;
+
+ char l_header_name_content_type[] = "Content-Type";
+
+ char *l_content_type = _http->getheader( l_header_name_content_type );
+ if ( l_content_type && *l_content_type )
+ {
+ if ( _CONTENT_TYPES_EXTENSIONS.count( l_content_type ) == 1 )
+ _fileext = _strdup( _CONTENT_TYPES_EXTENSIONS.find( l_content_type )->second.c_str() );
+ }
+
+ return _fileext;
+}
+
+
+
+
+/**********************************************************************************
+ * PRIVATE *
+ **********************************************************************************/
+
+
+
+/**********************************************************************************
+ **********************************************************************************/
+
+/**********************************************************************************
+ * PUBLIC *
+ **********************************************************************************/
+wa::Components::WAC_DownloadManager::WAC_DownloadManager( QObject *parent ) : QNetworkAccessManager( parent )
+{
+ this->setObjectName( "DownloadManagerService" );
+
+ this->init();
+}
+
+wa::Components::WAC_DownloadManager::~WAC_DownloadManager()
+{
+ disconnect( _connection_authentication_required );
+}
+
+
+DownloadToken wa::Components::WAC_DownloadManager::Download( const char *p_url, ifc_downloadManagerCallback *p_callback )
+{
+ return DownloadEx( p_url, p_callback, api_downloadManager::DOWNLOADEX_TEMPFILE );
+}
+
+DownloadToken wa::Components::WAC_DownloadManager::DownloadEx( const char *p_url, ifc_downloadManagerCallback *p_callback, int p_flags )
+{
+
+
+
+ return DownloadToken();
+}
+
+
+
+
+
+/**********************************************************************************
+ * PRIVATE *
+ **********************************************************************************/
+void wa::Components::WAC_DownloadManager::init()
+{
+ QString l_winamp_user_agent = QString( "%1 Winamp/%2" ).arg( QWebEngineProfile::defaultProfile()->httpUserAgent(), STR_WINAMP_PRODUCTVER ).replace( ",", "." );
+
+ QWebEngineProfile::defaultProfile()->setHttpUserAgent( l_winamp_user_agent );
+
+
+ _connection_authentication_required = connect( this, &QNetworkAccessManager::authenticationRequired, this, &wa::Components::WAC_DownloadManager::on_s_authentication_required );
+
+
+}
+
+
+QNetworkReply *wa::Components::WAC_DownloadManager::createRequest( Operation p_operation, const QNetworkRequest &p_request, QIODevice *p_outgoing_data )
+{
+ return QNetworkAccessManager::createRequest( p_operation, p_request, p_outgoing_data );
+}
+
+
+
+/**********************************************************************************
+ * PRIVATE SLOTS *
+ **********************************************************************************/
+void wa::Components::WAC_DownloadManager::on_s_authentication_required( QNetworkReply *p_reply, QAuthenticator *p_authenticator )
+{
+ Q_UNUSED( p_reply );
+ Q_UNUSED( p_authenticator );
+}
+
+
+
+
+
+/**********************************************************************************
+ **********************************************************************************/
+DownloadData::DownloadData( api_httpreceiver *p_http, const char *p_url, int p_flags, ifc_downloadManagerCallback *p_callback )
+{
+ flags = p_flags;
+ http = p_http;
+ callback = p_callback;
+
+ if ( callback )
+ callback->AddRef();
+
+ hFile = INVALID_HANDLE_VALUE;
+ filepath[ 0 ] = 0;
+ fileext = 0;
+
+ int download_method = ( api_downloadManager::DOWNLOADEX_MASK_DOWNLOADMETHOD & flags );
+ switch ( download_method )
+ {
+ case api_downloadManager::DOWNLOADEX_TEMPFILE:
+ {
+ wchar_t temppath[ MAX_PATH - 14 ] = { 0 }; // MAX_PATH-14 'cause MSDN said so
+ GetTempPathW( MAX_PATH - 14, temppath );
+ GetTempFileNameW( temppath, L"wdl", 0, filepath );
+ hFile = CreateFileW( filepath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_ALWAYS, 0, 0 );
+ }
+ break;
+ case api_downloadManager::DOWNLOADEX_CALLBACK:
+ if ( callback )
+ callback->GetLocation( filepath, MAX_PATH );
+ break;
+ }
+
+ strcpy_s( this->url, 1024, p_url );
+ source[ 0 ] = 0;
+ title[ 0 ] = 0;
+ if ( flags & api_downloadManager::DOWNLOADEX_CALLBACK )
+ {
+ if ( callback )
+ {
+ callback->GetSource( source, 1024 );
+ callback->GetTitle( title, 1024 );
+ }
+ }
+
+ connectionStart = lastDownloadTick = GetTickCount();
+ last_status = HTTPRECEIVER_STATUS_ERROR;
+ pending = ( flags & api_downloadManager::DOWNLOADEX_PENDING ) > 0;
+}
+
+DownloadData::~DownloadData()
+{
+ ServiceRelease( http, httpreceiverGUID );
+
+ http = NULL;
+
+ if ( fileext )
+ delete fileext;
+
+ int download_method = ( api_downloadManager::DOWNLOADEX_MASK_DOWNLOADMETHOD & flags );
+ if ( download_method == api_downloadManager::DOWNLOADEX_TEMPFILE && filepath[ 0 ] )
+ DeleteFileW( filepath );
+
+ if ( callback )
+ callback->Release();
+
+ callback = NULL;
+}
+
+
+void DownloadData::Retain()
+{
+ this->_refCount.fetch_add( 1 );
+}
+
+void DownloadData::Release()
+{
+ if ( this->_refCount.fetch_sub( 1 ) == 0 )
+ delete this;
+}
+
+
+void DownloadData::Close( ifc_downloadManagerCallback **callbackCopy )
+{
+ if ( hFile != INVALID_HANDLE_VALUE )
+ CloseHandle( hFile );
+
+ hFile = INVALID_HANDLE_VALUE;
+
+ if ( callbackCopy != NULL )
+ {
+ *callbackCopy = callback;
+ if ( callback != NULL )
+ callback->AddRef();
+ }
+ else if ( callback != NULL )
+ {
+ callback->Release();
+ callback = NULL;
+ }
+
+ // don't want to close http here, because someone might still want to get the headers out of it
+}
+
+bool DownloadData::getExtention()
+{
+ if ( fileext && *fileext )
+ return fileext;
+
+ char l_header_name_content_type[] = "Content-Type";
+ char *l_content_type = http->getheader( l_header_name_content_type );
+ if ( l_content_type && *l_content_type )
+ {
+ if ( _CONTENT_TYPES_EXTENSIONS.count( l_content_type ) == 1 )
+ fileext = _strdup( _CONTENT_TYPES_EXTENSIONS.find( l_content_type )->second.c_str() );
+ }
+
+ return fileext;
+}
+
+
+
+/**********************************************************************************
+ **********************************************************************************/
+
+ /**********************************************************************************
+ * PUBLIC *
+ **********************************************************************************/
+DownloadManager::DownloadManager()
+{
+ download_thread = NULL;
+ killswitch = CreateEvent( NULL, TRUE, FALSE, NULL );
+
+ InitializeCriticalSection( &downloadsCS );
+}
+
+
+void DownloadManager::Kill()
+{
+ SetEvent( killswitch );
+ if ( download_thread )
+ {
+ WaitForSingleObject( download_thread, 3000 );
+ CloseHandle( download_thread );
+ }
+
+ DeleteCriticalSection( &downloadsCS );
+ CloseHandle( killswitch );
+}
+
+
+static void SetUserAgent( api_httpreceiver *p_http )
+{
+ char agent[ 256 ] = { 0 };
+ StringCchPrintfA( agent, 256, "User-Agent: %S/%S", WASABI_API_APP->main_getAppName(), WASABI_API_APP->main_getVersionNumString() );
+ p_http->addheader( agent );
+
+ //QString l_winamp_user_agent = QString( "User-Agent: %1 Winamp/%2" ).arg( QWebEngineProfile::defaultProfile()->httpUserAgent(), STR_WINAMP_PRODUCTVER ).replace( ",", "." );
+
+ //http->addheader( l_winamp_user_agent.toStdString().c_str() );
+}
+
+
+DownloadToken DownloadManager::Download( const char *url, ifc_downloadManagerCallback *callback )
+{
+ return DownloadEx( url, callback, api_downloadManager::DOWNLOADEX_TEMPFILE );
+}
+
+DownloadToken DownloadManager::DownloadEx( const char *url, ifc_downloadManagerCallback *callback, int flags )
+{
+ if ( InitDownloadThread() )
+ {
+ api_httpreceiver *http = NULL;
+
+ ServiceBuild( http, httpreceiverGUID );
+
+ if ( http )
+ {
+ DownloadData *downloadData = new DownloadData( http, url, flags, callback );
+
+ int use_proxy = 1;
+ bool proxy80 = AGAVE_API_CONFIG->GetBool( internetConfigGroupGUID, L"proxy80", false );
+
+ if ( proxy80 && strstr( url, ":" ) && ( !strstr( url, ":80/" ) && strstr( url, ":80" ) != ( url + strlen( url ) - 3 ) ) )
+ use_proxy = 0;
+
+ const wchar_t *proxy = use_proxy ? AGAVE_API_CONFIG->GetString( internetConfigGroupGUID, L"proxy", 0 ) : 0;
+
+ http->open( API_DNS_AUTODNS, DOWNLOAD_BUFFER_SIZE, ( proxy && proxy[ 0 ] ) ? (const char *)AutoChar( proxy ) : NULL );
+
+ SetUserAgent( http );
+
+ if ( callback )
+ callback->OnInit( downloadData );
+
+ if ( downloadData->flags & api_downloadManager::DOWNLOADEX_UI )
+ {
+ for ( ifc_downloadManagerCallback *l_status : status_callbacks )
+ l_status->OnInit( downloadData );
+ }
+
+ //only call http->connect when it is not pending download request
+ if ( !( flags & DOWNLOADEX_PENDING ) )
+ http->connect( url, 1 );
+
+ //http->run(); // let's get this party started
+ EnterCriticalSection( &downloadsCS );
+ downloads.push_back( downloadData );
+ LeaveCriticalSection( &downloadsCS );
+
+ return downloadData;
+ }
+ }
+
+ return 0;
+}
+
+
+void DownloadManager::ResumePendingDownload( DownloadToken p_token )
+{
+ if ( !p_token )
+ return;
+
+ DownloadData *data = (DownloadData *)p_token;
+ if ( data->pending )
+ {
+ data->pending = false;
+ data->connectionStart = data->lastDownloadTick = GetTickCount();
+
+ data->http->connect( data->url );
+ }
+}
+
+void DownloadManager::CancelDownload( DownloadToken p_token )
+{
+ if ( !p_token )
+ return;
+
+ DownloadData *data = (DownloadData *)p_token;
+ EnterCriticalSection( &downloadsCS );
+
+ if ( downloads.end() != std::find( downloads.begin(), downloads.end(), data ) )
+ {
+ ifc_downloadManagerCallback *callback;
+ data->Close( &callback );
+
+ //downloads.eraseObject(p_data);
+ auto it = std::find( downloads.begin(), downloads.end(), data );
+ if ( it != downloads.end() )
+ {
+ downloads.erase( it );
+ }
+
+ LeaveCriticalSection( &downloadsCS );
+
+ if ( callback )
+ {
+ callback->OnCancel( p_token );
+ if ( data->flags & api_downloadManager::DOWNLOADEX_UI )
+ {
+ for ( ifc_downloadManagerCallback *l_status : status_callbacks )
+ l_status->OnCancel( p_token );
+ }
+
+ callback->Release();
+ }
+
+ data->Release();
+ }
+ else
+ LeaveCriticalSection( &downloadsCS );
+}
+
+void DownloadManager::RetainDownload( DownloadToken p_token )
+{
+ if ( !p_token )
+ return;
+
+ DownloadData *data = (DownloadData *)p_token;
+ if ( data )
+ data->Retain();
+}
+
+void DownloadManager::ReleaseDownload( DownloadToken p_token )
+{
+ if ( !p_token )
+ return;
+
+ DownloadData *data = (DownloadData *)p_token;
+ if ( data )
+ data->Release();
+}
+
+
+void DownloadManager::RegisterStatusCallback( ifc_downloadManagerCallback *callback )
+{
+ EnterCriticalSection( &downloadsCS );
+ status_callbacks.push_back( callback );
+ LeaveCriticalSection( &downloadsCS );
+}
+
+void DownloadManager::UnregisterStatusCallback( ifc_downloadManagerCallback *callback )
+{
+ EnterCriticalSection( &downloadsCS );
+
+ auto it = std::find( status_callbacks.begin(), status_callbacks.end(), callback );
+ if ( it != status_callbacks.end() )
+ status_callbacks.erase( it );
+
+ LeaveCriticalSection( &downloadsCS );
+}
+
+
+bool DownloadManager::IsPending( DownloadToken token )
+{
+ DownloadData *data = (DownloadData *)token;
+ if ( data )
+ return data->pending;
+ else
+ return FALSE;
+}
+
+
+/**********************************************************************************
+ * PRIVATE *
+ **********************************************************************************/
+bool DownloadManager::DownloadThreadTick()
+{
+ unsigned int i = 0;
+ char *downloadBuffer = (char *)malloc( DOWNLOAD_BUFFER_SIZE );
+
+ while ( WaitForSingleObject( killswitch, 0 ) != WAIT_OBJECT_0 )
+ {
+ EnterCriticalSection( &downloadsCS );
+ if ( downloads.empty() )
+ {
+ // TODO: might be nice to dynamically increase the sleep time if this happens
+ // (maybe to INFINITE and have Download() wake us?)
+ LeaveCriticalSection( &downloadsCS );
+
+ free( downloadBuffer );
+
+ return true;
+ }
+
+ if ( i >= downloads.size() )
+ {
+ LeaveCriticalSection( &downloadsCS );
+ free( downloadBuffer );
+
+ return true;
+ }
+
+ DownloadData *thisDownload = downloads[ i ];
+ if ( thisDownload->pending )
+ {
+ LeaveCriticalSection( &downloadsCS );
+ }
+ else
+ {
+ thisDownload->Retain();
+ LeaveCriticalSection( &downloadsCS );
+
+
+ INT tick = Tick( thisDownload, downloadBuffer, DOWNLOAD_BUFFER_SIZE );
+ switch ( tick )
+ {
+ case TICK_NODATA:
+ // do nothing
+ break;
+
+ case TICK_CONNECTING:
+ break;
+
+ case TICK_CONNECTED:
+ if ( thisDownload->callback )
+ thisDownload->callback->OnConnect( thisDownload );
+ if ( thisDownload->flags & api_downloadManager::DOWNLOADEX_UI )
+ {
+ for ( ifc_downloadManagerCallback *l_status : status_callbacks )
+ l_status->OnConnect( thisDownload );
+ }
+ break;
+
+ case TICK_SUCCESS:
+ if ( thisDownload->callback )
+ thisDownload->callback->OnTick( thisDownload );
+ if ( thisDownload->flags & api_downloadManager::DOWNLOADEX_UI )
+ {
+ for ( ifc_downloadManagerCallback *l_status : status_callbacks )
+ l_status->OnTick( thisDownload );
+ }
+
+ // TODO: send out update l_callback
+ break;
+
+ case TICK_FINISHED:
+ case TICK_FAILURE:
+ case TICK_TIMEOUT:
+ case TICK_CANT_CONNECT:
+ case TICK_WRITE_ERROR:
+ FinishDownload( thisDownload, tick );
+ break;
+ }
+ thisDownload->Release();
+ }
+
+ i++;
+ }
+
+ free( downloadBuffer );
+
+ return false; // we only get here when killswitch is set
+}
+
+int DownloadManager::DownloadTickThreadPoolFunc( HANDLE handle, void *user_data, intptr_t id )
+{
+ DownloadManager *dlmgr = (DownloadManager *)user_data;
+ if ( dlmgr->DownloadThreadTick() )
+ {
+ TimerHandle t( handle );
+ t.Wait( DOWNLOAD_SLEEP_MS );
+ }
+ else
+ {
+ WASABI_API_THREADPOOL->RemoveHandle( 0, handle );
+ SetEvent( dlmgr->download_thread );
+ }
+
+ return 0;
+}
+
+bool DownloadManager::InitDownloadThread()
+{
+ if ( download_thread == NULL )
+ {
+ download_thread = CreateEvent( 0, FALSE, FALSE, 0 );
+ TimerHandle t;
+ WASABI_API_THREADPOOL->AddHandle( 0, t, DownloadTickThreadPoolFunc, this, 0, api_threadpool::FLAG_LONG_EXECUTION );
+ t.Wait( DOWNLOAD_SLEEP_MS );
+ }
+
+ return ( download_thread != NULL );
+}
+
+void DownloadManager::FinishDownload( DownloadData *p_data, int code )
+{
+ if ( p_data == NULL )
+ return;
+
+ ifc_downloadManagerCallback *l_callback = NULL;
+
+ EnterCriticalSection( &downloadsCS );
+ p_data->Close( &l_callback );
+ LeaveCriticalSection( &downloadsCS );
+
+ if ( l_callback != NULL )
+ {
+ if ( code == TICK_FINISHED )
+ {
+ l_callback->OnFinish( p_data );
+ if ( p_data->flags & api_downloadManager::DOWNLOADEX_UI )
+ {
+ for ( ifc_downloadManagerCallback *l_data : status_callbacks )
+ l_data->OnFinish( p_data );
+ }
+ }
+ else
+ {
+ l_callback->OnError( p_data, code );
+ if ( p_data->flags & api_downloadManager::DOWNLOADEX_UI )
+ {
+ for ( ifc_downloadManagerCallback *l_data : status_callbacks )
+ l_data->OnError( p_data, code );
+ }
+ }
+
+ l_callback->Release();
+ }
+
+ EnterCriticalSection( &downloadsCS );
+
+ auto it = std::find( downloads.begin(), downloads.end(), p_data );
+ if ( it != downloads.end() )
+ downloads.erase( it );
+
+ LeaveCriticalSection( &downloadsCS );
+
+ p_data->Release();
+}
+
+int DownloadManager::Tick( DownloadData *thisDownload, void *buffer, int bufferSize )
+{
+ if ( !thisDownload )
+ return api_downloadManager::TICK_FAILURE;
+
+ int state = thisDownload->http->run();
+ if ( state == HTTPRECEIVER_RUN_ERROR || thisDownload == NULL )
+ return api_downloadManager::TICK_FAILURE;
+
+ if ( !thisDownload->fileext )
+ thisDownload->getExtention();
+
+
+ int downloaded = thisDownload->http->get_bytes( buffer, bufferSize );
+ if ( downloaded )
+ {
+ switch ( thisDownload->flags & DOWNLOADEX_MASK_DOWNLOADMETHOD )
+ {
+ case api_downloadManager::DOWNLOADEX_BUFFER:
+ {
+ thisDownload->buffer.reserve( thisDownload->http->content_length() );
+ thisDownload->buffer.add( buffer, downloaded );
+ }
+ break;
+ case api_downloadManager::DOWNLOADEX_TEMPFILE:
+ {
+ DWORD written = 0;
+ WriteFile( thisDownload->hFile, buffer, downloaded, &written, NULL );
+ if ( written != downloaded )
+ return api_downloadManager::TICK_WRITE_ERROR;
+ }
+ break;
+ case api_downloadManager::DOWNLOADEX_CALLBACK:
+ {
+ if ( thisDownload->flags & api_downloadManager::DOWNLOADEX_UI )
+ {
+ for ( ifc_downloadManagerCallback *l_status : status_callbacks )
+ l_status->OnData( thisDownload, buffer, downloaded );
+ }
+
+ if ( thisDownload->callback )
+ thisDownload->callback->OnData( thisDownload, buffer, downloaded );
+ }
+ }
+
+ thisDownload->lastDownloadTick = GetTickCount();
+ thisDownload->bytesDownloaded += downloaded;
+
+ return api_downloadManager::TICK_SUCCESS;
+ }
+ else // nothing in the buffer
+ {
+ if ( state == HTTPRECEIVER_RUN_CONNECTION_CLOSED ) // see if the connection is closed
+ {
+ return api_downloadManager::TICK_FINISHED; // yay we're done
+ }
+
+ if ( GetTickCount() - thisDownload->lastDownloadTick > DOWNLOAD_TIMEOUT_MS ) // check for timeout
+ return api_downloadManager::TICK_TIMEOUT;
+
+ switch ( thisDownload->http->get_status() )
+ {
+ case HTTPRECEIVER_STATUS_CONNECTING:
+ if ( thisDownload->last_status != HTTPRECEIVER_STATUS_CONNECTING )
+ {
+ thisDownload->last_status = HTTPRECEIVER_STATUS_CONNECTING;
+ return api_downloadManager::TICK_CONNECTING;
+ }
+ else
+ {
+ return api_downloadManager::TICK_NODATA;
+ }
+ case HTTPRECEIVER_STATUS_READING_HEADERS:
+ if ( thisDownload->last_status != HTTPRECEIVER_STATUS_READING_HEADERS )
+ {
+ thisDownload->last_status = HTTPRECEIVER_STATUS_READING_HEADERS;
+ return api_downloadManager::TICK_CONNECTED;
+ }
+ else
+ {
+ return api_downloadManager::TICK_NODATA;
+ }
+ }
+
+ if ( !thisDownload->replyCode )
+ thisDownload->replyCode = thisDownload->http->getreplycode();
+
+ switch ( thisDownload->replyCode )
+ {
+ case 0:
+ case 100:
+ case 200:
+ case 201:
+ case 202:
+ case 203:
+ case 204:
+ case 205:
+ case 206:
+ return api_downloadManager::TICK_NODATA;
+ default:
+ return api_downloadManager::TICK_CANT_CONNECT;
+ }
+ }
+}
+
+
+
+
+
+#define CBCLASS DownloadManager
+START_DISPATCH;
+CB( API_DOWNLOADMANAGER_DOWNLOAD, Download )
+CB( API_DOWNLOADMANAGER_DOWNLOADEX, DownloadEx )
+CB( API_DOWNLOADMANAGER_GETRECEIVER, GetReceiver )
+CB( API_DOWNLOADMANAGER_GETLOCATION, GetLocation )
+VCB( API_DOWNLOADMANAGER_SETLOCATION, SetLocation )
+CB( API_DOWNLOADMANAGER_GETEXTENTION, GetExtention )
+CB( API_DOWNLOADMANAGER_GETURL, GetUrl )
+CB( API_DOWNLOADMANAGER_GETBYTESDOWNLOADED, GetBytesDownloaded );
+CB( API_DOWNLOADMANAGER_GETBUFFER, GetBuffer );
+VCB( API_DOWNLOADMANAGER_RESUMEPENDINGDOWNLOAD, ResumePendingDownload );
+VCB( API_DOWNLOADMANAGER_CANCELDOWNLOAD, CancelDownload );
+VCB( API_DOWNLOADMANAGER_RETAINDOWNLOAD, RetainDownload );
+VCB( API_DOWNLOADMANAGER_RELEASEDOWNLOAD, ReleaseDownload );
+VCB( API_DOWNLOADMANAGER_REGISTERSTATUSCALLBACK, RegisterStatusCallback );
+VCB( API_DOWNLOADMANAGER_UNREGISTERSTATUSCALLBACK, UnregisterStatusCallback );
+CB( API_DOWNLOADMANAGER_GETSOURCE, GetSource );
+CB( API_DOWNLOADMANAGER_GETTITLE, GetTitle );
+CB( API_DOWNLOADMANAGER_ISPENDING, IsPending );
+END_DISPATCH;
+#undef CBCLASS
diff --git a/Src/Components/wac_downloadManager/wac_downloadManager.h b/Src/Components/wac_downloadManager/wac_downloadManager.h
new file mode 100644
index 00000000..aa06819c
--- /dev/null
+++ b/Src/Components/wac_downloadManager/wac_downloadManager.h
@@ -0,0 +1,318 @@
+#ifndef NULLSOFT_WAC_DOWNLOAD_MANAGER_DOWNLOAD_MANAGER_H
+#define NULLSOFT_WAC_DOWNLOAD_MANAGER_DOWNLOAD_MANAGER_H
+
+#include <vector>
+#include <map>
+#include <string> // for string class
+#include <atomic>
+
+#include <QtCore>
+#include <QAuthenticator>
+#include <QNetworkAccessManager>
+#include <QNetworkRequest>
+#include <QNetworkReply>
+
+#include <QUrl>
+#include <QUrlQuery>
+
+#include "../nu/GrowBuf.h"
+
+//#include "main.h"
+
+//#include "wac_downloadManager_Headers.h"
+
+#include "wac_download_http_receiver.h"
+//#include "wac_download_http_receiver_api.h"
+
+#include "wac_downloadManager_api.h"
+
+//#include "../wac_network/wac_network_http_receiver_api.h"
+
+#define MAX_SIMULTANEOUS_DOWNLOADS 2
+
+static std::map<std::string, std::string> _CONTENT_TYPES_EXTENSIONS = {
+ { "audio/aac", "aac" },
+ { "audio/mp4", "mp4" },
+ { "audio/MPA", "MPA" },
+ { "audio/mpeg", "mp3" },
+ { "audio/opus", "opus" },
+ { "audio/ogg", "ogg" },
+ { "audio/vorbis", "vorbis" },
+ { "audio/wav", "wav" },
+ { "video/mp2t", "ts" },
+ { "video/mp4", "mp4" },
+ { "video/mpeg", "mpeg" },
+ { "video/ogg", "ogv" },
+ { "video/x-matroska", "mkv" },
+ { "video/x-msvideo", "avi" }
+};
+
+
+
+namespace wa
+{
+ namespace Components
+ {
+ class WAC_DownloadData : public QObject
+ {
+ Q_OBJECT
+
+ public:
+ WAC_DownloadData( api_wac_download_manager_http_receiver *p_http, const char *p_url, int p_flags, ifc_downloadManagerCallback *p_callback );
+ ~WAC_DownloadData();
+
+ void Retain();
+ void Release();
+
+ void Close( ifc_downloadManagerCallback **callbackCopy );
+
+ bool getExtention();
+
+ api_wac_download_manager_http_receiver *_http = Q_NULLPTR;
+ ifc_downloadManagerCallback *_callback = Q_NULLPTR;
+
+ int _flags = 0;
+
+ HANDLE _hFile; // handle to the open file where data is written to
+
+ DWORD _lastDownloadTick; // last time we got data out of the connection. used for timeout
+ DWORD _connectionStart; // used for when the connection starts, to help us calculate a k/s download rate
+
+ wchar_t _filepath[ MAX_PATH ]; // where file is downloaded to. probably a temp path
+ char *_fileext = 0;
+ char _url[ 1024 ];
+ wchar_t _source[ 1024 ];
+ wchar_t _title[ 1024 ];
+
+ int _replyCode = 0; // HTTP 200, 404, etc.
+ uint64_t _bytesDownloaded = 0;
+ int _last_status; // from http->get_status()
+ bool _pending;
+
+ GrowBuf _buffer;
+
+
+ private:
+ std::atomic<std::size_t> _refCount = 1;
+
+
+ };
+
+ class WAC_DownloadManager : public QNetworkAccessManager, public api_downloadManager
+ {
+ Q_OBJECT
+
+ public:
+ WAC_DownloadManager( QObject *parent = Q_NULLPTR );
+ ~WAC_DownloadManager();
+
+ static const char *getServiceName() { return "Download Manager Service"; }
+ static GUID getServiceGuid() { return DownloadManagerGUID; }
+
+ DownloadToken Download( const char *p_url, ifc_downloadManagerCallback *p_callback );
+ DownloadToken DownloadEx( const char *p_url, ifc_downloadManagerCallback *p_callback, int p_flags );
+
+
+ private:
+ void init();
+
+ QNetworkReply *createRequest( Operation p_operation, const QNetworkRequest &p_request, QIODevice *p_outgoing_data = Q_NULLPTR );
+
+ QMetaObject::Connection _connection_authentication_required;
+
+ std::map<std::string, wa::Components::WAC_Download_HTTP_Receiver *> _runing_downloads;
+ std::map<std::string, wa::Components::WAC_Download_HTTP_Receiver *> _pending_downloads;
+
+
+ private Q_SLOTS:
+ void on_s_authentication_required( QNetworkReply *p_reply, QAuthenticator *p_authenticator );
+ };
+ }
+}
+
+
+
+
+
+
+#pragma region "DownloadData"
+struct DownloadData
+{
+ DownloadData( api_httpreceiver *http, const char *url, int flags, ifc_downloadManagerCallback *callback );
+ ~DownloadData();
+
+ void Retain();
+ void Release();
+
+ void Close( ifc_downloadManagerCallback **callbackCopy );
+
+ bool getExtention();
+
+ api_httpreceiver *http = NULL;
+ ifc_downloadManagerCallback *callback = NULL;
+
+ wchar_t filepath[ MAX_PATH ]; // where file is downloaded to. probably a temp path
+ char *fileext = 0;
+ char url[ 1024 ];
+ wchar_t source[ 1024 ];
+ wchar_t title[ 1024 ];
+
+ HANDLE hFile; // handle to the open file where data is written to
+ DWORD lastDownloadTick; // last time we got data out of the connection. used for timeout
+ DWORD connectionStart; // used for when the connection starts, to help us calculate a k/s download rate
+
+ int replyCode = 0; // HTTP 200, 404, etc.
+ uint64_t bytesDownloaded = 0;
+ int last_status; // from http->get_status()
+ bool pending;
+
+ int flags;
+ GrowBuf buffer;
+
+private:
+ std::atomic<std::size_t> _refCount = 1;
+};
+#pragma endregion
+
+
+/* method ideas
+
+Download(url, owner_token, callback, user_data)
+Lock() - call before enumerating and doing anything
+Unlock()
+CancelDownload()
+Enum(owner_token)
+
+*/
+
+class DownloadManager : public api_downloadManager
+{
+public:
+ static const char *getServiceName() { return "Download Manager"; }
+ static GUID getServiceGuid() { return DownloadManagerGUID; }
+
+ DownloadManager();
+
+ void Kill();
+
+ DownloadToken Download( const char *url, ifc_downloadManagerCallback *callback );
+ DownloadToken DownloadEx( const char *url, ifc_downloadManagerCallback *callback, int flags );
+
+ void ResumePendingDownload( DownloadToken token );
+ void CancelDownload( DownloadToken token );
+ void RetainDownload( DownloadToken token );
+ void ReleaseDownload( DownloadToken token );
+
+ void RegisterStatusCallback( ifc_downloadManagerCallback *callback );
+ void UnregisterStatusCallback( ifc_downloadManagerCallback *callback );
+
+ bool IsPending( DownloadToken token );
+
+ /*
+ only call these during a callback!
+ */
+ api_httpreceiver *GetReceiver( DownloadToken token )
+ {
+ if ( token )
+ return ( (DownloadData *)token )->http;
+ else
+ return 0;
+ }
+
+ const wchar_t *GetLocation( DownloadToken token )
+ {
+ if ( token )
+ return ( (DownloadData *)token )->filepath;
+ else
+ return 0;
+ }
+
+ const wchar_t *GetSource( DownloadToken p_token )
+ {
+ if ( !p_token )
+ return 0;
+
+ DownloadData *data = (DownloadData *)p_token;
+ if ( data )
+ return data->source;
+ else
+ return 0;
+ }
+
+ const wchar_t *GetTitle( DownloadToken p_token )
+ {
+ if ( !p_token )
+ return 0;
+
+ DownloadData *data = (DownloadData *)p_token;
+ if ( data )
+ return data->title;
+ else
+ return 0;
+ }
+
+ void SetLocation( DownloadToken token, const wchar_t *p_location )
+ {
+ if ( token )
+ wcscpy( ( (DownloadData *)token )->filepath, p_location );
+ }
+
+ const char *GetExtention( DownloadToken token )
+ {
+ if ( token )
+ return ( (DownloadData *)token )->fileext;
+ else
+ return 0;
+ }
+
+ const char *GetUrl( DownloadToken token )
+ {
+ if ( token )
+ return ( (DownloadData *)token )->url;
+ else
+ return 0;
+ }
+
+ int GetBuffer( DownloadToken token, void **buffer, size_t *bufferlen )
+ {
+ if ( token )
+ {
+ *buffer = ( (DownloadData *)token )->buffer.get();
+ *bufferlen = ( (DownloadData *)token )->buffer.getlen();
+
+ return 0;
+ }
+ else
+ return 1;
+ }
+
+ uint64_t GetBytesDownloaded( DownloadToken token )
+ {
+ if ( token )
+ return ( (DownloadData *)token )->bytesDownloaded;
+ else
+ return 0;
+ }
+
+private:
+ CRITICAL_SECTION downloadsCS;
+
+ bool DownloadThreadTick();
+ static int DownloadTickThreadPoolFunc( HANDLE handle, void *user_data, intptr_t id );
+
+ bool InitDownloadThread();
+ void FinishDownload( DownloadData *data, int code );
+ int Tick( DownloadData *thisDownload, void *buffer, int bufferSize );
+
+ HANDLE download_thread;
+ HANDLE killswitch;
+
+ std::vector<DownloadData *> downloads;
+ typedef std::vector<ifc_downloadManagerCallback *> StatusList;
+ StatusList status_callbacks;
+
+protected:
+ RECVS_DISPATCH;
+};
+
+#endif // !NULLSOFT_WAC_DOWNLOAD_MANAGER_DOWNLOAD_MANAGER_H
diff --git a/Src/Components/wac_downloadManager/wac_downloadManager.rc b/Src/Components/wac_downloadManager/wac_downloadManager.rc
new file mode 100644
index 00000000..fcff7711
--- /dev/null
+++ b/Src/Components/wac_downloadManager/wac_downloadManager.rc
@@ -0,0 +1,76 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.K.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "#include ""version.rc2""\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // English (U.K.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#include "version.rc2"
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/Src/Components/wac_downloadManager/wac_downloadManager.vcxproj b/Src/Components/wac_downloadManager/wac_downloadManager.vcxproj
new file mode 100644
index 00000000..4238f73b
--- /dev/null
+++ b/Src/Components/wac_downloadManager/wac_downloadManager.vcxproj
@@ -0,0 +1,209 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="17.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{66827D3B-AA81-4F38-A671-A0C9B0C2E21D}</ProjectGuid>
+ <Keyword>QtVS_v304</Keyword>
+ <WindowsTargetPlatformVersion Condition="'$(Configuration)|$(Platform)' == 'Debug|Win32'">10.0.19041.0</WindowsTargetPlatformVersion>
+ <WindowsTargetPlatformVersion Condition="'$(Configuration)|$(Platform)' == 'Release|Win32'">10.0.19041.0</WindowsTargetPlatformVersion>
+ <QtMsBuild Condition="'$(QtMsBuild)'=='' OR !Exists('$(QtMsBuild)\qt.targets')">$(MSBuildProjectDirectory)\QtMsBuild</QtMsBuild>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Condition="Exists('$(QtMsBuild)\qt_defaults.props')">
+ <Import Project="$(QtMsBuild)\qt_defaults.props" />
+ </ImportGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|Win32'" Label="QtSettings">
+ <QtInstall>5.15.2_msvc2019</QtInstall>
+ <QtModules>core;network;concurrent;webengine;webenginewidgets</QtModules>
+ <QtBuildConfig>debug</QtBuildConfig>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|Win32'" Label="QtSettings">
+ <QtInstall>5.15.2_msvc2019</QtInstall>
+ <QtModules>core;network;concurrent;webengine;webenginewidgets</QtModules>
+ <QtBuildConfig>release</QtBuildConfig>
+ </PropertyGroup>
+ <Target Name="QtMsBuildNotFound" BeforeTargets="CustomBuild;ClCompile" Condition="!Exists('$(QtMsBuild)\qt.targets') or !Exists('$(QtMsBuild)\qt.props')">
+ <Message Importance="High" Text="QtMsBuild: could not locate qt.targets, qt.props; project may not build correctly." />
+ </Target>
+ <ImportGroup Label="ExtensionSettings" />
+ <ImportGroup Label="Shared" />
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)' == 'Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(QtMsBuild)\Qt.props" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)' == 'Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(QtMsBuild)\Qt.props" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|Win32'">
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ <TargetExt>.w5s</TargetExt>
+ <LinkIncremental>false</LinkIncremental>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|Win32'">
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ <TargetExt>.w5s</TargetExt>
+ <LinkIncremental>false</LinkIncremental>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <AdditionalIncludeDirectories>..\..\Wasabi;..\..\replicant;%(AdditionalIncludeDirectories);$(Qt_INCLUDEPATH_)</AdditionalIncludeDirectories>
+ <WarningLevel>Level3</WarningLevel>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <StringPooling>true</StringPooling>
+ </ClCompile>
+ <Link>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <AdditionalDependencies>comctl32.lib;ws2_32.lib;Crypt32.lib;shlwapi.lib;%(AdditionalDependencies);$(Qt_LIBS_)</AdditionalDependencies>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\</Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ <AdditionalIncludeDirectories>..\..\Wasabi;..\..\replicant;%(AdditionalIncludeDirectories);$(Qt_INCLUDEPATH_)</AdditionalIncludeDirectories>
+ <SupportJustMyCode>false</SupportJustMyCode>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ </ClCompile>
+ <Link>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <AdditionalDependencies>comctl32.lib;ws2_32.lib;Crypt32.lib;shlwapi.lib;%(AdditionalDependencies);$(Qt_LIBS_)</AdditionalDependencies>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\
+xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\</Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <VcpkgUseStatic>true</VcpkgUseStatic>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <VcpkgUseStatic>true</VcpkgUseStatic>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg">
+ <VcpkgEnabled>true</VcpkgEnabled>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|Win32'" Label="Configuration">
+ <ClCompile>
+ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <Optimization>Disabled</Optimization>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;USE_SSL;WAC_DOWNLOAD_MANAGER_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Release|Win32'" Label="Configuration">
+ <ClCompile>
+ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <DebugInformationFormat>None</DebugInformationFormat>
+ <Optimization>MinSpace</Optimization>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;USE_SSL;WAC_DOWNLOAD_MANAGER_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="BackgroundDownloader.cpp" />
+ <ClCompile Include="wac_downloadManager.cpp">
+ <DynamicSource Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">input</DynamicSource>
+ <QtMocFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(Filename).moc</QtMocFileName>
+ <DynamicSource Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">input</DynamicSource>
+ <QtMocFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(Filename).moc</QtMocFileName>
+ </ClCompile>
+ <ClCompile Include="wac_downloadManager_api.cpp" />
+ <ClCompile Include="wac_downloadManager_factory.cpp" />
+ <ClCompile Include="wac_download_http_receiver.cpp" />
+ <ClCompile Include="wac_download_http_receiver_api.cpp" />
+ <ClCompile Include="wac_download_http_receiver_factory.cpp" />
+ <ClInclude Include="resource.h" />
+ <ClInclude Include="wac_downloadManager_api.h" />
+ <ClInclude Include="api__wac_downloadManager.h" />
+ <ClInclude Include="BackgroundDownloader.h" />
+ <ClInclude Include="DownloadCallbackT.h" />
+ <ClInclude Include="wac_downloadManager_factory.h" />
+ <ClInclude Include="wac_downloadManager_global.h" />
+ <ClInclude Include="main.h" />
+ <ClCompile Include="main.cpp" />
+ <ClInclude Include="wac_downloadManager_Headers.h" />
+ <ClInclude Include="wac_download_http_receiver_api.h" />
+ <ClInclude Include="wac_download_http_receiver_factory.h" />
+ <QtMoc Include="wac_download_http_receiver.h" />
+ <QtMoc Include="wac_downloadManager.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\tataki\tataki.vcxproj">
+ <Project>{255b68b5-7ef8-45ef-a675-2d6b88147909}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\..\Wasabi\Wasabi.vcxproj">
+ <Project>{3e0bfa8a-b86a-42e9-a33f-ec294f823f7f}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="wac_downloadManager.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="version.rc2" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')">
+ <Import Project="$(QtMsBuild)\qt.targets" />
+ </ImportGroup>
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/Src/Components/wac_downloadManager/wac_downloadManager.vcxproj.filters b/Src/Components/wac_downloadManager/wac_downloadManager.vcxproj.filters
new file mode 100644
index 00000000..7deccab2
--- /dev/null
+++ b/Src/Components/wac_downloadManager/wac_downloadManager.vcxproj.filters
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>qml;cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>qrc;rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ <Filter Include="Form Files">
+ <UniqueIdentifier>{99349809-55BA-4b9d-BF79-8FDBB0286EB3}</UniqueIdentifier>
+ <Extensions>ui</Extensions>
+ </Filter>
+ <Filter Include="Translation Files">
+ <UniqueIdentifier>{639EADAA-A684-42e4-A9AD-28FC9BCB8F7C}</UniqueIdentifier>
+ <Extensions>ts</Extensions>
+ </Filter>
+ <Filter Include="Header Files\HTTP Receiver">
+ <UniqueIdentifier>{738d86e2-2471-4e0d-bcb4-dd3b1c132c01}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files\downloadManager">
+ <UniqueIdentifier>{ddf711c1-7782-4349-9835-758b85fcfe53}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files\HTTP Receiver">
+ <UniqueIdentifier>{9892fa19-d3f5-43cf-a433-aa513290ca0d}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files\downloadManager">
+ <UniqueIdentifier>{c31b92ff-4576-420f-885a-333d90811b9b}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="main.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClInclude Include="main.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="api__wac_downloadManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="BackgroundDownloader.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="DownloadCallbackT.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="wac_download_http_receiver_factory.h">
+ <Filter>Header Files\HTTP Receiver</Filter>
+ </ClInclude>
+ <ClInclude Include="wac_download_http_receiver_api.h">
+ <Filter>Header Files\HTTP Receiver</Filter>
+ </ClInclude>
+ <ClInclude Include="wac_downloadManager_api.h">
+ <Filter>Header Files\downloadManager</Filter>
+ </ClInclude>
+ <ClInclude Include="wac_downloadManager_factory.h">
+ <Filter>Header Files\downloadManager</Filter>
+ </ClInclude>
+ <ClCompile Include="wac_downloadManager_api.cpp">
+ <Filter>Source Files\downloadManager</Filter>
+ </ClCompile>
+ <ClCompile Include="wac_downloadManager_factory.cpp">
+ <Filter>Source Files\downloadManager</Filter>
+ </ClCompile>
+ <ClCompile Include="wac_download_http_receiver.cpp">
+ <Filter>Source Files\HTTP Receiver</Filter>
+ </ClCompile>
+ <ClCompile Include="wac_download_http_receiver_api.cpp">
+ <Filter>Source Files\HTTP Receiver</Filter>
+ </ClCompile>
+ <ClCompile Include="wac_download_http_receiver_factory.cpp">
+ <Filter>Source Files\HTTP Receiver</Filter>
+ </ClCompile>
+ <ClCompile Include="wac_downloadManager.cpp">
+ <Filter>Source Files\downloadManager</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="BackgroundDownloader.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <QtMoc Include="wac_download_http_receiver.h">
+ <Filter>Header Files\HTTP Receiver</Filter>
+ </QtMoc>
+ <QtMoc Include="wac_downloadManager.h">
+ <Filter>Header Files\downloadManager</Filter>
+ </QtMoc>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="wac_downloadManager_global.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="wac_downloadManager_Headers.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="wac_downloadManager.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="version.rc2">
+ <Filter>Resource Files</Filter>
+ </None>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/Src/Components/wac_downloadManager/wac_downloadManager_Headers.h b/Src/Components/wac_downloadManager/wac_downloadManager_Headers.h
new file mode 100644
index 00000000..5c0ac00a
--- /dev/null
+++ b/Src/Components/wac_downloadManager/wac_downloadManager_Headers.h
@@ -0,0 +1,9 @@
+#ifndef NULLSOFT_WAC_DOWNLOAD_MANAGER_HEADERS_H
+#define NULLSOFT_WAC_DOWNLOAD_MANAGER_HEADERS_H
+
+#include "wac_downloadManager.h"
+#include "wac_download_http_receiver.h"
+
+
+#endif // NULLSOFT_WAC_DOWNLOAD_MANAGER_HEADERS_H
+
diff --git a/Src/Components/wac_downloadManager/wac_downloadManager_api.cpp b/Src/Components/wac_downloadManager/wac_downloadManager_api.cpp
new file mode 100644
index 00000000..54f5a1d3
--- /dev/null
+++ b/Src/Components/wac_downloadManager/wac_downloadManager_api.cpp
@@ -0,0 +1 @@
+#include "wac_downloadManager_api.h" \ No newline at end of file
diff --git a/Src/Components/wac_downloadManager/wac_downloadManager_api.h b/Src/Components/wac_downloadManager/wac_downloadManager_api.h
new file mode 100644
index 00000000..99ce9a79
--- /dev/null
+++ b/Src/Components/wac_downloadManager/wac_downloadManager_api.h
@@ -0,0 +1,274 @@
+#ifndef NULLSOFT_WAC_DOWNLOAD_MANAGER_API_DOWNLOADMANAGER_H
+#define NULLSOFT_WAC_DOWNLOAD_MANAGER_API_DOWNLOADMANAGER_H
+
+#include "bfc/dispatch.h"
+
+typedef void *DownloadToken;
+
+class ifc_downloadManagerCallback;
+class api_httpreceiver;
+
+class ifc_downloadManagerCallback : public Dispatchable
+{
+public:
+ void OnFinish( DownloadToken token );
+ void OnTick( DownloadToken token );
+ void OnError( DownloadToken token, int error );
+ void OnCancel( DownloadToken token );
+ void OnConnect( DownloadToken token );
+ void OnInit( DownloadToken token );
+ void OnData( DownloadToken token, void *data, size_t datalen );
+
+ int GetSource( wchar_t *source, size_t source_cch );
+ int GetTitle( wchar_t *title, size_t title_cch );
+ int GetLocation( wchar_t *location, size_t location_cch );
+
+ DISPATCH_CODES
+ {
+ IFC_DOWNLOADMANAGERCALLBACK_ONFINISH = 10,
+ IFC_DOWNLOADMANAGERCALLBACK_ONTICK = 20,
+ IFC_DOWNLOADMANAGERCALLBACK_ONERROR = 30,
+ IFC_DOWNLOADMANAGERCALLBACK_ONCANCEL = 40,
+ IFC_DOWNLOADMANAGERCALLBACK_ONCONNECT = 50,
+ IFC_DOWNLOADMANAGERCALLBACK_ONINIT = 60,
+ IFC_DOWNLOADMANAGERCALLBACK_ONDATA = 70,
+ IFC_DOWNLOADMANAGERCALLBACK_GETSOURCE = 80,
+ IFC_DOWNLOADMANAGERCALLBACK_GETTITLE = 90,
+ IFC_DOWNLOADMANAGERCALLBACK_GETLOCATION = 100,
+ };
+};
+
+inline void ifc_downloadManagerCallback::OnFinish( DownloadToken token )
+{
+ _voidcall( IFC_DOWNLOADMANAGERCALLBACK_ONFINISH, token );
+}
+
+inline void ifc_downloadManagerCallback::OnTick( DownloadToken token )
+{
+ _voidcall( IFC_DOWNLOADMANAGERCALLBACK_ONTICK, token );
+}
+
+inline void ifc_downloadManagerCallback::OnError( DownloadToken token, int error )
+{
+ _voidcall( IFC_DOWNLOADMANAGERCALLBACK_ONERROR, token, error );
+}
+
+inline void ifc_downloadManagerCallback::OnCancel( DownloadToken token )
+{
+ _voidcall( IFC_DOWNLOADMANAGERCALLBACK_ONCANCEL, token );
+}
+
+inline void ifc_downloadManagerCallback::OnConnect( DownloadToken token )
+{
+ _voidcall( IFC_DOWNLOADMANAGERCALLBACK_ONCONNECT, token );
+}
+
+inline void ifc_downloadManagerCallback::OnInit( DownloadToken token )
+{
+ _voidcall( IFC_DOWNLOADMANAGERCALLBACK_ONINIT, token );
+}
+
+inline void ifc_downloadManagerCallback::OnData( DownloadToken token, void *data, size_t datalen )
+{
+ _voidcall( IFC_DOWNLOADMANAGERCALLBACK_ONDATA, token, data, datalen );
+}
+
+inline int ifc_downloadManagerCallback::GetSource( wchar_t *source, size_t source_cch )
+{
+ return _call( IFC_DOWNLOADMANAGERCALLBACK_GETSOURCE, (int)1, source, source_cch );
+}
+
+inline int ifc_downloadManagerCallback::GetTitle( wchar_t *title, size_t title_cch )
+{
+ return _call( IFC_DOWNLOADMANAGERCALLBACK_GETTITLE, (int)1, title, title_cch );
+}
+
+inline int ifc_downloadManagerCallback::GetLocation( wchar_t *location, size_t location_cch )
+{
+ return _call( IFC_DOWNLOADMANAGERCALLBACK_GETLOCATION, (int)1, location, location_cch );
+}
+
+
+class api_downloadManager : public Dispatchable
+{
+public:
+ DownloadToken Download( const char *url, ifc_downloadManagerCallback *callback );
+ DownloadToken DownloadEx( const char *url, ifc_downloadManagerCallback *callback, int flags );
+
+ api_httpreceiver *GetReceiver( DownloadToken token );
+ const wchar_t *GetLocation( DownloadToken token );
+ void SetLocation( DownloadToken token, const wchar_t *p_location );
+
+
+ const char *GetExtention( DownloadToken token );
+ const char *GetUrl( DownloadToken token );
+
+ int GetBuffer( DownloadToken token, void **buffer, size_t *bufferLength );
+ uint64_t GetBytesDownloaded( DownloadToken token );
+
+ void ResumePendingDownload( DownloadToken token );
+ void CancelDownload( DownloadToken token );
+ void RetainDownload( DownloadToken token );
+ void ReleaseDownload( DownloadToken token );
+
+ /* added in 5.58 */
+ void RegisterStatusCallback( ifc_downloadManagerCallback *callback );
+ void UnregisterStatusCallback( ifc_downloadManagerCallback *callback );
+
+ const wchar_t *GetSource( DownloadToken token );
+ const wchar_t *GetTitle( DownloadToken token );
+
+ bool IsPending( DownloadToken token );
+
+ DISPATCH_CODES
+ {
+ API_DOWNLOADMANAGER_DOWNLOAD = 10,
+ API_DOWNLOADMANAGER_DOWNLOADEX = 20,
+ API_DOWNLOADMANAGER_GETRECEIVER = 100,
+ API_DOWNLOADMANAGER_GETLOCATION = 110,
+ API_DOWNLOADMANAGER_SETLOCATION = 112,
+ API_DOWNLOADMANAGER_GETEXTENTION = 115,
+ API_DOWNLOADMANAGER_GETURL = 117,
+ API_DOWNLOADMANAGER_GETBYTESDOWNLOADED = 120,
+ API_DOWNLOADMANAGER_GETBUFFER = 130,
+ API_DOWNLOADMANAGER_CANCELDOWNLOAD = 140,
+ API_DOWNLOADMANAGER_RETAINDOWNLOAD = 150,
+ API_DOWNLOADMANAGER_RELEASEDOWNLOAD = 160,
+ API_DOWNLOADMANAGER_REGISTERSTATUSCALLBACK = 170,
+ API_DOWNLOADMANAGER_UNREGISTERSTATUSCALLBACK = 180,
+ API_DOWNLOADMANAGER_GETSOURCE = 190,
+ API_DOWNLOADMANAGER_GETTITLE = 200,
+ API_DOWNLOADMANAGER_RESUMEPENDINGDOWNLOAD = 210,
+ API_DOWNLOADMANAGER_ISPENDING = 220,
+ };
+
+ enum
+ {
+ DOWNLOADEX_TEMPFILE = 0, // download as a temporary file
+ DOWNLOADEX_BUFFER = 1, // download to memory
+ DOWNLOADEX_CALLBACK = 2, // send data to OnData callback
+ DOWNLOADEX_MASK_DOWNLOADMETHOD = 0x3,
+ DOWNLOADEX_PENDING = 0xF00,
+ DOWNLOADEX_UI = 0xF000, // show up in the download manager UI
+ };
+
+ enum
+ {
+ TICK_NODATA = -2, // not necessarily an error, just means no data this time around
+ TICK_FINISHED = -1,
+ TICK_SUCCESS = 0,
+ TICK_FAILURE = 1,
+ TICK_TIMEOUT = 2,
+ TICK_CANT_CONNECT = 3,
+ TICK_WRITE_ERROR = 4,
+ TICK_CONNECTING = 5,
+ TICK_CONNECTED = 6,
+
+ };
+};
+
+
+inline DownloadToken api_downloadManager::Download( const char *url, ifc_downloadManagerCallback *callback )
+{
+ return _call( API_DOWNLOADMANAGER_DOWNLOAD, (DownloadToken *)0, url, callback );
+}
+
+inline DownloadToken api_downloadManager::DownloadEx( const char *url, ifc_downloadManagerCallback *callback, int flags )
+{
+ return _call( API_DOWNLOADMANAGER_DOWNLOADEX, (DownloadToken *)0, url, callback, flags );
+}
+
+inline api_httpreceiver *api_downloadManager::GetReceiver( DownloadToken token )
+{
+ return _call( API_DOWNLOADMANAGER_GETRECEIVER, (api_httpreceiver *)0, token );
+}
+
+inline const wchar_t *api_downloadManager::GetLocation( DownloadToken token )
+{
+ return _call( API_DOWNLOADMANAGER_GETLOCATION, (const wchar_t *)0, token );
+}
+
+inline void api_downloadManager::SetLocation( DownloadToken token, const wchar_t *p_location )
+{
+ _voidcall( API_DOWNLOADMANAGER_SETLOCATION, token, p_location );
+}
+
+inline const char *api_downloadManager::GetExtention( DownloadToken token )
+{
+ return _call( API_DOWNLOADMANAGER_GETEXTENTION, (const char *)0, token );
+}
+
+inline const char *api_downloadManager::GetUrl( DownloadToken token )
+{
+ return _call( API_DOWNLOADMANAGER_GETURL, (const char *)0, token );
+}
+
+inline uint64_t api_downloadManager::GetBytesDownloaded( DownloadToken token )
+{
+ return _call( API_DOWNLOADMANAGER_GETBYTESDOWNLOADED, (uint64_t)0, token );
+}
+
+inline int api_downloadManager::GetBuffer( DownloadToken token, void **buffer, size_t *bufferLength )
+{
+ return _call( API_DOWNLOADMANAGER_GETBUFFER, (int)1, token, buffer, bufferLength );
+}
+
+inline void api_downloadManager::ResumePendingDownload( DownloadToken token )
+{
+ _voidcall( API_DOWNLOADMANAGER_RESUMEPENDINGDOWNLOAD, token );
+}
+
+inline void api_downloadManager::CancelDownload( DownloadToken token )
+{
+ _voidcall( API_DOWNLOADMANAGER_CANCELDOWNLOAD, token );
+}
+
+inline void api_downloadManager::RetainDownload( DownloadToken token )
+{
+ _voidcall( API_DOWNLOADMANAGER_RETAINDOWNLOAD, token );
+}
+
+inline void api_downloadManager::ReleaseDownload( DownloadToken token )
+{
+ _voidcall( API_DOWNLOADMANAGER_RELEASEDOWNLOAD, token );
+}
+
+
+inline void api_downloadManager::RegisterStatusCallback( ifc_downloadManagerCallback *callback )
+{
+ _voidcall( API_DOWNLOADMANAGER_REGISTERSTATUSCALLBACK, callback );
+}
+
+inline void api_downloadManager::UnregisterStatusCallback( ifc_downloadManagerCallback *callback )
+{
+ _voidcall( API_DOWNLOADMANAGER_UNREGISTERSTATUSCALLBACK, callback );
+}
+
+
+inline const wchar_t *api_downloadManager::GetSource( DownloadToken token )
+{
+ return _call( API_DOWNLOADMANAGER_GETSOURCE, (const wchar_t *)0, token );
+}
+
+inline const wchar_t *api_downloadManager::GetTitle( DownloadToken token )
+{
+ return _call( API_DOWNLOADMANAGER_GETTITLE, (const wchar_t *)0, token );
+}
+
+inline bool api_downloadManager::IsPending( DownloadToken token )
+{
+ return _call( API_DOWNLOADMANAGER_ISPENDING, (bool)0, token );
+}
+
+
+// {9E5E732A-C612-489d-AB52-1501E1AF1710}
+static const GUID DownloadManagerGUID =
+{ 0x9e5e732a, 0xc612, 0x489d, { 0xab, 0x52, 0x15, 0x1, 0xe1, 0xaf, 0x17, 0x10 } };
+
+extern api_downloadManager *g_downloadManagerApi;
+
+#ifndef WAC_API_DOWNLOADMANAGER
+#define WAC_API_DOWNLOADMANAGER g_downloadManagerApi
+#endif // !WAC_API_DOWNLOADMANAGER
+
+#endif // !NULLSOFT_WAC_DOWNLOAD_MANAGER_API_DOWNLOADMANAGER_H
diff --git a/Src/Components/wac_downloadManager/wac_downloadManager_factory.cpp b/Src/Components/wac_downloadManager/wac_downloadManager_factory.cpp
new file mode 100644
index 00000000..eb7cacf4
--- /dev/null
+++ b/Src/Components/wac_downloadManager/wac_downloadManager_factory.cpp
@@ -0,0 +1,88 @@
+#include "wac_downloadManager_factory.h"
+
+static const char serviceName[] = "WAC Downloads";
+static const char testString[] = "Downloads Component";
+
+// {B000EE81-199F-48C2-BDCB-F7E3C31A2A13}
+static const GUID api_downloads_GUID = { 0xb000ee81, 0x199f, 0x48c2, { 0xbd, 0xcb, 0xf7, 0xe3, 0x1a, 0x12, 0x2a, 0x13 } };
+
+
+FOURCC wa::Components::WAC_DownloadManagerFactory::GetServiceType()
+{
+ return WaSvc::UNIQUE;
+}
+
+const char *wa::Components::WAC_DownloadManagerFactory::GetServiceName()
+{
+ return serviceName;
+}
+
+GUID wa::Components::WAC_DownloadManagerFactory::GetGUID()
+{
+ return api_downloads_GUID;
+}
+
+const char *wa::Components::WAC_DownloadManagerFactory::GetTestString()
+{
+ return testString;
+}
+
+
+void *wa::Components::WAC_DownloadManagerFactory::GetInterface( int global_lock )
+{
+ return nullptr;
+}
+
+int wa::Components::WAC_DownloadManagerFactory::ReleaseInterface( void *ifc )
+{
+ return 1;
+}
+
+
+int wa::Components::WAC_DownloadManagerFactory::SupportNonLockingInterface()
+{
+ return 1;
+}
+
+int wa::Components::WAC_DownloadManagerFactory::ServiceNotify( int msg, int param1, int param2 )
+{
+ return 1;
+}
+
+
+HRESULT wa::Components::WAC_DownloadManagerFactory::Register( api_service *p_service )
+{
+ if ( p_service == NULL )
+ return E_INVALIDARG;
+
+ p_service->service_register( this );
+
+ return S_OK;
+}
+
+HRESULT wa::Components::WAC_DownloadManagerFactory::Unregister( api_service *p_service )
+{
+ if ( p_service == NULL )
+ return E_INVALIDARG;
+
+ p_service->service_deregister( this );
+
+ return S_OK;
+}
+
+
+#ifdef CBCLASS
+#undef CBCLASS
+#endif
+
+#define CBCLASS wa::Components::WAC_DownloadManagerFactory
+START_DISPATCH;
+CB( WASERVICEFACTORY_GETSERVICETYPE, GetServiceType )
+CB( WASERVICEFACTORY_GETSERVICENAME, GetServiceName )
+CB( WASERVICEFACTORY_GETGUID, GetGUID )
+CB( WASERVICEFACTORY_GETINTERFACE, GetInterface )
+CB( WASERVICEFACTORY_SUPPORTNONLOCKINGGETINTERFACE, SupportNonLockingInterface )
+CB( WASERVICEFACTORY_RELEASEINTERFACE, ReleaseInterface )
+CB( WASERVICEFACTORY_GETTESTSTRING, GetTestString )
+CB( WASERVICEFACTORY_SERVICENOTIFY, ServiceNotify )
+END_DISPATCH; \ No newline at end of file
diff --git a/Src/Components/wac_downloadManager/wac_downloadManager_factory.h b/Src/Components/wac_downloadManager/wac_downloadManager_factory.h
new file mode 100644
index 00000000..98d52030
--- /dev/null
+++ b/Src/Components/wac_downloadManager/wac_downloadManager_factory.h
@@ -0,0 +1,37 @@
+#ifndef NULLSOFT_WAC_DOWNLOAD_MANAGER_FACTORY_H
+#define NULLSOFT_WAC_DOWNLOAD_MANAGER_FACTORY_H
+
+#include "api__wac_downloadManager.h"
+
+#include "api/service/waservicefactory.h"
+#include "api/service/services.h"
+
+namespace wa
+{
+ namespace Components
+ {
+ class WAC_DownloadManagerFactory : public waServiceFactory
+ {
+ public:
+ FOURCC GetServiceType();
+ const char *GetServiceName();
+ GUID GetGUID();
+ const char *GetTestString();
+
+ void *GetInterface( int global_lock );
+ int ReleaseInterface( void *ifc );
+
+ int SupportNonLockingInterface();
+ int ServiceNotify( int msg, int param1, int param2 );
+
+ HRESULT Register( api_service *p_service );
+ HRESULT Unregister( api_service *p_service );
+
+
+ protected:
+ RECVS_DISPATCH;
+ };
+ }
+}
+
+#endif // !NULLSOFT_WAC_DOWNLOAD_MANAGER_FACTORY_H
diff --git a/Src/Components/wac_downloadManager/wac_downloadManager_global.h b/Src/Components/wac_downloadManager/wac_downloadManager_global.h
new file mode 100644
index 00000000..c670ccae
--- /dev/null
+++ b/Src/Components/wac_downloadManager/wac_downloadManager_global.h
@@ -0,0 +1,16 @@
+#ifndef NULLSOFT_WAC_DOWNLOAD_MANAGER_GLOBAL_H
+#define NULLSOFT_WAC_DOWNLOAD_MANAGER_GLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+#ifndef BUILD_STATIC
+# if defined(WAC_DOWNLOAD_MANAGER_LIB)
+# define WAC_DOWNLOAD_MANAGER_EXPORT Q_DECL_EXPORT
+# else
+# define WAC_DOWNLOAD_MANAGER_EXPORT Q_DECL_IMPORT
+# endif
+#else
+# define WAC_DOWNLOAD_MANAGER_EXPORT
+#endif
+
+#endif // !NULLSOFT_WAC_DOWNLOAD_MANAGER_GLOBAL_H \ No newline at end of file
diff --git a/Src/Components/wac_downloadManager/wac_download_http_receiver.cpp b/Src/Components/wac_downloadManager/wac_download_http_receiver.cpp
new file mode 100644
index 00000000..46482862
--- /dev/null
+++ b/Src/Components/wac_downloadManager/wac_download_http_receiver.cpp
@@ -0,0 +1,64 @@
+#include "wac_download_http_receiver.h"
+
+
+wa::Components::WAC_Download_HTTP_Receiver::WAC_Download_HTTP_Receiver()
+{}
+
+wa::Components::WAC_Download_HTTP_Receiver::~WAC_Download_HTTP_Receiver()
+{}
+
+void wa::Components::WAC_Download_HTTP_Receiver::open( api_dns * p_dns, size_t p_recvbufsize, const char *p_proxy )
+{
+ Q_UNUSED( p_dns )
+ Q_UNUSED( p_recvbufsize )
+ Q_UNUSED( p_proxy )
+}
+
+
+std::size_t wa::Components::WAC_Download_HTTP_Receiver::AddRef()
+{
+ return this->_reference_count.fetch_add( 1 );
+}
+
+std::size_t wa::Components::WAC_Download_HTTP_Receiver::Release()
+{
+ std::size_t l_reference_count = this->_reference_count.fetch_sub( 1 );
+ if ( l_reference_count == 0 )
+ delete this;
+
+ return l_reference_count;
+}
+
+
+#ifdef CBCLASS
+#undef CBCLASS
+#endif
+
+#define CBCLASS wa::Components::WAC_Download_HTTP_Receiver
+START_DISPATCH;
+CB( ADDREF, AddRef )
+CB( RELEASE, Release )
+VCB( API_HTTPRECEIVER_OPEN, open )
+//VCB( API_HTTPRECEIVER_ADDHEADER, addheader )
+//VCB( API_HTTPRECEIVER_ADDHEADERVALUE, addheadervalue )
+//VCB( API_HTTPRECEIVER_CONNECT, connect )
+//CB( API_HTTPRECEIVER_RUN, run )
+//CB( API_HTTPRECEIVER_GETSTATUS, get_status )
+//CB( API_HTTPRECEIVER_GETBYTESAVAILABLE, bytes_available )
+//CB( API_HTTPRECEIVER_GETBYTES, get_bytes )
+//CB( API_HTTPRECEIVER_PEEKBYTES, peek_bytes )
+//CB( API_HTTPRECEIVER_GETHEADER, getheader )
+//CB( API_HTTPRECEIVER_GETCONTENTLENGTH, content_length )
+//CB( API_HTTPRECEIVER_GETALLHEADERS, getallheaders )
+//CB( API_HTTPRECEIVER_GETREPLYCODE, getreplycode )
+//CB( API_HTTPRECEIVER_GETREPLY, getreply )
+//CB( API_HTTPRECEIVER_GETERROR, geterrorstr )
+//CB( API_HTTPRECEIVER_GETCONNECTION, get_con )
+//VCB( API_HTTPRECEIVER_ALLOW_COMPRESSION, AllowCompression )
+//VCB( API_HTTPRECEIVER_RESET_HEADERS, reset_headers )
+//CB( API_HTTPRECEIVER_GET_URL, get_url )
+//VCB( API_HTTPRECEIVER_SET_SENDBUFSIZE, set_sendbufsize )
+//VCB( API_HTTPRECEIVER_SET_ACCEPT_ALL_REPLY_CODES, set_accept_all_reply_codes )
+//VCB( API_HTTPRECEIVER_SET_PERSISTENT, set_persistent )
+END_DISPATCH;
+#undef CBCLASS
diff --git a/Src/Components/wac_downloadManager/wac_download_http_receiver.h b/Src/Components/wac_downloadManager/wac_download_http_receiver.h
new file mode 100644
index 00000000..bf90ca8c
--- /dev/null
+++ b/Src/Components/wac_downloadManager/wac_download_http_receiver.h
@@ -0,0 +1,48 @@
+#ifndef NULLSOFT_WAC_DOWNLOAD_HTTP_RECEIVER_H
+#define NULLSOFT_WAC_NETWORK_HTTP_RECEIVER_H
+
+#include <atomic>
+
+#include <QtCore>
+//#include <QAuthenticator>
+//#include <QNetworkAccessManager>
+#include <QNetworkRequest>
+#include <QNetworkReply>
+
+#include <QUrl>
+#include <QUrlQuery>
+
+//#include "wac_downloadManager_Headers.h"
+
+#include "wac_download_http_receiver_api.h"
+
+namespace wa
+{
+ namespace Components
+ {
+ class WAC_Download_HTTP_Receiver : public QObject, public api_wac_download_manager_http_receiver
+ {
+ Q_OBJECT
+
+ public:
+ WAC_Download_HTTP_Receiver();
+ ~WAC_Download_HTTP_Receiver();
+
+ void open( api_dns *p_dns = API_DNS_AUTODNS, size_t p_recvbufsize = PACKET_SIZE, const char *p_proxy = NULL );
+
+ std::size_t AddRef();
+ std::size_t Release();
+
+ protected:
+ RECVS_DISPATCH;
+
+ private:
+ volatile std::atomic<std::size_t> _reference_count = 1;
+
+
+
+ };
+ }
+}
+
+#endif // !NULLSOFT_WAC_NETWORK_HTTP_RECEIVER_H \ No newline at end of file
diff --git a/Src/Components/wac_downloadManager/wac_download_http_receiver_api.cpp b/Src/Components/wac_downloadManager/wac_download_http_receiver_api.cpp
new file mode 100644
index 00000000..3d3e3c96
--- /dev/null
+++ b/Src/Components/wac_downloadManager/wac_download_http_receiver_api.cpp
@@ -0,0 +1 @@
+#include "wac_download_http_receiver_api.h" \ No newline at end of file
diff --git a/Src/Components/wac_downloadManager/wac_download_http_receiver_api.h b/Src/Components/wac_downloadManager/wac_download_http_receiver_api.h
new file mode 100644
index 00000000..52ced7f7
--- /dev/null
+++ b/Src/Components/wac_downloadManager/wac_download_http_receiver_api.h
@@ -0,0 +1,237 @@
+#ifndef NULLSOFT_WAC_DOWNLOAD_MANAGER_API_HTTP_RECEIVER_H
+#define NULLSOFT_WAC_DOWNLOAD_MANAGER_API_HTTP_RECEIVER_H
+
+#define PACKET_SIZE 16384
+
+#include "bfc/dispatch.h"
+#include "bfc/platform/types.h"
+
+#include "../wac_network/wac_network_dns_api.h"
+
+enum
+{
+ HTTP_RECEIVER_STATUS_ERROR = -1,
+ HTTP_RECEIVER_STATUS_CONNECTING = 0,
+ HTTP_RECEIVER_STATUS_READING_HEADERS = 1,
+ HTTP_RECEIVER_STATUS_READING_CONTENT = 2,
+};
+
+enum
+{
+ HTTP_RECEIVER_RUN_ERROR = -1,
+ HTTP_RECEIVER_RUN_OK = 0,
+ HTTP_RECEIVER_RUN_CONNECTION_CLOSED = 1,
+};
+
+
+class NOVTABLE api_wac_download_manager_http_receiver : public Dispatchable
+{
+protected:
+ api_wac_download_manager_http_receiver() {}
+ ~api_wac_download_manager_http_receiver() {}
+
+public:
+ void open( api_dns *dns = API_DNS_AUTODNS, size_t recvbufsize = PACKET_SIZE, const char *proxy = NULL );
+
+ void addheader( const char *header );
+ void AddHeaderValue( const char *header, const char *value );
+ void reset_headers();
+
+ char *getheader( char *headername );
+ const char *getallheaders(); // double null terminated, null delimited list
+
+ void connect( const char *url, int ver = 0, const char *requestmethod = "GET" );
+
+ int run(); // see HTTPRECEIVER_RUN_* enum for return values
+ int get_status(); // see HTTPRECEIVER_STATUS_* enum for return values
+
+ int bytes_available();
+ int get_bytes( void *buf, int len );
+ int peek_bytes( void *buf, int len );
+
+ uint64_t content_length();
+
+ int getreplycode(); // returns 0 if none yet, otherwise returns http reply code.
+ const char *GetReply();
+
+ const char *geterrorstr();
+
+ //api_connection *GetConnection();
+
+ void AllowCompression();
+ const char *get_url(); // might not be the same as what you passed in if a redirect happened
+
+ void set_sendbufsize( int sendbufsize = PACKET_SIZE ); // call if you're going to POST or do any kind of bidirectional communications
+ void set_accept_all_reply_codes();
+ void set_persistent();
+
+ DISPATCH_CODES
+ {
+ API_HTTPRECEIVER_OPEN = 10,
+
+ API_HTTPRECEIVER_ADDHEADER = 20,
+ API_HTTPRECEIVER_ADDHEADERVALUE = 30,
+
+ API_HTTPRECEIVER_CONNECT = 40,
+
+ API_HTTPRECEIVER_RUN = 50,
+ API_HTTPRECEIVER_GETSTATUS = 60,
+
+ API_HTTPRECEIVER_GETBYTESAVAILABLE = 70,
+ API_HTTPRECEIVER_GETBYTES = 80,
+ API_HTTPRECEIVER_PEEKBYTES = 90,
+
+ API_HTTPRECEIVER_GETHEADER = 100,
+ API_HTTPRECEIVER_GETCONTENTLENGTH = 110,
+ API_HTTPRECEIVER_GETALLHEADERS = 120,
+
+ API_HTTPRECEIVER_GETREPLYCODE = 130,
+ API_HTTPRECEIVER_GETREPLY = 140,
+
+ API_HTTPRECEIVER_GETERROR = 150,
+ API_HTTPRECEIVER_GETCONNECTION = 160,
+
+ API_HTTPRECEIVER_ALLOW_COMPRESSION = 170,
+
+ API_HTTPRECEIVER_RESET_HEADERS = 180,
+
+ API_HTTPRECEIVER_GET_URL = 190,
+
+ API_HTTPRECEIVER_SET_SENDBUFSIZE = 200,
+ API_HTTPRECEIVER_SET_ACCEPT_ALL_REPLY_CODES = 210,
+ API_HTTPRECEIVER_SET_PERSISTENT = 220,
+ };
+
+};
+
+inline void api_wac_download_manager_http_receiver::open( api_dns *dns, size_t recvbufsize, const char *proxy )
+{
+ _voidcall( API_HTTPRECEIVER_OPEN, dns, recvbufsize, proxy );
+}
+
+
+inline void api_wac_download_manager_http_receiver::addheader( const char *header )
+{
+ _voidcall( API_HTTPRECEIVER_ADDHEADER, header );
+}
+
+inline void api_wac_download_manager_http_receiver::AddHeaderValue( const char *header, const char *value )
+{
+ _voidcall( API_HTTPRECEIVER_ADDHEADERVALUE, header, value );
+}
+
+inline void api_wac_download_manager_http_receiver::reset_headers()
+{
+ _voidcall( API_HTTPRECEIVER_RESET_HEADERS );
+}
+
+
+inline char *api_wac_download_manager_http_receiver::getheader( char *headername )
+{
+ return _call( API_HTTPRECEIVER_GETHEADER, (char *)NULL, headername );
+}
+
+inline const char *api_wac_download_manager_http_receiver::getallheaders()
+{
+ return _call( API_HTTPRECEIVER_GETALLHEADERS, (const char *)NULL );
+}
+
+
+inline void api_wac_download_manager_http_receiver::connect( const char *url, int ver, const char *requestmethod )
+{
+ _voidcall( API_HTTPRECEIVER_CONNECT, url, ver, requestmethod );
+}
+
+
+inline int api_wac_download_manager_http_receiver::run()
+{
+ return _call( API_HTTPRECEIVER_RUN, (int)HTTP_RECEIVER_RUN_ERROR );
+}
+
+inline int api_wac_download_manager_http_receiver::get_status()
+{
+ return _call( API_HTTPRECEIVER_GETSTATUS, (int)HTTP_RECEIVER_STATUS_ERROR );
+}
+
+
+inline int api_wac_download_manager_http_receiver::bytes_available()
+{
+ return _call( API_HTTPRECEIVER_GETBYTESAVAILABLE, (int)0 );
+}
+
+inline int api_wac_download_manager_http_receiver::get_bytes( void *buf, int len )
+{
+ return _call( API_HTTPRECEIVER_GETBYTES, (int)0, buf, len );
+}
+
+inline int api_wac_download_manager_http_receiver::peek_bytes( void *buf, int len )
+{
+ return _call( API_HTTPRECEIVER_PEEKBYTES, (int)0, buf, len );
+}
+
+
+inline uint64_t api_wac_download_manager_http_receiver::content_length()
+{
+ return _call( API_HTTPRECEIVER_GETCONTENTLENGTH, (uint64_t)0 );
+}
+
+
+inline int api_wac_download_manager_http_receiver::getreplycode()
+{
+ return _call( API_HTTPRECEIVER_GETREPLYCODE, 0 );
+}
+
+inline const char *api_wac_download_manager_http_receiver::GetReply()
+{
+ return _call( API_HTTPRECEIVER_GETREPLY, (const char *)NULL );
+}
+
+
+inline const char *api_wac_download_manager_http_receiver::geterrorstr()
+{
+ return _call( API_HTTPRECEIVER_GETERROR, (const char *)NULL );
+}
+
+
+//inline api_connection *api_wac_download_manager_http_receiver::GetConnection()
+//{
+// return _call( API_HTTPRECEIVER_GETCONNECTION, (api_connection *)NULL );
+//}
+
+
+inline void api_wac_download_manager_http_receiver::AllowCompression()
+{
+ _voidcall( API_HTTPRECEIVER_ALLOW_COMPRESSION );
+}
+
+inline const char *api_wac_download_manager_http_receiver::get_url()
+{
+ return _call( API_HTTPRECEIVER_GET_URL, (const char *)0 );
+}
+
+
+inline void api_wac_download_manager_http_receiver::set_sendbufsize( int sendbufsize )
+{
+ _voidcall( API_HTTPRECEIVER_SET_SENDBUFSIZE, sendbufsize );
+}
+
+inline void api_wac_download_manager_http_receiver::set_accept_all_reply_codes()
+{
+ _voidcall( API_HTTPRECEIVER_SET_ACCEPT_ALL_REPLY_CODES );
+}
+
+inline void api_wac_download_manager_http_receiver::set_persistent()
+{
+ _voidcall( API_HTTPRECEIVER_SET_PERSISTENT );
+}
+
+//////// {12475CD9-1BA3-4665-B395-F87DBF31E30F}
+//////static const GUID httpreceiverGUID =
+//////{ 0x12475cd9, 0x1ba3, 0x4665, { 0xb3, 0x95, 0xf8, 0x7d, 0xbf, 0x31, 0xe3, 0xf } };
+
+// {1683C6B7-1F6A-4C56-8496-525A3F5929D9}
+static const GUID httpreceiverGUID2 =
+{ 0x1683c6b7, 0x1f6a, 0x4c56, { 0x84, 0x96, 0x52, 0x5a, 0x3f, 0x59, 0x29, 0xd9 } };
+
+
+#endif // !NULLSOFT_WAC_DOWNLOAD_MANAGER_API_HTTP_RECEIVER_H
diff --git a/Src/Components/wac_downloadManager/wac_download_http_receiver_factory.cpp b/Src/Components/wac_downloadManager/wac_download_http_receiver_factory.cpp
new file mode 100644
index 00000000..ae9e4f29
--- /dev/null
+++ b/Src/Components/wac_downloadManager/wac_download_http_receiver_factory.cpp
@@ -0,0 +1,82 @@
+#define GUID_EQUALS_DEFINED
+
+//#include "util.h"
+
+#include "api__wac_downloadManager.h"
+
+#include "wac_download_http_receiver.h"
+//#include "wac_download_http_receiver_api.h"
+#include "wac_download_http_receiver_factory.h"
+
+
+static const std::string _serviceName = "DownloadManager HTTP Receiver Service";
+
+
+FOURCC wa::Factory::WAC_DownloadMabager_HTTPReceiver_Factory::GetServiceType()
+{
+ return WaSvc::OBJECT;
+}
+
+const char *wa::Factory::WAC_DownloadMabager_HTTPReceiver_Factory::GetServiceName()
+{
+ return _serviceName.c_str();
+}
+
+GUID wa::Factory::WAC_DownloadMabager_HTTPReceiver_Factory::GetGUID()
+{
+ return httpreceiverGUID2;
+}
+
+void *wa::Factory::WAC_DownloadMabager_HTTPReceiver_Factory::GetInterface( int global_lock )
+{
+ //if ( JNL::open_socketlib() )
+ // return NULL;
+
+ api_wac_download_manager_http_receiver *ifc = new wa::Components::WAC_Download_HTTP_Receiver();
+
+ //JNL::close_socketlib(); // new JNL_HTTPGet will call open_socketlib also, so we can release now
+
+ //// if (global_lock)
+ //// WASABI_API_SVC->service_lock(this, (void *)ifc);
+
+ return ifc;
+ //return NULL;
+}
+
+int wa::Factory::WAC_DownloadMabager_HTTPReceiver_Factory::SupportNonLockingInterface()
+{
+ return 1;
+}
+
+int wa::Factory::WAC_DownloadMabager_HTTPReceiver_Factory::ReleaseInterface( void *ifc )
+{
+ //WASABI_API_SVC->service_unlock(ifc);
+ api_wac_download_manager_http_receiver *httpget = static_cast<api_wac_download_manager_http_receiver *>( ifc );
+ if ( httpget )
+ httpget->Release();
+
+ return 1;
+}
+
+const char *wa::Factory::WAC_DownloadMabager_HTTPReceiver_Factory::GetTestString()
+{
+ return NULL;
+}
+
+int wa::Factory::WAC_DownloadMabager_HTTPReceiver_Factory::ServiceNotify( int msg, int param1, int param2 )
+{
+ return 1;
+}
+
+#define CBCLASS wa::Factory::WAC_DownloadMabager_HTTPReceiver_Factory
+START_DISPATCH;
+CB( WASERVICEFACTORY_GETSERVICETYPE, GetServiceType )
+CB( WASERVICEFACTORY_GETSERVICENAME, GetServiceName )
+CB( WASERVICEFACTORY_GETGUID, GetGUID )
+CB( WASERVICEFACTORY_GETINTERFACE, GetInterface )
+CB( WASERVICEFACTORY_SUPPORTNONLOCKINGGETINTERFACE, SupportNonLockingInterface )
+CB( WASERVICEFACTORY_RELEASEINTERFACE, ReleaseInterface )
+CB( WASERVICEFACTORY_GETTESTSTRING, GetTestString )
+CB( WASERVICEFACTORY_SERVICENOTIFY, ServiceNotify )
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/Components/wac_downloadManager/wac_download_http_receiver_factory.h b/Src/Components/wac_downloadManager/wac_download_http_receiver_factory.h
new file mode 100644
index 00000000..4e98c41c
--- /dev/null
+++ b/Src/Components/wac_downloadManager/wac_download_http_receiver_factory.h
@@ -0,0 +1,33 @@
+#ifndef NULLSOFT_WAC_DOWNLOAD_MANAGER_FACTORY_HTTP_RECEIVER_H
+#define NULLSOFT_WAC_DOWNLOAD_MANAGER_FACTORY_HTTP_RECEIVER_H
+
+#include <string>
+
+#include "api/service/waservicefactory.h"
+#include "api/service/services.h"
+
+namespace wa
+{
+ namespace Factory
+ {
+ class WAC_DownloadMabager_HTTPReceiver_Factory : public waServiceFactory
+ {
+ public:
+ FOURCC GetServiceType();
+ const char *GetServiceName();
+ GUID GetGUID();
+
+ void *GetInterface( int global_lock );
+ int SupportNonLockingInterface();
+ int ReleaseInterface( void *ifc );
+
+ const char *GetTestString();
+ int ServiceNotify( int msg, int param1, int param2 );
+
+ protected:
+ RECVS_DISPATCH;
+ };
+ }
+}
+
+#endif //!NULLSOFT_WAC_DOWNLOAD_MANAGER_FACTORY_HTTP_RECEIVER_H \ No newline at end of file