//
// $Id: RPMVersionCompareData.cpp,v 1.13 2005/08/10 17:06:39 bakerj Exp $
//
//****************************************************************************************//
// Copyright (c) 2005, The MITRE Corporation
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice, this list
//       of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright notice, this 
//       list of conditions and the following disclaimer in the documentation and/or other
//       materials provided with the distribution.
//     * Neither the name of The MITRE Corporation nor the names of its contributors may be
//       used to endorse or promote products derived from this software without specific 
//       prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
// SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
// OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//****************************************************************************************//

#include "RPMVersionCompareData.h"

//****************************************************************************************//
//								RPMVersionCompareData Class								  //	
//****************************************************************************************//
// Initialize the item Vector
sVector RPMVersionCompareData::items;

RPMVersionCompareData::RPMVersionCompareData(DOMElement *test)
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Initialize a new RPMVersionCompareData and populate with the node's data
	// -----------------------------------------------------------------------

	string testName = XmlCommon::GetElementName(test);
	if(testName.compare("rpmversioncompare_test") != 0)
		throw ProbeDataException("Error: RPMVersionCompareData() Invalid test node specified. Received: " + testName);

	//	Init the data members
	//	this->rpm_name = new ObjectElement();
	this->tested_epoch = new ObjectElement();
	this->tested_version = new ObjectElement();
	this->tested_release = new ObjectElement();
	this->installed_version = new DataElement();
	// i am having an odd error if i do not initialize this last. 
	// however, i now seem to hang when writing the sc file to disk
	this->rpm_name = new ObjectElement();        

	//	Call the parse node function
	ParseNode(test);

	// set the xmlns and schema location
	this->SetXmlnsAlias("redhat");
	this->SetXmlns("http://oval.mitre.org/XMLSchema/system_characteristics#redhat");
	this->SetSchemaLocation("http://oval.mitre.org/XMLSchema/system_characteristics#redhat redhat-system-characteristics-schema.xsd");
}

RPMVersionCompareData::RPMVersionCompareData()
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Initialize a new RPMVersionCompareData as an empty object.
	// -----------------------------------------------------------------------
	this->rpm_name = new ObjectElement();
	this->tested_epoch = new ObjectElement();
	this->tested_version = new ObjectElement();
	this->tested_release = new ObjectElement();
	this->installed_version = new DataElement();

	// set the xmlns and schema location
	this->SetXmlnsAlias("redhat");
	this->SetXmlns("http://oval.mitre.org/XMLSchema/system_characteristics#redhat");
	this->SetSchemaLocation("http://oval.mitre.org/XMLSchema/system_characteristics#redhat redhat-system-characteristics-schema.xsd");
}

RPMVersionCompareData::~RPMVersionCompareData()
{
	// -----------------------------------------------------------------------
	//	Abstract
	//
	//	Delete the data memebers
	// -----------------------------------------------------------------------
	
	delete this->rpm_name;
	delete this->tested_epoch;
	delete this->tested_version;
	delete this->tested_release;
	delete this->installed_version;
}

// ***************************************************************************************	//
//								Public members												//
// ***************************************************************************************	//
void RPMVersionCompareData::Write()
{
  // -----------------------------------------------------------------------
  //	Abstract
  //
  //	Create a new RPMVersionCompareData node and add it 
  //	to the dataDocument.
  //	
  // -----------------------------------------------------------------------
  
  	// Create a string representation of the item
	string item =  rpm_name->object + ":" + tested_epoch->object + ":" + tested_version->object + ":" + tested_release->object;
	// Ensure that the item has not already been written
	if(WroteItem(&items, item))
		return;

	//	Create a new item node
	DOMElement *rpmversioncompareItem = CreateNewItemNode(dataDocument, "rpmversioncompare_item");

	// Add the object element
	DOMElement *objectElm = XmlCommon::AddChildElement(dataDocument, rpmversioncompareItem, "object");

	// Add the status attribute to the object if not default value
	string strStatus = this->SwitchStatusType(this->objectStatus);
	if (strStatus.compare("exists") != 0)
		XmlCommon::AddAttribute(objectElm, "status", strStatus);

	//	Add the object elements
	AddObjectChildElement(dataDocument, objectElm, "name", this->rpm_name);
	AddObjectChildElement(dataDocument, objectElm, "tested_epoch", this->tested_epoch);
	AddObjectChildElement(dataDocument, objectElm, "tested_version", this->tested_version);
	AddObjectChildElement(dataDocument, objectElm, "tested_release", this->tested_release);
	
	// Add the data section if the object status is exists
	if(objectStatus == exists && !this->isPatternMatchObject) {
		DOMElement *dataElm = XmlCommon::AddChildElement(dataDocument, rpmversioncompareItem, "data");

		// Add data subelements
		AddDataChildElement(dataDocument, dataElm, "installed_version", this->installed_version);
	}

	// Add the new item to the data document
	InsertItem(dataDocument, rpmversioncompareItem, "rpmversioncompare_items");
}

// ***************************************************************************************	//
//								Private members												//
// ***************************************************************************************	//
void RPMVersionCompareData::ParseNode(DOMElement *test)
{
  // -----------------------------------------------------------------------
  //	Abstract
  //
  //	Parse the node gathering all data to populate this
  //	InetListeningServersData object. 
  //	Really just need to gather the Test id and the program name
  // -----------------------------------------------------------------------

	///////////////////////////////////////////////////////////////////////////
	//	Get the test id
	///////////////////////////////////////////////////////////////////////////
	testId = XmlCommon::GetAttributeByName(test, "id");
	if(testId.compare("") == 0)
		throw ProbeDataException("Error: Unable to find the 'id' attribute for a Red Hat RPMVersionCompareData test.");	

  	///////////////////////////////////////////////////////////////////////////
	//	Parse the node
	///////////////////////////////////////////////////////////////////////////
	// Get the object element
	DOMElement *object = XmlCommon::FindNodeNS(test, "object");
	if (object == NULL) {
		throw new ProbeDataException("Error: Unable to locate object section for test: " + testId + "\n");
	}

	// Loop over childern of the object node
	//	get a list of the child nodes and their values
	string childName	= "";
	string childValue	= "";
	string childOp		= "";

	DOMNodeList *objectChildren = object->getChildNodes();
	unsigned int index = 0;
	while(index < objectChildren->getLength()) {
		DOMNode *tmpNode = objectChildren->item(index);

		//	only concerned with ELEMENT_NODEs
		if (tmpNode->getNodeType() == DOMNode::ELEMENT_NODE) {
			DOMElement* objectChild = (DOMElement*)tmpNode;
			//	get the name of the child
			childName = XmlCommon::GetElementName((DOMElement*)objectChild);
			childValue = XmlCommon::GetDataNodeValue(objectChild);
			childOp = XmlCommon::GetAttributeByName(objectChild, "operator");
			
			// Convert the type
			objectTypes curType;
			if(childOp.compare("pattern match") == 0) {
				curType = pattern_match;
				this->isPatternMatchObject = true;
			} else {
				curType = literal;
			}
			
			//	Get the name value	
			if(childName.compare("name")== 0) {
			        rpm_name->object = childValue;
				rpm_name->type = curType;

			} else if(childName.compare("tested_epoch")== 0) {
				if(curType == pattern_match)
					throw ProbeDataException("Error: Pattern matching is not supported on tested_epoch for RPM Version Compare Tests.");

				tested_epoch->object = childValue;
				tested_epoch->type = curType;

			} else if(childName.compare("tested_version")== 0) {
				if(curType == pattern_match)
					throw ProbeDataException("Error: Pattern matching is not supported on tested_version for RPM Version Compare Tests.");

				tested_version->object = childValue;
				tested_version->type = curType;
			} else if(childName.compare("tested_release")== 0) {
				if(curType == pattern_match)
					throw ProbeDataException("Error: Pattern matching is not supported on tested_release for RPM Version Compare Tests.");

				tested_release->object = childValue;
				tested_release->type = curType;
			}
		}
		index ++;
	}
}

