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
894 lines
28 KiB
/******************************************************************************
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
HyperLinks.cpp
|
|
|
|
Abstract:
|
|
This file contains the implementation of the HyperLinks library.
|
|
|
|
Revision History:
|
|
Davide Massarenti (Dmassare) 11/28/2000
|
|
created
|
|
|
|
******************************************************************************/
|
|
|
|
#include "stdafx.h"
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static const DATE l_TIME_hour = 1.0 / 24.0;
|
|
static const DATE l_TIME_minute = l_TIME_hour / 60.0;
|
|
static const DATE l_TIME_second = l_TIME_hour / 60.0;
|
|
static const DATE l_TIME_timeout = l_TIME_minute * 5.0;
|
|
|
|
static const WCHAR l_szMS_ITS [] = L"ms-its:";
|
|
static const WCHAR l_szMSITSTORE [] = L"mk:@MSITStore:";
|
|
static const WCHAR l_szITS [] = L"its:";
|
|
|
|
static const WCHAR l_szHOMEPAGE [] = L"hcp://services/centers/homepage";
|
|
static const WCHAR l_szSUPPORT [] = L"hcp://services/centers/support";
|
|
static const WCHAR l_szOPTIONS [] = L"hcp://services/centers/options";
|
|
static const WCHAR l_szUPDATE [] = L"hcp://services/centers/update";
|
|
static const WCHAR l_szCOMPAT [] = L"hcp://services/centers/compat";
|
|
static const WCHAR l_szTOOLS [] = L"hcp://services/centers/tools";
|
|
static const WCHAR l_szERRMSG [] = L"hcp://services/centers/errmsg";
|
|
|
|
static const WCHAR l_szSEARCH [] = L"hcp://services/search";
|
|
static const WCHAR l_szINDEX [] = L"hcp://services/index";
|
|
static const WCHAR l_szSUBSITE [] = L"hcp://services/subsite";
|
|
|
|
static const WCHAR l_szFULLWINDOW [] = L"hcp://services/layout/fullwindow";
|
|
static const WCHAR l_szCONTENTONLY[] = L"hcp://services/layout/contentonly";
|
|
static const WCHAR l_szKIOSK [] = L"hcp://services/layout/kiosk";
|
|
static const WCHAR l_szXML [] = L"hcp://services/layout/xml";
|
|
|
|
static const WCHAR l_szREDIRECT [] = L"hcp://services/redirect";
|
|
|
|
static const WCHAR l_szHCP [] = L"hcp://";
|
|
static const WCHAR l_szHCP_redir [] = L"hcp:";
|
|
|
|
static const WCHAR l_szAPPLICATION[] = L"app:";
|
|
|
|
static const WCHAR l_szRESOURCE [] = L"res://";
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
|
|
typedef enum
|
|
{
|
|
QFT_TEXT ,
|
|
QFT_URL ,
|
|
QFT_TAXONOMY ,
|
|
QFT_APPLICATION,
|
|
} QueryFieldType;
|
|
|
|
struct QueryField
|
|
{
|
|
LPCWSTR szName;
|
|
QueryFieldType qft;
|
|
bool fOptional;
|
|
};
|
|
|
|
struct Pattern
|
|
{
|
|
LPCWSTR szTxt;
|
|
size_t iLen; /* -1 for complete match */
|
|
HyperLinks::Format fmt;
|
|
|
|
const QueryField* rgQueryFields;
|
|
size_t iQueryFields;
|
|
};
|
|
|
|
////////////////////
|
|
|
|
static const QueryField l_rgTopic [] = { { L"topic" , QFT_URL , false } };
|
|
static const QueryField l_rgTopicOpt[] = { { L"topic" , QFT_URL , true } };
|
|
|
|
static const QueryField l_rgSEARCH [] = { { L"query" , QFT_TEXT , false } ,
|
|
{ L"topic" , QFT_URL , true } };
|
|
|
|
static const QueryField l_rgINDEX [] = { { L"scope" , QFT_APPLICATION, true } ,
|
|
{ L"select" , QFT_APPLICATION, true } ,
|
|
{ L"topic" , QFT_URL , true } };
|
|
|
|
static const QueryField l_rgSUBSITE [] = { { L"node" , QFT_TAXONOMY , false } ,
|
|
{ L"select" , QFT_TAXONOMY , true } ,
|
|
{ L"topic" , QFT_URL , true } };
|
|
|
|
static const QueryField l_rgXML [] = { { L"definition" , QFT_URL , false } ,
|
|
{ L"topic" , QFT_URL , true } };
|
|
|
|
static const QueryField l_rgREDIRECT[] = { { L"online" , QFT_URL , false } ,
|
|
{ L"offline" , QFT_URL , false } };
|
|
|
|
static const QueryField l_rgAPP [] = { { L"topic" , QFT_URL , true } };
|
|
|
|
|
|
static const Pattern l_rgPattern[] =
|
|
{
|
|
{ l_szMS_ITS , MAXSTRLEN( l_szMS_ITS ), HyperLinks::FMT_MSITS },
|
|
{ l_szMSITSTORE , MAXSTRLEN( l_szMSITSTORE ), HyperLinks::FMT_MSITS },
|
|
{ l_szITS , MAXSTRLEN( l_szITS ), HyperLinks::FMT_MSITS },
|
|
|
|
////////////////////
|
|
|
|
{ l_szHOMEPAGE , -1 , HyperLinks::FMT_CENTER_HOMEPAGE },
|
|
{ l_szSUPPORT , -1 , HyperLinks::FMT_CENTER_SUPPORT , l_rgTopicOpt, ARRAYSIZE(l_rgTopicOpt ) },
|
|
{ l_szOPTIONS , -1 , HyperLinks::FMT_CENTER_OPTIONS , l_rgTopicOpt, ARRAYSIZE(l_rgTopicOpt ) },
|
|
{ l_szUPDATE , -1 , HyperLinks::FMT_CENTER_UPDATE },
|
|
{ l_szCOMPAT , -1 , HyperLinks::FMT_CENTER_COMPAT },
|
|
{ l_szTOOLS , -1 , HyperLinks::FMT_CENTER_TOOLS , l_rgTopicOpt, ARRAYSIZE(l_rgTopicOpt ) },
|
|
{ l_szERRMSG , -1 , HyperLinks::FMT_CENTER_ERRMSG },
|
|
|
|
{ l_szSEARCH , -1 , HyperLinks::FMT_SEARCH , l_rgSEARCH , ARRAYSIZE(l_rgSEARCH ) },
|
|
{ l_szINDEX , -1 , HyperLinks::FMT_INDEX , l_rgINDEX , ARRAYSIZE(l_rgINDEX ) },
|
|
{ l_szSUBSITE , -1 , HyperLinks::FMT_SUBSITE , l_rgSUBSITE , ARRAYSIZE(l_rgSUBSITE ) },
|
|
|
|
{ l_szFULLWINDOW , -1 , HyperLinks::FMT_LAYOUT_FULLWINDOW , l_rgTopic , ARRAYSIZE(l_rgTopic ) },
|
|
{ l_szCONTENTONLY, -1 , HyperLinks::FMT_LAYOUT_CONTENTONLY, l_rgTopic , ARRAYSIZE(l_rgTopic ) },
|
|
{ l_szKIOSK , -1 , HyperLinks::FMT_LAYOUT_KIOSK , l_rgTopic , ARRAYSIZE(l_rgTopic ) },
|
|
{ l_szXML , -1 , HyperLinks::FMT_LAYOUT_XML , l_rgXML , ARRAYSIZE(l_rgXML ) },
|
|
|
|
{ l_szREDIRECT , -1 , HyperLinks::FMT_REDIRECT , l_rgREDIRECT, ARRAYSIZE(l_rgREDIRECT ) },
|
|
|
|
{ l_szHCP , MAXSTRLEN( l_szHCP ), HyperLinks::FMT_HCP },
|
|
{ l_szHCP_redir , MAXSTRLEN( l_szHCP_redir ), HyperLinks::FMT_HCP_REDIR },
|
|
|
|
////////////////////
|
|
|
|
{ l_szAPPLICATION, MAXSTRLEN( l_szAPPLICATION ), HyperLinks::FMT_APPLICATION , l_rgAPP , ARRAYSIZE(l_rgAPP ) },
|
|
|
|
////////////////////
|
|
|
|
{ l_szRESOURCE , MAXSTRLEN( l_szRESOURCE ), HyperLinks::FMT_RESOURCE },
|
|
|
|
////////////////////
|
|
|
|
{ NULL }
|
|
};
|
|
|
|
HyperLinks::ParsedUrl::ParsedUrl()
|
|
{
|
|
// MPC::wstring m_strURL;
|
|
m_fmt = HyperLinks::FMT_INVALID; // Format m_fmt;
|
|
m_state = HyperLinks::STATE_INVALID; // State m_state;
|
|
m_dLastChecked = 0; // DATE m_dLastChecked;
|
|
m_fBackground = true; // bool m_fBackground;
|
|
//
|
|
// MPC::wstring m_strBasePart;
|
|
// MPC::WStringLookup m_mapQuery;
|
|
//
|
|
m_hcpRedir = false; // bool m_hcpRedir;
|
|
|
|
}
|
|
|
|
HRESULT HyperLinks::ParsedUrl::Initialize( /*[in]*/ LPCWSTR szURL )
|
|
{
|
|
__HCP_FUNC_ENTRY( "HyperLinks::ParsedUrl::Initialize" );
|
|
|
|
HRESULT hr;
|
|
|
|
SANITIZEWSTR(szURL);
|
|
|
|
|
|
m_strURL = szURL;
|
|
m_fmt = HyperLinks::FMT_INVALID;
|
|
m_state = HyperLinks::STATE_NOTPROCESSED;
|
|
|
|
|
|
MPC::HTML::ParseHREF( m_strURL.c_str(), m_strBasePart, m_mapQuery );
|
|
|
|
|
|
if(m_strBasePart.size() == 0)
|
|
{
|
|
m_state = HyperLinks::STATE_MALFORMED;
|
|
}
|
|
else if(MPC::MSITS::IsCHM( m_strBasePart.c_str() ))
|
|
{
|
|
m_fmt = HyperLinks::FMT_MSITS;
|
|
}
|
|
else
|
|
{
|
|
CComBSTR bstrURL( m_strBasePart.c_str() ); if(bstrURL) ::CharLowerW( bstrURL );
|
|
|
|
szURL = bstrURL;
|
|
for(const Pattern* ptr=l_rgPattern; ptr->szTxt; ptr++)
|
|
{
|
|
int iCmp;
|
|
|
|
if(ptr->iLen) iCmp = wcsncmp( szURL, ptr->szTxt, ptr->iLen );
|
|
else iCmp = wcscmp ( szURL, ptr->szTxt );
|
|
|
|
if(iCmp == 0)
|
|
{
|
|
const QueryField* field = ptr->rgQueryFields;
|
|
|
|
for(size_t i=0; i<ptr->iQueryFields; i++, field++)
|
|
{
|
|
CComBSTR bstrValue;
|
|
|
|
if(GetQueryField( field->szName, bstrValue ) == false)
|
|
{
|
|
if(field->fOptional == false)
|
|
{
|
|
m_state = HyperLinks::STATE_MALFORMED;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(field->qft == QFT_TEXT)
|
|
{
|
|
;
|
|
}
|
|
else if(field->qft == QFT_URL)
|
|
{
|
|
if(FAILED(IsValid( bstrValue )))
|
|
{
|
|
m_state = HyperLinks::STATE_MALFORMED;
|
|
break;
|
|
}
|
|
}
|
|
else if(field->qft == QFT_TAXONOMY)
|
|
{
|
|
/* TO DO */
|
|
}
|
|
else if(field->qft == QFT_APPLICATION)
|
|
{
|
|
/* TO DO */
|
|
}
|
|
}
|
|
}
|
|
|
|
m_fmt = ptr->fmt;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the URL begins with HCP://, check if it's valid HCP or is HCP redirection
|
|
//
|
|
if(m_fmt == HyperLinks::FMT_HCP)
|
|
{
|
|
if (CHCPProtocol::IsHCPRedirection(szURL))
|
|
{
|
|
// Treat as HCP redirection
|
|
m_fmt = HyperLinks::FMT_HCP_REDIR;
|
|
m_hcpRedir = true;
|
|
__MPC_SET_ERROR_AND_EXIT(hr, Initialize( m_strURL.c_str() + MAXSTRLEN( l_szHCP ) ));
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the URL begins with HCP: but not HCP://, it's a protocol redirection, so recurse.
|
|
//
|
|
if(m_fmt == HyperLinks::FMT_HCP_REDIR)
|
|
{
|
|
m_hcpRedir = true;
|
|
__MPC_SET_ERROR_AND_EXIT(hr, Initialize( m_strURL.c_str() + MAXSTRLEN( l_szHCP_redir ) ));
|
|
}
|
|
|
|
if(m_fmt == HyperLinks::FMT_INVALID) // Still not resolved...
|
|
{
|
|
MPC::URL url;
|
|
INTERNET_SCHEME scheme;
|
|
|
|
if(SUCCEEDED(url.put_URL ( szURL )) &&
|
|
SUCCEEDED(url.get_Scheme( scheme )) )
|
|
{
|
|
switch(scheme)
|
|
{
|
|
case INTERNET_SCHEME_UNKNOWN : m_fmt = HyperLinks::FMT_INTERNET_UNKNOWN ; break;
|
|
case INTERNET_SCHEME_FTP : m_fmt = HyperLinks::FMT_INTERNET_FTP ; break;
|
|
case INTERNET_SCHEME_GOPHER : m_fmt = HyperLinks::FMT_INTERNET_GOPHER ; break;
|
|
case INTERNET_SCHEME_HTTP : m_fmt = HyperLinks::FMT_INTERNET_HTTP ; break;
|
|
case INTERNET_SCHEME_HTTPS : m_fmt = HyperLinks::FMT_INTERNET_HTTPS ; break;
|
|
case INTERNET_SCHEME_FILE : m_fmt = HyperLinks::FMT_INTERNET_FILE ; break;
|
|
case INTERNET_SCHEME_NEWS : m_fmt = HyperLinks::FMT_INTERNET_NEWS ; break;
|
|
case INTERNET_SCHEME_MAILTO : m_fmt = HyperLinks::FMT_INTERNET_MAILTO ; break;
|
|
case INTERNET_SCHEME_SOCKS : m_fmt = HyperLinks::FMT_INTERNET_SOCKS ; break;
|
|
case INTERNET_SCHEME_JAVASCRIPT: m_fmt = HyperLinks::FMT_INTERNET_JAVASCRIPT; break;
|
|
case INTERNET_SCHEME_VBSCRIPT : m_fmt = HyperLinks::FMT_INTERNET_VBSCRIPT ; break;
|
|
default : m_state = HyperLinks::STATE_MALFORMED ; break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
bool HyperLinks::ParsedUrl::IsLocal()
|
|
{
|
|
switch(m_fmt)
|
|
{
|
|
case HyperLinks::FMT_INTERNET_UNKNOWN :
|
|
case HyperLinks::FMT_INTERNET_FTP :
|
|
case HyperLinks::FMT_INTERNET_GOPHER :
|
|
case HyperLinks::FMT_INTERNET_HTTP :
|
|
case HyperLinks::FMT_INTERNET_HTTPS :
|
|
case HyperLinks::FMT_INTERNET_FILE :
|
|
case HyperLinks::FMT_INTERNET_NEWS :
|
|
case HyperLinks::FMT_INTERNET_MAILTO :
|
|
case HyperLinks::FMT_INTERNET_SOCKS :
|
|
case HyperLinks::FMT_INTERNET_JAVASCRIPT:
|
|
case HyperLinks::FMT_INTERNET_VBSCRIPT :
|
|
return false;
|
|
|
|
case HyperLinks::FMT_MSITS:
|
|
//
|
|
// Make sure it's not on a network share!
|
|
//
|
|
{
|
|
CComBSTR bstrStorageName;
|
|
CComBSTR bstrFilePath;
|
|
|
|
if(MPC::MSITS::IsCHM( m_strURL.c_str(), &bstrStorageName, &bstrFilePath ))
|
|
{
|
|
if(wcsncmp( L"\\\\", SAFEBSTR(bstrStorageName), 2 ) == 0)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
HyperLinks::State HyperLinks::ParsedUrl::CheckState( /*[in/out]*/ bool& fFirstWinInetUse )
|
|
{
|
|
HRESULT hr;
|
|
State state = HyperLinks::STATE_NOTFOUND;
|
|
LPCWSTR szURL = m_strURL.c_str();
|
|
LPCWSTR szEnd;
|
|
CComBSTR bstrURL;
|
|
|
|
//
|
|
// Skip the bookmark sign.
|
|
//
|
|
if((szEnd = wcschr( szURL, '#' )))
|
|
{
|
|
bstrURL.Attach( ::SysAllocStringLen( szURL, (szEnd - szURL) ) );
|
|
szURL = SAFEBSTR( bstrURL );
|
|
}
|
|
|
|
switch(m_fmt)
|
|
{
|
|
case HyperLinks::FMT_INVALID :
|
|
state = HyperLinks::STATE_MALFORMED;
|
|
break;
|
|
|
|
case HyperLinks::FMT_INTERNET_FTP :
|
|
case HyperLinks::FMT_INTERNET_GOPHER :
|
|
case HyperLinks::FMT_INTERNET_HTTP :
|
|
case HyperLinks::FMT_INTERNET_HTTPS :
|
|
case HyperLinks::FMT_INTERNET_FILE :
|
|
case HyperLinks::FMT_INTERNET_NEWS :
|
|
while(1)
|
|
{
|
|
DWORD dwTimeout = m_fBackground ? HC_TIMEOUT_LINKCHECKER_BACKGROUND : HC_TIMEOUT_LINKCHECKER_FOREGROUND;
|
|
|
|
if(SUCCEEDED(hr = MPC::Connectivity::DestinationReachable( szURL, dwTimeout )))
|
|
{
|
|
state = HyperLinks::STATE_ALIVE;
|
|
}
|
|
else if(hr == E_INVALIDARG) // Unsupported protocol, assume the link is OK.
|
|
{
|
|
state = HyperLinks::STATE_ALIVE;
|
|
}
|
|
else if(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
|
|
{
|
|
state = HyperLinks::STATE_NOTFOUND;
|
|
}
|
|
else if(hr == HRESULT_FROM_WIN32(ERROR_INTERNET_DISCONNECTED))
|
|
{
|
|
state = HyperLinks::STATE_OFFLINE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If it's the first time through, it could be that WinINET couldn't activate the proxy code in time...
|
|
//
|
|
if(fFirstWinInetUse == true)
|
|
{
|
|
fFirstWinInetUse = false; continue;
|
|
}
|
|
|
|
if(SUCCEEDED(MPC::Connectivity::NetworkAlive( dwTimeout )))
|
|
{
|
|
state = HyperLinks::STATE_UNREACHABLE;
|
|
}
|
|
else
|
|
{
|
|
state = HyperLinks::STATE_OFFLINE;
|
|
}
|
|
}
|
|
|
|
fFirstWinInetUse = false; break;
|
|
}
|
|
break;
|
|
|
|
case HyperLinks::FMT_INTERNET_UNKNOWN :
|
|
case HyperLinks::FMT_INTERNET_MAILTO :
|
|
case HyperLinks::FMT_INTERNET_SOCKS :
|
|
case HyperLinks::FMT_INTERNET_JAVASCRIPT:
|
|
case HyperLinks::FMT_INTERNET_VBSCRIPT :
|
|
state = HyperLinks::STATE_ALIVE;
|
|
break;
|
|
|
|
case HyperLinks::FMT_HCP :
|
|
{
|
|
CComPtr<IInternetProtocolRoot> obj;
|
|
|
|
state = HyperLinks::STATE_NOTFOUND;
|
|
|
|
if(SUCCEEDED(CHCPProtocol::CreateInstance( &obj )))
|
|
{
|
|
if(SUCCEEDED(obj->Start( szURL, NULL, NULL, 0, NULL )))
|
|
{
|
|
state = HyperLinks::STATE_ALIVE;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case HyperLinks::FMT_MSITS :
|
|
{
|
|
MPC::wstring strUrlModified;
|
|
MPC::wstring strUrlModified2;
|
|
CComBSTR bstrStorageName;
|
|
CComBSTR bstrFilePath;
|
|
CComPtr<IStream> stream;
|
|
|
|
state = HyperLinks::STATE_NOTFOUND;
|
|
|
|
CPCHWrapProtocolInfo::NormalizeUrl( szURL , strUrlModified , /*fReverse*/true );
|
|
CPCHWrapProtocolInfo::NormalizeUrl( strUrlModified.c_str(), strUrlModified2, /*fReverse*/false );
|
|
if(MPC::MSITS::IsCHM( strUrlModified2.c_str(), &bstrStorageName, &bstrFilePath ))
|
|
{
|
|
if(SUCCEEDED(MPC::MSITS::OpenAsStream( bstrStorageName, bstrFilePath, &stream )))
|
|
{
|
|
state = HyperLinks::STATE_ALIVE;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case HyperLinks::FMT_CENTER_HOMEPAGE :
|
|
case HyperLinks::FMT_CENTER_SUPPORT :
|
|
case HyperLinks::FMT_CENTER_OPTIONS :
|
|
case HyperLinks::FMT_CENTER_UPDATE :
|
|
case HyperLinks::FMT_CENTER_COMPAT :
|
|
case HyperLinks::FMT_CENTER_TOOLS :
|
|
case HyperLinks::FMT_CENTER_ERRMSG :
|
|
state = HyperLinks::STATE_ALIVE;
|
|
break;
|
|
|
|
case HyperLinks::FMT_SEARCH :
|
|
case HyperLinks::FMT_INDEX :
|
|
case HyperLinks::FMT_SUBSITE :
|
|
state = HyperLinks::STATE_ALIVE;
|
|
break;
|
|
|
|
case HyperLinks::FMT_LAYOUT_FULLWINDOW :
|
|
case HyperLinks::FMT_LAYOUT_CONTENTONLY :
|
|
case HyperLinks::FMT_LAYOUT_KIOSK :
|
|
case HyperLinks::FMT_LAYOUT_XML :
|
|
state = HyperLinks::STATE_ALIVE;
|
|
break;
|
|
|
|
case HyperLinks::FMT_REDIRECT :
|
|
state = HyperLinks::STATE_ALIVE;
|
|
break;
|
|
|
|
case HyperLinks::FMT_APPLICATION :
|
|
state = HyperLinks::STATE_ALIVE;
|
|
break;
|
|
|
|
case HyperLinks::FMT_RESOURCE :
|
|
state = HyperLinks::STATE_UNREACHABLE;
|
|
break;
|
|
}
|
|
|
|
m_dLastChecked = MPC::GetLocalTime();
|
|
|
|
return state;
|
|
}
|
|
|
|
bool HyperLinks::ParsedUrl::IsOkToProceed()
|
|
{
|
|
switch(m_state)
|
|
{
|
|
case HyperLinks::STATE_NOTPROCESSED:
|
|
case HyperLinks::STATE_CHECKING :
|
|
case HyperLinks::STATE_ALIVE :
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
bool HyperLinks::ParsedUrl::HasQueryField( /*[in]*/ LPCWSTR szField )
|
|
{
|
|
MPC::WStringLookupIter it = m_mapQuery.find( szField );
|
|
|
|
return (it != m_mapQuery.end());
|
|
}
|
|
|
|
bool HyperLinks::ParsedUrl::GetQueryField( /*[in]*/ LPCWSTR szField, /*[in]*/ CComBSTR& bstrValue )
|
|
{
|
|
MPC::WStringLookupIter it = m_mapQuery.find( szField );
|
|
|
|
if(it != m_mapQuery.end())
|
|
{
|
|
bstrValue = it->second.c_str();
|
|
return true;
|
|
}
|
|
|
|
bstrValue.Empty();
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
HyperLinks::UrlHandle::UrlHandle()
|
|
{
|
|
m_main = NULL; // Lookup* m_main;
|
|
m_pu = NULL; // ParsedUrl* m_pu;
|
|
}
|
|
|
|
HyperLinks::UrlHandle::~UrlHandle()
|
|
{
|
|
Release();
|
|
}
|
|
|
|
void HyperLinks::UrlHandle::Attach( /*[in]*/ Lookup* main ,
|
|
/*[in]*/ ParsedUrl* pu )
|
|
{
|
|
Release();
|
|
|
|
m_main = main; if(main) main->Lock();
|
|
m_pu = pu;
|
|
}
|
|
|
|
void HyperLinks::UrlHandle::Release()
|
|
{
|
|
if(m_main) m_main->Unlock();
|
|
|
|
m_main = NULL;
|
|
m_pu = NULL;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
HyperLinks::Lookup::Lookup()
|
|
{
|
|
// PendingUrlList m_lst;
|
|
// UrlMap m_map;
|
|
}
|
|
|
|
HyperLinks::Lookup::~Lookup()
|
|
{
|
|
Thread_Wait();
|
|
}
|
|
|
|
////////////////////
|
|
|
|
HyperLinks::Lookup* HyperLinks::Lookup::s_GLOBAL( NULL );
|
|
|
|
HRESULT HyperLinks::Lookup::InitializeSystem()
|
|
{
|
|
if(s_GLOBAL == NULL)
|
|
{
|
|
s_GLOBAL = new HyperLinks::Lookup;
|
|
}
|
|
|
|
return s_GLOBAL ? S_OK : E_OUTOFMEMORY;
|
|
}
|
|
|
|
void HyperLinks::Lookup::FinalizeSystem()
|
|
{
|
|
if(s_GLOBAL)
|
|
{
|
|
delete s_GLOBAL; s_GLOBAL = NULL;
|
|
}
|
|
}
|
|
|
|
////////////////////
|
|
|
|
HRESULT HyperLinks::Lookup::RunChecker()
|
|
{
|
|
__HCP_FUNC_ENTRY( "HyperLinks::Lookup::RunChecker" );
|
|
|
|
HRESULT hr;
|
|
MPC::SmartLock<_ThreadModel> lock( this );
|
|
bool fFirstWinInetUse = true;
|
|
|
|
|
|
Thread_SignalMain();
|
|
|
|
while(Thread_IsAborted() == false)
|
|
{
|
|
bool fSleep = true;
|
|
ParsedUrl* urlBest = NULL;
|
|
PendingUrlIter it;
|
|
|
|
//
|
|
// Look for the first query store not ready and execute it.
|
|
//
|
|
for(it = m_lst.begin(); it != m_lst.end();)
|
|
{
|
|
ParsedUrl* url = *it;
|
|
|
|
if(url->m_state != HyperLinks::STATE_NOTPROCESSED)
|
|
{
|
|
m_lst.erase( it );
|
|
|
|
it = m_lst.begin();
|
|
urlBest = NULL;
|
|
}
|
|
else
|
|
{
|
|
if(url->m_fBackground == false)
|
|
{
|
|
urlBest = url;
|
|
break;
|
|
}
|
|
|
|
urlBest = url;
|
|
it++;
|
|
}
|
|
}
|
|
|
|
if(urlBest)
|
|
{
|
|
State state = HyperLinks::STATE_NOTFOUND;
|
|
|
|
//
|
|
// Remove this query from the pending list.
|
|
//
|
|
for(it = m_lst.begin(); it != m_lst.end(); )
|
|
{
|
|
if(*it == urlBest)
|
|
{
|
|
m_lst.erase( it );
|
|
|
|
it = m_lst.begin();
|
|
}
|
|
else
|
|
{
|
|
it++;
|
|
}
|
|
}
|
|
|
|
DebugLog( L"%%%%%%%%%%%%%%%%%%%% CHECKING %s\n", urlBest->m_strURL.c_str() );
|
|
urlBest->m_state = HyperLinks::STATE_CHECKING;
|
|
|
|
lock = NULL;
|
|
__MPC_PROTECT( state = urlBest->CheckState( fFirstWinInetUse ) );
|
|
lock = this;
|
|
|
|
urlBest->m_state = state;
|
|
|
|
Thread_SignalMain();
|
|
|
|
fSleep = false;
|
|
}
|
|
|
|
if(fSleep)
|
|
{
|
|
lock = NULL;
|
|
Thread_WaitForEvents( NULL, INFINITE );
|
|
lock = this;
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
Thread_Abort();
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT HyperLinks::Lookup::CreateItem( /*[in ]*/ LPCWSTR szURL ,
|
|
/*[out]*/ ParsedUrl*& pu )
|
|
{
|
|
__HCP_FUNC_ENTRY( "HyperLinks::Lookup::CreateItem" );
|
|
|
|
HRESULT hr;
|
|
UrlIter it;
|
|
MPC::wstringUC strURL( SAFEWSTR( szURL ) );
|
|
|
|
it = m_map.find( strURL );
|
|
if(it == m_map.end())
|
|
{
|
|
pu = &(m_map[ strURL ]);
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, pu->Initialize( szURL ));
|
|
}
|
|
else
|
|
{
|
|
pu = &it->second;
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
////////////////////
|
|
|
|
HRESULT HyperLinks::Lookup::Queue( /*[in]*/ LPCWSTR szURL )
|
|
{
|
|
UrlHandle uh;
|
|
|
|
return Get( szURL, uh );
|
|
}
|
|
|
|
HRESULT HyperLinks::Lookup::Get( /*[in]*/ LPCWSTR szURL ,
|
|
/*[in]*/ UrlHandle& uh ,
|
|
/*[in]*/ DWORD dwWaitForCheck ,
|
|
/*[in]*/ bool fForce )
|
|
{
|
|
__HCP_FUNC_ENTRY( "HyperLinks::Lookup::Get" );
|
|
|
|
HRESULT hr;
|
|
MPC::SmartLock<_ThreadModel> lock( this );
|
|
ParsedUrl* pu = NULL;
|
|
|
|
|
|
uh.Release();
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
if(Thread_IsRunning() == false)
|
|
{
|
|
lock = NULL;
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, Thread_Start( this, RunChecker, NULL ));
|
|
|
|
Thread_WaitNotificationFromWorker( INFINITE, /*fNoMessagePump*/true );
|
|
lock = this;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, CreateItem( szURL, pu ));
|
|
|
|
if(fForce)
|
|
{
|
|
pu->m_state = HyperLinks::STATE_NOTPROCESSED;
|
|
}
|
|
|
|
switch(pu->m_state)
|
|
{
|
|
case HyperLinks::STATE_ALIVE :
|
|
case HyperLinks::STATE_NOTFOUND :
|
|
case HyperLinks::STATE_UNREACHABLE:
|
|
case HyperLinks::STATE_OFFLINE :
|
|
if(dwWaitForCheck)
|
|
{
|
|
//
|
|
// Make sure the state is not stale.
|
|
//
|
|
DATE dNow = MPC::GetLocalTime();
|
|
|
|
if((dNow - pu->m_dLastChecked) >= l_TIME_timeout)
|
|
{
|
|
pu->m_state = HyperLinks::STATE_NOTPROCESSED;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
if(pu->m_state == HyperLinks::STATE_NOTPROCESSED)
|
|
{
|
|
bool fQueue = false;
|
|
bool fWait = false;
|
|
|
|
if(dwWaitForCheck)
|
|
{
|
|
//
|
|
// Elevate the URL to "important".
|
|
//
|
|
pu->m_fBackground = false;
|
|
|
|
fWait = true;
|
|
|
|
if(pu->IsLocal() == false)
|
|
{
|
|
fQueue = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fQueue = true;
|
|
}
|
|
|
|
if(fQueue)
|
|
{
|
|
m_lst.push_back( pu );
|
|
Thread_Signal();
|
|
}
|
|
|
|
if(fWait)
|
|
{
|
|
if(pu->IsLocal())
|
|
{
|
|
bool fFirstWinInetUse = false;
|
|
|
|
pu->m_state = pu->CheckState( fFirstWinInetUse );
|
|
}
|
|
else
|
|
{
|
|
int iRetry = 5;
|
|
|
|
dwWaitForCheck /= iRetry;
|
|
|
|
while(pu->m_state == HyperLinks::STATE_NOTPROCESSED ||
|
|
pu->m_state == HyperLinks::STATE_CHECKING )
|
|
{
|
|
DWORD dwRes;
|
|
|
|
lock = NULL;
|
|
dwRes = Thread_WaitNotificationFromWorker( dwWaitForCheck, /*fNoMessagePump*/true );
|
|
lock = this;
|
|
|
|
if(iRetry-- == 0)
|
|
{
|
|
__MPC_SET_ERROR_AND_EXIT(hr, S_FALSE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
if(pu) uh.Attach( this, pu );
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT HyperLinks::IsValid( /*[in]*/ LPCWSTR szURL )
|
|
{
|
|
__HCP_FUNC_ENTRY( "HyperLinks::IsValid" );
|
|
|
|
HRESULT hr;
|
|
ParsedUrl pu;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, pu.Initialize( szURL ));
|
|
|
|
switch(pu.m_state)
|
|
{
|
|
case HyperLinks::STATE_INVALID :
|
|
case HyperLinks::STATE_MALFORMED:
|
|
__MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|