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.

876 lines
26 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. HRESULT HyperLinks::ParsedUrl::Initialize( /*[in]*/ LPCWSTR szURL )
  119. {
  120. __HCP_FUNC_ENTRY( "HyperLinks::ParsedUrl::Initialize" );
  121. HRESULT hr;
  122. SANITIZEWSTR(szURL);
  123. m_strURL = szURL;
  124. m_fmt = HyperLinks::FMT_INVALID;
  125. m_state = HyperLinks::STATE_NOTPROCESSED;
  126. MPC::HTML::ParseHREF( m_strURL.c_str(), m_strBasePart, m_mapQuery );
  127. if(m_strBasePart.size() == 0)
  128. {
  129. m_state = HyperLinks::STATE_MALFORMED;
  130. }
  131. else if(MPC::MSITS::IsCHM( m_strBasePart.c_str() ))
  132. {
  133. m_fmt = HyperLinks::FMT_MSITS;
  134. }
  135. else
  136. {
  137. CComBSTR bstrURL( m_strBasePart.c_str() ); if(bstrURL) ::CharLowerW( bstrURL );
  138. szURL = bstrURL;
  139. for(const Pattern* ptr=l_rgPattern; ptr->szTxt; ptr++)
  140. {
  141. int iCmp;
  142. if(ptr->iLen) iCmp = wcsncmp( szURL, ptr->szTxt, ptr->iLen );
  143. else iCmp = wcscmp ( szURL, ptr->szTxt );
  144. if(iCmp == 0)
  145. {
  146. const QueryField* field = ptr->rgQueryFields;
  147. for(size_t i=0; i<ptr->iQueryFields; i++, field++)
  148. {
  149. CComBSTR bstrValue;
  150. if(GetQueryField( field->szName, bstrValue ) == false)
  151. {
  152. if(field->fOptional == false)
  153. {
  154. m_state = HyperLinks::STATE_MALFORMED;
  155. break;
  156. }
  157. }
  158. else
  159. {
  160. if(field->qft == QFT_TEXT)
  161. {
  162. ;
  163. }
  164. else if(field->qft == QFT_URL)
  165. {
  166. if(FAILED(IsValid( bstrValue )))
  167. {
  168. m_state = HyperLinks::STATE_MALFORMED;
  169. break;
  170. }
  171. }
  172. else if(field->qft == QFT_TAXONOMY)
  173. {
  174. /* TO DO */
  175. }
  176. else if(field->qft == QFT_APPLICATION)
  177. {
  178. /* TO DO */
  179. }
  180. }
  181. }
  182. m_fmt = ptr->fmt;
  183. break;
  184. }
  185. }
  186. //
  187. // If the URL begins with HCP: but not HCP://, it's a protocol redirection, so recurse.
  188. //
  189. if(m_fmt == HyperLinks::FMT_HCP_REDIR)
  190. {
  191. __MPC_SET_ERROR_AND_EXIT(hr, Initialize( szURL + MAXSTRLEN( l_szHCP_redir ) ));
  192. }
  193. if(m_fmt == HyperLinks::FMT_INVALID) // Still not resolved...
  194. {
  195. MPC::URL url;
  196. INTERNET_SCHEME scheme;
  197. if(SUCCEEDED(url.put_URL ( szURL )) &&
  198. SUCCEEDED(url.get_Scheme( scheme )) )
  199. {
  200. switch(scheme)
  201. {
  202. case INTERNET_SCHEME_UNKNOWN : m_fmt = HyperLinks::FMT_INTERNET_UNKNOWN ; break;
  203. case INTERNET_SCHEME_FTP : m_fmt = HyperLinks::FMT_INTERNET_FTP ; break;
  204. case INTERNET_SCHEME_GOPHER : m_fmt = HyperLinks::FMT_INTERNET_GOPHER ; break;
  205. case INTERNET_SCHEME_HTTP : m_fmt = HyperLinks::FMT_INTERNET_HTTP ; break;
  206. case INTERNET_SCHEME_HTTPS : m_fmt = HyperLinks::FMT_INTERNET_HTTPS ; break;
  207. case INTERNET_SCHEME_FILE : m_fmt = HyperLinks::FMT_INTERNET_FILE ; break;
  208. case INTERNET_SCHEME_NEWS : m_fmt = HyperLinks::FMT_INTERNET_NEWS ; break;
  209. case INTERNET_SCHEME_MAILTO : m_fmt = HyperLinks::FMT_INTERNET_MAILTO ; break;
  210. case INTERNET_SCHEME_SOCKS : m_fmt = HyperLinks::FMT_INTERNET_SOCKS ; break;
  211. case INTERNET_SCHEME_JAVASCRIPT: m_fmt = HyperLinks::FMT_INTERNET_JAVASCRIPT; break;
  212. case INTERNET_SCHEME_VBSCRIPT : m_fmt = HyperLinks::FMT_INTERNET_VBSCRIPT ; break;
  213. default : m_state = HyperLinks::STATE_MALFORMED ; break;
  214. }
  215. }
  216. }
  217. }
  218. hr = S_OK;
  219. __HCP_FUNC_CLEANUP;
  220. __HCP_FUNC_EXIT(hr);
  221. }
  222. bool HyperLinks::ParsedUrl::IsLocal()
  223. {
  224. switch(m_fmt)
  225. {
  226. case HyperLinks::FMT_INTERNET_UNKNOWN :
  227. case HyperLinks::FMT_INTERNET_FTP :
  228. case HyperLinks::FMT_INTERNET_GOPHER :
  229. case HyperLinks::FMT_INTERNET_HTTP :
  230. case HyperLinks::FMT_INTERNET_HTTPS :
  231. case HyperLinks::FMT_INTERNET_FILE :
  232. case HyperLinks::FMT_INTERNET_NEWS :
  233. case HyperLinks::FMT_INTERNET_MAILTO :
  234. case HyperLinks::FMT_INTERNET_SOCKS :
  235. case HyperLinks::FMT_INTERNET_JAVASCRIPT:
  236. case HyperLinks::FMT_INTERNET_VBSCRIPT :
  237. return false;
  238. case HyperLinks::FMT_MSITS:
  239. //
  240. // Make sure it's not on a network share!
  241. //
  242. {
  243. CComBSTR bstrStorageName;
  244. CComBSTR bstrFilePath;
  245. if(MPC::MSITS::IsCHM( m_strURL.c_str(), &bstrStorageName, &bstrFilePath ))
  246. {
  247. if(wcsncmp( L"\\\\", SAFEBSTR(bstrStorageName), 2 ) == 0)
  248. {
  249. return false;
  250. }
  251. }
  252. }
  253. break;
  254. }
  255. return true;
  256. }
  257. HyperLinks::State HyperLinks::ParsedUrl::CheckState( /*[in/out]*/ bool& fFirstWinInetUse )
  258. {
  259. HRESULT hr;
  260. State state = HyperLinks::STATE_NOTFOUND;
  261. LPCWSTR szURL = m_strURL.c_str();
  262. LPCWSTR szEnd;
  263. CComBSTR bstrURL;
  264. //
  265. // Skip the bookmark sign.
  266. //
  267. if((szEnd = wcschr( szURL, '#' )))
  268. {
  269. bstrURL.Attach( ::SysAllocStringLen( szURL, (szEnd - szURL) ) );
  270. szURL = SAFEBSTR( bstrURL );
  271. }
  272. switch(m_fmt)
  273. {
  274. case HyperLinks::FMT_INVALID :
  275. state = HyperLinks::STATE_MALFORMED;
  276. break;
  277. case HyperLinks::FMT_INTERNET_FTP :
  278. case HyperLinks::FMT_INTERNET_GOPHER :
  279. case HyperLinks::FMT_INTERNET_HTTP :
  280. case HyperLinks::FMT_INTERNET_HTTPS :
  281. case HyperLinks::FMT_INTERNET_FILE :
  282. case HyperLinks::FMT_INTERNET_NEWS :
  283. while(1)
  284. {
  285. DWORD dwTimeout = m_fBackground ? HC_TIMEOUT_LINKCHECKER_BACKGROUND : HC_TIMEOUT_LINKCHECKER_FOREGROUND;
  286. if(SUCCEEDED(hr = MPC::Connectivity::DestinationReachable( szURL, dwTimeout )))
  287. {
  288. state = HyperLinks::STATE_ALIVE;
  289. }
  290. else if(hr == E_INVALIDARG) // Unsupported protocol, assume the link is OK.
  291. {
  292. state = HyperLinks::STATE_ALIVE;
  293. }
  294. else if(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
  295. {
  296. state = HyperLinks::STATE_NOTFOUND;
  297. }
  298. else if(hr == HRESULT_FROM_WIN32(ERROR_INTERNET_DISCONNECTED))
  299. {
  300. state = HyperLinks::STATE_OFFLINE;
  301. }
  302. else
  303. {
  304. //
  305. // If it's the first time through, it could be that WinINET couldn't activate the proxy code in time...
  306. //
  307. if(fFirstWinInetUse == true)
  308. {
  309. fFirstWinInetUse = false; continue;
  310. }
  311. if(SUCCEEDED(MPC::Connectivity::NetworkAlive( dwTimeout )))
  312. {
  313. state = HyperLinks::STATE_UNREACHABLE;
  314. }
  315. else
  316. {
  317. state = HyperLinks::STATE_OFFLINE;
  318. }
  319. }
  320. fFirstWinInetUse = false; break;
  321. }
  322. break;
  323. case HyperLinks::FMT_INTERNET_UNKNOWN :
  324. case HyperLinks::FMT_INTERNET_MAILTO :
  325. case HyperLinks::FMT_INTERNET_SOCKS :
  326. case HyperLinks::FMT_INTERNET_JAVASCRIPT:
  327. case HyperLinks::FMT_INTERNET_VBSCRIPT :
  328. state = HyperLinks::STATE_ALIVE;
  329. break;
  330. case HyperLinks::FMT_HCP :
  331. {
  332. CComPtr<IInternetProtocolRoot> obj;
  333. state = HyperLinks::STATE_NOTFOUND;
  334. if(SUCCEEDED(CHCPProtocol::CreateInstance( &obj )))
  335. {
  336. if(SUCCEEDED(obj->Start( szURL, NULL, NULL, 0, NULL )))
  337. {
  338. state = HyperLinks::STATE_ALIVE;
  339. }
  340. }
  341. }
  342. break;
  343. case HyperLinks::FMT_MSITS :
  344. {
  345. MPC::wstring strUrlModified;
  346. MPC::wstring strUrlModified2;
  347. CComBSTR bstrStorageName;
  348. CComBSTR bstrFilePath;
  349. CComPtr<IStream> stream;
  350. state = HyperLinks::STATE_NOTFOUND;
  351. CPCHWrapProtocolInfo::NormalizeUrl( szURL , strUrlModified , /*fReverse*/true );
  352. CPCHWrapProtocolInfo::NormalizeUrl( strUrlModified.c_str(), strUrlModified2, /*fReverse*/false );
  353. if(MPC::MSITS::IsCHM( strUrlModified2.c_str(), &bstrStorageName, &bstrFilePath ))
  354. {
  355. if(SUCCEEDED(MPC::MSITS::OpenAsStream( bstrStorageName, bstrFilePath, &stream )))
  356. {
  357. state = HyperLinks::STATE_ALIVE;
  358. }
  359. }
  360. }
  361. break;
  362. case HyperLinks::FMT_CENTER_HOMEPAGE :
  363. case HyperLinks::FMT_CENTER_SUPPORT :
  364. case HyperLinks::FMT_CENTER_OPTIONS :
  365. case HyperLinks::FMT_CENTER_UPDATE :
  366. case HyperLinks::FMT_CENTER_COMPAT :
  367. case HyperLinks::FMT_CENTER_TOOLS :
  368. case HyperLinks::FMT_CENTER_ERRMSG :
  369. state = HyperLinks::STATE_ALIVE;
  370. break;
  371. case HyperLinks::FMT_SEARCH :
  372. case HyperLinks::FMT_INDEX :
  373. case HyperLinks::FMT_SUBSITE :
  374. state = HyperLinks::STATE_ALIVE;
  375. break;
  376. case HyperLinks::FMT_LAYOUT_FULLWINDOW :
  377. case HyperLinks::FMT_LAYOUT_CONTENTONLY :
  378. case HyperLinks::FMT_LAYOUT_KIOSK :
  379. case HyperLinks::FMT_LAYOUT_XML :
  380. state = HyperLinks::STATE_ALIVE;
  381. break;
  382. case HyperLinks::FMT_REDIRECT :
  383. state = HyperLinks::STATE_ALIVE;
  384. break;
  385. case HyperLinks::FMT_APPLICATION :
  386. state = HyperLinks::STATE_ALIVE;
  387. break;
  388. case HyperLinks::FMT_RESOURCE :
  389. state = HyperLinks::STATE_UNREACHABLE;
  390. break;
  391. }
  392. m_dLastChecked = MPC::GetLocalTime();
  393. return state;
  394. }
  395. bool HyperLinks::ParsedUrl::IsOkToProceed()
  396. {
  397. switch(m_state)
  398. {
  399. case HyperLinks::STATE_NOTPROCESSED:
  400. case HyperLinks::STATE_CHECKING :
  401. case HyperLinks::STATE_ALIVE :
  402. return true;
  403. }
  404. return false;
  405. }
  406. bool HyperLinks::ParsedUrl::HasQueryField( /*[in]*/ LPCWSTR szField )
  407. {
  408. MPC::WStringLookupIter it = m_mapQuery.find( szField );
  409. return (it != m_mapQuery.end());
  410. }
  411. bool HyperLinks::ParsedUrl::GetQueryField( /*[in]*/ LPCWSTR szField, /*[in]*/ CComBSTR& bstrValue )
  412. {
  413. MPC::WStringLookupIter it = m_mapQuery.find( szField );
  414. if(it != m_mapQuery.end())
  415. {
  416. bstrValue = it->second.c_str();
  417. return true;
  418. }
  419. bstrValue.Empty();
  420. return false;
  421. }
  422. ////////////////////////////////////////////////////////////////////////////////
  423. HyperLinks::UrlHandle::UrlHandle()
  424. {
  425. m_main = NULL; // Lookup* m_main;
  426. m_pu = NULL; // ParsedUrl* m_pu;
  427. }
  428. HyperLinks::UrlHandle::~UrlHandle()
  429. {
  430. Release();
  431. }
  432. void HyperLinks::UrlHandle::Attach( /*[in]*/ Lookup* main ,
  433. /*[in]*/ ParsedUrl* pu )
  434. {
  435. Release();
  436. m_main = main; if(main) main->Lock();
  437. m_pu = pu;
  438. }
  439. void HyperLinks::UrlHandle::Release()
  440. {
  441. if(m_main) m_main->Unlock();
  442. m_main = NULL;
  443. m_pu = NULL;
  444. }
  445. ////////////////////////////////////////////////////////////////////////////////
  446. HyperLinks::Lookup::Lookup()
  447. {
  448. // PendingUrlList m_lst;
  449. // UrlMap m_map;
  450. }
  451. HyperLinks::Lookup::~Lookup()
  452. {
  453. Thread_Wait();
  454. }
  455. ////////////////////
  456. HyperLinks::Lookup* HyperLinks::Lookup::s_GLOBAL( NULL );
  457. HRESULT HyperLinks::Lookup::InitializeSystem()
  458. {
  459. if(s_GLOBAL == NULL)
  460. {
  461. s_GLOBAL = new HyperLinks::Lookup;
  462. }
  463. return s_GLOBAL ? S_OK : E_OUTOFMEMORY;
  464. }
  465. void HyperLinks::Lookup::FinalizeSystem()
  466. {
  467. if(s_GLOBAL)
  468. {
  469. delete s_GLOBAL; s_GLOBAL = NULL;
  470. }
  471. }
  472. ////////////////////
  473. HRESULT HyperLinks::Lookup::RunChecker()
  474. {
  475. __HCP_FUNC_ENTRY( "HyperLinks::Lookup::RunChecker" );
  476. HRESULT hr;
  477. MPC::SmartLock<_ThreadModel> lock( this );
  478. bool fFirstWinInetUse = true;
  479. Thread_SignalMain();
  480. while(Thread_IsAborted() == false)
  481. {
  482. bool fSleep = true;
  483. ParsedUrl* urlBest = NULL;
  484. PendingUrlIter it;
  485. //
  486. // Look for the first query store not ready and execute it.
  487. //
  488. for(it = m_lst.begin(); it != m_lst.end();)
  489. {
  490. ParsedUrl* url = *it;
  491. if(url->m_state != HyperLinks::STATE_NOTPROCESSED)
  492. {
  493. m_lst.erase( it );
  494. it = m_lst.begin();
  495. urlBest = NULL;
  496. }
  497. else
  498. {
  499. if(url->m_fBackground == false)
  500. {
  501. urlBest = url;
  502. break;
  503. }
  504. urlBest = url;
  505. it++;
  506. }
  507. }
  508. if(urlBest)
  509. {
  510. State state = HyperLinks::STATE_NOTFOUND;
  511. //
  512. // Remove this query from the pending list.
  513. //
  514. for(it = m_lst.begin(); it != m_lst.end(); )
  515. {
  516. if(*it == urlBest)
  517. {
  518. m_lst.erase( it );
  519. it = m_lst.begin();
  520. }
  521. else
  522. {
  523. it++;
  524. }
  525. }
  526. DebugLog( L"%%%%%%%%%%%%%%%%%%%% CHECKING %s\n", urlBest->m_strURL.c_str() );
  527. urlBest->m_state = HyperLinks::STATE_CHECKING;
  528. lock = NULL;
  529. __MPC_PROTECT( state = urlBest->CheckState( fFirstWinInetUse ) );
  530. lock = this;
  531. urlBest->m_state = state;
  532. Thread_SignalMain();
  533. fSleep = false;
  534. }
  535. if(fSleep)
  536. {
  537. lock = NULL;
  538. Thread_WaitForEvents( NULL, INFINITE );
  539. lock = this;
  540. }
  541. }
  542. hr = S_OK;
  543. Thread_Abort();
  544. __HCP_FUNC_EXIT(hr);
  545. }
  546. HRESULT HyperLinks::Lookup::CreateItem( /*[in ]*/ LPCWSTR szURL ,
  547. /*[out]*/ ParsedUrl*& pu )
  548. {
  549. __HCP_FUNC_ENTRY( "HyperLinks::Lookup::CreateItem" );
  550. HRESULT hr;
  551. UrlIter it;
  552. MPC::wstringUC strURL( SAFEWSTR( szURL ) );
  553. it = m_map.find( strURL );
  554. if(it == m_map.end())
  555. {
  556. pu = &(m_map[ strURL ]);
  557. __MPC_EXIT_IF_METHOD_FAILS(hr, pu->Initialize( szURL ));
  558. }
  559. else
  560. {
  561. pu = &it->second;
  562. }
  563. hr = S_OK;
  564. __HCP_FUNC_CLEANUP;
  565. __HCP_FUNC_EXIT(hr);
  566. }
  567. ////////////////////
  568. HRESULT HyperLinks::Lookup::Queue( /*[in]*/ LPCWSTR szURL )
  569. {
  570. UrlHandle uh;
  571. return Get( szURL, uh );
  572. }
  573. HRESULT HyperLinks::Lookup::Get( /*[in]*/ LPCWSTR szURL ,
  574. /*[in]*/ UrlHandle& uh ,
  575. /*[in]*/ DWORD dwWaitForCheck ,
  576. /*[in]*/ bool fForce )
  577. {
  578. __HCP_FUNC_ENTRY( "HyperLinks::Lookup::Get" );
  579. HRESULT hr;
  580. MPC::SmartLock<_ThreadModel> lock( this );
  581. ParsedUrl* pu;
  582. uh.Release();
  583. ////////////////////////////////////////////////////////////////////////////////
  584. if(Thread_IsRunning() == false)
  585. {
  586. lock = NULL;
  587. __MPC_EXIT_IF_METHOD_FAILS(hr, Thread_Start( this, RunChecker, NULL ));
  588. Thread_WaitNotificationFromWorker( INFINITE, /*fNoMessagePump*/true );
  589. lock = this;
  590. }
  591. ////////////////////////////////////////////////////////////////////////////////
  592. __MPC_EXIT_IF_METHOD_FAILS(hr, CreateItem( szURL, pu ));
  593. if(fForce)
  594. {
  595. pu->m_state = HyperLinks::STATE_NOTPROCESSED;
  596. }
  597. switch(pu->m_state)
  598. {
  599. case HyperLinks::STATE_ALIVE :
  600. case HyperLinks::STATE_NOTFOUND :
  601. case HyperLinks::STATE_UNREACHABLE:
  602. case HyperLinks::STATE_OFFLINE :
  603. if(dwWaitForCheck)
  604. {
  605. //
  606. // Make sure the state is not stale.
  607. //
  608. DATE dNow = MPC::GetLocalTime();
  609. if((dNow - pu->m_dLastChecked) >= l_TIME_timeout)
  610. {
  611. pu->m_state = HyperLinks::STATE_NOTPROCESSED;
  612. }
  613. }
  614. break;
  615. }
  616. if(pu->m_state == HyperLinks::STATE_NOTPROCESSED)
  617. {
  618. bool fQueue = false;
  619. bool fWait = false;
  620. if(dwWaitForCheck)
  621. {
  622. //
  623. // Elevate the URL to "important".
  624. //
  625. pu->m_fBackground = false;
  626. fWait = true;
  627. if(pu->IsLocal() == false)
  628. {
  629. fQueue = true;
  630. }
  631. }
  632. else
  633. {
  634. fQueue = true;
  635. }
  636. if(fQueue)
  637. {
  638. m_lst.push_back( pu );
  639. Thread_Signal();
  640. }
  641. if(fWait)
  642. {
  643. if(pu->IsLocal())
  644. {
  645. bool fFirstWinInetUse = false;
  646. pu->m_state = pu->CheckState( fFirstWinInetUse );
  647. }
  648. else
  649. {
  650. int iRetry = 5;
  651. dwWaitForCheck /= iRetry;
  652. while(pu->m_state == HyperLinks::STATE_NOTPROCESSED ||
  653. pu->m_state == HyperLinks::STATE_CHECKING )
  654. {
  655. DWORD dwRes;
  656. lock = NULL;
  657. dwRes = Thread_WaitNotificationFromWorker( dwWaitForCheck, /*fNoMessagePump*/true );
  658. lock = this;
  659. if(iRetry-- == 0)
  660. {
  661. __MPC_SET_ERROR_AND_EXIT(hr, S_FALSE);
  662. }
  663. }
  664. }
  665. }
  666. }
  667. hr = S_OK;
  668. __HCP_FUNC_CLEANUP;
  669. if(pu) uh.Attach( this, pu );
  670. __HCP_FUNC_EXIT(hr);
  671. }
  672. ////////////////////////////////////////////////////////////////////////////////
  673. HRESULT HyperLinks::IsValid( /*[in]*/ LPCWSTR szURL )
  674. {
  675. __HCP_FUNC_ENTRY( "HyperLinks::IsValid" );
  676. HRESULT hr;
  677. ParsedUrl pu;
  678. __MPC_EXIT_IF_METHOD_FAILS(hr, pu.Initialize( szURL ));
  679. switch(pu.m_state)
  680. {
  681. case HyperLinks::STATE_INVALID :
  682. case HyperLinks::STATE_MALFORMED:
  683. __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
  684. }
  685. hr = S_OK;
  686. __HCP_FUNC_CLEANUP;
  687. __HCP_FUNC_EXIT(hr);
  688. }