|
|
//---------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation
//
// File: urlhook.cpp
//
// History:
// 9-24-96 by dli
//------------------------------------------------------------------------
#include "priv.h"
#include "sccls.h"
#include "resource.h"
#include <mluisupp.h>
// CURRENT_USER
static const TCHAR c_szSearchUrl[] = TSZIEPATH TEXT("\\SearchUrl");
#define TF_URLSEARCHHOOK 0
// structure for the character replacement in URL searches
typedef struct _SUrlCharReplace { TCHAR from; TCHAR to[10]; } SUrlCharReplace;
class CURLSearchHook : public IURLSearchHook2 { public: CURLSearchHook(); // *** IUnknown Methods
virtual STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj); virtual STDMETHODIMP_(ULONG) AddRef(void) ; virtual STDMETHODIMP_(ULONG) Release(void);
// *** IURLSearchHook
virtual STDMETHODIMP Translate(LPWSTR lpwszSearchURL, DWORD cchBufferSize);
// *** IURLSearchHook2
virtual STDMETHODIMP TranslateWithSearchContext(LPWSTR lpwszSearchURL, DWORD cchBufferSize, ISearchContext * pSearchContext); protected: // IUnknown
UINT _cRef;
HRESULT _IsKeyWordSearch(LPCTSTR pcszURL); HRESULT _IsURLSearchable(LPTSTR pszURL, HKEY * phkeySearch, LPCTSTR * pcszQuery); HRESULT _ReplaceChars(HKEY hkeySearch, LPCTSTR pcszQuery, PTSTR pszReplaced, int cchReplaced); HRESULT _Search(HKEY hkeySearch, LPCTSTR pcszQuery, PTSTR pszTranslatedURL, DWORD cchTranslatedUrl, PTSTR pszSearchUrl, ISearchContext * pSC); void _ConvertToUtf8(LPWSTR pszQuery, int cch);
};
#ifdef DEBUG
#define _AddRef(psz) { ++_cRef; TraceMsg(TF_URLSEARCHHOOK, "CURLSearchHook(%x)::QI(%s) is AddRefing _cRef=%lX", this, psz, _cRef); }
#else
#define _AddRef(psz) ++_cRef
#endif
CURLSearchHook::CURLSearchHook() : _cRef(1) { DllAddRef(); }
HRESULT CURLSearchHook::QueryInterface(REFIID riid, LPVOID * ppvObj) { // ppvObj must not be NULL
ASSERT(ppvObj != NULL); if (ppvObj == NULL) return E_INVALIDARG;
*ppvObj = NULL; if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IURLSearchHook) || IsEqualIID(riid, IID_IURLSearchHook2)) { *ppvObj = SAFECAST(this, IURLSearchHook2 *); TraceMsg(TF_URLSEARCHHOOK, "QI IURLSEARCHHOOK succeeded"); } else return E_NOINTERFACE; // Otherwise, don't delegate to HTMLObj!!
_AddRef(TEXT("IURLSearchHook")); return S_OK; }
ULONG CURLSearchHook::AddRef() { _cRef++; TraceMsg(TF_URLSEARCHHOOK, "CURLSearchHook(%x)::AddRef called, new _cRef=%lX", this, _cRef); return _cRef; }
ULONG CURLSearchHook::Release() { _cRef--; TraceMsg(TF_URLSEARCHHOOK, "CURLSearchHook(%x)::Release called, new _cRef=%lX", this, _cRef); if (_cRef > 0) return _cRef;
delete this; DllRelease(); return 0; }
HRESULT CURLSearchHook::_IsKeyWordSearch(LPCTSTR pcszURL) { TCHAR szAcceptedRequestKey[256]; LPTSTR lpsz = szAcceptedRequestKey; LPTSTR lpszKey = szAcceptedRequestKey; // load the accepted request keywords and compare them with what the user typed in
MLLoadString(IDS_URL_SEARCH_KEY, szAcceptedRequestKey, ARRAYSIZE(szAcceptedRequestKey)-1); int RequestKeyLen = 0; while (*lpsz) { if (*lpsz == TEXT(' ')){ if (! StrCmpNI(pcszURL, lpszKey, RequestKeyLen+1)) return S_OK; else { lpsz++; lpszKey = lpsz; RequestKeyLen = 0; } } else { lpsz++; RequestKeyLen++; } } return S_FALSE; }
// This function determines if we will do an autosearch on the string user typed in
//
// Priorities:
// 1 --- Key word search: search with "go", "find" and so on
// 2 --- possible URL address: contains '.', ':', '/' and '\\', so don't search
// 3 --- Space triggered search.
// 4 --- Don't search.
HRESULT CURLSearchHook::_IsURLSearchable(LPTSTR pszURL, HKEY * phkeySearch, LPCTSTR * ppcszQuery) { BOOL fExtendedChar = FALSE; TCHAR szRegSearchKey[MAX_PATH]; LPTSTR pszKey = StrChr(pszURL, TEXT(' ')); if (pszKey == NULL) { // No keyword, but if any of the characters are non-ascii, we will default
// to search because it's likely not a url
fExtendedChar = HasExtendedChar(pszURL); if (!fExtendedChar) return S_FALSE;
pszKey = pszURL; } StrCpyN(szRegSearchKey, c_szSearchUrl, ARRAYSIZE(szRegSearchKey)); if ((_IsKeyWordSearch(pszURL) == S_FALSE) && !fExtendedChar) { // Find the end of the default Registry Subkey and
// append the keyword so the regkey becomes:
// Software\Microsoft\Internet Explorer\SearchUrl\go
ASSERT((ARRAYSIZE(c_szSearchUrl) + 1) < ARRAYSIZE(szRegSearchKey)); PTSTR pszEnd = &szRegSearchKey[ARRAYSIZE(c_szSearchUrl) - 1]; *pszEnd++ = TEXT('\\'); const int cchBuf = ARRAYSIZE(szRegSearchKey) - (ARRAYSIZE(c_szSearchUrl) + 1); const int cchToCopy = (int) (pszKey - pszURL + 1); StrCpyN(pszEnd, pszURL, min(cchBuf, cchToCopy));
// See if this is a search keyword in the registry
if (OpenRegUSKey(szRegSearchKey, 0, KEY_READ, phkeySearch) == ERROR_SUCCESS) { PathRemoveBlanks(pszKey); *ppcszQuery = pszKey; return S_OK; }
// No keyword so use entire "url" for the search
pszKey = pszURL;
if (StrCSpn(pszURL, TEXT(":/\\")) != lstrlen(pszURL)) { return S_FALSE; } } // Null out the key to signal that we should use the internal hard-coded search string
*phkeySearch = NULL; PathRemoveBlanks(pszKey); *ppcszQuery = pszKey; return S_OK; }
HRESULT CURLSearchHook::_ReplaceChars(HKEY hkeySearch, LPCTSTR pcszQuery, LPTSTR pszReplaced, int cchReplaced) { // The following are strings and its lengthes passed in RegEnumValue
TCHAR szOrig[2]; DWORD dwOrigLen; TCHAR szMatch[10]; DWORD dwMatchLen; HDSA hdsaReplace = NULL; // If we are using our hard-coded search url, we get the char replacements from the string table
if (NULL == hkeySearch) { WCHAR szSub[MAX_PATH]; if (MLLoadString(IDS_SEARCH_SUBSTITUTIONS, szSub, ARRAYSIZE(szSub)) && *szSub != NULL) { // The first char is our deliminator followed by replacement pairs (", ,+,#,%23,&,%26,?,%3F,+,%2B,=,%3d")
WCHAR chDelim = szSub[0]; LPWSTR pszFrom = &szSub[1]; BOOL fDone = FALSE; LPWSTR pszNext; do { // Null terminater our source string
LPWSTR pszTo = StrChr(pszFrom, chDelim); if (NULL == pszTo) { break; } *pszTo = L'\0';
// Null terminate the dest string
++pszTo; LPWSTR pszToEnd = StrChr(pszTo, chDelim); if (pszToEnd) { *pszToEnd = L'\0'; pszNext = pszToEnd + 1; } else { pszNext = NULL; } // If the "from" string is one char and the "to" substitution fits, store this pair
SUrlCharReplace scr; if (pszFrom[1] == L'\0' && lstrlen(pszTo) < ARRAYSIZE(scr.to)) { scr.from = pszFrom[0]; StrCpyN(scr.to, pszTo, ARRAYSIZE(scr.to)); if (!hdsaReplace) hdsaReplace = DSA_Create(SIZEOF(SUrlCharReplace), 4); if (hdsaReplace) DSA_AppendItem(hdsaReplace, &scr); }
pszFrom = pszNext; } while (pszNext != NULL); } }
// The search url is in the registry, so get the char substitutions from there
else { DWORD dwType; LONG lRegEnumResult; DWORD dwiValue = 0; do { dwOrigLen = ARRAYSIZE(szOrig); dwMatchLen = SIZEOF(szMatch); lRegEnumResult = RegEnumValue(hkeySearch, dwiValue, szOrig, &dwOrigLen, NULL, &dwType, (PBYTE)szMatch, &dwMatchLen); dwiValue++; SUrlCharReplace scr; if ((lRegEnumResult == ERROR_SUCCESS) && (dwType == REG_SZ) && (dwOrigLen == 1) && dwMatchLen < ARRAYSIZE(scr.to)) { scr.from = szOrig[0]; StrCpyN(scr.to, szMatch, ARRAYSIZE(scr.to)); if (!hdsaReplace) hdsaReplace = DSA_Create(SIZEOF(SUrlCharReplace), 4); if (hdsaReplace) DSA_AppendItem(hdsaReplace, &scr); } } while ((lRegEnumResult == ERROR_SUCCESS) || (lRegEnumResult == ERROR_MORE_DATA)); } if (hdsaReplace) { // Replace all characters found in the registry by their matches in the search key word
LPTSTR lpHead = pszReplaced; int cchHead = cchReplaced; int ich; int ihdsa; BOOL bCharFound; int querylen = lstrlen(pcszQuery); for (ich = 0; ich < querylen && cchHead > 1; ich++) { bCharFound = FALSE; // First look through the DSA array to find a match
for (ihdsa = 0; ihdsa < DSA_GetItemCount(hdsaReplace); ihdsa++) { SUrlCharReplace *pscr; pscr = (SUrlCharReplace *)DSA_GetItemPtr(hdsaReplace, ihdsa); if (pscr && pscr->from == pcszQuery[ich]) { int szLen = lstrlen(pscr->to); StrCpyN(lpHead, pscr->to, cchHead); lpHead += szLen; cchHead -= szLen; bCharFound = TRUE; break; } } // Copy the character over if there is no replacements
if (!bCharFound) { *lpHead = pcszQuery[ich]; lpHead++; cchHead--; } }
if (cchHead > 0) *lpHead = 0; DSA_Destroy(hdsaReplace); hdsaReplace = NULL; } return S_OK; }
void CURLSearchHook::_ConvertToUtf8(LPWSTR pszQuery, int cch) { // Only need to covert if extended characters found
if (HasExtendedChar(pszQuery)) { ConvertToUtf8Escaped(pszQuery, cch); } }
// pszTranslatedUrl is the output of this function
HRESULT CURLSearchHook::_Search(HKEY hkeySearch, LPCTSTR pcszQuery, PTSTR pszTranslatedUrl, DWORD cchTranslatedUrl, PTSTR pszSearchUrl, ISearchContext * pSC) { HRESULT hr = E_FAIL;
// Get the search provider from the registry
DWORD dwType; WCHAR szProvider[MAX_PATH]; szProvider[0] = 0; DWORD cbProvider = sizeof(szProvider); if (SHRegGetUSValue(c_szSearchUrl, L"Provider", &dwType, &szProvider, &cbProvider, FALSE, NULL, 0) != ERROR_SUCCESS || dwType != REG_SZ) { szProvider[0] = 0; }
TCHAR szSearchPath[MAX_URL_STRING]; DWORD dwSearchPathLen = SIZEOF(szSearchPath); BOOL fSuccess;
if (pszSearchUrl != NULL) { StrCpyNW(szSearchPath, pszSearchUrl, ARRAYSIZE(szSearchPath)); fSuccess = TRUE; } else { // Find the search URL in the registry or our string table
if (hkeySearch) { fSuccess = (RegQueryValueEx(hkeySearch, NULL, NULL, NULL, (PBYTE)szSearchPath, &dwSearchPathLen) == ERROR_SUCCESS); } else {
// See if we want the hardcoded intranet or internet url
UINT ids = (StrCmpI(szProvider, L"Intranet") == 0) ? IDS_SEARCH_INTRANETURL : IDS_SEARCH_URL;
// Use our internal hard-coded string
fSuccess = MLLoadString(ids, szSearchPath, ARRAYSIZE(szSearchPath)); } }
if (fSuccess && lstrlen(szSearchPath) > 1) { // 1. Look in the registry and find all of the original characters and it's
// matches and store them in the DSA arrays of SURlCharReplace
// 2. Replace all of the occurences of the original characters in the
// URL search key word by their matches.
// 3. Append the search URL and the search key words
TCHAR szURLReplaced[MAX_URL_STRING]; StrCpyN(szURLReplaced, pcszQuery, ARRAYSIZE(szURLReplaced)); _ReplaceChars(hkeySearch, pcszQuery, szURLReplaced, ARRAYSIZE(szURLReplaced));
//
// If we are using our search engine, convert the string to UTF8 and escape it
// so that it appears like normal ascii
//
if (NULL == hkeySearch) { _ConvertToUtf8(szURLReplaced, ARRAYSIZE(szURLReplaced)); }
// If this is an old-style url, there will be a %s in it for the search string.
// Otherwise there will be the following parameters:
//
// http://whatever.com?p=%1&srch=%2&prov=%3&utf8
//
// %1 = search string
// %2 = how to display results:
// "1" = just show me results in full window
// "2" = show results in full window, but redirect if possible
// "3" = show results in the search pane, and take me to the most
// likely site in the main window if there is one
// %3 = search provider name
//
LPWSTR pszParam1 = StrStr(szSearchPath, L"%1"); if (NULL != pszParam1) { //
// We can't use FormatMessage because on win95 it converts to ansi
// using the system code page and the translation back is lossy.
// So we'll replace the parameters ourselves. Arrrggg.
//
// First convert %1 to %s
pszParam1[1] = L's';
// Next replace %2 with the display option in %2
LPWSTR pszParam2 = StrStr(szSearchPath, L"%2"); if (NULL != pszParam2) { DWORD dwValue; if (pSC != NULL) { hr = pSC->GetSearchStyle(&dwValue); } else { DWORD cbValue = sizeof(dwValue); if (SHRegGetUSValue(REGSTR_PATH_MAIN, L"AutoSearch", &dwType, &dwValue, &cbValue, FALSE, NULL, 0) != ERROR_SUCCESS || dwValue > 9) { // Default to "display results in search pane and go to most likely site"
dwValue = 3; } }
*pszParam2 = (WCHAR)dwValue + L'0'; StrCpyN(pszParam2 + 1, pszParam2 + 2, (int)(ARRAYSIZE(szSearchPath) - ((pszParam2 + 1) - szSearchPath))); }
// Finally, find the third Param and convert it to %s too
LPWSTR pszParam3 = StrStr(szSearchPath, L"%3"); if (pszParam3) { // Insert the provider in the third param
WCHAR szTemp[MAX_URL_STRING]; StrCpyN(szTemp, pszParam3 + 2, ARRAYSIZE(szTemp)); *pszParam3 = 0; StrCatBuff(szSearchPath, szProvider, ARRAYSIZE(szSearchPath)); StrCatBuff(szSearchPath, szTemp, ARRAYSIZE(szSearchPath)); } }
// Now replace the %s with the search string
wnsprintf(pszTranslatedUrl, cchTranslatedUrl, szSearchPath, szURLReplaced); hr = S_OK; }
if (hkeySearch) RegCloseKey(hkeySearch); return hr; }
HRESULT CURLSearchHook::TranslateWithSearchContext(LPWSTR lpwszSearchURL, DWORD cchBufferSize, ISearchContext * pSC) { HRESULT hr = E_FAIL; TCHAR szSearchURL[MAX_URL_STRING];
SHUnicodeToTChar(lpwszSearchURL, szSearchURL, ARRAYSIZE(szSearchURL)); HKEY hkeySearch; LPCTSTR pcszQuery; if (_IsURLSearchable(szSearchURL, &hkeySearch, &pcszQuery) == S_OK) { BSTR bstrSearchUrl = NULL;
if (pSC != NULL) { pSC->GetSearchUrl(&bstrSearchUrl); }
hr = _Search(hkeySearch, pcszQuery, szSearchURL, ARRAYSIZE(szSearchURL), bstrSearchUrl, pSC); if (hr == S_OK) SHTCharToUnicode(szSearchURL, lpwszSearchURL, cchBufferSize);
if (bstrSearchUrl != NULL) { SysFreeString(bstrSearchUrl); } } return hr; }
HRESULT CURLSearchHook::Translate(LPWSTR lpwszSearchURL, DWORD cchBufferSize) { return TranslateWithSearchContext(lpwszSearchURL, cchBufferSize, NULL); }
#ifdef DEBUG
extern void remove_from_memlist(void *pv); #endif
STDAPI CURLSearchHook_CreateInstance(IUnknown* pUnkOuter, IUnknown **ppunk, LPCOBJECTINFO poi) { // aggregation checking is handled in class factory
HRESULT hr = E_OUTOFMEMORY;
CURLSearchHook *pcush = new CURLSearchHook;
if (pcush) { //
// HACK:(dli)
//
// IURLSearchHook objects are free-threaded objects, meaning that
// they are cacheed and shared between different IEXPLORE processes,
// and they are only deleted when the SHDOCVW DLL ref count is 0.
// So, we can remove them from the SATOSHI's memlist.
//
// By the way, SATOSHI has Okayed this. Don't copy this code without
// talking to SATOSHI.
//
*ppunk = (IUnknown *) pcush; hr = S_OK; }
return hr; }
|