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.

535 lines
18 KiB

  1. #include "private.h"
  2. #include "notfcvt.h"
  3. #include "subsmgrp.h"
  4. #include "subitem.h"
  5. #include "chanmgr.h"
  6. #include "chanmgrp.h"
  7. #include "helper.h"
  8. #include "shguidp.h" // IID_IChannelMgrPriv
  9. #include <mluisupp.h>
  10. #undef TF_THISMODULE
  11. #define TF_THISMODULE TF_ADMIN
  12. const CHAR c_pszRegKeyNotfMgr[] = "Software\\Microsoft\\Windows\\CurrentVersion\\NotificationMgr";
  13. const CHAR c_pszRegKeyScheduleItems[] = "Software\\Microsoft\\Windows\\CurrentVersion\\NotificationMgr\\SchedItems 0.6";
  14. const CHAR c_pszRegKeyScheduleGroup[] = "Software\\Microsoft\\Windows\\CurrentVersion\\NotificationMgr\\ScheduleGroup 0.6";
  15. const WCHAR c_wszIE4IntlPre[] = L"http://www.microsoft.com/ie_intl/";
  16. const WCHAR c_wszIE4IntlPre2[] = L"http://www.microsoft.com/windows/ie_intl/";
  17. const WCHAR c_wszIE4IntlPost[] = L"/ie40/download/cdf/ie4updates-";
  18. const WCHAR c_wszIE4English[] = L"http://www.microsoft.com/ie/ie40/download/cdf/ie4updates-";
  19. const WCHAR c_wszIE4English2[] = L"http://www.microsoft.com/windows/ie/ie40/download/cdf/ie4updates-";
  20. HRESULT ConvertNotfMgrScheduleGroup(NOTIFICATIONCOOKIE *pSchedCookie);
  21. BOOL IsIE4UpdateChannel(LPCWSTR pwszURL)
  22. {
  23. BOOL bResult = FALSE;
  24. int len = lstrlenW(pwszURL);
  25. // For update channels from the non-international version, simply compare the
  26. // English base name witht the passed in URL.
  27. //
  28. // International update channels look like:
  29. // http://www.microsoft.com/ie_intl/XX/ie40/download/cdf/ie4updates-XX.cdf
  30. // So we do two compares skipping the middle XX
  31. if (
  32. (
  33. (len > ARRAYSIZE(c_wszIE4English)) &&
  34. (0 == memcmp(c_wszIE4English, pwszURL, sizeof(c_wszIE4English) - sizeof(WCHAR)))
  35. )
  36. ||
  37. (
  38. (len > ARRAYSIZE(c_wszIE4English2)) &&
  39. (0 == memcmp(c_wszIE4English2, pwszURL, sizeof(c_wszIE4English2) - sizeof(WCHAR)))
  40. )
  41. ||
  42. (
  43. (len > (ARRAYSIZE(c_wszIE4IntlPre) + ARRAYSIZE(c_wszIE4IntlPost) + 4)) &&
  44. (0 == memcmp(c_wszIE4IntlPre, pwszURL, sizeof(c_wszIE4IntlPre) - sizeof(WCHAR))) &&
  45. (0 == memcmp(c_wszIE4IntlPost, pwszURL + ARRAYSIZE(c_wszIE4IntlPre) + 1,
  46. sizeof(c_wszIE4IntlPost) - sizeof(WCHAR)))
  47. )
  48. ||
  49. (
  50. (len > (ARRAYSIZE(c_wszIE4IntlPre2) + ARRAYSIZE(c_wszIE4IntlPost) + 4)) &&
  51. (0 == memcmp(c_wszIE4IntlPre2, pwszURL, sizeof(c_wszIE4IntlPre2) - sizeof(WCHAR))) &&
  52. (0 == memcmp(c_wszIE4IntlPost, pwszURL + ARRAYSIZE(c_wszIE4IntlPre2) + 1,
  53. sizeof(c_wszIE4IntlPost) - sizeof(WCHAR)))
  54. )
  55. )
  56. {
  57. bResult = TRUE;
  58. }
  59. return bResult;
  60. }
  61. struct NOTFSUBS
  62. {
  63. NOTIFICATIONITEM ni;
  64. NOTIFICATIONITEMEXTRA nix;
  65. CLSID clsidItem; // Ignore
  66. NOTIFICATIONCOOKIE notfCookie;
  67. NOTIFICATIONTYPE notfType;
  68. ULONG nProps;
  69. // Variable length data here:
  70. //SaveSTATPROPMAP statPropMap;
  71. //char szPropName[];
  72. //BYTE variant property data
  73. //...
  74. //SaveSTATPROPMAP statPropMap;
  75. //char szPropName[];
  76. //BYTE variant property data
  77. };
  78. HRESULT SubscriptionFromNotification(NOTFSUBS *pns,
  79. LPCWSTR pwszURL,
  80. LPCWSTR pwszName,
  81. const LPWSTR rgwszName[],
  82. VARIANT rgValue[])
  83. {
  84. HRESULT hr;
  85. ASSERT(NULL != pns);
  86. ASSERT(NULL != rgwszName);
  87. ASSERT(NULL != rgValue);
  88. if ((pns->ni.NotificationType == NOTIFICATIONTYPE_AGENT_START) &&
  89. (pns->nix.PackageFlags & PF_SCHEDULED) &&
  90. (NULL != pwszURL) &&
  91. (NULL != pwszName) &&
  92. (!IsIE4UpdateChannel(pwszURL)))
  93. {
  94. SUBSCRIPTIONITEMINFO sii;
  95. sii.cbSize = sizeof(SUBSCRIPTIONITEMINFO);
  96. sii.dwFlags = 0;
  97. sii.dwPriority = 0;
  98. sii.ScheduleGroup = CLSID_NULL;
  99. sii.clsidAgent = pns->ni.clsidDest;
  100. hr = AddUpdateSubscription(&pns->notfCookie,
  101. &sii,
  102. pwszURL,
  103. pns->nProps,
  104. rgwszName,
  105. rgValue);
  106. if (SUCCEEDED(hr))
  107. {
  108. if (NOTFCOOKIE_SCHEDULE_GROUP_MANUAL != pns->ni.groupCookie)
  109. {
  110. ISubscriptionItem *psi;
  111. hr = SubscriptionItemFromCookie(FALSE, &pns->notfCookie, &psi);
  112. if (SUCCEEDED(hr))
  113. {
  114. SYNCSCHEDULECOOKIE schedCookie = GUID_NULL;
  115. if (GUID_NULL == pns->ni.groupCookie)
  116. {
  117. WCHAR wszSchedName[MAX_PATH];
  118. CreatePublisherScheduleNameW(wszSchedName, ARRAYSIZE(wszSchedName),
  119. NULL, pwszName);
  120. // Create the schedule
  121. hr = CreateSchedule(wszSchedName, SYNCSCHEDINFO_FLAGS_READONLY,
  122. &schedCookie, &pns->ni.TaskTrigger, FALSE);
  123. // If we created a new one or for some strange reason
  124. // "MSN Recommended Schedule" already exists we go with it
  125. if (SUCCEEDED(hr) || (hr == SYNCMGR_E_NAME_IN_USE))
  126. {
  127. // sii should have been initialized and set above
  128. ASSERT(sizeof(SUBSCRIPTIONITEMINFO) == sii.cbSize);
  129. ASSERT(GUID_NULL == sii.ScheduleGroup);
  130. sii.ScheduleGroup = schedCookie;
  131. hr = psi->SetSubscriptionItemInfo(&sii);
  132. }
  133. }
  134. else
  135. {
  136. schedCookie = pns->ni.groupCookie;
  137. hr = ConvertNotfMgrScheduleGroup(&schedCookie);
  138. }
  139. if (SUCCEEDED(hr))
  140. {
  141. SYNC_HANDLER_ITEM_INFO shii;
  142. shii.handlerID = CLSID_WebCheckOfflineSync;
  143. shii.itemID = pns->notfCookie;
  144. shii.hIcon = NULL;
  145. StrCpyNW(shii.wszItemName, pwszName, ARRAYSIZE(shii.wszItemName));
  146. shii.dwCheckState = SYNCMGRITEMSTATE_CHECKED;
  147. // Not much we can do if this fails other than jump up and down
  148. // and scream like a baby.
  149. hr = AddScheduledItem(&shii, &schedCookie);
  150. }
  151. psi->Release();
  152. }
  153. }
  154. }
  155. }
  156. else
  157. {
  158. TraceMsgA(TF_THISMODULE, "Not converting Notification subscription %S URL: %S", pwszName, pwszURL);
  159. hr = S_FALSE;
  160. }
  161. return hr;
  162. }
  163. HRESULT ConvertScheduleItem(CHAR *pszSubsName)
  164. {
  165. HRESULT hr = E_FAIL;
  166. HKEY hkey;
  167. CHAR szKeyName[MAX_PATH];
  168. // Build path to this notification item
  169. strcpy(szKeyName, c_pszRegKeyScheduleItems);
  170. szKeyName[sizeof(c_pszRegKeyScheduleItems) - 1] = '\\';
  171. strcpy(szKeyName + sizeof(c_pszRegKeyScheduleItems), pszSubsName);
  172. // We just enumerated so this should be here!
  173. if (RegOpenKeyExA(HKEY_CURRENT_USER, szKeyName, 0, KEY_READ, &hkey)
  174. == ERROR_SUCCESS)
  175. {
  176. DWORD dwType;
  177. DWORD dwSize;
  178. // Read the {GUID} value. We need to alloc a buffer but don't know how big yet.
  179. // This gets us the size and type. If it's not binary or not big enough, bail.
  180. if ((RegQueryValueExA(hkey, pszSubsName, NULL, &dwType, NULL, &dwSize) == ERROR_SUCCESS) &&
  181. (dwType == REG_BINARY) &&
  182. (dwSize >= sizeof(NOTFSUBS)))
  183. {
  184. BYTE *pData = new BYTE[dwSize];
  185. if (NULL != pData)
  186. {
  187. if (RegQueryValueExA(hkey, pszSubsName, NULL, &dwType, pData, &dwSize) == ERROR_SUCCESS)
  188. {
  189. // Shouldn't have gotten here based on the check above.
  190. ASSERT(dwType == REG_BINARY);
  191. ASSERT(dwSize >= sizeof(NOTFSUBS));
  192. ULONG i;
  193. NOTFSUBS *pns = (NOTFSUBS *)pData;
  194. // Point to the repeated variable size block
  195. BYTE *pVarData = pData + FIELD_OFFSET(NOTFSUBS, nProps) + sizeof(ULONG);
  196. // Allocate buffers to hold the arrays of property names and values
  197. WCHAR **ppwszPropNames = new WCHAR *[pns->nProps];
  198. VARIANT *pVars = new VARIANT[pns->nProps];
  199. WCHAR *pwszURL = NULL;
  200. WCHAR *pwszName = NULL;
  201. if ((NULL != ppwszPropNames) && (NULL != pVars))
  202. {
  203. // adjust size remaining
  204. dwSize -= sizeof(NOTFSUBS);
  205. for (i = 0, hr = S_OK;
  206. (i < pns->nProps) && (dwSize >= sizeof(SaveSTATPROPMAP)) &&
  207. SUCCEEDED(hr);
  208. i++)
  209. {
  210. SaveSTATPROPMAP *pspm = (SaveSTATPROPMAP *)pVarData;
  211. CHAR *pszPropName = (CHAR *)(pVarData + sizeof(SaveSTATPROPMAP));
  212. DWORD cbUsed;
  213. ppwszPropNames[i] = new WCHAR[pspm->cbStrLen + 1];
  214. if (NULL == ppwszPropNames[i])
  215. {
  216. hr = E_OUTOFMEMORY;
  217. break;
  218. }
  219. MultiByteToWideChar(CP_ACP, 0, pszPropName, pspm->cbStrLen,
  220. ppwszPropNames[i], pspm->cbStrLen);
  221. // Point to where the variant blob starts
  222. pVarData += sizeof(SaveSTATPROPMAP) + pspm->cbStrLen;
  223. // adjust size remaining
  224. dwSize -= sizeof(SaveSTATPROPMAP) + pspm->cbStrLen;
  225. hr = BlobToVariant(pVarData, dwSize, &pVars[i], &cbUsed, TRUE);
  226. if ((3 == pspm->cbStrLen)
  227. && (StrCmpNIA(pszPropName, "URL", 3) == 0))
  228. {
  229. pwszURL = pVars[i].bstrVal;
  230. }
  231. else if ((4 == pspm->cbStrLen)
  232. && (StrCmpNIA(pszPropName, "Name", 4) == 0))
  233. {
  234. pwszName = pVars[i].bstrVal;
  235. }
  236. // Point to start of next SaveSTATPROPMAP
  237. pVarData += cbUsed;
  238. // adjust size remaining
  239. dwSize -= cbUsed;
  240. }
  241. if (SUCCEEDED(hr))
  242. {
  243. hr = SubscriptionFromNotification(pns,
  244. pwszURL,
  245. pwszName,
  246. ppwszPropNames,
  247. pVars);
  248. }
  249. else
  250. {
  251. TraceMsgA(TF_THISMODULE, "Not converting notification subscription %s", pszSubsName);
  252. }
  253. for (i = 0; i < pns->nProps; i++)
  254. {
  255. if (ppwszPropNames[i])
  256. {
  257. delete [] ppwszPropNames[i];
  258. }
  259. VariantClear(&pVars[i]);
  260. }
  261. }
  262. else
  263. {
  264. hr = E_OUTOFMEMORY;
  265. }
  266. SAFEDELETE(ppwszPropNames);
  267. SAFEDELETE(pVars);
  268. }
  269. delete [] pData;
  270. }
  271. else
  272. {
  273. hr = E_OUTOFMEMORY;
  274. }
  275. }
  276. }
  277. return hr;
  278. }
  279. HRESULT ConvertNotfMgrSubscriptions()
  280. {
  281. HRESULT hr = S_OK;
  282. HKEY hkey;
  283. if (RegOpenKeyExA(HKEY_CURRENT_USER, c_pszRegKeyScheduleItems, 0, KEY_READ, &hkey)
  284. == ERROR_SUCCESS)
  285. {
  286. int i = 0;
  287. CHAR szSubsName[MAX_PATH];
  288. TraceMsg(TF_THISMODULE, "Converting Notification Mgr subscriptions");
  289. while (RegEnumKeyA(hkey, i++, szSubsName, sizeof(szSubsName)) == ERROR_SUCCESS)
  290. {
  291. HRESULT hrConvert = ConvertScheduleItem(szSubsName);
  292. if (FAILED(hrConvert))
  293. {
  294. ASSERT(0);
  295. hr = S_FALSE;
  296. // Something failed, should we break or keep on truckin'?
  297. // break;
  298. }
  299. }
  300. RegCloseKey(hkey);
  301. }
  302. else
  303. {
  304. TraceMsg(TF_THISMODULE, "No Notification Mgr subscriptions to convert");
  305. // No Notification Manager schedule items key so there's nothing to do...
  306. hr = S_FALSE;
  307. }
  308. return hr;
  309. }
  310. struct NOTFSCHED
  311. {
  312. SCHEDULEGROUPITEM sgi;
  313. DWORD cchName;
  314. WCHAR wszName[1]; // varies depending on cchName
  315. };
  316. HRESULT ConvertNotfMgrScheduleGroup(NOTIFICATIONCOOKIE *pSchedCookie)
  317. {
  318. HRESULT hr = S_OK;
  319. if (!ScheduleCookieExists(pSchedCookie))
  320. {
  321. HKEY hkey;
  322. DWORD dwResult;
  323. dwResult = RegOpenKeyExA(HKEY_CURRENT_USER, c_pszRegKeyScheduleGroup, 0, KEY_READ, &hkey);
  324. if (ERROR_SUCCESS == dwResult)
  325. {
  326. TCHAR szGuid[GUIDSTR_MAX];
  327. DWORD dwType;
  328. DWORD cbSize;
  329. SHStringFromGUID(*pSchedCookie, szGuid, ARRAYSIZE(szGuid));
  330. dwResult = RegQueryValueEx(hkey, szGuid, NULL, &dwType, NULL, &cbSize);
  331. if (ERROR_SUCCESS == dwResult)
  332. {
  333. BYTE *pData = new BYTE[cbSize];
  334. if (NULL != pData)
  335. {
  336. dwResult = RegQueryValueEx(hkey, szGuid, NULL, &dwType, pData, &cbSize);
  337. if (ERROR_SUCCESS == dwResult)
  338. {
  339. if (dwType == REG_BINARY)
  340. {
  341. NOTFSCHED *pns = (NOTFSCHED *)pData;
  342. hr = CreateSchedule(pns->wszName, 0, &pns->sgi.GroupCookie,
  343. &pns->sgi.TaskTrigger, TRUE);
  344. if (SYNCMGR_E_NAME_IN_USE == hr)
  345. {
  346. hr = S_OK;
  347. }
  348. }
  349. else
  350. {
  351. hr = E_UNEXPECTED;
  352. }
  353. }
  354. else
  355. {
  356. hr = HRESULT_FROM_WIN32(dwResult);
  357. }
  358. delete [] pData;
  359. }
  360. else
  361. {
  362. hr = E_OUTOFMEMORY;
  363. }
  364. }
  365. else
  366. {
  367. hr = HRESULT_FROM_WIN32(dwResult);
  368. }
  369. RegCloseKey(hkey);
  370. }
  371. else
  372. {
  373. hr = HRESULT_FROM_WIN32(dwResult);
  374. }
  375. }
  376. else
  377. {
  378. hr = S_FALSE;
  379. }
  380. return hr;
  381. }
  382. HRESULT WhackIE4UpdateChannel()
  383. {
  384. HRESULT hr;
  385. IChannelMgr *pChannelMgr;
  386. hr = CoCreateInstance(CLSID_ChannelMgr, NULL, CLSCTX_INPROC_SERVER,
  387. IID_IChannelMgr, (void**)&pChannelMgr);
  388. if (SUCCEEDED(hr))
  389. {
  390. IEnumChannels *pEnumChannels;
  391. hr = pChannelMgr->EnumChannels(CHANENUM_ALLFOLDERS | CHANENUM_PATH | CHANENUM_URL,
  392. NULL, &pEnumChannels);
  393. if (SUCCEEDED(hr))
  394. {
  395. CHANNELENUMINFO cei;
  396. while (S_OK == pEnumChannels->Next(1, &cei, NULL))
  397. {
  398. if (IsIE4UpdateChannel(cei.pszURL))
  399. {
  400. TraceMsgA(TF_THISMODULE, "Whacking IE 4 update channel: %S %S", cei.pszURL, cei.pszPath);
  401. hr = pChannelMgr->DeleteChannelShortcut(cei.pszPath);
  402. ASSERT(SUCCEEDED(hr));
  403. }
  404. CoTaskMemFree(cei.pszURL);
  405. CoTaskMemFree(cei.pszPath);
  406. }
  407. pEnumChannels->Release();
  408. }
  409. pChannelMgr->Release();
  410. }
  411. return hr;
  412. }
  413. HRESULT FixupChannelScreenSaver()
  414. {
  415. HRESULT hr;
  416. IChannelMgrPriv2 *pChannelMgrPriv2;
  417. hr = CoCreateInstance(CLSID_ChannelMgr, NULL, CLSCTX_INPROC_SERVER,
  418. IID_IChannelMgrPriv2, (void**)&pChannelMgrPriv2);
  419. if (SUCCEEDED(hr))
  420. {
  421. TraceMsg(TF_THISMODULE, "Refreshing IE 4 Screen Saver URLs");
  422. hr = pChannelMgrPriv2->RefreshScreenSaverURLs();
  423. #ifdef DEBUG
  424. if (FAILED(hr))
  425. {
  426. DBG("Error refreshing screen saver urls!");
  427. }
  428. #endif
  429. pChannelMgrPriv2->Release();
  430. }
  431. return hr;
  432. }
  433. HRESULT ConvertIE4Subscriptions()
  434. {
  435. HRESULT hr;
  436. hr = ConvertNotfMgrSubscriptions();
  437. ASSERT(SUCCEEDED(hr));
  438. hr = WhackIE4UpdateChannel();
  439. ASSERT(SUCCEEDED(hr));
  440. hr = FixupChannelScreenSaver();
  441. ASSERT(SUCCEEDED(hr));
  442. return hr;
  443. }