2025-04-27 07:49:33 -04:00

1850 lines
56 KiB
C++

// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 2000
//
// File: aucatalog.cpp
//
// Purpose: AU catalog file using IU
//
// Creator: WeiW
//
// History: 08-15-01 first created
//
//--------------------------------------------------------------------------
#include "pch.h"
#pragma hdrstop
const LPTSTR ITEM_FILE = _T("item.xml");
const LPTSTR DRIVERS_FILE = _T("drivers.xml");
const LPTSTR CATALOG_FILE = _T("catalog.xml");
const LPTSTR DETAILS_FILE = _T("details.xml");
//following files are write once and never be read.
#ifdef DBG
const LPTSTR DRIVER_SYSSPEC_FILE = _T("driversys.xml");
const LPTSTR NONDRIVER_SYSSPEC_FILE = _T("nondriversys.xml");
const LPTSTR PROVIDER_FILE = _T("provider.xml");
const LPTSTR PRODUCT_FILE = _T("product.xml");
const LPTSTR DETECT1_FILE = _T("detect1.xml");
const LPTSTR DETECT2_FILE = _T("detect2.xml");
const LPTSTR DETECT3_FILE = _T("detect3.xml");
const LPTSTR INSTALL_FILE = _T("install.xml");
#endif
#ifdef DBG
const TCHAR REG_AUCATLIFESPAN[] = _T("CatLifeSpan"); //REG_DWORD
const TCHAR REG_AUCATOFFLINELIFESPAN[] = _T("CatOfflineLifeSpan"); //REG_DWORD
#endif
BSTR AUCatalog::AUPROVIDERQUERY;
BSTR AUCatalog::AUPRODUCTQUERY;
BSTR AUCatalog::AUITEMQUERY;
BSTR AUCatalog::AUDETAILSQUERY;
BSTR AUCatalog::AUDRIVERSQUERY;
BSTR AUCatalog::PRODUCT_PRUNE_PATTERN;
BSTR AUCatalog::DETAILS_PRUNE_PATTERN;
BSTR AUCatalog::AUDRIVERSYSCLASS;
BSTR AUCatalog::AUNONDRIVERSYSCLASS;
BSTR AUCatalog::bstrParentItems;
BSTR AUCatalog::bstrItemID;
BSTR AUCatalog::bstrTagAUCATALOG;
BSTR AUCatalog::bstrAttrVERSION;
BSTR AUCatalog::bstrAttrDOWNLOADID;
BSTR AUCatalog::bstrAttrITEMCOUNT;
BSTR AUCatalog::bstrAttrUpdateDriver;
BSTR AUCatalog::bstrAttrSTATUS;
BSTR AUCatalog::bstrHiddenItems;
BSTR AUCatalog::bstrTagITEM;
BSTR AUCatalog::bstrAttrID;
BSTR AUCatalog::bstrProviderNamePattern;
BSTR AUCatalog::bstrItemIDPattern;
BSTR AUCatalog::bstrTitlePattern;
BSTR AUCatalog::bstrDescPattern;
BSTR AUCatalog::bstrRTFUrlPattern;
BSTR AUCatalog::bstrEulaUrlPattern;
BSTR AUCatalog::bstrExclusiveItemPattern;
BSTR AUCatalog::bstrItemIdsPattern;
BSTR AUCatalog::bstrTemplate;
BSTR AUCatalog::bstrResultTemplate;
BSTR AUCatalog::bstrCatalog;
inline BOOL FServiceShuttingDown()
{
return WaitForSingleObject(ghServiceFinished, 0) == WAIT_OBJECT_0;
}
#ifdef DBG
inline BOOL fDBGUseLocalFile()
{
DWORD dwLevel;
if (FAILED(GetRegDWordValue(TEXT("UseLocalFile"), &dwLevel)) || 1 != dwLevel)
{
return FALSE;
}
return TRUE;
}
#endif
AUCatalog::~AUCatalog(void)
{
Clear();
SafeFreeBSTR(m_bstrClientInfo);
SafeFreeBSTR(m_bstrDriverClientInfo);
}
//always called before any other method on AUCatalog is used.
HRESULT AUCatalog::Init()
{
HRESULT hr = S_OK;
m_fNeedToContinueJob = FALSE;
m_bstrInstallation = NULL;
m_fUpdateDriver = !gpState->fWin2K();
m_dwCatLifeSpan = CATALOG_LIFESPAN;
m_dwOfflineCatLifeSpan = CATALOG_OFFLINE_LIFESPAN;
ZeroMemory(&m_stExpireTime, sizeof(m_stExpireTime)) ;
ZeroMemory(&m_stOfflineExpireTime, sizeof(m_stOfflineExpireTime));
m_bstrClientInfo = SysAllocString(AUCLIENTINFO);
m_bstrDriverClientInfo = SysAllocString(AUDRIVERCLIENTINFO);
if (NULL == m_bstrClientInfo || NULL == m_bstrDriverClientInfo)
{
DEBUGMSG("AUCatalog::Init() fail to alloc string for client info");
hr = E_FAIL;
goto end;
}
#ifdef DBG
if (FAILED(GetRegDWordValue(REG_AUCATLIFESPAN, &m_dwCatLifeSpan)))
{
m_dwCatLifeSpan = CATALOG_LIFESPAN;
}
if (FAILED(GetRegDWordValue(REG_AUCATOFFLINELIFESPAN, &m_dwOfflineCatLifeSpan)))
{
m_dwOfflineCatLifeSpan = CATALOG_OFFLINE_LIFESPAN;
}
#endif
end:
return hr;
}
//////////////////////////////////////////////////////////////////////
// clear out more dynamic internal data
/////////////////////////////////////////////////////////////////////
void AUCatalog::Clear()
{
m_ItemList.Clear();
SafeFreeBSTRNULL(m_bstrInstallation);
ZeroMemory(&m_stExpireTime, sizeof(m_stExpireTime));
ZeroMemory(&m_stOfflineExpireTime, sizeof(m_stOfflineExpireTime));
}
HRESULT AUCatalog::GetSystemSpec(DETECTLEVEL enLevel, BSTR * pbstrSysSpec)
{
HRESULT hr = E_FAIL;
if (FServiceShuttingDown())
{
DEBUGMSG("Skip AUCatalog::GetSystemSpec() because service is shutting down");
hr = E_ABORT;
goto done;
}
BSTR bstrSysClass = (DRIVERS_LEVEL == enLevel) ? AUDRIVERSYSCLASS : AUNONDRIVERSYSCLASS;
hr = m_pfnGetSystemSpec(m_hIUEngineInst, bstrSysClass, 0, pbstrSysSpec); //online mode
#ifdef DBG
if (SUCCEEDED(hr))
{
LOGXMLFILE((DRIVERS_LEVEL == enLevel) ? DRIVER_SYSSPEC_FILE : NONDRIVER_SYSSPEC_FILE, *pbstrSysSpec);
}
#endif
done:
return hr;
}
////////////////////////////////////////////////////////////////////////////////
// compose query based on a format and items picked out from detection result
//
HRESULT AUCatalog::GetQuery(IN DETECTLEVEL enLevel, IN BSTR bstrDetectResult, OUT BSTR *pbstrQuery)
{
BSTR bstrPrunePattern;
BSTR bstrQuery = NULL;
HRESULT hr = S_OK;
IXMLDOMNodeList *pItems = NULL;
IXMLDOMNode *pParentItems = NULL;
IXMLDOMDocument *pQueryXML= NULL;
IXMLDOMDocument *pResultXML= NULL;
DEBUGMSG("GetQuery() starts");
AUASSERT(NULL != pbstrQuery);
*pbstrQuery = NULL;
switch (enLevel)
{
case PROVIDER_LEVEL:
bstrQuery = AUPROVIDERQUERY;
break;
case DRIVERS_LEVEL:
bstrQuery = AUDRIVERSQUERY;
break;
case PRODUCT_LEVEL:
bstrQuery = AUPRODUCTQUERY;
bstrPrunePattern = PRODUCT_PRUNE_PATTERN;
break;
case ITEM_LEVEL:
bstrQuery = AUITEMQUERY;
bstrPrunePattern = PRODUCT_PRUNE_PATTERN; //the same as product pruning logic
break;
case DETAILS_LEVEL:
bstrQuery = AUDETAILSQUERY;
bstrPrunePattern = DETAILS_PRUNE_PATTERN;
break;
default:
AUASSERT(FALSE); //should never be here
return E_INVALIDARG;
}
if (FAILED(hr = LoadXMLDoc(bstrQuery, &pQueryXML, TRUE)))
{
DEBUGMSG("GetQuery() fail to load query XML with error %#lx", hr);
goto done;
}
if (enLevel != PROVIDER_LEVEL && DRIVERS_LEVEL != enLevel)
{
if (FAILED(hr = LoadXMLDoc(bstrDetectResult, &pResultXML, TRUE)))
{
DEBUGMSG("GetQuery() fail to load XML for detect result with error %#lx", hr);
goto done;
}
if (FAILED(hr = pResultXML->selectNodes(bstrPrunePattern, &pItems)))
{
DEBUGMSG("GetQuery() fail to select node or nothing to select with error %#lx", hr);
goto done;
}
long lLen = 0;
if (FAILED(hr = pItems->get_length(&lLen)))
{
DEBUGMSG("GetQuery() fail to get item number with error %#lx", hr);
goto done;
}
DEBUGMSG("GetQuery(): pruning result %d items", lLen);
if (0 == lLen)
{
DEBUGMSG("No updates applicable");
hr = S_FALSE;
goto done;
}
if (S_OK != (hr = pQueryXML->selectSingleNode(bstrParentItems, &pParentItems)))
{
DEBUGMSG("GetQuery() fail to select single node %#lx or nothing to select", hr);
hr = E_FAIL;
goto done;
}
for (int i = 0; i < lLen; i++)
{
IXMLDOMNode *pIdentity1 = NULL;
IXMLDOMNode *pItemStatus;
if (S_OK != (hr = pItems->get_item(i, &pItemStatus)))
{
hr = FAILED(hr) ? hr : E_FAIL;
goto done;
}
hr = pItemStatus->selectSingleNode(bstrItemID, &pIdentity1);
pItemStatus->Release();
if (FAILED(hr) || NULL == pIdentity1)
{
DEBUGMSG("GetQuery() fail to select itemID with error %#lx", hr);
hr = FAILED(hr) ? hr : E_FAIL;
goto done;
}
if (NULL == pIdentity1)
{
DEBUGMSG("GetQuery() fail to select itemID");
hr = E_FAIL;
goto done;
}
{
BSTR bstrItemId = NULL;
IXMLDOMElement *pItem= NULL;
IXMLDOMText *pItemIdText = NULL;
if (S_OK != (hr = pIdentity1->get_text(&bstrItemId)))
{
DEBUGMSG("Fail to get text for item");
hr = FAILED(hr) ? hr : E_FAIL;
}
else if (FAILED(hr = pQueryXML->createTextNode(bstrItemId, &pItemIdText)))
{
DEBUGMSG("Fail to create text node");
}
else if (FAILED (hr = pQueryXML->createElement(KEY_ITEM, &pItem)))
{
DEBUGMSG("GetQuery() fail to create element");
}
else if (FAILED(hr = pItem->appendChild(pItemIdText, NULL)))
{
DEBUGMSG("Fail to append child");
}
else if (FAILED(hr = pParentItems->appendChild(pItem, NULL)))
{
DEBUGMSG("Fail to append child with error %#lx", hr);
}
SafeRelease(pItem);
SafeRelease(pItemIdText);
SafeFreeBSTR(bstrItemId);
pIdentity1->Release();
if (FAILED(hr))
{
goto done;
}
}
}
}
if (FAILED(hr = pQueryXML->get_xml(pbstrQuery)))
{
DEBUGMSG("Fail to get query xml with error %#lx", hr);
goto done;
}
done:
// DEBUGMSG("GetQuery(): Query string is %S", *pbstrQuery);
SafeRelease(pItems);
SafeRelease(pParentItems);
SafeRelease(pQueryXML);
SafeRelease(pResultXML);
if (FAILED(hr))
{
SafeFreeBSTRNULL(*pbstrQuery);
}
return hr;
}
HRESULT AUCatalog::DoDetection(IN DETECTLEVEL enLevel, IN BSTR bstrCatalog, OUT BSTR *pbstrResult, IN BOOL fOnline)
{
HRESULT hr = E_FAIL;
#ifdef DBG
DWORD dwStart = GetTickCount();
#endif
AUASSERT(m_pfnDetect != NULL);
AUASSERT(bstrCatalog != NULL);
AUASSERT(m_hIUEngineInst != NULL);
AUASSERT(NULL != pbstrResult);
*pbstrResult = NULL;
if (FServiceShuttingDown())
{
DEBUGMSG("Skip AUCatalog::DoDetection() because service is shutting down");
hr = E_ABORT;
goto done;
}
hr = m_pfnDetect(m_hIUEngineInst, bstrCatalog, fOnline ? 0 : FLAG_OFFLINE_MODE, pbstrResult);
#ifdef DBG
if (SUCCEEDED(hr))
{
switch (enLevel)
{
case PROVIDER_LEVEL:
LOGXMLFILE(DETECT1_FILE, *pbstrResult);
break;
case PRODUCT_LEVEL:
LOGXMLFILE(DETECT2_FILE, *pbstrResult);
break;
case ITEM_LEVEL:
LOGXMLFILE(DETECT3_FILE, *pbstrResult);
break;
default:
AUASSERT(FALSE);
hr = E_INVALIDARG;
break;
}
}
#endif
done:
#ifdef DBG
DEBUGMSG("DoDetection() take %d msecs", GetTickCount() - dwStart);
#endif
if (FAILED(hr))
{
SafeFreeBSTRNULL(*pbstrResult);
}
return hr;
}
LPCTSTR AUCatalog::GetLogFile(IN DETECTLEVEL enLevel)
{
switch (enLevel)
{
#ifdef DBG
case PROVIDER_LEVEL:
return PROVIDER_FILE;
case PRODUCT_LEVEL:
return PRODUCT_FILE;
#endif
case ITEM_LEVEL:
return ITEM_FILE;
case DETAILS_LEVEL:
return DETAILS_FILE;
case DRIVERS_LEVEL:
return DRIVERS_FILE;
default:
return NULL;
}
}
HRESULT AUCatalog::GetManifest(IN DETECTLEVEL enLevel, IN BSTR bstrDetectResult, OUT BSTR *pbstrManifest)
{
HRESULT hr = E_FAIL;
BSTR bstrQuery = NULL;
#ifdef DBG
DWORD dwStart= GetTickCount();
#endif
AUASSERT(NULL != m_pfnGetManifest);
*pbstrManifest = NULL;
if (FServiceShuttingDown())
{
DEBUGMSG("Skip AUCatalog::GetManifest() because service is shutting down");
hr = E_ABORT;
goto done;
}
if (S_OK != (hr = GetQuery(enLevel, bstrDetectResult, &bstrQuery)))
{
goto done;
}
BSTR bstrSysSpec = NULL;
if (FAILED(hr = GetSystemSpec(enLevel, &bstrSysSpec)))
{
goto done;
}
DEBUGMSG("WUAUENG: Calling IU getmanifest()....");
hr = m_pfnGetManifest(m_hIUEngineInst, (DRIVERS_LEVEL == enLevel) ? m_bstrDriverClientInfo :m_bstrClientInfo,
bstrSysSpec, bstrQuery, FLAG_USE_COMPRESSION, pbstrManifest); //compression on
DEBUGMSG("WUAUENG: IU getmanifest() done");
SysFreeString(bstrSysSpec);
if (FAILED(hr))
{
goto done;
}
LPCTSTR ptszLogFile = GetLogFile(enLevel);
if (NULL != ptszLogFile)
{
if (FAILED(hr = LOGXMLFILE(ptszLogFile, *pbstrManifest)))
{
goto done;
}
}
done:
SafeFreeBSTR(bstrQuery);
#ifdef DBG
DEBUGMSG("GetManifest() take %d msecs", GetTickCount() - dwStart);
#endif
if (FAILED(hr))
{
SafeFreeBSTRNULL(*pbstrManifest);
}
return hr;
}
HRESULT AUCatalog::DownloadItems()
{
// USES_CONVERSION;
HRESULT hr = S_OK;
CItemDetails itemdetails;
UINT uItemCount;
DEBUGMSG("AUCatalog downloading items...");
PersistHiddenItems(m_ItemList, URLLOGACTIVITY_Download);
if (m_fNeedToContinueJob)
{
m_fNeedToContinueJob = FALSE;
if (SUCCEEDED(m_audownloader.ContinueLastDownloadJob()))
{
DEBUGMSG("found previous download job, reconnecting succeed");
goto end;
}
}
#ifdef DBG
else
{
DEBUGMSG("no previous download job found");
}
#endif
DWORD dwNumSelected = m_ItemList.GetNumSelected();
if (0 == dwNumSelected)
{
hr = S_FALSE;
DEBUGMSG("Nothing to download, bail out");
goto end;
}
if (NULL == m_bstrInstallation)
{
DEBUGMSG("AUCatalog::DownloadItems() can't get installation xml");
hr = E_FAIL;
goto end;
}
if (!itemdetails.Init(m_bstrInstallation))
{
hr = E_FAIL;
DEBUGMSG("fail to init itemdetails");
goto end;
}
for (UINT i = 0; i < m_ItemList.Count(); i++)
{
AUCatalogItem &item = m_ItemList[i];
if (item.fSelected() || m_ItemList.ItemIsRelevant(i))
{
BSTR * pCRCCabNames, *pRealCabNames, *pCabChecksums;
UINT uCabsNum;
BSTR bstrItemId = item.bstrID();
BSTR bstrItemDownloadPath = itemdetails.GetItemDownloadPath(bstrItemId);
if (NULL == bstrItemDownloadPath)
{
DEBUGMSG("fail to build item downloadPath");
hr = E_FAIL;
goto end;
}
if (SUCCEEDED(hr = itemdetails.GetCabNames(bstrItemId, &pCRCCabNames, &pRealCabNames, &pCabChecksums, &uCabsNum)))
{
DEBUGMSG("Need to download following files for %S", bstrItemId);
for (UINT j = 0; j < uCabsNum; j++)
{
TCHAR szFullFileName[MAX_PATH];
if (SUCCEEDED(hr) &&
SUCCEEDED(hr = StringCchCopyEx(szFullFileName, ARRAYSIZE(szFullFileName), W2T(bstrItemDownloadPath), NULL, NULL, MISTSAFE_STRING_FLAGS)))
{
if (SUCCEEDED(hr = PathCchAppend(szFullFileName, ARRAYSIZE(szFullFileName), W2T(pRealCabNames[j]))))
{
hr = m_audownloader.QueueDownloadFile(W2T(pCRCCabNames[j]), szFullFileName);
}
}
DEBUGMSG(" from %S to %S", pCRCCabNames[j], szFullFileName);
SafeFreeBSTR(pCRCCabNames[j]);
SafeFreeBSTR(pRealCabNames[j]);
SafeFreeBSTR(pCabChecksums[j]);
}
free(pCRCCabNames);
free(pRealCabNames);
free(pCabChecksums);
}
#ifdef DBG
else
{
DEBUGMSG("fail to get cab names for %S", bstrItemId);
}
#endif
SysFreeString(bstrItemDownloadPath);
if (FAILED(hr))
{
goto end;
}
}
}
if (SUCCEEDED(hr = m_audownloader.StartDownload()))
{
Serialize(); //serialize download id
}
end:
itemdetails.Uninit();
if (FAILED(hr))
{
m_audownloader.Reset();
}
DEBUGMSG("AUCatalog downloading items done");
return hr;
}
char * AUCatalog::GetLevelStr(DETECTLEVEL enLevel)
{
switch (enLevel)
{
case PROVIDER_LEVEL: return "Provider";
case PRODUCT_LEVEL: return "Product";
case ITEM_LEVEL: return "Item";
case DETAILS_LEVEL: return "ItemDetails";
default: return NULL;
}
}
BOOL AUCatalog::hasExpired(BOOL fOffline)
{
SYSTEMTIME stTmp ;
SYSTEMTIME stExpire;
ZeroMemory(&stTmp, sizeof(stTmp));
stExpire = fOffline ? m_stOfflineExpireTime : m_stExpireTime;
GetSystemTime(&stTmp);
#ifdef DBG
TCHAR szExpireTime[80], szCurrentTime[80];
if (SUCCEEDED(SystemTime2String(stExpire, szExpireTime, ARRAYSIZE(szExpireTime)))
&& SUCCEEDED(SystemTime2String(stTmp, szCurrentTime, ARRAYSIZE(szCurrentTime))))
{
DEBUGMSG("AUCatalog::hasExpired() expire time is %S current time is %S", szExpireTime, szCurrentTime);
}
#endif
return TimeDiff(stExpire, stTmp) >= 0;
}
HRESULT AUCatalog::setExpireTime(BOOL fOffline)
{
SYSTEMTIME stCurrent;
HRESULT hr = E_FAIL;
GetSystemTime(&stCurrent);
if (FAILED(hr = TimeAddSeconds(stCurrent, dwSecsToWait(m_dwOfflineCatLifeSpan), &m_stOfflineExpireTime)))
{
DEBUGMSG("Fail to calculate m_stOfflineExpireTime with error %#lx", hr);
goto done;
}
if (!fOffline)
{
if (FAILED(hr = TimeAddSeconds(stCurrent, dwSecsToWait(m_dwCatLifeSpan), &m_stExpireTime)))
{
DEBUGMSG("Fail to calculate m_stExpireTime with error %#lx", hr);
goto done;
}
}
#ifdef DBG
TCHAR szCurrentTime[80], szExpireTime[80];
if (SUCCEEDED(SystemTime2String(stCurrent, szCurrentTime, ARRAYSIZE(szCurrentTime)))
&& SUCCEEDED(SystemTime2String(m_stOfflineExpireTime, szExpireTime, ARRAYSIZE(szExpireTime))))
{
DEBUGMSG("AUCatalog::setExpireTime with current time %S and expire time %S", szCurrentTime, szExpireTime);
}
#endif
hr = S_OK;
done:
if (FAILED(hr))
{
ZeroMemory(&m_stOfflineExpireTime, sizeof(m_stOfflineExpireTime));
ZeroMemory(&m_stExpireTime, sizeof(m_stOfflineExpireTime));
}
return hr;
}
//when m_fUpdateDriver is FALSE, bstrDrivers are not looked at
HRESULT AUCatalog::ValidateOffline(BSTR bstrItems, BSTR bstrDrivers)
{
HRESULT hr= E_FAIL;
BSTR bstrResult = NULL;
BSTR bstrQuery = NULL;
IXMLDOMDocument *pQueryXml = NULL;
IXMLDOMDocument *pDriversXml = NULL;
// DEBUGMSG("ValidateOffline starts");
if (0 == m_ItemList.Count())
{
hr = S_FALSE;
goto done; //no need to validate
}
if (FAILED(hr = PrepareIU(FALSE)))
{
DEBUGMSG(" fail to prepare IU offline with error %#lx", hr);
goto done;
}
if (FAILED(hr = DoDetection(ITEM_LEVEL, bstrItems, &bstrResult, FALSE)))
{
DEBUGMSG("Fail to detect items with error %#lx", hr);
goto done;
}
if (S_OK != (hr = GetQuery(DETAILS_LEVEL, bstrResult, &bstrQuery)))
{
goto done;
}
// DEBUGMSG("Query Result is %S", bstrQuery);
if (FAILED(hr = LoadXMLDoc(bstrQuery, &pQueryXml, TRUE)) ||
(m_fUpdateDriver && FAILED(hr = LoadXMLDoc(bstrDrivers, &pDriversXml, TRUE)))) //offline
{
DEBUGMSG("Fail to load xml with error %#lx", hr);
goto done;
}
for (UINT u = 0; u < m_ItemList.Count(); u++)
{
IXMLDOMNode *pItemIdentityNode1 = NULL;
IXMLDOMNode *pItemNode2 = NULL;
CAU_BSTR aubsItemPattern;
CAU_BSTR aubsDriverItemIdentityPattern;
if (!aubsDriverItemIdentityPattern.append(L"/catalog/provider/item/identity[@itemID=\"") || !aubsDriverItemIdentityPattern.append(m_ItemList[u].bstrID()) || !aubsDriverItemIdentityPattern.append(L"\"]"))
{
DEBUGMSG("failed to create driver pattern string");
hr = E_OUTOFMEMORY;
goto done;
}
if (!aubsItemPattern.append(L"/query/dObjQueryV1/parentItems/item[.=\"") || !aubsItemPattern.append(m_ItemList[u].bstrID()) || !aubsItemPattern.append(L"\"]"))
{
DEBUGMSG("OUT OF MEMORY and failed to create pattern string");
hr = E_OUTOFMEMORY;
goto done;
}
if ((m_fUpdateDriver && HRESULT_FROM_WIN32(ERROR_NOT_FOUND) == FindSingleDOMNode(pDriversXml, aubsDriverItemIdentityPattern, &pItemIdentityNode1)
&& HRESULT_FROM_WIN32(ERROR_NOT_FOUND) == FindSingleDOMNode(pQueryXml, aubsItemPattern, &pItemNode2)) ||
(!m_fUpdateDriver && HRESULT_FROM_WIN32(ERROR_NOT_FOUND) == FindSingleDOMNode(pQueryXml, aubsItemPattern, &pItemNode2)))
{
DEBUGMSG("item %S installed off band, remove it from AU's list", m_ItemList[u].bstrID());
m_ItemList.Remove(m_ItemList[u].bstrID());
}
SafeRelease(pItemIdentityNode1);
SafeRelease(pItemNode2);
}
done:
FreeIU();
SafeFreeBSTR(bstrQuery);
SafeFreeBSTR(bstrResult);
SafeRelease(pQueryXml);
SafeRelease(pDriversXml);
// DEBUGMSG("ValidateOffline ends");
return hr;
}
///////////////////////////////////////////////////////////////////////////////////////
//update internal list to reflect latest applicable items
// return S_FALSE if nothing is appliable anymore
//////////////////////////////////////////////////////////////////////////////////////
HRESULT AUCatalog::ValidateItems(BOOL fOnline )
{
HRESULT hr = S_OK;
BSTR bstrNonDrivers = NULL, bstrDrivers = NULL;
DEBUGMSG("AUCatalog validating items...");
if (fOnline && !hasExpired())
{
DEBUGMSG("Catalog was valid and hasn't expired online. Do offline validation only");
fOnline = FALSE;
}
if (!fOnline && !hasExpired(TRUE))
{
DEBUGMSG("Catalog was valid and hasn't expired offline. No validation needed");
goto done;
}
if (fOnline)
{
//do online detection
DEBUGMSG("Doing online validating");
AUCatalogItemList olditemlist;
if (FAILED(hr = olditemlist.Copy(m_ItemList)))
{
goto done;
}
if (S_OK != (hr = DetectItems(TRUE))) //update instead of building from scratch
{
//fail to detect or no items applicable
goto done;
}
BOOL fItemPulled;
do
{
fItemPulled = FALSE;
UINT uOldListLen = olditemlist.Count();
for (UINT u=0; u < uOldListLen; u++)
{
if (m_ItemList.Contains(olditemlist[u].bstrID()) < 0)
{
DEBUGMSG("item %S is pulled from site", olditemlist[u].bstrID());
olditemlist.Remove(olditemlist[u].bstrID());
fItemPulled = TRUE;
break;
}
}
}
while (fItemPulled);
if (FAILED(hr = m_ItemList.Copy(olditemlist))) //update item list
{
goto done;
}
}
if (NULL == (bstrNonDrivers =ReadXMLFromFile(ITEM_FILE)) ||
(m_fUpdateDriver && (NULL == (bstrDrivers = ReadXMLFromFile(DRIVERS_FILE)))))
{
DEBUGMSG("Fail to read item or drivers xml file ");
hr = E_FAIL;
goto done;
}
if (!fOnline)
{
//do offline validation for non drivers
DEBUGMSG("Doing offline validating");
if (FAILED(hr = ValidateOffline(bstrNonDrivers, bstrDrivers)))
{
DEBUGMSG("Fail to validate offline with error %#lx", hr);
goto done;
}
}
if (m_ItemList.GetNumHidden() == m_ItemList.Count())
{
DEBUGMSG("No applicable items left");
hr = S_FALSE;
goto done;
}
if (FAILED(hr = BuildDependencyList(m_ItemList, bstrDrivers, bstrNonDrivers)))
{
DEBUGMSG("Fail to build dependency list with error %#lx", hr);
goto done;
}
setExpireTime(fOnline);
Serialize();
done:
if (S_OK != hr)
{
Clear(); //need to redetect anyway
DelCatFiles();
}
SafeFreeBSTR(bstrNonDrivers);
SafeFreeBSTR(bstrDrivers);
DEBUGMSG("AUCatalog done validating items");
return hr;
}
HRESULT AUCatalog::getUpdatesList(VARIANT OUT *pvarList)
{
SAFEARRAYBOUND bound[1] = { m_ItemList.Count() * 7, 0};
SAFEARRAY * psa = SafeArrayCreate(VT_VARIANT, 1, bound);
VARIANT * grVariant;
BOOL fRet = FALSE;
AUASSERT(NULL != pvarList);
DEBUGMSG("AUCatalog::getUpdateList() starts");
VariantInit(pvarList);
if ( 0 == m_ItemList.Count() )
{
DEBUGMSG("AUCatalog::getUpdateList fails because getNumItems is 0");
goto done;
}
if (NULL == psa || S_OK != SafeArrayAccessData(psa, (void **)&grVariant))
goto done;
BOOL fError = FALSE;
for ( UINT n = 0; n < m_ItemList.Count(); n++ )
{
grVariant[n*7+0].vt = VT_I4;
grVariant[n*7+0].lVal = m_ItemList[n].dwStatus();
grVariant[n*7+1].vt = VT_BSTR;
grVariant[n*7+1].bstrVal = SysAllocString(m_ItemList[n].bstrID());
grVariant[n*7+2].vt = VT_BSTR;
grVariant[n*7+2].bstrVal = SysAllocString(m_ItemList[n].bstrProviderName());
grVariant[n*7+3].vt = VT_BSTR;
grVariant[n*7+3].bstrVal = SysAllocString(m_ItemList[n].bstrTitle());
grVariant[n*7+4].vt = VT_BSTR;
grVariant[n*7+4].bstrVal = SysAllocString(m_ItemList[n].bstrDescription());
grVariant[n*7+5].vt = VT_BSTR;
grVariant[n*7+5].bstrVal = SysAllocString(m_ItemList[n].bstrRTFPath());
grVariant[n*7+6].vt = VT_BSTR;
grVariant[n*7+6].bstrVal = SysAllocString(m_ItemList[n].bstrEULAPath());
if ((NULL != m_ItemList[n].bstrID() && NULL == grVariant[n*7+1].bstrVal)
|| (NULL != m_ItemList[n].bstrProviderName() && NULL == grVariant[n*7+2].bstrVal)
|| (NULL != m_ItemList[n].bstrTitle() && NULL == grVariant[n*7+3].bstrVal)
|| (NULL != m_ItemList[n].bstrDescription() && NULL == grVariant[n*7+4].bstrVal)
|| (NULL != m_ItemList[n].bstrRTFPath() && NULL == grVariant[n*7+5].bstrVal)
|| (NULL != m_ItemList[n].bstrEULAPath() && NULL == grVariant[n*7+6].bstrVal))
{
DEBUGMSG("OUT OF MEMORY, Fail to allocate string");
fError = TRUE;
break;
}
}
if (FAILED(SafeArrayUnaccessData(psa)))
{
goto done;
}
if (!fError)
{
fRet = TRUE;
pvarList->vt = VT_ARRAY | VT_VARIANT;
pvarList->parray = psa;
}
done:
DEBUGMSG("AUCatalog::getUpdateList() ends");
if (!fRet && NULL != psa)
{
SafeArrayDestroy(psa);
}
return (fRet ? S_OK : E_FAIL);
}
//if udpate, meaning get updated information about existing items. Used in online validation. Treat exclusive and non exclusive the same
//if not update, meaning building a fresh new item list
//return S_FALSE if nothing applicable
HRESULT AUCatalog::DetectItems(BOOL fUpdate )
{
HRESULT hr;
BSTR bstrNonDriverInstall = NULL, bstrDriverInstall = NULL;
AUCatalogItemList nonDriverList, driverList;
BOOL fExclusiveItemFound = FALSE;
BOOL fExclusiveDriverFound = FALSE;
DEBUGMSG("CAUCatalog::DetectItems() starts");
//clean up memory and local disk
Clear();
DelCatFiles(fUpdate);
if (FAILED(hr = PrepareIU()))
{
DEBUGMSG("AUCatalog::DetectItems() fail to prepare IU %#lx", hr);
goto done;
}
if (FAILED(hr = DetectNonDriverItems(&bstrNonDriverInstall, nonDriverList, &fExclusiveItemFound)))
{
if (E_ABORT != hr)
{
DEBUGMSG(" fail to detect non driver updates %#lx", hr);
}
goto done;
}
DEBUGMSG("Non driver items got");
if (m_fUpdateDriver)
{
if (FAILED(hr = DetectDriverItems(&bstrDriverInstall, driverList, &fExclusiveDriverFound)))
{
if (E_ABORT != hr)
{
DEBUGMSG("fail to detect driver updates %#lx", hr);
DEBUGMSG("consider driver update not essential, continue even if it fails");
//consider driver update not essential, continue even if it fails
m_fUpdateDriver = FALSE; //from now on in this cycle do not care about driver any more
}
else
{
goto done; //bail out if service shutdown
}
}
DEBUGMSG("Driver items got");
}
else
{
DEBUGMSG("Driver updates not supported");
}
if (fExclusiveItemFound)
{
AUCatalogItemList dummydriverList;
hr = MergeDetectionResult(NULL, dummydriverList, FALSE, bstrNonDriverInstall, nonDriverList, fExclusiveItemFound);
DEBUGMSG("Exclusive item found");
}
else if (fExclusiveDriverFound)
{
AUCatalogItemList dummynonDriverList;
hr = MergeDetectionResult(bstrDriverInstall, driverList, fExclusiveDriverFound, NULL, dummynonDriverList, FALSE);
DEBUGMSG("Exclusive driver found");
}
else
{
hr = MergeDetectionResult(bstrDriverInstall, driverList, fExclusiveDriverFound, bstrNonDriverInstall, nonDriverList, fExclusiveItemFound);
DEBUGMSG("Merge detection result for non driver and driver");
}
if (FAILED(hr))
{
DEBUGMSG("MergeDetectionResult fail with error %#lx", hr);
goto done;
}
if (m_ItemList.Count() == m_ItemList.GetNumHidden())
{ //nothing to show to the user
hr = S_FALSE;
goto done;
}
#ifdef DBG
// m_ItemList.DbgDump();
#endif
if (!fUpdate)
{
BSTR bstrNonDrivers;
if (NULL == (bstrNonDrivers =ReadXMLFromFile(ITEM_FILE)))
{
DEBUGMSG("Fail to read item file ");
goto done;
}
hr = BuildDependencyList(m_ItemList, bstrDriverInstall, bstrNonDrivers);
SysFreeString(bstrNonDrivers);
if (FAILED(hr))
{
DEBUGMSG("fail to build dependency list with error %#lx", hr);
goto done;
}
hr = DownloadRTFsnEULAs(GetSystemDefaultLangID());
DEBUGMSG("downloading RTF and EULAs %s", FAILED(hr)? "failed" : "succeeded");
setExpireTime();
Serialize();
}
done:
FreeIU();
SafeFreeBSTR(bstrNonDriverInstall);
SafeFreeBSTR(bstrDriverInstall);
if (FAILED(hr))
{
Clear();
}
DEBUGMSG("CAUCatalog::DetectItems() ends");
return hr;
}
HRESULT AUCatalog::MergeDetectionResult(BSTR bstrDriverInstall, AUCatalogItemList & driverlist, BOOL fExclusiveDriverFound, BSTR bstrNonDriverInstall, AUCatalogItemList & nondriverlist, BOOL fExclusiveItemFound)
{
HRESULT hr= S_OK;
UINT uDriverNum = driverlist.Count();
UINT uNonDriverNum = nondriverlist.Count();
UINT nums[2] = {uDriverNum, uNonDriverNum};
AUCatalogItemList * pitemlists[2] = {&driverlist, &nondriverlist};
if (fExclusiveDriverFound || fExclusiveItemFound)
{ //no merge needed
DEBUGMSG("Exclusive driver or non driver found, no need to merge");
AUCatalogItemList *pItemList = fExclusiveDriverFound ? &driverlist : & nondriverlist;
BSTR bstrInstall = fExclusiveDriverFound? bstrDriverInstall : bstrNonDriverInstall;
if (FAILED(hr = m_ItemList.Copy(*pItemList)))
{
goto done;
}
if (NULL == (m_bstrInstallation = SysAllocString(bstrInstall)))
{
hr = E_OUTOFMEMORY;
DEBUGMSG("OUT of memory: fail to alloc string");
goto done;
}
}
else
{
for (UINT j = 0; j < ARRAYSIZE(nums) ; j++)
{
for (UINT i = 0; i < nums[j]; i++)
{
AUCatalogItem * pItem = new AUCatalogItem((*pitemlists[j])[i]);
if (NULL == pItem)
{
DEBUGMSG("Fail to create item");
hr = E_FAIL;
goto done;
}
if (!pItem->fEqual((*pitemlists[j])[i]))
{
DEBUGMSG("Fail to create item");
hr = E_OUTOFMEMORY;
delete pItem;
goto done;
}
if (!m_ItemList.Add(pItem))
{
hr = E_OUTOFMEMORY;
delete pItem;
goto done;
}
}
}
hr = MergeCatalogs(bstrDriverInstall, bstrNonDriverInstall, &m_bstrInstallation);
}
done:
if (FAILED(hr))
{
Clear();
}
return hr;
}
// go through 1 cycle to detect driver items
HRESULT AUCatalog::DetectDriverItems(OUT BSTR *pbstrInstall, OUT AUCatalogItemList &itemList, BOOL *pfFoundExclusiveItem)
{
HRESULT hr = S_OK;
BSTR bstrManifest;
if (NULL == pbstrInstall || NULL == pfFoundExclusiveItem)
{
return E_INVALIDARG;
}
DEBUGMSG("CAUCatalog detecting driver items...");
*pbstrInstall = NULL;
*pfFoundExclusiveItem = FALSE;
itemList.Clear();
#ifdef DBG
if (fDBGUseLocalFile())
{
DEBUGMSG("Use local file instead of going on line");
if (NULL == (bstrManifest = ReadXMLFromFile(DRIVERS_FILE)))
{
DEBUGMSG("fail to get drivers from file %s", DRIVERS_FILE);
hr = E_FAIL;
goto end;
}
}
else
#endif
{
if (FAILED(hr = GetManifest(DRIVERS_LEVEL, NULL, &bstrManifest)))
{
DEBUGMSG(" Fail to get drivers manifest %#lx", hr);
goto end;
}
if (S_FALSE == hr)
{ //no updates applicable
goto end;
}
}
*pbstrInstall = bstrManifest;
if (!fExtractItemInfo(*pbstrInstall, itemList, pfFoundExclusiveItem))
{
DEBUGMSG("fail to extract information for driver items");
hr = E_FAIL;
goto end;
}
#ifdef DBG
// itemList.DbgDump();
#endif
end:
DEBUGMSG("CAUCatalog detecting driver items done");
if (FAILED(hr))
{
SafeFreeBSTRNULL(*pbstrInstall);
*pfFoundExclusiveItem = FALSE;
itemList.Clear();
}
return hr;
}
// go through 4 cycles to detect software items
// get down manifest
HRESULT AUCatalog::DetectNonDriverItems(OUT BSTR *pbstrInstall, OUT AUCatalogItemList &itemList, OUT BOOL *pfFoundExclusiveItem)
{
HRESULT hr = S_OK;
BSTR bstrManifest = NULL;
BSTR bstrResult=NULL;
if (NULL == pbstrInstall || NULL == pfFoundExclusiveItem)
{
return E_INVALIDARG;
}
DEBUGMSG("CAUCatalog detecting non driver items...");
*pbstrInstall = NULL;
*pfFoundExclusiveItem = FALSE;
itemList.Clear();
#ifdef DBG
if (fDBGUseLocalFile())
{
DEBUGMSG("Use local file instead of going on line");
if (NULL == (bstrManifest = ReadXMLFromFile(DETAILS_FILE)))
{
hr = E_FAIL;
DEBUGMSG("Fail to get item details from file %s", DETAILS_FILE);
goto end;
}
}
else
#endif
{
for (int enLevel = MIN_LEVEL; enLevel <= MAX_LEVEL; enLevel++)
{
DEBUGMSG("#%d pass", enLevel+1);
hr = GetManifest((DETECTLEVEL)enLevel, bstrResult, &bstrManifest);
SafeFreeBSTR(bstrResult);
if (FAILED(hr))
{
DEBUGMSG(" Fail to get %s %#lx", GetLevelStr((DETECTLEVEL)enLevel), hr);
goto end;
}
if (S_FALSE == hr)
{
goto end;
}
DEBUGMSG("%s got", GetLevelStr((DETECTLEVEL)enLevel));
if (DETAILS_LEVEL != enLevel)
{
DEBUGMSG("Doing detection........");
hr = DoDetection((DETECTLEVEL)enLevel, bstrManifest, &bstrResult);
SafeFreeBSTR(bstrManifest);
if (FAILED(hr))
{
DEBUGMSG("Fail to do detection %#lx", hr);
goto end;
}
}
}
}
*pbstrInstall = bstrManifest;
if (!fExtractItemInfo(bstrManifest, itemList, pfFoundExclusiveItem))
{
DEBUGMSG("Fail to extract item information for non drivers");
hr = E_FAIL;
goto end;
}
#ifdef DBG
// itemList.DbgDump();
#endif
end:
DEBUGMSG("CAUCatalog detecting non driver items done");
if (FAILED(hr))
{
SafeFreeBSTRNULL(*pbstrInstall);
*pfFoundExclusiveItem = FALSE;
itemList.Clear();
}
if (gpState->fInCorpWU())
{
if (SUCCEEDED(hr))
{
gPingStatus.PingDetectionSuccess(TRUE, itemList.Count());
}
else
{
gPingStatus.PingDetectionFailure(TRUE, hr);
}
}
return hr;
}
//////////////////////////////////////////////////////////////////////////////////////////////
// delete all local cat log files we might use to do offline operation, including item.xml details.xml,
// mergedcatalog.xml, drivers.xml and catalog.xml. If not fUpdate (i.e., will build everything from scratch), also clean up RTFs and Cabs
/////////////////////////////////////////////////////////////////////////////////////////////
void AUCatalog::DelCatFiles(BOOL fUpdate)
{
TCHAR tszPath[MAX_PATH];
TCHAR tszFullFileName[MAX_PATH];
DEBUGMSG("DelCatFiles()");
#ifdef DBG
if (fDBGUseLocalFile())
{
DEBUGMSG("When use local file in debugging mode, do not delete local catalog files");
return;
}
else
#endif
{
AUASSERT(_T('\0') != g_szWUDir[0]);
if (FAILED(StringCchCopyEx(tszPath, ARRAYSIZE(tszPath) , g_szWUDir, NULL, NULL, MISTSAFE_STRING_FLAGS)))
{
return;
}
LPCTSTR FILES_TO_DELETE[] = {ITEM_FILE, DRIVERS_FILE, DETAILS_FILE,
#ifdef DBG
DETECT1_FILE, DETECT2_FILE, DETECT3_FILE, DRIVER_SYSSPEC_FILE, NONDRIVER_SYSSPEC_FILE,
PROVIDER_FILE, PRODUCT_FILE, INSTALL_FILE,
#endif
CATALOG_FILE };
for (int i = 0; i< ARRAYSIZE(FILES_TO_DELETE); i++)
{
if (SUCCEEDED(StringCchCopyEx(tszFullFileName, ARRAYSIZE(tszFullFileName) , tszPath, NULL, NULL, MISTSAFE_STRING_FLAGS)) &&
SUCCEEDED(StringCchCatEx(tszFullFileName, ARRAYSIZE(tszFullFileName), FILES_TO_DELETE[i], NULL, NULL, MISTSAFE_STRING_FLAGS)))
{
AUDelFileOrDir(tszFullFileName);
}
}
if (!fUpdate)
{
TCHAR tszDownloadTmpDir[MAX_PATH];
if (SUCCEEDED(GetDownloadPath(tszDownloadTmpDir, ARRAYSIZE(tszDownloadTmpDir))))
{
DelDir(tszDownloadTmpDir);
RemoveDirectory(tszDownloadTmpDir);
}
}
}
}
////////////////////////////////////////////
// caller needs to free the returned BSTR
////////////////////////////////////////////
BSTR GetCatalogFile(void)
{
TCHAR szFile[MAX_PATH];
AUASSERT(_T('\0') != g_szWUDir[0]);
if (FAILED(StringCchCopyEx(szFile, ARRAYSIZE(szFile), g_szWUDir, NULL, NULL, MISTSAFE_STRING_FLAGS))||
FAILED(StringCchCatEx(szFile, ARRAYSIZE(szFile), CATALOG_FILE, NULL, NULL, MISTSAFE_STRING_FLAGS)))
{
return NULL;
}
return SysAllocString(T2W(szFile));
}
//=======================================================================
//
// AUCatalog::Serialize
//
//=======================================================================
HRESULT AUCatalog::Serialize(void)
{
HRESULT hr = S_OK;
DEBUGMSG("WUAUENG: serializing");
BSTR bstrCatFile = NULL ;
IXMLDOMDocument *pxmlCatalog = NULL;
IXMLDOMElement *pelemAUCATALOG = NULL;
AU_VARIANT varValueVERSION(CATALOG_XML_VERSION);
AU_VARIANT varValueDOWNLOADID(m_audownloader.getID());
AU_VARIANT varValueITEMCOUNT(m_ItemList.Count());
AU_VARIANT varValueUpdateDriver(m_fUpdateDriver);
if (NULL == (bstrCatFile = GetCatalogFile()))
{
DEBUGMSG("Fail to get catalog file with error %#lx", hr);
goto done;
}
AUDelFileOrDir(W2T(bstrCatFile)); //delete old catalog file
if ( FAILED(hr = CoCreateInstance(__uuidof(DOMDocument), NULL, CLSCTX_INPROC_SERVER,
__uuidof(IXMLDOMDocument), (void**)&pxmlCatalog)) ||
FAILED(hr = pxmlCatalog->createElement(bstrTagAUCATALOG, &pelemAUCATALOG)) ||
FAILED(hr = pelemAUCATALOG->setAttribute(bstrAttrVERSION, varValueVERSION)) ||
FAILED(hr = pelemAUCATALOG->setAttribute(bstrAttrDOWNLOADID, varValueDOWNLOADID)) ||
FAILED(hr = pelemAUCATALOG->setAttribute(bstrAttrITEMCOUNT, varValueITEMCOUNT)) ||
FAILED(hr = pelemAUCATALOG->setAttribute(bstrAttrUpdateDriver, varValueUpdateDriver)) ||
FAILED(hr = pxmlCatalog->appendChild(pelemAUCATALOG, NULL)) )
{
DEBUGMSG("Fail to create Catalog.xml");
goto done;
}
VARIANT varValueID;
VARIANT varValueSTATUS;
varValueID.vt = VT_BSTR;
varValueSTATUS.vt = VT_I4;
// write out item information
for ( DWORD index = 0; index < m_ItemList.Count(); index++ )
{
IXMLDOMElement *pelemITEM = NULL;
varValueID.bstrVal = m_ItemList[index].bstrID();
varValueSTATUS.lVal = m_ItemList[index].dwStatus();
// DEBUGMSG("Status is %d for item %S", varValueSTATUS.lVal, m_ItemList[index].bstrID());
if ( FAILED(hr = pxmlCatalog->createElement(bstrTagITEM, &pelemITEM)) ||
FAILED(hr = pelemITEM->setAttribute(bstrAttrID, varValueID)) ||
FAILED(hr = pelemITEM->setAttribute(bstrAttrSTATUS, varValueSTATUS)) ||
FAILED(hr = pelemAUCATALOG->appendChild(pelemITEM, NULL)) )
{
SafeRelease(pelemITEM);
goto done;
}
SafeRelease(pelemITEM);
}
if ( FAILED(hr = SaveDocument(pxmlCatalog, bstrCatFile)))
{
DEBUGMSG("saving of %S failed, hr = %#lx", bstrCatFile, hr);
if ( SUCCEEDED(hr) )
{
hr = E_FAIL;
}
goto done;
}
done:
if (FAILED(hr) && NULL != bstrCatFile)
{
AUDelFileOrDir(bstrCatFile);
}
SafeFreeBSTR(bstrCatFile);
SafeRelease(pelemAUCATALOG);
SafeRelease(pxmlCatalog);
return hr;
}
//=======================================================================
//
// AUCatalog::Unserialize
//
//=======================================================================
HRESULT AUCatalog::Unserialize()
{
// USES_CONVERSION;
DEBUGMSG("WUAUENG: unserializing");
HRESULT hr = S_OK;
IXMLDOMDocument *pxmlCatalog = NULL;
IXMLDOMNodeList *pitemnodes = NULL;
IXMLDOMNode *pcatalog = NULL;
BSTR bstrCatFile = NULL;
long lVersion;
long lItemCount;
BSTR bstrDownloadId = NULL;
GUID downloadId;
if (NULL == (bstrCatFile = GetCatalogFile()))
{
DEBUGMSG("Fail to get catalog file with error %#lx", hr);
goto done;
}
if ( FAILED(hr = LoadDocument(bstrCatFile, &pxmlCatalog, TRUE)))
{
DEBUGMSG("Could not Load catalog file with error %#lx", hr);
goto done;
}
//get catalog node (root)
if (!FindNode(pxmlCatalog, bstrTagAUCATALOG, &pcatalog))
{
hr = E_FAIL;
DEBUGMSG("fail to find catalog node ");
goto done;
}
// get version
if ( FAILED(hr = GetAttribute(pcatalog, bstrAttrVERSION, &lVersion)))
{
DEBUGMSG("Fail to get version with error %#lx", hr);
goto done;
}
DEBUGMSG("Catalog Version Number is %d", lVersion);
if ( CATALOG_XML_VERSION != lVersion )
{
DEBUGMSG("invalid XML version");
hr = E_FAIL;
goto done;
}
// get DOWNLOADID
if ( FAILED(hr = GetAttribute(pcatalog, bstrAttrDOWNLOADID, &bstrDownloadId)) ||
FAILED(hr = CLSIDFromString(bstrDownloadId, &downloadId)))
{
DEBUGMSG("failed to get download id with error %#lx", hr);
goto done;
}
if (GUID_NULL != downloadId)
{
m_audownloader.setID(downloadId);
m_fNeedToContinueJob = TRUE;
}
// get ITEMCOUNT
if ( FAILED(hr = GetAttribute(pcatalog, bstrAttrITEMCOUNT, &lItemCount)))
{
DEBUGMSG("failed to get item count with error %#lx", hr);
goto done;
}
if (m_fUpdateDriver)
{
if (FAILED(hr = GetAttribute(pcatalog, bstrAttrUpdateDriver, &m_fUpdateDriver)))
{
DEBUGMSG("failed to get fUpdateDriver with error %#lx", hr);
goto done;
}
}
DEBUGMSG("Catalog item count is %d", lItemCount);
if (FAILED(hr = m_ItemList.Allocate(lItemCount)))
{
DEBUGMSG("Out of memory, fail to allocate item list");
goto done;
}
if ( NULL == (pitemnodes = FindDOMNodeList(pcatalog, bstrTagITEM)))
{
hr = E_FAIL;
DEBUGMSG("Fail to find items in the catalog ");
goto done;
}
// read in item list
for ( DWORD index = 0; index < m_ItemList.Count(); index++ )
{
IXMLDOMNode *pitemnode = NULL;
if ( S_OK != (hr = pitemnodes->get_item(index, &pitemnode)) )
{
DEBUGMSG("failed to get item node %d", index);
hr = FAILED(hr) ? hr : E_FAIL;
goto done;
}
// get ID
if ( FAILED(hr = GetAttribute(pitemnode, bstrAttrID, &(m_ItemList[index].m_bstrID))))
{
DEBUGMSG("Fail to find ID for item %d", index);
SafeRelease(pitemnode);
goto done;
}
// get STATUS
if ( FAILED(hr = GetAttribute(pitemnode, bstrAttrSTATUS, (long*)(&(m_ItemList[index].m_dwStatus)))))
{
DEBUGMSG("Fail to find status for item %d with error %#lx", index, hr);
SafeRelease(pitemnode);
goto done;
}
// DEBUGMSG("item %S status is %d", m_ItemList[index].m_bstrID, m_ItemList[index].m_dwStatus);
pitemnode->Release();
}
//populate m_ItemList with other information than itemID and status
hr = GetDetailedItemInfoFromDisk(m_ItemList, &m_bstrInstallation, m_fUpdateDriver);
done:
SafeFreeBSTR(bstrDownloadId);
SafeFreeBSTR(bstrCatFile);
SafeRelease(pcatalog);
SafeRelease(pitemnodes);
SafeRelease(pxmlCatalog);
if (FAILED(hr))
{
DelCatFiles();
Clear();
}
DEBUGMSG("WUAUENG unserializing done with result %#lx", hr);
return hr;
}
//only download RTFs for now
HRESULT AUCatalog::DownloadRTFsnEULAs(LANGID langid)
{
BSTR bstrRTFUrl, bstrEULAUrl;
TCHAR tszLocalRTFDir[MAX_PATH];
HRESULT hr;
if (FAILED(hr = GetRTFDownloadPath(tszLocalRTFDir, ARRAYSIZE(tszLocalRTFDir), langid)))
{
DEBUGMSG("Fail to get RTF download path %#lx", hr);
goto done;
}
DEBUGMSG("Got RTF path %S", tszLocalRTFDir);
UINT uItemCount = m_ItemList.Count();
// DEBUGMSG("Downloading %d RTFs", uItemCount);
for (UINT i = 0; i<uItemCount; i++)
{
AUCatalogItem & item = (m_ItemList)[i];
if (item.fSelected())
{
bstrRTFUrl = item.bstrRTFPath();
if (NULL != bstrRTFUrl)
{
HRESULT hr1 =DownloadFile(bstrRTFUrl, tszLocalRTFDir,NULL, NULL, &ghServiceFinished, 1, NULL,NULL, WUDF_SKIPCABVALIDATION);
DEBUGMSG("download RTF file from %S to %S %s (with error %#lx)", bstrRTFUrl, tszLocalRTFDir, FAILED(hr1)? "failed" : "succeeded", hr1);
if(SUCCEEDED(hr1))
{
ValidateDownloadedRTF(bstrRTFUrl, m_ItemList[i].bstrID());
}
}
}
}
done:
return hr;
}
DWORD AUCatalog::GetNumSelected(void)
{
UINT uItemNum = m_ItemList.Count();
DWORD dwSelectedNum = 0;
for (UINT i = 0; i < uItemNum; i++)
{
AUCatalogItem &item = m_ItemList[i];
if (item.fSelected())
{
dwSelectedNum++;
}
}
return dwSelectedNum;
}
//=======================================================================
//
// AUCatalog::GetInstallXML
//
//=======================================================================
HRESULT AUCatalog::GetInstallXML(BSTR *pbstrCatalogXML, BSTR *pbstrDownloadXML)
{
DEBUGMSG("AUCatalog::GetInstallXML");
HRESULT hr = S_OK;
PersistHiddenItems(m_ItemList, URLLOGACTIVITY_Installation);
if (m_ItemList.GetNumSelected() == 0)
{
DEBUGMSG("Nothing to install");
hr = S_FALSE;
goto end;
}
if (S_OK != (hr = ValidateItems(FALSE/*, TRUE*/)))
{
DEBUGMSG("Invalid catalog with error %#lx or no items", hr);
hr = E_FAIL;
goto end;
}
if (NULL == m_bstrInstallation )
{
DEBUGMSG(" can't get installation xml or download result xml");
hr = E_FAIL;
goto end;
}
hr = PrepareInstallXML(m_bstrInstallation, m_ItemList, pbstrDownloadXML, pbstrCatalogXML);
#ifdef DBG
if (SUCCEEDED(hr))
{
LOGXMLFILE(INSTALL_FILE, *pbstrCatalogXML); //download xml is logged by client
}
#endif
end:
return hr;
}
//=======================================================================
//
// AUCatalog::FindItemIdByLocalFileName
// return value should not be freed
//=======================================================================
BSTR AUCatalog::FindItemIdByLocalFileName(LPCWSTR pwszLocalFileName)
{
CItemDetails itemdetails;
if (NULL == pwszLocalFileName ||
0 == m_ItemList.GetNumSelected() ||
NULL == m_bstrInstallation ||
!itemdetails.Init(m_bstrInstallation))
{
DEBUGMSG("AUCatalog::FindItemIdByLocalFileName bad params or failed to init CItemDetails");
return NULL;
}
UINT uItemCount = m_ItemList.Count();
BSTR bstrResult = NULL;
BOOL fDone = FALSE;
for (UINT i = 0; i < uItemCount && !fDone; i++)
{
AUCatalogItem &item = m_ItemList[i];
if (item.fSelected() || m_ItemList.ItemIsRelevant(i))
{
BSTR bstrItemId = item.bstrID();
BSTR bstrItemDownloadPath = itemdetails.GetItemDownloadPath(bstrItemId);
if (NULL == bstrItemDownloadPath)
{
DEBUGMSG("AUCatalog::FindItemIdByLocalFileName fail to build item downloadPath for %S", bstrItemId);
fDone = TRUE;
}
else
{
BSTR *pCRCCabNames = NULL;
BSTR *pRealCabNames = NULL;
BSTR *pCabChecksums = NULL;
UINT uCabsNum;
if (FAILED(itemdetails.GetCabNames(bstrItemId, &pCRCCabNames, &pRealCabNames, &pCabChecksums, &uCabsNum)))
{
DEBUGMSG("AUCatalog::FindItemIdByLocalFileName fail to get cab names for %S", bstrItemId);
fDone = TRUE;
}
else
{
for (UINT j = 0; j < uCabsNum; j++)
{
WCHAR wszFullFileName[MAX_PATH];
if (!fDone &&
SUCCEEDED(PathCchCombineW(
wszFullFileName,
ARRAYSIZE(wszFullFileName),
bstrItemDownloadPath,
pRealCabNames[j])) &&
0 == StrCmpIW(wszFullFileName, pwszLocalFileName))
{
DEBUGMSG("AUCatalog::FindItemIdByLocalFileName found item");
bstrResult = bstrItemId;
fDone = TRUE;
}
SafeFreeBSTR(pCRCCabNames[j]);
SafeFreeBSTR(pRealCabNames[j]);
SafeFreeBSTR(pCabChecksums[j]);
}
SafeFree(pCRCCabNames);
SafeFree(pRealCabNames);
SafeFree(pCabChecksums);
}
SysFreeString(bstrItemDownloadPath);
}
}
}
itemdetails.Uninit();
return bstrResult;
}
//=======================================================================
//// AUCatalog::ValidateDownloadedCabs
// The OUT parameter (itemid) will be NULL if no error or if the error
// is other than ERROR_CRC
//=======================================================================
HRESULT AUCatalog::ValidateDownloadedCabs(BSTR *pbstrErrorItemId)
{
HRESULT hr = E_FAIL;
CItemDetails itemdetails;
AUASSERT(NULL != m_bstrInstallation);
if(NULL == pbstrErrorItemId)
{
return E_INVALIDARG;
}
*pbstrErrorItemId = NULL;
//if no items selected or if failed to load install xml
if (0 == m_ItemList.GetNumSelected() ||
!itemdetails.Init(m_bstrInstallation))
{
return hr;
}
UINT uItemCount = m_ItemList.Count();
BOOL fError = FALSE;
BSTR *pCRCCabNames = NULL;
BSTR *pRealCabNames = NULL;
BSTR *pCabChecksums = NULL;
UINT uCabsNum = 0;
for (UINT i = 0; i < uItemCount && !fError; i++)
{
if (!m_ItemList[i].fSelected() && !m_ItemList.ItemIsRelevant(i))
{
continue;
}
BSTR bstrItemId = m_ItemList[i].bstrID();
BSTR bstrItemDownloadPath = itemdetails.GetItemDownloadPath(bstrItemId);
if( NULL == bstrItemDownloadPath)
{
hr = E_OUTOFMEMORY;
break;
}
if (FAILED(hr = itemdetails.GetCabNames(bstrItemId, &pCRCCabNames, &pRealCabNames, &pCabChecksums, &uCabsNum)))
{
SysFreeString(bstrItemDownloadPath);
break;
}
//Iterate through all the cabs in an item
for (UINT j = 0; j < uCabsNum; j++)
{
//If no error and CRC exists
if(!fError && NULL != pCabChecksums[j])
{
WCHAR wszFullFileName[MAX_PATH+1];
if (SUCCEEDED(hr = PathCchCombineW(wszFullFileName, ARRAYSIZE(wszFullFileName), bstrItemDownloadPath, pRealCabNames[j])))
{
if(FAILED(hr = VerifyFileCRC(wszFullFileName, pCabChecksums[j])))
{
fError = TRUE;
if(hr == HRESULT_FROM_WIN32(ERROR_CRC))
{
*pbstrErrorItemId = bstrItemId;
}
DEBUGMSG("Checksum Failed for file %S", wszFullFileName);
}
}
else
{
fError = TRUE;
}
}
//Free up memory
SafeFreeBSTR(pCRCCabNames[j]);
SafeFreeBSTR(pRealCabNames[j]);
SafeFreeBSTR(pCabChecksums[j]);
}
SafeFreeNULL(pCRCCabNames);
SafeFreeNULL(pRealCabNames);
SafeFreeNULL(pCabChecksums);
SysFreeString(bstrItemDownloadPath);
}
itemdetails.Uninit();
return hr;
}
void AUCatalog::ValidateDownloadedRTF(BSTR bstrRTFUrl, BSTR bstrItemId)
{
CItemDetails itemdetails;
BSTR bstrCRC = NULL;
TCHAR szRTFName[MAX_PATH+1];
AUASSERT(NULL != bstrItemId && NULL != bstrRTFUrl && NULL != m_bstrInstallation);
//if failed to load install xml
if (itemdetails.Init(m_bstrInstallation) &&
SUCCEEDED(itemdetails.GetRTFCRC(bstrItemId, &bstrCRC)) &&
SUCCEEDED(GetRTFLocalFileName(bstrRTFUrl, szRTFName, ARRAYSIZE(szRTFName), GetSystemDefaultLangID())) &&
HRESULT_FROM_WIN32(ERROR_CRC) == VerifyFileCRC(szRTFName, bstrCRC))
{
DEBUGMSG("Checksum Failed for RTF %S, deleting it.", szRTFName);
DeleteFile(szRTFName);
}
SafeFreeBSTR(bstrCRC);
itemdetails.Uninit();
}