diff options
author | Rob Mensching <rob@firegiant.com> | 2021-04-22 17:06:54 -0700 |
---|---|---|
committer | Rob Mensching <rob@firegiant.com> | 2021-04-29 16:36:06 -0700 |
commit | af10c45d7b3a44af0b461a557847fe03263dcc10 (patch) | |
tree | 6a5c1532304782c36ffe4200b38f3afb76789a43 /src/burn/engine/detect.cpp | |
parent | 9c2aed97299fb96aeee3f1471ce40225437aaecf (diff) | |
download | wix-af10c45d7b3a44af0b461a557847fe03263dcc10.tar.gz wix-af10c45d7b3a44af0b461a557847fe03263dcc10.tar.bz2 wix-af10c45d7b3a44af0b461a557847fe03263dcc10.zip |
Move burn into burn
Diffstat (limited to 'src/burn/engine/detect.cpp')
-rw-r--r-- | src/burn/engine/detect.cpp | 469 |
1 files changed, 469 insertions, 0 deletions
diff --git a/src/burn/engine/detect.cpp b/src/burn/engine/detect.cpp new file mode 100644 index 00000000..dc35e747 --- /dev/null +++ b/src/burn/engine/detect.cpp | |||
@@ -0,0 +1,469 @@ | |||
1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
2 | |||
3 | #include "precomp.h" | ||
4 | |||
5 | typedef struct _DETECT_AUTHENTICATION_REQUIRED_DATA | ||
6 | { | ||
7 | BURN_USER_EXPERIENCE* pUX; | ||
8 | LPCWSTR wzPackageOrContainerId; | ||
9 | } DETECT_AUTHENTICATION_REQUIRED_DATA; | ||
10 | |||
11 | // internal function definitions | ||
12 | static HRESULT WINAPI AuthenticationRequired( | ||
13 | __in LPVOID pData, | ||
14 | __in HINTERNET hUrl, | ||
15 | __in long lHttpCode, | ||
16 | __out BOOL* pfRetrySend, | ||
17 | __out BOOL* pfRetry | ||
18 | ); | ||
19 | |||
20 | static HRESULT DetectAtomFeedUpdate( | ||
21 | __in_z LPCWSTR wzBundleId, | ||
22 | __in BURN_USER_EXPERIENCE* pUX, | ||
23 | __in BURN_UPDATE* pUpdate | ||
24 | ); | ||
25 | |||
26 | static HRESULT DownloadUpdateFeed( | ||
27 | __in_z LPCWSTR wzBundleId, | ||
28 | __in BURN_USER_EXPERIENCE* pUX, | ||
29 | __in BURN_UPDATE* pUpdate, | ||
30 | __deref_inout_z LPWSTR* psczTempFile | ||
31 | ); | ||
32 | |||
33 | // function definitions | ||
34 | |||
35 | extern "C" void DetectReset( | ||
36 | __in BURN_REGISTRATION* pRegistration, | ||
37 | __in BURN_PACKAGES* pPackages | ||
38 | ) | ||
39 | { | ||
40 | RelatedBundlesUninitialize(&pRegistration->relatedBundles); | ||
41 | ReleaseNullStr(pRegistration->sczDetectedProviderKeyBundleId); | ||
42 | pRegistration->fSelfRegisteredAsDependent = FALSE; | ||
43 | pRegistration->fParentRegisteredAsDependent = FALSE; | ||
44 | pRegistration->fForwardCompatibleBundleExists = FALSE; | ||
45 | pRegistration->fEligibleForCleanup = FALSE; | ||
46 | |||
47 | if (pRegistration->rgIgnoredDependencies) | ||
48 | { | ||
49 | ReleaseDependencyArray(pRegistration->rgIgnoredDependencies, pRegistration->cIgnoredDependencies); | ||
50 | } | ||
51 | pRegistration->rgIgnoredDependencies = NULL; | ||
52 | pRegistration->cIgnoredDependencies = 0; | ||
53 | |||
54 | if (pRegistration->rgDependents) | ||
55 | { | ||
56 | ReleaseDependencyArray(pRegistration->rgDependents, pRegistration->cDependents); | ||
57 | } | ||
58 | pRegistration->rgDependents = NULL; | ||
59 | pRegistration->cDependents = 0; | ||
60 | |||
61 | for (DWORD iPackage = 0; iPackage < pPackages->cPackages; ++iPackage) | ||
62 | { | ||
63 | BURN_PACKAGE* pPackage = pPackages->rgPackages + iPackage; | ||
64 | |||
65 | pPackage->currentState = BOOTSTRAPPER_PACKAGE_STATE_UNKNOWN; | ||
66 | pPackage->fPackageProviderExists = FALSE; | ||
67 | pPackage->cacheRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_UNKNOWN; | ||
68 | pPackage->installRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_UNKNOWN; | ||
69 | |||
70 | pPackage->fCached = FALSE; | ||
71 | |||
72 | if (BURN_PACKAGE_TYPE_MSI == pPackage->type) | ||
73 | { | ||
74 | for (DWORD iFeature = 0; iFeature < pPackage->Msi.cFeatures; ++iFeature) | ||
75 | { | ||
76 | BURN_MSIFEATURE* pFeature = pPackage->Msi.rgFeatures + iFeature; | ||
77 | |||
78 | pFeature->currentState = BOOTSTRAPPER_FEATURE_STATE_UNKNOWN; | ||
79 | } | ||
80 | |||
81 | for (DWORD iSlipstreamMsp = 0; iSlipstreamMsp < pPackage->Msi.cSlipstreamMspPackages; ++iSlipstreamMsp) | ||
82 | { | ||
83 | BURN_SLIPSTREAM_MSP* pSlipstreamMsp = pPackage->Msi.rgSlipstreamMsps + iSlipstreamMsp; | ||
84 | |||
85 | pSlipstreamMsp->dwMsiChainedPatchIndex = BURN_PACKAGE_INVALID_PATCH_INDEX; | ||
86 | } | ||
87 | |||
88 | ReleaseNullMem(pPackage->Msi.rgChainedPatches); | ||
89 | pPackage->Msi.cChainedPatches = 0; | ||
90 | } | ||
91 | else if (BURN_PACKAGE_TYPE_MSP == pPackage->type) | ||
92 | { | ||
93 | ReleaseNullMem(pPackage->Msp.rgTargetProducts); | ||
94 | pPackage->Msp.cTargetProductCodes = 0; | ||
95 | } | ||
96 | |||
97 | for (DWORD iProvider = 0; iProvider < pPackage->cDependencyProviders; ++iProvider) | ||
98 | { | ||
99 | BURN_DEPENDENCY_PROVIDER* pProvider = pPackage->rgDependencyProviders + iProvider; | ||
100 | |||
101 | if (pProvider->rgDependents) | ||
102 | { | ||
103 | ReleaseDependencyArray(pProvider->rgDependents, pProvider->cDependents); | ||
104 | } | ||
105 | pProvider->rgDependents = NULL; | ||
106 | pProvider->cDependents = 0; | ||
107 | } | ||
108 | } | ||
109 | |||
110 | for (DWORD iPatchInfo = 0; iPatchInfo < pPackages->cPatchInfo; ++iPatchInfo) | ||
111 | { | ||
112 | MSIPATCHSEQUENCEINFOW* pPatchInfo = pPackages->rgPatchInfo + iPatchInfo; | ||
113 | pPatchInfo->dwOrder = 0; | ||
114 | pPatchInfo->uStatus = 0; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | extern "C" HRESULT DetectForwardCompatibleBundles( | ||
119 | __in BURN_USER_EXPERIENCE* pUX, | ||
120 | __in BURN_REGISTRATION* pRegistration | ||
121 | ) | ||
122 | { | ||
123 | HRESULT hr = S_OK; | ||
124 | int nCompareResult = 0; | ||
125 | |||
126 | if (pRegistration->sczDetectedProviderKeyBundleId && | ||
127 | CSTR_EQUAL != ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pRegistration->sczDetectedProviderKeyBundleId, -1, pRegistration->sczId, -1)) | ||
128 | { | ||
129 | for (DWORD iRelatedBundle = 0; iRelatedBundle < pRegistration->relatedBundles.cRelatedBundles; ++iRelatedBundle) | ||
130 | { | ||
131 | BURN_RELATED_BUNDLE* pRelatedBundle = pRegistration->relatedBundles.rgRelatedBundles + iRelatedBundle; | ||
132 | |||
133 | if (BOOTSTRAPPER_RELATION_UPGRADE == pRelatedBundle->relationType && | ||
134 | CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pRegistration->sczDetectedProviderKeyBundleId, -1, pRelatedBundle->package.sczId, -1)) | ||
135 | { | ||
136 | hr = VerCompareParsedVersions(pRegistration->pVersion, pRelatedBundle->pVersion, &nCompareResult); | ||
137 | ExitOnFailure(hr, "Failed to compare bundle version '%ls' to related bundle version '%ls'", pRegistration->pVersion->sczVersion, pRelatedBundle->pVersion->sczVersion); | ||
138 | |||
139 | if (nCompareResult <= 0) | ||
140 | { | ||
141 | if (pRelatedBundle->fPlannable) | ||
142 | { | ||
143 | pRelatedBundle->fForwardCompatible = TRUE; | ||
144 | pRegistration->fForwardCompatibleBundleExists = TRUE; | ||
145 | } | ||
146 | |||
147 | hr = UserExperienceOnDetectForwardCompatibleBundle(pUX, pRelatedBundle->package.sczId, pRelatedBundle->relationType, pRelatedBundle->sczTag, pRelatedBundle->package.fPerMachine, pRelatedBundle->pVersion, !pRelatedBundle->package.fCached); | ||
148 | ExitOnRootFailure(hr, "BA aborted detect forward compatible bundle."); | ||
149 | |||
150 | LogId(REPORT_STANDARD, MSG_DETECTED_FORWARD_COMPATIBLE_BUNDLE, pRelatedBundle->package.sczId, LoggingRelationTypeToString(pRelatedBundle->relationType), LoggingPerMachineToString(pRelatedBundle->package.fPerMachine), pRelatedBundle->pVersion->sczVersion, LoggingBoolToString(pRelatedBundle->package.fCached)); | ||
151 | } | ||
152 | } | ||
153 | } | ||
154 | } | ||
155 | |||
156 | LExit: | ||
157 | return hr; | ||
158 | } | ||
159 | |||
160 | extern "C" HRESULT DetectReportRelatedBundles( | ||
161 | __in BURN_USER_EXPERIENCE* pUX, | ||
162 | __in BURN_REGISTRATION* pRegistration, | ||
163 | __in BOOTSTRAPPER_RELATION_TYPE relationType, | ||
164 | __in BOOTSTRAPPER_ACTION action, | ||
165 | __out BOOL* pfEligibleForCleanup | ||
166 | ) | ||
167 | { | ||
168 | HRESULT hr = S_OK; | ||
169 | int nCompareResult = 0; | ||
170 | BOOTSTRAPPER_REQUEST_STATE uninstallRequestState = BOOTSTRAPPER_REQUEST_STATE_NONE; | ||
171 | *pfEligibleForCleanup = pRegistration->fInstalled || pRegistration->fCached; | ||
172 | |||
173 | for (DWORD iRelatedBundle = 0; iRelatedBundle < pRegistration->relatedBundles.cRelatedBundles; ++iRelatedBundle) | ||
174 | { | ||
175 | const BURN_RELATED_BUNDLE* pRelatedBundle = pRegistration->relatedBundles.rgRelatedBundles + iRelatedBundle; | ||
176 | BOOTSTRAPPER_RELATED_OPERATION operation = BOOTSTRAPPER_RELATED_OPERATION_NONE; | ||
177 | |||
178 | switch (pRelatedBundle->relationType) | ||
179 | { | ||
180 | case BOOTSTRAPPER_RELATION_UPGRADE: | ||
181 | if (BOOTSTRAPPER_RELATION_UPGRADE != relationType && BOOTSTRAPPER_ACTION_UNINSTALL < action) | ||
182 | { | ||
183 | hr = VerCompareParsedVersions(pRegistration->pVersion, pRelatedBundle->pVersion, &nCompareResult); | ||
184 | ExitOnFailure(hr, "Failed to compare bundle version '%ls' to related bundle version '%ls'", pRegistration->pVersion->sczVersion, pRelatedBundle->pVersion->sczVersion); | ||
185 | |||
186 | if (nCompareResult < 0) | ||
187 | { | ||
188 | operation = BOOTSTRAPPER_RELATED_OPERATION_DOWNGRADE; | ||
189 | } | ||
190 | else | ||
191 | { | ||
192 | operation = BOOTSTRAPPER_RELATED_OPERATION_MAJOR_UPGRADE; | ||
193 | } | ||
194 | } | ||
195 | break; | ||
196 | |||
197 | case BOOTSTRAPPER_RELATION_PATCH: __fallthrough; | ||
198 | case BOOTSTRAPPER_RELATION_ADDON: | ||
199 | if (BOOTSTRAPPER_ACTION_UNINSTALL == action) | ||
200 | { | ||
201 | operation = BOOTSTRAPPER_RELATED_OPERATION_REMOVE; | ||
202 | } | ||
203 | else if (BOOTSTRAPPER_ACTION_INSTALL == action || BOOTSTRAPPER_ACTION_MODIFY == action) | ||
204 | { | ||
205 | operation = BOOTSTRAPPER_RELATED_OPERATION_INSTALL; | ||
206 | } | ||
207 | else if (BOOTSTRAPPER_ACTION_REPAIR == action) | ||
208 | { | ||
209 | operation = BOOTSTRAPPER_RELATED_OPERATION_REPAIR; | ||
210 | } | ||
211 | break; | ||
212 | |||
213 | case BOOTSTRAPPER_RELATION_DETECT: __fallthrough; | ||
214 | case BOOTSTRAPPER_RELATION_DEPENDENT: | ||
215 | break; | ||
216 | |||
217 | default: | ||
218 | hr = E_FAIL; | ||
219 | ExitOnRootFailure(hr, "Unexpected relation type encountered: %d", pRelatedBundle->relationType); | ||
220 | break; | ||
221 | } | ||
222 | |||
223 | LogId(REPORT_STANDARD, MSG_DETECTED_RELATED_BUNDLE, pRelatedBundle->package.sczId, LoggingRelationTypeToString(pRelatedBundle->relationType), LoggingPerMachineToString(pRelatedBundle->package.fPerMachine), pRelatedBundle->pVersion->sczVersion, LoggingRelatedOperationToString(operation), LoggingBoolToString(pRelatedBundle->package.fCached)); | ||
224 | |||
225 | hr = UserExperienceOnDetectRelatedBundle(pUX, pRelatedBundle->package.sczId, pRelatedBundle->relationType, pRelatedBundle->sczTag, pRelatedBundle->package.fPerMachine, pRelatedBundle->pVersion, operation, !pRelatedBundle->package.fCached); | ||
226 | ExitOnRootFailure(hr, "BA aborted detect related bundle."); | ||
227 | |||
228 | // For now, if any related bundles will be executed during uninstall by default then never automatically clean up the bundle. | ||
229 | if (*pfEligibleForCleanup && pRelatedBundle->fPlannable) | ||
230 | { | ||
231 | uninstallRequestState = BOOTSTRAPPER_REQUEST_STATE_NONE; | ||
232 | hr = PlanDefaultRelatedBundleRequestState(relationType, pRelatedBundle->relationType, BOOTSTRAPPER_ACTION_UNINSTALL, pRegistration->pVersion, pRelatedBundle->pVersion, &uninstallRequestState); | ||
233 | ExitOnFailure(hr, "Failed to get the default request state for related bundle for calculating fEligibleForCleanup"); | ||
234 | |||
235 | if (BOOTSTRAPPER_REQUEST_STATE_NONE != uninstallRequestState) | ||
236 | { | ||
237 | *pfEligibleForCleanup = FALSE; | ||
238 | } | ||
239 | } | ||
240 | } | ||
241 | |||
242 | LExit: | ||
243 | return hr; | ||
244 | } | ||
245 | |||
246 | extern "C" HRESULT DetectUpdate( | ||
247 | __in_z LPCWSTR wzBundleId, | ||
248 | __in BURN_USER_EXPERIENCE* pUX, | ||
249 | __in BURN_UPDATE* pUpdate | ||
250 | ) | ||
251 | { | ||
252 | HRESULT hr = S_OK; | ||
253 | BOOL fBeginCalled = FALSE; | ||
254 | BOOL fSkip = TRUE; | ||
255 | BOOL fIgnoreError = FALSE; | ||
256 | LPWSTR sczOriginalSource = NULL; | ||
257 | |||
258 | // If no update source was specified, skip update detection. | ||
259 | if (!pUpdate->sczUpdateSource || !*pUpdate->sczUpdateSource) | ||
260 | { | ||
261 | ExitFunction(); | ||
262 | } | ||
263 | |||
264 | fBeginCalled = TRUE; | ||
265 | |||
266 | hr = StrAllocString(&sczOriginalSource, pUpdate->sczUpdateSource, 0); | ||
267 | ExitOnFailure(hr, "Failed to duplicate update feed source."); | ||
268 | |||
269 | hr = UserExperienceOnDetectUpdateBegin(pUX, sczOriginalSource, &fSkip); | ||
270 | ExitOnRootFailure(hr, "BA aborted detect update begin."); | ||
271 | |||
272 | if (!fSkip) | ||
273 | { | ||
274 | hr = DetectAtomFeedUpdate(wzBundleId, pUX, pUpdate); | ||
275 | ExitOnFailure(hr, "Failed to detect atom feed update."); | ||
276 | } | ||
277 | |||
278 | LExit: | ||
279 | ReleaseStr(sczOriginalSource); | ||
280 | |||
281 | if (fBeginCalled) | ||
282 | { | ||
283 | UserExperienceOnDetectUpdateComplete(pUX, hr, &fIgnoreError); | ||
284 | if (fIgnoreError) | ||
285 | { | ||
286 | hr = S_OK; | ||
287 | } | ||
288 | } | ||
289 | |||
290 | return hr; | ||
291 | } | ||
292 | |||
293 | static HRESULT WINAPI AuthenticationRequired( | ||
294 | __in LPVOID pData, | ||
295 | __in HINTERNET hUrl, | ||
296 | __in long lHttpCode, | ||
297 | __out BOOL* pfRetrySend, | ||
298 | __out BOOL* pfRetry | ||
299 | ) | ||
300 | { | ||
301 | Assert(401 == lHttpCode || 407 == lHttpCode); | ||
302 | |||
303 | HRESULT hr = S_OK; | ||
304 | DWORD er = ERROR_SUCCESS; | ||
305 | BOOTSTRAPPER_ERROR_TYPE errorType = (401 == lHttpCode) ? BOOTSTRAPPER_ERROR_TYPE_HTTP_AUTH_SERVER : BOOTSTRAPPER_ERROR_TYPE_HTTP_AUTH_PROXY; | ||
306 | LPWSTR sczError = NULL; | ||
307 | DETECT_AUTHENTICATION_REQUIRED_DATA* pAuthenticationData = reinterpret_cast<DETECT_AUTHENTICATION_REQUIRED_DATA*>(pData); | ||
308 | int nResult = IDNOACTION; | ||
309 | |||
310 | *pfRetrySend = FALSE; | ||
311 | *pfRetry = FALSE; | ||
312 | |||
313 | hr = StrAllocFromError(&sczError, HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED), NULL); | ||
314 | ExitOnFailure(hr, "Failed to allocation error string."); | ||
315 | |||
316 | UserExperienceOnError(pAuthenticationData->pUX, errorType, pAuthenticationData->wzPackageOrContainerId, ERROR_ACCESS_DENIED, sczError, MB_RETRYTRYAGAIN, 0, NULL, &nResult); // ignore return value. | ||
317 | nResult = UserExperienceCheckExecuteResult(pAuthenticationData->pUX, FALSE, MB_RETRYTRYAGAIN, nResult); | ||
318 | if (IDTRYAGAIN == nResult && pAuthenticationData->pUX->hwndDetect) | ||
319 | { | ||
320 | er = ::InternetErrorDlg(pAuthenticationData->pUX->hwndDetect, hUrl, ERROR_INTERNET_INCORRECT_PASSWORD, FLAGS_ERROR_UI_FILTER_FOR_ERRORS | FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS | FLAGS_ERROR_UI_FLAGS_GENERATE_DATA, NULL); | ||
321 | if (ERROR_SUCCESS == er || ERROR_CANCELLED == er) | ||
322 | { | ||
323 | hr = HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT); | ||
324 | } | ||
325 | else if (ERROR_INTERNET_FORCE_RETRY == er) | ||
326 | { | ||
327 | *pfRetrySend = TRUE; | ||
328 | hr = S_OK; | ||
329 | } | ||
330 | else | ||
331 | { | ||
332 | hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED); | ||
333 | } | ||
334 | } | ||
335 | else if (IDRETRY == nResult) | ||
336 | { | ||
337 | *pfRetry = TRUE; | ||
338 | hr = S_OK; | ||
339 | } | ||
340 | else | ||
341 | { | ||
342 | hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED); | ||
343 | } | ||
344 | |||
345 | LExit: | ||
346 | ReleaseStr(sczError); | ||
347 | |||
348 | return hr; | ||
349 | } | ||
350 | |||
351 | static HRESULT DownloadUpdateFeed( | ||
352 | __in_z LPCWSTR wzBundleId, | ||
353 | __in BURN_USER_EXPERIENCE* pUX, | ||
354 | __in BURN_UPDATE* pUpdate, | ||
355 | __deref_inout_z LPWSTR* psczTempFile | ||
356 | ) | ||
357 | { | ||
358 | HRESULT hr = S_OK; | ||
359 | DOWNLOAD_SOURCE downloadSource = { }; | ||
360 | DOWNLOAD_CACHE_CALLBACK cacheCallback = { }; | ||
361 | DOWNLOAD_AUTHENTICATION_CALLBACK authenticationCallback = { }; | ||
362 | DETECT_AUTHENTICATION_REQUIRED_DATA authenticationData = { }; | ||
363 | LPWSTR sczUpdateId = NULL; | ||
364 | LPWSTR sczError = NULL; | ||
365 | DWORD64 qwDownloadSize = 0; | ||
366 | |||
367 | // Always do our work in the working folder, even if cached. | ||
368 | hr = PathCreateTimeBasedTempFile(NULL, L"UpdateFeed", NULL, L"xml", psczTempFile, NULL); | ||
369 | ExitOnFailure(hr, "Failed to create UpdateFeed based on current system time."); | ||
370 | |||
371 | // Do we need a means of the BA to pass in a user name and password? If so, we should copy it to downloadSource here | ||
372 | hr = StrAllocString(&downloadSource.sczUrl, pUpdate->sczUpdateSource, 0); | ||
373 | ExitOnFailure(hr, "Failed to copy update url."); | ||
374 | |||
375 | cacheCallback.pfnProgress = NULL; //UpdateProgressRoutine; | ||
376 | cacheCallback.pfnCancel = NULL; // TODO: set this | ||
377 | cacheCallback.pv = NULL; //pProgress; | ||
378 | |||
379 | authenticationData.pUX = pUX; | ||
380 | authenticationData.wzPackageOrContainerId = wzBundleId; | ||
381 | |||
382 | authenticationCallback.pv = static_cast<LPVOID>(&authenticationData); | ||
383 | authenticationCallback.pfnAuthenticate = &AuthenticationRequired; | ||
384 | |||
385 | hr = DownloadUrl(&downloadSource, qwDownloadSize, *psczTempFile, &cacheCallback, &authenticationCallback); | ||
386 | ExitOnFailure(hr, "Failed attempt to download update feed from URL: '%ls' to: '%ls'", downloadSource.sczUrl, *psczTempFile); | ||
387 | |||
388 | LExit: | ||
389 | if (FAILED(hr)) | ||
390 | { | ||
391 | if (*psczTempFile) | ||
392 | { | ||
393 | FileEnsureDelete(*psczTempFile); | ||
394 | } | ||
395 | |||
396 | ReleaseNullStr(*psczTempFile); | ||
397 | } | ||
398 | |||
399 | ReleaseStr(downloadSource.sczUrl); | ||
400 | ReleaseStr(downloadSource.sczUser); | ||
401 | ReleaseStr(downloadSource.sczPassword); | ||
402 | ReleaseStr(sczUpdateId); | ||
403 | ReleaseStr(sczError); | ||
404 | return hr; | ||
405 | } | ||
406 | |||
407 | |||
408 | static HRESULT DetectAtomFeedUpdate( | ||
409 | __in_z LPCWSTR wzBundleId, | ||
410 | __in BURN_USER_EXPERIENCE* pUX, | ||
411 | __in BURN_UPDATE* pUpdate | ||
412 | ) | ||
413 | { | ||
414 | Assert(pUpdate && pUpdate->sczUpdateSource && *pUpdate->sczUpdateSource); | ||
415 | #ifdef DEBUG | ||
416 | LogStringLine(REPORT_STANDARD, "DetectAtomFeedUpdate() - update location: %ls", pUpdate->sczUpdateSource); | ||
417 | #endif | ||
418 | |||
419 | |||
420 | HRESULT hr = S_OK; | ||
421 | LPWSTR sczUpdateFeedTempFile = NULL; | ||
422 | ATOM_FEED* pAtomFeed = NULL; | ||
423 | APPLICATION_UPDATE_CHAIN* pApupChain = NULL; | ||
424 | BOOL fStopProcessingUpdates = FALSE; | ||
425 | |||
426 | hr = AtomInitialize(); | ||
427 | ExitOnFailure(hr, "Failed to initialize Atom."); | ||
428 | |||
429 | hr = DownloadUpdateFeed(wzBundleId, pUX, pUpdate, &sczUpdateFeedTempFile); | ||
430 | ExitOnFailure(hr, "Failed to download update feed."); | ||
431 | |||
432 | hr = AtomParseFromFile(sczUpdateFeedTempFile, &pAtomFeed); | ||
433 | ExitOnFailure(hr, "Failed to parse update atom feed: %ls.", sczUpdateFeedTempFile); | ||
434 | |||
435 | hr = ApupAllocChainFromAtom(pAtomFeed, &pApupChain); | ||
436 | ExitOnFailure(hr, "Failed to allocate update chain from atom feed."); | ||
437 | |||
438 | if (0 < pApupChain->cEntries) | ||
439 | { | ||
440 | for (DWORD i = 0; i < pApupChain->cEntries; ++i) | ||
441 | { | ||
442 | APPLICATION_UPDATE_ENTRY* pAppUpdateEntry = &pApupChain->rgEntries[i]; | ||
443 | |||
444 | hr = UserExperienceOnDetectUpdate(pUX, pAppUpdateEntry->rgEnclosures ? pAppUpdateEntry->rgEnclosures->wzUrl : NULL, | ||
445 | pAppUpdateEntry->rgEnclosures ? pAppUpdateEntry->rgEnclosures->dw64Size : 0, | ||
446 | pAppUpdateEntry->pVersion, pAppUpdateEntry->wzTitle, | ||
447 | pAppUpdateEntry->wzSummary, pAppUpdateEntry->wzContentType, pAppUpdateEntry->wzContent, &fStopProcessingUpdates); | ||
448 | ExitOnRootFailure(hr, "BA aborted detect update."); | ||
449 | |||
450 | if (fStopProcessingUpdates) | ||
451 | { | ||
452 | break; | ||
453 | } | ||
454 | } | ||
455 | } | ||
456 | |||
457 | LExit: | ||
458 | if (sczUpdateFeedTempFile && *sczUpdateFeedTempFile) | ||
459 | { | ||
460 | FileEnsureDelete(sczUpdateFeedTempFile); | ||
461 | } | ||
462 | |||
463 | ApupFreeChain(pApupChain); | ||
464 | AtomFreeFeed(pAtomFeed); | ||
465 | ReleaseStr(sczUpdateFeedTempFile); | ||
466 | AtomUninitialize(); | ||
467 | |||
468 | return hr; | ||
469 | } | ||