Leaked source code of windows server 2003
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.
 
 
 
 
 
 

609 lines
13 KiB

// WebChangelistEditor.cpp : Implementation of CWebChangelistEditor
#include "stdafx.h"
#include "WebChangelistEditor.h"
#include <fcntl.h>
// CWebChangelistEditor
STDMETHODIMP CWebChangelistEditor::Initialize(BSTR ChangelistKey, BOOL* Result)
{
HKEY hKey = NULL;
DWORD cbData = MAX_PATH * sizeof(WCHAR);
DWORD dwDatatype;
// Initialize the Result return value to FALSE:
if (Result == NULL)
return E_POINTER;
*Result = FALSE;
// Put our Key/Value name into a CComBSTR
m_ChangelistKey = ChangelistKey;
// Make sure we can't be initialized twice:
if (m_fInitialized)
return E_FAIL;
// Sanity check the ChangelistKey argument.
// It must be 40 characters, null-terminated, containing only hex digits.
if (m_ChangelistKey.Length() != 40)
goto Done;
if (m_ChangelistKey[40] != L'\0')
goto Done;
if (wcsspn(m_ChangelistKey, L"ABCDEFabcdef1234567890") != 40)
goto Done;
// Open our Key:
if (RegOpenKeyExW(HKEY_CURRENT_USER,
g_wszRegKey,
0,
KEY_QUERY_VALUE,
&hKey) != ERROR_SUCCESS)
{
hKey = NULL;
goto Done;
}
// Read the specified subkey:
if ((RegQueryValueExW(hKey,
m_ChangelistKey,
0,
&dwDatatype,
(LPBYTE)m_wszCLFilename,
&cbData) != ERROR_SUCCESS) ||
(dwDatatype != REG_SZ))
{
goto Done;
}
// Now that we have the filename and key read successfully
// we can parse the file and populate all the properties of this object.
*Result = m_fInitialized = _ReadFile();
Done:
if (hKey != NULL)
RegCloseKey(hKey);
if (!m_fInitialized)
{
// If we failed, clean up nicely.
_WipeRegEntries();
}
return S_OK;
}
STDMETHODIMP CWebChangelistEditor::Save()
{
FILE *CLFile = NULL;
IFilesAndActions *pIFiles = NULL;
IFileAndAction *pIFile = NULL;
long count;
VARIANT varTemp;
CComBSTR bstrFilename;
CComBSTR bstrAction;
BOOL fEnabled;
HKEY hKey;
// Save can't be called unless we've been properly initialized
if (!m_fInitialized)
return E_FAIL;
// Open the file write-only.
// This clears the file contents.
CLFile = _wfopen(m_wszCLFilename, L"wt");
if (CLFile == NULL)
goto Done;
// Print a much shortened comment block:
fwprintf(CLFile, L"# Source Depot Changelist.\n");
// Print the simple stuff
fwprintf(CLFile, L"\nChange:\t%s\n", m_Change);
if (_wcsicmp(m_Status, L"new") != 0)
{
// Only print the Date line if Status != "new"
fwprintf(CLFile, L"\nDate:\t%s\n", m_Date);
}
fwprintf(CLFile, L"\nClient:\t%s\n", m_Client);
fwprintf(CLFile, L"\nUser:\t%s\n", m_User);
fwprintf(CLFile, L"\nStatus:\t%s\n", m_Status);
fwprintf(CLFile, L"\nDescription:\n");
fwprintf(CLFile, L"\t%s\n", m_Description);
fwprintf(CLFile, L"\nFiles:\n");
// Get the FilesAndActions interface
if (FAILED(m_Files->QueryInterface<IFilesAndActions>(&pIFiles)))
goto Done; // This shouldn't ever fail.
varTemp.vt = VT_EMPTY;
// Loop over the entries and remove each entry as we print it
while (SUCCEEDED(pIFiles->get_Count(&count)) &&
(count >= 1))
{
if (SUCCEEDED(pIFiles->get_Item(1, &varTemp)) && // Get item
(varTemp.vt == VT_DISPATCH) && // Check Variant type
(pIFile = (IFileAndAction*)varTemp.pdispVal) && // <-- Yes, this is an assignment
SUCCEEDED(pIFile->get_Filename(&bstrFilename)) &&
SUCCEEDED(pIFile->get_Action(&bstrAction)) &&
SUCCEEDED(pIFile->get_Enabled(&fEnabled)))
{
// If it's enabled, print the complete line.
if (fEnabled)
fwprintf(CLFile, L"\t%s\t# %s\n", bstrFilename, bstrAction);
// Clean up for the next pass
//pIFile->Release();
pIFile = NULL;
VariantClear(&varTemp);
pIFiles->Remove(1);
}
else
break; // This should not happen.
} // End of while loop
Done:
// OK, we're closing. Un-Initialize the thing.
m_fInitialized = FALSE;
// Close the file
if (CLFile)
fclose(CLFile);
// Release the FilesAndActions interface
if (pIFiles)
pIFiles->Release();
// Delete the registry value we used.
// This may trigger the waiting executable to continue, so do
// this _after_ saving and closing the file.
if (RegOpenKeyExW(HKEY_CURRENT_USER,
g_wszRegKey,
0,
KEY_QUERY_VALUE | KEY_SET_VALUE,
&hKey) == ERROR_SUCCESS)
{
RegDeleteValueW(hKey, m_ChangelistKey);
RegCloseKey(hKey);
}
return S_OK;
}
BOOL CWebChangelistEditor::_ReadFile(void)
{
BOOL fRetVal = FALSE;
FILE *CLFile = NULL;
IFilesAndActions *pIFiles = NULL;
WCHAR wszBuffer[500];
WCHAR wszBuffer2[500];
WCHAR wszBuffer3[50];
long count;
DWORD dwState = 0; // State of parsing engine
// Ensure that we don't have any old Files entries
if (FAILED(m_Files->QueryInterface<IFilesAndActions>(&pIFiles)))
return FALSE;
if (FAILED(pIFiles->get_Count(&count)))
goto Done;
if (count != 0)
goto Done;
// Open the file read-only
CLFile = _wfopen(m_wszCLFilename, L"rt");
if (CLFile == NULL)
goto Done;
while (fwscanf(CLFile, L"%499[^\n]%*[\n]", &wszBuffer) == 1)
{
// Expect a comment block at the top of the file
switch (dwState)
{
case 0: // Comment block at top of file
if (wszBuffer[0] == L'#')
{
// Skip each comment line
break;
}
else
{
// Stop expecting a comment block
dwState++;
// Fall through to status=1 below
}
case 1: // Change field
if (wcsncmp(wszBuffer, L"Change:\t", 8) == 0)
{
// Store the Change string:
m_Change = &wszBuffer[8];
// move on:
dwState++;
break;
}
else
{
// Invalid file.
goto Done;
}
case 2: // Date field
if (wcsncmp(wszBuffer, L"Date:\t", 6) == 0)
{
// Store the Date string:
m_Date = &wszBuffer[6];
// move on:
dwState++;
break;
}
else
{
// Maybe the Date line is missing. Skip it.
dwState++;
// Fall through to status=3 below
}
case 3: // Client field
if (wcsncmp(wszBuffer, L"Client:\t", 8) == 0)
{
// Store the Client string:
m_Client = &wszBuffer[8];
// move on:
dwState++;
break;
}
else
{
// Invalid file.
goto Done;
}
case 4: // User field
if (wcsncmp(wszBuffer, L"User:\t", 6) == 0)
{
// Store the User string:
m_User = &wszBuffer[6];
// move on:
dwState++;
break;
}
else
{
// Invalid file.
goto Done;
}
case 5: // Status field
if (wcsncmp(wszBuffer, L"Status:\t", 8) == 0)
{
// Store the Status string:
m_Status = &wszBuffer[8];
// move on:
dwState++;
break;
}
else
{
// Invalid file.
goto Done;
}
case 6: // Description field name
if (wcscmp(wszBuffer, L"Description:") == 0)
{
// Found it, but the actual Description is on the next line
dwState++;
break;
}
else
{
// Invalid file.
goto Done;
}
case 7: // Description field value
if (wszBuffer[0] == L'\t')
{
// Store the Description string:
m_Description = &wszBuffer[1];
// move on:
dwState++;
break;
}
else
{
// Invalid file.
goto Done;
}
case 8: // Files field name
if (wcscmp(wszBuffer, L"Files:") == 0)
{
// Found it, but the actual Files and Actions are on the following lines
dwState++;
break;
}
else
{
// Invalid file.
goto Done;
}
case 9: // Files and Actions field values
if (swscanf(wszBuffer, L"\t%499[^\t]\t# %49s",
wszBuffer2, wszBuffer3) == 2)
{
// Add the new FileAndAction data
if (_AddFileAndAction(pIFiles, wszBuffer2, wszBuffer3) == FALSE)
{
// Unable to add data. Nothing we can do about it.
goto Done;
}
// move on:
break; // This is the final state. No increment.
}
else
{
// Invalid file.
goto Done;
}
} // end of case statement
} // end of while loop
if ((dwState == 7) || (dwState == 9))
{
// We got to the Description section, so we completed parsing successfully.
fRetVal = TRUE;
}
Done:
if ((dwState == 9) && (fRetVal == FALSE))
{
// We might have to remove some failed files entries
while (SUCCEEDED(pIFiles->get_Count(&count)) &&
(count >= 1))
{
if (FAILED(pIFiles->Remove(1)))
break;
}
}
if (pIFiles)
pIFiles->Release();
if (CLFile)
fclose(CLFile);
return fRetVal;
}
BOOL CWebChangelistEditor::_AddFileAndAction(IFilesAndActions *pIFiles, WCHAR* wszFilename, WCHAR* wszAction)
{
CComBSTR bstrFile = wszFilename;
CComBSTR bstrAction = wszAction;
IFileAndAction *pIFile = NULL;
CComObject<CFileAndAction> *pBase = NULL;
CComVariant varTemp;
// Create a new FileAndAction object
if (FAILED(CComObject<CFileAndAction>::CreateInstance(&pBase)))
{
// Unable to create instance. Nothing we can do about it.
return FALSE;
}
if (FAILED(pBase->QueryInterface<IFileAndAction>(&pIFile)))
{
// Unable to query inferface. Nothing we can do about it.
return FALSE;
}
// Add the data to the new object
if (FAILED(pIFile->put_Action(bstrAction)) ||
FAILED(pIFile->put_Filename(bstrFile)))
{
// Unable to add data. Nothing we can do about it.
pIFile->Release();
return FALSE;
}
// Put the Interface ptr into a Variant, and release the old Interface ptr
varTemp = (IDispatch*)pIFile;
pIFile->Release();
// Add the new object to the collection
if (FAILED(pIFiles->Add(varTemp)))
{
// Unable to add data. Nothing we can do about it.
return FALSE;
}
// Success
return TRUE;
}
void CWebChangelistEditor::_WipeRegEntries(void)
{
HKEY hKey = NULL;
WCHAR wszValueName[41];
DWORD cchValueName = 41;
DWORD dwDatatype;
DWORD dwIndex;
HRESULT hr;
// Open our Key:
if (RegOpenKeyExW(HKEY_CURRENT_USER,
g_wszRegKey,
0,
KEY_QUERY_VALUE | KEY_SET_VALUE,
&hKey) != ERROR_SUCCESS)
{
hKey = NULL;
goto Done;
}
// For each value under that is named a 40-digit hex value,
// Delete it.
dwIndex = 0;
while ((hr = RegEnumValueW(hKey,
dwIndex,
wszValueName,
&cchValueName,
0,
&dwDatatype,
NULL, NULL)) != ERROR_NO_MORE_ITEMS)
{
if (FAILED(hr))
{
// This is most likely because the buffers are the wrong size
// but we don't care about the key unless we can read it into
// the buffers we've got, so just move on.
dwIndex++;
cchValueName = 41; // Set it back to the size of the buffer.
continue;
}
// Check the datatype:
if (dwDatatype != REG_SZ)
{
dwIndex++;
cchValueName = 41; // Set it back to the size of the buffer.
continue;
}
// Check the name:
// It must be 40 characters, containing only hex digits.
if ((cchValueName != 40) ||
(wcsspn(wszValueName, L"ABCDEFabcdef1234567890") != 40))
{
dwIndex++;
cchValueName = 41; // Set it back to the size of the buffer.
continue;
}
// If all the above checks succeeded, delete the value.
RegDeleteValueW(hKey, wszValueName);
// Since we've changed the indexing, start over:
cchValueName = 41; // Set it back to the size of the buffer.
dwIndex = 0;
}
Done:
if (hKey != NULL)
RegCloseKey(hKey);
}
STDMETHODIMP CWebChangelistEditor::get_Change(BSTR* pVal)
{
if (pVal == NULL)
return E_POINTER;
if (!m_fInitialized)
return E_FAIL;
return m_Change.CopyTo(pVal);
}
STDMETHODIMP CWebChangelistEditor::put_Change(BSTR newVal)
{
if (!m_fInitialized)
return E_FAIL;
m_Change = newVal;
return S_OK;
}
STDMETHODIMP CWebChangelistEditor::get_Date(BSTR* pVal)
{
if (pVal == NULL)
return E_POINTER;
if (!m_fInitialized)
return E_FAIL;
return m_Date.CopyTo(pVal);
}
STDMETHODIMP CWebChangelistEditor::put_Date(BSTR newVal)
{
if (!m_fInitialized)
return E_FAIL;
m_Date = newVal;
return S_OK;
}
STDMETHODIMP CWebChangelistEditor::get_Client(BSTR* pVal)
{
if (pVal == NULL)
return E_POINTER;
if (!m_fInitialized)
return E_FAIL;
return m_Client.CopyTo(pVal);
}
STDMETHODIMP CWebChangelistEditor::put_Client(BSTR newVal)
{
if (!m_fInitialized)
return E_FAIL;
m_Client = newVal;
return S_OK;
}
STDMETHODIMP CWebChangelistEditor::get_User(BSTR* pVal)
{
if (pVal == NULL)
return E_POINTER;
if (!m_fInitialized)
return E_FAIL;
return m_User.CopyTo(pVal);
}
STDMETHODIMP CWebChangelistEditor::put_User(BSTR newVal)
{
if (!m_fInitialized)
return E_FAIL;
m_User = newVal;
return S_OK;
}
STDMETHODIMP CWebChangelistEditor::get_Status(BSTR* pVal)
{
if (pVal == NULL)
return E_POINTER;
if (!m_fInitialized)
return E_FAIL;
return m_Status.CopyTo(pVal);
}
STDMETHODIMP CWebChangelistEditor::put_Status(BSTR newVal)
{
if (!m_fInitialized)
return E_FAIL;
m_Status = newVal;
return S_OK;
}
STDMETHODIMP CWebChangelistEditor::get_Description(BSTR* pVal)
{
if (pVal == NULL)
return E_POINTER;
if (!m_fInitialized)
return E_FAIL;
return m_Description.CopyTo(pVal);
}
STDMETHODIMP CWebChangelistEditor::put_Description(BSTR newVal)
{
if (!m_fInitialized)
return E_FAIL;
m_Description = newVal;
return S_OK;
}
STDMETHODIMP CWebChangelistEditor::get_Files(IFilesAndActions** pVal)
{
if (pVal == NULL)
return E_POINTER;
if (!m_fInitialized)
return E_FAIL;
return m_Files->QueryInterface<IFilesAndActions>(pVal);
}