Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

768 lines
21 KiB

  1. #include "private.h"
  2. #include <urlmon.h>
  3. #include <wininet.h>
  4. #include <msxml.h>
  5. #include "cdfagent.h"
  6. #include "cdlabsc.h"
  7. #include "cdlagent.h"
  8. #include <urlmon.h>
  9. #include <subsmgr.h>
  10. #include "subsmgrp.h"
  11. #include <mluisupp.h>
  12. HRESULT GetXMLAttribute(IXMLElement *pItem, LPCWSTR pwszAttribute, VARIANT *pvRet);
  13. HRESULT GetNextChildTag(IXMLElement *pRoot, LPCWSTR szTag, IXMLElement **ppChildReq, int &nLastChild)
  14. {
  15. BSTR bstrTag = NULL;
  16. IXMLElementCollection * pChildren = NULL;
  17. HRESULT hr = S_FALSE; // assume not found.
  18. IXMLElement * pChild = NULL;
  19. //
  20. // Find the children if they exist
  21. //
  22. if (SUCCEEDED(pRoot->get_children(&pChildren)) && pChildren)
  23. {
  24. long length = 0;
  25. if (SUCCEEDED(pChildren->get_length(&length)) && length > 0)
  26. {
  27. VARIANT vIndex, vEmpty;
  28. vIndex.vt = VT_I4;
  29. vEmpty.vt = VT_EMPTY;
  30. nLastChild++;
  31. for (long i=nLastChild; i<length; i++)
  32. {
  33. vIndex.lVal = i;
  34. IDispatch *pDispItem = NULL;
  35. if (SUCCEEDED(pChildren->item(vIndex, vEmpty, &pDispItem)))
  36. {
  37. if (SUCCEEDED(pDispItem->QueryInterface(IID_IXMLElement, (void **)&pChild)))
  38. {
  39. // look for first SoftDist tag
  40. pChild->get_tagName(&bstrTag);
  41. if (StrCmpIW(bstrTag, szTag) == 0) {
  42. nLastChild = i;
  43. hr = S_OK;
  44. goto Exit;
  45. }
  46. SAFEFREEBSTR(bstrTag);
  47. SAFERELEASE(pChild);
  48. }
  49. pDispItem->Release();
  50. }
  51. }
  52. }
  53. }
  54. else
  55. {
  56. hr = E_FAIL;
  57. }
  58. Exit:
  59. *ppChildReq = pChild;
  60. if (pChildren)
  61. SAFERELEASE(pChildren);
  62. SAFEFREEBSTR(bstrTag);
  63. return hr;
  64. }
  65. HRESULT GetFirstChildTag(IXMLElement *pRoot, LPCWSTR szTag, IXMLElement **ppChildReq)
  66. {
  67. int nLastChild = -1; // first child, never seen any before this one
  68. return GetNextChildTag(pRoot, szTag, ppChildReq, nLastChild);
  69. }
  70. CCDLAgent::CCDLAgent()
  71. : m_pCCDLAgentBSC(NULL)
  72. , m_szCDF(NULL)
  73. , m_bAcceptSoftware(FALSE)
  74. {
  75. m_sdi.cbSize = sizeof(SOFTDISTINFO);
  76. m_bSilentMode = TRUE;
  77. }
  78. CCDLAgent::~CCDLAgent()
  79. {
  80. SAFERELEASE(m_pSoftDistElement);
  81. SAFERELEASE(m_pSoftDistExt);
  82. CRunDeliveryAgent::SafeRelease(m_pAgent);
  83. SAFEFREEOLESTR(m_szCDF);
  84. SAFEFREEBSTR(m_szErrorText);
  85. SAFEDELETE(m_sdi.szAbstract);
  86. SAFEDELETE(m_sdi.szTitle);
  87. SAFEDELETE(m_sdi.szHREF);
  88. SAFEFREEOLESTR(m_szDistUnit);
  89. }
  90. HRESULT CCDLAgent::StartOperation()
  91. {
  92. HRESULT hr = S_OK, hr2;
  93. // unknown pointers
  94. IUnknown *punk = NULL;
  95. IServiceProvider *pSP;
  96. m_pSoftDistElement = NULL;
  97. if (FAILED(ReadOLESTR(m_pSubscriptionItem, c_szPropURL, &m_szURL)))
  98. {
  99. hr = E_INVALIDARG;
  100. goto Failed;
  101. }
  102. hr2 = E_FAIL;
  103. if (SUCCEEDED(m_pAgentEvents->QueryInterface(IID_IServiceProvider, (void **)&pSP)) && pSP)
  104. {
  105. hr2 = pSP->QueryService(CLSID_XMLDocument, IID_IXMLElement, (void **)&punk);
  106. pSP->Release();
  107. }
  108. if (FAILED(hr2) || !punk)
  109. {
  110. // We are processing a request to pull a CAB, probably from Web Crawler agent.
  111. if (FAILED(ReadOLESTR(m_pSubscriptionItem, L"DistUnit", &m_szDistUnit)) ||
  112. FAILED(ReadDWORD(m_pSubscriptionItem, L"VersionMS",&m_dwVersionMS)) ||
  113. FAILED(ReadDWORD(m_pSubscriptionItem, L"VersionLS", &m_dwVersionLS)))
  114. {
  115. hr = E_INVALIDARG;
  116. goto Failed;
  117. }
  118. m_pSoftDistElement = NULL;
  119. }
  120. else
  121. {
  122. if (FAILED(punk->QueryInterface(IID_IXMLElement, (void **)&m_pSoftDistElement)))
  123. {
  124. SAFERELEASE(punk);
  125. hr = E_INVALIDARG;
  126. goto Failed;
  127. }
  128. SAFERELEASE(punk);
  129. Assert(m_pSoftDistElement);
  130. }
  131. ReadDWORD(m_pSubscriptionItem, c_szPropCrawlMaxSize, &m_dwMaxSizeKB);
  132. ReadDWORD(m_pSubscriptionItem, c_szPropChannelFlags, &m_dwChannelFlags);
  133. ReadDWORD(m_pSubscriptionItem, c_szPropAgentFlags, &m_dwAgentFlags);
  134. hr = CDeliveryAgent::StartOperation();
  135. return hr;
  136. Failed:
  137. SetEndStatus(hr);
  138. SendUpdateNone();
  139. return hr;
  140. }
  141. HRESULT CCDLAgent::StartDownload()
  142. {
  143. IBindCtx *pbc = NULL;
  144. HRESULT hr = S_OK;
  145. LPWSTR szCodeBase;
  146. DWORD dwSize;
  147. BOOL bCleanUpNow = FALSE;
  148. DWORD dwPolicy = 0;
  149. DWORD dwContext = 0;
  150. IInternetSecurityManager * pism = NULL;
  151. if (FAILED(GetEndStatus())) {
  152. hr = GetEndStatus();
  153. goto Exit;
  154. }
  155. hr = CoCreateInstance(CLSID_SoftDistExt, NULL, CLSCTX_INPROC_SERVER, IID_ISoftDistExt, (void **)&m_pSoftDistExt);
  156. if (FAILED(hr))
  157. goto Exit;
  158. // Process SOFTDIST tag structure if present.
  159. if (m_pSoftDistElement != NULL) {
  160. dwPolicy = 0xFFFF0000;
  161. if (FAILED(CoCreateInstance(CLSID_InternetSecurityManager, NULL, CLSCTX_INPROC_SERVER,
  162. IID_IInternetSecurityManager, (void**)&pism)) || !pism)
  163. {
  164. hr = E_ACCESSDENIED;
  165. goto Exit;
  166. }
  167. hr = pism->ProcessUrlAction(m_szURL, URLACTION_CHANNEL_SOFTDIST_PERMISSIONS,
  168. (BYTE *)&dwPolicy, sizeof(dwPolicy),
  169. (BYTE *)&dwContext, sizeof(dwContext), PUAF_NOUI, 0);
  170. pism->Release();
  171. if (FAILED(hr))
  172. {
  173. goto Exit;
  174. }
  175. dwPolicy &= 0xFFFF0000;
  176. if (dwPolicy != URLPOLICY_CHANNEL_SOFTDIST_PROHIBIT
  177. && dwPolicy != URLPOLICY_CHANNEL_SOFTDIST_PRECACHE
  178. && dwPolicy != URLPOLICY_CHANNEL_SOFTDIST_AUTOINSTALL)
  179. {
  180. hr = E_INVALIDARG;
  181. goto Exit;
  182. }
  183. if (dwPolicy == URLPOLICY_CHANNEL_SOFTDIST_PROHIBIT)
  184. {
  185. hr = E_ACCESSDENIED;
  186. goto Exit;
  187. }
  188. hr = m_pSoftDistExt->ProcessSoftDist(m_szCDF, m_pSoftDistElement, &m_sdi);
  189. if (m_sdi.dwFlags & SOFTDIST_FLAG_DELETE_SUBSCRIPTION) {
  190. ISubscriptionMgr *pSubMgr = NULL;
  191. hr = CoCreateInstance(CLSID_SubscriptionMgr, NULL, CLSCTX_INPROC_SERVER, IID_ISubscriptionMgr, (void**)&pSubMgr);
  192. if (SUCCEEDED(hr))
  193. {
  194. hr = pSubMgr->DeleteSubscription(m_szURL,NULL);
  195. pSubMgr->Release();
  196. }
  197. hr = S_FALSE;
  198. }
  199. // Send email & update software?
  200. if (hr == S_OK) {
  201. if (m_sdi.dwFlags) {
  202. m_bSendEmail = TRUE;
  203. } else {
  204. // no usage flag and no restriction implies no email.
  205. m_bSendEmail = FALSE;
  206. }
  207. if (m_sdi.dwFlags & SOFTDIST_FLAG_USAGE_AUTOINSTALL) {
  208. m_bAcceptSoftware = (dwPolicy == URLPOLICY_CHANNEL_SOFTDIST_AUTOINSTALL) ? TRUE : FALSE;
  209. m_bSilentMode = FALSE;
  210. } else if (m_sdi.dwFlags & SOFTDIST_FLAG_USAGE_PRECACHE) {
  211. // to get here, we must have precache or autoinstall policy permissions
  212. m_bAcceptSoftware = TRUE;
  213. } else {
  214. m_bAcceptSoftware = FALSE;
  215. }
  216. } else {
  217. m_bSendEmail = FALSE;
  218. m_bAcceptSoftware = FALSE;
  219. bCleanUpNow = TRUE;
  220. }
  221. // Do only code download from here on.
  222. if (!m_bAcceptSoftware ||
  223. !((m_dwChannelFlags & CHANNEL_AGENT_PRECACHE_SOME) ||
  224. (m_dwChannelFlags & CHANNEL_AGENT_PRECACHE_ALL)) ) {
  225. // No caching allowed, return immediately.
  226. bCleanUpNow = TRUE;
  227. goto Exit;
  228. } else {
  229. if (m_dwChannelFlags & CHANNEL_AGENT_PRECACHE_ALL) {
  230. m_dwMaxSizeKB = 0;
  231. }
  232. }
  233. }
  234. m_pCCDLAgentBSC = new CDLAgentBSC(this, m_dwMaxSizeKB, m_bSilentMode, m_szCDF);
  235. if (m_pCCDLAgentBSC == NULL) {
  236. hr = E_OUTOFMEMORY;
  237. goto Exit;
  238. }
  239. // attempt to use AsyncInstallDistributionUnit
  240. hr = CreateBindCtx(0, &pbc);
  241. if (FAILED(hr)) {
  242. goto Exit;
  243. }
  244. hr = RegisterBindStatusCallback(pbc, m_pCCDLAgentBSC, NULL, 0);
  245. if (FAILED(hr)) {
  246. goto Exit;
  247. }
  248. if (m_pSoftDistElement != NULL) {
  249. hr = m_pSoftDistExt->AsyncInstallDistributionUnit(pbc, NULL, 0, NULL);
  250. if (hr == S_OK) {
  251. SendUpdateNone();
  252. }
  253. } else {
  254. CODEBASEHOLD *pcbh = new CODEBASEHOLD;
  255. if (pcbh == NULL) {
  256. hr = E_OUTOFMEMORY;
  257. goto Exit;
  258. }
  259. pcbh->cbSize = sizeof(CODEBASEHOLD);
  260. pcbh->szDistUnit = m_szDistUnit;
  261. pcbh->szCodeBase = m_szURL;
  262. pcbh->dwVersionMS = m_dwVersionMS;
  263. pcbh->dwVersionLS = m_dwVersionLS;
  264. pcbh->dwStyle = 0;
  265. // Since notification is likely from web crawler and we only support MSICD we
  266. // don't fire a notification back.
  267. hr = m_pSoftDistExt->AsyncInstallDistributionUnit(pbc, NULL, 0, pcbh);
  268. if (hr == S_OK) {
  269. SendUpdateNone();
  270. }
  271. SAFEDELETE(pcbh);
  272. goto Exit;
  273. }
  274. if (hr != E_NOTIMPL) {
  275. // May have succeeded or failed, either way, we are out of here.
  276. goto Exit;
  277. }
  278. hr = m_pSoftDistExt->GetFirstCodeBase(&szCodeBase, &dwSize);
  279. if (SUCCEEDED(hr) && szCodeBase) {
  280. hr = StartNextDownload(szCodeBase,dwSize);
  281. SAFEDELETE(szCodeBase);
  282. } else {
  283. // no CODEBASE, return OK
  284. bCleanUpNow = TRUE;
  285. hr = S_OK;
  286. }
  287. Exit:
  288. // In case of SOFTDIST tag we work asychronously and send an END_REPORT back immediately. If we were called
  289. // to install a particular CAB then CleanUp is called by CDLABSC::OnStopBinding and report is sent back then.
  290. SAFERELEASE(pbc);
  291. if (FAILED(hr) || bCleanUpNow)
  292. {
  293. SetEndStatus(hr);
  294. CleanUp();
  295. }
  296. return hr;
  297. }
  298. HRESULT CCDLAgent::StartNextDownload(LPWSTR wzCodeBase, DWORD dwSize)
  299. {
  300. HRESULT hr = E_FAIL;
  301. DWORD dwTemp = 0;
  302. ISubscriptionItem *pItem;
  303. if (m_dwMaxSizeKB && (dwSize > m_dwMaxSizeKB))
  304. {
  305. hr = INET_E_AGENT_MAX_SIZE_EXCEEDED;
  306. goto Exit;
  307. }
  308. else
  309. {
  310. // Any other type of INSTALL protocol.
  311. // Send notification to WebCrawl agent to crawl the codebase. This should force it in the
  312. // case. Only do this if there is any chance the DL will not overflow the cache.
  313. // Note this will only download the CAB file and not any dependencies inside the CAB. They
  314. // should be included as separate CONFIG entries.
  315. if (m_dwMaxSizeKB && ((m_dwCurSize>>10) > m_dwMaxSizeKB))
  316. {
  317. // We've exceeded our maximum download KB limit and can't continue.
  318. hr = INET_E_AGENT_MAX_SIZE_EXCEEDED;
  319. goto Exit;
  320. }
  321. if (FAILED(hr = DoCloneSubscriptionItem(m_pSubscriptionItem, NULL, &pItem)) || !pItem)
  322. {
  323. goto Exit;
  324. }
  325. dwTemp = DELIVERY_AGENT_FLAG_NO_BROADCAST;
  326. WriteDWORD(pItem, c_szPropAgentFlags, dwTemp);
  327. WriteOLESTR(pItem, c_szPropURL, wzCodeBase);
  328. if (m_dwMaxSizeKB)
  329. {
  330. // KB limit for us to pull.
  331. WriteDWORD(pItem, c_szPropCrawlMaxSize, m_dwMaxSizeKB - (m_dwCurSize>>10));
  332. }
  333. WriteDWORD(pItem, c_szPropCrawlLevels, 0);
  334. m_dwCurSize += dwSize;
  335. m_pAgent = new CRunDeliveryAgent();
  336. if (m_pAgent)
  337. hr = m_pAgent->Init((CRunDeliveryAgentSink *)this, pItem, CLSID_WebCrawlerAgent);
  338. pItem->Release();
  339. if (m_pAgent && SUCCEEDED(hr))
  340. {
  341. hr = m_pAgent->StartAgent();
  342. if (hr == E_PENDING)
  343. {
  344. hr = S_OK;
  345. }
  346. else
  347. {
  348. DBG_WARN("StartNextDownload in CDL agent failed!");
  349. hr = E_FAIL;
  350. }
  351. }
  352. else
  353. {
  354. hr = E_OUTOFMEMORY;
  355. }
  356. }
  357. Exit:
  358. return hr;
  359. }
  360. HRESULT CCDLAgent::OnAgentEnd(const SUBSCRIPTIONCOOKIE *pSubscriptionCookie,
  361. long lSizeDownloaded, HRESULT hrResult, LPCWSTR wszResult,
  362. BOOL fSynchronous)
  363. {
  364. HRESULT hr = S_OK;
  365. BOOL fDone = FALSE;
  366. LPWSTR wzCodeBase = NULL;
  367. DWORD dwSize;
  368. ASSERT(m_pAgent != NULL);
  369. if (fSynchronous)
  370. {
  371. // We must have failed. Let StartNextDownload return failure.
  372. return S_OK;
  373. }
  374. CRunDeliveryAgent::SafeRelease(m_pAgent);
  375. if (SUCCEEDED(hrResult))
  376. {
  377. hr = m_pSoftDistExt->GetNextCodeBase(&wzCodeBase, &dwSize);
  378. if (SUCCEEDED(hr) && wzCodeBase)
  379. {
  380. hr = StartNextDownload(wzCodeBase, dwSize);
  381. SAFEDELETE(wzCodeBase);
  382. if (FAILED(hr)) {
  383. // we are done
  384. fDone = TRUE;
  385. }
  386. } else {
  387. // no more codebases to crawl
  388. hr = S_OK;
  389. fDone = TRUE;
  390. }
  391. }
  392. else
  393. {
  394. hr = hrResult;
  395. fDone = TRUE;
  396. }
  397. if (fDone) {
  398. SetEndStatus(hr);
  399. CleanUp();
  400. }
  401. return hr;
  402. }
  403. void CCDLAgent::CleanUp()
  404. {
  405. if (m_pCCDLAgentBSC != NULL) {
  406. m_pCCDLAgentBSC->Release();
  407. }
  408. m_pCCDLAgentBSC = NULL;
  409. CDeliveryAgent::CleanUp();
  410. }
  411. void CCDLAgent::SetErrorEndText(LPCWSTR szErrorText)
  412. {
  413. if (szErrorText)
  414. m_szErrorText = SysAllocString(szErrorText);
  415. }
  416. HRESULT CCDLAgent::AgentAbort(DWORD dwFlags)
  417. {
  418. HRESULT hr = S_OK;
  419. if (m_pCCDLAgentBSC != NULL )
  420. {
  421. hr = m_pCCDLAgentBSC->Abort();
  422. }
  423. return hr;
  424. }
  425. HRESULT CCDLAgent::AgentPause(DWORD dwFlags)
  426. {
  427. HRESULT hr = S_OK;
  428. if (m_pCCDLAgentBSC != NULL )
  429. {
  430. hr = m_pCCDLAgentBSC->Pause();
  431. }
  432. return hr;
  433. }
  434. HRESULT CCDLAgent::AgentResume(DWORD dwFlags)
  435. {
  436. HRESULT hr = S_OK;
  437. if (m_pCCDLAgentBSC != NULL )
  438. {
  439. hr = m_pCCDLAgentBSC->Resume();
  440. }
  441. return hr;
  442. }
  443. HRESULT CCDLAgent::ModifyUpdateEnd(ISubscriptionItem *pEndItem, UINT *puiRes)
  444. {
  445. VARIANT vHref;
  446. ASSERT(pEndItem);
  447. // The END_REPORT is sent for both functionalities of CDL agent (SOFTDIST and Pull single CAB).
  448. // customize our end status string
  449. switch (GetEndStatus())
  450. {
  451. case E_OUTOFMEMORY : *puiRes = IDS_AGNT_STATUS_SIZELIMIT; break;
  452. case E_FAIL : *puiRes = IDS_CRAWL_STATUS_NOT_OK; break;
  453. case S_FALSE : *puiRes = IDS_CRAWL_STATUS_UNCHANGED; break;
  454. case INET_S_AGENT_PART_FAIL : *puiRes = IDS_CRAWL_STATUS_MOSTLYOK; break;
  455. // This is actually a success code from URLMON
  456. case HRESULT_FROM_WIN32(ERROR_CANCELLED)
  457. : SetEndStatus(S_OK);
  458. *puiRes = IDS_CRAWL_STATUS_OK; break;
  459. case TRUST_E_FAIL : SetEndStatus(TRUST_E_SUBJECT_NOT_TRUSTED);
  460. case TRUST_E_SUBJECT_NOT_TRUSTED :
  461. case HRESULT_FROM_WIN32(ERROR_IO_INCOMPLETE) : SetEndStatus(S_OK);
  462. // fall through
  463. case S_OK : *puiRes = IDS_CRAWL_STATUS_OK; break;
  464. default : *puiRes = IDS_CRAWL_STATUS_NOT_OK; break;
  465. break;
  466. }
  467. // force gleam on this channel if we got S_OK on precaching bits
  468. if (SUCCEEDED(GetEndStatus()) && (GetEndStatus() != S_FALSE)) {
  469. WriteDWORD(pEndItem, c_szPropEnableShortcutGleam, 1);
  470. }
  471. // If we are sending email the status must be S_OK, we incorporate the error
  472. // message into the text body for reporting.
  473. if (m_bSendEmail) {
  474. VariantInit(&vHref);
  475. WriteDWORD(pEndItem, c_szPropEmailFlags, MAILAGENT_FLAG_CUSTOM_MSG);
  476. // This must exist or m_bSendEmail would never have been set in first place.
  477. GetXMLAttribute(m_pSoftDistElement, L"HREF", &vHref);
  478. WriteOLESTR(pEndItem, c_szPropURL, vHref.bstrVal);
  479. VariantClear(&vHref);
  480. if (m_sdi.szTitle) {
  481. BSTR bstrTitle = SysAllocString(m_sdi.szTitle);
  482. if (bstrTitle)
  483. WriteOLESTR(pEndItem, c_szPropEmailTitle, m_sdi.szTitle);
  484. SAFEFREEBSTR(bstrTitle);
  485. }
  486. if (FAILED(GetEndStatus()) && !m_szErrorText) {
  487. m_szErrorText = GetErrorMessage(GetEndStatus());
  488. }
  489. if (m_sdi.szAbstract) {
  490. BSTR bstrAbstract = SysAllocString(m_sdi.szAbstract);
  491. if (bstrAbstract != NULL) {
  492. if (m_szErrorText) {
  493. //This is wrecking havoc with the email message, some resource strings
  494. //have a 'CR/LF' tacked on the end. We kill any that exist.
  495. DWORD dwLen = lstrlenW(m_szErrorText)-1;
  496. while (dwLen > 0 &&
  497. (m_szErrorText[dwLen] == 0x0a
  498. || m_szErrorText[dwLen] == 0x0d
  499. || m_szErrorText[dwLen] == L'.'))
  500. {
  501. m_szErrorText[dwLen] = L'\0';
  502. dwLen--;
  503. }
  504. // BUGBUG - needs cleanup!
  505. CHAR szPrefixMsg[MAX_PATH], szFormattedPrefixMsg[MAX_PATH*2];
  506. if (MLLoadStringA(IDS_CDLAGENT_ERROR_EMAIL, szPrefixMsg, ARRAYSIZE(szPrefixMsg))>0) {
  507. LPWSTR wszNewAbstract = NULL;
  508. LPSTR szNewAbstract = NULL;
  509. wnsprintfA(szFormattedPrefixMsg,
  510. ARRAYSIZE(szFormattedPrefixMsg),
  511. szPrefixMsg,
  512. m_szErrorText);
  513. DWORD dwNewLen = lstrlenA(szFormattedPrefixMsg) + lstrlenW(bstrAbstract) + 4;
  514. szNewAbstract = (LPSTR)LocalAlloc(0,dwNewLen*sizeof(CHAR));
  515. if (szNewAbstract) {
  516. wnsprintfA(szNewAbstract,
  517. dwNewLen*sizeof(CHAR),
  518. "%s%ws",
  519. szFormattedPrefixMsg,
  520. bstrAbstract);
  521. dwNewLen = lstrlenA(szNewAbstract) + 1;
  522. wszNewAbstract = (LPWSTR)LocalAlloc(0,dwNewLen*sizeof(WCHAR));
  523. if (wszNewAbstract &&
  524. (MultiByteToWideChar(CP_ACP, 0, szNewAbstract, -1, wszNewAbstract, dwNewLen)>0)) {
  525. SAFEFREEBSTR(bstrAbstract);
  526. bstrAbstract = SysAllocString(wszNewAbstract);
  527. }
  528. if (wszNewAbstract)
  529. LocalFree(wszNewAbstract);
  530. LocalFree(szNewAbstract);
  531. }
  532. }
  533. }
  534. WriteOLESTR(pEndItem, c_szPropEmailAbstract, bstrAbstract);
  535. SAFEFREEBSTR(bstrAbstract);
  536. }
  537. }
  538. // because user is notified of error we don't pass it on anywhere else
  539. SetEndStatus(S_OK);
  540. WriteSCODE(pEndItem, c_szPropStatusCode, S_OK);
  541. }
  542. ClearAgentFlag(DELIVERY_AGENT_FLAG_NO_BROADCAST);
  543. return CDeliveryAgent::ModifyUpdateEnd(pEndItem, puiRes);
  544. }
  545. LPWSTR CCDLAgent::GetErrorMessage(HRESULT hr)
  546. {
  547. LPSTR szBuf = NULL;
  548. LPWSTR wszBuf = NULL;
  549. DWORD dwLen;
  550. DWORD dwResource = 0;
  551. if (SUCCEEDED(hr))
  552. return NULL;
  553. dwLen = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
  554. hr, 0, (LPTSTR)&szBuf, 0, NULL);
  555. if (!dwLen) {
  556. // NOTE: If out of memory we return NULL.
  557. if (SUCCEEDED(hr))
  558. dwResource = IDS_CDLAGENT_SUCCESS;
  559. else if (hr == TRUST_E_SUBJECT_NOT_TRUSTED)
  560. dwResource = IDS_CDLAGENT_TRUST_ERROR;
  561. else
  562. dwResource = IDS_CDLAGENT_FAILURE;
  563. // We know strings will fit into max_path
  564. WCHAR szTmp[MAX_PATH];
  565. if (MLLoadStringW(dwResource, szTmp, MAX_PATH)>0) {
  566. wszBuf = SysAllocString(szTmp);
  567. }
  568. } else {
  569. WCHAR wszTemp[MAX_PATH];
  570. if (MultiByteToWideChar(CP_ACP, 0, szBuf, -1, wszTemp, MAX_PATH)>0) {
  571. wszBuf = SysAllocString(wszTemp);
  572. } else
  573. wszBuf = NULL;
  574. SAFEDELETE(szBuf);
  575. }
  576. return wszBuf;
  577. }