|
|
// ===========================================================================
// 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; }
|