2025-04-27 07:49:33 -04:00

578 lines
18 KiB
C++

/*
** BROWSER.CPP
** Sean P. Nolan
**
** Browser Capabilities SSO
*/
#pragma warning(disable: 4237) // disable "bool" reserved
#include "ssobase.h"
#include "browser.h"
#include <iis64.h>
/*--------------------------------------------------------------------------+
| Local Prototypes |
+--------------------------------------------------------------------------*/
HRESULT SSOOnFreeTemplate(WORD wInvokeFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult, SSSTUFF *pstuff);
HRESULT SSOAbout(WORD wInvokeFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult, SSSTUFF *pstuff);
HRESULT SSODynamic(WORD wInvokeFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult, SSSTUFF *pstuff);
/*--------------------------------------------------------------------------+
| Globals We Have To Provide |
+--------------------------------------------------------------------------*/
SSOMETHOD g_rgssomethod[] = { { c_wszOnFreeTemplate,
(PFNSSOMETHOD) SSOOnFreeTemplate,
0 },
{ L"About",
(PFNSSOMETHOD) SSOAbout,
0 },
{ NULL,
NULL,
0 }};
PFNSSOMETHOD g_pfnssoDynamic = (PFNSSOMETHOD) SSODynamic;
LPSTR g_szSSOProgID = "MSWC.BrowserType";
BOOL g_fPersistentSSO = TRUE;
GUID CDECL g_clsidSSO =
{ 0xace4881, 0x8305, 0x11cf,
{ 0x94, 0x27, 0x44, 0x45, 0x53, 0x54, 0x0, 0x0 } };
/*--------------------------------------------------------------------------+
| Constants |
+--------------------------------------------------------------------------*/
#define SN_BLOCK_SIZE 1024 // Allocation block size for Section Names
#define DEFAULTSTRSIZE 1024 // size of localized text string
const CHAR *c_szUnknown = "Unknown";
const OLECHAR *c_wszUnknown = L"Unknown";
const CHAR *c_szTrue = "TRUE";
const CHAR *c_szFalse = "FALSE";
const OLECHAR *c_wszParent = L"Parent";
const CHAR *c_szDefault = "Default Browser Capability Settings";
const CHAR c_chWildCard = '*';
const char *c_szIniExt = ".INI";
const OLECHAR *c_wszUA_OS = L"UA_OS";
const OLECHAR *c_wszUA_Color = L"UA_Color";
const OLECHAR *c_wszUA_Pixels = L"UA_Pixels";
const OLECHAR *c_wszUA_CPU = L"UA_CPU";
/*--------------------------------------------------------------------------+
| CIniDataFile |
+--------------------------------------------------------------------------*/
class CVariantHash;
class CIniDataFile : public CDataFile
{
private:
CVariantHash *m_pvh;
public:
CIniDataFile(LPSTR szDataPath, CDataFileGroup *pfg, CVariantHash *pvh);
void ResetVariantHash(void);
BOOL FWatchIt(void);
virtual void FreeDataFile(void) { delete this; }
};
/*--------------------------------------------------------------------------+
| CVariantHash |
+--------------------------------------------------------------------------*/
class CVariantHash : public CGenericHash
{
private:
CIniDataFile *m_pdf;
BOOL m_fInited;
CHAR m_szIniFile[MAX_PATH];
public:
CVariantHash(DWORD cBuckets);
~CVariantHash(void);
BOOL FInit(void);
void Uninit(void);
VARIANT *GetVariant(OLECHAR *wszUserAgent, OLECHAR *wszAttribute);
virtual void FreeHashData(LPVOID pv);
};
CVariantHash::CVariantHash(DWORD cBuckets)
: CGenericHash(cBuckets)
{
m_pdf = NULL;
m_fInited = FALSE;
}
CVariantHash::~CVariantHash()
{
if (m_pdf)
m_pdf->Release();
}
void
CVariantHash::Uninit()
{
this->Lock();
m_fInited = FALSE;
if (m_pdf)
{
m_pdf->Release();
m_pdf = NULL;
}
this->RemoveAll();
this->Unlock();
}
BOOL
CVariantHash::FInit()
{
char *pch;
this->Lock();
if (!m_fInited)
{
// even if we fail
m_fInited = TRUE;
// get the path to the datafile
::GetModuleFileName(g_hinst, m_szIniFile, sizeof(m_szIniFile));
pch = m_szIniFile + lstrlen(m_szIniFile) - 1;
while (pch != m_szIniFile && *pch != '.')
pch = ::CharPrev(m_szIniFile, pch);
if (*pch == '.')
lstrcpy(pch, c_szIniExt);
// create the data file and start watching it
if (m_pdf = new CIniDataFile(m_szIniFile, NULL, this))
{
m_pdf->AddRef();
m_pdf->FWatchIt();
}
}
this->Unlock();
return(m_fInited);
}
void
CVariantHash::FreeHashData(LPVOID pv)
{
::VariantClear((VARIANT*)pv);
_MsnFree(pv);
}
VARIANT *
CVariantHash::GetVariant(OLECHAR *wszInUserAgent, OLECHAR *wszAttribute)
{
OLECHAR wszUserAgent[1024];
CHAR szUserAgent[1024];
CHAR szAttribute[1024];
OLECHAR wszTag[1024];
CHAR szValue[1024];
OLECHAR wszValue[1024];
OLECHAR wszPrefix[2];
OLECHAR *wszValReal;
VARIANT *pvar, *pvarNew, *pvarParent, *pvarT;
BOOL fNum = FALSE;
CHAR *szSecName = NULL;
DWORD dwBlocks = 8;
CHAR *pszSecName=NULL;
CHAR *pszStarLoc=NULL;
USHORT ccLeft;
USHORT ccRight;
if (!this->FInit())
return(NULL);
wcscpy(wszTag, wszInUserAgent);
wcscat(wszTag, L"-");
wcscat(wszTag, wszAttribute);
if (!(pvar = (VARIANT *) this->PvFind(wszTag)))
{
// Haven't seen this yet combination yet.
// First let's see if the user agent string is an exact match
// or if we need to get a wildcard match
wcstombs(szUserAgent, wszInUserAgent, sizeof(szUserAgent));
wcstombs(szAttribute, wszAttribute, sizeof(szAttribute));
if (0 ==::GetPrivateProfileSectionA(szUserAgent,
szValue,
sizeof(szValue) / sizeof(CHAR),
m_szIniFile))
{ // no exact match for User Agent found
szSecName = (CHAR*)_MsnAlloc((dwBlocks*SN_BLOCK_SIZE*sizeof(CHAR)));
if (NULL == szSecName)
return(NULL);
while ((::GetPrivateProfileSectionNamesA(szSecName,
(dwBlocks*SN_BLOCK_SIZE),
m_szIniFile)) == dwBlocks*SN_BLOCK_SIZE-2)
{
dwBlocks++;
szSecName = (CHAR *)_MsnRealloc(szSecName, (dwBlocks*SN_BLOCK_SIZE*sizeof(CHAR)));
if (!szSecName)
return(NULL);
}
for (pszSecName=szSecName; *pszSecName!='\0'; pszSecName+=lstrlen(pszSecName)+1)
{
if ((pszStarLoc=strchr(pszSecName, c_chWildCard)) &&
(lstrlen(szUserAgent)>=(lstrlen(pszSecName)-1)))
{ // If there's a wildcard character in the section name,
// and the User-Agent string is long enough to match,
// then try to match the strings on both sides of the
// wildcard character. If no wildcard character, then
// do nothing, since we've already failed the exact match.
ccLeft = DIFF(pszStarLoc-pszSecName);
ccRight = lstrlen(pszSecName) - ccLeft - 1;
if ((CompareString(LOCALE_USER_DEFAULT,
NORM_IGNORECASE,
pszSecName,
ccLeft,
szUserAgent,
ccLeft)==2) &&
(CompareString(LOCALE_USER_DEFAULT,
NORM_IGNORECASE,
(CHAR*)(pszStarLoc+1),
ccRight,
(CHAR*)(szUserAgent+(lstrlen(szUserAgent)-ccRight)),
ccRight)==2))
{
lstrcpy(szUserAgent, pszSecName);
break;
}
}
}
if (szSecName)
_MsnFree(szSecName);
}
// See if an entry exists in the ini file
::GetPrivateProfileStringA(szUserAgent,
szAttribute,
c_szUnknown,
szValue,
sizeof(szValue) / sizeof(CHAR),
m_szIniFile);
pvarT = NULL;
if (!stricmp(szValue, c_szUnknown) &&
wcsicmp(wszAttribute, c_wszParent))
{
// ok .. tried to read it out of the ini file,
// but it wasn't there. see if there's a parent entry
// for this guy and, if so, query the parent for it
// and then munge it into place here. if not, just go
// on about our business as usual
mbstowcs(wszUserAgent, szUserAgent, sizeof(wszUserAgent) / sizeof(OLECHAR));
if (pvarParent = this->GetVariant(wszUserAgent, (OLECHAR*) c_wszParent))
{
if (pvarParent->vt == VT_BSTR &&
wcsicmp(V_BSTR(pvarParent), c_wszUnknown))
{
// if this fails, no sweat. If it succeeds, we'll use it instead
// of what's in szValue later
pvarT = this->GetVariant(V_BSTR(pvarParent), wszAttribute);
}
}
}
if (!stricmp(szValue, c_szUnknown) && !pvarT)
{
// ok .. tried to read it out of the ini file,
// but it wasn't there. Also tried looking for
// a parent entry, but there was none. See if
// there's a default entry
::GetPrivateProfileStringA((CHAR*) c_szDefault,
szAttribute,
c_szUnknown,
szValue,
sizeof(szValue) / sizeof(CHAR),
m_szIniFile);
}
if (!(pvarNew = (VARIANT*) _MsnAlloc(sizeof(VARIANT))))
return(NULL);
if (pvarT)
{
// pulled from parent or default
::VariantInit(pvarNew);
::VariantCopy(pvarNew, pvarT);
}
else if (!stricmp(szValue, c_szTrue))
{
// bool true
pvarNew->vt = VT_BOOL;
V_BOOL(pvarNew) = VARIANT_TRUE;
}
else if (!stricmp(szValue, c_szFalse))
{
// bool false
pvarNew->vt = VT_BOOL;
V_BOOL(pvarNew) = VARIANT_FALSE;
}
else
{
mbstowcs(wszValue, szValue, sizeof(wszValue) / sizeof(OLECHAR));
wszPrefix[0] = wszValue[0];
wszPrefix[1] = 0;
if (!wcsicmp(wszPrefix, L"#"))
{
// number
fNum = TRUE;
wszValReal = &(wszValue[1]);
}
else
{
// string
fNum = FALSE;
wszValReal = wszValue;
}
pvarNew->vt = VT_BSTR;
if (!(V_BSTR(pvarNew) = ::SysAllocString(wszValReal)))
{
_MsnFree(pvarNew);
return(NULL);
}
if (fNum)
::VariantChangeType(pvarNew, pvarNew, 0, VT_I4);
}
if (!this->FAdd(wszTag, (LPVOID) pvarNew))
{
::VariantClear(pvarNew);
_MsnFree(pvarNew);
return(NULL);
}
pvar = pvarNew;
}
return(pvar);
}
/*--------------------------------------------------------------------------+
| CIniDataFile Implementation |
+--------------------------------------------------------------------------*/
CIniDataFile::CIniDataFile(LPSTR szDataPath, CDataFileGroup *pfg, CVariantHash *pvh)
: CDataFile(szDataPath, pfg)
{
m_pvh = pvh;
}
void
CIniDataFile::ResetVariantHash()
{
m_pvh->Uninit();
}
void
IniFileChanged(LPSTR szFile, LONG lUser)
{
CIniDataFile *pdf = (CIniDataFile*) lUser;
pdf->ResetVariantHash();
}
BOOL
CIniDataFile::FWatchIt()
{
return(this->FWatchFile((PFNFILECHANGED)IniFileChanged));
}
/*--------------------------------------------------------------------------+
| Private Globals |
+--------------------------------------------------------------------------*/
CVariantHash g_vh(1023);
/*--------------------------------------------------------------------------+
| External Interface |
+--------------------------------------------------------------------------*/
HRESULT
SSOOnFreeTemplate(WORD wInvokeFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult, SSSTUFF *pstuff)
{
if (pstuff->lUser)
::SysFreeString((BSTR)(pstuff->lUser));
return(NOERROR);
}
HRESULT
SSODynamic(WORD wInvokeFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult, SSSTUFF *pstuff)
{
VARIANT *pvar = NULL;
VARIANT varUserAgent;
IDispatch *pDispUserAgent = NULL;
IRequest *preq = NULL;
IDispatch *pDispIEProperty = NULL;
VARIANT varIEProperty;
HRESULT hr = NOERROR;
OLECHAR *wszName = NULL;
IScriptingContext *pcxt = NULL;
::VariantInit(&varUserAgent);
if (!wcsicmp(pstuff->wszMethodName, c_wszOnNewTemplate))
goto end;
if (pvarResult)
::VariantInit(pvarResult);
else
goto end;
if (wInvokeFlags & DISPATCH_PROPERTYPUT)
{
hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
goto end;
}
// get the user-agent string
if (FAILED(hr = pstuff->punk->QueryInterface(IID_IScriptingContext, reinterpret_cast<void **>(&pcxt))))
goto end;
if (FAILED(hr = pcxt->get_Request(&preq)))
goto end;
hr = preq->get_Item(L"HTTP_USER_AGENT", &pDispUserAgent);
if (FAILED(hr))
{
pvarResult->vt = VT_BSTR;
V_BSTR(pvarResult) = ::SysAllocString(c_wszUnknown);
hr = NOERROR;
goto end;
}
V_VT(&varUserAgent) = VT_DISPATCH;
V_DISPATCH(&varUserAgent) = pDispUserAgent;
if (FAILED(hr = VariantChangeType(&varUserAgent, &varUserAgent, 0, VT_BSTR)))
goto end;
// now get it out of the hash table
if (pstuff->wszMethodName[0])
{
// dynamic property
wszName = pstuff->wszMethodName;
}
else
{
// default method
if (pdispparams->cArgs == 0)
{
hr = DISP_E_PARAMNOTOPTIONAL;
goto end;
}
if (pdispparams->cArgs > 1)
{
hr = DISP_E_PARAMNOTFOUND;
goto end;
}
wszName = V_BSTR(pdispparams->rgvarg);
}
if (!wcsicmp(wszName, c_wszUA_OS) ||
!wcsicmp(wszName, c_wszUA_Pixels) ||
!wcsicmp(wszName, c_wszUA_Color) ||
!wcsicmp(wszName, c_wszUA_CPU))
{
::VariantInit(&varIEProperty);
OLECHAR wszTag[1024];
wcscpy(wszTag, L"HTTP_");
wcscat(wszTag, wszName);
hr = preq->get_Item(wszTag, &pDispIEProperty);
if (SUCCEEDED(hr))
{
V_VT(&varIEProperty) = VT_DISPATCH;
V_DISPATCH(&varIEProperty) = pDispIEProperty;
if (SUCCEEDED(hr = VariantChangeType(&varIEProperty, &varIEProperty, 0, VT_BSTR)))
{
::VariantCopy(pvarResult, &varIEProperty);
goto end;
}
}
}
g_vh.Lock();
if (!(pvar = g_vh.GetVariant(V_BSTR(&varUserAgent), wszName)))
{
g_vh.Unlock();
pvarResult->vt = VT_BSTR;
V_BSTR(pvarResult) = ::SysAllocString(c_wszUnknown);
hr = NOERROR;
goto end;
}
::VariantCopy(pvarResult, pvar);
g_vh.Unlock();
end:
if (pcxt)
pcxt->Release();
if (preq != NULL)
preq->Release();
::VariantClear(&varUserAgent);
return hr;
}
HRESULT
SSOAbout(WORD wInvokeFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult, SSSTUFF *pstuff)
{
char sz[MAX_PATH];
CHAR szBrowserAboutFormat[DEFAULTSTRSIZE];
OLECHAR wsz[MAX_PATH];
#ifdef _DEBUG
char *szVersion = "Debug";
#else
char *szVersion = "Release";
#endif
CchLoadStringOfId(SSO_BROWSER_ABOUT_FORMAT, szBrowserAboutFormat, DEFAULTSTRSIZE);
wsprintf(sz, szBrowserAboutFormat, szVersion, __DATE__, __TIME__);
::MultiByteToWideChar(CP_ACP, 0, sz, -1, wsz, sizeof(wsz) / sizeof(OLECHAR));
VariantInit(pvarResult);
pvarResult->vt = VT_BSTR;
V_BSTR(pvarResult) = ::SysAllocString(wsz);
return(NOERROR);
}
/*--------------------------------------------------------------------------+
| DllMain |
+--------------------------------------------------------------------------*/
BOOL WINAPI
DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved)
{
return(SSODllMain(hInstance, ulReason, pvReserved));
}