1113 lines
23 KiB
C++
1113 lines
23 KiB
C++
|
/*
|
||
|
** Command & Conquer Renegade(tm)
|
||
|
** Copyright 2025 Electronic Arts Inc.
|
||
|
**
|
||
|
** This program is free software: you can redistribute it and/or modify
|
||
|
** it under the terms of the GNU General Public License as published by
|
||
|
** the Free Software Foundation, either version 3 of the License, or
|
||
|
** (at your option) any later version.
|
||
|
**
|
||
|
** This program is distributed in the hope that it will be useful,
|
||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
** GNU General Public License for more details.
|
||
|
**
|
||
|
** You should have received a copy of the GNU General Public License
|
||
|
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* FILE
|
||
|
* $Archive: /Commando/Code/WWOnline/WOLDownload.cpp $
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* This class specifies patch files to be downloaded from the server.
|
||
|
*
|
||
|
* PROGRAMMER
|
||
|
* $Author: Denzil_l $
|
||
|
*
|
||
|
* VERSION INFO
|
||
|
* $Revision: 8 $
|
||
|
* $Modtime: 1/12/02 9:26p $
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
#include <WWLib\Always.h>
|
||
|
#include "WOLDownload.h"
|
||
|
#include "WOLProduct.h"
|
||
|
#include "WOLErrorUtil.h"
|
||
|
#include "WOLString.h"
|
||
|
#include <WOLAPI\DownloadDefs.h>
|
||
|
#include <WWLib\WWString.h>
|
||
|
#include <WWDebug\WWDebug.h>
|
||
|
|
||
|
namespace WWOnline {
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* Download::Create
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Create a new download.
|
||
|
*
|
||
|
* INPUTS
|
||
|
* Download - IDownload object.
|
||
|
* Update - WOL update description.
|
||
|
*
|
||
|
* RESULT
|
||
|
* Download - Reference to new download instance.
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
RefPtr<Download> Download::Create(const WOL::Update& update)
|
||
|
{
|
||
|
return new Download(update);
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* Download::Download
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Constructor
|
||
|
*
|
||
|
* INPUTS
|
||
|
* Download - IDownload object.
|
||
|
* Update - WOL update description.
|
||
|
*
|
||
|
* RESULT
|
||
|
* NONE
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
Download::Download(const WOL::Update& update) :
|
||
|
mDownloadCookie(0),
|
||
|
mState(DLPending),
|
||
|
mStatusCode(DOWNLOADSTATUS_DONE),
|
||
|
mErrorCode(0),
|
||
|
mErrorText(NULL),
|
||
|
mBytesRead(0),
|
||
|
mTotalSize(0),
|
||
|
mTimeElapsed(0),
|
||
|
mTimeRemaining(0)
|
||
|
{
|
||
|
memcpy(&mWOLUpdate, &update, sizeof(mWOLUpdate));
|
||
|
mWOLUpdate.next = NULL;
|
||
|
|
||
|
WWDEBUG_SAY(("WOL: Download instantiated '%s'\n", GetFilename()));
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* Download::~Download
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Destructor
|
||
|
*
|
||
|
* INPUTS
|
||
|
* NONE
|
||
|
*
|
||
|
* RESULT
|
||
|
* NONE
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
Download::~Download()
|
||
|
{
|
||
|
WWDEBUG_SAY(("WOL: Download destructing '%s'\n", GetFilename()));
|
||
|
Stop();
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* Download::CreateDownloadObject
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
*
|
||
|
* INPUTS
|
||
|
* NONE
|
||
|
*
|
||
|
* RESULT
|
||
|
* True if successful.
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
bool Download::CreateDownloadObject(void)
|
||
|
{
|
||
|
//---------------------------------------------------------------------------
|
||
|
// Create Download object
|
||
|
//---------------------------------------------------------------------------
|
||
|
WWDEBUG_SAY(("WOL: Creating IID_IDownload object\n"));
|
||
|
|
||
|
WOL::IDownload* downloadObject = NULL;
|
||
|
HRESULT hr = CoCreateInstance(WOL::CLSID_Download, NULL, CLSCTX_INPROC_SERVER,
|
||
|
WOL::IID_IDownload, (void **)&downloadObject);
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
WWDEBUG_SAY(("WOLERROR: Failed to create IID_IDownload\n"));
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
mDownloadObject = downloadObject;
|
||
|
|
||
|
// Register this download as an event sink for download events
|
||
|
hr = AtlAdvise(mDownloadObject, this, WOL::IID_IDownloadEvent, &mDownloadCookie);
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
WWDEBUG_SAY(("WOLERROR: AltAdvise failed\n"));
|
||
|
SetError(-1, "WOL_NOTINITIALIZED");
|
||
|
mDownloadCookie = 0;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* Download::ReleaseDownloadObject
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
*
|
||
|
* INPUTS
|
||
|
* NONE
|
||
|
*
|
||
|
* RESULT
|
||
|
* NONE
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
void Download::ReleaseDownloadObject(void)
|
||
|
{
|
||
|
// No longer listen to download events.
|
||
|
if (mDownloadObject && mDownloadCookie != 0)
|
||
|
{
|
||
|
HRESULT hr = AtlUnadvise(mDownloadObject, WOL::IID_IDownloadEvent, mDownloadCookie);
|
||
|
mDownloadCookie = 0;
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
WWDEBUG_SAY(("WOLERROR: Download AltUnadvise failed\n"));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
mDownloadObject.Release();
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* Download::Start
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Start downloading file.
|
||
|
*
|
||
|
* INPUTS
|
||
|
* NONE
|
||
|
*
|
||
|
* RESULT
|
||
|
* True if download started successfully.
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
bool Download::Start(void)
|
||
|
{
|
||
|
// If the file was already download successfully then we are done.
|
||
|
if (DLComplete == mState)
|
||
|
{
|
||
|
OnEnd();
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// Verify product is initialized
|
||
|
RefPtr<Product> product = Product::Current();
|
||
|
|
||
|
if (!product.IsValid())
|
||
|
{
|
||
|
WWDEBUG_SAY(("WOLERROR: Product not initialized\n"));
|
||
|
SetError(-1, "WOL_NOTINITIALIZED");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool downloadCreated = CreateDownloadObject();
|
||
|
|
||
|
if (!downloadCreated)
|
||
|
{
|
||
|
WWDEBUG_SAY(("WOLERROR: IDownload object not initialized\n"));
|
||
|
SetError(-1, "WOL_NOTINITIALIZED");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// Attempt to create the target path for the download file.
|
||
|
const char* localPath = GetLocalPath();
|
||
|
int dirCreated = CreateDirectory(localPath, NULL);
|
||
|
|
||
|
if (!dirCreated && (ERROR_ALREADY_EXISTS != GetLastError()))
|
||
|
{
|
||
|
WWDEBUG_SAY(("WOLERROR: Failed to create download directory '%s'\n", localPath));
|
||
|
Print_Win32Error(GetLastError());
|
||
|
SetError(DOWNLOADEVENT_LOCALFILEOPENFAILED, GetOnErrorText(DOWNLOADEVENT_LOCALFILEOPENFAILED));
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// Generate full pathname for source and target
|
||
|
const char* downloadPath = GetDownloadPath();
|
||
|
const char* filename = GetFilename();
|
||
|
|
||
|
StringClass localFile(true);
|
||
|
localFile.Format("%s\\%s", localPath, filename);
|
||
|
|
||
|
StringClass downloadFile(true);
|
||
|
downloadFile.Format("%s\\%s", downloadPath, filename);
|
||
|
|
||
|
// Initiate download of file.
|
||
|
const char* server = GetServerName();
|
||
|
const char* login = GetLoginName();
|
||
|
const char* password = GetPassword();
|
||
|
const char* regPath = product->GetRegistryPath();
|
||
|
|
||
|
WWDEBUG_SAY(("WOL: Downloading '%s' to '%s'\n", (const char*)downloadFile, (const char*)localFile));
|
||
|
HRESULT hr = mDownloadObject->DownloadFile(server, login, password, downloadFile, localFile, regPath);
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
WWDEBUG_SAY(("WOLERROR: DownloadFile() HRESULT = %s\n", GetDownloadErrorString(hr)));
|
||
|
AtlUnadvise(mDownloadObject, WOL::IID_IDownloadEvent, mDownloadCookie);
|
||
|
SetError(DOWNLOADEVENT_COULDNOTCONNECT, GetOnErrorText(DOWNLOADEVENT_COULDNOTCONNECT));
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
mState = DLDownloading;
|
||
|
|
||
|
DownloadEvent event(DownloadEvent::DOWNLOAD_BEGIN, this);
|
||
|
NotifyObservers(event);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* Download::Stop
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Stop the download in progress.
|
||
|
*
|
||
|
* INPUTS
|
||
|
* NONE
|
||
|
*
|
||
|
* RESULT
|
||
|
* NONE
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
void Download::Stop(void)
|
||
|
{
|
||
|
if (mDownloadObject)
|
||
|
{
|
||
|
// If the download is in progress then stop it.
|
||
|
if (DLDownloading == mState)
|
||
|
{
|
||
|
mState = DLAborted;
|
||
|
|
||
|
HRESULT hr = mDownloadObject->Abort();
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
WWDEBUG_SAY(("WOLERROR: WOL::IDownload::Abort() HRESULT = %s\n", GetDownloadErrorString(hr)));
|
||
|
}
|
||
|
|
||
|
DownloadEvent event(DownloadEvent::DOWNLOAD_STOPPED, this);
|
||
|
NotifyObservers(event);
|
||
|
}
|
||
|
|
||
|
ReleaseDownloadObject();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* Download::IsDone
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Check if the download has finished.
|
||
|
*
|
||
|
* INPUTS
|
||
|
* NONE
|
||
|
*
|
||
|
* RESULT
|
||
|
* True if download is finished.
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
bool Download::IsDone(void) const
|
||
|
{
|
||
|
return (DLComplete == mState);
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* Download::Process
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Yield time for the download to process.
|
||
|
*
|
||
|
* INPUTS
|
||
|
* NONE
|
||
|
*
|
||
|
* RESULT
|
||
|
* NONE
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
void Download::Process(void)
|
||
|
{
|
||
|
if (mDownloadObject)
|
||
|
{
|
||
|
mDownloadObject->PumpMessages();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* Download::GetStatusText
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Get a text description of the current download status.
|
||
|
*
|
||
|
* INPUTS
|
||
|
* NONE
|
||
|
*
|
||
|
* RESULT
|
||
|
* Status - Text description of status.
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
const wchar_t* Download::GetStatusText(void) const
|
||
|
{
|
||
|
static const char* _statusText[] =
|
||
|
{
|
||
|
// DOWNLOADSTATUS_DONE
|
||
|
"WOL_DOWNLOADDONE",
|
||
|
|
||
|
// DOWNLOADSTATUS_GO
|
||
|
"WOL_DOWNLOADGO",
|
||
|
|
||
|
// DOWNLOADSTATUS_CONNECTING
|
||
|
"WOL_DOWNLOADCONNECT",
|
||
|
|
||
|
// DOWNLOADSTATUS_LOGGINGIN
|
||
|
"WOL_DOWNLOADLOGIN",
|
||
|
|
||
|
// DOWNLOADSTATUS_FINDINGFILE
|
||
|
"WOL_DOWNLOADFIND",
|
||
|
|
||
|
// DOWNLOADSTATUS_QUERYINGRESUME
|
||
|
"WOL_DOWNLOADRESUME",
|
||
|
|
||
|
// DOWNLOADSTATUS_DOWNLOADING
|
||
|
"WOL_DOWNLOADING",
|
||
|
|
||
|
// DOWNLOADSTATUS_DISCONNECTING
|
||
|
"WOL_DOWNLOADDISCONNECT"
|
||
|
};
|
||
|
|
||
|
if ((mStatusCode >= 0) && (mStatusCode < ARRAY_SIZE(_statusText)))
|
||
|
{
|
||
|
return WOLSTRING(_statusText[mStatusCode]);
|
||
|
}
|
||
|
|
||
|
return L"";
|
||
|
}
|
||
|
|
||
|
|
||
|
const wchar_t* Download::GetErrorText(void) const
|
||
|
{
|
||
|
return WOLSTRING(mErrorText);
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* Download::GetOnErrorText
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Get a text description of the current error condition.
|
||
|
*
|
||
|
* INPUTS
|
||
|
* NONE
|
||
|
*
|
||
|
* RESULT
|
||
|
* Error - Text description of error.
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
const char* Download::GetOnErrorText(int onErrorCode) const
|
||
|
{
|
||
|
static const char* _onErrorText[] =
|
||
|
{
|
||
|
// DOWNLOADEVENT_NOSUCHSERVER
|
||
|
"WOL_DOWNLOADNOSERVER",
|
||
|
|
||
|
// DOWNLOADEVENT_COULDNOTCONNECT
|
||
|
"WOL_DOWNLOADCONNECTERROR",
|
||
|
|
||
|
// DOWNLOADEVENT_LOGINFAILED
|
||
|
"WOL_DOWNLOADLOGINERROR",
|
||
|
|
||
|
// DOWNLOADEVENT_NOSUCHFILE
|
||
|
"WOL_DOWNLOADFNF",
|
||
|
|
||
|
// DOWNLOADEVENT_LOCALFILEOPENFAILED
|
||
|
"WOL_DOWNLOADOPENERROR",
|
||
|
|
||
|
// DOWNLOADEVENT_TCPERROR
|
||
|
"WOL_DOWNLOADIOERROR",
|
||
|
|
||
|
// DOWNLOADEVENT_DISCONNECTERROR
|
||
|
"WOL_DOWNLOADDISCONNECTERROR"
|
||
|
};
|
||
|
|
||
|
if ((onErrorCode >= 1) && (onErrorCode < ARRAY_SIZE(_onErrorText)))
|
||
|
{
|
||
|
return _onErrorText[onErrorCode - 1];
|
||
|
}
|
||
|
|
||
|
return "";
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* Download::SetError
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
*
|
||
|
* INPUTS
|
||
|
* ErrorCode - Numerical error code.
|
||
|
* ErrorText - Text description of error code.
|
||
|
*
|
||
|
* RESULT
|
||
|
* NONE
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
void Download::SetError(int errorCode, const char* errorText)
|
||
|
{
|
||
|
mState = DLError;
|
||
|
mErrorCode = errorCode;
|
||
|
mErrorText = errorText;
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* Download::GetProgress
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Get the progress of the download.
|
||
|
*
|
||
|
* INPUTS
|
||
|
* BytesRead - On Return; Number of bytes read.
|
||
|
* TotalSize - On Return; Total number of bytes to download.
|
||
|
* TimeElapsed - On Return; Time elapsed since download began.
|
||
|
* TimeRemaining - On Return; Estimated time remaining for download.
|
||
|
*
|
||
|
* RESULT
|
||
|
* NONE
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
void Download::GetProgress(int& bytesRead, int& totalSize, int& timeElapsed, int& timeRemaining) const
|
||
|
{
|
||
|
bytesRead = mBytesRead;
|
||
|
totalSize = mTotalSize;
|
||
|
timeElapsed = mTimeElapsed;
|
||
|
timeRemaining = mTimeRemaining;
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* IUnknown::QueryInterface
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
*
|
||
|
* INPUTS
|
||
|
*
|
||
|
* RESULT
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
STDMETHODIMP Download::QueryInterface(const IID& iid, void** ppv)
|
||
|
{
|
||
|
if ((iid == IID_IUnknown) || (iid == WOL::IID_IDownloadEvent))
|
||
|
{
|
||
|
*ppv = static_cast<WOL::IDownloadEvent*>(this);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*ppv = NULL;
|
||
|
return E_NOINTERFACE;
|
||
|
}
|
||
|
|
||
|
static_cast<IUnknown*>(*ppv)->AddRef();
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* IUnknown::AddRef
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
*
|
||
|
* INPUTS
|
||
|
* NONE
|
||
|
*
|
||
|
* RESULT
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
ULONG STDMETHODCALLTYPE Download::AddRef(void)
|
||
|
{
|
||
|
RefCounted::AddReference();
|
||
|
return RefCounted::ReferenceCount();
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* IUnknown::Release
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
*
|
||
|
* INPUTS
|
||
|
* NONE
|
||
|
*
|
||
|
* RESULT
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
|
||
|
ULONG STDMETHODCALLTYPE Download::Release(void)
|
||
|
{
|
||
|
ULONG refCount = RefCounted::ReferenceCount();
|
||
|
RefCounted::ReleaseReference();
|
||
|
return --refCount;
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* Download::OnEnd
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Notification that the download has completed.
|
||
|
*
|
||
|
* INPUTS
|
||
|
* NONE
|
||
|
*
|
||
|
* RESULT
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
STDMETHODIMP Download::OnEnd(void)
|
||
|
{
|
||
|
WWDEBUG_SAY(("WOL: Download End '%s'\n", GetFilename()));
|
||
|
|
||
|
SetError(0, NULL);
|
||
|
mState = DLComplete;
|
||
|
|
||
|
DownloadEvent event(DownloadEvent::DOWNLOAD_END, this);
|
||
|
NotifyObservers(event);
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* Download::OnError
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Notification that the download has encountered an error.
|
||
|
*
|
||
|
* INPUTS
|
||
|
*
|
||
|
* RESULT
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
STDMETHODIMP Download::OnError(int error)
|
||
|
{
|
||
|
WWDEBUG_SAY(("WOLERROR: Download '%s'\n", GetFilename()));
|
||
|
|
||
|
#ifdef WWDEBUG
|
||
|
static const char* _errors[] =
|
||
|
{
|
||
|
"DOWNLOADEVENT_NOSUCHSERVER",
|
||
|
"DOWNLOADEVENT_COULDNOTCONNECT",
|
||
|
"DOWNLOADEVENT_LOGINFAILED",
|
||
|
"DOWNLOADEVENT_NOSUCHFILE",
|
||
|
"DOWNLOADEVENT_LOCALFILEOPENFAILED",
|
||
|
"DOWNLOADEVENT_TCPERROR",
|
||
|
"DOWNLOADEVENT_DISCONNECTERROR"
|
||
|
};
|
||
|
|
||
|
WWDEBUG_SAY(("WOLERROR: Download Error: %s\n", _errors[error - 1]));
|
||
|
#endif
|
||
|
|
||
|
SetError(error, GetOnErrorText(error));
|
||
|
|
||
|
DownloadEvent event(DownloadEvent::DOWNLOAD_ERROR, this);
|
||
|
NotifyObservers(event);
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* Download::OnProgressUpdate
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Notification of the downloads progress.
|
||
|
*
|
||
|
* INPUTS
|
||
|
*
|
||
|
* RESULT
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
STDMETHODIMP Download::OnProgressUpdate(int bytesRead, int totalSize,
|
||
|
int timeElapsed, int timeRemaining)
|
||
|
{
|
||
|
mBytesRead = bytesRead;
|
||
|
mTotalSize = totalSize;
|
||
|
mTimeElapsed = timeElapsed;
|
||
|
mTimeRemaining = timeRemaining;
|
||
|
|
||
|
DownloadEvent event(DownloadEvent::DOWNLOAD_PROGRESS, this);
|
||
|
NotifyObservers(event);
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* DownloadObserver::OnQueryResume
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
*
|
||
|
* INPUTS
|
||
|
*
|
||
|
* RESULT
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
STDMETHODIMP Download::OnQueryResume(void)
|
||
|
{
|
||
|
WWDEBUG_SAY(("WOL: Download QueryResume '%s'\n", GetFilename()));
|
||
|
|
||
|
DownloadEvent event(DownloadEvent::DOWNLOAD_RESUME, this);
|
||
|
NotifyObservers(event);
|
||
|
|
||
|
return DOWNLOADEVENT_RESUME;
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* DownloadObserver::OnStatusUpdate
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Notification of the downloads status change.
|
||
|
*
|
||
|
* INPUTS
|
||
|
*
|
||
|
* RESULT
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
STDMETHODIMP Download::OnStatusUpdate(int status)
|
||
|
{
|
||
|
#ifdef WWDEBUG
|
||
|
static const char* _status[] =
|
||
|
{
|
||
|
"DOWNLOADSTATUS_DONE",
|
||
|
"DOWNLOADSTATUS_GO",
|
||
|
"DOWNLOADSTATUS_CONNECTING",
|
||
|
"DOWNLOADSTATUS_LOGGINGIN",
|
||
|
"DOWNLOADSTATUS_FINDINGFILE",
|
||
|
"DOWNLOADSTATUS_QUERYINGRESUME",
|
||
|
"DOWNLOADSTATUS_DOWNLOADING",
|
||
|
"DOWNLOADSTATUS_DISCONNECTING",
|
||
|
};
|
||
|
|
||
|
WWDEBUG_SAY(("WOL: Download Status: %s\n", _status[status]));
|
||
|
#endif
|
||
|
|
||
|
mStatusCode = status;
|
||
|
|
||
|
DownloadEvent event(DownloadEvent::DOWNLOAD_STATUS, this);
|
||
|
NotifyObservers(event);
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* DownloadWait::Create
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Create a wait condition to process downloads.
|
||
|
*
|
||
|
* INPUTS
|
||
|
* List of download files.
|
||
|
*
|
||
|
* RESULT
|
||
|
* Wait condition to process.
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
RefPtr<DownloadWait> DownloadWait::Create(const DownloadList& files)
|
||
|
{
|
||
|
if (files.empty())
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
return new DownloadWait(files);
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* DownloadWait::DownloadWait
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Constructor
|
||
|
*
|
||
|
* INPUTS
|
||
|
* List of download files.
|
||
|
*
|
||
|
* RESULT
|
||
|
* NONE
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
DownloadWait::DownloadWait(const DownloadList& files) :
|
||
|
SingleWait(WOLSTRING("WOL_DOWNLOADING")),
|
||
|
mFiles(files),
|
||
|
mFileIndex(-1),
|
||
|
mCallback(NULL)
|
||
|
{
|
||
|
WWDEBUG_SAY(("WOL: DownloadWait Create\n"));
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* DownloadWait::~DownloadWait
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Destructor
|
||
|
*
|
||
|
* INPUTS
|
||
|
* NONE
|
||
|
*
|
||
|
* RESULT
|
||
|
* NONE
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
DownloadWait::~DownloadWait()
|
||
|
{
|
||
|
WWDEBUG_SAY(("WOL: DownloadWait End '%S'\n", mEndText));
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* DownloadWait::WaitBeginning
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Begin download process.
|
||
|
*
|
||
|
* INPUTS
|
||
|
* NONE
|
||
|
*
|
||
|
* RESULT
|
||
|
* NONE
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
void DownloadWait::WaitBeginning(void)
|
||
|
{
|
||
|
WWDEBUG_SAY(("WOL: DownloadWait Begin\n"));
|
||
|
|
||
|
// If there are no files to download then just say we are done.
|
||
|
if (mFiles.empty())
|
||
|
{
|
||
|
SingleWait::EndWait(ConditionMet, WOLSTRING("WOL_DOWNLOADDONE"));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// WaitBeginning should only be called once.
|
||
|
if (mCurrentDownload.IsValid())
|
||
|
{
|
||
|
WWDEBUG_SAY(("WOLERROR: DownloadWait::WaitBeginning() called more that once"));
|
||
|
WWASSERT("DownloadWait::WaitBeginning() called more that once");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Start the first download
|
||
|
mFileIndex = 0;
|
||
|
mCurrentDownload = mFiles[0];
|
||
|
|
||
|
Observer<DownloadEvent>::NotifyMe(*mCurrentDownload);
|
||
|
bool started = mCurrentDownload->Start();
|
||
|
|
||
|
if (!started)
|
||
|
{
|
||
|
SingleWait::EndWait(Error, mCurrentDownload->GetErrorText());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* DownloadWait::GetResult
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Check the status of the download.
|
||
|
* This must be called regularly for the wait condition to be processed.
|
||
|
*
|
||
|
* INPUTS
|
||
|
* NONE
|
||
|
*
|
||
|
* RESULT
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
WaitCondition::WaitResult DownloadWait::GetResult(void)
|
||
|
{
|
||
|
if (mFileIndex == -1)
|
||
|
{
|
||
|
return Waiting;
|
||
|
}
|
||
|
|
||
|
// Process the current download
|
||
|
if (mEndResult == Waiting)
|
||
|
{
|
||
|
mCurrentDownload->Process();
|
||
|
|
||
|
// If the current download is complete then start the next one.
|
||
|
if (mCurrentDownload->IsDone())
|
||
|
{
|
||
|
Observer<DownloadEvent>::StopObserving();
|
||
|
|
||
|
mCurrentDownload->Stop();
|
||
|
mCurrentDownload.Release();
|
||
|
|
||
|
// Advance to the next file.
|
||
|
++mFileIndex;
|
||
|
|
||
|
// If there are more files then start the next one in sequence.
|
||
|
if ((unsigned)mFileIndex < mFiles.size())
|
||
|
{
|
||
|
mCurrentDownload = mFiles[mFileIndex];
|
||
|
WWASSERT(mCurrentDownload.IsValid());
|
||
|
Observer<DownloadEvent>::NotifyMe(*mCurrentDownload);
|
||
|
|
||
|
bool started = mCurrentDownload->Start();
|
||
|
|
||
|
if (!started)
|
||
|
{
|
||
|
EndWait(Error, mCurrentDownload->GetErrorText());
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// If all of the files have downloaded successfully then the wait
|
||
|
// condition has been met.
|
||
|
EndWait(ConditionMet, WOLSTRING("WOL_DOWNLOADCOMPLETE"));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return mEndResult;
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* DownloadWait::EndWait
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
* Terminate the wait condition.
|
||
|
*
|
||
|
* INPUTS
|
||
|
*
|
||
|
* RESULT
|
||
|
* NONE
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
void DownloadWait::EndWait(WaitResult endResult, const wchar_t* endText)
|
||
|
{
|
||
|
if ((ConditionMet != endResult) && mCurrentDownload.IsValid())
|
||
|
{
|
||
|
mCurrentDownload->Stop();
|
||
|
}
|
||
|
|
||
|
SingleWait::EndWait(endResult, endText);
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* DownloadWait::SetCallback
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
*
|
||
|
* INPUTS
|
||
|
*
|
||
|
* RESULT
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
void DownloadWait::SetCallback(DownloadWaitCallback callback, unsigned long userdata)
|
||
|
{
|
||
|
mCallback = callback;
|
||
|
mUserdata = userdata;
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* DownloadWait::DoCallback
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
*
|
||
|
* INPUTS
|
||
|
*
|
||
|
* RESULT
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
void DownloadWait::DoCallback(DownloadEvent& event)
|
||
|
{
|
||
|
if (mCallback)
|
||
|
{
|
||
|
mCallback(event, mUserdata);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
*
|
||
|
* NAME
|
||
|
* DownloadWait::HandleNotification(DownloadEvent)
|
||
|
*
|
||
|
* DESCRIPTION
|
||
|
*
|
||
|
* INPUTS
|
||
|
*
|
||
|
* RESULT
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
void DownloadWait::HandleNotification(DownloadEvent& event)
|
||
|
{
|
||
|
if (mEndResult == Waiting)
|
||
|
{
|
||
|
const RefPtr<Download>& download = event.GetDownload();
|
||
|
WWASSERT(download.IsValid());
|
||
|
WWASSERT(mCurrentDownload == download);
|
||
|
|
||
|
switch (event.GetEvent())
|
||
|
{
|
||
|
case DownloadEvent::DOWNLOAD_ERROR:
|
||
|
WWDEBUG_SAY(("WOLERROR: Download Error %S\n", download->GetErrorText()));
|
||
|
EndWait(Error, download->GetErrorText());
|
||
|
break;
|
||
|
|
||
|
case DownloadEvent::DOWNLOAD_STATUS:
|
||
|
mWaitText = download->GetStatusText();
|
||
|
break;
|
||
|
|
||
|
case DownloadEvent::DOWNLOAD_BEGIN:
|
||
|
break;
|
||
|
|
||
|
case DownloadEvent::DOWNLOAD_PROGRESS:
|
||
|
break;
|
||
|
|
||
|
case DownloadEvent::DOWNLOAD_END:
|
||
|
WWDEBUG_SAY(("WOL: Download complete\n"));
|
||
|
break;
|
||
|
|
||
|
case DownloadEvent::DOWNLOAD_STOPPED:
|
||
|
WWDEBUG_SAY(("WOL: Download stopped\n"));
|
||
|
EndWait(UserCancel, WOLSTRING("WOL_DOWNLOADSTOPPED"));
|
||
|
break;
|
||
|
|
||
|
case DownloadEvent::DOWNLOAD_RESUME:
|
||
|
WWDEBUG_SAY(("WOL: Download resumed\n"));
|
||
|
mWaitText = WOLSTRING("WOL_DOWNLOADRESUME");
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
DoCallback(event);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} // namespace WWOnline
|