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.
530 lines
15 KiB
530 lines
15 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1998 - 1999
|
|
//
|
|
// File: listvw.cpp
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include "pch.cpp"
|
|
#pragma hdrstop
|
|
|
|
#include <commctrl.h>
|
|
#include <assert.h>
|
|
|
|
#include "celib.h"
|
|
#include "listvw.h"
|
|
|
|
extern HINSTANCE g_hInstance;
|
|
|
|
typedef struct _DISPLAYSTRING_EXPANSION
|
|
{
|
|
LPCWSTR szContractedToken;
|
|
LPCWSTR szExpansionString;
|
|
} DISPLAYSTRING_EXPANSION, *PDISPLAYSTRING_EXPANSION;
|
|
|
|
DISPLAYSTRING_EXPANSION displayStrings[] =
|
|
{
|
|
{ wszFCSAPARM_SERVERDNSNAME, L"%SERVER_DNS_NAME%"},
|
|
{ wszFCSAPARM_SERVERSHORTNAME, L"%SERVER_SHORT_NAME%"},
|
|
{ wszFCSAPARM_SANITIZEDCANAME, L"%CA_NAME%"},
|
|
{ wszFCSAPARM_CERTFILENAMESUFFIX, L"%CERT_SUFFIX%"},
|
|
{ wszFCSAPARM_DOMAINDN, L"%DOMAIN_NAME%"},
|
|
{ wszFCSAPARM_CONFIGDN, L"%CONFIG_NAME%"},
|
|
{ wszFCSAPARM_SANITIZEDCANAMEHASH, L"%CA_NAME_HASH%"},
|
|
{ wszFCSAPARM_CRLFILENAMESUFFIX, L"%CRL_SUFFIX%"},
|
|
};
|
|
|
|
DISPLAYSTRING_EXPANSION escapedStrings[] =
|
|
{
|
|
{ L"%9", L"%%"},
|
|
};
|
|
|
|
|
|
|
|
|
|
HRESULT ValidateTokens(
|
|
IN OUT LPWSTR szURL,
|
|
OUT DWORD* pchBadBegin,
|
|
OUT DWORD* pchBadEnd)
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
int i;
|
|
LPWSTR pszMatch;
|
|
LPWSTR pszFound = szURL;
|
|
|
|
WCHAR rgszToken[MAX_PATH];
|
|
|
|
*pchBadBegin = -1;
|
|
*pchBadEnd = -1;
|
|
|
|
// look for escape token open marker
|
|
while(NULL != (pszFound = wcschr(pszFound, L'%')))
|
|
{
|
|
pszMatch = wcschr(&pszFound[1], L'%'); // look for closing marker
|
|
if (pszMatch == NULL)
|
|
goto Ret;
|
|
|
|
DWORD dwChars = SAFE_SUBTRACT_POINTERS(pszMatch, pszFound) +1; // dwChars is chars including markers
|
|
if (dwChars == 2)
|
|
goto NextMatch; // %% is valid escape sequence
|
|
|
|
if (dwChars > MAX_PATH)
|
|
goto Ret; // invalid escape token!
|
|
|
|
// isolate the token
|
|
CopyMemory(rgszToken, pszFound, dwChars * sizeof(WCHAR));
|
|
rgszToken[dwChars] = L'\0';
|
|
|
|
for (i=0; i<ARRAYSIZE(displayStrings); i++)
|
|
{
|
|
if (0 == _wcsicmp(rgszToken, displayStrings[i].szExpansionString))
|
|
{
|
|
// copy from displayStrings -- these are guaranteed to be properly uppercased
|
|
CopyMemory(pszFound, displayStrings[i].szExpansionString, dwChars * sizeof(WCHAR));
|
|
goto NextMatch;
|
|
}
|
|
}
|
|
|
|
// if we get here, we found no match
|
|
goto Ret;
|
|
|
|
NextMatch:
|
|
pszFound = ++pszMatch;
|
|
}
|
|
|
|
hr = S_OK;
|
|
Ret:
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
*pchBadBegin = SAFE_SUBTRACT_POINTERS(pszFound, szURL); // offset to first incorrect %
|
|
|
|
if (pszMatch)
|
|
*pchBadEnd = SAFE_SUBTRACT_POINTERS(pszMatch, szURL) + 1; // offset past final incorrect %
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
ExpandDisplayString(
|
|
IN LPCWSTR szContractedString,
|
|
OUT LPWSTR* ppszDisplayString)
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwChars;
|
|
int i, iescapedStrings;
|
|
LPWSTR pszTempContracted = NULL;
|
|
LPWSTR pszFound;
|
|
|
|
// account for %% escaping in contracted string --
|
|
// replace "%%" with %9, let FormatString expand to "%%"
|
|
pszTempContracted = (LPWSTR)LocalAlloc(LMEM_FIXED, (wcslen(szContractedString)+1)*sizeof(WCHAR));
|
|
if (pszTempContracted == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Ret;
|
|
}
|
|
wcscpy(pszTempContracted, szContractedString);
|
|
|
|
pszFound = wcsstr(pszTempContracted, L"%%");
|
|
while(pszFound)
|
|
{
|
|
CopyMemory(pszFound, escapedStrings[0].szContractedToken, wcslen(escapedStrings[0].szContractedToken)*sizeof(WCHAR));
|
|
pszFound = wcsstr(pszFound, L"%%");
|
|
}
|
|
|
|
|
|
LPCWSTR args[ARRAYSIZE(displayStrings)+ARRAYSIZE(escapedStrings)];
|
|
for (i=0; i<ARRAYSIZE(displayStrings); i++)
|
|
{
|
|
args[i] = displayStrings[i].szExpansionString;
|
|
}
|
|
// and tell FormatString to expand %9 to %%
|
|
for (iescapedStrings=0; iescapedStrings<ARRAYSIZE(escapedStrings); iescapedStrings++)
|
|
{
|
|
args[i+iescapedStrings] = escapedStrings[iescapedStrings].szExpansionString;
|
|
}
|
|
|
|
|
|
dwChars = FormatMessage(
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_FROM_STRING,
|
|
pszTempContracted,
|
|
0, //msgid
|
|
0, //langid
|
|
(LPWSTR)ppszDisplayString,
|
|
1, // minimum chars to alloc
|
|
(va_list *)args);
|
|
|
|
if (dwChars == 0)
|
|
{
|
|
hr = GetLastError();
|
|
hr = HRESULT_FROM_WIN32(hr);
|
|
goto Ret;
|
|
}
|
|
|
|
hr = S_OK;
|
|
Ret:
|
|
if (pszTempContracted)
|
|
LocalFree(pszTempContracted);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
ContractDisplayString(
|
|
IN LPCWSTR szDisplayString,
|
|
OUT LPWSTR* ppContractedString)
|
|
{
|
|
HRESULT hr;
|
|
int i;
|
|
|
|
*ppContractedString = (LPWSTR)LocalAlloc(LMEM_FIXED, (wcslen(szDisplayString)+1) * sizeof(WCHAR));
|
|
if (*ppContractedString == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Ret;
|
|
}
|
|
|
|
wcscpy(*ppContractedString, szDisplayString);
|
|
|
|
for (i=0; i<ARRAYSIZE(displayStrings); i++)
|
|
{
|
|
DWORD chContractedToken, chExpansionString;
|
|
|
|
LPWSTR pszFound = wcsstr(*ppContractedString, displayStrings[i].szExpansionString);
|
|
while(pszFound)
|
|
{
|
|
// calc commonly used values
|
|
chContractedToken = wcslen(displayStrings[i].szContractedToken);
|
|
chExpansionString = wcslen(displayStrings[i].szExpansionString);
|
|
|
|
// replace with token
|
|
CopyMemory(pszFound, displayStrings[i].szContractedToken, chContractedToken*sizeof(WCHAR));
|
|
|
|
// slide rest of string left
|
|
MoveMemory(
|
|
&pszFound[chContractedToken], // destination
|
|
&pszFound[chExpansionString], // source
|
|
(wcslen(&pszFound[chExpansionString])+1) *sizeof(WCHAR) );
|
|
|
|
// step Found over insertion
|
|
pszFound += chContractedToken;
|
|
|
|
// find any other ocurrences after this one
|
|
pszFound = wcsstr(pszFound, displayStrings[i].szExpansionString);
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
Ret:
|
|
return hr;
|
|
}
|
|
|
|
void AddStringToCheckList(
|
|
HWND hWndListView,
|
|
LPCWSTR szText,
|
|
LPVOID pvData,
|
|
BOOL fCheck)
|
|
{
|
|
LVITEMW lvI;
|
|
ZeroMemory(&lvI, sizeof(lvI));
|
|
|
|
//
|
|
// set up the fields in the list view item struct that don't change from item to item
|
|
//
|
|
lvI.mask = LVIF_TEXT | LVIF_PARAM;
|
|
lvI.pszText = (LPWSTR)szText;
|
|
lvI.iSubItem = 0;
|
|
lvI.lParam = (LPARAM)pvData;
|
|
lvI.iItem = ListView_GetItemCount(hWndListView);
|
|
lvI.cchTextMax = wcslen(szText);
|
|
|
|
ListView_InsertItem(hWndListView, &lvI);
|
|
ListView_SetCheckState(hWndListView, lvI.iItem, fCheck);
|
|
|
|
ListView_SetColumnWidth(hWndListView, 0, LVSCW_AUTOSIZE);
|
|
}
|
|
|
|
DWORD DetermineURLType(PCERTSVR_URL_PARSING prgURLParsing, int cURLParsingEntries, LPCWSTR szCandidateURL)
|
|
{
|
|
int iURLTypeMatch;
|
|
|
|
// determine URL type
|
|
WCHAR rgsz[6]; // "http:\0" , etc
|
|
lstrcpyn(rgsz, szCandidateURL, 6);
|
|
WCHAR* pch = wcschr(rgsz, L':'); // find ':'
|
|
if (NULL == pch)
|
|
return -1; // invalid item
|
|
pch[1] = '\0'; // whack the elt after :
|
|
|
|
// find the prefix in our list of known protocols
|
|
for (iURLTypeMatch=0; iURLTypeMatch<cURLParsingEntries; iURLTypeMatch++)
|
|
{
|
|
if (0 == _wcsicmp(rgsz, prgURLParsing[iURLTypeMatch].szKnownPrefix))
|
|
break;
|
|
}
|
|
if (iURLTypeMatch == cURLParsingEntries) // no match
|
|
return -1;
|
|
|
|
return iURLTypeMatch;
|
|
}
|
|
|
|
|
|
HRESULT WriteChanges(HWND hListView, HKEY hkeyStorage, PCERTSVR_URL_PARSING prgURLParsing, DWORD cURLParsingEntries)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
// empty item to dump to
|
|
LV_ITEM lvI;
|
|
ZeroMemory(&lvI, sizeof(lvI));
|
|
lvI.mask = LVIF_TEXT;
|
|
WCHAR szText[MAX_PATH+1];
|
|
lvI.pszText = szText;
|
|
lvI.cchTextMax = MAX_PATH;
|
|
|
|
LPWSTR pszContracted = NULL;
|
|
|
|
int iURLArrayLen = cURLParsingEntries;
|
|
int iURLTypeMatch;
|
|
|
|
DWORD* rgchszzEntries = NULL;
|
|
LPWSTR* rgszzEntries = NULL;
|
|
|
|
// entries will be sorted into one of the following
|
|
rgchszzEntries = (DWORD*)LocalAlloc(LMEM_FIXED|LMEM_ZEROINIT, sizeof(DWORD) * cURLParsingEntries);
|
|
if (NULL == rgchszzEntries)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Ret;
|
|
}
|
|
|
|
rgszzEntries = (LPWSTR*)LocalAlloc(LMEM_FIXED|LMEM_ZEROINIT, sizeof(LPWSTR) * cURLParsingEntries);
|
|
if (NULL == rgszzEntries)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Ret;
|
|
}
|
|
|
|
// enumerate through all the items and add to the arrays
|
|
for (lvI.iItem=0; ; lvI.iItem++)
|
|
{
|
|
BOOL fCheck = TRUE;
|
|
LPWSTR pszTmp;
|
|
|
|
// go until we hit end-of-list
|
|
if (!ListView_GetItem(hListView, &lvI))
|
|
break;
|
|
|
|
// determine URL type
|
|
iURLTypeMatch = DetermineURLType(prgURLParsing, iURLArrayLen, lvI.pszText);
|
|
if (iURLTypeMatch == -1) // no match
|
|
continue;
|
|
|
|
hr = ContractDisplayString(
|
|
lvI.pszText,
|
|
&pszContracted);
|
|
|
|
// determine check state
|
|
if (!ListView_GetCheckState(hListView, lvI.iItem))
|
|
{
|
|
// item not checked! add '-'
|
|
fCheck = FALSE;
|
|
}
|
|
|
|
// alloc enough to hold existing, plus new [-]"string\0", plus \0 we'll tack on end of string
|
|
DWORD dwAllocBytes = ((rgchszzEntries[iURLTypeMatch] + wcslen(pszContracted) + 2) * sizeof(WCHAR)) + (fCheck ? 0 : sizeof(WCHAR));
|
|
|
|
if (NULL == rgszzEntries[iURLTypeMatch])
|
|
{
|
|
pszTmp = (LPWSTR)LocalAlloc(LMEM_FIXED, dwAllocBytes);
|
|
}
|
|
else
|
|
{
|
|
pszTmp = (LPWSTR)LocalReAlloc(
|
|
rgszzEntries[iURLTypeMatch],
|
|
dwAllocBytes,
|
|
LMEM_MOVEABLE);
|
|
}
|
|
if (NULL == pszTmp)
|
|
{
|
|
// leave ppszzEntries as valid as it already is, try to recover
|
|
break;
|
|
}
|
|
|
|
rgszzEntries[iURLTypeMatch] = pszTmp; // assign new mem to rgszz; meanwhile, pszTmp is shorthand
|
|
DWORD chTmp = rgchszzEntries[iURLTypeMatch]; // temp assign
|
|
|
|
if (!fCheck)
|
|
{
|
|
pszTmp[chTmp++] = L'-'; // item not checked
|
|
}
|
|
wcscpy(&pszTmp[chTmp], pszContracted);
|
|
chTmp += wcslen(pszContracted)+1; // skip string\0
|
|
pszTmp[chTmp] = L'\0'; // double NULL, don't count in rgchszzEntries
|
|
|
|
// reassign chTmp to rgchszzEntries[iURLTypeMatch]
|
|
rgchszzEntries[iURLTypeMatch] = chTmp;
|
|
|
|
// clean up
|
|
if (pszContracted)
|
|
LocalFree(pszContracted);
|
|
pszContracted = NULL;
|
|
|
|
// next listbox entry!
|
|
}
|
|
|
|
// done, now commit all URL types to registry
|
|
for (iURLTypeMatch=0; iURLTypeMatch<iURLArrayLen; iURLTypeMatch++)
|
|
{
|
|
hr = RegSetValueEx(
|
|
hkeyStorage,
|
|
prgURLParsing[iURLTypeMatch].szRegEntries,
|
|
0,
|
|
REG_MULTI_SZ,
|
|
(BYTE *) (NULL == rgszzEntries[iURLTypeMatch]?
|
|
L"\0\0" : rgszzEntries[iURLTypeMatch]),
|
|
(NULL == rgszzEntries[iURLTypeMatch]?
|
|
2 : rgchszzEntries[iURLTypeMatch] + 1) *
|
|
sizeof(WCHAR)); // now add 2nd '\0'
|
|
|
|
// Zero
|
|
if (rgszzEntries[iURLTypeMatch])
|
|
{
|
|
LocalFree(rgszzEntries[iURLTypeMatch]);
|
|
rgszzEntries[iURLTypeMatch] = NULL;
|
|
rgchszzEntries[iURLTypeMatch] = 0;
|
|
}
|
|
|
|
if (hr != ERROR_SUCCESS)
|
|
{
|
|
//ASSERT(!"RegSetValueEx error!");
|
|
continue;
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
Ret:
|
|
if (rgchszzEntries)
|
|
LocalFree(rgchszzEntries);
|
|
|
|
if (rgszzEntries)
|
|
LocalFree(rgszzEntries);
|
|
|
|
if (pszContracted)
|
|
LocalFree(pszContracted);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT PopulateListView(
|
|
HWND hListView,
|
|
HKEY hkeyStorage,
|
|
PCERTSVR_URL_PARSING prgURLParsing,
|
|
DWORD cURLParsingEntries,
|
|
DWORD dwEnableFlags)
|
|
{
|
|
HRESULT hr;
|
|
LPWSTR pwszzMultiString = NULL, psz;
|
|
for (DWORD i=0; i<cURLParsingEntries; i++)
|
|
{
|
|
DWORD cb=0, dwType;
|
|
hr = RegQueryValueEx(
|
|
hkeyStorage,
|
|
prgURLParsing[i].szRegEntries,
|
|
0,
|
|
&dwType,
|
|
NULL,
|
|
&cb);
|
|
if ((hr != ERROR_SUCCESS) || (dwType != REG_MULTI_SZ) || (cb == 0))
|
|
continue;
|
|
pwszzMultiString = (LPWSTR)LocalAlloc(LMEM_FIXED, cb);
|
|
if (NULL == pwszzMultiString)
|
|
continue;
|
|
hr = RegQueryValueEx(
|
|
hkeyStorage,
|
|
prgURLParsing[i].szRegEntries,
|
|
0,
|
|
&dwType,
|
|
(PBYTE)pwszzMultiString,
|
|
&cb);
|
|
if ((HRESULT) ERROR_SUCCESS != hr)
|
|
{
|
|
if (pwszzMultiString)
|
|
LocalFree(pwszzMultiString);
|
|
pwszzMultiString = NULL;
|
|
|
|
continue;
|
|
}
|
|
|
|
// walk pwszzMultiString components
|
|
for (psz = pwszzMultiString; (psz) && (psz[0] != '\0'); psz += wcslen(psz)+1)
|
|
{
|
|
BOOL fCheck = TRUE;
|
|
LPWSTR szDisplayString;
|
|
|
|
// if string starts with -, this is unchecked
|
|
if (psz[0] == L'-')
|
|
{
|
|
fCheck = FALSE;
|
|
psz++; // step past this char
|
|
}
|
|
|
|
// enable flags -- override
|
|
if (prgURLParsing[i].dwEnableFlag != (dwEnableFlags & prgURLParsing[i].dwEnableFlag))
|
|
fCheck = FALSE;
|
|
|
|
hr = ExpandDisplayString(
|
|
psz,
|
|
&szDisplayString);
|
|
if (hr != S_OK)
|
|
continue;
|
|
|
|
// add this sz
|
|
AddStringToCheckList(
|
|
hListView,
|
|
szDisplayString, //psz,
|
|
NULL,
|
|
fCheck);
|
|
|
|
LocalFree(szDisplayString);
|
|
}
|
|
|
|
if (pwszzMultiString)
|
|
{
|
|
LocalFree(pwszzMultiString);
|
|
pwszzMultiString = NULL;
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
//Ret:
|
|
return hr;
|
|
}
|
|
|
|
BOOL OnDialogHelp(LPHELPINFO pHelpInfo, LPCTSTR szHelpFile, const DWORD rgzHelpIDs[])
|
|
{
|
|
if (rgzHelpIDs == NULL || szHelpFile == NULL)
|
|
return TRUE;
|
|
|
|
if (pHelpInfo != NULL && pHelpInfo->iContextType == HELPINFO_WINDOW)
|
|
{
|
|
// Display context help for a control
|
|
WinHelp((HWND)pHelpInfo->hItemHandle, szHelpFile,
|
|
HELP_WM_HELP, (ULONG_PTR)(LPVOID)rgzHelpIDs);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL OnDialogContextHelp(HWND hWnd, LPCTSTR szHelpFile, const DWORD rgzHelpIDs[])
|
|
{
|
|
if (rgzHelpIDs == NULL || szHelpFile == NULL)
|
|
return TRUE;
|
|
assert(IsWindow(hWnd));
|
|
WinHelp(hWnd, szHelpFile, HELP_CONTEXTMENU, (ULONG_PTR)(LPVOID)rgzHelpIDs);
|
|
return TRUE;
|
|
}
|