Leaked source code of windows server 2003
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.

894 lines
28 KiB

  1. /******************************************************************************
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. HyperLinks.cpp
  5. Abstract:
  6. This file contains the implementation of the HyperLinks library.
  7. Revision History:
  8. Davide Massarenti (Dmassare) 11/28/2000
  9. created
  10. ******************************************************************************/
  11. #include "stdafx.h"
  12. ////////////////////////////////////////////////////////////////////////////////
  13. static const DATE l_TIME_hour = 1.0 / 24.0;
  14. static const DATE l_TIME_minute = l_TIME_hour / 60.0;
  15. static const DATE l_TIME_second = l_TIME_hour / 60.0;
  16. static const DATE l_TIME_timeout = l_TIME_minute * 5.0;
  17. static const WCHAR l_szMS_ITS [] = L"ms-its:";
  18. static const WCHAR l_szMSITSTORE [] = L"mk:@MSITStore:";
  19. static const WCHAR l_szITS [] = L"its:";
  20. static const WCHAR l_szHOMEPAGE [] = L"hcp://services/centers/homepage";
  21. static const WCHAR l_szSUPPORT [] = L"hcp://services/centers/support";
  22. static const WCHAR l_szOPTIONS [] = L"hcp://services/centers/options";
  23. static const WCHAR l_szUPDATE [] = L"hcp://services/centers/update";
  24. static const WCHAR l_szCOMPAT [] = L"hcp://services/centers/compat";
  25. static const WCHAR l_szTOOLS [] = L"hcp://services/centers/tools";
  26. static const WCHAR l_szERRMSG [] = L"hcp://services/centers/errmsg";
  27. static const WCHAR l_szSEARCH [] = L"hcp://services/search";
  28. static const WCHAR l_szINDEX [] = L"hcp://services/index";
  29. static const WCHAR l_szSUBSITE [] = L"hcp://services/subsite";
  30. static const WCHAR l_szFULLWINDOW [] = L"hcp://services/layout/fullwindow";
  31. static const WCHAR l_szCONTENTONLY[] = L"hcp://services/layout/contentonly";
  32. static const WCHAR l_szKIOSK [] = L"hcp://services/layout/kiosk";
  33. static const WCHAR l_szXML [] = L"hcp://services/layout/xml";
  34. static const WCHAR l_szREDIRECT [] = L"hcp://services/redirect";
  35. static const WCHAR l_szHCP [] = L"hcp://";
  36. static const WCHAR l_szHCP_redir [] = L"hcp:";
  37. static const WCHAR l_szAPPLICATION[] = L"app:";
  38. static const WCHAR l_szRESOURCE [] = L"res://";
  39. //////////////////////////////////////////////////////////////////////////////////
  40. typedef enum
  41. {
  42. QFT_TEXT ,
  43. QFT_URL ,
  44. QFT_TAXONOMY ,
  45. QFT_APPLICATION,
  46. } QueryFieldType;
  47. struct QueryField
  48. {
  49. LPCWSTR szName;
  50. QueryFieldType qft;
  51. bool fOptional;
  52. };
  53. struct Pattern
  54. {
  55. LPCWSTR szTxt;
  56. size_t iLen; /* -1 for complete match */
  57. HyperLinks::Format fmt;
  58. const QueryField* rgQueryFields;
  59. size_t iQueryFields;
  60. };
  61. ////////////////////
  62. static const QueryField l_rgTopic [] = { { L"topic" , QFT_URL , false } };
  63. static const QueryField l_rgTopicOpt[] = { { L"topic" , QFT_URL , true } };
  64. static const QueryField l_rgSEARCH [] = { { L"query" , QFT_TEXT , false } ,
  65. { L"topic" , QFT_URL , true } };
  66. static const QueryField l_rgINDEX [] = { { L"scope" , QFT_APPLICATION, true } ,
  67. { L"select" , QFT_APPLICATION, true } ,
  68. { L"topic" , QFT_URL , true } };
  69. static const QueryField l_rgSUBSITE [] = { { L"node" , QFT_TAXONOMY , false } ,
  70. { L"select" , QFT_TAXONOMY , true } ,
  71. { L"topic" , QFT_URL , true } };
  72. static const QueryField l_rgXML [] = { { L"definition" , QFT_URL , false } ,
  73. { L"topic" , QFT_URL , true } };
  74. static const QueryField l_rgREDIRECT[] = { { L"online" , QFT_URL , false } ,
  75. { L"offline" , QFT_URL , false } };
  76. static const QueryField l_rgAPP [] = { { L"topic" , QFT_URL , true } };
  77. static const Pattern l_rgPattern[] =
  78. {
  79. { l_szMS_ITS , MAXSTRLEN( l_szMS_ITS ), HyperLinks::FMT_MSITS },
  80. { l_szMSITSTORE , MAXSTRLEN( l_szMSITSTORE ), HyperLinks::FMT_MSITS },
  81. { l_szITS , MAXSTRLEN( l_szITS ), HyperLinks::FMT_MSITS },
  82. ////////////////////
  83. { l_szHOMEPAGE , -1 , HyperLinks::FMT_CENTER_HOMEPAGE },
  84. { l_szSUPPORT , -1 , HyperLinks::FMT_CENTER_SUPPORT , l_rgTopicOpt, ARRAYSIZE(l_rgTopicOpt ) },
  85. { l_szOPTIONS , -1 , HyperLinks::FMT_CENTER_OPTIONS , l_rgTopicOpt, ARRAYSIZE(l_rgTopicOpt ) },
  86. { l_szUPDATE , -1 , HyperLinks::FMT_CENTER_UPDATE },
  87. { l_szCOMPAT , -1 , HyperLinks::FMT_CENTER_COMPAT },
  88. { l_szTOOLS , -1 , HyperLinks::FMT_CENTER_TOOLS , l_rgTopicOpt, ARRAYSIZE(l_rgTopicOpt ) },
  89. { l_szERRMSG , -1 , HyperLinks::FMT_CENTER_ERRMSG },
  90. { l_szSEARCH , -1 , HyperLinks::FMT_SEARCH , l_rgSEARCH , ARRAYSIZE(l_rgSEARCH ) },
  91. { l_szINDEX , -1 , HyperLinks::FMT_INDEX , l_rgINDEX , ARRAYSIZE(l_rgINDEX ) },
  92. { l_szSUBSITE , -1 , HyperLinks::FMT_SUBSITE , l_rgSUBSITE , ARRAYSIZE(l_rgSUBSITE ) },
  93. { l_szFULLWINDOW , -1 , HyperLinks::FMT_LAYOUT_FULLWINDOW , l_rgTopic , ARRAYSIZE(l_rgTopic ) },
  94. { l_szCONTENTONLY, -1 , HyperLinks::FMT_LAYOUT_CONTENTONLY, l_rgTopic , ARRAYSIZE(l_rgTopic ) },
  95. { l_szKIOSK , -1 , HyperLinks::FMT_LAYOUT_KIOSK , l_rgTopic , ARRAYSIZE(l_rgTopic ) },
  96. { l_szXML , -1 , HyperLinks::FMT_LAYOUT_XML , l_rgXML , ARRAYSIZE(l_rgXML ) },
  97. { l_szREDIRECT , -1 , HyperLinks::FMT_REDIRECT , l_rgREDIRECT, ARRAYSIZE(l_rgREDIRECT ) },
  98. { l_szHCP , MAXSTRLEN( l_szHCP ), HyperLinks::FMT_HCP },
  99. { l_szHCP_redir , MAXSTRLEN( l_szHCP_redir ), HyperLinks::FMT_HCP_REDIR },
  100. ////////////////////
  101. { l_szAPPLICATION, MAXSTRLEN( l_szAPPLICATION ), HyperLinks::FMT_APPLICATION , l_rgAPP , ARRAYSIZE(l_rgAPP ) },
  102. ////////////////////
  103. { l_szRESOURCE , MAXSTRLEN( l_szRESOURCE ), HyperLinks::FMT_RESOURCE },
  104. ////////////////////
  105. { NULL }
  106. };
  107. HyperLinks::ParsedUrl::ParsedUrl()
  108. {
  109. // MPC::wstring m_strURL;
  110. m_fmt = HyperLinks::FMT_INVALID; // Format m_fmt;
  111. m_state = HyperLinks::STATE_INVALID; // State m_state;
  112. m_dLastChecked = 0; // DATE m_dLastChecked;
  113. m_fBackground = true; // bool m_fBackground;
  114. //
  115. // MPC::wstring m_strBasePart;
  116. // MPC::WStringLookup m_mapQuery;
  117. //
  118. m_hcpRedir = false; // bool m_hcpRedir;
  119. }
  120. HRESULT HyperLinks::ParsedUrl::Initialize( /*[in]*/ LPCWSTR szURL )
  121. {
  122. __HCP_FUNC_ENTRY( "HyperLinks::ParsedUrl::Initialize" );
  123. HRESULT hr;
  124. SANITIZEWSTR(szURL);
  125. m_strURL = szURL;
  126. m_fmt = HyperLinks::FMT_INVALID;
  127. m_state = HyperLinks::STATE_NOTPROCESSED;
  128. MPC::HTML::ParseHREF( m_strURL.c_str(), m_strBasePart, m_mapQuery );
  129. if(m_strBasePart.size() == 0)
  130. {
  131. m_state = HyperLinks::STATE_MALFORMED;
  132. }
  133. else if(MPC::MSITS::IsCHM( m_strBasePart.c_str() ))
  134. {
  135. m_fmt = HyperLinks::FMT_MSITS;
  136. }
  137. else
  138. {
  139. CComBSTR bstrURL( m_strBasePart.c_str() ); if(bstrURL) ::CharLowerW( bstrURL );
  140. szURL = bstrURL;
  141. for(const Pattern* ptr=l_rgPattern; ptr->szTxt; ptr++)
  142. {
  143. int iCmp;
  144. if(ptr->iLen) iCmp = wcsncmp( szURL, ptr->szTxt, ptr->iLen );
  145. else iCmp = wcscmp ( szURL, ptr->szTxt );
  146. if(iCmp == 0)
  147. {
  148. const QueryField* field = ptr->rgQueryFields;
  149. for(size_t i=0; i<ptr->iQueryFields; i++, field++)
  150. {
  151. CComBSTR bstrValue;
  152. if(GetQueryField( field->szName, bstrValue ) == false)
  153. {
  154. if(field->fOptional == false)
  155. {
  156. m_state = HyperLinks::STATE_MALFORMED;
  157. break;
  158. }
  159. }
  160. else
  161. {
  162. if(field->qft == QFT_TEXT)
  163. {
  164. ;
  165. }
  166. else if(field->qft == QFT_URL)
  167. {
  168. if(FAILED(IsValid( bstrValue )))
  169. {
  170. m_state = HyperLinks::STATE_MALFORMED;
  171. break;
  172. }
  173. }
  174. else if(field->qft == QFT_TAXONOMY)
  175. {
  176. /* TO DO */
  177. }
  178. else if(field->qft == QFT_APPLICATION)
  179. {
  180. /* TO DO */
  181. }
  182. }
  183. }
  184. m_fmt = ptr->fmt;
  185. break;
  186. }
  187. }
  188. //
  189. // If the URL begins with HCP://, check if it's valid HCP or is HCP redirection
  190. //
  191. if(m_fmt == HyperLinks::FMT_HCP)
  192. {
  193. if (CHCPProtocol::IsHCPRedirection(szURL))
  194. {
  195. // Treat as HCP redirection
  196. m_fmt = HyperLinks::FMT_HCP_REDIR;
  197. m_hcpRedir = true;
  198. __MPC_SET_ERROR_AND_EXIT(hr, Initialize( m_strURL.c_str() + MAXSTRLEN( l_szHCP ) ));
  199. }
  200. }
  201. //
  202. // If the URL begins with HCP: but not HCP://, it's a protocol redirection, so recurse.
  203. //
  204. if(m_fmt == HyperLinks::FMT_HCP_REDIR)
  205. {
  206. m_hcpRedir = true;
  207. __MPC_SET_ERROR_AND_EXIT(hr, Initialize( m_strURL.c_str() + MAXSTRLEN( l_szHCP_redir ) ));
  208. }
  209. if(m_fmt == HyperLinks::FMT_INVALID) // Still not resolved...
  210. {
  211. MPC::URL url;
  212. INTERNET_SCHEME scheme;
  213. if(SUCCEEDED(url.put_URL ( szURL )) &&
  214. SUCCEEDED(url.get_Scheme( scheme )) )
  215. {
  216. switch(scheme)
  217. {
  218. case INTERNET_SCHEME_UNKNOWN : m_fmt = HyperLinks::FMT_INTERNET_UNKNOWN ; break;
  219. case INTERNET_SCHEME_FTP : m_fmt = HyperLinks::FMT_INTERNET_FTP ; break;
  220. case INTERNET_SCHEME_GOPHER : m_fmt = HyperLinks::FMT_INTERNET_GOPHER ; break;
  221. case INTERNET_SCHEME_HTTP : m_fmt = HyperLinks::FMT_INTERNET_HTTP ; break;
  222. case INTERNET_SCHEME_HTTPS : m_fmt = HyperLinks::FMT_INTERNET_HTTPS ; break;
  223. case INTERNET_SCHEME_FILE : m_fmt = HyperLinks::FMT_INTERNET_FILE ; break;
  224. case INTERNET_SCHEME_NEWS : m_fmt = HyperLinks::FMT_INTERNET_NEWS ; break;
  225. case INTERNET_SCHEME_MAILTO : m_fmt = HyperLinks::FMT_INTERNET_MAILTO ; break;
  226. case INTERNET_SCHEME_SOCKS : m_fmt = HyperLinks::FMT_INTERNET_SOCKS ; break;
  227. case INTERNET_SCHEME_JAVASCRIPT: m_fmt = HyperLinks::FMT_INTERNET_JAVASCRIPT; break;
  228. case INTERNET_SCHEME_VBSCRIPT : m_fmt = HyperLinks::FMT_INTERNET_VBSCRIPT ; break;
  229. default : m_state = HyperLinks::STATE_MALFORMED ; break;
  230. }
  231. }
  232. }
  233. }
  234. hr = S_OK;
  235. __HCP_FUNC_CLEANUP;
  236. __HCP_FUNC_EXIT(hr);
  237. }
  238. bool HyperLinks::ParsedUrl::IsLocal()
  239. {
  240. switch(m_fmt)
  241. {
  242. case HyperLinks::FMT_INTERNET_UNKNOWN :
  243. case HyperLinks::FMT_INTERNET_FTP :
  244. case HyperLinks::FMT_INTERNET_GOPHER :
  245. case HyperLinks::FMT_INTERNET_HTTP :
  246. case HyperLinks::FMT_INTERNET_HTTPS :
  247. case HyperLinks::FMT_INTERNET_FILE :
  248. case HyperLinks::FMT_INTERNET_NEWS :
  249. case HyperLinks::FMT_INTERNET_MAILTO :
  250. case HyperLinks::FMT_INTERNET_SOCKS :
  251. case HyperLinks::FMT_INTERNET_JAVASCRIPT:
  252. case HyperLinks::FMT_INTERNET_VBSCRIPT :
  253. return false;
  254. case HyperLinks::FMT_MSITS:
  255. //
  256. // Make sure it's not on a network share!
  257. //
  258. {
  259. CComBSTR bstrStorageName;
  260. CComBSTR bstrFilePath;
  261. if(MPC::MSITS::IsCHM( m_strURL.c_str(), &bstrStorageName, &bstrFilePath ))
  262. {
  263. if(wcsncmp( L"\\\\", SAFEBSTR(bstrStorageName), 2 ) == 0)
  264. {
  265. return false;
  266. }
  267. }
  268. }
  269. break;
  270. }
  271. return true;
  272. }
  273. HyperLinks::State HyperLinks::ParsedUrl::CheckState( /*[in/out]*/ bool& fFirstWinInetUse )
  274. {
  275. HRESULT hr;
  276. State state = HyperLinks::STATE_NOTFOUND;
  277. LPCWSTR szURL = m_strURL.c_str();
  278. LPCWSTR szEnd;
  279. CComBSTR bstrURL;
  280. //
  281. // Skip the bookmark sign.
  282. //
  283. if((szEnd = wcschr( szURL, '#' )))
  284. {
  285. bstrURL.Attach( ::SysAllocStringLen( szURL, (szEnd - szURL) ) );
  286. szURL = SAFEBSTR( bstrURL );
  287. }
  288. switch(m_fmt)
  289. {
  290. case HyperLinks::FMT_INVALID :
  291. state = HyperLinks::STATE_MALFORMED;
  292. break;
  293. case HyperLinks::FMT_INTERNET_FTP :
  294. case HyperLinks::FMT_INTERNET_GOPHER :
  295. case HyperLinks::FMT_INTERNET_HTTP :
  296. case HyperLinks::FMT_INTERNET_HTTPS :
  297. case HyperLinks::FMT_INTERNET_FILE :
  298. case HyperLinks::FMT_INTERNET_NEWS :
  299. while(1)
  300. {
  301. DWORD dwTimeout = m_fBackground ? HC_TIMEOUT_LINKCHECKER_BACKGROUND : HC_TIMEOUT_LINKCHECKER_FOREGROUND;
  302. if(SUCCEEDED(hr = MPC::Connectivity::DestinationReachable( szURL, dwTimeout )))
  303. {
  304. state = HyperLinks::STATE_ALIVE;
  305. }
  306. else if(hr == E_INVALIDARG) // Unsupported protocol, assume the link is OK.
  307. {
  308. state = HyperLinks::STATE_ALIVE;
  309. }
  310. else if(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
  311. {
  312. state = HyperLinks::STATE_NOTFOUND;
  313. }
  314. else if(hr == HRESULT_FROM_WIN32(ERROR_INTERNET_DISCONNECTED))
  315. {
  316. state = HyperLinks::STATE_OFFLINE;
  317. }
  318. else
  319. {
  320. //
  321. // If it's the first time through, it could be that WinINET couldn't activate the proxy code in time...
  322. //
  323. if(fFirstWinInetUse == true)
  324. {
  325. fFirstWinInetUse = false; continue;
  326. }
  327. if(SUCCEEDED(MPC::Connectivity::NetworkAlive( dwTimeout )))
  328. {
  329. state = HyperLinks::STATE_UNREACHABLE;
  330. }
  331. else
  332. {
  333. state = HyperLinks::STATE_OFFLINE;
  334. }
  335. }
  336. fFirstWinInetUse = false; break;
  337. }
  338. break;
  339. case HyperLinks::FMT_INTERNET_UNKNOWN :
  340. case HyperLinks::FMT_INTERNET_MAILTO :
  341. case HyperLinks::FMT_INTERNET_SOCKS :
  342. case HyperLinks::FMT_INTERNET_JAVASCRIPT:
  343. case HyperLinks::FMT_INTERNET_VBSCRIPT :
  344. state = HyperLinks::STATE_ALIVE;
  345. break;
  346. case HyperLinks::FMT_HCP :
  347. {
  348. CComPtr<IInternetProtocolRoot> obj;
  349. state = HyperLinks::STATE_NOTFOUND;
  350. if(SUCCEEDED(CHCPProtocol::CreateInstance( &obj )))
  351. {
  352. if(SUCCEEDED(obj->Start( szURL, NULL, NULL, 0, NULL )))
  353. {
  354. state = HyperLinks::STATE_ALIVE;
  355. }
  356. }
  357. }
  358. break;
  359. case HyperLinks::FMT_MSITS :
  360. {
  361. MPC::wstring strUrlModified;
  362. MPC::wstring strUrlModified2;
  363. CComBSTR bstrStorageName;
  364. CComBSTR bstrFilePath;
  365. CComPtr<IStream> stream;
  366. state = HyperLinks::STATE_NOTFOUND;
  367. CPCHWrapProtocolInfo::NormalizeUrl( szURL , strUrlModified , /*fReverse*/true );
  368. CPCHWrapProtocolInfo::NormalizeUrl( strUrlModified.c_str(), strUrlModified2, /*fReverse*/false );
  369. if(MPC::MSITS::IsCHM( strUrlModified2.c_str(), &bstrStorageName, &bstrFilePath ))
  370. {
  371. if(SUCCEEDED(MPC::MSITS::OpenAsStream( bstrStorageName, bstrFilePath, &stream )))
  372. {
  373. state = HyperLinks::STATE_ALIVE;
  374. }
  375. }
  376. }
  377. break;
  378. case HyperLinks::FMT_CENTER_HOMEPAGE :
  379. case HyperLinks::FMT_CENTER_SUPPORT :
  380. case HyperLinks::FMT_CENTER_OPTIONS :
  381. case HyperLinks::FMT_CENTER_UPDATE :
  382. case HyperLinks::FMT_CENTER_COMPAT :
  383. case HyperLinks::FMT_CENTER_TOOLS :
  384. case HyperLinks::FMT_CENTER_ERRMSG :
  385. state = HyperLinks::STATE_ALIVE;
  386. break;
  387. case HyperLinks::FMT_SEARCH :
  388. case HyperLinks::FMT_INDEX :
  389. case HyperLinks::FMT_SUBSITE :
  390. state = HyperLinks::STATE_ALIVE;
  391. break;
  392. case HyperLinks::FMT_LAYOUT_FULLWINDOW :
  393. case HyperLinks::FMT_LAYOUT_CONTENTONLY :
  394. case HyperLinks::FMT_LAYOUT_KIOSK :
  395. case HyperLinks::FMT_LAYOUT_XML :
  396. state = HyperLinks::STATE_ALIVE;
  397. break;
  398. case HyperLinks::FMT_REDIRECT :
  399. state = HyperLinks::STATE_ALIVE;
  400. break;
  401. case HyperLinks::FMT_APPLICATION :
  402. state = HyperLinks::STATE_ALIVE;
  403. break;
  404. case HyperLinks::FMT_RESOURCE :
  405. state = HyperLinks::STATE_UNREACHABLE;
  406. break;
  407. }
  408. m_dLastChecked = MPC::GetLocalTime();
  409. return state;
  410. }
  411. bool HyperLinks::ParsedUrl::IsOkToProceed()
  412. {
  413. switch(m_state)
  414. {
  415. case HyperLinks::STATE_NOTPROCESSED:
  416. case HyperLinks::STATE_CHECKING :
  417. case HyperLinks::STATE_ALIVE :
  418. return true;
  419. }
  420. return false;
  421. }
  422. bool HyperLinks::ParsedUrl::HasQueryField( /*[in]*/ LPCWSTR szField )
  423. {
  424. MPC::WStringLookupIter it = m_mapQuery.find( szField );
  425. return (it != m_mapQuery.end());
  426. }
  427. bool HyperLinks::ParsedUrl::GetQueryField( /*[in]*/ LPCWSTR szField, /*[in]*/ CComBSTR& bstrValue )
  428. {
  429. MPC::WStringLookupIter it = m_mapQuery.find( szField );
  430. if(it != m_mapQuery.end())
  431. {
  432. bstrValue = it->second.c_str();
  433. return true;
  434. }
  435. bstrValue.Empty();
  436. return false;
  437. }
  438. ////////////////////////////////////////////////////////////////////////////////
  439. HyperLinks::UrlHandle::UrlHandle()
  440. {
  441. m_main = NULL; // Lookup* m_main;
  442. m_pu = NULL; // ParsedUrl* m_pu;
  443. }
  444. HyperLinks::UrlHandle::~UrlHandle()
  445. {
  446. Release();
  447. }
  448. void HyperLinks::UrlHandle::Attach( /*[in]*/ Lookup* main ,
  449. /*[in]*/ ParsedUrl* pu )
  450. {
  451. Release();
  452. m_main = main; if(main) main->Lock();
  453. m_pu = pu;
  454. }
  455. void HyperLinks::UrlHandle::Release()
  456. {
  457. if(m_main) m_main->Unlock();
  458. m_main = NULL;
  459. m_pu = NULL;
  460. }
  461. ////////////////////////////////////////////////////////////////////////////////
  462. HyperLinks::Lookup::Lookup()
  463. {
  464. // PendingUrlList m_lst;
  465. // UrlMap m_map;
  466. }
  467. HyperLinks::Lookup::~Lookup()
  468. {
  469. Thread_Wait();
  470. }
  471. ////////////////////
  472. HyperLinks::Lookup* HyperLinks::Lookup::s_GLOBAL( NULL );
  473. HRESULT HyperLinks::Lookup::InitializeSystem()
  474. {
  475. if(s_GLOBAL == NULL)
  476. {
  477. s_GLOBAL = new HyperLinks::Lookup;
  478. }
  479. return s_GLOBAL ? S_OK : E_OUTOFMEMORY;
  480. }
  481. void HyperLinks::Lookup::FinalizeSystem()
  482. {
  483. if(s_GLOBAL)
  484. {
  485. delete s_GLOBAL; s_GLOBAL = NULL;
  486. }
  487. }
  488. ////////////////////
  489. HRESULT HyperLinks::Lookup::RunChecker()
  490. {
  491. __HCP_FUNC_ENTRY( "HyperLinks::Lookup::RunChecker" );
  492. HRESULT hr;
  493. MPC::SmartLock<_ThreadModel> lock( this );
  494. bool fFirstWinInetUse = true;
  495. Thread_SignalMain();
  496. while(Thread_IsAborted() == false)
  497. {
  498. bool fSleep = true;
  499. ParsedUrl* urlBest = NULL;
  500. PendingUrlIter it;
  501. //
  502. // Look for the first query store not ready and execute it.
  503. //
  504. for(it = m_lst.begin(); it != m_lst.end();)
  505. {
  506. ParsedUrl* url = *it;
  507. if(url->m_state != HyperLinks::STATE_NOTPROCESSED)
  508. {
  509. m_lst.erase( it );
  510. it = m_lst.begin();
  511. urlBest = NULL;
  512. }
  513. else
  514. {
  515. if(url->m_fBackground == false)
  516. {
  517. urlBest = url;
  518. break;
  519. }
  520. urlBest = url;
  521. it++;
  522. }
  523. }
  524. if(urlBest)
  525. {
  526. State state = HyperLinks::STATE_NOTFOUND;
  527. //
  528. // Remove this query from the pending list.
  529. //
  530. for(it = m_lst.begin(); it != m_lst.end(); )
  531. {
  532. if(*it == urlBest)
  533. {
  534. m_lst.erase( it );
  535. it = m_lst.begin();
  536. }
  537. else
  538. {
  539. it++;
  540. }
  541. }
  542. DebugLog( L"%%%%%%%%%%%%%%%%%%%% CHECKING %s\n", urlBest->m_strURL.c_str() );
  543. urlBest->m_state = HyperLinks::STATE_CHECKING;
  544. lock = NULL;
  545. __MPC_PROTECT( state = urlBest->CheckState( fFirstWinInetUse ) );
  546. lock = this;
  547. urlBest->m_state = state;
  548. Thread_SignalMain();
  549. fSleep = false;
  550. }
  551. if(fSleep)
  552. {
  553. lock = NULL;
  554. Thread_WaitForEvents( NULL, INFINITE );
  555. lock = this;
  556. }
  557. }
  558. hr = S_OK;
  559. Thread_Abort();
  560. __HCP_FUNC_EXIT(hr);
  561. }
  562. HRESULT HyperLinks::Lookup::CreateItem( /*[in ]*/ LPCWSTR szURL ,
  563. /*[out]*/ ParsedUrl*& pu )
  564. {
  565. __HCP_FUNC_ENTRY( "HyperLinks::Lookup::CreateItem" );
  566. HRESULT hr;
  567. UrlIter it;
  568. MPC::wstringUC strURL( SAFEWSTR( szURL ) );
  569. it = m_map.find( strURL );
  570. if(it == m_map.end())
  571. {
  572. pu = &(m_map[ strURL ]);
  573. __MPC_EXIT_IF_METHOD_FAILS(hr, pu->Initialize( szURL ));
  574. }
  575. else
  576. {
  577. pu = &it->second;
  578. }
  579. hr = S_OK;
  580. __HCP_FUNC_CLEANUP;
  581. __HCP_FUNC_EXIT(hr);
  582. }
  583. ////////////////////
  584. HRESULT HyperLinks::Lookup::Queue( /*[in]*/ LPCWSTR szURL )
  585. {
  586. UrlHandle uh;
  587. return Get( szURL, uh );
  588. }
  589. HRESULT HyperLinks::Lookup::Get( /*[in]*/ LPCWSTR szURL ,
  590. /*[in]*/ UrlHandle& uh ,
  591. /*[in]*/ DWORD dwWaitForCheck ,
  592. /*[in]*/ bool fForce )
  593. {
  594. __HCP_FUNC_ENTRY( "HyperLinks::Lookup::Get" );
  595. HRESULT hr;
  596. MPC::SmartLock<_ThreadModel> lock( this );
  597. ParsedUrl* pu = NULL;
  598. uh.Release();
  599. ////////////////////////////////////////////////////////////////////////////////
  600. if(Thread_IsRunning() == false)
  601. {
  602. lock = NULL;
  603. __MPC_EXIT_IF_METHOD_FAILS(hr, Thread_Start( this, RunChecker, NULL ));
  604. Thread_WaitNotificationFromWorker( INFINITE, /*fNoMessagePump*/true );
  605. lock = this;
  606. }
  607. ////////////////////////////////////////////////////////////////////////////////
  608. __MPC_EXIT_IF_METHOD_FAILS(hr, CreateItem( szURL, pu ));
  609. if(fForce)
  610. {
  611. pu->m_state = HyperLinks::STATE_NOTPROCESSED;
  612. }
  613. switch(pu->m_state)
  614. {
  615. case HyperLinks::STATE_ALIVE :
  616. case HyperLinks::STATE_NOTFOUND :
  617. case HyperLinks::STATE_UNREACHABLE:
  618. case HyperLinks::STATE_OFFLINE :
  619. if(dwWaitForCheck)
  620. {
  621. //
  622. // Make sure the state is not stale.
  623. //
  624. DATE dNow = MPC::GetLocalTime();
  625. if((dNow - pu->m_dLastChecked) >= l_TIME_timeout)
  626. {
  627. pu->m_state = HyperLinks::STATE_NOTPROCESSED;
  628. }
  629. }
  630. break;
  631. }
  632. if(pu->m_state == HyperLinks::STATE_NOTPROCESSED)
  633. {
  634. bool fQueue = false;
  635. bool fWait = false;
  636. if(dwWaitForCheck)
  637. {
  638. //
  639. // Elevate the URL to "important".
  640. //
  641. pu->m_fBackground = false;
  642. fWait = true;
  643. if(pu->IsLocal() == false)
  644. {
  645. fQueue = true;
  646. }
  647. }
  648. else
  649. {
  650. fQueue = true;
  651. }
  652. if(fQueue)
  653. {
  654. m_lst.push_back( pu );
  655. Thread_Signal();
  656. }
  657. if(fWait)
  658. {
  659. if(pu->IsLocal())
  660. {
  661. bool fFirstWinInetUse = false;
  662. pu->m_state = pu->CheckState( fFirstWinInetUse );
  663. }
  664. else
  665. {
  666. int iRetry = 5;
  667. dwWaitForCheck /= iRetry;
  668. while(pu->m_state == HyperLinks::STATE_NOTPROCESSED ||
  669. pu->m_state == HyperLinks::STATE_CHECKING )
  670. {
  671. DWORD dwRes;
  672. lock = NULL;
  673. dwRes = Thread_WaitNotificationFromWorker( dwWaitForCheck, /*fNoMessagePump*/true );
  674. lock = this;
  675. if(iRetry-- == 0)
  676. {
  677. __MPC_SET_ERROR_AND_EXIT(hr, S_FALSE);
  678. }
  679. }
  680. }
  681. }
  682. }
  683. hr = S_OK;
  684. __HCP_FUNC_CLEANUP;
  685. if(pu) uh.Attach( this, pu );
  686. __HCP_FUNC_EXIT(hr);
  687. }
  688. ////////////////////////////////////////////////////////////////////////////////
  689. HRESULT HyperLinks::IsValid( /*[in]*/ LPCWSTR szURL )
  690. {
  691. __HCP_FUNC_ENTRY( "HyperLinks::IsValid" );
  692. HRESULT hr;
  693. ParsedUrl pu;
  694. __MPC_EXIT_IF_METHOD_FAILS(hr, pu.Initialize( szURL ));
  695. switch(pu.m_state)
  696. {
  697. case HyperLinks::STATE_INVALID :
  698. case HyperLinks::STATE_MALFORMED:
  699. __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
  700. }
  701. hr = S_OK;
  702. __HCP_FUNC_CLEANUP;
  703. __HCP_FUNC_EXIT(hr);
  704. }