/*******************************************************************

Copyright (c) 2004 Open Mobile Alliance, Ltd.  All Rights Reserved.

This software is made available under the usage and distribution terms 
covered by the Common Public License 1.0 and by using this software you
are bound by the terms and conditions of the same.

EXCEPT AS EXPRESSLY SET FORTH IN THE COMMON PUBLIC LICENSE,
THIS PROGRAM IS PROVIDED ON AN "AS IS" BASIS, 
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, 
ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, 
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
   
Each recipient is solely responsible for determining the 
appropriateness of using and distributing this program and assumes 
all risks associated with its exercise of rights under the Common 
Public License, including but not limited to the risks and 
costs of program errors, compliance with applicable laws, 
damage to or loss of data, programs or equipment, and 
unavailability or interruption of operations.

********************************************************************/
#include "SctsDevManTestEngine.h"
#include "SctsDevManSession.h"
#include "SctsDevManDevice.h"
#include "SctsDevManTestClient.h"
#include "SctsDevManTestServer.h"
#ifdef __SCTS_USING_SCTS__
#include "string"
#include "time.h"
#define STAGE_INTERVAL 1000

/* test case prerequisites */
SctsDMTestPreReq sctsServerTestCasePreReqs[]=
{
	101,"Authentication",
	"To check if the Test Object implements 'Server Layer Authentication'. SCTS sends SyncHdr with wrong credentials.",
	"The Test Object MUST return a 401 status code on the SyncHdr",
	"UserID and Password should be configured for the DMAccount in use.",
	false,
	201,"Authentication",
	"To check if the Test Object implements 'Server Layer Authentication'. SCTS sends SyncHdr with no credentials.",
	"The Test Object MUST return a 407 status code on the first SyncHdr",
	"",
	false,
	202,"Authentication",
	"To check if the Test Object accepts the credentials sent and proceeds with the Sync Session.",
	"The Test Object MUST return either a 200 or 212 status code on the first/second SyncHdr.",
	"",
	false,
	203,"Replace",
	"To check if the Test Object processed the Replace command with devInfo without errors.",
	"The Test Object MUST return a 200 status code on the Replace.",
	"",
	false,
	204,"Alert",
	"To check if the Test Object processed the Alert command without errors.",
	"The Test Object MUST return a 200 status code on the Alert.",
	"",
	false,
	301,"Get",
	"To check if the Test Object generates a valid Get command on a existing interior node(Root Node, '.').",
	"SCTS should respond with a 200 status code on the Get.",
	"",
	false,
	401,"Add",
	"To check if the Test Object generates a valid Add command to add a leaf node(./SCTSValue).",
	"SCTS should respond with a 200 status code on the Add.",
	"",
	false,
	501,"Replace",
	"To check if the Test Object generates a valid Replace command to replace the contents of a leaf node(./SCTSValue).",
	"SCTS should respond with a 200 status code on the Replace.",
	"",
	false,
	601,"Delete",
	"To check if the Test Object generates a valid Delete command to delete a leaf node(./SCTSValue).",
	"SCTS should respond with a 200 status code on the Delete.",
	"",
	false,
	701,"Multiple Messages Test",
	"To check if the Test Object can handle multiple messages.",
	"The session MUST complete successfully.",
	"",
	false,
	801,"Sequence",
	"To check if the Test Object generates a valid Sequence command.Sequence should contain two Replace commands.",
	"SCTS should respond with a 200 status code on the Sequence.",
	"",
	false,
	901,"Atomic",
	"To check if the Test Object generates a valid Atomic command.Atomic should contain two Replace commands.",
	"SCTS should respond with a 200 status code on the Atomic.",
	"",
	false,
	1001,"Add Text Large Object",
	"To check if the Test Object can Add a text Large Object.(./SCTSLrgObjText).",
	"Successfully Add the text based large object that is larger than MaxMsgSize.Final status to Add should be 200.",
	"",
	false,
	1002,"Get Text Large Object",
	"To check if the Test Object can Get a text Large Object.(./SCTSLrgObjText).",
	"Successfully Get the text based large object.",
	"",
	false,
	1101,"Add Binary Large Object",
	"To check if the Test Object can Add a binary Large Object.(./SCTSLrgObjBin).",
	"Successfully Add the binary large object that is larger than MaxMsgSize.Final status to Add should be 200.",
	"",
	false,
	1102,"Get Binary Large Object",
	"To check if the Test Object can Get a binary Large Object.(./SCTSLrgObjBin).",
	"A binary large object that is larger than MaxMsgSize.",
	"",
	false,
	1201,"Session Abort Alert",
	"To check if the Test Object responds with a status after SCTS has sent a Session Abort Alert 1223.",
	"Response to Session Abort Alert MUST be 200.",
	"",
	false,
	1301,"Get (<URI>?list=Struct)",
	"To check if the Test Object can send a Get with '.?list=Struct' and handle the results correctly.",
	"SCTS should receive a valid Get and the Test Object should send status of 200 to all the results sent by SCTS.",
	"",
	false,
	1401,"Get (<URI>?list=StructData)",
	"To check if the Test Object can send a Get with '.?list=StructData' and handle the results correctly.",
	"SCTS should receive a valid Get and the Test Object should send status of 200 to all the results sent by SCTS.",
	"",
	false,
	1501,"UI Display Alert",
	"To check if the Test Object can send a UI Display Alert.",
	"SCTS should respond with a status code of 200 to the Alert.",
	"",
	false,
	1601,"UI Confirmation Alert",
	"To check if the Test Object can send a UI Confirmation Alert.",
	"SCTS should respond with a status code of 200/304 to the Alert.",
	"",
	false,
	1701,"UI User Input Alert",
	"To check if the Test Object can send a UI User Input Alert.",
	"SCTS should respond with a status code of 200 to the Alert.",
	"",
	false,
	1801,"Notification Session",
	"To check if the Test Object supports Notification Initiated Session using HTTP.",
	"The Test Object must verify the Notification HTTP headers and data format and connect to SCTS with a Alert of 1200.",
	"",
	false,
	1901,"Support of Generic alert",
	"To check if the Test Object can receive, parse and send status back to the Test Tool for a Generic alert 1226.",
	"The Test Object should respond with a status code of 200 or 202 to the Alert.",
	"",
	false,
	2001,"Support for sending and receiving Correlator",
	"To check if the Test Object can support sending and receiving a correlator.",
	"DM server is able to send exec including the correlator. SCTS returns 200 for a valid Exec command. DM Server returns a status code 200 or 202 in response to the Generic alert.",
	"",
	false,
	0,0,0,0,0,0
};

SctsDMTestPreReq sctsClientTestCasePreReqs[]=
{
	/* -- Removed by DM 1.2 ETS. -- */
	//101,"Authentication",
	//"To check if the Test Object supports the Basic authentication scheme. SCTS will challenge the Test Object for credentials in this scheme.",
	//"The Test Object MUST send valid credentials encoded using the Basic authentication scheme.",
	//"Incoming userid & password configured on SCTS should match those of the clients outgoing userid & password.",
	//false,
	101,"Alert",
	"To check if the Test Object sends valid Alert command.",
	"The Test Object MUST send valid Client Initiated Alert.",
	"",
	false,
	102,"Device Information",
	"To check if the Test Object sends Device Information",
	"The Test Object MUST send its Device Information in a Replace command",
	"",
	false,
	103,"Device ID",
	"To check if the client's Source LocURI is same as the value in ./DevInfo/DevId",
	"The value of Source LocURI in the SyncHdr sent by the client MUST be equal to the value sent in ./DevInfo/DevId",
	"",
	false,
	201,"Authentication",
	"To check if the Test Object can switch the authentication scheme based on the challenge(MD5).",
	"The Test Object MUST update its authentication scheme and send credentials using MD5 in the next session.",
	"",
	false,
	301,"Authentication",
	"To check if the Test Object supports the MD5 Digest authentication scheme.",
	"The Test Object MUST send valid credentials encoded using the MD5 Digest authentication scheme.",
	"Incoming userid & password configured on SCTS should match those of the clients outgoing userid & password.",
	false,
	302,"Get",
	"To check if the Test Object responds with a Results for a Get on the Root node.",
	"The Test Object MUST respond with a Results containing at least the following element: DevInfo, DevDetail, SyncML.",
	"SCTS should have ACL access rights for Get on the Root node.",
	false,
	303,"Get",
	"To check if the Test Object responds with a Results for a Get on a leaf node.",
	"The Test Object MUST respond with a Results.",
	"SCTS should have ACL access rights for Get on the leaf node.",
	false,
	304,"Get",
	"To check if the Test Object responds correctly for a Get on a non-existant node.",
	"The Test Object MUST return a 404 status code on the Get.",
	"",
	false,
	401,"Integrity",
	"To check if the Test Object uses HMAC scheme.",
	"The Test Object MUST send valid HMAC.",
	"The client should support HMAC and use a insecure transport.",
	false,
	501,"Add",
	"To check if a interior node can be Added to a client.",
	"The Test Object MUST return either a 200 or 405 status code.If the status code is 200,the new interior node MUST exist.",
	"The node MUST not exist on the device",
	false,
	502,"Add",
	"To check if a leaf node can be Added to a client.",
	"The Test Object MUST return a 200 status code and the new leaf node MUST exist.",
	"",
	false,
	503,"Add",
	"To check if the Test Object returns a status code of 418 (Already Exists) for a Add on a existing leaf node.",
	"The Test Object MUST return a 418 status code.",
	"Test case 501 should have passed with a 200 status code.",
	false,
	601,"Replace",
	"To check if the Test Object handles a Replace.",
	"The Test Object MUST return a 200 status code.",
	"",
	false,
	602,"Replace",
	"To check if the Test Object rejects a Replace on a non-existant node.",
	"The Test Object MUST return a 404 status code.",
	"",
	false,
	701,"Sequence",
	"To check if the Test Object handles the Sequence command correctly.",
	"The Test Object MUST behave according to the rules specified for Sequence.",
	"",
	false,
	801,"User Interaction Alert",
	"To check if the Test Object implements Confirmation User Interaction Alert command.",
	"The test object must accept the change and send a status of 200 status code on the Alert.",
	"",
	false,
	802,"User InteractionAlert",
	"To check if the Test Object implements Confirmation User Interaction Alert command.",
	"The test object must reject the change and send a status of 304 status code on the Alert.",
	"",
	false,
	901,"Delete",
	"To check if the Test Object deletes a interior node correctly.",
	"The Test Object MUST return either a 200/405 status code.",
	"There should be interior node configured under test node.",	
	false,
	902,"Delete",
	"To check if the Test Object sends a 404 status code for a Delete on a non-existant node.",
	"The Test Object MUST return a 404 status code.",
	"",
	false,
	903,"Delete",
	"To check if the Test Object rejects a delete on a Permanent node",
	"The Test Object MUST return a 405 status code.",
	"",
	false,
	1001,"Multiple Messages Test",
	"To check if the Test Object can handle multiple messages.",
	"The session MUST complete successfully.",
	"",
	false,
	1101,"Atomic",
	"To check if the Test Object handles the Atomic command correctly.",
	"The Test Object MUST return a 200 status code on the Atomic.",
	"",
	false,
	1201,"Standard Objects (DevInfo)",
	"To check if the structure of the ./DevInfo standard object is correct.",
	"The Results returned by the Test Object MUST contain the names of all the mandatory nodes under ./DevInfo seperated by /",
	"",
	false,
	1202,"Standard Objects (DevDetail)",
	"To check if the structure of the ./DevDetail standard object is correct.",
	"The Results returned by the Test Object MUST contain the names of all the mandatory nodes under ./DevDetail seperated by /",
	"",
	false,
	1203,"Standard Objects (DMAcc)",
	"To check if the structure of the DMAcc MO is correct.",
	"The Results returned by the Test Object MUST contain the names of all the mandatory nodes under  <Interior Node> separated by /",
	"",
	false,
	1301,"Get on ACL prop",
	"To check if the Root node has ACL.",
	"Response to Get on '.?prop=ACL' MUST be 200 and the Results must contain valid ACL .",
	"",
	false,
	1302,"Get on Format prop",
	"To check if Test Object supports Get on Format property on a Interior node('.')",
	"Status to Get on '.?prop=Format' MUST be 200 and the Results must contain the data 'node'.",
	"",
	false,
	1303,"Get on Type prop",
	"To check if Test Object supports Get on the Type property on a Interior node('.').",
	"Response to Get on '.?prop=Type' MUST be 200 and the Results must be null or point to DDF document.",
	"",
	false,
	1304,"Get on Size prop (interior)",
	"To check if the Test Object supports Get on the Size property on a Interior node('.').",
	"Status to Get on '.?prop=Size' MUST be a 406.",
	"",
	false,
	1305,"Get on Name prop",
	"To check if the Test Object supports Get on the Name property on a Interior node('./DevDetail/URI').",
	"Status to Get on '.DevDetail/URI?prop=Name' MUST be 200 and the Results must have the data as 'URI'.",
	"",
	false,
	1306,"Get on Size prop (leaf)",
	"To check if the Test Object supports Get on the Size property on a leaf node('./DevDetail/URI/MaxToTLen').",
	"Status to Get on '.DevDetail/URI?prop=Size' MUST be 200.",
	"",
	false,
	1307,"Replace on Name prop",
	"To check the behaviour of the Test Object for Replace on the Name property on a permanent node('./DevDetail').",
	"Status to Replace on '.DevDetail?prop=Name' MUST be 405.",
	"",
	false,
	1308,"Replace on ACL prop",
	"To check if the Test Object supports Replace on the ACL property on the interior test node.",
	"Status to Replace on the interior test node MUST be 200.",
	"An interior test node must be set prior to the execution of this test and there should be replace access rights for SCTS.",
	false,
	1401,"ACL Enforcement",
	"To check if the Test Object enforces ACL. SCTS replaces the ACL of the test interior node to 'Get=*&Add=*&Replace=*' and issues a Get and Delete command.",
	"SCTS should get a 200 status code for Get and 425 status code for Delete.",
	"SCTS should have replace access rights on the test interior node.",
	false,
	1501,"ACL Setting",
	"SCTS removes the Replace access right for the test interior node and tries to replace the ACL of a leaf node under the test interior node.",
	"SCTS should receive a 425 status code for the Replace.",
	"SCTS should have replace access right on the test interior node and this node should have atleast one leaf node as its child.",
	false,
	1601,"Delete",
	"To check if the Test Object deletes a leaf node correctly.",
	"The Test Object MUST return a 200/405 status code.",
	"The device should allow Adding and Deleting of nodes.There should be a leaf node under the test node.",	
	false,
	1701,"LrgObj Support",
	"To check if the Test Object supports Large Object Delivery Mechanism.SCTS issues a Get on ./DevDetail/LrgObj.",
	"SCTS should receive a status of 200 on Get and the result should contain a value of either 'true' or 'false'.",
	"",
	false,
	1702,"LrgObj Add",
	"To checks if the Test Object follows the Large Object Delivery rules.SCTS Adds a leaf node with a Large Object.",
	"SCTS should receive a status code of 200.",
	"This test is executed only if the Test Object indicates support for Large Object.",
	false,
	1703,"LrgObj Get",
	"To check if the Test Object can send Results with a Large Object.SCTS issues a Get on the Large Object node added by the previous test case.",
	"SCTS should receive a status code of 200 on the Get and valid results.",	
	"This test is executed only if Test Case 1702 successfully added a leaf node with Large Object.",
	false,
	1704,"MaxObjSize Check",
	"To check if the Test Object honors the server MaxObjSize.SCTS sends a small MaxObjSize and issues a Get on the Large Object added by Test case 1702.",
	"SCTS should receive a status code of 413.",
	"This test is executed only if Test Case 1702 successfully added a leaf node with Large Object.",
	false,
	1801,"Get (<URI>?list=Struct)",
	"To check if the Test Object can handle a Get with 'list=Struct'. SCTS issues a Get on './DevDetail?list=Struct'.",
	"SCTS should receive a status code of either 200/406. If status is 200, SCTS should receive valid results.",
	"",
	false,
	1901,"Get (<URI>?list=StructData)",
	"To check if the Test Object can handle a Get with 'list=Struct'. SCTS issues a Get on './DevDetail?list=StructData'.",
	"SCTS should receive a status code of either 200/406. If status is 200, SCTS should receive valid results.",
	"",
	false,
	2001,"Notification Session",
	"To check if the Test Object supports Notification Initiated Session using HTTP.",
	"The Test Object must verify the Notification HTTP headers and data format and connect to SCTS with a Alert of 1200.",
	"",
	false,
	2101,"Exec on a node with AccessType restriction",
	"To check if the Test Object returns 405 for an Exec on a node where AccessType property does not contain Exec.",
	"The Test Object MUST return a 405 status code.",
	"",
	false,
	2102,"Exec on an ACL protected node",
	"To check if the Test Object returns 425 for an Exec on an ACL protected node.",
	"The Test Object MUST return a 425 status code.",
	"",
	false,
	2201,"Checking Implicit Addition of Interior node/s",
	"To check if the Test Object supports implicit addition of parent interior nodes for an addition of a child node whose valid parent/parents does not exist in the DM Tree.",
	"The Test Object MUST return a 200 status code and the value of the newly Added child node.",
	"",
	false,
	2301,"Handling of Get with 'list=TNDS'",
	"To check if the Test Object can handle a Get with 'list=TNDS'.",
	"SCTS should receive valid results in TNDS format (including ACLs, Format and Value).",
	"",
	false,
	2401,"Handling of Copy command",
	"To check if the Test Object can handle the Copy command, It would be followed by a Get command on both the URI.",
	"DM Client returs a status 200 code for the copy. Results from the get commend at the source at the same as results for the get command at the target.",
	"",
	false,
	2501,"Support for Correlator",
	"To check if the DM Client can support receiving and processing a Correlator.",
	"Client returns 200 for the EXEC.",
	"",
	false,
	0,0,0,0,0,0
};

SctsDMTestGroup *SctsDMTestGroup::GetTestGroup(SctsDMDevice *device,int id)
{
	SctsDMTestGroup *nextTestGroup=new SctsDMTestGroup(device);

	if (device->IsServerDevice())
	{
		switch (id)
		{
		case 1:
			nextTestGroup->AddTestCase(new SctsDMTestCase101C);
			nextTestGroup->AddTestCase(new SctsDMTestCase102C);
			nextTestGroup->AddTestCase(new SctsDMTestCase103C);
			break;
		case 2:
			nextTestGroup->AddTestCase(new SctsDMTestCase201C);
			break;
		case 3:
			nextTestGroup->AddTestCase(new SctsDMTestCase301C);
			nextTestGroup->AddTestCase(new SctsDMTestCase302C);
			nextTestGroup->AddTestCase(new SctsDMTestCase303C);
			nextTestGroup->AddTestCase(new SctsDMTestCase304C);
			break;
		case 4:
			nextTestGroup->AddTestCase(new SctsDMTestCase401C);
			break;
		case 5:	
			nextTestGroup->AddTestCase(new SctsDMTestCase501C);
			nextTestGroup->AddTestCase(new SctsDMTestCase502C);
			nextTestGroup->AddTestCase(new SctsDMTestCase503C);
			break;
		case 6:		
			nextTestGroup->AddTestCase(new SctsDMTestCase601C);			
			nextTestGroup->AddTestCase(new SctsDMTestCase602C);			
			break;
		case 7:			
			nextTestGroup->AddTestCase(new SctsDMTestCase701C);
			break;
		case 8:			
			nextTestGroup->AddTestCase(new SctsDMTestCase801C);	
			nextTestGroup->AddTestCase(new SctsDMTestCase802C);				
			break;
		case 9:			
			nextTestGroup->AddTestCase(new SctsDMTestCase901C);
			nextTestGroup->AddTestCase(new SctsDMTestCase902C);
			nextTestGroup->AddTestCase(new SctsDMTestCase903C);
			break;
		case 10:
			nextTestGroup->AddTestCase(new SctsDMTestCase1001C);			
			break;		
		case 11:			
			nextTestGroup->AddTestCase(new SctsDMTestCase1101C);
			break;
		case 12:			
			nextTestGroup->AddTestCase(new SctsDMTestCase1201C);
			nextTestGroup->AddTestCase(new SctsDMTestCase1202C);
			nextTestGroup->AddTestCase(new SctsDMTestCase1203C);
			break;
		case 13:			
			nextTestGroup->AddTestCase(new SctsDMTestCase1301C);
			nextTestGroup->AddTestCase(new SctsDMTestCase1302C);
			nextTestGroup->AddTestCase(new SctsDMTestCase1303C);
			nextTestGroup->AddTestCase(new SctsDMTestCase1304C);
			nextTestGroup->AddTestCase(new SctsDMTestCase1305C);
			nextTestGroup->AddTestCase(new SctsDMTestCase1306C);
			nextTestGroup->AddTestCase(new SctsDMTestCase1307C);
			nextTestGroup->AddTestCase(new SctsDMTestCase1308C);
			break;
		case 14:
			nextTestGroup->AddTestCase(new SctsDMTestCase1401C);
			break;
		case 15:
			nextTestGroup->AddTestCase(new SctsDMTestCase1501C);
			break;
		case 16:
			nextTestGroup->AddTestCase(new SctsDMTestCase1601C);
			break;
		case 17:			
			nextTestGroup->AddTestCase(new SctsDMTestCase1701C);
			nextTestGroup->AddTestCase(new SctsDMTestCase1702C);
			nextTestGroup->AddTestCase(new SctsDMTestCase1703C);
			nextTestGroup->AddTestCase(new SctsDMTestCase1704C);
			break;
		case 18:			
			nextTestGroup->AddTestCase(new SctsDMTestCase1801C);
			break;
		case 19:			
			nextTestGroup->AddTestCase(new SctsDMTestCase1901C);
			break;
		case 20:			
			nextTestGroup->AddTestCase(new SctsDMTestCase2001C);
			break;	
		case 21:			
			nextTestGroup->AddTestCase(new SctsDMTestCase2101C);
			nextTestGroup->AddTestCase(new SctsDMTestCase2102C);
			break;	
		case 22:			
			nextTestGroup->AddTestCase(new SctsDMTestCase2201C);
			break;	
		case 23:			
			nextTestGroup->AddTestCase(new SctsDMTestCase2301C);
			break;	
		case 24:			
			nextTestGroup->AddTestCase(new SctsDMTestCase2401C);
			break;	
		case 25:			
			nextTestGroup->AddTestCase(new SctsDMTestCase2501C);
			break;	
		default:
			delete nextTestGroup;
			nextTestGroup=0;
		}
	}
	else
	{
		switch (id)
		{
		case 1:
			nextTestGroup->AddTestCase(new SctsDMTestCase101S);
			break;
		case 2:
			nextTestGroup->AddTestCase(new SctsDMTestCase201S);
			nextTestGroup->AddTestCase(new SctsDMTestCase202S);
			nextTestGroup->AddTestCase(new SctsDMTestCase203S);
			nextTestGroup->AddTestCase(new SctsDMTestCase204S);
			break;		
		case 3:
			nextTestGroup->AddTestCase(new SctsDMTestCase301S);
			break;
		case 4:
			nextTestGroup->AddTestCase(new SctsDMTestCase401S);
			break;
		case 5:
			nextTestGroup->AddTestCase(new SctsDMTestCase501S);
			break;
		case 6:
			nextTestGroup->AddTestCase(new SctsDMTestCase601S);
			break;
		case 7:
			nextTestGroup->AddTestCase(new SctsDMTestCase701S);
			break;
		case 8:
			nextTestGroup->AddTestCase(new SctsDMTestCase801S);
			break;
		case 9:
			nextTestGroup->AddTestCase(new SctsDMTestCase901S);
			break;
		case 10:
			nextTestGroup->AddTestCase(new SctsDMTestCase1001S);
			nextTestGroup->AddTestCase(new SctsDMTestCase1002S);
			break;
		case 11:
			nextTestGroup->AddTestCase(new SctsDMTestCase1101S);
			nextTestGroup->AddTestCase(new SctsDMTestCase1102S);
			break;
		case 12:
			nextTestGroup->AddTestCase(new SctsDMTestCase1201S);
			break;
		case 13:
			nextTestGroup->AddTestCase(new SctsDMTestCase1301S);
			break;
		case 14:
			nextTestGroup->AddTestCase(new SctsDMTestCase1401S);
			break;
		case 15:
			nextTestGroup->AddTestCase(new SctsDMTestCase1501S);
			break;
		case 16:
			nextTestGroup->AddTestCase(new SctsDMTestCase1601S);
			break;
		case 17:
			nextTestGroup->AddTestCase(new SctsDMTestCase1701S);
			break;
		case 18:
			nextTestGroup->AddTestCase(new SctsDMTestCase1801S);
			break;
		case 19:
			nextTestGroup->AddTestCase(new SctsDMTestCase1901S);
			break;
		case 20:
			nextTestGroup->AddTestCase(new SctsDMTestCase2001S);
			break;
		default:
			delete nextTestGroup;
			nextTestGroup=0;
		}
	} 
	return nextTestGroup;
}

void SctsDMTestGroup::AddTestCase(SctsDMTestCase *testCase)
{
	SCTSASSERT(testCase);
	testCases.push_back(testCase);
	testCase->testGroup=this;
}

void SctsDMTestGroup::StateInitiatePreBuild()
{
	std::list <SctsDMTestCase *>::iterator it;
	for (it=testCases.begin();it!=testCases.end();++it) 
	{
		if ((*it)->doneSIPreB) continue;
		(*it)->StateInitiatePreBuild();
	}
}

void SctsDMTestGroup::StateInitiatePostBuild()
{
	std::list <SctsDMTestCase *>::iterator it;
	for (it=testCases.begin();it!=testCases.end();++it) 
	{
		if ((*it)->doneSIPostB) continue;
		(*it)->StateInitiatePostBuild();
	}
}

void SctsDMTestGroup::StateInitiatePreProcess()
{
	std::list <SctsDMTestCase *>::iterator it;
	for (it=testCases.begin();it!=testCases.end();++it) 
	{
		if ((*it)->doneSIPreP) continue;
		(*it)->StateInitiatePreProcess();
	}
}

void SctsDMTestGroup::StateInitiatePostProcess()
{
	std::list <SctsDMTestCase *>::iterator it;
	for (it=testCases.begin();it!=testCases.end();++it) 
	{
		if ((*it)->doneSIPostP) continue;
		(*it)->StateInitiatePostProcess();
	}
}

void SctsDMTestGroup::StateManagePreBuild()
{
	std::list <SctsDMTestCase *>::iterator it;
	for (it=testCases.begin();it!=testCases.end();++it) 
	{
		if ((*it)->doneSMPreB) continue;
		(*it)->StateManagePreBuild();
	}
}

void SctsDMTestGroup::StateManagePostBuild()
{
	std::list <SctsDMTestCase *>::iterator it;
	for (it=testCases.begin();it!=testCases.end();++it) 
	{
		if ((*it)->doneSMPostB) continue;
		(*it)->StateManagePostBuild();
	}
}

void SctsDMTestGroup::StateManagePreProcess()
{
	std::list <SctsDMTestCase *>::iterator it;
	for (it=testCases.begin();it!=testCases.end();++it) 
	{
		if ((*it)->doneSMPreP) continue;
		(*it)->StateManagePreProcess();
	}
}

void SctsDMTestGroup::StateManagePostProcess()
{
	std::list <SctsDMTestCase *>::iterator it;
	for (it=testCases.begin();it!=testCases.end();++it) 
	{
		if ((*it)->doneSMPostP) continue;
		(*it)->StateManagePostProcess();
	}
}


void SctsDMTestGroup::StateTerminate()
{
	std::list <SctsDMTestCase *>::iterator it;
	for (it=testCases.begin();it!=testCases.end();++it) (*it)->StateTerminate();
	session=0;
}

SctsDMTestGroup::~SctsDMTestGroup()
{
	/* Delete test cases */
	while (testCases.begin()!=testCases.end())
	{
		delete *testCases.begin();
		testCases.pop_front();
	}
}

/******************************************************************
SctsDMTester Definition
******************************************************************/

/* Callback functions used to route the call to the test device object */

void sctsTestDeviceExecuteStageTest(SctsDMSession *session)
{
	if (session->tempDevice && session->tempDevice->tester)
		(session->tempDevice->tester)->ExecuteStageTest(session);
}

void sctsTestDeviceExecuteStageTerminate(SctsDMSession *session)
{
	if (session->tempDevice)
		(session->tempDevice->tester)->ExecuteStageTerminate(session);
}

SctsDMTestEngineState SctsDMTester::GetState()
{
	SctsDMTestEngineState _state;
	stateLock.Lock();
	_state=state;
	stateLock.Unlock();
	return _state;
}

void SctsDMTester::SetState(SctsDMTestEngineState _state)
{
	stateLock.Lock();
	state=_state;
	if (state==TE_TERMINATE)
	{
		if (!device || device->Lock(0) && sctsIsServer)
		{
			if (device) device->Unlock();
			state=TE_IDLE;
			if (uiCallback) 
			{
				Lock();
				(*uiCallback)(uiCallbackData,0);
				Unlock();
			}
		}
		/* Clean up */
		if (device)
		{
			if (nextTestGroup) delete nextTestGroup;
			nextTestGroup=0;
		}
	}
	stateLock.Unlock();
}

void SctsDMTester::SetNextTestGroupID(int _nextTestGroupID)
{
	SctsDMTestPreReq *_preReq;
	if (sctsIsServer)
		_preReq=sctsClientTestCasePreReqs;
	else
		_preReq=sctsServerTestCasePreReqs;
	for (;_preReq->id && _preReq->id/100!=_nextTestGroupID;++_preReq);
	if (_preReq->id)
		nextTestGroupID=_nextTestGroupID;
	else
		nextTestGroupID=1;
}

int SctsDMTester::GetNextTestGroupID()
{
	return nextTestGroupID;
}

void SctsDMTester::Save(FILE *fp)
{
	SctsDMTestInfo *_testInfo;
	fwrite(&sctsIsServer,sizeof(bool),1,fp);
	sctsFWriteString(__SCTS_TESTCASE_VER__,fp);
	sctsFWriteString(testNode,fp);
	sctsFWriteString(leaftestNode,fp);
	for (_testInfo=testInfo;_testInfo;_testInfo=_testInfo->next)
	{
		fputc(1,fp);
		fwrite(_testInfo,sizeof(SctsDMTestInfo),1,fp);
	}
	fputc(0,fp);
}

SctsDMTester::SctsDMTester(FILE *fp) 
{
	SctsDMTestPreReq *testPreReq;
	SctsDMTestInfo *_testInfo=0;
	char *testCaseVer;
	fread(&sctsIsServer,sizeof(bool),1,fp);
	testCaseVer=sctsFReadString(fp);
	testNode=sctsFReadString(fp);
	leaftestNode=sctsFReadString(fp);
	/* Test case versions dont match */
	if (sctsStrcmp(testCaseVer,__SCTS_TESTCASE_VER__))
	{
		if (sctsIsServer)
			testPreReq=sctsClientTestCasePreReqs;
		else
			testPreReq=sctsServerTestCasePreReqs;
		for (;testPreReq->id;++testPreReq)
		{
			if (!_testInfo)
			{
				testInfo=_testInfo=(SctsDMTestInfo *)sctsMalloc(sizeof(SctsDMTestInfo));
				while (fgetc(fp)) fread(_testInfo,sizeof(SctsDMTestInfo),1,fp);
			}
			else
				_testInfo=_testInfo->next=(SctsDMTestInfo *)sctsMalloc(sizeof(SctsDMTestInfo));
			_testInfo->id=testPreReq->id;
			_testInfo->timeStamp=0;
			_testInfo->next=0;
		}
	}
	else
	{
		while (fgetc(fp))
		{
			if (!_testInfo)
				testInfo=_testInfo=(SctsDMTestInfo *)sctsMalloc(sizeof(SctsDMTestInfo));
			else
				_testInfo=_testInfo->next=(SctsDMTestInfo *)sctsMalloc(sizeof(SctsDMTestInfo));
			fread(_testInfo,sizeof(SctsDMTestInfo),1,fp);
		}
	}
	uiCallbackData=0;
	uiCallback=0;
	lastTestGroupID=-1;
	nextTestGroupID=1;
	nextTestGroup=0;
	state=TE_IDLE;
}

SctsDMTester::SctsDMTester(SctsDMDevice *_device,char *_testNode) 
{
	SctsDMTestPreReq *testPreReq;
	SctsDMTestInfo *_testInfo=0;
	device=_device;
	lastTestGroupID=-1;
	nextTestGroupID=1;
	nextTestGroup=0;
	uiCallbackData=0;
	uiCallback=0;
	SetState(TE_IDLE);
	testNode=sctsStrdup(_testNode);
	leaftestNode=0;
	sctsIsServer=device->IsServerDevice();
	if (sctsIsServer) 
		testPreReq=sctsClientTestCasePreReqs;
	else
		testPreReq=sctsServerTestCasePreReqs;
	for (;testPreReq->id;++testPreReq)
	{
		if (!_testInfo)
			testInfo=_testInfo=(SctsDMTestInfo *)sctsMalloc(sizeof(SctsDMTestInfo));
		else
			_testInfo=_testInfo->next=(SctsDMTestInfo *)sctsMalloc(sizeof(SctsDMTestInfo));
		_testInfo->state=testPreReq->optional?TEST_OPTIONAL:NOT_TESTED;
		_testInfo->id=testPreReq->id;
		_testInfo->timeStamp=0;
		_testInfo->transport=UNKNOWN_TRANSPORT;
		_testInfo->proto=SYNCML_UNKNOWN;
		_testInfo->next=0;
	}
}

void SctsDMTester::ResetTests()
{
	SctsDMTestPreReq *testPreReq;
	SctsDMTestInfo *_testInfo=testInfo;
	if (sctsIsServer) 
		testPreReq=sctsClientTestCasePreReqs;
	else
		testPreReq=sctsServerTestCasePreReqs;
	for (;testPreReq->id && testInfo;++testPreReq)
	{
		_testInfo->state=testPreReq->optional?TEST_OPTIONAL:NOT_TESTED;
		_testInfo->timeStamp=0;
		_testInfo=_testInfo->next;		
	}
}
SctsDMTester::~SctsDMTester()
{
	SctsDMTestInfo *_testInfo;
	sctsFree(testNode);
	sctsFree(leaftestNode);
	while (testInfo)
	{
		_testInfo=testInfo->next;
		sctsFree(testInfo);
		testInfo=_testInfo;
	}
}

/* Used to initiate testing and set the callback function which is called at the end of testing */
void SctsDMTester::ExecuteTestGroup()
{
	device->sessionType=DMSESSION_TEST;
	ExecuteStageCheck();	
}

void SctsDMTester::ExecuteStageCheck()
{
	std::list <SctsDMTestCase *>::iterator it;
	/* Set stage */
	if (GetState()==TE_TERMINATE) 
	{
		ExecuteStageTerminate(0);
		return;
	}
	SetState(TE_STAGE_CHECK);

	/* Check if test group is selected */
	if (!nextTestGroupID)
	{
		ExecuteStageTerminate(0);
		return;
	}
	
	/* Construct the next test group object */
	SCTSASSERT(!nextTestGroup);
	nextTestGroup=SctsDMTestGroup::GetTestGroup(device,nextTestGroupID);
	SCTSASSERT(nextTestGroup);
	
	/* If test group is in sequence jump to stage 2 */
	if (nextTestGroupID==1) sequenceTimestamp=sctsGetTime();
	
	if (nextTestGroupID!=lastTestGroupID+1) sequenceTimestamp=sctsGetTime(); 

	/* Clear any notification devices */
	if (!device->IsServerDevice())
		SctsDMClientDevice::setNotificationDeviceParams(0,0);
	/* Currently pre-conditions have to be performed manually */
	bool preReqs=true;
	for (it=nextTestGroup->testCases.begin();it!=nextTestGroup->testCases.end();++it) 
	{
		if ((preReqs=(*it)->StatePreReq())==false) break;
	}
	if (device->IsServerDevice() || !SctsDMClientDevice::getNotificationDevice())
	{
		if (preReqs)
			ExecuteStageTest(0);
		else
			ExecuteStageTerminate(0);
	}
	else
		SetState(TE_STAGE_TEST);
}


void SctsDMTester::ExecuteStageTest(SctsDMSession *session)
{
	std::list <SctsDMTestCase *>::iterator it;
	
	/* Set stage */
	if (GetState()<=TE_TERMINATE) 
	{
		ExecuteStageTerminate(0);
		return;
	}
	SetState(TE_STAGE_TEST);
	
	if (uiCallback) 
	{
		Lock();
		(*uiCallback)(uiCallbackData,session);
		Unlock();
	}

	/* Create Client session */
	if (!sctsIsServer)
	{
		SctsDMClientSession *session=new SctsDMClientSession((SctsDMClientDevice *)device,((SctsDMClientDevice *)device)->encoding,sctsTestDeviceExecuteStageTerminate);
		nextTestGroup->session=session;
		session->testGroup=nextTestGroup;
		session->Create();
	}
}

void SctsDMTester::ExecuteStageTerminate(SctsDMSession *session)
{
	std::list<SctsDMCommand *>::iterator cmdIt;
	lastTestGroupID=nextTestGroupID;
    if (!nextTestGroup->HasPendingCases())
    {
        if (session && session->IsSuccessful()) SetNextTestGroupID(++nextTestGroupID);
    }
	/* Update test info */
	if (GetState()==TE_STAGE_TEST)
	{
		SctsDMTestInfo *_testInfo;
		std::list <SctsDMTestCase *>::iterator it;
		for (it=nextTestGroup->testCases.begin();it!=nextTestGroup->testCases.end();++it)
		{
			for (_testInfo=testInfo;_testInfo;_testInfo=_testInfo->next)
			{
				if (_testInfo->id==(*it)->GetID())
				{
					_testInfo->state=(*it)->GetState();
					_testInfo->timeStamp=sequenceTimestamp;
					_testInfo->transport=session->transport->GetType();
					_testInfo->proto=session->proto;
					break;
				}
			}
		}
	}
	/* Clear the commands list, if the device is a server */
	if (device->IsServerDevice() && !nextTestGroup->HasPendingCases())
	{
		while (!((SctsDMServerDevice *)device)->cmdList.empty())
		{
			cmdIt=((SctsDMServerDevice *)device)->cmdList.begin();
			delete (*cmdIt);
			((SctsDMServerDevice *)device)->cmdList.erase(cmdIt);
		}
	}
	/* Clean up */
	if (nextTestGroup && !nextTestGroup->HasPendingCases())
    {
        delete nextTestGroup;
	    nextTestGroup=0;
    }

	/* Set stage */
	SetState(nextTestGroup->HasPendingCases()?TE_STAGE_TEST:TE_IDLE);
	if (uiCallback)
	{
		Lock();
		(*uiCallback)(uiCallbackData,session);
		Unlock();
	}
	device->sessionType=nextTestGroup->HasPendingCases()?DMSESSION_TEST:DMSESSION_NORMAL;
}

void *SctsDMTester::SetUICallback(void *_uiCallbackData,void (*_uiCallback)(void *,SctsDMSession *),bool alreadyLocked)
{
	void *_temp;
	if (!alreadyLocked)
		Lock();
	_temp=uiCallbackData;
	uiCallbackData=_uiCallbackData;
	uiCallback=_uiCallback;
	if (!alreadyLocked)
		Unlock();
	return _temp;
}

void SctsDMTester::GenerateReport(char *fname)
{
	MD5_CTX md5Context;
	char md5Digest[16];
	char buffer[1000];
	char *tempStr;
	long fileLength;
	unsigned int passCnt=0;
	SctsDMTestInfo *_testInfo;
	SctsDMTestPreReq *_preReq;
	FILE *fp;
	
	char transport[][10]={"-","HTTP","HTTP","HTTP","OBEX/TCP","OBEX/TCP","OBEX/IR","OBEX/IR"};
	/* DMFINAL */
	char proto[][15]={"DM 1.1","DM 1.2","-"};

	if (!(fp=fopen(fname,"w"))) return;
	/* HTML Header */
	fprintf (fp,"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">");
	fprintf (fp,"<HTML>");
	fprintf (fp,"<HEAD>");
	fprintf (fp,"   <META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=iso-8859-1\">");
	fprintf (fp,"   <META NAME=\"Author\" CONTENT=\"SyncML\">");
	fprintf (fp,"   <META NAME=\"GENERATOR\" CONTENT=\"Mozilla/4.07 [en] (WinNT; I) [Netscape]\">");
	fprintf (fp,"   <TITLE>Report</TITLE>");
	fprintf (fp,"</HEAD>");
	fprintf (fp,"<BODY>");

	/* Report Header */
	fprintf (fp,"<B><FONT SIZE=+2><FONT FACE=\"Arial,Helvetica\">SyncML Conformance Test Suite Report</FONT></FONT></B>");
	fprintf (fp,"<BR><FONT FACE=\"Arial,Helvetica\"></FONT>&nbsp;");
	fprintf (fp,"<TABLE WIDTH=\"80%%\" >");
	fprintf (fp,"<TR>");
	fprintf (fp,"<TD WIDTH=\"20%%\"><B><FONT FACE=\"Arial,Helvetica\">SCTS Version</FONT></B></TD>");
	fprintf (fp,"<TD><FONT FACE=\"Arial,Helvetica\">%s</FONT></TD>",SCTS_VERSION);
	fprintf (fp,"</TR>");

	fprintf (fp,"<TR>");
	fprintf (fp,"<TD><B><FONT FACE=\"Arial,Helvetica\">Report Date</FONT></B></TD>");
	fprintf (fp,"<TD><FONT FACE=\"Arial,Helvetica\">%s ",_strdate(buffer));
	fprintf (fp,"%s</FONT></TD>",_strtime(buffer));

	/* Test object details */
	fprintf (fp,"</TR>");
	fprintf (fp,"</TABLE>");
	fprintf (fp,"<FONT FACE=\"Arial,Helvetica\"></FONT><B><FONT FACE=\"Arial,Helvetica\"></FONT></B>");
	fprintf (fp,"<P><B><FONT FACE=\"Arial,Helvetica\"><FONT SIZE=+1>Test Object Details</FONT></FONT></B>");
	fprintf (fp,"<BR><FONT FACE=\"Arial,Helvetica\"></FONT>&nbsp;");
	fprintf (fp,"<TABLE WIDTH=\"80%%\" >");

	fprintf (fp,"<TR>");
	fprintf (fp,"<TD WIDTH=\"20%%\"><B><FONT FACE=\"Arial,Helvetica\">Type</FONT></B></TD>");
	if (sctsIsServer)
		sctsStrcpy(buffer,"Client");
	else
		sctsStrcpy(buffer,"Server");
	fprintf (fp,"<TD><FONT FACE=\"Arial,Helvetica\">%s</FONT></TD>",buffer);
	fprintf (fp,"</TR>");

	fprintf (fp,"<TR>");
	fprintf (fp,"<TD WIDTH=\"20%%\"><B><FONT FACE=\"Arial,Helvetica\">Manufacturer</FONT></B></TD>");
	if (device && device->productCompany)
		sctsStrcpy(buffer,device->productCompany);
	else
		sctsStrcpy(buffer,"______________________________________");
	fprintf (fp,"<TD><FONT FACE=\"Arial,Helvetica\">%s</FONT></TD>",buffer);
	fprintf (fp,"</TR>");

	fprintf (fp,"<TR>");
	fprintf (fp,"<TD><B><FONT FACE=\"Arial,Helvetica\">Product Name</FONT></B></TD>");
	if (device && device->productName)
		sctsStrcpy(buffer,device->productName);
	else
		sctsStrcpy(buffer,"______________________________________");
	fprintf (fp,"<TD><FONT FACE=\"Arial,Helvetica\">%s</FONT></TD>",buffer);
	fprintf (fp,"</TR>");


	fprintf (fp,"<TR>");
	fprintf (fp,"<TD><B><FONT FACE=\"Arial,Helvetica\">Contact Person</FONT></B></TD>");
	if (device && device->productContact) 
		sctsStrcpy(buffer,device->productContact);
	else 
		sctsStrcpy(buffer,"______________________________________");
	fprintf (fp,"<TD><FONT FACE=\"Arial,Helvetica\">%s</FONT></TD>",buffer);
	fprintf (fp,"</TR>");
	fprintf (fp,"</TABLE>");

	/* Test results */
	fprintf (fp,"<BR><P><B><FONT FACE=\"Arial,Helvetica\"><FONT SIZE=+1>Test Results</FONT></FONT></B>");
	fprintf (fp,"<BR><FONT FACE=\"Arial,Helvetica\"></FONT>&nbsp;");
	fprintf (fp,"<TABLE BORDER WIDTH=\"80%%\" >");
	fprintf (fp,"<TR>");
	fprintf (fp,"<TD WIDTH=\"15%%\"><B><FONT FACE=\"Arial,Helvetica\">Test Case ID</FONT></B></TD>");
	fprintf (fp,"<TD WIDTH=\"15%%\"><B><FONT FACE=\"Arial,Helvetica\">Seq. Time</FONT></B></TD>");
	fprintf (fp,"<TD WIDTH=\"12%%\"><B><FONT FACE=\"Arial,Helvetica\">Transport</FONT></B></TD>");
	fprintf (fp,"<TD WIDTH=\"12%%\"><B><FONT FACE=\"Arial,Helvetica\">Protocol</FONT></B></TD>");
	fprintf (fp,"<TD ALIGN=LEFT><B><FONT FACE=\"Arial,Helvetica\">Description</FONT></B></TD>");
	fprintf (fp,"<TD WIDTH=\"15%%\"><B><FONT FACE=\"Arial,Helvetica\">Result</FONT></B></TD>");
	fprintf (fp,"</TR>");
	for (_testInfo=testInfo;_testInfo;_testInfo=_testInfo->next)
	{
		/* Test case id */
		sprintf(buffer,"%04d%c",_testInfo->id,sctsIsServer?'C':'S');
		fprintf (fp,"<TR>");
		fprintf (fp,"<TD WIDTH=\"15%%\"><FONT FACE=\"Arial,Helvetica\">%s</FONT></TD>",buffer);
		
		/* Sequence time stamp */
		if (_testInfo->state==NOT_TESTED || _testInfo->state==TEST_OPTIONAL)
			fprintf (fp,"<TD WIDTH=\"15%%\"><FONT FACE=\"Arial,Helvetica\">-</FONT></TD>");
		else
		{
			tempStr=sctsGetTimeStamp(false,_testInfo->timeStamp);
			fprintf (fp,"<TD WIDTH=\"15%%\"><FONT FACE=\"Arial,Helvetica\">%s</FONT></TD>",tempStr);
			sctsFree(tempStr);
		}
		fprintf (fp,"<TD WIDTH=\"12%%\"><FONT FACE=\"Arial,Helvetica\">%s</FONT></TD>",transport[_testInfo->transport]);
		fprintf (fp,"<TD WIDTH=\"12%%\"><FONT FACE=\"Arial,Helvetica\">%s</FONT></TD>",proto[_testInfo->proto]);
		
		/* Get test case description */
		if (sctsIsServer)
			_preReq=sctsClientTestCasePreReqs;
		else
			_preReq=sctsServerTestCasePreReqs;
		for (;_preReq->id && _preReq->id!=_testInfo->id;++_preReq);
		fprintf (fp,"<TD ALIGN=LEFT><FONT FACE=\"Arial,Helvetica\">%s</FONT></TD>",_preReq->desc);
		
		/* Test case result */
		switch(_testInfo->state)
		{
		case NOT_TESTED:
			sctsStrcpy(buffer,"Not Tested");
			break;
		case TEST_PASSED:
			sctsStrcpy(buffer,"Passed");
			++passCnt;
			break;
		case TEST_FAILED:
			sctsStrcpy(buffer,"Failed");
			break;
		case TEST_OPTIONAL:
			sctsStrcpy(buffer,"Optional Test");
			break;
		case NOT_SUPPORTED:
			sctsStrcpy(buffer,"Not Supported");
			break;

		}
		fprintf (fp,"<TD WIDTH=\"15%%\"><FONT FACE=\"Arial,Helvetica\">%s</FONT></TD>",buffer);
		fprintf (fp,"</TR>");
	}
	fprintf (fp,"</TABLE>");
	fprintf (fp,"<FONT FACE=\"Arial,Helvetica\"></FONT>");
	fprintf (fp,"</BODY>");
	fprintf (fp,"</HTML>");
	fclose(fp);

	/* Generate watermark */
	fp=fopen(fname,"r+b");
	fseek(fp,0,SEEK_END);
	fileLength=ftell(fp);
	fseek(fp,0,SEEK_SET);
	tempStr=(char *)sctsMalloc(fileLength+sizeof(int)+3);
	fread(tempStr,1,fileLength,fp);
	tempStr[fileLength]='S';
	tempStr[fileLength+1]='I';
	tempStr[fileLength+2]='C';
	fileLength+=3;
	sctsMemcpy(tempStr+fileLength,&passCnt,sizeof(int));
	fileLength+=sizeof(int);
		
	/* Create the digest */
	MD5Init(&md5Context);
	MD5Update(&md5Context,tempStr,fileLength);
	MD5Final(md5Digest,&md5Context);
	sctsFree(tempStr);
	
	/* Base64 Encode digest */
	passCnt=16;
	tempStr=sctsBase64Encode((unsigned char *)md5Digest,passCnt);
	fseek(fp,0,SEEK_END);
	fprintf(fp,"<!-- %s -->",tempStr);
	sctsFree(tempStr);
	fclose(fp);
}

#endif
