You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3353 lines
96 KiB
3353 lines
96 KiB
// ===========================================================================
|
|
// File: DL.CXX
|
|
// implements CDownload, CBindStatusCallback classes
|
|
//
|
|
|
|
#include <cdlpch.h>
|
|
|
|
// SILENT MODE
|
|
#include <winineti.h>
|
|
#include <shlwapi.h>
|
|
#include <shlwapip.h>
|
|
#include <comcat.h>
|
|
|
|
#include <initguid.h> // office antivirus goo
|
|
#define AVVENDOR // don't look at unwanted office defs
|
|
#include <msoav.h>
|
|
|
|
extern char g_szOCXTempDir[MAX_PATH];
|
|
extern IEnumFORMATETC *g_pEFmtETC;
|
|
extern FORMATETC g_rgfmtetc[];
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CDownload::CDownload
|
|
// CDownload is the basic download obj.
|
|
// ---------------------------------------------------------------------------
|
|
|
|
CDownload::CDownload(LPCWSTR szURL, FILEXTN extn, HRESULT *phr)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
None,
|
|
"CDownload::CDownload",
|
|
"this=%#x, %.80wq, %#x, %#x",
|
|
this, szURL, extn, phr
|
|
));
|
|
|
|
DllAddRef();
|
|
DWORD len = lstrlenW(szURL); // make private copy
|
|
|
|
m_url = new WCHAR [len + 1];
|
|
|
|
if (m_url)
|
|
StrCpyW(m_url, szURL);
|
|
else
|
|
*phr = E_OUTOFMEMORY;
|
|
|
|
m_pmk = 0;
|
|
m_pbc = 0;
|
|
m_pbsc = 0;
|
|
|
|
m_pdlnext= NULL;
|
|
|
|
m_ParentCDL.RemoveAll();
|
|
|
|
m_extn = extn;
|
|
m_pFileName = NULL; // we don't know the dest filename
|
|
// till we create a temp file in the first
|
|
// notification of OnDataAvailable
|
|
// This is guaranteed to get set before
|
|
// OnStopBinding
|
|
|
|
m_ulProgress = 0;
|
|
m_ulProgressMax = 0;
|
|
|
|
m_state = DLSTATE_INIT;
|
|
|
|
m_psess = NULL;
|
|
m_pFilesToExtract = NULL;
|
|
|
|
m_pSetuphead = NULL;
|
|
|
|
m_hPostData = NULL;
|
|
m_cbPostData = 0;
|
|
|
|
m_hrOSB = S_OK;
|
|
m_hrStatus = S_OK;
|
|
m_hrResponseHdr = S_OK;
|
|
|
|
m_bCompleteSignalled = FALSE;
|
|
|
|
m_flags = DL_FLAGS_INIT;
|
|
|
|
m_SetupHooks.RemoveAll();
|
|
|
|
m_JavaSetupList.RemoveAll();
|
|
|
|
m_pUnkForCacheFileRelease = NULL;
|
|
|
|
m_pbJavaTrust = NULL;
|
|
|
|
m_wszDistUnit = NULL;
|
|
|
|
m_pcbhList = NULL;
|
|
m_ppmkContext = NULL;
|
|
m_grfBINDF = 0;
|
|
|
|
m_bExactVersion = FALSE;
|
|
|
|
DEBUG_LEAVE(0);
|
|
} // CDownload
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CDownload::~CDownload
|
|
// ---------------------------------------------------------------------------
|
|
|
|
CDownload::~CDownload()
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
None,
|
|
"CDownload::~CDownload",
|
|
"this=%#x",
|
|
this
|
|
));
|
|
|
|
int i;
|
|
CCodeBaseHold *pcbh = NULL;
|
|
LISTPOSITION lpos = 0;
|
|
|
|
CleanUp();
|
|
LISTPOSITION pos = m_ParentCDL.GetHeadPosition();
|
|
int iNum = m_ParentCDL.GetCount();
|
|
|
|
Assert(iNum == 0);
|
|
for (i=0; i < iNum; i++) {
|
|
CParentCDL *pParentCDL = m_ParentCDL.GetNext(pos); // pass ref!
|
|
delete pParentCDL;
|
|
}
|
|
m_ParentCDL.RemoveAll();
|
|
|
|
if (m_pcbhList != NULL) {
|
|
lpos = m_pcbhList->GetHeadPosition();
|
|
while (lpos) {
|
|
pcbh = m_pcbhList->GetNext(lpos);
|
|
delete pcbh;
|
|
}
|
|
m_pcbhList->RemoveAll();
|
|
}
|
|
SAFEDELETE(m_pcbhList);
|
|
SAFEDELETE(m_wszDistUnit);
|
|
|
|
pos = m_SetupHooks.GetHeadPosition();
|
|
iNum = m_SetupHooks.GetCount();
|
|
for (i=0; i < iNum; i++) {
|
|
CSetupHook *pSetupHook = m_SetupHooks.GetNext(pos); // pass ref!
|
|
delete pSetupHook;
|
|
}
|
|
m_SetupHooks.RemoveAll();
|
|
|
|
pos = m_JavaSetupList.GetHeadPosition();
|
|
iNum = m_JavaSetupList.GetCount();
|
|
for (i=0; i < iNum; i++) {
|
|
CJavaSetup *pJavaSetup = m_JavaSetupList.GetNext(pos); // pass ref!
|
|
delete pJavaSetup;
|
|
}
|
|
m_JavaSetupList.RemoveAll();
|
|
DllRelease();
|
|
|
|
DEBUG_LEAVE(0);
|
|
} // ~CDownload
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CDownload::HasJavaPermissions
|
|
// ---------------------------------------------------------------------------
|
|
BOOL
|
|
CDownload::HasJavaPermissions()
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Bool,
|
|
"CDownload::HasJavaPermissions",
|
|
"this=%#x",
|
|
this
|
|
));
|
|
|
|
if (m_pbJavaTrust) {
|
|
// new jaavcypt > 2151 succeeds even if one of activex/java
|
|
// is allowed
|
|
|
|
DEBUG_LEAVE((m_pbJavaTrust->pbJavaPermissions != NULL));
|
|
return (m_pbJavaTrust->pbJavaPermissions != NULL);
|
|
}
|
|
|
|
DEBUG_LEAVE(FALSE);
|
|
return FALSE;
|
|
}
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CDownload::HasAllActiveXPermissions
|
|
// ---------------------------------------------------------------------------
|
|
BOOL
|
|
CDownload::HasAllActiveXPermissions()
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Bool,
|
|
"CDownload::HasAllActiveXPermissions",
|
|
"this=%#x",
|
|
this
|
|
));
|
|
|
|
PJAVA_TRUST pbJavaTrust = NULL;
|
|
|
|
if (m_pbJavaTrust) {
|
|
// new jaavcypt > 2151 succeeds even if one of activex/java
|
|
// is allowed
|
|
|
|
DEBUG_LEAVE(m_pbJavaTrust->fAllActiveXPermissions);
|
|
return m_pbJavaTrust->fAllActiveXPermissions;
|
|
}
|
|
else {
|
|
pbJavaTrust = GetCodeDownload()->GetJavaTrust();
|
|
if (pbJavaTrust) {
|
|
|
|
DEBUG_LEAVE(pbJavaTrust->fAllActiveXPermissions);
|
|
return pbJavaTrust->fAllActiveXPermissions;
|
|
}
|
|
}
|
|
|
|
DEBUG_LEAVE(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CDownload::CompleteSignal
|
|
// ---------------------------------------------------------------------------
|
|
HRESULT
|
|
CDownload::CompleteSignal(HRESULT hrOSB, HRESULT hrStatus, HRESULT hrResponseHdr, LPCWSTR szError)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Hresult,
|
|
"CDownload::CompleteSignal",
|
|
"this=%#x, %#x, %#x, %#x, %.80wq",
|
|
this, hrOSB, hrStatus, hrResponseHdr, szError
|
|
));
|
|
|
|
int i, iNum;
|
|
LISTPOSITION pos;
|
|
|
|
m_hrOSB = hrOSB;
|
|
m_hrStatus = hrStatus;
|
|
m_hrResponseHdr = hrResponseHdr;
|
|
|
|
m_bCompleteSignalled = TRUE;
|
|
|
|
restart:
|
|
|
|
iNum = m_ParentCDL.GetCount();
|
|
Assert(iNum);
|
|
|
|
pos = m_ParentCDL.GetHeadPosition();
|
|
|
|
for (i=0; i < iNum; i++) {
|
|
CParentCDL *pParentCDL = m_ParentCDL.GetNext(pos); // pass ref!
|
|
|
|
if (!pParentCDL->m_bCompleteSignalled) {
|
|
|
|
// unsignalled code download
|
|
pParentCDL->m_bCompleteSignalled = TRUE;
|
|
pParentCDL->m_pcdl->CompleteOne( this ,hrOSB, hrStatus, hrResponseHdr, szError);
|
|
|
|
if (iNum > 1) {
|
|
// failed complete reports could cause CodeDownloads to release
|
|
// us and thus change the list
|
|
goto restart;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
DEBUG_LEAVE(S_OK);
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CDownload::AddParent(CCodeDownload *pcdl)
|
|
// ---------------------------------------------------------------------------
|
|
HRESULT
|
|
CDownload::AddParent(CCodeDownload *pcdl)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Hresult,
|
|
"CDownload::AddParent",
|
|
"this=%#x, %#x",
|
|
this, pcdl
|
|
));
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
CParentCDL *pParentCDL = new CParentCDL(pcdl);
|
|
|
|
if (pParentCDL)
|
|
m_ParentCDL.AddTail(pParentCDL);
|
|
else
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
if (m_bCompleteSignalled) {
|
|
pParentCDL->m_bCompleteSignalled = TRUE;
|
|
pcdl->CompleteOne(this ,m_hrOSB, m_hrStatus, m_hrResponseHdr, NULL);
|
|
} else {
|
|
|
|
hr = FAILED(m_hrOSB)?m_hrOSB:(FAILED(m_hrStatus)?m_hrStatus:(FAILED(m_hrResponseHdr)?m_hrResponseHdr:S_OK));
|
|
|
|
}
|
|
}
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CDownload::IsSignalled(CCodeDownload *pcdl)
|
|
// ---------------------------------------------------------------------------
|
|
BOOL
|
|
CDownload::IsSignalled(CCodeDownload *pcdl)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Bool,
|
|
"CDownload::IsSignalled",
|
|
"this=%#x, %#x",
|
|
this, pcdl
|
|
));
|
|
|
|
CParentCDL *pParentCDL = NULL;
|
|
BOOL bRet = FALSE;
|
|
LISTPOSITION pos = 0;
|
|
DLSTATE dls;
|
|
int iNum = 0;
|
|
int i;
|
|
|
|
dls = GetDLState();
|
|
if (dls == DLSTATE_DONE || dls == DLSTATE_READY_TO_SETUP) {
|
|
bRet = TRUE;
|
|
goto Exit;
|
|
}
|
|
|
|
iNum = m_ParentCDL.GetCount();
|
|
Assert(iNum);
|
|
pos = m_ParentCDL.GetHeadPosition();
|
|
|
|
for (i=0; i < iNum; i++) {
|
|
pParentCDL = m_ParentCDL.GetNext(pos); // pass ref!
|
|
if (pParentCDL->m_pcdl == pcdl && pParentCDL->m_bCompleteSignalled) {
|
|
bRet = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
DEBUG_LEAVE(bRet);
|
|
return bRet;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CDownload::Abort(CCodeDownload *pcdl)
|
|
// ---------------------------------------------------------------------------
|
|
HRESULT
|
|
CDownload::Abort(CCodeDownload *pcdl)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Hresult,
|
|
"CDownload::Abort",
|
|
"this=%#x, %#x",
|
|
this, pcdl
|
|
));
|
|
|
|
int i;
|
|
CParentCDL *pThisParentCDL = NULL;
|
|
BOOL bDelinkParent = FALSE;
|
|
BOOL fWaitForAbortCompletion = FALSE;
|
|
HRESULT hr = S_OK;
|
|
|
|
int iNum = m_ParentCDL.GetCount();
|
|
Assert(iNum);
|
|
LISTPOSITION pos = m_ParentCDL.GetHeadPosition();
|
|
|
|
for (i=0; i < iNum; i++) {
|
|
CParentCDL *pParentCDL = m_ParentCDL.GetNext(pos); // pass ref!
|
|
|
|
if (pParentCDL->m_pcdl == pcdl)
|
|
pThisParentCDL = pParentCDL;
|
|
else if ( !pParentCDL->m_bCompleteSignalled )
|
|
bDelinkParent = TRUE;
|
|
}
|
|
|
|
Assert(pThisParentCDL);
|
|
|
|
if (!pThisParentCDL)
|
|
{
|
|
DEBUG_LEAVE(E_FAIL);
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (bDelinkParent) {
|
|
|
|
// multiple code downloads interested in this
|
|
// delink this parent, by marking as complete signalled
|
|
|
|
pThisParentCDL->m_bCompleteSignalled = TRUE;
|
|
|
|
DEBUG_LEAVE(S_OK);
|
|
return S_OK;
|
|
}
|
|
|
|
switch ( GetDLState()) {
|
|
|
|
case DLSTATE_BINDING:
|
|
|
|
GetBSC()->GetBinding()->Abort();
|
|
|
|
break;
|
|
|
|
case DLSTATE_ABORT:
|
|
|
|
// have aborted this but the OSB has not been recieved yet
|
|
// so wait for that to come to us before we complteall
|
|
// or post the setup packet to completeall
|
|
|
|
fWaitForAbortCompletion = TRUE;
|
|
break;
|
|
|
|
case DLSTATE_DONE:
|
|
case DLSTATE_READY_TO_SETUP:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// packet processing pending for this state. we will check for
|
|
// DLSTATE_ABORT in each packet processing state and if true
|
|
// it will call CompleteOne(us), which marks each piece DLSTATE_DONE
|
|
|
|
SetDLState(DLSTATE_ABORT);
|
|
fWaitForAbortCompletion = TRUE;
|
|
|
|
}
|
|
|
|
if (fWaitForAbortCompletion) {
|
|
|
|
hr = S_FALSE;
|
|
}
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CDownload::ReleaseParent(CCodeDownload *pcdl)
|
|
// ---------------------------------------------------------------------------
|
|
HRESULT
|
|
CDownload::ReleaseParent(CCodeDownload *pcdl)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Hresult,
|
|
"CDownload::ReleaseParent",
|
|
"this=%#x, %#x",
|
|
this, pcdl
|
|
));
|
|
|
|
int iNum = m_ParentCDL.GetCount();
|
|
|
|
Assert(iNum);
|
|
LISTPOSITION pos = m_ParentCDL.GetHeadPosition();
|
|
|
|
for (int i=0; i < iNum; i++) {
|
|
CParentCDL *pParentCDL = m_ParentCDL.GetNext(pos); // pass ref!
|
|
|
|
if (pParentCDL->m_pcdl == pcdl) {
|
|
|
|
// found the item
|
|
// getnext would have stepped past the position
|
|
pos = m_ParentCDL.Find(pParentCDL);
|
|
m_ParentCDL.RemoveAt(pos);
|
|
iNum = m_ParentCDL.GetCount();
|
|
if (iNum == 0) {
|
|
|
|
CleanupFiles();
|
|
|
|
delete this;
|
|
}
|
|
|
|
DEBUG_LEAVE(S_OK);
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
// not found in list
|
|
Assert(TRUE);
|
|
|
|
DEBUG_LEAVE(E_FAIL);
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// HRESULT CDownload::IsDownloadedVersionRequired()
|
|
// returns S_OK if downloaded version is required
|
|
// error if local version is OK and new verison is not required
|
|
// ---------------------------------------------------------------------------
|
|
HRESULT CDownload::IsDownloadedVersionRequired()
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Hresult,
|
|
"CDownload::IsDownloadedVersionRequired",
|
|
"this=%#x",
|
|
this
|
|
));
|
|
|
|
HRESULT hr = S_OK;
|
|
char szFullURL[INTERNET_MAX_URL_LENGTH];
|
|
DWORD dwLen = INTERNET_MAX_URL_LENGTH;
|
|
FILETIME *pftLastMod = GetCodeDownload()->GetLastModifiedTime();
|
|
HANDLE hf = INVALID_HANDLE_VALUE;
|
|
|
|
if (!GetCodeDownload()->LocalVersionPresent()) {
|
|
// if no prev version always download
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
} else {
|
|
// if prev version exists, but we are not doing Get Latest
|
|
// then accept the download.
|
|
if (!GetCodeDownload()->NeedLatestVersion())
|
|
{
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
if (GetMoniker() != GetCodeDownload()->GetContextMoniker()){
|
|
// if we are not the context (or the main moniker then
|
|
// -1 does not apply (to secondary CABs)
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|
|
dwLen = WideCharToMultiByte(CP_ACP, 0, GetURL(), -1,
|
|
szFullURL, INTERNET_MAX_URL_LENGTH, NULL, NULL);
|
|
|
|
Assert(dwLen);
|
|
|
|
if (!dwLen) {
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
goto Exit;
|
|
}
|
|
|
|
if (StrCmpNI(szFullURL, "file:", 5) == 0) {
|
|
|
|
WIN32_FIND_DATA fd;
|
|
|
|
hf = FindFirstFile(GetFileName(), &fd);
|
|
|
|
if (hf == INVALID_HANDLE_VALUE) {
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
goto Exit;
|
|
}
|
|
|
|
// BUGBUG: Defend against Bug#40696 - Vatsan should check to see if this is the _right_ defense.
|
|
if ( pftLastMod != NULL &&
|
|
CompareFileTime(pftLastMod, &(fd.ftLastWriteTime)) >= 0) {
|
|
|
|
// if the file needs no upgrade then fail!
|
|
// if we succeed then an update will take place.
|
|
hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
Exit:
|
|
|
|
if ( hf != INVALID_HANDLE_VALUE)
|
|
FindClose(hf);
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CDownload::GetFriendlyName
|
|
// ---------------------------------------------------------------------------
|
|
HRESULT CDownload::GetFriendlyName(LPSTR szUrlPath, LPSTR *ppBaseFileName)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Hresult,
|
|
"CDownload::GetFriendlyName",
|
|
"this=%#x, %.80q, %#x",
|
|
this, szUrlPath, ppBaseFileName
|
|
));
|
|
|
|
HRESULT hr = S_OK;
|
|
char szFullURL[INTERNET_MAX_URL_LENGTH];
|
|
DWORD dwLen = INTERNET_MAX_URL_LENGTH;
|
|
URL_COMPONENTS UrlComponents;
|
|
char *pBaseFileName = NULL;
|
|
|
|
dwLen = WideCharToMultiByte(CP_ACP, 0, GetURL(), -1,
|
|
szFullURL, INTERNET_MAX_URL_LENGTH, NULL, NULL);
|
|
|
|
|
|
memset(&UrlComponents, 0, sizeof(URL_COMPONENTS));
|
|
UrlComponents.dwStructSize = sizeof(URL_COMPONENTS);
|
|
|
|
UrlComponents.lpszUrlPath = szUrlPath;
|
|
UrlComponents.dwUrlPathLength = INTERNET_MAX_URL_LENGTH;
|
|
|
|
if (!InternetCrackUrl( szFullURL, 0,
|
|
ICU_DECODE, &UrlComponents)) {
|
|
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
goto Exit;
|
|
}
|
|
|
|
Assert(UrlComponents.lpszUrlPath);
|
|
Assert(UrlComponents.dwUrlPathLength);
|
|
|
|
if ( !UrlComponents.dwUrlPathLength ||
|
|
!UrlComponents.lpszUrlPath ) {
|
|
|
|
hr = E_UNEXPECTED;
|
|
goto Exit;
|
|
}
|
|
|
|
if (ppBaseFileName)
|
|
GetExtnAndBaseFileName(szUrlPath, ppBaseFileName);
|
|
|
|
Exit:
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CDownload::SniffType
|
|
// ---------------------------------------------------------------------------
|
|
HRESULT CDownload::SniffType()
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Hresult,
|
|
"CDownload::SniffType",
|
|
"this=%#x",
|
|
this
|
|
));
|
|
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
HRESULT hr = S_OK;
|
|
DWORD dwSignature;
|
|
DWORD dwBytesRead = 0;
|
|
|
|
#define CAB_SIG 0x4643534d
|
|
|
|
if (GetExtn() != FILEXTN_CAB) {
|
|
|
|
|
|
if ( (hFile = CreateFile(GetFileName(), GENERIC_READ, FILE_SHARE_READ,
|
|
NULL, OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL, 0)) == INVALID_HANDLE_VALUE) {
|
|
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
goto Exit;
|
|
}
|
|
|
|
if ((ReadFile(hFile, &dwSignature, sizeof(DWORD), &dwBytesRead, NULL))
|
|
&& (dwSignature == CAB_SIG)) {
|
|
|
|
SetURLAndExtn(NULL, FILEXTN_CAB);
|
|
} else {
|
|
|
|
// here if its not a CAB
|
|
// check if of compatible type
|
|
|
|
hr = IsCompatibleFile(GetFileName());
|
|
}
|
|
|
|
}
|
|
|
|
Exit:
|
|
|
|
if (hFile != INVALID_HANDLE_VALUE)
|
|
CloseHandle(hFile);
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CDownload::VerifyTrust
|
|
// ---------------------------------------------------------------------------
|
|
VOID CDownload::VerifyTrust()
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
None,
|
|
"CDownload::VerifyTrust",
|
|
"this=%#x",
|
|
this
|
|
));
|
|
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
HRESULT hr = S_OK;
|
|
HWND hWnd = GetCodeDownload()->GetClientBinding()->GetHWND();
|
|
WCHAR szDisplayUrl[INTERNET_MAX_URL_LENGTH];
|
|
DWORD cchDisplayUrl = INTERNET_MAX_URL_LENGTH;
|
|
LPSTR szCatalogFile = NULL;
|
|
|
|
CUrlMkTls tls(hr); // hr passed by reference!
|
|
if (FAILED(hr)) // if tls ctor failed above
|
|
goto Exit;
|
|
|
|
if ( GetDLState() == DLSTATE_ABORT) {
|
|
hr = E_ABORT;
|
|
goto Exit;
|
|
}
|
|
|
|
// sniff file for detecting CAB extensions
|
|
// and if not CAB, assume PE and check if of compatible type
|
|
// before calling trust on it. The reason we presniff for
|
|
// compat is because it will make for better user experience to
|
|
// fail if not of correct binary before we present trust dialogs
|
|
|
|
hr = SniffType();
|
|
|
|
if (FAILED(hr))
|
|
goto Exit;
|
|
|
|
Assert(tls->pTrustCookie);
|
|
|
|
// need to serialize all trust verification on this thread
|
|
// grab the trust cookie
|
|
|
|
hr = tls->pTrustCookie->Acquire(this);
|
|
if (hr != S_OK) {
|
|
|
|
Assert(!tls->pTrustCookie->IsFree());
|
|
Assert(!tls->pTrustCookie->IsOwner(this));
|
|
|
|
DEBUG_LEAVE(0);
|
|
return; // wait till we get posted a message when the current owner
|
|
// relinquishes the cookie
|
|
}
|
|
|
|
// have the cookie
|
|
Assert(tls->pTrustCookie->IsOwner(this));
|
|
|
|
if ( (hFile = CreateFile(GetFileName(), GENERIC_READ, FILE_SHARE_READ,
|
|
NULL, OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL, 0)) == INVALID_HANDLE_VALUE) {
|
|
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
goto Exit;
|
|
}
|
|
|
|
// form friendly displayable URL (ie. decode) in browser mode
|
|
hr = UrlUnescapeW((LPWSTR)GetURL(), szDisplayUrl, &cchDisplayUrl, 0);
|
|
|
|
Assert(!GetCodeDownload()->IsSilentMode() || hWnd == INVALID_HANDLE_VALUE);
|
|
|
|
// Try to get a catalog file
|
|
szCatalogFile = GetCodeDownload()->GetCatalogFile();
|
|
|
|
hr = m_wvt.VerifyTrust(hFile, hWnd, &m_pbJavaTrust, szDisplayUrl,
|
|
GetCodeDownload()->GetClientBinding()->GetHostSecurityManager(),
|
|
(char *)GetFileName(), szCatalogFile, this);
|
|
|
|
if(SUCCEEDED(hr)) {
|
|
|
|
SetTrustVerified();
|
|
|
|
} else {
|
|
|
|
// trust failed on this file. Delete it from the cache for
|
|
// added safety.
|
|
|
|
// remove entry from cache only if we're not in silent mode.
|
|
// or we are in silent mode and the hr != TRUST_E_SUBJECT_NOT_TRUSTED
|
|
// when ui choice is NONE, WVT reurns the special error code to
|
|
// mean that all was OK but could not trust because we did not
|
|
// allow them to put up confirmation UI.
|
|
|
|
if (!GetCodeDownload()->IsSilentMode())
|
|
{
|
|
CHAR szURL[INTERNET_MAX_URL_LENGTH];
|
|
DWORD cchURL = INTERNET_MAX_URL_LENGTH;
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, GetURL(), -1, szURL,
|
|
INTERNET_MAX_URL_LENGTH, 0,0);
|
|
|
|
// If we still have the file open when we call DeleteUrlCacheEntry, then
|
|
// WinInet won't be able to delete it. Having untrusted bits in the cache
|
|
// is dangerous.
|
|
if ( hFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
CloseHandle(hFile);
|
|
hFile = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
DeleteUrlCacheEntryA(szURL);
|
|
}
|
|
else
|
|
GetCodeDownload()->SetTrustSomeFailed();
|
|
}
|
|
|
|
Exit:
|
|
|
|
// reset status to resume the rest of download if we're in
|
|
// silent mode
|
|
if (GetCodeDownload()->IsSilentMode() && FAILED(hr) && (hr != E_ABORT))
|
|
hr = S_OK;
|
|
|
|
if (tls->pTrustCookie->IsOwner(this)) {
|
|
tls->pTrustCookie->Relinquish(this);
|
|
}
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
CCDLPacket *pPkt= new CCDLPacket(CODE_DOWNLOAD_PROCESS_PIECE, this, 0);
|
|
|
|
if (pPkt) {
|
|
hr = pPkt->Post();
|
|
} else {
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
}
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
// does all the master state analysis
|
|
CompleteSignal(hr, S_OK, S_OK, NULL);
|
|
}
|
|
|
|
if ( hFile != INVALID_HANDLE_VALUE)
|
|
CloseHandle(hFile);
|
|
|
|
DEBUG_LEAVE(0);
|
|
return;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CDownload::SetCdlProtocol
|
|
// ---------------------------------------------------------------------------
|
|
HRESULT
|
|
CDownload::SetUsingCdlProtocol(LPWSTR wszDistUnit)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Hresult,
|
|
"CDownload::SetUsingCdlProtocol",
|
|
"this=%#x, %.80wq",
|
|
this, wszDistUnit
|
|
));
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
m_wszDistUnit = new WCHAR [lstrlenW(wszDistUnit) + 1];
|
|
|
|
if (m_wszDistUnit)
|
|
StrCpyW(m_wszDistUnit, wszDistUnit);
|
|
else
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
m_flags |= DL_FLAGS_CDL_PROTOCOL;
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CDownload::ExtractManifest()
|
|
// ---------------------------------------------------------------------------
|
|
HRESULT
|
|
CDownload::ExtractManifest(FILEXTN extn, LPSTR szFileName, LPSTR& pBaseFileName)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Hresult,
|
|
"CDownload::ExtractManifest",
|
|
"this=%#x, %#x, %.80q, %#x",
|
|
this, extn, szFileName, &pBaseFileName
|
|
));
|
|
|
|
CCodeDownload *pcdl = GetCodeDownload();
|
|
char * pFileName;
|
|
PSESSION psess = NULL;
|
|
PFNAME pf = NULL;
|
|
HRESULT hr = S_FALSE; // assume not found
|
|
|
|
Assert(m_psess);
|
|
|
|
for (pf = m_psess->pFileList; pf != NULL; pf = pf->pNextName) {
|
|
|
|
FILEXTN curextn = ::GetExtnAndBaseFileName(pf->pszFilename,
|
|
&pBaseFileName);
|
|
|
|
if (( curextn == extn) &&
|
|
((szFileName[0] == '\0') ||
|
|
(lstrcmpi(szFileName, pBaseFileName) == 0))) {
|
|
|
|
FNAME fne;
|
|
memset(&fne, 0, sizeof(FNAME));
|
|
fne.pszFilename = pf->pszFilename;
|
|
|
|
// INF present in CAB, extract it and process it
|
|
m_psess->pFilesToExtract = &fne;
|
|
m_psess->flags &= ~SESSION_FLAG_ENUMERATE; // already enumerated
|
|
|
|
if (FAILED((hr=ExtractFromCabinet(m_psess, GetFileName()))))
|
|
goto Exit;
|
|
|
|
// side effect!
|
|
// if extract succeeds we also have set the return hr to S_OK.
|
|
// hr = S_OK;
|
|
|
|
m_psess->pFilesToExtract = NULL;
|
|
|
|
if (!catDirAndFile(szFileName, MAX_PATH, m_psess->achLocation,
|
|
pf->pszFilename)) {
|
|
hr = E_UNEXPECTED;
|
|
}
|
|
|
|
goto Exit;
|
|
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CDownload::ProcessPiece
|
|
// CBSC::OnStopBinding calls us as soon as a piece gets downloaded
|
|
// and trust is verified.
|
|
// ie. this CDownload obj has completed binding
|
|
// Depending on the Content type we will process further
|
|
// This triggers a change state in our state machine. Depending on the
|
|
// obj we have downloaded (a CAB or INF or DLL/OCX/EXE) we:
|
|
//
|
|
// OCX:
|
|
// Csetup for this download is usually previously created
|
|
// mark this download as done and
|
|
// call into main CodeDownload::CompleteOne (state analyser)
|
|
//
|
|
// CAB:
|
|
// if we don't have an INF already we look for one in the CAB
|
|
// if INF in CAB
|
|
// process INF (may trigger further extractions/downloads/Csetup)
|
|
// else
|
|
// look for primary OCX in CAB and create CSetup or it.
|
|
//
|
|
// INF:
|
|
// Process INF
|
|
//
|
|
// ---------------------------------------------------------------------------
|
|
VOID
|
|
CDownload::ProcessPiece()
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
None,
|
|
"CDownload::ProcessPiece",
|
|
"this=%#x",
|
|
this
|
|
));
|
|
|
|
CCodeDownload *pcdl = GetCodeDownload();
|
|
char * pFileName;
|
|
char *pBaseFileName;
|
|
PSESSION psess = NULL;
|
|
PFNAME pf = NULL;
|
|
HRESULT hr = S_OK; // assume all OK
|
|
CSetup *pSetup;
|
|
char szBuf[INTERNET_MAX_URL_LENGTH];
|
|
char szCatalogBuf[INTERNET_MAX_URL_LENGTH];
|
|
FILEXTN extn = m_extn;
|
|
|
|
if ( GetDLState() == DLSTATE_ABORT) {
|
|
hr = E_ABORT;
|
|
goto Exit;
|
|
}
|
|
|
|
//REVIEW: Virus scanning a CAB or INF file may not be a bright thing to do since
|
|
// they are not executable.
|
|
|
|
if (FAILED(hr = PerformVirusScan((char *)GetFileName()))) {
|
|
goto Exit;
|
|
}
|
|
|
|
switch (extn) {
|
|
|
|
case FILEXTN_EXE:
|
|
case FILEXTN_OCX:
|
|
case FILEXTN_DLL:
|
|
case FILEXTN_NONE:
|
|
case FILEXTN_UNKNOWN:
|
|
|
|
pSetup = GetSetupHead();
|
|
|
|
if (pSetup) {
|
|
// If a CSetup exists for this m_pdl then initialize its
|
|
// m_pSrcFileName using the m_pFileName
|
|
|
|
Assert(pSetup->GetNext() == NULL);
|
|
|
|
pSetup->SetSrcFileName(GetFileName());
|
|
|
|
} else {
|
|
|
|
if (!HasAllActiveXPermissions()) {
|
|
|
|
if (GetCodeDownload()->IsSilentMode())
|
|
{
|
|
GetCodeDownload()->SetBitsInCache();
|
|
}
|
|
|
|
hr = TRUST_E_FAIL;
|
|
goto Exit;
|
|
}
|
|
|
|
// If no CSetup exists then make one and attach it to the m_pdl
|
|
// initiated at top level
|
|
|
|
hr = GetFriendlyName(szBuf, &pBaseFileName);
|
|
if (pBaseFileName[0] == '\0') {
|
|
hr = E_UNEXPECTED; // No filename to setup!
|
|
goto Exit;
|
|
}
|
|
|
|
if (FAILED(hr)) {
|
|
goto Exit;
|
|
}
|
|
|
|
pSetup = new CSetup(GetFileName(), pBaseFileName, extn,
|
|
pcdl->GetDestDirHint(), &hr);
|
|
|
|
if (!pSetup) {
|
|
hr = E_OUTOFMEMORY;
|
|
goto Exit;
|
|
} else if (FAILED(hr)) {
|
|
delete pSetup;
|
|
goto Exit;
|
|
}
|
|
|
|
AddSetupToList(pSetup);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case FILEXTN_CAB:
|
|
// if CAB then make SESSION for this CDownload
|
|
Assert(!(GetSession()));
|
|
|
|
psess = new SESSION;
|
|
if (!psess) {
|
|
hr = E_OUTOFMEMORY;
|
|
goto Exit;
|
|
}
|
|
|
|
SetSession(psess);
|
|
|
|
// Initialize the structure
|
|
psess->pFileList = NULL;
|
|
psess->cFiles = 0;
|
|
psess->cbCabSize = 0;
|
|
psess->flags = SESSION_FLAG_ENUMERATE;
|
|
|
|
// extract files in a CAB into a unique dir so that
|
|
// parallel downloads of CABs containing same name
|
|
// components can go on without conflict.
|
|
// By serailizing the setup phase we make sure the right
|
|
// latest version is finally left on client machine.
|
|
|
|
hr = MakeUniqueTempDirectory(g_szOCXTempDir, psess->achLocation, sizeof(psess->achLocation));
|
|
|
|
if (FAILED(hr)) {
|
|
goto Exit;
|
|
}
|
|
|
|
psess->pFilesToExtract = NULL; // just enumerate first
|
|
|
|
if (!pcdl->HaveManifest() || NeedToExtractAllFiles()) {
|
|
psess->flags |= SESSION_FLAG_EXTRACT_ALL;
|
|
}
|
|
|
|
// enumerate the files of the CAB
|
|
if (FAILED((hr = ExtractFromCabinet(psess, GetFileName()))))
|
|
goto Exit;
|
|
|
|
if (!pcdl->HaveManifest() || NeedToExtractAllFiles()) {
|
|
psess->flags |= SESSION_FLAG_EXTRACTED_ALL;
|
|
}
|
|
|
|
// if we don't have INF already look for one
|
|
if (!pcdl->HaveManifest()) {
|
|
|
|
// Extract catalog file
|
|
szCatalogBuf[0] = '\0';
|
|
if (ExtractManifest(FILEXTN_CAT, szCatalogBuf, pBaseFileName) == S_OK) {
|
|
if (FAILED(pcdl->SetCatalogFile(szCatalogBuf))) {
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
szBuf[0] = '\0';
|
|
hr = ExtractManifest(FILEXTN_OSD , szBuf, pBaseFileName);
|
|
if (FAILED(hr))
|
|
goto Exit;
|
|
|
|
if (hr == S_FALSE) {
|
|
szBuf[0] = '\0';
|
|
|
|
// if no dist unit profile, process old INF
|
|
hr = ExtractManifest(FILEXTN_INF , szBuf, pBaseFileName);
|
|
|
|
if (FAILED(hr))
|
|
goto Exit;
|
|
|
|
if (hr == S_OK) {
|
|
hr=pcdl->SetupInf(szBuf, pBaseFileName, this);
|
|
goto Exit;
|
|
}
|
|
|
|
} else {
|
|
// process dist unit profile
|
|
|
|
hr=pcdl->ParseOSD(szBuf, pBaseFileName, this);
|
|
goto Exit;
|
|
}
|
|
|
|
if (!pcdl->HaveManifest()) { // still don't have an INF?
|
|
|
|
|
|
if (!HasAllActiveXPermissions()) {
|
|
|
|
if (GetCodeDownload()->IsSilentMode())
|
|
{
|
|
GetCodeDownload()->SetBitsInCache();
|
|
}
|
|
|
|
hr = TRUST_E_FAIL;
|
|
goto Exit;
|
|
}
|
|
|
|
// only valid case at this point is
|
|
// case where we have a CAB file with ONE file in it
|
|
if (psess->cFiles != 1) {
|
|
hr = E_INVALIDARG;
|
|
goto Exit;
|
|
}
|
|
|
|
pf = psess->pFilesToExtract = psess->pFileList;
|
|
psess->flags &= ~SESSION_FLAG_ENUMERATE; // already enumerated
|
|
|
|
if (FAILED((hr=ExtractFromCabinet(psess, GetFileName()))))
|
|
goto Exit;
|
|
|
|
|
|
extn = GetExtnAndBaseFileName(pf->pszFilename, &pBaseFileName);
|
|
|
|
if (!catDirAndFile(szBuf, MAX_PATH, psess->achLocation,
|
|
pf->pszFilename)) {
|
|
hr = E_UNEXPECTED;
|
|
goto Exit;
|
|
}
|
|
|
|
psess->pFilesToExtract = NULL;
|
|
|
|
pSetup = new CSetup(szBuf, pBaseFileName, extn,
|
|
pcdl->GetDestDirHint(), &hr);
|
|
if (!pSetup) {
|
|
hr = E_OUTOFMEMORY;
|
|
goto Exit;
|
|
} else if (FAILED(hr)) {
|
|
delete pSetup;
|
|
goto Exit;
|
|
}
|
|
|
|
AddSetupToList(pSetup);
|
|
|
|
}
|
|
|
|
} else { /* have inf */
|
|
|
|
// INF processor would have made Csetup already
|
|
|
|
psess->pFilesToExtract = GetFilesToExtract();
|
|
|
|
if (!psess->pFilesToExtract) {
|
|
// no files to extract, means there was only a hook
|
|
// in this CAB and no other particular files
|
|
// the general code downloader is looking for
|
|
// so no setup work either.
|
|
|
|
Assert(NeedToExtractAllFiles());
|
|
|
|
break;
|
|
}
|
|
|
|
psess->flags &= ~SESSION_FLAG_ENUMERATE; // already enumerated
|
|
|
|
CSetup *pSetupCur = m_pSetuphead;
|
|
Assert(m_pSetuphead);
|
|
|
|
// set fully qual names for all of these
|
|
for (; pSetupCur; pSetupCur = pSetupCur->GetNext()) {
|
|
|
|
if (!catDirAndFile(szBuf, MAX_PATH, m_psess->achLocation,
|
|
(LPSTR)pSetupCur->GetSrcFileName())) {
|
|
|
|
hr = E_UNEXPECTED;
|
|
goto Exit;
|
|
}
|
|
|
|
pSetupCur->SetSrcFileName(szBuf);
|
|
}
|
|
|
|
if (FAILED((hr=ExtractFromCabinet(psess, GetFileName()))))
|
|
goto Exit;
|
|
}
|
|
|
|
break;
|
|
|
|
case FILEXTN_INF:
|
|
|
|
if(pcdl->HaveManifest()) {
|
|
hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
|
|
goto Exit;
|
|
}
|
|
|
|
hr = GetFriendlyName(szBuf, &pBaseFileName);
|
|
|
|
if (FAILED(hr)) {
|
|
goto Exit;
|
|
}
|
|
|
|
// get friendly name for INF from URL
|
|
hr=pcdl->SetupInf(GetFileName(), pBaseFileName, this);
|
|
|
|
if (FAILED(hr)) {
|
|
SetDLState(DLSTATE_DONE);
|
|
}
|
|
|
|
goto Exit;
|
|
|
|
case FILEXTN_OSD:
|
|
|
|
if(pcdl->HaveManifest()) {
|
|
hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
|
|
goto Exit;
|
|
}
|
|
|
|
hr = GetFriendlyName(szBuf, &pBaseFileName);
|
|
|
|
if (FAILED(hr)) {
|
|
goto Exit;
|
|
}
|
|
|
|
// get friendly name for OSD from URL
|
|
hr=pcdl->ParseOSD(GetFileName(), pBaseFileName, this);
|
|
goto Exit;
|
|
|
|
} /* end switch (extn) */
|
|
|
|
// done with this CDownload. Mark it ready for setup
|
|
SetDLState(DLSTATE_READY_TO_SETUP);
|
|
|
|
Assert(SUCCEEDED(hr));
|
|
|
|
Exit:
|
|
|
|
if ( (FAILED(hr)) || (GetDLState() == DLSTATE_READY_TO_SETUP)) {
|
|
CompleteSignal(hr, S_OK, S_OK, NULL);
|
|
}
|
|
|
|
// if success setupInf would have dispatched a msg for
|
|
// INF processing and only when that completes this
|
|
// CDownload is deemed completed/ready_to_setup
|
|
|
|
DEBUG_LEAVE(0);
|
|
return;
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CDownload::SetURLAndExnt(LPCWSTR szURL, FILEXTN extn);
|
|
// ---------------------------------------------------------------------------
|
|
HRESULT
|
|
CDownload::SetURLAndExtn(LPCWSTR szURL, FILEXTN extn)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Hresult,
|
|
"CDownload::ProcessPiece",
|
|
"this=%#x, %.80wq, %#x",
|
|
this, szURL, extn
|
|
));
|
|
|
|
m_extn = extn;
|
|
|
|
if (!szURL)
|
|
{
|
|
DEBUG_LEAVE(S_OK);
|
|
return S_OK;
|
|
}
|
|
|
|
DWORD len = lstrlenW(szURL); // make private copy
|
|
LPWSTR lpch = new WCHAR [len + 1];
|
|
|
|
if (!lpch)
|
|
{
|
|
DEBUG_LEAVE(E_OUTOFMEMORY);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
StrCpyW(lpch, szURL);
|
|
|
|
if (m_url)
|
|
SAFEDELETE(m_url);
|
|
|
|
m_url = lpch;
|
|
|
|
DEBUG_LEAVE(S_OK);
|
|
return S_OK;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CDownload::CheckForNameCollision(LPCSTR szCacheDir);
|
|
// for each in list CSetup::CheckForNameCollision
|
|
// ---------------------------------------------------------------------------
|
|
HRESULT
|
|
CDownload::CheckForNameCollision(LPCSTR szCacheDir)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Hresult,
|
|
"CDownload::CheckForNameCollision",
|
|
"this=%#x, %.80q",
|
|
this, szCacheDir
|
|
));
|
|
|
|
CSetup *pSetupCur = m_pSetuphead;
|
|
HRESULT hr = S_OK;
|
|
|
|
for (pSetupCur = m_pSetuphead; pSetupCur; pSetupCur =pSetupCur->GetNext()) {
|
|
if ((hr=pSetupCur->CheckForNameCollision(GetCodeDownload(), szCacheDir)) == S_FALSE)
|
|
break;
|
|
}
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CDownload::FindJavaSetup
|
|
// ---------------------------------------------------------------------------
|
|
CJavaSetup*
|
|
CDownload::FindJavaSetup(LPCWSTR szPackageName)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Pointer,
|
|
"CDownload::FindJavaSetup",
|
|
"this=%#x, %.80wq",
|
|
this, szPackageName
|
|
));
|
|
|
|
HRESULT hr = S_OK;
|
|
CJavaSetup *pjs = NULL;
|
|
|
|
if (!szPackageName)
|
|
{
|
|
DEBUG_LEAVE(NULL);
|
|
return NULL;
|
|
}
|
|
|
|
int iNumJavaSetup = m_JavaSetupList.GetCount();
|
|
LISTPOSITION curpos = m_JavaSetupList.GetHeadPosition();
|
|
for (int i=0; i < iNumJavaSetup; i++) {
|
|
|
|
pjs = m_JavaSetupList.GetNext(curpos);
|
|
|
|
if (pjs->GetPackageName() && (StrCmpIW(szPackageName, pjs->GetPackageName()) == 0)) {
|
|
|
|
DEBUG_LEAVE(pjs);
|
|
return pjs;
|
|
}
|
|
}
|
|
|
|
DEBUG_LEAVE(NULL);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CDownload::FindHook
|
|
// ---------------------------------------------------------------------------
|
|
CSetupHook*
|
|
CDownload::FindHook(LPCSTR szHook)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Pointer,
|
|
"CDownload::FindHook",
|
|
"this=%#x, %.80q",
|
|
this, szHook
|
|
));
|
|
|
|
HRESULT hr = S_OK;
|
|
CSetupHook *psh = NULL;
|
|
|
|
if (!szHook)
|
|
{
|
|
DEBUG_LEAVE(NULL);
|
|
return NULL;
|
|
}
|
|
|
|
int iNumHooks = m_SetupHooks.GetCount();
|
|
LISTPOSITION curpos = m_SetupHooks.GetHeadPosition();
|
|
for (int i=0; i < iNumHooks; i++) {
|
|
|
|
psh = m_SetupHooks.GetNext(curpos);
|
|
|
|
if (psh->GetHookName() && (lstrcmpi(szHook, psh->GetHookName()) == 0)) {
|
|
|
|
DEBUG_LEAVE(psh);
|
|
return psh;
|
|
}
|
|
}
|
|
|
|
DEBUG_LEAVE(NULL);
|
|
return NULL;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CDownload::DoSetup
|
|
// ---------------------------------------------------------------------------
|
|
HRESULT
|
|
CDownload::DoSetup()
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Hresult,
|
|
"CDownload::DoSetup",
|
|
"this=%#x",
|
|
this
|
|
));
|
|
|
|
CSetup *pSetupCur = m_pSetuphead;
|
|
HRESULT hr = S_OK;
|
|
int nSetupsPerCall = 0;
|
|
int iNumHooks,i;
|
|
POSITION curpos;
|
|
|
|
SetDLState(DLSTATE_SETUP);
|
|
|
|
// SILENT MODE
|
|
// determine if we're in silent mode
|
|
if (GetCodeDownload()->IsSilentMode() && !GetCodeDownload()->IsAllTrusted())
|
|
{
|
|
SetDLState(DLSTATE_DONE);
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|
|
if (m_JavaSetupList.GetCount() != 0) {
|
|
|
|
CJavaSetup *pjs = m_JavaSetupList.GetHead();
|
|
curpos = m_JavaSetupList.GetHeadPosition();
|
|
BOOL bInstallReqd = FALSE;
|
|
|
|
if (pjs != NULL) {
|
|
|
|
for (int i=0; i< m_JavaSetupList.GetCount(); i++) {
|
|
|
|
CJavaSetup *pjs = m_JavaSetupList.GetNext(curpos);
|
|
Assert(pjs != NULL);
|
|
|
|
if (pjs->GetState() != INSTALL_DONE) {
|
|
bInstallReqd = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
if (bInstallReqd) {
|
|
Assert(HasJavaPermissions());
|
|
// the below check is our final security test
|
|
// we should never need to test this in retail
|
|
// but, we do anyway
|
|
if (HasJavaPermissions())
|
|
hr = pjs->DoSetup();
|
|
else
|
|
hr = TRUST_E_FAIL;
|
|
|
|
if (FAILED(hr))
|
|
goto Exit;
|
|
else
|
|
{
|
|
DEBUG_LEAVE(S_OK);
|
|
return S_OK;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// done processing Java Setups
|
|
// process all hooks
|
|
iNumHooks = m_SetupHooks.GetCount();
|
|
curpos = m_SetupHooks.GetHeadPosition();
|
|
for (i=0; i < iNumHooks; i++) {
|
|
|
|
CSetupHook *psh = m_SetupHooks.GetNext(curpos);
|
|
|
|
if (psh->GetState() == INSTALL_DONE)
|
|
continue;
|
|
|
|
if (nSetupsPerCall++) {
|
|
// here if we have already done 1 hook and there's more to
|
|
// do in this CDownload
|
|
|
|
// we don't set DLState to DONE and just return
|
|
|
|
DEBUG_LEAVE(S_OK);
|
|
return S_OK;
|
|
}
|
|
|
|
Assert(HasAllActiveXPermissions());
|
|
// the below check is our final security test
|
|
// we should never need to test this in retail
|
|
// but, we do anyway
|
|
if (HasAllActiveXPermissions())
|
|
hr=psh->Run();
|
|
else
|
|
hr = TRUST_E_FAIL;
|
|
|
|
if (FAILED(hr))
|
|
goto Exit;
|
|
|
|
if (psh->GetState() != INSTALL_DONE) {
|
|
|
|
// more work left in this setup hook
|
|
// wait for next msg, don't mark ourselves done yet.
|
|
|
|
DEBUG_LEAVE(S_OK);
|
|
return S_OK;
|
|
}
|
|
|
|
}
|
|
|
|
// processed all Java Setups, hooks, now run setups
|
|
for (pSetupCur = m_pSetuphead; pSetupCur; pSetupCur = pSetupCur->GetNext()) {
|
|
|
|
if (pSetupCur->GetState() == INSTALL_DONE)
|
|
continue;
|
|
|
|
if (nSetupsPerCall++) {
|
|
// here if we have already done 1 setup and there's more to
|
|
// do in this CDownload
|
|
|
|
// we don't set DLState to DONE and just return
|
|
|
|
DEBUG_LEAVE(S_OK);
|
|
return S_OK;
|
|
}
|
|
|
|
if (m_bExactVersion) {
|
|
pSetupCur->SetExactVersion(TRUE);
|
|
}
|
|
|
|
if (pSetupCur->GetExtn() == FILEXTN_OSD) {
|
|
hr=pSetupCur->DoSetup(GetCodeDownload(), this);
|
|
} else {
|
|
|
|
Assert(HasAllActiveXPermissions());
|
|
// the below check is our final security test
|
|
// we should never need to test this in retail
|
|
// but, we do anyway
|
|
if (HasAllActiveXPermissions())
|
|
hr=pSetupCur->DoSetup(GetCodeDownload(), this);
|
|
else
|
|
hr = TRUST_E_FAIL;
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
break;
|
|
|
|
if (pSetupCur->GetState() != INSTALL_DONE) {
|
|
|
|
// more work left in this CSetup (pSetupCur)
|
|
// wait for next msg, don't mark ourselves done yet.
|
|
|
|
DEBUG_LEAVE(S_OK);
|
|
return S_OK;
|
|
}
|
|
|
|
} /* for each CSetup */
|
|
|
|
|
|
Exit:
|
|
SetDLState(DLSTATE_DONE);
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CDownload::AddJavaSetup
|
|
//
|
|
// create and add a new JavaSetup to the list of setup hooks in this cab
|
|
// ---------------------------------------------------------------------------
|
|
HRESULT
|
|
CDownload::AddJavaSetup(
|
|
LPCWSTR szPackageName,
|
|
LPCWSTR szNameSpace,
|
|
IXMLElement *pPackage,
|
|
DWORD dwVersionMS,
|
|
DWORD dwVersionLS,
|
|
DWORD flags)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Hresult,
|
|
"CDownload::AddJavaSetup",
|
|
"this=%#x, %.80wq, %.80wq, %#x, %#x, %#x, %#x",
|
|
this, szPackageName, szNameSpace, pPackage, dwVersionMS, dwVersionLS, flags
|
|
));
|
|
|
|
HRESULT hr = S_OK;
|
|
CJavaSetup *pJavaSetup = NULL;
|
|
|
|
if (GetCodeDownload()->IsDuplicateJavaSetup(szPackageName) == S_OK) {
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
// create a CJavaSetup OBJ and add it to the CDownload obj
|
|
pJavaSetup = new CJavaSetup(this, szPackageName, szNameSpace, pPackage, dwVersionMS, dwVersionLS, flags, &hr);
|
|
if(!pJavaSetup) {
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
if (FAILED(hr)) {
|
|
SAFEDELETE(pJavaSetup);
|
|
goto Exit;
|
|
}
|
|
|
|
m_JavaSetupList.AddTail(pJavaSetup);
|
|
|
|
Exit:
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CDownload::AddHook
|
|
//
|
|
// create and add a new hook to the list of setup hooks in this cab
|
|
// ---------------------------------------------------------------------------
|
|
HRESULT
|
|
CDownload::AddHook(
|
|
LPCSTR szHook,
|
|
LPCSTR szInf,
|
|
LPCSTR szInfSection,
|
|
DWORD flags)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Hresult,
|
|
"CDownload::AddHook",
|
|
"this=%#x, %.80wq, %.80wq, %.80wq, %#x",
|
|
this, szHook, szInf, szInfSection, flags
|
|
));
|
|
|
|
HRESULT hr = S_OK;
|
|
CSetupHook *psh;
|
|
|
|
Assert(m_state != DLSTATE_EXTRACTING);
|
|
|
|
|
|
if (GetCodeDownload()->IsDuplicateHook(szHook) == S_OK) {
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
if (m_extn == FILEXTN_CAB) { // if a CAB
|
|
|
|
if (m_state > DLSTATE_DOWNLOADED) {
|
|
|
|
// this CAB is ready, extract this code first
|
|
// BUGBUG: multi-threading issue: we are relying on
|
|
// not being re-enterant in our extraction
|
|
|
|
Assert(m_psess);
|
|
|
|
if (!m_psess) {
|
|
hr = E_UNEXPECTED;
|
|
goto Exit;
|
|
}
|
|
|
|
if (!(m_psess->flags & SESSION_FLAG_EXTRACTED_ALL)) {
|
|
|
|
m_psess->pFilesToExtract = NULL;
|
|
m_psess->flags &= ~SESSION_FLAG_ENUMERATE; // already enumerated
|
|
m_psess->flags |= SESSION_FLAG_EXTRACT_ALL;
|
|
|
|
if (FAILED((hr = ExtractFromCabinet(m_psess, m_pFileName)))) {
|
|
goto Exit;
|
|
}
|
|
|
|
m_psess->flags |= SESSION_FLAG_EXTRACTED_ALL;
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
// newly initiated download, mark CDownload as extract all.
|
|
SetNeedToExtractAll();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
psh = new CSetupHook(this, szHook, szInf, szInfSection, flags, &hr);
|
|
|
|
if (psh && SUCCEEDED(hr)) {
|
|
|
|
m_SetupHooks.AddTail(psh);
|
|
|
|
} else {
|
|
|
|
if (psh)
|
|
delete psh;
|
|
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
Exit:
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CDownload::AddSetupToExistingCAB
|
|
// if CAB is already downloaded
|
|
// extract file; create CSetup to install it (piggy back to pdl)
|
|
// else if some other CAB that has been set for download
|
|
// attach file to be extracted to pFilesToExtract
|
|
// attach a CSetup for this file
|
|
// else
|
|
// ---------------------------------------------------------------------------
|
|
HRESULT
|
|
CDownload::AddSetupToExistingCAB(char * lpCode, const char * szDestDir, DESTINATION_DIR dest, DWORD dwRegisterServer, DWORD dwCopyFlags)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Hresult,
|
|
"CDownload::AddSetupToExistingCAB",
|
|
"this=%#x, %.80q, %.80q, %#x, %#x, %#x",
|
|
this, lpCode, szDestDir, dest, dwRegisterServer, dwCopyFlags
|
|
));
|
|
|
|
char *pBaseFileName = lpCode;
|
|
FILEXTN extn;
|
|
HRESULT hr = NO_ERROR;
|
|
CSetup* pSetup = NULL;
|
|
char szBuf[MAX_PATH];
|
|
|
|
Assert(lpCode);
|
|
|
|
if (!lpCode) {
|
|
hr = E_INVALIDARG;
|
|
goto Exit;
|
|
}
|
|
|
|
if (IsDuplicateSetup(lpCode))
|
|
goto Exit;
|
|
|
|
// assumes that both CAB extraction and download
|
|
// are into same temp dir
|
|
// make a name for extraction ie: tempdir\curcode
|
|
|
|
extn = GetExtnAndBaseFileName( lpCode, &pBaseFileName);
|
|
|
|
// this check is totally legit : ie no race condition here
|
|
// we are on the main wininet thread and all onstopbindgs get
|
|
// posted on this thread. So a newly initialted download could not
|
|
// have completed, and even if so CAB extraction could not have started
|
|
|
|
Assert(m_state != DLSTATE_EXTRACTING);
|
|
Assert(m_state != DLSTATE_SETUP);
|
|
Assert(m_state != DLSTATE_DONE);
|
|
|
|
if (m_state > DLSTATE_DOWNLOADED) {
|
|
|
|
// part of CAB that the INF is in,
|
|
// or part of a CAB of some other code download that matches our spec.
|
|
// extract this code first
|
|
|
|
Assert(m_psess);
|
|
|
|
if (!m_psess) {
|
|
hr = E_UNEXPECTED;
|
|
goto Exit;
|
|
}
|
|
|
|
FNAME fname;
|
|
|
|
fname.pszFilename = pBaseFileName;
|
|
fname.pNextName = NULL;
|
|
fname.status = SFNAME_INIT;
|
|
|
|
m_psess->pFilesToExtract = &fname;
|
|
m_psess->flags &= ~SESSION_FLAG_ENUMERATE; // already enumerated
|
|
|
|
if (FAILED((hr = ExtractFromCabinet(m_psess, m_pFileName)))) {
|
|
goto Exit;
|
|
}
|
|
|
|
m_psess->pFilesToExtract = NULL;
|
|
|
|
} else {
|
|
|
|
|
|
// newly initiated download, piggy back to end of extraction list
|
|
|
|
PFNAME pf = new FNAME;
|
|
if (!pf) {
|
|
hr = E_OUTOFMEMORY;
|
|
goto Exit;
|
|
}
|
|
|
|
pf->pszFilename = new char [lstrlen(pBaseFileName)+1];
|
|
|
|
if (!pf->pszFilename) {
|
|
delete pf;
|
|
hr = E_OUTOFMEMORY;
|
|
goto Exit;
|
|
}
|
|
|
|
lstrcpy(pf->pszFilename, pBaseFileName);
|
|
pf->status = SFNAME_INIT;
|
|
|
|
pf->pNextName = m_pFilesToExtract; // add to list
|
|
m_pFilesToExtract = pf;
|
|
}
|
|
|
|
if (!catDirAndFile(szBuf, MAX_PATH,
|
|
(m_psess)?m_psess->achLocation:NULL, pBaseFileName)) {
|
|
hr = E_UNEXPECTED;
|
|
goto Exit;
|
|
}
|
|
|
|
// create a CSetup OBJ and add it to us
|
|
pSetup = new CSetup(szBuf, pBaseFileName, extn, szDestDir, &hr, dest);
|
|
if (!pSetup) {
|
|
hr = E_OUTOFMEMORY;
|
|
goto Exit;
|
|
} else if (FAILED(hr)) {
|
|
delete pSetup;
|
|
goto Exit;
|
|
}
|
|
|
|
AddSetupToList(pSetup);
|
|
|
|
pSetup->SetCopyFlags (dwCopyFlags);
|
|
if (dwRegisterServer) {
|
|
pSetup->SetUserOverrideRegisterServer(dwRegisterServer&CST_FLAG_REGISTERSERVER);
|
|
}
|
|
|
|
Exit:
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CDownload::IsDuplicateSetup
|
|
// ---------------------------------------------------------------------------
|
|
BOOL
|
|
CDownload::IsDuplicateSetup(LPCSTR pBaseFileName)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Bool,
|
|
"CDownload::IsDuplicateSetup",
|
|
"this=%#x, %.80q",
|
|
this, pBaseFileName
|
|
));
|
|
|
|
CSetup *pSetupCur = m_pSetuphead;
|
|
|
|
for (pSetupCur = m_pSetuphead; pSetupCur; pSetupCur=pSetupCur->GetNext()) {
|
|
|
|
if (lstrcmpi(pBaseFileName, pSetupCur->GetBaseFileName()) == 0)
|
|
{
|
|
DEBUG_LEAVE(TRUE);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
DEBUG_LEAVE(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CDownload::AddSetupToList
|
|
// ---------------------------------------------------------------------------
|
|
VOID
|
|
CDownload::AddSetupToList(CSetup *pSetup)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
None,
|
|
"CDownload::AddSetupToList",
|
|
"this=%#x, %#x",
|
|
this, pSetup
|
|
));
|
|
|
|
pSetup->SetNext(m_pSetuphead);
|
|
m_pSetuphead = pSetup;
|
|
|
|
DEBUG_LEAVE(0);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CDownload::RemoveSetupFromList
|
|
// ---------------------------------------------------------------------------
|
|
HRESULT
|
|
CDownload::RemoveSetupFromList(CSetup *pSetup)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Hresult,
|
|
"CDownload::RemoveSetupFromList",
|
|
"this=%#x, %#x",
|
|
this, pSetup
|
|
));
|
|
|
|
CSetup *pSetupCur = m_pSetuphead;
|
|
HRESULT hr = HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND);
|
|
|
|
Assert(pSetup);
|
|
Assert(pSetupCur); // empty list?
|
|
|
|
if (pSetupCur == pSetup) {
|
|
m_pSetuphead = pSetup->GetNext();
|
|
hr = S_OK;
|
|
goto Exit;
|
|
}
|
|
|
|
do {
|
|
if (pSetupCur->GetNext() == pSetup) {
|
|
pSetupCur->SetNext(pSetup->GetNext());
|
|
hr = S_OK;
|
|
goto Exit;
|
|
}
|
|
} while ( (pSetupCur = pSetupCur->GetNext()));
|
|
|
|
Exit:
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr; // not found in list!
|
|
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CDownload::CleanupFiles
|
|
// ---------------------------------------------------------------------------
|
|
HRESULT
|
|
CDownload::CleanupFiles()
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Hresult,
|
|
"CDownload::CleanupFiles",
|
|
"this=%#x",
|
|
this
|
|
));
|
|
|
|
if (m_psess) { // CAB?
|
|
|
|
DeleteExtractedFiles(m_psess);
|
|
RemoveDirectoryAndChildren(m_psess->achLocation);
|
|
SAFEDELETE(m_psess);
|
|
|
|
}
|
|
|
|
if (!m_pSetuphead) {
|
|
|
|
if (m_pFileName) {
|
|
delete (LPSTR)m_pFileName;
|
|
m_pFileName = NULL;
|
|
}
|
|
|
|
} else {
|
|
|
|
CSetup *pSetupCur = m_pSetuphead;
|
|
CSetup *pSetupNext;
|
|
|
|
for (pSetupCur = m_pSetuphead; pSetupCur;
|
|
pSetupCur = pSetupNext) {
|
|
pSetupNext = pSetupCur->GetNext();
|
|
SAFEDELETE(pSetupCur);
|
|
}
|
|
|
|
}
|
|
|
|
if (m_pUnkForCacheFileRelease)
|
|
SAFERELEASE(m_pUnkForCacheFileRelease);
|
|
|
|
DEBUG_LEAVE(S_OK);
|
|
return S_OK;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CDownload::DoDownload
|
|
// CDownload is the basic download obj. It's action entry point is DoDownload
|
|
// Here it creates a URL moniker for the given m_url and a bind ctx to go
|
|
// with it and then calls pmk->BindToStorage to get the bits. Note how we
|
|
// use URL mon's services to get the bits even as URLmon is our client for
|
|
// the Code Download. We are its client for individual downloads. CDownload
|
|
// has a BSC implementation to track progress and completion. This BSC is
|
|
// where the magic of taking us from one state to next occurs.
|
|
//
|
|
// ---------------------------------------------------------------------------
|
|
HRESULT
|
|
CDownload::DoDownload(LPMONIKER *ppmkContext, DWORD grfBINDF,
|
|
CList<CCodeBaseHold *, CCodeBaseHold *> *pcbhList)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Hresult,
|
|
"CDownload::DoDownload",
|
|
"this=%#x, %#x, %#x, %#x",
|
|
this, ppmkContext, grfBINDF, pcbhList
|
|
));
|
|
|
|
HRESULT hr = NOERROR;
|
|
IBindHost *pBindHost = NULL;
|
|
|
|
m_pcbhList = pcbhList;
|
|
|
|
m_ppmkContext = ppmkContext;
|
|
|
|
m_grfBINDF = grfBINDF;
|
|
|
|
pBindHost = GetCodeDownload()->GetClientBinding()->GetIBindHost();
|
|
|
|
hr = CreateBindCtx(0, &m_pbc);
|
|
|
|
if (FAILED(hr)) {
|
|
goto Exit;
|
|
}
|
|
|
|
// register the format enumerator with the bind ctx if one exists
|
|
|
|
if (g_pEFmtETC) {
|
|
hr = RegisterFormatEnumerator(m_pbc, g_pEFmtETC, 0);
|
|
}
|
|
|
|
if( SUCCEEDED(hr) ) {
|
|
|
|
m_pbsc = new CBindStatusCallback(this, grfBINDF);
|
|
|
|
if (m_pbsc == NULL)
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
if (!pBindHost)
|
|
if (SUCCEEDED(hr))
|
|
hr = RegisterBindStatusCallback(m_pbc, m_pbsc, 0, 0);
|
|
}
|
|
|
|
if (FAILED(hr)) {
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
|
|
if (pBindHost) {
|
|
|
|
IMoniker *pmk;
|
|
|
|
hr = pBindHost->CreateMoniker(m_url, m_pbc, &pmk, 0);
|
|
|
|
if (FAILED(hr)) {
|
|
goto Exit;
|
|
}
|
|
|
|
if (*ppmkContext == NULL) { // no context moniker yet?
|
|
|
|
m_pmk = pmk;
|
|
m_ppmkContext = &pmk;
|
|
|
|
} else {
|
|
|
|
hr = (*ppmkContext)->ComposeWith(pmk, FALSE, &m_pmk);
|
|
|
|
pmk->Release();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
hr = CreateURLMoniker(*ppmkContext, m_url, &m_pmk);
|
|
|
|
|
|
}
|
|
|
|
|
|
if( SUCCEEDED(hr) ) {
|
|
|
|
// store away the full URL
|
|
SAFEDELETE(m_url);
|
|
hr = m_pmk->GetDisplayName(m_pbc, NULL, &m_url);
|
|
|
|
if (FAILED(hr))
|
|
goto Exit;
|
|
|
|
// everything succeeded
|
|
if (*ppmkContext == NULL) { // no context moniker yet?
|
|
|
|
// make this the context moniker
|
|
*ppmkContext = m_pmk;
|
|
}
|
|
|
|
IUnknown *pUnk = NULL;
|
|
|
|
if (pBindHost) {
|
|
hr = pBindHost->MonikerBindToStorage(m_pmk, m_pbc, m_pbsc,
|
|
IID_IUnknown, (void **)&pUnk);
|
|
} else {
|
|
hr = m_pmk->BindToStorage(m_pbc, 0, IID_IUnknown, (void**)&pUnk);
|
|
}
|
|
// m_pbc will get the onstopbinding, ondatavailable, and onprogress
|
|
// messages and pass them on to m_pbsc; wait asynchronously
|
|
|
|
|
|
if (pUnk) {
|
|
pUnk->Release();
|
|
}
|
|
|
|
}
|
|
|
|
|
|
Exit:
|
|
|
|
if (FAILED(hr) && hr != E_PENDING) {
|
|
|
|
// real failure!
|
|
m_hrOSB = hr;
|
|
SetDLState(DLSTATE_DONE);
|
|
|
|
if (*ppmkContext == m_pmk)
|
|
*ppmkContext = NULL;
|
|
|
|
}
|
|
else {
|
|
|
|
/*
|
|
// everything succeeded
|
|
if (*ppmkContext == NULL) { // no context moniker yet?
|
|
|
|
// make this the context moniker
|
|
*ppmkContext = m_pmk;
|
|
}
|
|
*/
|
|
hr = MK_S_ASYNCHRONOUS;
|
|
}
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
} // CDownload::DoDownload
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CDownload::PerformVirusScan
|
|
// S_OK : continue with operation
|
|
// S_FALSE : cancel operation.
|
|
// ---------------------------------------------------------------------------
|
|
HRESULT CDownload::PerformVirusScan(LPSTR szFileName)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Hresult,
|
|
"CDownload::PerformVirusScan",
|
|
"this=%#x, %.80q",
|
|
this, szFileName
|
|
));
|
|
|
|
HRESULT hr = S_OK, hrReturn = S_OK;
|
|
ICatInformation * pci = NULL; // category manager
|
|
IEnumCLSID * peclsid = NULL; // enum of av objects
|
|
IOfficeAntiVirus * poav = NULL; // current av interface
|
|
CLSID clsidCurrent; // current av clsid
|
|
ULONG pcFetched;
|
|
MSOAVINFO msavi; // antivirus struct
|
|
BOOL fInitStruct = FALSE;
|
|
|
|
//
|
|
// Get COM category manager and get an enumerator for our virus
|
|
// scanner category
|
|
//
|
|
// If something goes wrong finding AV objects, proceed as normal.
|
|
//
|
|
|
|
hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL,
|
|
CLSCTX_INPROC_SERVER, IID_ICatInformation, (void **)&pci);
|
|
if(FAILED(hr))
|
|
{
|
|
DEBUG_LEAVE(NOERROR);
|
|
return NOERROR;
|
|
}
|
|
|
|
hr = pci->EnumClassesOfCategories(1, (GUID *)&CATID_MSOfficeAntiVirus, 0, NULL, &peclsid);
|
|
pci->Release();
|
|
if(FAILED(hr))
|
|
{
|
|
DEBUG_LEAVE(NOERROR);
|
|
return NOERROR;
|
|
}
|
|
|
|
//
|
|
// Call all scanners. If any fail, return E_FAIL.
|
|
//
|
|
|
|
hr = peclsid->Next(1, &clsidCurrent, &pcFetched);
|
|
while(SUCCEEDED(hr) && pcFetched > 0)
|
|
{
|
|
if(FALSE == fInitStruct)
|
|
{
|
|
if (FAILED(Ansi2Unicode(szFileName,&msavi.u.pwzFullPath)))
|
|
{
|
|
break;
|
|
}
|
|
msavi.cbsize = sizeof(msavi);
|
|
msavi.fPath = TRUE;
|
|
msavi.fHttpDownload = TRUE;
|
|
msavi.fReadOnlyRequest = FALSE;
|
|
msavi.fInstalled = FALSE;
|
|
msavi.hwnd = GetCodeDownload()->GetClientBinding()->GetHWND();
|
|
msavi.pwzOrigURL = (LPWSTR)GetURL();
|
|
|
|
// per office spec, this is only meant as a method for the scanner
|
|
// to differentiate the caller. Not localized.
|
|
msavi.pwzHostName = L"Urlmon";
|
|
|
|
fInitStruct = TRUE;
|
|
}
|
|
|
|
// have clsid of av component
|
|
hr = CoCreateInstance(clsidCurrent, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_IOfficeAntiVirus, (void **)&poav);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
// call scan method
|
|
hr = poav->Scan(&msavi);
|
|
poav->Release();
|
|
|
|
if(hr == E_FAIL)
|
|
{
|
|
// file could not be cleaned
|
|
hrReturn = E_FAIL;
|
|
}
|
|
}
|
|
|
|
hr = peclsid->Next(1, &clsidCurrent, &pcFetched);
|
|
}
|
|
|
|
//
|
|
// clean up
|
|
//
|
|
peclsid->Release();
|
|
|
|
if(fInitStruct)
|
|
{
|
|
SAFEDELETE(msavi.u.pwzFullPath);
|
|
}
|
|
|
|
DEBUG_LEAVE(hrReturn);
|
|
return hrReturn;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CDownload::DownloadRedundantCodeBase()
|
|
// Returns S_OK if starting next download, or S_FALSE if no redundant
|
|
// codebases remaining to try.
|
|
// ---------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP CDownload::DownloadRedundantCodeBase()
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Hresult,
|
|
"CDownload::DownloadRedundantCodeBase",
|
|
"this=%#x",
|
|
this
|
|
));
|
|
|
|
HRESULT hr = S_FALSE;
|
|
LISTPOSITION lpos = 0;
|
|
CCodeBaseHold *pcbh = NULL;
|
|
|
|
if (m_pcbhList == NULL) {
|
|
goto Exit;
|
|
}
|
|
|
|
lpos = m_pcbhList->GetHeadPosition();
|
|
while (lpos) {
|
|
pcbh = m_pcbhList->GetNext(lpos);
|
|
if (!(pcbh->dwFlags & CBH_FLAGS_DOWNLOADED)) {
|
|
RevokeBindStatusCallback(GetBindCtx(), GetBSC());
|
|
CleanUp();
|
|
m_url = new WCHAR[lstrlenW(pcbh->wszCodeBase) + 1];
|
|
if (m_url == NULL) {
|
|
hr = E_OUTOFMEMORY;
|
|
goto Exit;
|
|
}
|
|
StrCpyW(m_url, pcbh->wszCodeBase);
|
|
SetResponseHeaderStatus(S_OK);
|
|
pcbh->dwFlags |= CBH_FLAGS_DOWNLOADED;
|
|
|
|
// Try another download
|
|
hr = DoDownload(m_ppmkContext, m_grfBINDF, m_pcbhList);
|
|
break;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
if (hr == S_FALSE) {
|
|
GetCodeDownload()->CodeDownloadDebugOut(DEB_CODEDL, FALSE, ID_CDLDBG_DL_REDUNDANT_FAILED);
|
|
}
|
|
else {
|
|
LPSTR szUrl = NULL;
|
|
Unicode2Ansi(m_url, &szUrl);
|
|
GetCodeDownload()->CodeDownloadDebugOut(DEB_CODEDL, FALSE, ID_CDLDBG_DL_REDUNDANT, (szUrl == NULL) ? ("") : (szUrl), hr);
|
|
delete szUrl;
|
|
}
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|
|
void CDownload::CleanUp()
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
None,
|
|
"CDownload::CleanUp",
|
|
"this=%#x",
|
|
this
|
|
));
|
|
|
|
LISTPOSITION pos = 0;
|
|
int i, iNum;
|
|
|
|
SAFERELEASE(m_pmk);
|
|
SAFERELEASE(m_pbc);
|
|
SAFERELEASE(m_pbsc);
|
|
SAFEDELETE(m_url);
|
|
|
|
if (m_pFilesToExtract) {
|
|
PFNAME pf = m_pFilesToExtract;
|
|
PFNAME pfnext;
|
|
|
|
for (;pf != NULL; pf = pfnext) {
|
|
delete pf->pszFilename;
|
|
pfnext = pf->pNextName;
|
|
delete pf;
|
|
}
|
|
}
|
|
m_pFilesToExtract = NULL;
|
|
|
|
if (m_hPostData)
|
|
GlobalFree(m_hPostData);
|
|
|
|
SAFERELEASE(m_pUnkForCacheFileRelease);
|
|
|
|
SAFEDELETE(m_pbJavaTrust);
|
|
|
|
DEBUG_LEAVE(0);
|
|
}
|
|
|
|
HRESULT CDownload::SetMainCABJavaTrustPermissions(PJAVA_TRUST pbJavaTrust)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
None,
|
|
"CDownload::SetMainCABJavaTrustPermissions",
|
|
"this=%#x, %#x",
|
|
this, pbJavaTrust
|
|
));
|
|
|
|
HRESULT hr = GetCodeDownload()->SetMainCABJavaTrustPermissions(pbJavaTrust);
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CBindStatusCallback::CBindStatusCallback
|
|
// The BSC implementation for CDownload to track progress of indiv dwlds
|
|
// ---------------------------------------------------------------------------
|
|
CBindStatusCallback::CBindStatusCallback(CDownload *pdl, DWORD grfBINDF)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
None,
|
|
"CBindStatusCallback::CBindStatusCallback",
|
|
"this=%#x, %#x, %#x",
|
|
this, pdl, grfBINDF
|
|
));
|
|
|
|
DllAddRef();
|
|
m_pbinding = NULL;
|
|
m_cRef = 1; // equ of internal addref
|
|
m_pdl = pdl;
|
|
|
|
m_grfBINDF = grfBINDF;
|
|
|
|
DEBUG_LEAVE(0);
|
|
} // CBindStatusCallback
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CBindStatusCallback::~CBindStatusCallback
|
|
// ---------------------------------------------------------------------------
|
|
CBindStatusCallback::~CBindStatusCallback()
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
None,
|
|
"CBindStatusCallback::~CBindStatusCallback",
|
|
"this=%#x",
|
|
this
|
|
));
|
|
|
|
SAFERELEASE(m_pbinding);
|
|
DllRelease();
|
|
|
|
DEBUG_LEAVE(0);
|
|
} // ~CBindStatusCallback
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CBindStatusCallback::AddRef
|
|
// ---------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG)
|
|
CBindStatusCallback::AddRef()
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Dword,
|
|
"CBindStatusCallback::IUnknown::AddRef",
|
|
"this=%#x",
|
|
this
|
|
));
|
|
|
|
ULONG ulRet = m_cRef++;
|
|
|
|
DEBUG_LEAVE(ulRet);
|
|
return ulRet;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CBindStatusCallback::Release
|
|
// ---------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG)
|
|
CBindStatusCallback::Release()
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Dword,
|
|
"CBindStatusCallback::IUnknown::Release",
|
|
"this=%#x",
|
|
this
|
|
));
|
|
|
|
if (--m_cRef == 0) {
|
|
delete this;
|
|
|
|
DEBUG_LEAVE(0);
|
|
return 0;
|
|
}
|
|
|
|
DEBUG_LEAVE(m_cRef);
|
|
return m_cRef;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CBindStatusCallback::QueryInterface
|
|
// ---------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CBindStatusCallback::QueryInterface(REFIID riid, void** ppv)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Hresult,
|
|
"CBindStatusCallback::IUnknown::QueryInterface",
|
|
"this=%#x, %#x, %#x",
|
|
this, &riid, ppv
|
|
));
|
|
|
|
*ppv = NULL;
|
|
|
|
if (riid==IID_IUnknown || riid==IID_IBindStatusCallback)
|
|
*ppv = (IBindStatusCallback *)this;
|
|
|
|
if (riid==IID_IHttpNegotiate)
|
|
*ppv = (IHttpNegotiate *)this;
|
|
|
|
if (riid==IID_IWindowForBindingUI)
|
|
*ppv = (IWindowForBindingUI*)this;
|
|
|
|
if (riid==IID_IServiceProvider)
|
|
*ppv = (IServiceProvider *)this;
|
|
|
|
if (riid==IID_ICatalogFileInfo)
|
|
*ppv = (ICatalogFileInfo *)this;
|
|
|
|
if (*ppv == NULL)
|
|
{
|
|
DEBUG_LEAVE(E_NOINTERFACE);
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
AddRef();
|
|
|
|
DEBUG_LEAVE(S_OK);
|
|
return S_OK;
|
|
|
|
} // CBindStatusCallback::QueryInterface
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CBindStatusCallback::GetWindow
|
|
// ---------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CBindStatusCallback::GetWindow(REFGUID rguidreason, HWND *phWnd)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Hresult,
|
|
"CBindStatusCallback::IWindowForBindingUI::GetWindow",
|
|
"this=%#x, %#x, %#x",
|
|
this, &rguidreason, phWnd
|
|
));
|
|
|
|
HRESULT hr = S_OK;
|
|
CCodeDownload *pcdl = m_pdl->GetCodeDownload();
|
|
HWND hWnd = pcdl->GetClientBinding()->GetHWND(rguidreason);
|
|
|
|
if (hWnd == INVALID_HANDLE_VALUE)
|
|
hr = S_FALSE;
|
|
|
|
*phWnd = hWnd;
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CBindStatusCallback::QueryService
|
|
// ---------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CBindStatusCallback::QueryService(REFGUID guidService, REFIID riid, LPVOID *ppv)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Hresult,
|
|
"CBindStatusCallback::IServiceProvider::QueryService",
|
|
"this=%#x, %#x, %#x, %#x",
|
|
this, &guidService, &riid, ppv
|
|
));
|
|
|
|
IBindStatusCallback *pbsc = m_pdl->GetCodeDownload()->GetClientBSC();
|
|
IServiceProvider *psp = NULL;
|
|
HRESULT hr = E_NOINTERFACE;
|
|
|
|
ASSERT(pbsc);
|
|
|
|
if (pbsc && SUCCEEDED(pbsc->QueryInterface(IID_IServiceProvider, (void **)&psp)) && psp) {
|
|
hr = psp->QueryService(guidService, riid, ppv);
|
|
SAFERELEASE(psp);
|
|
}
|
|
|
|
// Since this is QueryService we can QI on our client's BSC object too.
|
|
if (FAILED(hr)) {
|
|
|
|
// This is special case we handle so we can bind to client's ultimate IBindHost
|
|
// if one exists. BUG BUG: Support other interfaces here, in general?
|
|
// BUG BUG: Rearrange order of comparisons for performance.
|
|
|
|
if (IsEqualGUID(guidService, riid) &&
|
|
(IsEqualGUID(riid, IID_IBindHost) ||
|
|
IsEqualGUID(riid, IID_IWindowForBindingUI) ||
|
|
IsEqualGUID(riid, IID_ICodeInstall) ||
|
|
IsEqualGUID(riid, IID_ICatalogFileInfo) ||
|
|
IsEqualGUID(riid, IID_IInternetHostSecurityManager))) {
|
|
|
|
hr = pbsc->QueryInterface(riid, (void **)ppv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CBindStatusCallback::GetBindInfo
|
|
// ---------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CBindStatusCallback::GetBindInfo(DWORD* pgrfBINDF, BINDINFO* pbindInfo)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Hresult,
|
|
"CBindStatusCallback::IBindingStatusCallback::GetBindInfo",
|
|
"this=%#x, %#x, %#x",
|
|
this, pgrfBINDF, pbindInfo
|
|
));
|
|
|
|
if ((pgrfBINDF == NULL) || (pbindInfo == NULL) || (pbindInfo->cbSize == 0))
|
|
{
|
|
DEBUG_LEAVE(E_INVALIDARG);
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
*pgrfBINDF = m_grfBINDF;
|
|
|
|
// clear BINDINFO but keep its size
|
|
DWORD cbSize = pbindInfo->cbSize;
|
|
ZeroMemory( pbindInfo, cbSize );
|
|
pbindInfo->cbSize = cbSize;
|
|
|
|
// use IE5's utf-8 policy
|
|
pbindInfo->dwOptions |= BINDINFO_OPTIONS_USE_IE_ENCODING;
|
|
|
|
|
|
if (m_pdl->DoPost()) {
|
|
|
|
pbindInfo->dwBindVerb = BINDVERB_POST;
|
|
|
|
pbindInfo->stgmedData.tymed = TYMED_HGLOBAL;
|
|
pbindInfo->stgmedData.hGlobal = m_pdl->GetPostData(&(pbindInfo->cbstgmedData));
|
|
pbindInfo->stgmedData.pUnkForRelease = (IUnknown *) (IBindStatusCallback *) this;
|
|
AddRef(); // AddRef ourselves so we stick around; caller must release!
|
|
|
|
}
|
|
|
|
DWORD grfBINDF = 0;
|
|
BINDINFO bindInfo;
|
|
memset(&bindInfo, 0, sizeof(BINDINFO));
|
|
bindInfo.cbSize = sizeof(BINDINFO);
|
|
|
|
CCodeDownload *pcdl = m_pdl->GetCodeDownload();
|
|
pcdl->GetClientBSC()->GetBindInfo(&grfBINDF, &bindInfo);
|
|
|
|
if (grfBINDF & BINDF_SILENTOPERATION)
|
|
{
|
|
*pgrfBINDF |= BINDF_SILENTOPERATION;
|
|
pcdl->SetSilentMode();
|
|
}
|
|
|
|
if (grfBINDF & BINDF_OFFLINEOPERATION)
|
|
*pgrfBINDF |= BINDF_OFFLINEOPERATION;
|
|
|
|
if (grfBINDF & BINDF_GETNEWESTVERSION)
|
|
*pgrfBINDF |= BINDF_GETNEWESTVERSION;
|
|
|
|
if (grfBINDF & BINDF_RESYNCHRONIZE)
|
|
*pgrfBINDF |= BINDF_RESYNCHRONIZE;
|
|
|
|
// or should we always insist on this regardless of what client wants?
|
|
if (grfBINDF & BINDF_PREFERDEFAULTHANDLER)
|
|
*pgrfBINDF |= BINDF_PREFERDEFAULTHANDLER;
|
|
|
|
if (grfBINDF & BINDF_ENFORCERESTRICTED)
|
|
*pgrfBINDF |= BINDF_ENFORCERESTRICTED;
|
|
|
|
// To make sure the file winds up on disk even for SSL connections, we need to add
|
|
*pgrfBINDF |= BINDF_NEEDFILE;
|
|
|
|
// BINDINFO_FIX(LaszloG 8/15/97)
|
|
ReleaseBindInfo(&bindInfo);
|
|
|
|
DEBUG_LEAVE(S_OK);
|
|
return S_OK;
|
|
} // CBindStatusCallback::GetBindInfo
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CBindStatusCallback::OnStartBinding
|
|
// ---------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CBindStatusCallback::OnStartBinding(DWORD grfBSCOPTION,IBinding* pbinding)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Hresult,
|
|
"CBindStatusCallback::IBindingStatusCallback::OnStartBinding",
|
|
"this=%#x, %#x, %#x",
|
|
this, grfBSCOPTION, pbinding
|
|
));
|
|
|
|
CCodeDownload *pcdl = m_pdl->GetCodeDownload();
|
|
|
|
Assert(pbinding);
|
|
|
|
if (m_pbinding != NULL)
|
|
SAFERELEASE(m_pbinding);
|
|
m_pbinding = pbinding;
|
|
if (m_pbinding != NULL)
|
|
m_pbinding->AddRef();
|
|
|
|
m_pdl->SetDLState(DLSTATE_BINDING);
|
|
|
|
// call the client BSC::OnStartBinding if not already done
|
|
|
|
CClBinding *pClientBinding = pcdl->GetClientBinding();
|
|
|
|
if(pClientBinding->GetState() == CDL_NoOperation){
|
|
|
|
Assert(pClientBinding->GetAssBSC() == pcdl->GetClientBSC());
|
|
|
|
pClientBinding->SetState(CDL_Downloading);
|
|
pcdl->AddRef();
|
|
pcdl->GetClientBSC()->OnStartBinding(grfBSCOPTION, pClientBinding);
|
|
}
|
|
|
|
DEBUG_LEAVE(S_OK);
|
|
return S_OK;
|
|
} // CBindStatusCallback::OnStartBinding
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CBindStatusCallback::GetPriority
|
|
// ---------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CBindStatusCallback::GetPriority(LONG* pnPriority)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Hresult,
|
|
"CBindStatusCallback::IBindingStatusCallback::GetPriority",
|
|
"this=%#x, %#x",
|
|
this, pnPriority
|
|
));
|
|
|
|
DEBUG_LEAVE(E_NOTIMPL);
|
|
return E_NOTIMPL;
|
|
} // CBindStatusCallback::GetPriority
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CBindStatusCallback::OnProgress
|
|
// Here we get the master CodeDownload obj to collate progress and report
|
|
// cumulative code download progress to client BSC::OnProgress.
|
|
// ---------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CBindStatusCallback::OnProgress(ULONG ulProgress, ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Hresult,
|
|
"CBindStatusCallback::IBindingStatusCallback::GetPriority",
|
|
"this=%#x, %#x, %#x, %#x, %.80wq",
|
|
this, ulProgress, ulProgressMax, ulStatusCode, szStatusText
|
|
));
|
|
|
|
IBindStatusCallback *pClientBSC = m_pdl->GetCodeDownload()->GetClientBSC();
|
|
char szURL[INTERNET_MAX_URL_LENGTH];
|
|
FILEXTN extn;
|
|
char *pBaseFileName;
|
|
HRESULT hr = S_OK;
|
|
IMoniker *pmk = NULL;
|
|
CCodeDownload *pcdl = m_pdl->GetCodeDownload();
|
|
|
|
// if this a redirect set the context appropriately
|
|
// also use this URL to get the extension and base dest name for this
|
|
// component, if its a POST (Search Path)
|
|
|
|
if (m_pdl->DoPost() && (ulStatusCode == BINDSTATUS_REDIRECTING)) {
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, szStatusText, -1, szURL,
|
|
INTERNET_MAX_URL_LENGTH, 0,0);
|
|
|
|
|
|
// BUGBUG: use mime type in response header to determine extn
|
|
extn = GetExtnAndBaseFileName( szURL, &pBaseFileName);
|
|
|
|
hr = m_pdl->SetURLAndExtn( szStatusText, extn);
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
IBindHost *pBH = pcdl->GetClientBinding()->GetIBindHost();
|
|
if (pBH) {
|
|
hr = pBH->CreateMoniker((LPOLESTR)szStatusText, m_pdl->GetBindCtx(), &pmk, 0);
|
|
} else {
|
|
hr = CreateURLMoniker(NULL, szStatusText, &pmk);
|
|
}
|
|
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
pcdl->SetContextMoniker(pmk);
|
|
pcdl->MarkNewContextMoniker();
|
|
}
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
m_pdl->SetResponseHeaderStatus( hr );
|
|
}
|
|
|
|
// we are only interested in cumulative numbers for "downloading" status
|
|
// for all others progress is usually: "connecting: 0 of 0", so we
|
|
// pass these as is to our client
|
|
|
|
if ((ulStatusCode != BINDSTATUS_DOWNLOADINGDATA ) &&
|
|
(ulStatusCode != BINDSTATUS_ENDDOWNLOADDATA )) {
|
|
|
|
// pass on progress as is to our client
|
|
pClientBSC->OnProgress(ulProgress, ulProgressMax, ulStatusCode,
|
|
szStatusText);
|
|
|
|
DEBUG_LEAVE(S_OK);
|
|
return S_OK;
|
|
}
|
|
|
|
// here if Downloading Data progress
|
|
m_pdl->SetProgress(ulProgress, ulProgressMax); // update my dl-object's prog
|
|
|
|
// now summate stats and report to client
|
|
CDownload *pdl = m_pdl->GetCodeDownload()->GetDownloadHead();
|
|
ULONG ulSum = 0;
|
|
ULONG ulSumMax = 0;
|
|
|
|
// walk each dl object and make a sum of all ulProgress and ulProgressMax
|
|
do {
|
|
pdl->SumProgress(&ulSum, &ulSumMax);
|
|
} while ((pdl = pdl->GetNext()) != NULL);
|
|
|
|
|
|
// pass on cumulative downloading progress to our client
|
|
pClientBSC->OnProgress(ulSum, ulSumMax, BINDSTATUS_DOWNLOADINGDATA,
|
|
m_pdl->GetCodeDownload()->GetMainURL());
|
|
|
|
if (ulStatusCode == BINDSTATUS_ENDDOWNLOADDATA ) {
|
|
// pass on progress as is to our client
|
|
pClientBSC->OnProgress(ulProgress, ulProgressMax, ulStatusCode,
|
|
szStatusText);
|
|
}
|
|
|
|
DEBUG_LEAVE(NOERROR);
|
|
return(NOERROR);
|
|
} // CBindStatusCallback
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CBindStatusCallback::OnDataAvailable
|
|
// At the last notification we get the filename URLmon has downloaded the
|
|
// m_url data to and rename it to a file in the temp dir.
|
|
// ---------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CBindStatusCallback::OnDataAvailable(DWORD grfBSC, DWORD dwSize, FORMATETC *pFmtetc, STGMEDIUM __RPC_FAR *pstgmed)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Hresult,
|
|
"CBindStatusCallback::IBindingStatusCallback::OnDataAvailable",
|
|
"this=%#x, %#x, %#x, %#x, %#x",
|
|
this, grfBSC, dwSize, pFmtetc, pstgmed
|
|
));
|
|
|
|
HRESULT hr = NO_ERROR;
|
|
|
|
// never forward OnDataAvailable to code download's client BSC
|
|
|
|
if (grfBSC & BSCF_LASTDATANOTIFICATION)
|
|
{
|
|
// if this is the final notification then get the data and display it
|
|
|
|
// we asked for IUnknown, we should get back a filename
|
|
Assert((pFmtetc->tymed & TYMED_FILE));
|
|
|
|
if (pFmtetc->tymed & TYMED_FILE) {
|
|
|
|
char szFile[MAX_PATH];
|
|
DWORD dwLen = 0;
|
|
|
|
if (!(dwLen = WideCharToMultiByte(CP_ACP, 0 , pstgmed->lpszFileName , -1 , szFile, MAX_PATH, NULL, NULL))) {
|
|
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
goto Exit;
|
|
|
|
} else {
|
|
|
|
LPSTR lpFileName = new char[dwLen + 1];
|
|
|
|
if (!lpFileName) {
|
|
hr = E_OUTOFMEMORY;
|
|
goto Exit;
|
|
} else {
|
|
|
|
lstrcpy(lpFileName, szFile);
|
|
m_pdl->SetFileName(lpFileName);
|
|
}
|
|
}
|
|
|
|
// check last modified date for file: URLs
|
|
// maybe we don't need the file
|
|
HRESULT hr1 = m_pdl->IsDownloadedVersionRequired();
|
|
|
|
if (FAILED(hr1)) {
|
|
m_pdl->SetResponseHeaderStatus(hr1);
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
// ref count on the cache
|
|
// file.
|
|
|
|
pstgmed->pUnkForRelease->AddRef();
|
|
|
|
m_pdl->SetUnkForCacheFileRelease(pstgmed->pUnkForRelease);
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
Exit:
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
|
|
} // CBindStatusCallback::OnDataAvailable
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CBindStatusCallback::OnObjectAvailable
|
|
// ---------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CBindStatusCallback::OnObjectAvailable( REFIID riid, IUnknown* punk)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Hresult,
|
|
"CBindStatusCallback::IBindingStatusCallback::OnObjectAvailable",
|
|
"this=%#x, %#x, %#x",
|
|
this, &riid, punk
|
|
));
|
|
|
|
// Not applicable: we call pmk->BTS not BTO
|
|
|
|
DEBUG_LEAVE(E_NOTIMPL);
|
|
return E_NOTIMPL;
|
|
} // CBindStatusCallback::OnObjectAvailable
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CBindStatusCallback::OnLowResource
|
|
// ---------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CBindStatusCallback::OnLowResource(DWORD dwReserved)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Hresult,
|
|
"CBindStatusCallback::IBindingStatusCallback::OnObjectAvailable",
|
|
"this=%#x, %#x",
|
|
this, dwReserved
|
|
));
|
|
|
|
DEBUG_LEAVE(E_NOTIMPL);
|
|
return E_NOTIMPL;
|
|
} // CBindStatusCallback::OnLoadResource
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CBindStatusCallback::OnStopBinding
|
|
//
|
|
// we get here when we have fully downloaded 'this'.
|
|
// ---------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CBindStatusCallback::OnStopBinding(HRESULT hrStatus, LPCWSTR szError)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Hresult,
|
|
"CBindStatusCallback::IBindingStatusCallback::OnStopBinding",
|
|
"this=%#x, %#x, %.80wq",
|
|
this, hrStatus, szError
|
|
));
|
|
|
|
CCodeDownload *pcdl = m_pdl->GetCodeDownload();
|
|
HRESULT hrResponseHdr = m_pdl->GetResponseHeaderStatus();
|
|
IBindHost *pBindHost = NULL;
|
|
HRESULT hr = S_OK; // assume all OK
|
|
|
|
if (pcdl) {
|
|
pcdl->CodeDownloadDebugOut(DEB_CODEDL, FALSE, ID_CDLDBG_DL_ON_STOP_BINDING, hrStatus, hrResponseHdr);
|
|
}
|
|
if ((FAILED(hrStatus) && (SCODE_FACILITY(hrStatus) == FACILITY_INTERNET)) ||
|
|
FAILED(hrResponseHdr) || SCODE_CODE(hrStatus) == ERROR_MOD_NOT_FOUND) {
|
|
hr = m_pdl->DownloadRedundantCodeBase();
|
|
if (hr == E_PENDING || hr == MK_S_ASYNCHRONOUS) {
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
m_pdl->SetDLState(DLSTATE_DOWNLOADED);
|
|
|
|
pBindHost = pcdl->GetClientBinding()->GetIBindHost();
|
|
|
|
SAFERELEASE(m_pbinding);
|
|
|
|
if (!pBindHost) {
|
|
hr = RevokeBindStatusCallback(m_pdl->GetBindCtx(), m_pdl->GetBSC());
|
|
|
|
}
|
|
|
|
if (FAILED(hr)) {
|
|
goto OSB_Complete;
|
|
}
|
|
|
|
// if URLMON failed the download or if the response hdr indicated
|
|
// a failure that URLMON failed to detect properly
|
|
// pass the problem to pcdl->CompleteOne(). This will determine if it
|
|
// will query for the clsid with more urls in the CodeSearchPath
|
|
// in the registry.
|
|
if (FAILED(hrStatus) || FAILED(hrResponseHdr)) {
|
|
goto OSB_Complete;
|
|
}
|
|
|
|
// BUGBUG: also check here for Last Modified Date on the Cache Entry
|
|
// versus Last Modified if a previous version exists and we are doung
|
|
// GetLatest. If data is in the cache then wininet ignores our
|
|
// if-modified-since and so we will end up re-installing even though
|
|
// there is no version change.
|
|
|
|
if (m_pdl->GetFileName() != NULL) { // should be set by OnDataAvailable
|
|
|
|
// This takes us to the next state. VerifyTrust moves us when
|
|
// complete to the next state of processing the ProcessPiece.
|
|
|
|
CCDLPacket *pPkt= new CCDLPacket(CODE_DOWNLOAD_TRUST_PIECE, m_pdl, 0);
|
|
|
|
if (pPkt) {
|
|
hr = pPkt->Post();
|
|
} else {
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
goto Exit;
|
|
// else fall thru to OSB_Complete
|
|
|
|
} else if (!m_pdl->UsingCdlProtocol()) {
|
|
|
|
// In case of CDL protocol handler we don't need OnDataAvailable or
|
|
// Trust Verification done here.
|
|
|
|
// BindToStorage may have not detected the error
|
|
if (m_pdl->DoPost())
|
|
hrResponseHdr = HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND);
|
|
else
|
|
hr = HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND);
|
|
}
|
|
|
|
OSB_Complete:
|
|
|
|
// does all the master state analysis
|
|
m_pdl->CompleteSignal(hr, hrStatus, hrResponseHdr, szError);
|
|
|
|
// This very BSC may already have been deleted if all done.
|
|
// Don't access any members. Just return !!!
|
|
|
|
Exit:
|
|
|
|
DEBUG_LEAVE(S_OK);
|
|
return S_OK; // always succeed to url mon.
|
|
|
|
} // CBindStatusCallback::OnStopBinding
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CBindStatusCallback::BeginningTransaction
|
|
// ---------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CBindStatusCallback::BeginningTransaction(
|
|
LPCWSTR szURL,
|
|
LPCWSTR szHeaders,
|
|
DWORD dwReserved,
|
|
LPWSTR *pszAdditionalHeaders)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Hresult,
|
|
"CBindStatusCallback::IHttpNegotiate::BeginningTransaction",
|
|
"this=%#x, %.80wq, %.80wq, %#x, %#x",
|
|
this, szURL, szHeaders, dwReserved, pszAdditionalHeaders
|
|
));
|
|
|
|
HRESULT hr = S_OK;
|
|
char szHttpDate[INTERNET_RFC1123_BUFSIZE+1];
|
|
DWORD dwLen = 0;
|
|
LPWSTR szAHdrs = NULL;
|
|
static const char cszHeaderFmt[] = "%s %s\r\n";
|
|
static const char szIfMod[] = "If-Modified-Since:";
|
|
static const char szNONEMATCH[] = "If-None-Match:";
|
|
static const WCHAR szFORM[] = L"Content-Type: application/x-www-form-urlencoded\r\n";
|
|
static const char szAcceptLanguageFmt[] = "Accept-Language: %s\r\n";
|
|
char szBuf[MAX_PATH];
|
|
WCHAR szAcceptLanguage[MAX_PATH];
|
|
char szLangBuf[10];
|
|
char *pszNoneMatch = NULL;
|
|
|
|
CCodeDownload *pcdl = m_pdl->GetCodeDownload();
|
|
LCID lcid = pcdl->GetLCID();
|
|
|
|
// BUGBUG: we currently only support primary lang or default
|
|
// it should really be "en-us, en", instead of just "en"
|
|
// waiting for note from TonyCi about some servers like Apache
|
|
// broken by this
|
|
lcid = MAKELCID(MAKELANGID(PRIMARYLANGID(LANGIDFROMLCID(lcid)), SUBLANG_DEFAULT), SORT_DEFAULT);
|
|
|
|
DEBUG_PRINT(DOWNLOAD,
|
|
INFO,
|
|
("this=%#x, m_lcid: %d (%#x), lcid: %d (%#x)\n",
|
|
this, pcdl->GetLCID(), pcdl->GetLCID(), lcid, lcid
|
|
));
|
|
|
|
*szAcceptLanguage = L'\0';
|
|
if (pcdl->GetLangInfo()->GetAcceptLanguageString(lcid, szLangBuf, sizeof(szLangBuf))
|
|
&& (*szLangBuf != '\0'))
|
|
{
|
|
wnsprintf(szBuf, sizeof(szBuf)-1, szAcceptLanguageFmt, szLangBuf);
|
|
dwLen = MultiByteToWideChar(CP_ACP, 0, szBuf, -1, szAcceptLanguage, MAX_PATH);
|
|
}
|
|
|
|
Assert((pszAdditionalHeaders != NULL));
|
|
|
|
FILETIME *pftLastMod = pcdl->GetLastModifiedTime();
|
|
SYSTEMTIME sSysTime;
|
|
|
|
BOOL bSendNoneMatch = !pcdl->ForceDownload() && ( pcdl->LocalVersionPresent() && (pcdl->GetLocalVersionEtag()) ) && pcdl->NeedLatestVersion();
|
|
|
|
BOOL bSendLastMod = !bSendNoneMatch && (!pcdl->ForceDownload() && ( pcdl->LocalVersionPresent() && (pftLastMod) ) && pcdl->NeedLatestVersion());
|
|
|
|
|
|
if ( bSendLastMod) {
|
|
Assert( (pftLastMod != NULL) ); // Check for bug#40696
|
|
|
|
// need to send If-Modified-Since
|
|
|
|
if (!FileTimeToSystemTime(pftLastMod, &sSysTime)) {
|
|
m_pdl->SetResponseHeaderStatus( HRESULT_FROM_WIN32(GetLastError()));
|
|
goto Exit;
|
|
}
|
|
|
|
if (!InternetTimeFromSystemTimeA(&sSysTime, INTERNET_RFC1123_FORMAT,
|
|
szHttpDate, INTERNET_RFC1123_BUFSIZE)) {
|
|
|
|
m_pdl->SetResponseHeaderStatus( HRESULT_FROM_WIN32(GetLastError()));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
dwLen += (INTERNET_RFC1123_BUFSIZE + 1 + sizeof(szIfMod) +
|
|
sizeof(cszHeaderFmt));
|
|
|
|
}
|
|
|
|
if (bSendNoneMatch) {
|
|
|
|
DWORD dwNoneMatch = lstrlen(pcdl->GetLocalVersionEtag()) + sizeof(szNONEMATCH) + sizeof(cszHeaderFmt);
|
|
pszNoneMatch = new char [dwNoneMatch+1];
|
|
wsprintf(pszNoneMatch, cszHeaderFmt, szNONEMATCH, pcdl->GetLocalVersionEtag());
|
|
|
|
dwLen += dwNoneMatch;
|
|
}
|
|
|
|
if (m_pdl->DoPost()) {
|
|
dwLen += sizeof(szFORM);
|
|
}
|
|
|
|
if (dwLen) {
|
|
|
|
szAHdrs = new WCHAR [dwLen + 1];
|
|
|
|
if (!szAHdrs) {
|
|
m_pdl->SetResponseHeaderStatus( E_OUTOFMEMORY );
|
|
|
|
// BUGBUG: Clean all this up to never return right away, and
|
|
// goto exit to cleanup
|
|
SAFEDELETE(pszNoneMatch);
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|
|
szAHdrs[0] = '\0';
|
|
}
|
|
|
|
if (bSendLastMod) {
|
|
char *szTemp = new char [dwLen + 1];
|
|
|
|
if (!szTemp) {
|
|
hr = E_OUTOFMEMORY;
|
|
delete szAHdrs;
|
|
goto Exit;
|
|
}
|
|
|
|
wsprintf(szTemp, cszHeaderFmt, szIfMod, szHttpDate);
|
|
MultiByteToWideChar(CP_ACP, 0, szTemp, -1, szAHdrs, dwLen);
|
|
|
|
delete szTemp;
|
|
|
|
}
|
|
|
|
if (bSendNoneMatch) {
|
|
MultiByteToWideChar(CP_ACP, 0, pszNoneMatch, -1, szAHdrs, dwLen);
|
|
}
|
|
|
|
if (m_pdl->DoPost()) {
|
|
StrCatW(szAHdrs, szFORM);
|
|
}
|
|
|
|
if (*szAcceptLanguage != L'\0')
|
|
{
|
|
StrCatW(szAHdrs, szAcceptLanguage);
|
|
}
|
|
|
|
Exit:
|
|
|
|
SAFEDELETE(pszNoneMatch);
|
|
|
|
*pszAdditionalHeaders = szAHdrs;
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CBindStatusCallback::OnResponse
|
|
// ---------------------------------------------------------------------------
|
|
STDMETHODIMP
|
|
CBindStatusCallback::OnResponse(
|
|
DWORD dwResponseCode,
|
|
LPCWSTR szResponseHeaders,
|
|
LPCWSTR szRequestHeaders,
|
|
LPWSTR *pszAdditionalRequestHeaders)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Hresult,
|
|
"CBindStatusCallback::IHttpNegotiate::OnResponse",
|
|
"this=%#x, %#x, %.80wq, %.80wq, %#x",
|
|
this, dwResponseCode, szResponseHeaders, szRequestHeaders, pszAdditionalRequestHeaders
|
|
));
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
// propogate errors here to CSBC::OnStopBinding
|
|
// we need this as urlmon might just convert any error returned here
|
|
// as user_cancelled
|
|
if (dwResponseCode != HTTP_STATUS_OK) {
|
|
if (dwResponseCode == HTTP_STATUS_NOT_MODIFIED) {
|
|
hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
|
|
} else {
|
|
hr = HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND);
|
|
}
|
|
m_pdl->SetResponseHeaderStatus( hr );
|
|
}
|
|
|
|
if (m_pdl->DoPost() ||
|
|
(m_pdl->GetMoniker() == m_pdl->GetCodeDownload()->GetContextMoniker())){
|
|
|
|
// Get the HttpQueryInfo wrapper object.
|
|
IWinInetHttpInfo *pHttpInfo = NULL;
|
|
HRESULT hr = GetBinding()->QueryInterface
|
|
(IID_IWinInetHttpInfo, (void **) &pHttpInfo);
|
|
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
DWORD cbLen = INTERNET_RFC1123_BUFSIZE + 1;
|
|
char szHttpDate[INTERNET_RFC1123_BUFSIZE+1];
|
|
|
|
|
|
if ((pHttpInfo->QueryInfo (HTTP_QUERY_LAST_MODIFIED,
|
|
(LPVOID)szHttpDate, &cbLen, NULL, 0) == S_OK) && cbLen)
|
|
m_pdl->GetCodeDownload()->SetLastModifiedTime(szHttpDate);
|
|
|
|
cbLen = 0; // reset
|
|
|
|
if ( (pHttpInfo->QueryInfo (HTTP_QUERY_ETAG,
|
|
(LPVOID)NULL, &cbLen, NULL, 0) == S_OK) && cbLen) {
|
|
|
|
char *pbEtag = new char [cbLen +1];
|
|
|
|
if (pbEtag)
|
|
{
|
|
*pbEtag = '\0'; // clr
|
|
|
|
pHttpInfo->QueryInfo (HTTP_QUERY_ETAG,
|
|
(LPVOID)pbEtag, &cbLen, NULL, 0);
|
|
|
|
if (*pbEtag)
|
|
m_pdl->GetCodeDownload()->SetEtag(pbEtag);
|
|
}
|
|
}
|
|
|
|
pHttpInfo->Release();
|
|
}
|
|
}
|
|
|
|
DEBUG_LEAVE(S_OK);
|
|
return S_OK;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CBindStatusCallback::GetCatalogFile
|
|
// ---------------------------------------------------------------------------
|
|
STDMETHODIMP CBindStatusCallback::GetCatalogFile(LPSTR *ppszCatalogFile)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Hresult,
|
|
"CBindStatusCallback::ICatalogFileInfo::GetCatalogFile",
|
|
"this=%#x, %#x",
|
|
this, ppszCatalogFile
|
|
));
|
|
|
|
HRESULT hr = S_OK;
|
|
LPSTR pszCatFile = NULL;
|
|
|
|
if (ppszCatalogFile) {
|
|
pszCatFile = m_pdl->GetCodeDownload()->GetCatalogFile();
|
|
if (pszCatFile) {
|
|
*ppszCatalogFile = new char[lstrlen(pszCatFile) + 1];
|
|
if (*ppszCatalogFile == NULL) {
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
else {
|
|
lstrcpy(*ppszCatalogFile, pszCatFile);
|
|
}
|
|
}
|
|
else {
|
|
*ppszCatalogFile = NULL;
|
|
}
|
|
}
|
|
else {
|
|
hr = E_INVALIDARG;
|
|
}
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// %%Function: CBindStatusCallback::GetJavaTrust
|
|
// ---------------------------------------------------------------------------
|
|
STDMETHODIMP CBindStatusCallback::GetJavaTrust(void **ppJavaTrust)
|
|
{
|
|
DEBUG_ENTER((DBG_DOWNLOAD,
|
|
Hresult,
|
|
"CBindStatusCallback::ICatalogFileInfo::GetJavaTrust",
|
|
"this=%#x, %#x",
|
|
this, ppJavaTrust
|
|
));
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (ppJavaTrust) {
|
|
*ppJavaTrust = (void *)m_pdl->GetCodeDownload()->GetJavaTrust();
|
|
}
|
|
else {
|
|
hr = E_INVALIDARG;
|
|
}
|
|
|
|
DEBUG_LEAVE(hr);
|
|
return hr;
|
|
}
|
|
|