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.
1800 lines
47 KiB
1800 lines
47 KiB
|
|
#include "headers.hxx"
|
|
#include "global.hpp"
|
|
|
|
|
|
#include "Analysis.hpp"
|
|
#include "AnalysisResults.hpp"
|
|
#include "CSVDSReader.hpp"
|
|
#include "resourceDspecup.h"
|
|
#include "AdsiHelpers.hpp"
|
|
#include "constants.hpp"
|
|
#include "dspecup.hpp"
|
|
|
|
|
|
Analysis::Analysis
|
|
(
|
|
const GUID guid_,
|
|
const CSVDSReader& csvReader409_,
|
|
const CSVDSReader& csvReaderIntl_,
|
|
const String& ldapPrefix_,
|
|
const String& rootContainerDn_,
|
|
AnalysisResults &res,
|
|
const String &reportName_,//=L"",
|
|
void *caleeStruct_,//=NULL,
|
|
progressFunction stepIt_,//=NULL,
|
|
progressFunction totalSteps_//=NULL,
|
|
)
|
|
:
|
|
guid(guid_),
|
|
csvReader409(csvReader409_),
|
|
csvReaderIntl(csvReaderIntl_),
|
|
ldapPrefix(ldapPrefix_),
|
|
rootContainerDn(rootContainerDn_),
|
|
results(res),
|
|
reportName(reportName_),
|
|
caleeStruct(caleeStruct_),
|
|
stepIt(stepIt_),
|
|
totalSteps(totalSteps_)
|
|
{
|
|
LOG_CTOR(Analysis);
|
|
ASSERT(!ldapPrefix.empty());
|
|
ASSERT(!rootContainerDn.empty());
|
|
|
|
};
|
|
|
|
|
|
// Analysis entry point
|
|
HRESULT
|
|
Analysis::run()
|
|
{
|
|
LOG_FUNCTION(Analysis::run);
|
|
|
|
if(changes.size()==0)
|
|
{
|
|
setChanges();
|
|
}
|
|
|
|
HRESULT hr=S_OK;
|
|
do
|
|
{
|
|
LongList locales;
|
|
for(long t=0;LOCALEIDS[t]!=0;t++)
|
|
{
|
|
locales.push_back(LOCALEIDS[t]);
|
|
}
|
|
locales.push_back(LOCALE409[0]);
|
|
|
|
if(totalSteps!=NULL)
|
|
{
|
|
// The cast bellow is for IA64 compilation since we know
|
|
// that locales.size() will fit in a long.
|
|
totalSteps(static_cast<long>(locales.size()),caleeStruct);
|
|
}
|
|
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
LongList::iterator begin=locales.begin();
|
|
LongList::iterator end=locales.end();
|
|
|
|
while(begin!=end)
|
|
{
|
|
long locale=*begin;
|
|
bool isPresent;
|
|
|
|
hr=dealWithContainer(locale,isPresent);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
if (isPresent)
|
|
{
|
|
hr=dealWithW2KObjects(locale);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
}
|
|
|
|
if(stepIt!=NULL)
|
|
{
|
|
stepIt(1,caleeStruct);
|
|
}
|
|
|
|
begin++;
|
|
}
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
if(!reportName.empty())
|
|
{
|
|
hr=createReport(reportName);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
}
|
|
}
|
|
while (0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
// add entry to result.createContainers if container is not present
|
|
// also returns flag isPresent
|
|
HRESULT
|
|
Analysis::dealWithContainer(
|
|
const long locale,
|
|
bool &isPresent)
|
|
{
|
|
LOG_FUNCTION(Analysis::dealWithContainer);
|
|
|
|
ASSERT(locale > 0);
|
|
ASSERT(!rootContainerDn.empty());
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
|
|
do
|
|
{
|
|
String container = String::format(L"CN=%1!3x!,", locale);
|
|
String childContainerDn =ldapPrefix + container + rootContainerDn;
|
|
|
|
// Attempt to bind to the container.
|
|
|
|
SmartInterface<IADs> iads(0);
|
|
hr = AdsiOpenObject<IADs>(childContainerDn, iads);
|
|
if (HRESULT_CODE(hr) == ERROR_DS_NO_SUCH_OBJECT)
|
|
{
|
|
// The container object does not exist. This is possible because
|
|
// the user has manually removed the container, or because it
|
|
// was never created due to an aboted post-dcpromo import of the
|
|
// display specifiers when the forest root dc was first promoted.
|
|
|
|
// NTRAID#NTBUG9-726839-2002/10/31-lucios
|
|
// We are only recovering the 409 container since recovering
|
|
// an international locale will overwrite possible 409 customizations
|
|
if (locale == 0x409) results.createContainers.push_back(locale);
|
|
|
|
isPresent=false;
|
|
|
|
hr = S_OK;
|
|
break;
|
|
}
|
|
else if (FAILED(hr))
|
|
{
|
|
error=String::format(IDS_ERROR_BINDING_TO_CONTAINER,
|
|
childContainerDn.c_str());
|
|
break;
|
|
}
|
|
|
|
|
|
// At this point, the bind succeeded, so the child container exists.
|
|
// So now we want to examine objects in that container.
|
|
|
|
isPresent=true;
|
|
}
|
|
while (0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
// sets iDirObj with the Active Directory object
|
|
// corresponding to the locale and object
|
|
HRESULT
|
|
Analysis::getADObj
|
|
(
|
|
const long locale,
|
|
const String& object,
|
|
SmartInterface<IDirectoryObject> &iDirObj
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
do
|
|
{
|
|
String objectPath =
|
|
ldapPrefix + L"CN=" + object + L"," +
|
|
String::format(L"CN=%1!3x!,", locale) + rootContainerDn;
|
|
|
|
SmartInterface<IADs> iads(0);
|
|
hr = AdsiOpenObject<IADs>(objectPath, iads);
|
|
if (HRESULT_CODE(hr) == ERROR_DS_NO_SUCH_OBJECT)
|
|
{
|
|
// The object does not exist.
|
|
hr = S_FALSE;
|
|
break;
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
// Unexpected error
|
|
error=String::format
|
|
(
|
|
IDS_ERROR_BINDING_TO_OBJECT,
|
|
object.c_str(),
|
|
objectPath.c_str()
|
|
);
|
|
|
|
break;
|
|
}
|
|
|
|
// At this point, the display specifier object exists.
|
|
|
|
hr=iDirObj.AcquireViaQueryInterface(iads);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
|
|
} while (0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
// add entries to results.createW2KObjects
|
|
// and results.objectActions as necessary
|
|
HRESULT
|
|
Analysis::dealWithW2KObjects(const long locale)
|
|
{
|
|
LOG_FUNCTION(Analysis::dealWithW2KObjects);
|
|
ASSERT(locale > 0);
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
do
|
|
{
|
|
hr=checkChanges(locale,changes[guid][locale]);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
hr=checkChanges(locale,changes[guid][-1]);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
} while (0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
Analysis::checkChanges
|
|
(
|
|
const long locale,
|
|
const changeList& changes
|
|
)
|
|
{
|
|
LOG_FUNCTION(Analysis::checkChanges);
|
|
|
|
HRESULT hr=S_OK;
|
|
|
|
do
|
|
{
|
|
changeList::const_iterator curChange,endChange;
|
|
for
|
|
(
|
|
curChange=changes.begin(),endChange=changes.end();
|
|
curChange!=endChange;
|
|
curChange++
|
|
)
|
|
{
|
|
const String &object=curChange->object;
|
|
const String &property=curChange->property;
|
|
const String &firstArg=curChange->firstArg;
|
|
const String &secondArg=curChange->secondArg;
|
|
|
|
SmartInterface<IDirectoryObject> iDirObj;
|
|
hr=getADObj(locale,object,iDirObj);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
if(hr==S_FALSE) // object doesn't exist
|
|
{
|
|
ObjectId tempObj(locale,String(object));
|
|
if(curChange->type==ADD_OBJECT)
|
|
{
|
|
results.createWhistlerObjects.push_back(tempObj);
|
|
}
|
|
else
|
|
{
|
|
// NTRAID#NTBUG9-726839-2002/10/31-lucios
|
|
// We are only recovering objects in the 409 container
|
|
// since recovering an object in an international locale
|
|
// will overwrite possible 409 customizations
|
|
if (
|
|
(locale == 0x409) &&
|
|
find
|
|
(
|
|
results.createW2KObjects.begin(),
|
|
results.createW2KObjects.end(),
|
|
tempObj
|
|
) == results.createW2KObjects.end()
|
|
)
|
|
{
|
|
results.createW2KObjects.push_back(tempObj);
|
|
}
|
|
}
|
|
hr=S_OK;
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
ObjectId tempObj(locale,String(object));
|
|
if(curChange->type==ADD_OBJECT)
|
|
{
|
|
results.conflictingWhistlerObjects.push_back(tempObj);
|
|
}
|
|
}
|
|
|
|
switch(curChange->type)
|
|
{
|
|
case ADD_ALL_CSV_VALUES:
|
|
|
|
hr = addAllCsvValues
|
|
(
|
|
iDirObj,
|
|
locale,
|
|
object,
|
|
property
|
|
);
|
|
break;
|
|
|
|
case ADD_VALUE:
|
|
|
|
hr = addValue
|
|
(
|
|
iDirObj,
|
|
locale,
|
|
object,
|
|
property,
|
|
firstArg
|
|
);
|
|
break;
|
|
|
|
case REPLACE_W2K_MULTIPLE_VALUE:
|
|
|
|
hr = replaceW2KMultipleValue
|
|
(
|
|
iDirObj,
|
|
locale,
|
|
object,
|
|
property,
|
|
firstArg,
|
|
secondArg
|
|
);
|
|
break;
|
|
|
|
case REPLACE_W2K_SINGLE_VALUE:
|
|
|
|
hr = replaceW2KSingleValue
|
|
(
|
|
iDirObj,
|
|
locale,
|
|
object,
|
|
property,
|
|
firstArg,
|
|
secondArg
|
|
);
|
|
break;
|
|
|
|
case ADD_GUID:
|
|
|
|
hr = addGuid
|
|
(
|
|
iDirObj,
|
|
locale,
|
|
object,
|
|
property,
|
|
firstArg
|
|
);
|
|
break;
|
|
|
|
case REMOVE_GUID:
|
|
|
|
hr = removeGuid
|
|
(
|
|
iDirObj,
|
|
locale,
|
|
object,
|
|
property,
|
|
firstArg
|
|
);
|
|
break;
|
|
|
|
case REPLACE_GUID:
|
|
hr = replaceGuid
|
|
(
|
|
iDirObj,
|
|
locale,
|
|
object,
|
|
property,
|
|
firstArg,
|
|
secondArg
|
|
);
|
|
break;
|
|
case ADD_OBJECT:
|
|
break; // dealt with in the beginning of the function
|
|
|
|
default:
|
|
ASSERT(false);
|
|
}
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
}
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
} while(0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
// adds ordAndGuid to the property if Guid is not already there.
|
|
HRESULT
|
|
Analysis::addGuid
|
|
(
|
|
IDirectoryObject *iDirObj,
|
|
const int locale,
|
|
const String &object,
|
|
const String &property,
|
|
const String &ordAndGuid
|
|
)
|
|
{
|
|
LOG_FUNCTION(Analysis::addGuid);
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
do
|
|
{
|
|
String guidFound;
|
|
hr=getADGuid(
|
|
iDirObj,
|
|
property,
|
|
ordAndGuid,
|
|
guidFound
|
|
);
|
|
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
if (hr == S_FALSE)
|
|
{
|
|
ObjectId tempObj(locale,String(object));
|
|
|
|
ValueActions &act=results.objectActions[tempObj][property];
|
|
act.addValues.push_back(ordAndGuid);
|
|
}
|
|
|
|
}
|
|
while (0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
// replaces ordAndGuidWin2K for ordAndGuidWhistler.
|
|
HRESULT
|
|
Analysis::replaceGuid
|
|
(
|
|
IDirectoryObject *iDirObj,
|
|
const int locale,
|
|
const String &object,
|
|
const String &property,
|
|
const String &ordAndGuidWin2K,
|
|
const String &ordAndGuidWhistler
|
|
)
|
|
{
|
|
LOG_FUNCTION(Analysis::replaceGuid);
|
|
HRESULT hr = S_OK;
|
|
|
|
do
|
|
{
|
|
String guidFound;
|
|
hr=getADGuid(
|
|
iDirObj,
|
|
property,
|
|
ordAndGuidWhistler,
|
|
guidFound
|
|
);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
if (hr == S_OK) // The Whistler GUID was found
|
|
{
|
|
hr=removeExtraneousGUID
|
|
(
|
|
iDirObj,
|
|
locale,
|
|
object,
|
|
property,
|
|
guidFound,
|
|
ordAndGuidWin2K,
|
|
ordAndGuidWhistler
|
|
);
|
|
break;
|
|
}
|
|
|
|
// The Whistler GUID is not present
|
|
|
|
hr=getADGuid(
|
|
iDirObj,
|
|
property,
|
|
ordAndGuidWin2K,
|
|
guidFound
|
|
);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
if (hr == S_OK) // The Win2K GUID was found
|
|
{
|
|
size_t posFound=guidFound.find(L',');
|
|
ASSERT(posFound != String::npos);
|
|
size_t posWhistler=ordAndGuidWhistler.find(L',');
|
|
ASSERT(posWhistler != String::npos);
|
|
|
|
String guidToAdd = guidFound.substr(0,posFound) +
|
|
ordAndGuidWhistler.substr(posWhistler);
|
|
|
|
ObjectId tempObj(locale,String(object));
|
|
ValueActions &act=results.objectActions[tempObj][property];
|
|
act.delValues.push_back(guidFound);
|
|
act.addValues.push_back(guidToAdd);
|
|
|
|
hr=removeExtraneousGUID
|
|
(
|
|
iDirObj,
|
|
locale,
|
|
object,
|
|
property,
|
|
guidFound,
|
|
ordAndGuidWin2K,
|
|
ordAndGuidWhistler
|
|
);
|
|
break;
|
|
}
|
|
|
|
// Neither the Win2K nor the Whistler GUIDs were found
|
|
// Since the customer did not wan't the Win2K GUID
|
|
// he probably will not want the Whistler GUID either,
|
|
// so we do nothing.
|
|
|
|
} while(0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
// removes ordAndGuid from the property if Guid is there.
|
|
HRESULT
|
|
Analysis::removeGuid
|
|
(
|
|
IDirectoryObject *iDirObj,
|
|
const int locale,
|
|
const String &object,
|
|
const String &property,
|
|
const String &ordAndGuid)
|
|
{
|
|
|
|
LOG_FUNCTION(Analysis::removeGuid);
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
do
|
|
{
|
|
String guidFound;
|
|
hr=getADGuid(
|
|
iDirObj,
|
|
property,
|
|
ordAndGuid,
|
|
guidFound
|
|
);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
ObjectId tempObj(locale,String(object));
|
|
|
|
ValueActions &act=results.objectActions[tempObj][property];
|
|
act.delValues.push_back(guidFound);
|
|
}
|
|
|
|
}
|
|
while (0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
// adds all csv values still not on the property
|
|
HRESULT
|
|
Analysis::addAllCsvValues
|
|
(
|
|
IDirectoryObject *iDirObj,
|
|
const long locale,
|
|
const String &object,
|
|
const String &property
|
|
)
|
|
{
|
|
LOG_FUNCTION(Analysis::addAllCsvValues);
|
|
|
|
HRESULT hr = S_OK;
|
|
const CSVDSReader &csvReader=(locale==0x409)?csvReader409:csvReaderIntl;
|
|
|
|
do
|
|
{
|
|
StringList values;
|
|
hr=csvReader.getCsvValues(locale,object.c_str(),property.c_str(),values);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
if (values.size()==0)
|
|
{
|
|
error=String::format(IDS_NO_CSV_VALUE,locale,object.c_str());
|
|
hr=E_FAIL;
|
|
break;
|
|
}
|
|
StringList::iterator begin=values.begin();
|
|
StringList::iterator end=values.end();
|
|
while(begin!=end)
|
|
{
|
|
hr=addValue(iDirObj,locale,object,property,begin->c_str());
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
begin++;
|
|
}
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
}
|
|
while (0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
// adds value to the property if it is not already there.
|
|
HRESULT
|
|
Analysis::addValue(
|
|
IDirectoryObject *iDirObj,
|
|
const long locale,
|
|
const String &object,
|
|
const String &property,
|
|
const String &value)
|
|
{
|
|
LOG_FUNCTION(Analysis::addValue);
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
do
|
|
{
|
|
hr=isADValuePresent (
|
|
iDirObj,
|
|
property,
|
|
value
|
|
);
|
|
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
if (hr == S_FALSE)
|
|
{
|
|
ObjectId tempObj(locale,String(object));
|
|
|
|
ValueActions &act=results.objectActions[tempObj][property];
|
|
act.addValues.push_back(value);
|
|
}
|
|
|
|
}
|
|
while (0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
// The idea of replaceW2KValue is replacing the W2K value
|
|
// for the Whistler. We also make sure we don't extraneous values.
|
|
HRESULT
|
|
Analysis::replaceW2KSingleValue
|
|
(
|
|
IDirectoryObject *iDirObj,
|
|
const int locale,
|
|
const String &object,
|
|
const String &property,
|
|
const String &W2KCsvValue,
|
|
const String &WhistlerCsvValue
|
|
)
|
|
{
|
|
LOG_FUNCTION(Analysis::replaceW2KSingleValue);
|
|
|
|
|
|
HRESULT hr = S_OK;
|
|
do
|
|
{
|
|
|
|
hr=isADValuePresent(iDirObj,property,WhistlerCsvValue);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
if(hr == S_OK) // The Whistler value is already there
|
|
{
|
|
// We will remove any other value than the Whistler
|
|
hr=removeExtraneous
|
|
(
|
|
iDirObj,
|
|
locale,
|
|
object,
|
|
property,
|
|
WhistlerCsvValue
|
|
);
|
|
break;
|
|
}
|
|
|
|
// Now we know that the Whistler value is not present
|
|
// and therefore we will add it if the W2K value is present
|
|
|
|
hr=isADValuePresent(iDirObj,property,W2KCsvValue);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
if(hr == S_OK) // The W2K value is there.
|
|
{
|
|
ObjectId tempObj(locale,String(object));
|
|
|
|
ValueActions &act=results.objectActions[tempObj][property];
|
|
act.addValues.push_back(WhistlerCsvValue);
|
|
act.delValues.push_back(W2KCsvValue);
|
|
|
|
// remove all but the W2K that we removed in the previous line
|
|
hr=removeExtraneous
|
|
(
|
|
iDirObj,
|
|
locale,
|
|
object,
|
|
property,
|
|
W2KCsvValue
|
|
);
|
|
break;
|
|
}
|
|
|
|
// Now we know that neither Whistler nor W2K values are present
|
|
// If we have a value we will log that it is a custom value
|
|
|
|
String ADValue;
|
|
hr=getADFirstValue(iDirObj,property,ADValue);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
if(hr == S_OK) // We have a value
|
|
{
|
|
SingleValue tmpCustom(locale,object,property,ADValue);
|
|
results.customizedValues.push_back(tmpCustom);
|
|
|
|
// We will remove any other value than the one we found
|
|
hr=removeExtraneous(iDirObj,locale,object,property,ADValue);
|
|
break;
|
|
}
|
|
|
|
// Now we know that we don't have any values at all.
|
|
ObjectId tempObj(locale,String(object));
|
|
|
|
ValueActions &act=results.objectActions[tempObj][property];
|
|
act.addValues.push_back(WhistlerCsvValue);
|
|
}
|
|
while(0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
// The idea of replaceW2KValue is replacing the W2K value
|
|
// for the Whistler. We also make sure we don't ahve extraneous values.
|
|
HRESULT
|
|
Analysis::replaceW2KMultipleValue
|
|
(
|
|
IDirectoryObject *iDirObj,
|
|
const int locale,
|
|
const String &object,
|
|
const String &property,
|
|
const String &W2KCsvValue,
|
|
const String &WhistlerCsvValue
|
|
)
|
|
{
|
|
LOG_FUNCTION(Analysis::replaceW2KMultipleValue);
|
|
|
|
// First we should get the beginning of the W2K
|
|
// snd Whistler strings for use in removeExtraneous calls
|
|
size_t pos=W2KCsvValue.find(L',');
|
|
ASSERT(pos != String::npos); // W2KRepl ensures the comma
|
|
String W2KStart=W2KCsvValue.substr(0,pos+1);
|
|
|
|
|
|
pos=WhistlerCsvValue.find(L',');
|
|
ASSERT(pos != String::npos); // W2KRepl ensures the comma
|
|
String WhistlerStart=WhistlerCsvValue.substr(0,pos+1);
|
|
|
|
|
|
HRESULT hr = S_OK;
|
|
do
|
|
{
|
|
|
|
hr=isADValuePresent(iDirObj,property,WhistlerCsvValue);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
if(hr == S_OK) // The Whistler value is already there
|
|
{
|
|
hr=removeExtraneous(
|
|
iDirObj,
|
|
locale,
|
|
object,
|
|
property,
|
|
WhistlerCsvValue,
|
|
WhistlerStart,
|
|
W2KStart
|
|
);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
break;
|
|
}
|
|
|
|
// Now we know that the Whistler value is not present
|
|
// and therefore we will add it if the W2K value is present
|
|
|
|
hr=isADValuePresent(iDirObj,property,W2KCsvValue);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
if(hr == S_OK) // The W2K value is there.
|
|
{
|
|
ObjectId tempObj(locale,String(object));
|
|
|
|
ValueActions &act=results.objectActions[tempObj][property];
|
|
act.addValues.push_back(WhistlerCsvValue);
|
|
act.delValues.push_back(W2KCsvValue);
|
|
|
|
// remove all but the W2K that we removed in the previous line
|
|
hr=removeExtraneous(
|
|
iDirObj,
|
|
locale,
|
|
object,
|
|
property,
|
|
W2KCsvValue,
|
|
WhistlerStart,
|
|
W2KStart
|
|
);
|
|
break;
|
|
}
|
|
|
|
// Now we know that neither Whistler nor W2K values are present
|
|
// If we have a value starting like the W2K we will log that it
|
|
// is a custom value
|
|
|
|
|
|
String ADValue;
|
|
|
|
hr=isADStartValuePresent(iDirObj,property,W2KStart,ADValue);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
if(hr==S_OK) // Something starts like the W2K csv value
|
|
{
|
|
SingleValue tmpCustom(locale,object,property,ADValue);
|
|
results.customizedValues.push_back(tmpCustom);
|
|
|
|
// We will keep only the first custom value
|
|
hr=removeExtraneous(
|
|
iDirObj,
|
|
locale,
|
|
object,
|
|
property,
|
|
ADValue,
|
|
WhistlerStart,
|
|
W2KStart
|
|
);
|
|
break;
|
|
}
|
|
|
|
|
|
// Now neither Whistler, W2K or W2KStart are present
|
|
if ( WhistlerStart == W2KStart )
|
|
{
|
|
// We have to check the WhistlerStart as well
|
|
|
|
hr=isADStartValuePresent(iDirObj,property,WhistlerStart,ADValue);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
if(hr == S_OK) // Something starts like the Whistler csv value
|
|
{
|
|
SingleValue tmpCustom(locale,object,property,ADValue);
|
|
results.customizedValues.push_back(tmpCustom);
|
|
|
|
// We will keep only the first custom value
|
|
hr=removeExtraneous(
|
|
iDirObj,
|
|
locale,
|
|
object,
|
|
property,
|
|
ADValue,
|
|
WhistlerStart,
|
|
W2KStart
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Now we know that there are no values starting like
|
|
// the Whistler or W2K csv values so we have to add
|
|
// the Whistler value
|
|
ObjectId tempObj(locale,String(object));
|
|
|
|
ValueActions &act=results.objectActions[tempObj][property];
|
|
act.addValues.push_back(WhistlerCsvValue);
|
|
}
|
|
while(0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
//called from RwplaceW2KMultipleValue to remove all values
|
|
// starting with start1 or start2 other than keeper
|
|
HRESULT
|
|
Analysis::removeExtraneous
|
|
(
|
|
IDirectoryObject *iDirObj,
|
|
const int locale,
|
|
const String &object,
|
|
const String &property,
|
|
const String &keeper,
|
|
const String &start1,
|
|
const String &start2
|
|
)
|
|
{
|
|
LOG_FUNCTION(Analysis::removeExtraneous);
|
|
HRESULT hr = S_OK;
|
|
|
|
DWORD dwReturn=0;
|
|
ADS_ATTR_INFO *pAttrInfo =NULL;
|
|
|
|
// iDirObj->GetObjectAttributes swears that pAttrName is an IN argument.
|
|
// It should have used a LPCWSTR but now we have to pay the
|
|
// casting price
|
|
LPWSTR pAttrName[] ={const_cast<LPWSTR>(property.c_str())};
|
|
|
|
|
|
|
|
do
|
|
{
|
|
hr = iDirObj->GetObjectAttributes(
|
|
pAttrName,
|
|
1,
|
|
&pAttrInfo,
|
|
&dwReturn
|
|
);
|
|
|
|
do
|
|
{
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
if(pAttrInfo==NULL)
|
|
{
|
|
hr = S_FALSE;
|
|
break;
|
|
}
|
|
|
|
for (
|
|
DWORD val=0;
|
|
val < pAttrInfo->dwNumValues;
|
|
val++
|
|
)
|
|
{
|
|
ASSERT
|
|
(
|
|
pAttrInfo->pADsValues[val].dwType ==
|
|
ADSTYPE_CASE_IGNORE_STRING
|
|
);
|
|
wchar_t *valueAD = pAttrInfo->pADsValues[val].CaseIgnoreString;
|
|
|
|
if ( wcscmp(valueAD,keeper.c_str())!=0 &&
|
|
(
|
|
wcsncmp(valueAD,start1.c_str(),start1.size())==0 ||
|
|
wcsncmp(valueAD,start2.c_str(),start2.size())==0
|
|
)
|
|
)
|
|
{
|
|
String value=valueAD;
|
|
ObjectId tempObj(locale,String(object));
|
|
|
|
ValueActions &act=results.extraneousValues[tempObj][property];
|
|
act.delValues.push_back(value);
|
|
}
|
|
}
|
|
} while(0);
|
|
|
|
if (pAttrInfo!=NULL) FreeADsMem(pAttrInfo);
|
|
}
|
|
while (0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
// called from RwplaceW2KSingleValue to remove all values
|
|
// other than keeper
|
|
HRESULT
|
|
Analysis::removeExtraneous
|
|
(
|
|
IDirectoryObject *iDirObj,
|
|
const int locale,
|
|
const String &object,
|
|
const String &property,
|
|
const String &keeper
|
|
)
|
|
{
|
|
LOG_FUNCTION(Analysis::removeExtraneous);
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
DWORD dwReturn=0;
|
|
ADS_ATTR_INFO *pAttrInfo =NULL;
|
|
|
|
// iDirObj->GetObjectAttributes swears that pAttrName is an IN argument.
|
|
// It should have used a LPCWSTR but now we have to pay the
|
|
// casting price
|
|
LPWSTR pAttrName[] ={const_cast<LPWSTR>(property.c_str())};
|
|
|
|
|
|
|
|
do
|
|
{
|
|
hr = iDirObj->GetObjectAttributes(
|
|
pAttrName,
|
|
1,
|
|
&pAttrInfo,
|
|
&dwReturn
|
|
);
|
|
|
|
do
|
|
{
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
if(pAttrInfo==NULL)
|
|
{
|
|
hr = S_FALSE;
|
|
break;
|
|
}
|
|
|
|
|
|
for (
|
|
DWORD val=0;
|
|
val < pAttrInfo->dwNumValues;
|
|
val++
|
|
)
|
|
{
|
|
ASSERT
|
|
(
|
|
pAttrInfo->pADsValues[val].dwType ==
|
|
ADSTYPE_CASE_IGNORE_STRING
|
|
);
|
|
wchar_t *valueAD = pAttrInfo->pADsValues[val].CaseIgnoreString;
|
|
|
|
if ( wcscmp(valueAD,keeper.c_str())!=0 )
|
|
{
|
|
String value=valueAD;
|
|
ObjectId tempObj(locale,String(object));
|
|
|
|
ValueActions &act=results.extraneousValues[tempObj][property];
|
|
act.delValues.push_back(value);
|
|
}
|
|
}
|
|
} while(0);
|
|
|
|
if (pAttrInfo!=NULL) FreeADsMem(pAttrInfo);
|
|
}
|
|
while (0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
// called from replaceGUID to remove all values
|
|
// starting with the GUID in ordAndGuid1
|
|
// or the GUID in ordAndGuid2 other than keeper
|
|
HRESULT
|
|
Analysis::removeExtraneousGUID
|
|
(
|
|
IDirectoryObject *iDirObj,
|
|
const int locale,
|
|
const String &object,
|
|
const String &property,
|
|
const String &keeper,
|
|
const String &ordAndGuid1,
|
|
const String &ordAndGuid2
|
|
)
|
|
{
|
|
LOG_FUNCTION(Analysis::removeExtraneousGUID);
|
|
HRESULT hr = S_OK;
|
|
|
|
size_t pos=ordAndGuid1.find(L',');
|
|
ASSERT(pos != String::npos);
|
|
String guid1=ordAndGuid1.substr(pos+1);
|
|
|
|
pos=ordAndGuid2.find(L',');
|
|
ASSERT(pos != String::npos);
|
|
String guid2=ordAndGuid2.substr(pos+1);
|
|
|
|
DWORD dwReturn=0;
|
|
ADS_ATTR_INFO *pAttrInfo =NULL;
|
|
|
|
// iDirObj->GetObjectAttributes swears that pAttrName is an IN argument.
|
|
// It should have used a LPCWSTR but now we have to pay the
|
|
// casting price
|
|
LPWSTR pAttrName[] ={const_cast<LPWSTR>(property.c_str())};
|
|
|
|
|
|
|
|
do
|
|
{
|
|
hr = iDirObj->GetObjectAttributes(
|
|
pAttrName,
|
|
1,
|
|
&pAttrInfo,
|
|
&dwReturn
|
|
);
|
|
|
|
do
|
|
{
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
if(pAttrInfo==NULL)
|
|
{
|
|
hr = S_FALSE;
|
|
break;
|
|
}
|
|
|
|
for (
|
|
DWORD val=0;
|
|
val < pAttrInfo->dwNumValues;
|
|
val++
|
|
)
|
|
{
|
|
ASSERT
|
|
(
|
|
pAttrInfo->pADsValues[val].dwType ==
|
|
ADSTYPE_CASE_IGNORE_STRING
|
|
);
|
|
wchar_t *valueAD = pAttrInfo->pADsValues[val].CaseIgnoreString;
|
|
|
|
if (keeper.icompare(valueAD)!=0)
|
|
{
|
|
String valueStr=valueAD;
|
|
pos=valueStr.find(L',');
|
|
if (pos!=String::npos)
|
|
{
|
|
String guid=valueStr.substr(pos+1);
|
|
if(guid1.icompare(guid)==0 || guid2.icompare(guid)==0)
|
|
{
|
|
ObjectId tempObj(locale,String(object));
|
|
|
|
ValueActions &act=results.extraneousValues[tempObj][property];
|
|
act.delValues.push_back(valueStr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} while(0);
|
|
|
|
if (pAttrInfo!=NULL) FreeADsMem(pAttrInfo);
|
|
}
|
|
while (0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
// if any value exists in the AD with the same guid as guidValue
|
|
// it is returned in guidFound, otherwise S_FALSE is returned
|
|
HRESULT
|
|
Analysis::getADGuid
|
|
(
|
|
IDirectoryObject *iDirObj,
|
|
const String &property,
|
|
const String &guidValue,
|
|
String &guidFound
|
|
)
|
|
{
|
|
LOG_FUNCTION(Analysis::getADGuid);
|
|
|
|
DWORD dwReturn=0;
|
|
ADS_ATTR_INFO *pAttrInfo =NULL;
|
|
|
|
// iDirObj->GetObjectAttributes swears that pAttrName is an IN argument.
|
|
// It should have used a LPCWSTR but now we have to pay the
|
|
// casting price
|
|
LPWSTR pAttrName[] ={const_cast<LPWSTR>(property.c_str())};
|
|
|
|
size_t pos=guidValue.find(L',');
|
|
ASSERT(pos!=String::npos);
|
|
|
|
String guid=guidValue.substr(pos+1);
|
|
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
do
|
|
{
|
|
hr = iDirObj->GetObjectAttributes(
|
|
pAttrName,
|
|
1,
|
|
&pAttrInfo,
|
|
&dwReturn
|
|
);
|
|
|
|
do
|
|
{
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
// If there are no values we finish the search
|
|
hr=S_FALSE;
|
|
|
|
if(pAttrInfo==NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
for (
|
|
DWORD val=0;
|
|
val < pAttrInfo->dwNumValues;
|
|
val++
|
|
)
|
|
{
|
|
ASSERT
|
|
(
|
|
pAttrInfo->pADsValues[val].dwType ==
|
|
ADSTYPE_CASE_IGNORE_STRING
|
|
);
|
|
wchar_t *guidAD=wcschr(pAttrInfo->pADsValues[val].CaseIgnoreString,L',');
|
|
if(guidAD != NULL)
|
|
{
|
|
guidAD++;
|
|
|
|
if (guid.icompare(guidAD)==0)
|
|
{
|
|
guidFound=pAttrInfo->pADsValues[val].CaseIgnoreString;
|
|
hr=S_OK;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} while(0);
|
|
|
|
if (pAttrInfo!=NULL) FreeADsMem(pAttrInfo);
|
|
|
|
}
|
|
while (0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
// returns S_OK if value is present or S_FALSE otherwise
|
|
HRESULT
|
|
Analysis::isADValuePresent
|
|
(
|
|
IDirectoryObject *iDirObj,
|
|
const String &property,
|
|
const String &value
|
|
)
|
|
{
|
|
LOG_FUNCTION(Analysis::isADValuePresent);
|
|
|
|
DWORD dwReturn=0;
|
|
ADS_ATTR_INFO *pAttrInfo =NULL;
|
|
|
|
// iDirObj->GetObjectAttributes swears that pAttrName is an IN argument.
|
|
// It should have used a LPCWSTR but now we have to pay the
|
|
// casting price
|
|
LPWSTR pAttrName[] ={const_cast<LPWSTR>(property.c_str())};
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
do
|
|
{
|
|
hr = iDirObj->GetObjectAttributes(
|
|
pAttrName,
|
|
1,
|
|
&pAttrInfo,
|
|
&dwReturn
|
|
);
|
|
|
|
do
|
|
{
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
hr=S_FALSE;
|
|
|
|
// If there are no values we finish the search
|
|
if(pAttrInfo==NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
|
|
for (
|
|
DWORD val=0;
|
|
val < pAttrInfo->dwNumValues;
|
|
val++
|
|
)
|
|
{
|
|
ASSERT
|
|
(
|
|
pAttrInfo->pADsValues[val].dwType ==
|
|
ADSTYPE_CASE_IGNORE_STRING
|
|
);
|
|
wchar_t *valueAD=pAttrInfo->pADsValues[val].CaseIgnoreString;
|
|
if (wcscmp(value.c_str(),valueAD)==0)
|
|
{
|
|
hr=S_OK;
|
|
break;
|
|
}
|
|
}
|
|
} while(0);
|
|
if (pAttrInfo!=NULL) FreeADsMem(pAttrInfo);
|
|
}
|
|
while (0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
// retrieves the first value starting with valueStart
|
|
// from the Active Directory
|
|
// If no value is found S_FALSE is returned.
|
|
HRESULT
|
|
Analysis::isADStartValuePresent
|
|
(
|
|
IDirectoryObject *iDirObj,
|
|
const String &property,
|
|
const String &valueStart,
|
|
String &value
|
|
)
|
|
{
|
|
LOG_FUNCTION(Analysis::isADStartValuePresent);
|
|
|
|
DWORD dwReturn=0;
|
|
ADS_ATTR_INFO *pAttrInfo =NULL;
|
|
|
|
// iDirObj->GetObjectAttributes swears that pAttrName is an IN argument.
|
|
// It should have used a LPCWSTR but now we have to pay the
|
|
// casting price
|
|
LPWSTR pAttrName[] ={const_cast<LPWSTR>(property.c_str())};
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
do
|
|
{
|
|
hr = iDirObj->GetObjectAttributes(
|
|
pAttrName,
|
|
1,
|
|
&pAttrInfo,
|
|
&dwReturn
|
|
);
|
|
|
|
do
|
|
{
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
value.erase();
|
|
|
|
hr = S_FALSE;
|
|
|
|
// If there are no values we finish the search
|
|
if(pAttrInfo==NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
for (
|
|
DWORD val=0;
|
|
(val < pAttrInfo->dwNumValues);
|
|
val++
|
|
)
|
|
{
|
|
ASSERT
|
|
(
|
|
pAttrInfo->pADsValues[val].dwType ==
|
|
ADSTYPE_CASE_IGNORE_STRING
|
|
);
|
|
wchar_t *valueAD=pAttrInfo->pADsValues[val].CaseIgnoreString;
|
|
if (wcsncmp(valueStart.c_str(),valueAD,valueStart.size())==0)
|
|
{
|
|
value=pAttrInfo->pADsValues[val].CaseIgnoreString;
|
|
hr=S_OK;
|
|
break;
|
|
}
|
|
}
|
|
} while(0);
|
|
|
|
if (pAttrInfo!=NULL) FreeADsMem(pAttrInfo);
|
|
|
|
|
|
}
|
|
while (0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
// retrieves the first value
|
|
// from the Active Directory
|
|
// If no value is found S_FALSE is returned.
|
|
HRESULT
|
|
Analysis::getADFirstValue
|
|
(
|
|
IDirectoryObject *iDirObj,
|
|
const String &property,
|
|
String &value
|
|
)
|
|
{
|
|
LOG_FUNCTION(Analysis::getADFirstValue);
|
|
|
|
DWORD dwReturn=0;
|
|
ADS_ATTR_INFO *pAttrInfo =NULL;
|
|
|
|
// iDirObj->GetObjectAttributes swears that pAttrName is an IN argument.
|
|
// It should have used a LPCWSTR but now we have to pay the
|
|
// casting price
|
|
LPWSTR pAttrName[] ={const_cast<LPWSTR>(property.c_str())};
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
do
|
|
{
|
|
hr = iDirObj->GetObjectAttributes(
|
|
pAttrName,
|
|
1,
|
|
&pAttrInfo,
|
|
&dwReturn
|
|
);
|
|
|
|
do
|
|
{
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
// If there are no values we finish the search
|
|
if(pAttrInfo==NULL)
|
|
{
|
|
hr = S_FALSE;
|
|
break;
|
|
}
|
|
ASSERT(pAttrInfo->pADsValues->dwType==ADSTYPE_CASE_IGNORE_STRING);
|
|
|
|
value=pAttrInfo->pADsValues->CaseIgnoreString;
|
|
} while(0);
|
|
if (pAttrInfo!=NULL) FreeADsMem(pAttrInfo);
|
|
|
|
}
|
|
while (0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
// auxiliary in the createReport to
|
|
// enumerate an ObjectIdList
|
|
HRESULT
|
|
Analysis::reportObjects
|
|
(
|
|
HANDLE file,
|
|
const ObjectIdList &list,
|
|
const String &header
|
|
)
|
|
{
|
|
LOG_FUNCTION(Analysis::reportObjects);
|
|
HRESULT hr=S_OK;
|
|
|
|
do
|
|
{
|
|
if(list.size()==0) break;
|
|
hr=FS::WriteLine(file,header);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
ObjectIdList::const_iterator begin,end;
|
|
begin=list.begin();
|
|
end=list.end();
|
|
while(begin!=end)
|
|
{
|
|
|
|
hr=FS::WriteLine(
|
|
file,
|
|
String::format
|
|
(
|
|
IDS_RPT_OBJECT_FORMAT,
|
|
begin->object.c_str(),
|
|
begin->locale
|
|
)
|
|
);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
begin++;
|
|
}
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
}
|
|
while(0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
// auxiliary in the createReport to
|
|
// enumerate a LongList
|
|
HRESULT
|
|
Analysis::reportContainers
|
|
(
|
|
HANDLE file,
|
|
const LongList &list,
|
|
const String &header
|
|
)
|
|
{
|
|
LOG_FUNCTION(Analysis::reportContainers);
|
|
HRESULT hr=S_OK;
|
|
|
|
do
|
|
{
|
|
if(list.size()==0) break;
|
|
hr=FS::WriteLine(file,header);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
LongList::const_iterator begin,end;
|
|
begin=list.begin();
|
|
end=list.end();
|
|
while(begin!=end)
|
|
{
|
|
|
|
hr=FS::WriteLine(
|
|
file,
|
|
String::format
|
|
(
|
|
IDS_RPT_CONTAINER_FORMAT,
|
|
*begin
|
|
)
|
|
);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
begin++;
|
|
}
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
}
|
|
while(0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
// auxiliary in the createReport to
|
|
// enumerate a SingleValueList
|
|
HRESULT
|
|
Analysis::reportValues
|
|
(
|
|
HANDLE file,
|
|
const SingleValueList &list,
|
|
const String &header
|
|
)
|
|
{
|
|
LOG_FUNCTION(Analysis::reportValues);
|
|
HRESULT hr=S_OK;
|
|
|
|
do
|
|
{
|
|
if(list.size()==0) break;
|
|
hr=FS::WriteLine(file,header);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
SingleValueList::const_iterator begin,end;
|
|
begin=list.begin();
|
|
end=list.end();
|
|
while(begin!=end)
|
|
{
|
|
|
|
hr=FS::WriteLine(
|
|
file,
|
|
String::format
|
|
(
|
|
IDS_RPT_VALUE_FORMAT,
|
|
begin->value.c_str(),
|
|
begin->locale,
|
|
begin->object.c_str(),
|
|
begin->property.c_str()
|
|
)
|
|
);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
begin++;
|
|
}
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
}
|
|
while(0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
// auxiliary in the createReport to
|
|
// enumerate ObjectActions
|
|
HRESULT
|
|
Analysis::reportActions
|
|
(
|
|
HANDLE file,
|
|
const ObjectActions &list,
|
|
const String &header
|
|
)
|
|
{
|
|
LOG_FUNCTION(Analysis::reportActions);
|
|
HRESULT hr=S_OK;
|
|
|
|
do
|
|
{
|
|
if(list.size()==0) break;
|
|
hr=FS::WriteLine(file,header);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
ObjectActions::const_iterator beginObj=list.begin();
|
|
ObjectActions::const_iterator endObj=list.end();
|
|
|
|
while(beginObj!=endObj)
|
|
{
|
|
|
|
hr=FS::WriteLine
|
|
(
|
|
file,
|
|
String::format
|
|
(
|
|
IDS_RPT_OBJECT_FORMAT,
|
|
beginObj->first.object.c_str(),
|
|
beginObj->first.locale
|
|
)
|
|
);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
|
|
PropertyActions::iterator beginAct=beginObj->second.begin();
|
|
PropertyActions::iterator endAct=beginObj->second.end();
|
|
|
|
while(beginAct!=endAct)
|
|
{
|
|
|
|
StringList::iterator
|
|
beginDel = beginAct->second.delValues.begin();
|
|
StringList::iterator
|
|
endDel = beginAct->second.delValues.end();
|
|
while(beginDel!=endDel)
|
|
{
|
|
hr=FS::WriteLine
|
|
(
|
|
file,
|
|
String::format
|
|
(
|
|
IDS_RPT_DEL_VALUE_FORMAT,
|
|
beginAct->first.c_str(),
|
|
beginDel->c_str()
|
|
)
|
|
);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
beginDel++;
|
|
}
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
|
|
StringList::iterator
|
|
beginAdd = beginAct->second.addValues.begin();
|
|
StringList::iterator
|
|
endAdd = beginAct->second.addValues.end();
|
|
while(beginAdd!=endAdd)
|
|
{
|
|
hr=FS::WriteLine
|
|
(
|
|
file,
|
|
String::format
|
|
(
|
|
IDS_RPT_ADD_VALUE_FORMAT,
|
|
beginAct->first.c_str(),
|
|
beginAdd->c_str()
|
|
)
|
|
);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
beginAdd++;
|
|
}
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
beginAct++;
|
|
} // while(beginAct!=endAct)
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
beginObj++;
|
|
} // while(beginObj!=endObj)
|
|
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
}
|
|
while(0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
// Create the report from the AnalysisResults
|
|
HRESULT
|
|
Analysis::createReport(const String& reportName)
|
|
{
|
|
LOG_FUNCTION(Analysis::createReport);
|
|
HRESULT hr=S_OK;
|
|
do
|
|
{
|
|
|
|
HANDLE file;
|
|
|
|
hr=FS::CreateFile(reportName,
|
|
file,
|
|
GENERIC_WRITE);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
error=String::format(IDS_COULD_NOT_CREATE_FILE,reportName.c_str());
|
|
break;
|
|
}
|
|
|
|
|
|
do
|
|
{
|
|
hr=FS::WriteLine(file,String::load(IDS_RPT_HEADER));
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
|
|
hr=reportActions (
|
|
file,
|
|
results.extraneousValues,
|
|
String::load(IDS_RPT_EXTRANEOUS)
|
|
);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
|
|
|
|
hr=reportValues (
|
|
file,
|
|
results.customizedValues,
|
|
String::load(IDS_RPT_CUSTOMIZED)
|
|
);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
hr=reportObjects
|
|
(
|
|
file,
|
|
results.conflictingWhistlerObjects,
|
|
String::load
|
|
(
|
|
IDS_RPT_CONFLICTING_WITH_NEW_WHISTLER_OBJECTS
|
|
)
|
|
);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
hr=reportActions (
|
|
file,
|
|
results.objectActions,
|
|
String::load(IDS_RPT_ACTIONS)
|
|
);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
hr=reportObjects (
|
|
file,
|
|
results.createW2KObjects,
|
|
String::load(IDS_RPT_CREATEW2K)
|
|
);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
hr=reportObjects (
|
|
file,
|
|
results.createWhistlerObjects,
|
|
String::load(IDS_RPT_CREATE_WHISTLER)
|
|
);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
hr=reportContainers(
|
|
file,
|
|
results.createContainers,
|
|
String::load(IDS_RPT_CONTAINERS)
|
|
);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
} while(0);
|
|
|
|
CloseHandle(file);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
} while(0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|