windows-nt/Source/XPSP1/NT/shell/ext/webcheck/webcheck.cpp

1153 lines
30 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
#include "private.h"
#include "subsmgrp.h"
#include "offsync.h"
#include "offl_cpp.h"
#include "factory.h"
#include "notfcvt.h"
#define TF_THISMODULE TF_WEBCHECKCORE
#include "resource.h"
#define INITGUIDS
#include <shlguid.h>
#define MLUI_INIT
#include <mluisupp.h>
// We're going to use our own new and delete so that we can
// use shdocvw's leak detection code
//
//
// Subscription property names
//
// Agent Start
extern const WCHAR c_szPropURL[] = L"URL";
extern const WCHAR c_szPropName[] = L"Name";
extern const WCHAR c_szPropAgentFlags[] = L"AgentFlags";
extern const WCHAR c_szPropCrawlLevels[] = L"RecurseLevels";
extern const WCHAR c_szPropCrawlFlags[] = L"RecurseFlags";
extern const WCHAR c_szPropCrawlMaxSize[] = L"MaxSizeKB";
extern const WCHAR c_szPropCrawlChangesOnly[] = L"CheckChangesOnly";
extern const WCHAR c_szPropChangeCode[] = L"ChangeCode";
extern const WCHAR c_szPropCrawlUsername[] = L"Username";
extern const WCHAR c_szPropEmailNotf[] = L"EmailNotification";
extern const WCHAR c_szPropCrawlLocalDest[] = L"LocalDest";
extern const WCHAR c_szPropCrawlGroupID[] = L"GroupID";
extern const WCHAR c_szPropCrawlNewGroupID[] = L"NewGroupID";
extern const WCHAR c_szPropActualProgressMax[] = L"ActualProgressMax";
extern const WCHAR c_szPropCrawlActualSize[] = L"ActualSizeKB";
extern const WCHAR c_szPropEnableShortcutGleam[] = L"EnableShortcutGleam";
extern const WCHAR c_szPropChannelFlags[] = L"ChannelFlags";
extern const WCHAR c_szPropChannel[] = L"Channel";
extern const WCHAR c_szPropDesktopComponent[] = L"DesktopComponent";
extern const WCHAR c_szPropStatusCode[] = L"StatusCode";
extern const WCHAR c_szPropStatusString[] = L"StatusString";
extern const WCHAR c_szPropCompletionTime[] = L"CompletionTime";
extern const WCHAR c_szPropPassword[] = L"Password";
// End Report
extern const WCHAR c_szPropEmailURL[] = L"EmailURL";
extern const WCHAR c_szPropEmailFlags[] = L"EmailFlags";
extern const WCHAR c_szPropEmailTitle[] = L"EmailTitle";
extern const WCHAR c_szPropEmailAbstract[] = L"EmailAbstract";
extern const WCHAR c_szPropCharSet[] = L"CharSet";
// Tray Agent Properties
extern const WCHAR c_szPropGuidsArr[] = L"Guids Array";
// Tracking Properties
extern const WCHAR c_szTrackingCookie[] = L"LogGroupID";
extern const WCHAR c_szTrackingPostURL[] = L"PostURL";
extern const WCHAR c_szPostingRetry[] = L"PostFailureRetry";
extern const WCHAR c_szPostHeader[] = L"PostHeader";
extern const WCHAR c_szPostPurgeTime[] = L"PostPurgeTime";
// Delivery Agent Properties
extern const WCHAR c_szStartCookie[] = L"StartCookie";
// Initial cookie in AGENT_INIT
extern const WCHAR c_szInitCookie[] = L"InitCookie";
STDAPI OfflineFolderRegisterServer();
STDAPI OfflineFolderUnregisterServer();
// Count number of objects and number of locks.
ULONG g_cObj=0;
ULONG g_cLock=0;
// DLL Instance handle
HINSTANCE g_hInst=0;
// other globals
BOOL g_fIsWinNT; // Are we on WinNT? Always initialized.
BOOL g_fIsWinNT5; // Is it NT5?
BOOL g_fIsMillennium = FALSE;
// logging globals
BOOL g_fCheckedForLog = FALSE; // have we checked registry?
TCHAR * g_pszLoggingFile = NULL; // file to write log to
TCHAR szInternetSettings[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings");
TCHAR szProxyEnable[] = TEXT("ProxyEnable");
const TCHAR c_szRegKey[] = WEBCHECK_REGKEY;
const TCHAR c_szRegKeyUsernames[] = WEBCHECK_REGKEY TEXT("\\UserFormFieldNames");
const TCHAR c_szRegKeyPasswords[] = WEBCHECK_REGKEY TEXT("\\PasswordFormFieldNames");
const TCHAR c_szRegKeyStore[] = WEBCHECK_REGKEY_STORE;
// Pstore related variables.
static PST_PROVIDERID s_provID = GUID_NULL;
// {14D96C20-255B-11d1-898F-00C04FB6BFC4}
static const GUID GUID_PStoreType = { 0x14d96c20, 0x255b, 0x11d1, { 0x89, 0x8f, 0x0, 0xc0, 0x4f, 0xb6, 0xbf, 0xc4 } };
static PST_KEY s_Key = PST_KEY_CURRENT_USER;
static WCHAR c_szInfoDel[] = L"InfoDelivery";
static WCHAR c_szSubscriptions[] = L"Subscriptions";
//////////////////////////////////////////////////////////////////////////
//
// DLL entry point
//
//////////////////////////////////////////////////////////////////////////
EXTERN_C BOOL WINAPI DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved)
{
switch (ulReason)
{
case DLL_PROCESS_ATTACH:
{
SHFusionInitializeFromModule((HMODULE)hInstance);
OSVERSIONINFOA vi;
DisableThreadLibraryCalls(hInstance);
g_hInst = hInstance;
MLLoadResources(g_hInst, TEXT("webchklc.dll"));
vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
GetVersionExA(&vi);
if(vi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
g_fIsWinNT = TRUE;
if(vi.dwMajorVersion > 4)
g_fIsWinNT5 = TRUE;
else
g_fIsWinNT5 = FALSE;
} else {
g_fIsWinNT = FALSE;
g_fIsWinNT5 = FALSE;
g_fIsMillennium = IsOS(OS_MILLENNIUM);
}
#ifdef DEBUG
g_qwTraceFlags = TF_NEVER; // Default if not overridden from INI
CcshellGetDebugFlags();
#endif
}
break;
case DLL_PROCESS_DETACH:
{
MLFreeResources(g_hInst);
SHFusionUninitialize();
}
break;
}
return TRUE;
}
//////////////////////////////////////////////////////////////////////////
//
// Standard OLE entry points
//
//////////////////////////////////////////////////////////////////////////
// Class factory -
// For classes with no special needs these macros should take care of it.
// If your class needs some special stuff just to get the ball rolling,
// implement your own CreateInstance method. (ala, CConnectionAgent)
#define DEFINE_CREATEINSTANCE(cls, iface) \
HRESULT cls##_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk) \
{ \
ASSERT(NULL == punkOuter); \
ASSERT(NULL != ppunk); \
*ppunk = (iface *)new cls; \
return (NULL != *ppunk) ? S_OK : E_OUTOFMEMORY; \
}
#define DEFINE_AGGREGATED_CREATEINSTANCE(cls, iface) \
HRESULT cls##_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk) \
{ \
ASSERT(NULL != punkOuter); \
ASSERT(NULL != ppunk); \
*ppunk = (iface *)new cls(punkOuter); \
return (NULL != *ppunk) ? S_OK : E_OUTOFMEMORY; \
}
DEFINE_CREATEINSTANCE(CWebCheck, IOleCommandTarget)
DEFINE_CREATEINSTANCE(CWebCrawler, ISubscriptionAgentControl)
DEFINE_CREATEINSTANCE(CChannelAgent, ISubscriptionAgentControl)
DEFINE_CREATEINSTANCE(COfflineFolder, IShellFolder)
// extern HRESULT CConnectionAgent_CreateInstance(LPUNKNOWN pUnkOuter, IUnknown **ppunk);
DEFINE_CREATEINSTANCE(CSubscriptionMgr, ISubscriptionMgr2);
DEFINE_CREATEINSTANCE(CWCPostAgent, ISubscriptionAgentControl)
DEFINE_CREATEINSTANCE(CCDLAgent, ISubscriptionAgentControl)
DEFINE_CREATEINSTANCE(COfflineSync, ISyncMgrSynchronize)
const CFactoryData g_FactoryData[] =
{
{ &CLSID_WebCheck, CWebCheck_CreateInstance, 0 }
,{ &CLSID_WebCrawlerAgent, CWebCrawler_CreateInstance, 0 }
,{ &CLSID_ChannelAgent, CChannelAgent_CreateInstance, 0 }
,{ &CLSID_OfflineFolder, COfflineFolder_CreateInstance, 0 }
// ,{ &CLSID_ConnectionAgent, CConnectionAgent_CreateInstance, 0 }
,{ &CLSID_SubscriptionMgr, CSubscriptionMgr_CreateInstance, 0 }
,{ &CLSID_PostAgent, CWCPostAgent_CreateInstance, 0 }
,{ &CLSID_CDLAgent, CCDLAgent_CreateInstance, 0 }
,{ &CLSID_WebCheckOfflineSync, COfflineSync_CreateInstance, 0 }
};
HRESULT APIENTRY DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv)
{
HRESULT hr = S_OK;
IUnknown *punk = NULL;
*ppv = NULL;
// Validate request
for (int i = 0; i < ARRAYSIZE(g_FactoryData); i++)
{
if (rclsid == *g_FactoryData[i].m_pClsid)
{
punk = new CClassFactory(&g_FactoryData[i]);
break;
}
}
if (ARRAYSIZE(g_FactoryData) <= i)
{
ASSERT(NULL == punk);
hr = CLASS_E_CLASSNOTAVAILABLE;
}
else if (NULL == punk)
{
hr = E_OUTOFMEMORY;
}
else
{
hr = punk->QueryInterface(riid, ppv);
punk->Release();
}
ASSERT((SUCCEEDED(hr) && (NULL != *ppv)) ||
(FAILED(hr) && (NULL == *ppv)));
return hr;
}
STDAPI DllCanUnloadNow(void)
{
// check objects and locks
return (0L == DllGetRef() && 0L == DllGetLock()) ? S_OK : S_FALSE;
}
//////////////////////////////////////////////////////////////////////////
//
// helper functions
//
//////////////////////////////////////////////////////////////////////////
int MyOleStrToStrN(LPTSTR psz, int cchMultiByte, LPCOLESTR pwsz)
{
int i;
#ifdef UNICODE
StrCpyN(psz, pwsz, cchMultiByte);
i = cchMultiByte;
#else
i=WideCharToMultiByte(CP_ACP, 0, pwsz, -1, psz,
cchMultiByte, NULL, NULL);
if (!i)
{
DBG_WARN("MyOleStrToStrN string too long; truncated");
psz[cchMultiByte - 1]=0;
}
#ifdef DEBUG
else
ZeroMemory(psz+i, sizeof(TCHAR)*(cchMultiByte-i));
#endif
#endif
return i;
}
int MyStrToOleStrN(LPOLESTR pwsz, int cchWideChar, LPCTSTR psz)
{
int i;
#ifdef UNICODE
StrCpyN(pwsz, psz, cchWideChar);
i = cchWideChar;
#else
i=MultiByteToWideChar(CP_ACP, 0, psz, -1, pwsz, cchWideChar);
if (!i)
{
DBG_WARN("MyStrToOleStrN string too long; truncated");
pwsz[cchWideChar-1]=0;
}
#ifdef DEBUG
else
ZeroMemory(pwsz+i, sizeof(OLECHAR)*(cchWideChar-i));
#endif
#endif
return i;
}
// Convert upper to lower for ASCII wide characters
inline WCHAR MyToLower(WCHAR wch)
{
return (wch >= 'A' && wch <= 'Z') ? (wch - 'A'+ 'a') : wch;
}
// Optimized for the knowledge that urls are 7-bit characters.
int MyAsciiCmpNIW(LPCWSTR pwsz1, LPCWSTR pwsz2, int iLen)
{
while (iLen-- && *pwsz1 && *pwsz2)
{
ASSERT(*pwsz1 || *pwsz2);
if (MyToLower(*pwsz1++) != MyToLower(*pwsz2++))
return 1;
}
return 0;
}
int MyAsciiCmpW(LPCWSTR pwsz1, LPCWSTR pwsz2)
{
while (*pwsz1)
{
if (*pwsz1++ != *pwsz2++)
{
return 1;
}
}
if (*pwsz2)
return 1;
return 0;
}
#ifdef DEBUG
void DumpIID(LPCSTR psz, REFIID riid)
{
// Convert the GUID to an ANSI string
TCHAR pszGUID[GUIDSTR_MAX];
WCHAR pwszGUID[GUIDSTR_MAX];
int len = StringFromGUID2(riid, pwszGUID, ARRAYSIZE(pwszGUID));
ASSERT(GUIDSTR_MAX == len);
ASSERT(0 == pwszGUID[GUIDSTR_MAX - 1]);
len = MyOleStrToStrN(pszGUID, GUIDSTR_MAX, pwszGUID);
ASSERT(GUIDSTR_MAX == len);
ASSERT(0 == pszGUID[GUIDSTR_MAX - 1]);
// See if the IID has a string in the registry
TCHAR pszKey[MAX_PATH];
TCHAR pszIIDName[MAX_PATH];
wnsprintf(pszKey, ARRAYSIZE(pszKey), TEXT("Interface\\%s"), pszGUID);
BOOL fRet;
fRet = ReadRegValue(HKEY_CLASSES_ROOT, pszKey, NULL, pszIIDName, sizeof(pszIIDName));
// Print all the strings
if (fRet)
TraceMsg(TF_THISMODULE, "%s - %s %s", psz, pszIIDName, pszGUID);
else
TraceMsg(TF_THISMODULE, "%s - %s", psz, pszGUID);
}
#endif // DEBUG
//////////////////////////////////////////////////////////////////////////
//
// Autoregistration entry points
//
//////////////////////////////////////////////////////////////////////////
HRESULT CallRegInstall(LPSTR szSection)
{
HRESULT hr = E_FAIL;
HINSTANCE hinstAdvPack = LoadLibrary(TEXT("ADVPACK.DLL"));
if (hinstAdvPack)
{
REGINSTALL pfnri = (REGINSTALL)GetProcAddress(hinstAdvPack, achREGINSTALL);
if (pfnri)
{
hr = pfnri(g_hInst, szSection, NULL);
}
FreeLibrary(hinstAdvPack);
}
return hr;
}
STDAPI DllRegisterServer(void)
{
// Delete any old registration entries, then add the new ones.
// Keep ADVPACK.DLL loaded across multiple calls to RegInstall.
HINSTANCE hinstAdvPack = LoadLibrary(TEXT("ADVPACK.DLL"));
// CallRegInstall("UnReg");
CallRegInstall("Reg");
if (hinstAdvPack)
{
FreeLibrary(hinstAdvPack);
}
// OfflineFolder registers.
OfflineFolderRegisterServer();
// do external setup stuff on non-NT5 platforms
if(FALSE == g_fIsWinNT5)
{
// register LCE
HINSTANCE hLCE = LoadLibrary(TEXT("estier2.dll"));
if (hLCE)
{
LCEREGISTER regfunc;
regfunc = (LCEREGISTER)GetProcAddress(hLCE, "LCERegisterServer");
if (regfunc)
if (FAILED(regfunc(NULL)))
DBG_WARN("LCE register server failed!");
FreeLibrary(hLCE);
}
// create reg key that SENS needs
DWORD dwValue = 0;
WriteRegValue(HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\Mobile\\Sens"),
TEXT("Configured"), &dwValue, sizeof(DWORD), REG_DWORD);
// if we're on NT4, call SENS configuration api
if (g_fIsWinNT)
{
HINSTANCE hSENS = LoadLibrary(TEXT("senscfg.dll"));
if(hSENS)
{
SENSREGISTER regfunc;
regfunc = (SENSREGISTER)GetProcAddress(hSENS, "SensRegister");
if(regfunc)
if (FAILED(regfunc()))
DBG_WARN("SENS register server failed!");
FreeLibrary(hSENS);
}
}
}
return NOERROR;
}
STDAPI
DllUnregisterServer(void)
{
HRESULT hr;
hr = OfflineFolderUnregisterServer();
hr = CallRegInstall("UnReg");
// do external unregister stuff on non-NT5 platforms
if(FALSE == g_fIsWinNT5) {
// unregister SENS on NT4
if(g_fIsWinNT){
HINSTANCE hSENS = LoadLibrary(TEXT("senscfg.dll"));
if(hSENS) {
SENSREGISTER regfunc;
regfunc = (SENSREGISTER)GetProcAddress(hSENS, "SensUnregister");
if(regfunc)
regfunc();
FreeLibrary(hSENS);
}
}
// unregister LCE
HINSTANCE hLCE = LoadLibrary(TEXT("estier2.dll"));
if(hLCE) {
LCEUNREGISTER unregfunc;
unregfunc = (LCEUNREGISTER)GetProcAddress(hLCE, "LCEUnregisterServer");
if(unregfunc)
unregfunc(NULL);
FreeLibrary(hLCE);
}
// Remove Sens key
SHDeleteKey( HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\Mobile\\Sens") );
}
return hr;
}
STDAPI DllInstall(BOOL bInstall, LPCWSTR pszCmdLine)
{
HRESULT hr = S_OK;
typedef enum { InstallNone, InstallPolicies, InstallPerUser } InstallType;
InstallType installType = InstallNone;
if (pszCmdLine && *pszCmdLine)
{
//
// Setup will call DllInstall by running 'regsvr32 /n /i:Policy webcheck.dll'.
// This tells webcheck to process the Infodelivery Admin Policies.
//
if (0 == StrCmpIW(pszCmdLine, TEXTW("policy")))
{
installType = InstallPolicies;
}
else if (0 == StrCmpIW(pszCmdLine, TEXTW("U")))
{
installType = InstallPerUser;
}
}
if (bInstall && (installType != InstallNone))
{
hr = CoInitialize(NULL);
if (SUCCEEDED(hr))
{
switch (installType)
{
case InstallPolicies:
hr = ProcessInfodeliveryPolicies();
break;
case InstallPerUser:
hr = ConvertIE4Subscriptions();
DBGASSERT(SUCCEEDED(hr), "webcheck DllInstall - Failed to convert notification manager subscriptions");
break;
}
}
CoUninitialize();
}
return SUCCEEDED(hr) ? S_OK : hr;
}
//////////////////////////////////////////////////////////////////////////
//
// Helper functions for Subscription Store
//
//////////////////////////////////////////////////////////////////////////
// Can return S_OK with NULL bstr
HRESULT ReadBSTR(ISubscriptionItem *pItem, LPCWSTR szName, BSTR *bstrRet)
{
ASSERT(pItem && bstrRet);
VARIANT Val;
Val.vt = VT_EMPTY;
if (SUCCEEDED(pItem->ReadProperties(1, &szName, &Val)) &&
(Val.vt==VT_BSTR))
{
*bstrRet = Val.bstrVal;
return S_OK;
}
else
{
VariantClear(&Val); // free any return value of wrong type
*bstrRet = NULL;
return E_INVALIDARG;
}
}
// Cannot return S_OK with emptry string
HRESULT ReadOLESTR(ISubscriptionItem *pItem, LPCWSTR szName, LPWSTR *ppszRet)
{
HRESULT hr;
BSTR bstrRet = NULL;
*ppszRet = NULL;
hr = ReadBSTR(pItem, szName, &bstrRet);
if (SUCCEEDED(hr) && bstrRet && bstrRet[0])
{
int len = (lstrlenW(bstrRet) + 1) * sizeof(WCHAR);
*ppszRet = (LPWSTR) CoTaskMemAlloc(len);
if (*ppszRet)
{
CopyMemory(*ppszRet, bstrRet, len);
}
}
SAFEFREEBSTR(bstrRet);
if (*ppszRet)
return S_OK;
else
return E_FAIL;
}
HRESULT ReadAnsiSTR(ISubscriptionItem *pItem, LPCWSTR szName, LPSTR *ppszRet)
{
HRESULT hr;
BSTR bstrRet = NULL;
*ppszRet = NULL;
hr = ReadBSTR(pItem, szName, &bstrRet);
if (SUCCEEDED(hr) && bstrRet && bstrRet[0])
{
// Don't forget to allocate a long string for DBCS.
int len = (lstrlenW(bstrRet) + 1) * sizeof(CHAR) * 2;
*ppszRet = (LPSTR) MemAlloc(LMEM_FIXED, len);
if (*ppszRet)
{
SHUnicodeToAnsi(bstrRet, *ppszRet, len);
}
}
SAFEFREEBSTR(bstrRet);
if (*ppszRet)
return S_OK;
else
return E_FAIL;
}
HRESULT ReadBool(ISubscriptionItem *pItem, LPCWSTR szName, VARIANT_BOOL *pBoolRet)
{
ASSERT(pItem && pBoolRet);
VARIANT Val;
Val.vt = VT_EMPTY;
// accept VT_I4 or VT_BOOL
if (SUCCEEDED(pItem->ReadProperties(1, &szName, &Val)) &&
(Val.vt==VT_BOOL || Val.vt==VT_I4))
{
if (Val.vt==VT_I4)
{
if (Val.lVal)
*pBoolRet = VARIANT_TRUE;
else
*pBoolRet = VARIANT_FALSE;
}
else
*pBoolRet = Val.boolVal;
return S_OK;
}
else
{
VariantClear(&Val); // free any return value of wrong type
return E_INVALIDARG;
}
}
HRESULT ReadSCODE(ISubscriptionItem *pItem, LPCWSTR szName, SCODE *pscRet)
{
ASSERT(pItem && pscRet);
VARIANT Val;
Val.vt = VT_EMPTY;
if (SUCCEEDED(pItem->ReadProperties(1, &szName, &Val)) && Val.vt == VT_ERROR)
{
*pscRet = Val.scode;
return S_OK;
}
else
{
VariantClear(&Val);
return E_INVALIDARG;
}
}
HRESULT WriteEMPTY(ISubscriptionItem *pItem, LPCWSTR szName)
{
ASSERT(pItem);
VARIANT Val;
Val.vt = VT_EMPTY;
return pItem->WriteProperties(1, &szName, &Val);
}
HRESULT WriteSCODE(ISubscriptionItem *pItem, LPCWSTR szName, SCODE scVal)
{
ASSERT(pItem);
VARIANT Val;
Val.vt = VT_ERROR;
Val.scode = scVal;
return pItem->WriteProperties(1, &szName, &Val);
}
HRESULT ReadDWORD(ISubscriptionItem *pItem, LPCWSTR szName, DWORD *pdwRet)
{
ASSERT(pItem && pdwRet);
VARIANT Val;
Val.vt = VT_EMPTY;
if (SUCCEEDED(pItem->ReadProperties(1, &szName, &Val)) &&
(Val.vt==VT_I4 || Val.vt==VT_I2))
{
if (Val.vt==VT_I4)
*pdwRet = (DWORD) Val.lVal;
else
*pdwRet = (DWORD) Val.iVal;
return S_OK;
}
else
{
VariantClear(&Val); // free any return value of wrong type
return E_INVALIDARG;
}
}
HRESULT ReadLONGLONG(ISubscriptionItem *pItem, LPCWSTR szName, LONGLONG *pllRet)
{
ASSERT(pItem && pllRet);
VARIANT Val;
Val.vt = VT_EMPTY;
if (SUCCEEDED(pItem->ReadProperties(1, &szName, &Val)) &&
(Val.vt==VT_CY))
{
*pllRet = *((LONGLONG *) &(Val.cyVal));
return S_OK;
}
else
{
*pllRet = 0;
VariantClear(&Val); // free any return value of wrong type
return E_INVALIDARG;
}
}
HRESULT ReadGUID(ISubscriptionItem *pItem, LPCWSTR szName, GUID *pGuid)
{
ASSERT(pItem && pGuid);
BSTR bstrGUID = NULL;
HRESULT hr = E_INVALIDARG;
if (SUCCEEDED(ReadBSTR(pItem, szName, &bstrGUID)) &&
SUCCEEDED(CLSIDFromString(bstrGUID, pGuid)))
{
hr = NOERROR;
}
SAFEFREEBSTR(bstrGUID);
return hr;
}
HRESULT WriteGUID(ISubscriptionItem *pItem, LPCWSTR szName, GUID *pGuid)
{
ASSERT(pItem && pGuid);
WCHAR wszCookie[GUIDSTR_MAX];
#ifdef DEBUG
int len =
#endif
StringFromGUID2(*pGuid, wszCookie, ARRAYSIZE(wszCookie));
ASSERT(GUIDSTR_MAX == len);
return WriteOLESTR(pItem, szName, wszCookie);
}
HRESULT WriteLONGLONG(ISubscriptionItem *pItem, LPCWSTR szName, LONGLONG llVal)
{
VARIANT Val;
Val.vt = VT_CY;
Val.cyVal = *((CY *) &llVal);
return pItem->WriteProperties(1, &szName, &Val);
}
HRESULT WriteDWORD(ISubscriptionItem *pItem, LPCWSTR szName, DWORD dwVal)
{
VARIANT Val;
Val.vt = VT_I4;
Val.lVal = dwVal;
return pItem->WriteProperties(1, &szName, &Val);
}
HRESULT ReadDATE(ISubscriptionItem *pItem, LPCWSTR szName, DATE *dtVal)
{
ASSERT(pItem && dtVal);
VARIANT Val;
Val.vt = VT_EMPTY;
if (SUCCEEDED(pItem->ReadProperties(1, &szName, &Val)) && (Val.vt==VT_DATE))
{
*dtVal = Val.date;
return S_OK;
}
else
{
VariantClear(&Val); // free any return value of wrong type
return E_INVALIDARG;
}
}
HRESULT WriteDATE(ISubscriptionItem *pItem, LPCWSTR szName, DATE *dtVal)
{
VARIANT Val;
Val.vt = VT_DATE;
Val.date= *dtVal;
return pItem->WriteProperties(1, &szName, &Val);
}
HRESULT ReadVariant (ISubscriptionItem *pItem, LPCWSTR szName, VARIANT *pvarRet)
{
ASSERT(pvarRet->vt == VT_EMPTY);
return pItem->ReadProperties(1, &szName, pvarRet);
}
HRESULT WriteVariant (ISubscriptionItem *pItem, LPCWSTR szName, VARIANT *pvarVal)
{
return pItem->WriteProperties(1, &szName, pvarVal);
}
HRESULT WriteOLESTR(ISubscriptionItem *pItem, LPCWSTR szName, LPCWSTR szVal)
{
VARIANT Val;
Val.vt = VT_BSTR;
Val.bstrVal = SysAllocString(szVal);
HRESULT hr = pItem->WriteProperties(1, &szName, &Val);
SysFreeString(Val.bstrVal);
return hr;
}
HRESULT WriteAnsiSTR(ISubscriptionItem *pItem, LPCWSTR szName, LPCSTR szVal)
{
VARIANT Val;
BSTR bstrVal;
HRESULT hr;
bstrVal = SysAllocStringByteLen(szVal, lstrlenA(szVal));
if (bstrVal)
{
Val.vt = VT_BSTR;
Val.bstrVal = bstrVal;
hr = pItem->WriteProperties(1, &szName, &Val);
SysFreeString(bstrVal);
}
else
{
hr = E_OUTOFMEMORY;
}
return hr;
}
HRESULT WriteResSTR(ISubscriptionItem *pItem, LPCWSTR szName, UINT uID)
{
TCHAR szString[MAX_RES_STRING_LEN];
if (MLLoadString(uID, szString, ARRAYSIZE(szString)))
{
return WriteTSTR(pItem, szName, szString);
}
return E_INVALIDARG;
}
DWORD LogEvent(LPTSTR pszFormat, ...)
{
// check registry if necessary
if(FALSE == g_fCheckedForLog) {
TCHAR pszFilePath[MAX_PATH];
if(ReadRegValue(HKEY_CURRENT_USER, c_szRegKey, TEXT("LoggingFile"),
pszFilePath, sizeof(pszFilePath))) {
g_pszLoggingFile = new TCHAR[lstrlen(pszFilePath) + 1];
if(g_pszLoggingFile) {
StrCpy(g_pszLoggingFile, pszFilePath);
}
}
g_fCheckedForLog = TRUE;
}
if(g_pszLoggingFile) {
TCHAR pszString[MAX_PATH+INTERNET_MAX_URL_LENGTH];
SYSTEMTIME st;
HANDLE hLog;
DWORD dwWritten;
va_list va;
hLog = CreateFile(g_pszLoggingFile, GENERIC_WRITE, 0, NULL,
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if(INVALID_HANDLE_VALUE == hLog)
return GetLastError();
// seek to end of file
SetFilePointer(hLog, 0, 0, FILE_END);
// dump time
GetLocalTime(&st);
wnsprintf(pszString, ARRAYSIZE(pszString), TEXT("\r\n%02d:%02d:%02d - "), st.wHour, st.wMinute, st.wSecond);
WriteFile(hLog, pszString, lstrlen(pszString), &dwWritten, NULL);
// dump passed in string
va_start(va, pszFormat);
wvnsprintf(pszString, ARRAYSIZE(pszString), pszFormat, va);
va_end(va);
WriteFile(hLog, pszString, lstrlen(pszString), &dwWritten, NULL);
// clean up
CloseHandle(hLog);
}
return 0;
}
// Functions related to saving and restoring user passwords from the pstore.
// We have wrappers around Create and Release to allow for future caching of the pstore
// instance within webcheck.
STDAPI CreatePStore(IPStore **ppIPStore)
{
HRESULT hr;
hr = PStoreCreateInstance ( ppIPStore,
IsEqualGUID(s_provID, GUID_NULL) ? NULL : &s_provID,
NULL,
0);
return hr;
}
STDAPI ReleasePStore(IPStore *pIPStore)
{
HRESULT hr;
if (pIPStore)
{
pIPStore->Release();
hr = S_OK;
}
else
{
hr = E_POINTER;
}
return hr;
}
// Given a field name this figures out the type and sub-type in the pstore
// that should be queried. Currently these are hard-coded.
STDAPI GetPStoreTypes(LPCWSTR /* wszField */, GUID * pguidType, GUID * pguidSubType)
{
*pguidType = GUID_PStoreType;
*pguidSubType = GUID_NULL;
return S_OK;
}
STDAPI ReadNotificationPassword(LPCWSTR wszUrl, BSTR *pbstrPassword)
{
GUID itemType = GUID_NULL;
GUID itemSubtype = GUID_NULL;
PST_PROMPTINFO promptInfo = {0};
IPStore* pStore = NULL;
HRESULT hr ;
if (wszUrl == NULL || pbstrPassword == NULL)
return E_POINTER;
// Will return NULL if there is no password entry or we
// fail for some reason.
*pbstrPassword = NULL;
promptInfo.cbSize = sizeof(promptInfo);
promptInfo.szPrompt = NULL;
promptInfo.dwPromptFlags = 0;
promptInfo.hwndApp = NULL;
hr = CreatePStore(&pStore);
if (SUCCEEDED(hr))
{
ASSERT(pStore != NULL);
hr = GetPStoreTypes(wszUrl, &itemType, &itemSubtype);
if (SUCCEEDED(hr))
{
DWORD cbData;
BYTE * pbData = NULL;
hr = pStore->ReadItem(
s_Key,
&itemType,
&itemSubtype,
wszUrl,
&cbData,
&pbData,
&promptInfo,
0);
if (SUCCEEDED(hr))
{
*pbstrPassword = SysAllocString((OLECHAR *)pbData);
CoTaskMemFree(pbData);
hr = S_OK;
}
}
ReleasePStore(pStore);
}
return hr;
}
STDAPI WriteNotificationPassword(LPCWSTR wszUrl, BSTR bstrPassword)
{
HRESULT hr;
PST_TYPEINFO typeInfo;
PST_PROMPTINFO promptInfo;
IPStore * pStore;
if (wszUrl == NULL)
return E_POINTER;
typeInfo.cbSize = sizeof(typeInfo);
typeInfo.szDisplayName = c_szInfoDel;
promptInfo.cbSize = sizeof(promptInfo);
promptInfo.dwPromptFlags = 0;
promptInfo.hwndApp = NULL;
promptInfo.szPrompt = NULL;
hr = CreatePStore(&pStore);
if (SUCCEEDED(hr))
{
GUID itemType = GUID_NULL;
GUID itemSubtype = GUID_NULL;
ASSERT(pStore != NULL);
hr = GetPStoreTypes(wszUrl, &itemType, &itemSubtype);
if (SUCCEEDED(hr))
{
hr = pStore->CreateType(s_Key, &itemType, &typeInfo, 0);
// PST_E_TYPE_EXISTS implies type already exists which is just fine
// by us.
if (SUCCEEDED(hr) || hr == PST_E_TYPE_EXISTS)
{
typeInfo.szDisplayName = c_szSubscriptions;
hr = pStore->CreateSubtype(
s_Key,
&itemType,
&itemSubtype,
&typeInfo,
NULL,
0);
if (SUCCEEDED(hr) || hr == PST_E_TYPE_EXISTS)
{
if (bstrPassword != NULL)
{
hr = pStore->WriteItem(
s_Key,
&itemType,
&itemSubtype,
wszUrl,
((lstrlenW(bstrPassword)+1) * sizeof(WCHAR)),
(BYTE *)bstrPassword,
&promptInfo,
PST_CF_NONE,
0);
}
else
{
hr = pStore->DeleteItem(
s_Key,
&itemType,
&itemSubtype,
wszUrl,
&promptInfo,
0);
}
}
}
}
ReleasePStore(pStore);
}
return hr;
}
HRESULT WritePassword(ISubscriptionItem *pItem, BSTR bstrPassword)
{
BSTR bstrURL = NULL;
HRESULT hr = E_FAIL;
hr = ReadBSTR(pItem, c_szPropURL, &bstrURL);
RETURN_ON_FAILURE(hr);
hr = WriteNotificationPassword(bstrURL, bstrPassword);
SAFEFREEBSTR(bstrURL);
return hr;
}
HRESULT ReadPassword(ISubscriptionItem *pItem, BSTR * pBstrPassword)
{
BSTR bstrURL = NULL;
HRESULT hr = E_FAIL;
hr = ReadBSTR(pItem, c_szPropURL, &bstrURL);
RETURN_ON_FAILURE(hr);
ASSERT(pBstrPassword);
hr = ReadNotificationPassword(bstrURL, pBstrPassword);
SAFEFREEBSTR(bstrURL);
return hr;
}