Coding Sample

This program moves files from a Filenet Mezzanine Document Management Repository to a
web server, using Filenet's API to interface with the repository. It's another example of gaining,
an understanding of an environment through experimentation. The Filenet API documentation
was pretty good, but I had to play around with it for a few days to finally know what I
was doing. (Note that the free C++2HTML converter I used leaves some odd spacing at times.)

/*=      WEBUPDATE PROGRAM
 *							Allocate Search Request OAB
 *							Build Where, Show, Order Structures
 *							Find all Items where User is the Profile Originator
 *                  		Print each OAB using OABInfo and Object information calls
 *
 *	To make a new project for this program, using Dev Studio 97, just go to :
 *	File, New, Console Application.  Fill in the name and hit the Create button.
 *	In the project, go to : Build, Settings, Link Tab.
 *	Set Category to "General".  Add srs_mapi.lib to the end of the entries
 *	in the Object/library modules box.  That's it.

  TESTING IN NYC

  Comment out the set of #defines for MIAMI and restore the vals for NYC.
  The values for some of the custom properties and the competer and repository names need to be changed.

CHANGE LOG
======================
BB   9-25-1998  ADD CODE TO PUT THE EFFECTIVE DATE META TAG IN THE HTML FILE DURING
	         THE COPY OUT PROCESS.

 *=========================================================================*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <time.h>

/*
#if defined(WIN32)
#ifdef _MSC_VER
#pragma warning(disable:4514) // disable C4514 warning
#pragma warning(disable:4214) // disable C4214 warning
#pragma warning(disable:4201) // disable C4201 warning
#pragma warning(disable:4115) // disable C4115 warning
#endif	// _MSC_VER

#include <winbase.h>
#ifdef _MSC_VER
#pragma warning(default:4214) // enable 4214 warning
#pragma warning(default:4201) // enable 4201 warning
#pragma warning(default:4115) // enable 4115 warning
#endif
#endif /* WIN32 */


#include <windows.h>

#define SPI_INCLUDE_OBJECTS
#define SPI_INCLUDE_ATTRIBUTES
extern "C"
{
#include <spi.h>
#include <spi_sts.h>
#include <spi_obj.h>
#include <spi_attr.h>
}

// FUNCTION DECLARATIONS
int copyItemToIIS ( SPI_SCTX_HNDL sctx, char * itemID, char * fileName, char * ansSub, char * keywords, char * effDate );
int deleteItemFromIIS ( SPI_SCTX_HNDL sctx, char * itemID, char * fileName );
int queryKeywordObject(SPI_SCTX_HNDL sctx, char * itemID, char * folderNum, char * parentKeyName );
int extractParent(char * keywordName, char * folderNum);
int getFullPath ( SPI_SCTX_HNDL sctx, char * itemID,char * fileName, char * parentNum, char * retParentName,  char * fullPath );
int expireTheFile(SPI_SCTX_HNDL sctx, char * itemID, char * parentKeyName, char * parentNum, char * parentName, char * fullPath  ) ;
int getSystemTime ( char * runTime, char * fileNameTime);
int processMetaData( char * fullPath, char * metaTag, int numToSkip, char * propVal);
int updateFile(FILE * htmlFile, char * fullPath, char * propName, int NumToSkip, char * oldVal, char * newVal);
int insertMetaData(FILE * htmlFile, char * metaString, char * beforeString);
int insertAnsSub( FILE * oFile, char * ansSubVal, char * inString);
int changeDateFormat( char* filenetDate, char * date );
int editFullPath( char* fullPath, char * halfPath );
void killTime();
int getFolderNum ( SPI_SCTX_HNDL sctx, char * folderName, char * folderNum );

// CUSTOM PROPERTIES ARE PROP NUMBERS 282 - 301 IN THE ITEM OBJECT.  IN FILESHARE, IF YOU LOOK AT THE CUSTOM PROPERTIES
// LIST, THEY ARE NUMBERED FROM 1.  SO, 1 = 282, 2 = 283, ETC.
//  PROP                NYC			    VAL			MIAMI		VAL
// ===================  =======================		=======================
// EFFECTICE DATE       SPI_ITEM_CUSTOM05 -	286		SPI_ITEM_CUSTOM04 -	285
// ANS SUB              SPI_ITEM_CUSTOM01 -	282		SPI_ITEM_CUSTOM01 -	282
// KEYWORDS				SPI_ITEM_CUSTOM13 -	294		SPI_ITEM_CUSTOM07 -	288
// EXPIRATION DATE      SPI_ITEM_CUSTOM06 -	287		SPI_ITEM_CUSTOM05 -	286

//  NYC VALUES
//#define COMPUTER          		"server2"
//#define REPOSITORY        		"password"
//#define EFFECTIVE_DATE			286
//#define KEYWORDS				294
//#define EXPIRATION_DATE			287

//  MIAMI VALUES
#define COMPUTER          	"server1"
#define REPOSITORY        	"password"
#define EFFECTIVE_DATE		285
#define KEYWORDS			288
#define EXPIRATION_DATE		286

// open up the output files
FILE   *logFile;

FILE   *report;

FILE   *timeFile;

FILE   *bootUpLog;

int main( void	)
{

SPI_SCTX_HNDL			sctx;
char					username[SPI_MAXLEN_STRING+1] = "bob";
char					password[SPI_MAXLEN_STRING+1] ="bobspw";
char					catalog[SPI_MAXLEN_STRING+1] = REPOSITORY;
char					server[SPI_MAXLEN_STRING+1] = COMPUTER;


SPI_STATUS		  		status;
SPI_QUERY_HNDL			qhnd;
unsigned long			count;
SPI_OAB_HNDL			srOAB;
SPI_OAB_HNDL			rowOAB;
unsigned long	  		ii;
SPI_ATTR_NO		        selectList[SPI_MAX_QRY_SHOW];
SPI_QUERY_SELECTION     whereClause[SPI_MAX_QRY_SELECTIONS];
SPI_QUERY_SORT	        orderBy[SPI_MAX_QRY_SORT];
int						isMoreRows;
int						firstRow;
char 					keybuf[SPI_MAXLEN_ITEM + 1];
char					itemID[SPI_MAXLEN_STRING + 1];
char					ansSub[SPI_MAXLEN_ATTR + 1];
char					effDate[SPI_MAXLEN_ATTR + 1];
char					keywords[SPI_MAXLEN_ATTR + 1];
char					itemName[SPI_MAXLEN_ATTR + 1];
char					runTime[22];
char					fileNameTime[22];
char					timeLastRun[22];
char					logName[100] = "C:\\Program Files\\Acme\\KBAT Web Update\\Logs\\WebUpdateLog";
char					reportName[100] = "C:\\Program Files\\Acme\\KBAT Web Update\\Logs\\WebUpdateReport";
char					dotTxt[5] = ".txt";
int						numItemsUpdated = 0;
int						numItemsDeleted = 0;

// open up the output files

// The log and report file names include the system time.  Until the time is obtained, use boot up log.
bootUpLog = fopen("c:\\Program Files\\Acme\\KBAT Web Update\\Logs\\WebUpdateBootUpLog.txt","w");  // use boot up log till time is obtained

timeFile = fopen("c:\\program files\\Acme\\WebUpdateTimeLastRun.txt","r+");	 //  read-write
if (timeFile == NULL)
{
	fprintf ( bootUpLog,  "No c:\\program files\\Acme\\WebUpdateTimeLastRun.txt file.  Going to EOJ.\n");
	fflush( bootUpLog );
	fclose ( bootUpLog );
	return(1);
}
else
{
	fprintf ( bootUpLog,  "Good Time read.  Continuing on.  All further log messages written to the log file.\n");
	fflush( bootUpLog );

}


// Get the system time and save to write to the time last run file at EOJ
status = getSystemTime( runTime, fileNameTime );
if ( status!= 0) {
 		fprintf ( bootUpLog,  "Failed to get system time.  Going to EOJ.\n");
		fflush( bootUpLog );
		fclose ( bootUpLog );
		return(1);
}
else
{
	fprintf ( bootUpLog,  "Got system time : %s\n", runTime  );
	fflush( bootUpLog );
	fclose ( bootUpLog );
}

strcat ( logName, fileNameTime );
strcat ( reportName, fileNameTime );
strcat ( logName, dotTxt );
strcat ( reportName, dotTxt );

logFile = fopen( logName,"w" );
report = fopen( reportName,"w" );


// Get the time that the program ran last from the file
fgets( timeLastRun, 22, timeFile);

// set file	pointer back to start to overwrite previous date
//WRITE THE SYSTEM TIME TO THE TIME LAST RUN FILE AND CLOSE THE FILE
rewind(timeFile);
fputs( runTime, timeFile);
fclose(timeFile);
fprintf ( logFile,  "Got system time : %s\n", runTime  );
fflush( logFile );

fprintf ( logFile,  "Time last run was : %s\n", timeLastRun);
fflush( logFile );
fprintf ( report,  "Web Update \n"  );
fprintf ( report,  "================================\n"  );
fprintf ( report,  "System time : %s\n", runTime  );
fprintf ( report,  "Last run time : %s\n", timeLastRun  );
fflush( report );





#if defined (WIN32)
//================================================================
//	Win32 console mode apps must tell the filesystem to use the
//	OEM codepage for file operations.
//================================================================
	SetFileApisToOEM();
#endif /* WIN32 */


	//================================================================
	//LOGIN TO MEZZANINE REPOSITORY
	//================================================================
	status= spiSessionLogin( &sctx, username, password, catalog, server,
		".", NULL, NULL, 0, 0 );

	if ( status!= SPI_STS_SUCCESS ) {
 		fprintf ( logFile,  "Failed to login. Going EOJ. Status = %d\n", status);
		fflush( logFile );
		return(1);
	}
	fprintf(logFile,"Successfully logged in as %s\n", username );
	fflush(logFile);
	fprintf ( report,  "\n\nUpdated or Added These Files\n");
	fprintf ( report,  "===================================\n\n");
	fflush( report );


	//=====================================================================
	//SET UP TO SEARCH FOR THE ITEMS WITH AN EFFECTIVE DATE TODAY OR BEFORE
	//=====================================================================

	//OAB ALLOCATE FOR THE EFFECTIVE DATE SEARCH REQUEST OBJECT
  	status= spiOABAlloc( sctx, SPI_OBJ_SEARCH_REQUEST, &srOAB );

	if ( status!= SPI_STS_SUCCESS ) {
 		fprintf ( logFile,  "Search OAB Alloc for effective date. Going EOJ. status = %d\n", status);
		fflush( logFile );
		return(1);
	}

	//BUILD THE SELECT, WHERE AND ORDER CLAUSES FOR THE QUERY
    selectList[0] = SPI_ITEM_ID;					//ITEM ID
	selectList[1] = SPI_ITEM_ICON_TITLE;			//FILE NAME
	selectList[2] = SPI_ITEM_CUSTOM01;				//ANSWER SUBJECT
	selectList[3] = EFFECTIVE_DATE;			        //EFFECTIVE DATE
	selectList[4] = KEYWORDS;						//keywords


	selectList[5] = 0;
	status = spiOABAttrPut( sctx, srOAB, SPI_SR_SHOW, selectList );
	if ( status!= SPI_STS_SUCCESS ) {
 		fprintf ( logFile,  "OABAttrPut Failed-Select for effective date search, status = %d\n", status);
		fflush( logFile );
		spiOABFree( sctx, srOAB );
		return(1);
	}

	whereClause[0].andOrStop = SPI_ANDOR_START;
	whereClause[0].nestingLevel = 0;
	whereClause[0].attrNo = EFFECTIVE_DATE;					//effective date
	whereClause[0].relOp = SPI_RELOP_GE;
	strcpy( whereClause[0].value, timeLastRun);

	whereClause[1].andOrStop = SPI_ANDOR_AND;
	whereClause[1].nestingLevel = 0;
	whereClause[1].attrNo = EFFECTIVE_DATE;					//effective date
	whereClause[1].relOp = SPI_RELOP_LT;
	strcpy( whereClause[1].value, runTime);

	whereClause[2].andOrStop = SPI_ANDOR_STOP;
	whereClause[2].nestingLevel = 0;
	status = spiOABAttrPut( sctx, srOAB, SPI_SR_QUERY, whereClause );
	if ( status!= SPI_STS_SUCCESS ) {
 		fprintf ( logFile,  "OABAttrPut Failed-Where for effective date search, status = %d\n", status);
		fflush( logFile );
		spiOABFree( sctx, srOAB );
		return(1);
	}

	orderBy[0].attrNo = SPI_ITEM_ID;
	orderBy[0].ascDesc = SPI_QUERY_SORT_ASCENDING;
	orderBy[1].attrNo = 0;
	status = spiOABAttrPut( sctx, srOAB, SPI_SR_SORT, orderBy );
	if ( status!= SPI_STS_SUCCESS ) {
 		fprintf ( logFile,  "OABAttrBut Failed-Orderby for effective date search, status = %d\n", status);
		fflush( logFile );
		spiOABFree( sctx, srOAB );
		return(1);
	}

	//PARTIAL OAB ALLOCATE FOR THE SEARCH REQUEST OBJECT
	status= spiOABRowAlloc( sctx, srOAB, &rowOAB );
	if ( status!= SPI_STS_SUCCESS ) {
 		fprintf ( logFile,  "Search OAB Row Alloc Failed-effective date search, status = %d\n", status);
		fflush( logFile );
		spiOABFree( sctx, srOAB );
		return(1);
	}

	//=====================================================================
	//ISSUE THE SEARCH - THIS DO-WHILE IS THE MAIN PROCESSING LOOP
	//=====================================================================
	//THE QUERY WILL PPROBABLY RETURN MULTIPLE ROWS.
	//WE GRAB UP TO 100 ROWS AT A TIME.  PROCESS THEM AND THEN GRAB ANOTHER 100.
	//IN THE DO-WHILE LOOP. A FOR LOOP INSIDE THE DO-WHILE PROCESS THE ROWS
	//OF THE CURRENT RESULT SET.
	*keybuf = '\0';
	firstRow = 0;
	do
	{
		//ISSUE THE SEARCH.  IN THE DO-WHILE LOOP, GRAB UP TO 100 ROWS.
		//AT A TIME.  A STATUS = 52 MEANS > 100 ROWS SATISFIED THE QUERY
		//AND ANOTHER SEARCH REQUEST CALL WILL BE NEEDED.
		//THE FOR LOOP INSIDE THE DO-WHILE PROCESSES EACH ROW OF THE SET.
		status= spiQuerySearchRequest( sctx, srOAB, SPI_QUERY_FORWARD,
					keybuf, (unsigned long)200, &count, &qhnd );

		if ((status != SPI_STS_SUCCESS) && (status != SPI_STS_MORE_ROWS)) {
 			fprintf ( logFile,  "Query Search Request Failed-Effective date search, status = %d\n", status);
			fflush( logFile );
			spiQueryDone( sctx, qhnd );
			spiOABFree( sctx, srOAB );
			spiOABFree( sctx, rowOAB );
      		return(1);
   		}
		isMoreRows = (status == SPI_STS_MORE_ROWS);

		// fetch 100 rows at a time. After first time, don't show the first row.
		fprintf ( logFile, "Rows found-Effective Date search: %d%s\n", count,
				 ((firstRow == 0)? "" : "  (Note: Not displaying first row)") );
		fflush(logFile);

		//FOR LOOP BEGIN. READ EACH ROW AND PROCESS TILL NO MORE ROWS IN THE RESULT SET
		for ( ii = firstRow; ii < count; ii++ ) {
			status= spiQueryRow( sctx, ii, rowOAB, qhnd );
			if ( status!= SPI_STS_SUCCESS ) {
 				fprintf ( logFile,  "QueryRow Failed-Effective Date search, status = %d\n", status);
				fflush( logFile );
				spiQueryDone( sctx, qhnd );
				spiOABFree( sctx, srOAB );
				spiOABFree( sctx, rowOAB );
      			return(1);
	 		}
			// Get the values of the SPI_ITEM_ID, item name and Answer Subject props of the item.
			status = spiOABAttrGet( sctx, rowOAB, SPI_ITEM_ID, itemID, SPI_MAXLEN_STRING + 1 );
			status = spiOABAttrGet( sctx, rowOAB, SPI_ITEM_ICON_TITLE, itemName, SPI_MAXLEN_ATTR + 1 );
			status = spiOABAttrGet( sctx, rowOAB, SPI_ITEM_CUSTOM01, ansSub, SPI_MAXLEN_ATTR + 1 );
			status = spiOABAttrGet( sctx, rowOAB, EFFECTIVE_DATE, effDate, SPI_MAXLEN_ATTR + 1 );
			status = spiOABAttrGet( sctx, rowOAB, KEYWORDS, keywords, SPI_MAXLEN_ATTR + 1 );

			fprintf ( logFile,  "Item : %s  %s \n", itemID, itemName );
			fprintf ( logFile,  "	Answer sub : %s\n", ansSub );
			fprintf ( logFile,  "	Effective Date : %s\n", effDate);
			fflush(logFile);
			if ( status!= SPI_STS_SUCCESS ) {
 				fprintf ( logFile,  "Attr Get Failed-Effective Date search, status = %d\n", status);
				fflush( logFile );
				spiQueryDone( sctx, qhnd );
				spiOABFree( sctx, srOAB );
				spiOABFree( sctx, rowOAB );
      			return(1);
	 		}


			//=====================================================================
			//COPY THE ITEM TO THE IIS FILE STRUCTURE
			//=====================================================================

			status = copyItemToIIS( sctx, itemID, itemName, ansSub, keywords, effDate );	 //copy the item to IIS file system
			if (status > 0) {
				fprintf (logFile,"	Bad Copy - status : %d, moving on to next row\n", status);
				fflush(logFile);
				fprintf (report,"	*****Bad Copy - Check the log file - status : %d, moving on to next row\n", status);
				fflush(report);

			}
				else
			{
				numItemsUpdated++;
			}



		} //FOR LOOP END. THE LOOP PROCESSES EACH ROW OF THE RESULT SET


		//IF MORE ROWS, GET ANOTHER RESULT SET CONTAINING UP TO 100 ROWS.
		if (isMoreRows) { /* start next search from end of this one */
			spiOABAttrGet(sctx, rowOAB, SPI_ITEM_ID, keybuf, SPI_MAXLEN_ITEM+1);
			firstRow = 1;
		}

		// CLOSE THE QUERY AND RELEASE RESOURCES
		status= spiQueryDone( sctx, qhnd );
	}
	while (isMoreRows);

	// Write report total
	fprintf ( report,  "\n\n\nTotal items updated : %d\n", numItemsUpdated);
	fflush( report );


	//===================================================================================
	//END OF THE BIG DO-WHILE LOOP * ALL NEWW EFFECTIVE DATE ITEMS PUPROCESSED
	//===================================================================================
	//FREE THE OAB'S
	status= spiOABFree( sctx, srOAB );
	if ( status!= SPI_STS_SUCCESS ) {
 		fprintf ( logFile,  "OAB Free Failed, status = %d\n", status);
		fflush( logFile );
        return(1);
	}

	status= spiOABFree( sctx, rowOAB );
 	if ( status!= SPI_STS_SUCCESS ) {
 		fprintf ( logFile,  "OAB Free Failed, status = %d\n", status);
		fflush( logFile );
        return(1);
	}

//========================================================================================
//NOW DO THE DELETES
//===================================================================================
//===================================================================================
//===================================================================================
//===================================================================================
//===================================================================================
//===================================================================================
//===================================================================================
//===================================================================================

	fprintf ( report,  "\n\n\nDeleted These Files\n\n");
	fprintf ( report,  "==============================\n\n");
	fflush( report );

	//OAB ALLOCATE FOR THE EFFECTIVE DATE SEARCH REQUEST OBJECT
  	status= spiOABAlloc( sctx, SPI_OBJ_SEARCH_REQUEST, &srOAB );

	if ( status!= SPI_STS_SUCCESS ) {
 		fprintf ( logFile,  "Search OAB Alloc for EXPIRATION date, status = %d\n", status);
		fflush( logFile );
		return(1);
	}

	//BUILD THE SELECT, WHERE AND ORDER CLAUSES FOR THE QUERY
    selectList[0] = SPI_ITEM_ID;					//ITEM ID
	selectList[1] = SPI_ITEM_ICON_TITLE;			//FILE NAME
	selectList[2] = SPI_ITEM_CUSTOM01;				//ANSWER SUBJECT
	selectList[3] = 0;
	spiOABAttrPut( sctx, srOAB, SPI_SR_SHOW, selectList );
	if ( status!= SPI_STS_SUCCESS ) {
 		fprintf ( logFile,  "OABAttrPut Failed-Select for effective date search, status = %d\n", status);
		fflush( logFile );
		return(1);
	}

	whereClause[0].andOrStop = SPI_ANDOR_START;
	whereClause[0].nestingLevel = 0;
	whereClause[0].attrNo = EXPIRATION_DATE;
	whereClause[0].relOp = SPI_RELOP_GE;
	strcpy( whereClause[0].value, timeLastRun);


	whereClause[1].andOrStop = SPI_ANDOR_AND;
	whereClause[1].nestingLevel = 0;
	whereClause[1].attrNo = EXPIRATION_DATE;
	whereClause[1].relOp = SPI_RELOP_LT;
	strcpy( whereClause[1].value, runTime);

	whereClause[2].andOrStop = SPI_ANDOR_STOP;
	whereClause[2].nestingLevel = 0;
	spiOABAttrPut( sctx, srOAB, SPI_SR_QUERY, whereClause );
	if ( status!= SPI_STS_SUCCESS ) {
 		fprintf ( logFile,  "OABAttrPut Failed-Where for effective date search, status = %d\n", status);
		fflush( logFile );
		return(1);
	}

	orderBy[0].attrNo = SPI_ITEM_ID;
	orderBy[0].ascDesc = SPI_QUERY_SORT_ASCENDING;
	orderBy[1].attrNo = 0;
	spiOABAttrPut( sctx, srOAB, SPI_SR_SORT, orderBy );
	if ( status!= SPI_STS_SUCCESS ) {
 		fprintf ( logFile,  "OABAttrBut Failed-Orderby for effective date search, status = %d\n", status);
		fflush( logFile );
		return(1);
	}

	//PARTIAL OAB ALLOCATE FOR THE SEARCH REQUEST OBJECT
	status= spiOABRowAlloc( sctx, srOAB, &rowOAB );
	if ( status!= SPI_STS_SUCCESS ) {
 		fprintf ( logFile,  "Search OAB Row Alloc Failed-effective date search, status = %d\n", status);
		fflush( logFile );
		return(1);
	}

	//=====================================================================
	//ISSUE THE SEARCH - THIS DO-WHILE IS THE MAIN PROCESSING LOOP
	//=====================================================================
	//THE QUERY WILL PPROBABLY RETURN MULTIPLE ROWS.
	//WE GRAB UP TO 100 ROWS AT A TIME.  PROCESS THEM AND THEN GRAB ANOTHER 100.
	//IN THE DO-WHILE LOOP. A FOR LOOP INSIDE THE DO-WHILE PROCESS THE ROWS
	//OF THE CURRENT RESULT SET.
	*keybuf = '\0';
	firstRow = 0;
	do
	{
		//ISSUE THE SEARCH.  IN THE DO-WHILE LOOP, GRAB UP TO 100 ROWS.
		//AT A TIME.  A STATUS = 52 MEANS > 100 ROWS SATISFIED THE QUERY
		//AND ANOTHER SEARCH REQUEST CALL WILL BE NEEDED.
		//THE FOR LOOP INSIDE THE DO-WHILE PROCESSES EACH ROW OF THE SET.
		status= spiQuerySearchRequest( sctx, srOAB, SPI_QUERY_FORWARD,
					keybuf, (unsigned long)200, &count, &qhnd );

		if ((status != SPI_STS_SUCCESS) && (status != SPI_STS_MORE_ROWS)) {
 			fprintf ( logFile,  "Query Search Request Failed-Effective date search, status = %d\n", status);
			fflush( logFile );
      		return(1);
   		}
		isMoreRows = (status == SPI_STS_MORE_ROWS);

		// fetch 100 rows at a time. After first time, don't show the first row.
		fprintf ( logFile, "Rows found-EXPIRE Date search: %d%s\n", count,
				 ((firstRow == 0)? "" : "  (Note: Not displaying first row)") );
		fflush(logFile);

		//FOR LOOP BEGIN. READ EACH ROW AND PROCESS TILL NO MORE ROWS IN THE RESULT SET
		for ( ii = firstRow; ii < count; ii++ ) {
			status= spiQueryRow( sctx, ii, rowOAB, qhnd );
			if ( status!= SPI_STS_SUCCESS ) {
 				fprintf ( logFile,  "QueryRow Failed-EXPIRE Date search, status = %d\n", status);
				spiQueryDone( sctx, qhnd );
				spiOABFree( sctx, srOAB );
				spiOABFree( sctx, rowOAB );
				fflush( logFile );
      			return(1);
	 		}
			// Get the values of the SPI_ITEM_ID, item name and Answer Subject props of the item.
			spiOABAttrGet( sctx, rowOAB, SPI_ITEM_ID, itemID, SPI_MAXLEN_ATTR+1 );
			spiOABAttrGet( sctx, rowOAB, SPI_ITEM_ICON_TITLE, itemName, SPI_MAXLEN_ATTR+1 );

			fprintf ( logFile,  "Item : %s  %s \n", itemID, itemName );

			fflush(logFile);
			//=====================================================================
			//DELETE THE ITEM FROM THE IIS FILE STRUCTURE
			//=====================================================================

			status = deleteItemFromIIS( sctx, itemID, itemName );	 //copy the item to IIS file system
			if (status > 0) {
				fprintf (logFile,"	Bad Delete Item not expired - status : %d\n", status);
				fflush(logFile);
			}
			else
				numItemsDeleted++;

		} //FOR LOOP END. THE LOOP PROCESSES EACH ROW OF THE RESULT SET


		//IF MORE ROWS, GET ANOTHER RESULT SET CONTAINING UP TO 100 ROWS.
		if (isMoreRows) { /* start next search from end of this one */
			spiOABAttrGet(sctx, rowOAB, SPI_ITEM_ID, keybuf, SPI_MAXLEN_ITEM+1);
			firstRow = 1;
		}

		// CLOSE THE QUERY AND RELEASE RESOURCES
		status= spiQueryDone( sctx, qhnd );
	}
	while (isMoreRows);

	 fprintf ( report,  "\n\n\nTotal items deleted : %d\n", numItemsDeleted);
	 fflush( report );


	//===================================================================================
	//END OF THE BIG DO-WHILE LOOP * ALL ITEMS PROCESSED
	//===================================================================================
	//FREE THE OAB'S
	status= spiOABFree( sctx, srOAB );
		if ( status!= SPI_STS_SUCCESS ) {
 		fprintf ( logFile,  "OAB Free Failed, status = %d\n", status);
		fflush( logFile );
        return(1);
	}

	status= spiOABFree( sctx, rowOAB );
 	if ( status!= SPI_STS_SUCCESS ) {
 		fprintf ( logFile,  "OAB Free Failed, status = %d\n", status);
		fflush( logFile );
        return(1);
	}


	//LOGOUT FROM MEZZ AND GO TO END OF JOB
	spiSessionLogout( sctx );
	if ( status!= SPI_STS_SUCCESS ) {
 		fprintf ( logFile,  "Failed to logout, status = %d\n", status);
		fflush( logFile );
      return(1);
	}
	fprintf ( logFile,  "Successfully logged out as %s\n", username );
	fflush( logFile );
	flushall();
	fclose( logFile);
	fclose ( report);

	return 0;
}

//===================================================================================
//===================================================================================
//===================================================================================
//==============F U N C T I O N S						   ==========================
//===================================================================================
//===================================================================================
//===================================================================================


//***********************************************************************************
//		F U N C T I O N
//
//		copyItemToIIS
//
//		Params:  sctx - handle to the mezzanaine session
//				 itemID - string holding the item's id number
//				 ansSub - string holding the item's answer subject property
//      Function:
//		Copies the document to the local IIS file structure
//
//
//		We have the item number of the item to be copied out. We need the folder it is in so now we:
//			1. look in the Keyword_Object table to first get the folder num of the folder that contains the item.
//				  This folder will be referred to as the parent folder.
//				  This is done in a call to another function:queryKeywordObject. The keyword object
//				  contains just the parent folder number as shown in the table below.
//
//				 The structure of the Keyword object is:
//
//				 kw_e_name	(file number)		kw_name	   (folder number)
//			     -----------------				-----------------------------
//				 987120003						{MTISDM}11111111
//				  In this example, we have the item id.  We query on the keyword object to get the
//				     folder number of the folder where the item resides.
//				  To get the parent folder NAME ( we have the folder number now ), a query on
//				  the Custom Object is required.
//
//			2. Custom_object is shown below. co_key is the folder number and co_string2 is the folder
//				name.  co-string1 is the folder number of the parent of the folder.
//
//				The query exists in a loop and is executed for each folder in a file's
//				 full path, i.e. till the Root folder is reached.
//				 In this example
//
//			   	 The structure of the custom object is:
//
//				 co_key       co_string1           co_string2
//				--------	--------------------   -----------------------------
//				11111111	  22222222				Health_Bennies_Folder
//				22222222	  33333333				Benefits_Folder
//				33333333	  SDMROOT				CSR_Procedures_Folder
//
//			In this example, we have the folder number, 11111111, and we query the custon object for
//			   the folder name and the folder num where it in turn resides: 22222222.
//
//			Then the custom object is selected based on co_key = 11111111 and the name,
//			 Health_Bennies_Folder is added to the path and the next select is done
//			 based on co_key = 22222222, and so on till SDMROOT is reached.
//
//			3. Now we have the full path and filename, so do the copy.
//			C:\CSR_Procedures_Folder\Benefits_Folder\Health_Bennies_Folder\file.html
//***********************************************************************************
int copyItemToIIS ( SPI_SCTX_HNDL sctx, char * itemID, char * fileName, char * ansSub, char * keywords, char * effDate )
{
	SPI_STATUS				status;
	SPI_OAB_HNDL			checkoutOAB;
	char					parentNum[SPI_MAXLEN_STRING+1];
	char					parentName[SPI_MAXLEN_STRING+1]={""};
	char					parentKeyName[SPI_MAXLEN_STRING+1];
	char					fullPath[300] = "C:\\srvapps\\Inetsrv\\WWWRoot\\Self_Serv\\";
	char					halfPath[300] = "";
	char					date[11] = "";
	char					retParentName[SPI_MAXLEN_STRING+1]={""};
	//===================================================================================
	//Keyword Object Query returns folder num and parent key name of file's parent folder
	// parentNum is a string with a number in it - "2345". key name is like - {MTISDM}2345"
	//===================================================================================
	status = queryKeywordObject(sctx, itemID, parentNum, parentKeyName);
	if ( status!= SPI_STS_SUCCESS )
	{
 		fprintf ( logFile,  "	queryKeywordObject failed, status = %d\n", status);
		fflush( logFile );
		fprintf ( report,  "PROBLEM PROCESSING ITEM NUMBER %s - see LOG file - %s\n", itemID, fileName );
		fflush( report );
 		return(1);
	}





	fprintf ( logFile,  "	Back with parent num : %s\n", parentNum);
	fflush( logFile );

	//===================================================================================
	//Now get the full path of the item - fills in the fullPath string
	//===================================================================================
	status = getFullPath( sctx, itemID, fileName, parentNum, retParentName, fullPath );
	if ( status!= SPI_STS_SUCCESS )
	{
 		fprintf ( logFile,  "	getFullPath failed, status = %d\n", status);
		fflush( logFile );
		fprintf ( report,  "PROBLEM PROCESSING ITEM NUMBER %s - see LOG file - %s\n", itemID, fileName );
		fflush( report );
		return(1);
	}

	// Report the item
	status = editFullPath( fullPath,  halfPath );

	fprintf ( report,  "%s - %s\n", halfPath, itemID);
	fflush( report );


	// COPY THE ITEM OUT
	//Allocate the checkout OAB
	status = spiOABAlloc(sctx, SPI_OBJ_VERSION_CHECKOUT, &checkoutOAB);
	if(status != SPI_STS_SUCCESS)
	{
		fprintf ( logFile, "	Failed to allocate Checkout OAB, error = %x\n",status);
		fflush( logFile );
		return (1);
	}

	status = spiVersionCheckout ( sctx, itemID,"", checkoutOAB, fullPath, SPI_CHECKOUT_COPY|SPI_CHECKOUT_MAINLINE|SPI_CHECKOUT_OVERWRITE);
	if ( status!= SPI_STS_SUCCESS )
	{

 		fprintf ( logFile,  "	Copy out Failed, status = %d\n", status);
		fflush( logFile );
		fprintf ( report,  "	*****  Copy out Failed, status = %d\n", status);
		fflush( report );

		spiOABFree( sctx, checkoutOAB );
		return(1);
	}
	//else
	//{
	//	fprintf ( report,  "%s - %s\n", itemID, fullPath);
	//	fflush( report );
	//}


	//FREE THE OAB'S
	status= spiOABFree( sctx, checkoutOAB );
 	if ( status!= SPI_STS_SUCCESS ) {
 		fprintf ( logFile,  "	Checkout OAB Free Failed, status = %d\n", status);
		fflush( logFile );
        return(1);
	}

	// Insert props into the doc
	status = processMetaData( fullPath, "keywords", 19, keywords);
	if ( status > 0 ) {
 		fprintf ( logFile,  "	process keywords Failed, status = %d\n", status);
		fflush( logFile );
        return(7);
	}
	status = changeDateFormat( effDate, date );
	status = processMetaData( fullPath, "EFFECTIVE-DATE", 25, date);
	if ( status > 0 ) {
 		fprintf ( logFile,  "	process eff date Failed, status = %d\n", status);
		fflush( logFile );
        return(7);
	}
	status = processMetaData( fullPath, "NAME=\"ANSWER-SUBJECT", 29, ansSub);
	if ( status > 0 ) {
 		fprintf ( logFile,  "	process ans sub Failed, status = %d\n", status);
		fflush( logFile );
        return(7);
	}

	return (0);
} //Function end


//***********************************************************************************
//		F U N C T I O N
//
//		deleteItemFromIIS
//		GET THE PATH, DELETE FROM IT'S MEZZ FOLDER, ADD IT TO DEAD FOLDER, DEL FROM NT
//		Params:  sctx - handle to the mezzanaine session
//				 itemID - string holding the item's id number
//
//      Function:
//		1) Deletes the document from it's Mezzanine folder (custom object)
//		2) Adds the doc to the Expired Mezzanine folder
//		3) Deletes the file from the local IIS file structure
//
//***********************************************************************************
int deleteItemFromIIS ( SPI_SCTX_HNDL sctx, char * itemID, char * fileName )
{
	SPI_STATUS				status;
	BOOL					deleteStatus;
	char					parentNum[SPI_MAXLEN_STRING+1];
	char					parentNumSave[SPI_MAXLEN_STRING+1];
	char					parentName[SPI_MAXLEN_STRING+1]={""};
	char					retParentName[SPI_MAXLEN_STRING+1]={""};
	char					parentKeyName[SPI_MAXLEN_STRING+1]="";
	char					fullPath[300] = "C:\\srvapps\\Inetsrv\\WWWRoot\\Self_Serv\\";
	char					halfPath[300] = "";


	//===================================================================================
	//Keyword Object Query returns folder num of file's parent folder
	//===================================================================================
	status = queryKeywordObject(sctx, itemID, parentNum, parentKeyName );
	if ( status == 1)
	{	fprintf ( logFile,  "	%s - %s - Skipping this file.  It's in 2 places!!\n", fileName, itemID );
		fflush( logFile );
		fprintf ( report,  "%s - %s - Skipping this file.  It's in 2 places!!\n", fileName, itemID );
		fprintf ( report,  "	This file not expired.  Search in Mezz for 2 or more occurrences\n" );
		fflush( report );
		return(1);
	}


	fprintf ( logFile,  "	  %s, Parent Key Name : %s\n", parentNum, parentKeyName);
	fflush( logFile );
	strcpy ( parentNumSave, parentNum );        //  save it for call to expireTheFile

	//===================================================================================
	//Now get the full path of the item
	//===================================================================================

	status = getFullPath( sctx, itemID, fileName, parentNum, retParentName, fullPath );
	if ( status!= SPI_STS_SUCCESS )
	{
 		fprintf ( logFile,  "	getFullPath failed, status = %d\n", status);
		fflush( logFile );
		return(1);
	}

	// Report the item
	status = editFullPath( fullPath,  halfPath );

	fprintf ( report,  "%s - %s\n", halfPath, itemID);
	fflush( report );

	// Add item to expired folder and delete it from it's parent folder
	status =  expireTheFile(sctx, itemID, parentKeyName, parentNumSave, retParentName, fullPath );
	if ( status!= SPI_STS_SUCCESS )
	{
 		fprintf ( logFile,  "	expireTheFile failed, status = %d\n", status);
		fflush( logFile );
		fprintf ( report,  "	File not deleted from Mezz INFO.  status = %d\n", status);
		fflush( report );

		return(1);
	}

	// DELETE THE ITEM from the IIS Structure


	deleteStatus = DeleteFile(fullPath);
	if (deleteStatus)
	{
		fprintf ( logFile, "	deleted %s\n", fullPath);
		fflush( logFile );
		//status = editFullPath( fullPath,  halfPath );
 		//fprintf ( report,  "%s %s\n",  halfPath, itemID);
		//fflush( report );
	}
	else
	{
		fprintf ( logFile, "	Delete from IIS structure failed !!! Must not have been there to delete. %s\n", fullPath);
		fflush( logFile );
		fprintf ( report,  "	File not deleted from IIS INFO. Maybe it wasnt there in the first place.\n");
		fflush( report );

	}

	return (0);
} //Function end




//***********************************************************************************
//		F U N C T I O N
//
//		queryKeywordObject
//
//		Params:  sctx - handle to the mezzanine session
//				 &parentNum, a string ptr containing the parent folder's number only
//				 &parentKeyName - string hold whole folder key - "{MTISDM}12345"
//				 itemID - the item id of the document to be copied out
//
//		The table which corresponds to the keyword object, elem_kw, has a column
//		called kw_name, which contains the folder number.  The data in the column,
//		however has 2 parts.  The first is always the string "{MTISDM}".
//		The second part is the folder number.  The data in the colimn therefore
//		would look like "{MTISDM}1234", for folder number 1234.
//		The data base col is called kw_name and the corresponding API name is
//		SPI_KWRD_NAME.
// 		The query of the keyword object may return more that one row.
//		The row we're interested in is the one where the col SPI_KWRD_NAME
//		begins with the string '{MTISDM}'.
//
//		Two data items are returned for the calling function's consumption:
//		The 1234 is extracteded and put into a string the pointer to which is
//		passed between the functions.  The whole value is put in the string
//		parentKeyName.
//***********************************************************************************

int queryKeywordObject(SPI_SCTX_HNDL sctx, char * itemID, char * parentNum, char * parentKeyName )
{
	SPI_STATUS		  		status;
	SPI_QUERY_HNDL			qhnd;
	unsigned long			count;
	SPI_OAB_HNDL			srOAB;
	SPI_OAB_HNDL			rowOAB;
	SPI_ATTR_NO		        selectList[SPI_MAX_QRY_SHOW];
	SPI_QUERY_SELECTION     whereClause[SPI_MAX_QRY_SELECTIONS];
	char					keywordName[SPI_MAXLEN_ATTR+1];
	char 					keybuf[SPI_MAXLEN_ITEM+1];

 	/*	Allocate Search Request Object */
  	status= spiOABAlloc( sctx, SPI_OBJ_SEARCH_REQUEST, &srOAB );

	if ( status!= SPI_STS_SUCCESS ) {
 		fprintf ( logFile,  "	Search OAB Alloc failed - Keyword Search, status = %d\n", status);
		fflush( logFile );
		return(1);
	}

	//==================================================================
	//  Build Select, Where, and Order and put in Search OAB
	//  The SQL here is:
	//	select kw_e_name kw_name from elem_kw where
	//	kw_e_name = 'item id' and kw_name like '{MTISDM}'
	//==================================================================

    selectList[0] = SPI_KWRD_ITEM_ID;
	selectList[1] = SPI_KWRD_NAME;
	selectList[2] = 0;
	status = spiOABAttrPut( sctx, srOAB, SPI_SR_SHOW, selectList );
	if ( status!= SPI_STS_SUCCESS ) {
 		fprintf ( logFile,  "	Select OABAttrPut Failed-Keyword, status = %d\n", status);
		fflush( logFile );
		spiOABFree( sctx, srOAB );
		return(1);
	}

	// If more than one file with the same name existed, more than 1 row
	// with {MTISDM} indicator would be returned, but fot the KBAT set of
	// files, there should be no duplicated filenames.

	whereClause[0].andOrStop = SPI_ANDOR_START;
	whereClause[0].nestingLevel = 0;
	whereClause[0].attrNo = SPI_KWRD_ITEM_ID;
	whereClause[0].relOp = SPI_RELOP_EQ;
	strcpy( whereClause[0].value, itemID);
	whereClause[1].andOrStop = SPI_ANDOR_AND;
	whereClause[1].nestingLevel = 0;
	whereClause[1].attrNo = SPI_KWRD_NAME;
	whereClause[1].relOp = SPI_RELOP_LK;
	strcpy( whereClause[1].value, "{MTISDM}*");

	//whereClause[2].andOrStop = SPI_ANDOR_AND;
	//whereClause[2].nestingLevel = 0;
	//whereClause[2].attrNo = SPI_KWRD_NAME;
	//whereClause[2].relOp = SPI_RELOP_NL;
	//strcpy( whereClause[2].value, "{MTISDM}5*");

	whereClause[2].andOrStop = SPI_ANDOR_STOP;
	whereClause[2].nestingLevel = 0;
	spiOABAttrPut( sctx, srOAB, SPI_SR_QUERY, whereClause );
	if ( status!= SPI_STS_SUCCESS ) {
 		fprintf ( logFile,  "	Where OABAttrPut Failed-Keyword, status = %d\n", status);
		fflush( logFile );
		spiOABFree( sctx, srOAB );
		return(1);
	}


	/* Allocate Partial OAB to hold Search Request Results */
	status= spiOABRowAlloc( sctx, srOAB, &rowOAB );
	if ( status!= SPI_STS_SUCCESS ) {
 		fprintf ( logFile,  "	OAB Row Alloc Failed-Keyword, status = %d\n", status);
		fflush( logFile );
		spiOABFree( sctx, srOAB );
		return(1);
	}

	*keybuf = '\0';
	// Issue Search - status will == 52 if the result set contains > 1 row.
	// Should just get 1 row
	status= spiQuerySearchRequest( sctx, srOAB, SPI_QUERY_FORWARD,
					keybuf, (unsigned long)1, &count, &qhnd );
	if ((status ==  SPI_STS_MORE_ROWS)) {
			fprintf ( logFile,  "	Keyword Object Query Returned more than 1 row : Item is in more than 1 folder\n");
			fflush( logFile );
			//fprintf ( report,  "	******Oops!! Item is in more than 1 folder - skip it. Count is %d\n", count);
			//fflush( report );
			spiQueryDone( sctx, qhnd );
			spiOABFree( sctx, srOAB );
			spiOABFree( sctx, rowOAB );
      		return(1);
   	}
	if (status != SPI_STS_SUCCESS)  {
 			fprintf ( logFile,  "	spiQuerySearchRequest Failed-Keyword, status = %d\n", status);
			fflush( logFile );
			spiQueryDone( sctx, qhnd );
			spiOABFree( sctx, srOAB );
			spiOABFree( sctx, rowOAB );
      		return(1);
   	}
	status= spiQueryRow( sctx, (unsigned long)0, rowOAB, qhnd );
   	if ( status!= SPI_STS_SUCCESS ) {
 		fprintf ( logFile,  "	spiQueryRow Failed-Keyword, status = %d\n", status);
		fflush( logFile );
		spiQueryDone( sctx, qhnd );
		spiOABFree( sctx, srOAB );
		spiOABFree( sctx, rowOAB );
     	return(1);
	}
	// AttrGet return the value of the SPI_KWRD_NAME property of the object
	status = spiOABAttrGet( sctx, rowOAB, SPI_KWRD_NAME, keywordName, SPI_MAXLEN_ATTR+1 );
	if ( status!= SPI_STS_SUCCESS ) {
 		fprintf ( logFile,  "	attr get Failed-Keyword name, status = %d\n", status);
		fflush( logFile );
		spiQueryDone( sctx, qhnd );
		spiOABFree( sctx, srOAB );
		spiOABFree( sctx, rowOAB );
     	return(1);
	}

	fprintf ( logFile,  "	Keyword Name : %s\n", keywordName);
	flushall();

	strcpy ( parentKeyName, keywordName);

	extractParent( keywordName, parentNum);	   // isolate the folder number in parentNum
	fprintf ( logFile,  "	in keyword to get parent : %s\n", parentNum);
	fflush( logFile );

	// FREE THE QUERY RESOURCES
	status= spiQueryDone( sctx, qhnd );

	//FREE THE OAB'S
	status= spiOABFree( sctx, srOAB );
	if ( status!= SPI_STS_SUCCESS ) {
 		fprintf ( logFile,  "	OAB search Free Failed-Keyword, status = %d\n", status);
		fflush( logFile );

	}

	status= spiOABFree( sctx, rowOAB );
 	if ( status!= SPI_STS_SUCCESS ) {
 		fprintf ( logFile,  "	OAB row Free Failed-Keyword, status = %d\n", status);
		fflush( logFile );
        return(1);
	}

	return (0);
} //end queryKeywordObject function


//***********************************************************************************
//		F U N C T I O N
//
//		getFullPath
//		Get the full path of the item
//		Params:  sctx - handle to the mezzanaine session
//				 itemID - string holding the item's id number
//				 &fullPath - pointer to the string of the full path
//      Function:
//		1)
//
//***********************************************************************************
int getFullPath ( SPI_SCTX_HNDL sctx, char * itemID, char * fileName, char * parentNum, char * retParentName, char * fullPath )
{
	SPI_STATUS				status;
	SPI_QUERY_HNDL			qhnd;
	unsigned long			count;
	SPI_OAB_HNDL			srOAB;
	SPI_OAB_HNDL			rowOAB;
	SPI_ATTR_NO		        selectList[SPI_MAX_QRY_SHOW];
	SPI_QUERY_SELECTION     whereClause[SPI_MAX_QRY_SELECTIONS];
	int						ptr;
	int						i,j;
	char					parentName[SPI_MAXLEN_STRING + 1]={""};
	char					parentNameLong[SPI_MAXLEN_ATTR + 1]={""};
	char					key[SPI_MAXLEN_STRING+1];
	char					path[50][300];		 //array to hold the full path: 50, 300 char strings
	char					whackwhack[3] = "\\";
	char					*pPtr;              // ptr to short parent within long parent name
	int nameLen = 0;
	int firstTimeThru = 1;
	// null out the path array
	for ( i=0; i < 50; i++ )
	{
		for ( j=0; j<300; j++ )
		{
			path[i][j] = NULL;
		}
	}

	// put the filename in array position 0
	strcpy(path[0],fileName);
	ptr=1;	 // Array pos 0 holds the filename. 1 and up will hold the folder names in the path.


	//===================================================================================
	//Custom Object query. Build the full path, getting each successive parent folder.
	//===================================================================================

	// while the parent num not = sdmroot
	while (strcmp(parentNum, "SDMROOT"))   // returns 0 if the 2 strings are =
	{
		//Allocate Search Request Object
  		status= spiOABAlloc( sctx, SPI_OBJ_SEARCH_REQUEST, &srOAB );
		if ( status!= SPI_STS_SUCCESS ) {
 			fprintf ( logFile,  "	CUSTOM OBJ SEARCH OAB Alloc failed, status = %d\n", status);
			fflush( logFile );
			return(1);
		}

		//Build Select, Where, and Order and put in Search OAB
		selectList[0] = SPI_CO_ISV_ID;			// Must include this in select on custom table!!!!!
		selectList[1] = SPI_CO_OBJECT_TYPE;
		selectList[2] = SPI_CO_KEY;				// folder num
		selectList[3] = SPI_CO_STRING1;			// key of the folder's parent
		selectList[4] = SPI_CO_STRING2;			// folder	name
		selectList[5] = SPI_CO_LONG_STRING1;	// comment field in properties dialog box, holds long folder name
		selectList[6] = 0;						// folder names in co-string1 & 2 limited to 32 chars

		spiOABAttrPut( sctx, srOAB, SPI_SR_SHOW, selectList );
		if ( status!= SPI_STS_SUCCESS ) {
 			fprintf ( logFile,  "	Select OABAttrPut Failed-Custom, status = %d\n", status);
			fflush( logFile );
			spiOABFree( sctx, srOAB );
			return(1);
		}

		whereClause[0].andOrStop = SPI_ANDOR_START;
		whereClause[0].nestingLevel = 0;
		whereClause[0].attrNo = SPI_CO_KEY;
		whereClause[0].relOp = SPI_RELOP_EQ;
		strcpy( whereClause[0].value, parentNum);
		whereClause[1].andOrStop = SPI_ANDOR_STOP;
		whereClause[1].nestingLevel = 0;
		spiOABAttrPut( sctx, srOAB, SPI_SR_QUERY, whereClause );
		if ( status!= SPI_STS_SUCCESS ) {
 			fprintf ( logFile,  "	Where OABAttrPut Failed-Custom, status = %d\n", status);
			fflush( logFile );
			spiOABFree( sctx, srOAB );
			return(1);
		}

		// Allocate Partial OAB to hold Search Request Result set

		status= spiOABRowAlloc( sctx, srOAB, &rowOAB );
		if ( status!= SPI_STS_SUCCESS ) {
  			fprintf ( logFile,  "	ROW OAB Alloc Failed-Custom , status = %d\n", status);
			fflush( logFile );
			spiOABFree( sctx, srOAB );
			return(1);
		}

		// Issue Search - status will == 52 if the result set contains > 1 row.
		// Should just get 1 row
		status= spiQuerySearchRequest( sctx, srOAB, SPI_QUERY_FORWARD,
				NULL, (unsigned long)100, &count, &qhnd );
		if ((status ==  SPI_STS_MORE_ROWS)) {
 			fprintf ( logFile,  "	Custom Object Query Returned more than 1 row, status = %d\n", status);
			fflush( logFile );
			spiQueryDone( sctx, qhnd );
			spiOABFree( sctx, srOAB );
			spiOABFree( sctx, rowOAB );
      		return(1);
   		}
		if (status != SPI_STS_SUCCESS)  {
 			fprintf ( logFile,  "	Custom Query Search Request Failed, status = %d\n", status);
			fflush( logFile );
			spiQueryDone( sctx, qhnd );
			spiOABFree( sctx, srOAB );
			spiOABFree( sctx, rowOAB );
      		return(1);
   		}

		// GOOD SELECT.  NOW ACCESS THE DATA AND ADD IT TO THE PATH
		status= spiQueryRow( sctx, (unsigned long)0, rowOAB, qhnd );
		if ( status!= SPI_STS_SUCCESS ) {
 			fprintf ( logFile,  "	spiQueryRow Failed-Custom, status = %d\n", status);
			fflush( logFile );
			spiQueryDone( sctx, qhnd );
			spiOABFree( sctx, srOAB );
			spiOABFree( sctx, rowOAB );
     		return(1);
		}


		// CALL AttrGet TO GET THE VALUES OF THE 4 SELECTED PROPERTIES OF THE CUSTOM OBJECT
		spiOABAttrGet( sctx, rowOAB, SPI_CO_KEY, key, SPI_MAXLEN_STRING + 1 );
		if ( status!= SPI_STS_SUCCESS ) {
 			fprintf ( logFile,  "	spiAttrGet Failed-SPI_CO_KEY, status = %d\n", status);
			fflush( logFile );
			spiQueryDone( sctx, qhnd );
			spiOABFree( sctx, srOAB );
			spiOABFree( sctx, rowOAB );
     		return(1);
		}
		fprintf ( logFile,  "	Key : %s\n", key);
		flushall();

		spiOABAttrGet( sctx, rowOAB, SPI_CO_STRING1, parentNum, SPI_MAXLEN_STRING + 1 );
		if ( status!= SPI_STS_SUCCESS ) {
 			fprintf ( logFile,  "	spiAttrGet Failed-SPI_CO_STRING1, status = %d\n", status);
			fflush( logFile );
			spiQueryDone( sctx, qhnd );
			spiOABFree( sctx, srOAB );
			spiOABFree( sctx, rowOAB );
     		return(1);
		}
		fprintf ( logFile,  "	Parent # Str1 : %s\n", parentNum);
		flushall();

		spiOABAttrGet( sctx, rowOAB, SPI_CO_STRING2, parentName, SPI_MAXLEN_STRING + 1 );
		if ( status!= SPI_STS_SUCCESS ) {
 			fprintf ( logFile,  "	spiAttrGet Failed-SPI_CO_STRING2, status = %d\n", status);
			fflush( logFile );
			spiQueryDone( sctx, qhnd );
			spiOABFree( sctx, srOAB );
			spiOABFree( sctx, rowOAB );
     		return(1);
		}
		fprintf ( logFile,  "	Parent Name Str2 : %s\n", parentName);
		flushall();
		//  BB 5/25/1999
		//  first time thru the whiule loop, it gets the folder where the file resides, ie the end of the path
		// before the file name.  Return this value to the calling function.
		if ( firstTimeThru )
		{
			strcpy (retParentName , parentName );
		    firstTimeThru = 0;
		}
   		spiOABAttrGet( sctx, rowOAB, SPI_CO_LONG_STRING1, parentNameLong, SPI_MAXLEN_ATTR + 1 );
		if ( status!= SPI_STS_SUCCESS ) {
 			fprintf ( logFile,  "	spiAttrGet Failed-SPI_CO_STRING2, status = %d\n", status);
			fflush( logFile );
			spiQueryDone( sctx, qhnd );
			spiOABFree( sctx, srOAB );
			spiOABFree( sctx, rowOAB );
     		return(1);
		}
		fprintf ( logFile,  "	Parent Name long: %s\n", parentNameLong );
		flushall();


		// Put the folder name in the path array
		// If the folder has a name longer than 32 chars, the full name (not truncated at 32) is in the
		// co_long_string1 column of the custom table.  This field is accessed by the users as the comment
		// field in ghe folder properties dialog box.
		//  We do a strstr here to see if the short name is in the long name filed as a way to check
		// if there is anything in the long name field.  That way, if someone types something in the
		// comment field as a comment  , we wont mistake it for a long file name.
		// if there is a long file name, use it, instead of the truncated name, to build the path.

		pPtr = strstr(parentNameLong, parentName );	   // pPtr points to short parent in the string
		if ( pPtr == NULL )
		{
		     strcpy(path[ptr], parentName);
	 		 ptr++;
	 	}
		else
		{
			 nameLen = strlen(parentNameLong);
			 strcpy(path[ptr], parentNameLong);
			 ptr++;
		}



		//CLOSE QUERY AND FREE RESOURCES
		status= spiQueryDone( sctx, qhnd );
		if ( status!= SPI_STS_SUCCESS ) {
 			fprintf ( logFile,  "	query done Failed-Custom, status = %d\n", status);
			fflush( logFile );
			spiOABFree( sctx, srOAB );
			spiOABFree( sctx, rowOAB );
     		return(1);
		}
		//FREE THE OAB RESOURCES
		status= spiOABFree( sctx, srOAB );
		if ( status!= SPI_STS_SUCCESS ) {
 			fprintf ( logFile,  "	Search OAB Free Failed-Custom, status = %d\n", status);
			fflush( logFile );
			spiOABFree( sctx, rowOAB );
     		return(1);
		}
		status= spiOABFree( sctx, rowOAB );
		if ( status!= SPI_STS_SUCCESS ) {
 			fprintf ( logFile,  "	Row OAB Free Failed-Custom, status = %d\n", status);
			fflush( logFile );
			return(1);
		}


	} // LOOP TO TOP IF NOT AT THE ROOT OF THE PATH YET


	//FREE THE OAB RESOURCES
	//status= spiOABFree( sctx, srOAB );
	//if ( status!= SPI_STS_SUCCESS ) {
 //			fprintf ( logFile,  "	Search OAB Free Failed-Custom, status = %d\n", status);
//			fflush( logFile );
//			spiOABFree( sctx, rowOAB );
  //   		return(1);
	//}
//	status= spiOABFree( sctx, rowOAB );
//	if ( status!= SPI_STS_SUCCESS ) {
 //			fprintf ( logFile,  "	Row OAB Free Failed-Custom, status = %d\n", status);
//			fflush( logFile );
//			return(1);
//	}

	// BUILD THE FULL PATH FROM THE PATH ARRAY
	ptr--;
	for ( i=ptr; i>-1; i-- )
	{
		strcat( fullPath, path[i] );
		if ( i > 0 )
		{
			strcat( fullPath, whackwhack );
		}
	}

	fprintf ( logFile,  "	Full path : %s\n", fullPath);
	fflush( logFile );

	return (0);

}  //  getFullPath  function end






//***********************************************************************************
//		F U N C T I O N
//
//		extractParent
//
//		extracts the folder number from the property SPI_KWRD_NAME
//      The string will have "{MTISDM}7", the 7 being the folder number, which
//        is extracted by this function.
//***********************************************************************************

int extractParent(char * keywordName, char * parentNum)
{
	int i;
	int j = 0;
	// string manipulation code to isolate the folder num from the {MTISDM} string
	// initialize the string
	for (i=0; i<10;i++)
	{
		parentNum[i] = 32;
	}
	i=0;
	// find the beginning of where the number is - I know this will always be 8
	// but what the heck.  Maybe it'll change someday.
	while ( keywordName[i] != '}' )		  // count chars till } of {MTISDM}
	{
		i++;
	}
	i++;
	// move the value char by char to the folderNum string and return it
	while ( keywordName[i] != NULL )		  //till a space is encountered
	{
		 parentNum[j] = keywordName[i];
		 i++;
		 j++;
	}
	parentNum[j] = '\0';

	return (0);
}	// end of function


//***********************************************************************************
//		F U N C T I O N
//
//		expireTheFile
//
//		Params:  sctx - handle to the mezzanine session
//				 &parentKeyName, a string ptr containing the parent folder's key value
//						eg. {MTSIDM}567
//				 &parentNum - key of the parent eg 567
//			     &parentName - folder name of the parent folder
//				 itemID - the item id of the document to be expired
//
//
//		 Remove the file from it's parent directory and put it in It's corresponding
//			expired (DEAD) directory.
//		 The whole INFO structure has a corresponding DEAD structure where expired
//			files go to rest in peace.
//
//
//**********************************************************************************

int expireTheFile(SPI_SCTX_HNDL sctx, char * itemID, char * parentKeyName, char * parentNum, char * parentName, char * fullPath  )

{


	SPI_STATUS		  	status;
	SPI_OAB_HNDL		keywordOAB;
	char				kwName[SPI_MAXLEN_KEY+1] = "";
	char				delKey[SPI_MAXLEN_KEY+1] = "";
	char				szKeyword[SPI_MAXLEN_ATTR+1] = "";
	int					x;
	char				strParentNum[10] = "";
	char				folderName[32] = "DEAD";

	//build the keyword	for the DEAD folder
	strcpy(szKeyword, "{MTISDM}");	//keyword for a folder strarts with "MTISDM"
	// BB 6/1/99 comment out the next 3 lines
	//x = atoi(parentNum);			//convert string to an int
	//x = x + 5000;					//a folder's corresponding Dead folder has the same key + 5000 in Mezz
	//itoa( x, strParentNum, 10 );	// convert back to an int
	//replace above 3 lines with function call which gets the number of the folder.  This way DEAD folders no longer will need
	// A little history about this change.  When a file is expired by web update, it is added to the DEAD folder corresponding to its
	// live folder, and deleted from the live folder.  I thought it would be nice to be able to locate the DEAD folder simply by
	// adding a number to the folder number of the live folder.
	//  Web update has the live folder number already and a simple add would be easy and quick.
	// To accomplish this, all DEAD folders needed to be added to the system with
	// folder numbers = thier live counterparts + a Number (5000 I chose).  All's well except the only way to add a folder to the system
	// and be able to dictate the number it is assigned is to use a c program using the mezz api.  If you use the IDM desktop
	// to add a folder, the system assigns a number to it.  When I did the big conversion I added all the folders using a program I wrote,
	// but any new folders KBAT wants to add, subsequent to the conversion, need to added using the folder add utility I wrote
	// using the c api. This is a pain and KBAT should have access to the folder add functionality in the IDM desktop.
	//  So I'm fixing this flaw, and adding code here to go and get the DEAD folder number based on the live folder name.
	//  The getFoldewrNum function is the new function.  Notice folderNmae is initialized with "DEAD" and the live folder name is
	// concatenated to it.
	strcat ( folderName, parentName );
	status = getFolderNum ( sctx, folderName, strParentNum );

	strcat(szKeyword, strParentNum); // tack folder key onto the keyword

	// Allocate the keyword OAB
	status = spiOABAlloc(sctx, SPI_OBJ_KEYWORD, &keywordOAB);
	if ( status!= SPI_STS_SUCCESS ) {

		fprintf( logFile, "	!!OAB alloc went wrong! status = %d \n", status );
		flushall();
		return(1);
	}
	//fill Keyword OAB with ItemID and Keyword before adding the object
	status = spiOABAttrPut(sctx, keywordOAB, SPI_KWRD_ITEM_ID, itemID);
	if ( status!= SPI_STS_SUCCESS ) {
 		fprintf( logFile,  "	SPI_KWRD_ITEM_ID Put went wrong! status = %d \n", status);
		flushall();
		spiOABFree( sctx, keywordOAB );
		return(1);
	}
	status = spiOABAttrPut(sctx, keywordOAB, SPI_KWRD_NAME, szKeyword);
	if ( status!= SPI_STS_SUCCESS ) {
		fprintf( logFile,  "	SPI_KWRD_NAME Put went wrong! status = %d \n", status);
		flushall();
		spiOABFree( sctx, keywordOAB );
		return(1);
	}
	//Add the object - PUT THE FILE IN THE EXPIRED (DEAD) FOLDER
	status = spiObjectAdd(sctx,  keywordOAB);
	if ( status!= SPI_STS_SUCCESS ) {
		fprintf( logFile,  "	OAB Add went wrong! status = %d \n", status);
		flushall();
		spiOABFree( sctx, keywordOAB );
		return(1);
	}
	else
	{
		fprintf( logFile, "			File Added to DEAD folder. Status = %d \n", status);
		flushall();

	}
	// Build the key for the Object delete call and do the delete from parent folder
	status = spiKeyBuild ( sctx, delKey, sizeof(delKey),
				(char SPI_DFAR *) itemID,
				(char SPI_DFAR *) parentKeyName,
				(char SPI_DFAR *) NULL);
	if ( status!= SPI_STS_SUCCESS ) {
 		fprintf( logFile,    "	Key Build Failed B4 Delete-Keyword, status = %d\n", status);
		flushall();
		spiOABFree( sctx, keywordOAB );
		return(1);
	}


	status = spiObjectDelete(sctx,  SPI_OBJ_KEYWORD, delKey);
	if ( status!= SPI_STS_SUCCESS ) {
 		fprintf( logFile,    "	Object Delete Failed-Keyword, status = %d\n", status);
		flushall();
		spiOABFree( sctx, keywordOAB );
		return(1);
	}

	// FREE THE QUERY RESOURCES

	//FREE THE OAB
	status= spiOABFree( sctx, keywordOAB );
	if ( status!= SPI_STS_SUCCESS ) {
 		fprintf( logFile,    "	OAB search Free Failed-Keyword, status = %d\n", status);
		flushall();
		return(1);
	}


	return(0);
}



//***********************************************************************************
//		F U N C T I O N
//
//		getSystemTime
//
//		Params:  runTime - pointer to the string which will hold the date in the
//				           filenet format :   1997-02-01T13:05:09
//
//**********************************************************************************
int getSystemTime ( char * runTime, char * fileNameTime)
{

	char   yr[8];
	char   mon[8];
	char   day[8];
	char   min[8];
	char   hr[8];
	char   sec[8];

	time_t timer;
	struct tm *sys_time;
	time(&timer);
	sys_time = localtime(&timer);

	// Convert the ints to strings
	itoa(sys_time->tm_year,yr,10);
	sys_time->tm_mon++;				  //month is 0 based, 0-11, so add 1
	itoa(sys_time->tm_mon,mon,10);
	itoa(sys_time->tm_mday,day,10);
	itoa(sys_time->tm_hour,hr,10);
	itoa(sys_time->tm_min,min,10);
	itoa(sys_time->tm_sec,sec,10);


	// Year 2000 windowing
	if (sys_time->tm_year > 50)
		strcpy(runTime, "19");
	else
		strcpy(runTime, "20");
	// Build the date string in filenet format from the date pieces in the tm structure
	strcat(runTime, yr);
	strcat(runTime, "-");
	if (sys_time->tm_mon < 10)
	{
		strcat(runTime, "0");
	}
	strcat(runTime, mon);
	strcat(runTime, "-");
	if (sys_time->tm_mday < 10)
	{
		strcat(runTime, "0");
	}
	strcat(runTime, day);
	strcat(runTime, "T");
	if (sys_time->tm_hour < 10)
	{
		strcat(runTime, "0");
	}
	strcat(runTime, hr);
	strcat(runTime, ":");
	if (sys_time->tm_min < 10)
	{
		strcat(runTime, "0");
	}
	strcat(runTime, min);
	strcat(runTime, ":");
	if (sys_time->tm_sec < 10)
	{
		strcat(runTime, "0");
	}
	strcat(runTime, sec);
	// The time is appended to the output file names so during successive runs they arent
	// overwritten.
	// Same code Again for the fileNameTime   colons are'nt legal chars for use in filenames.  Use underscore.
	if (sys_time->tm_year > 50)
		strcpy(fileNameTime, "19");
	else
		strcpy(fileNameTime, "20");

	strcat(fileNameTime, yr);
	strcat(fileNameTime, "-");
	if (sys_time->tm_mon < 10)
	{
		strcat(fileNameTime, "0");
	}
	strcat(fileNameTime, mon);
	strcat(fileNameTime, "-");
	if (sys_time->tm_mday < 10)
	{
		strcat(fileNameTime, "0");
	}
	strcat(fileNameTime, day);
	strcat(fileNameTime, "T");
	if (sys_time->tm_hour < 10)
	{
		strcat(fileNameTime, "0");
	}
	strcat(fileNameTime, hr);
	strcat(fileNameTime, "_");	   // underscore used for use in filename
	if (sys_time->tm_min < 10)
	{
		strcat(fileNameTime, "0");
	}
	strcat(fileNameTime, min);
	strcat(fileNameTime, "_");
	if (sys_time->tm_sec < 10)
	{
		strcat(fileNameTime, "0");
	}
	strcat(fileNameTime, sec);



	return (0);



}  //  End of getSystemDate Fucntion


/**************************************************************************************************
processMetaData : 2 properties in the Document Management system : Keywords and answer subject need
				   to be in the text of the html file as meta data.

  1.  Reads the html file looking for the meta data tag name, ie answer-subject.
  2.  If it's not there, rewrite the file & insert it, with the value of the property.
  3.  if it is there
		  - is it the same as the property value from the doc management system? (has it changed)
		        - if the same, get out - nothing to do
				-  if different, rewite the file with the new data.


 A problem here is that the answwr subject meta tag is different from the others.  It is in a form
 as a hidden property.  This difference is enough to require separate processing if the property
 being dealt with is the ans sub.  Watch for this in the code.

  Rewriting the html file means write it to a temp file, delete the old and rename the temp to
  the name of the old.
***************************************************************************************************/
int processMetaData(char * fullPath, char * metaTag, int numToSkip, char * propVal)
{

	char inChar;
	char inString[5000] = "";		// Hopefully there's not a string longer than 5000 chars out there
	char tstString[100] = "";
	int ptr,i;
	int retVal = 0;
	char *cPtr;
	char metaVal[256];
	int status = 0;
	int gotIt = 0;
	int updatedFlag = 0;
	char tempPath[200] = "c:\\temp\\webUpdateTemp.html";
	char tempOld[200] = "c:\\temp\\theOldFile.html";
	// Only have a meta tag string to add for keywords.  Answer Subject tag is much longer and is
	// dealt with in a separate function. This is needed if the tag is not already in the file
	// and needs to be inserted.
	char  keywordString[254] =  "<META NAME=\"keywords\" CONTENT=\"";	  // keywords meta tag
	unsigned long dummy;

	ptr = 0;
	fprintf ( logFile,  "	Processing meta data for : %s\n", metaTag );
	fflush( logFile );

	FILE   *htmlFile;
    htmlFile = fopen(fullPath,"r");

	// I use fgetc instead of fgets so I can count the characters as they come in and be sure I know
	// if a string > 5000 chars exists.  With fgets, you need to specify a string length and it won't
	// tell you the length of the string actully returned.


	while ( (inChar = fgetc(htmlFile) ) != EOF && gotIt == 0 && ptr < 5000)// Get chars one at a time
	{
		 if (inChar == 10)   // is it a line feed? ascii code for LF line feed
		 {
			 ptr = 0;
			 cPtr = strstr(inString, metaTag);	    // cPtr points to meta tag in the string if !NULL
			 if ( cPtr == NULL )					// meta tag not found in the string
			 {
				 for (i=0; i<5000; i++)             // Null the string for next line
					inString[i] = NULL;
			 }
			 else
			 {
				 fprintf ( logFile,  "	Got the html line with the meta tag.  Now get the value of the meta data.\n");
		         fflush( logFile );
				 gotIt = 1;
				 for ( i = 0; i < 256; i++ )					// initailize to nulls
					metaVal[i] = NULL;

				 cPtr = strstr(inString, metaTag);		// now look for value of metaTag

				 cPtr = cPtr + numToSkip;				// skip from the tag to the value to isolate it
				 ptr = 0;

				 while (  cPtr[ptr] != 34 && ptr < 256)	// 34 is a double quote
				 {
					 metaVal[ptr] = cPtr[ptr];			// copy the value to variable from the string
					 ptr ++;
				 }
				 if (ptr > 254)
				 {
					 fprintf ( logFile,  "	BAD or too long meta data value from html file.  Length limit = 254\n");
			         fflush( logFile );
				 }

				 fprintf ( logFile,  "	**Doc meta val : %s  **Mezz Val :  %s\n", metaVal, propVal);
			     fflush( logFile );

				if ( (strcmp (metaVal, propVal)) && (ptr < 254)) // has value changed?
				{
					//replace old with new - need to rewrite the whole file

					status = updateFile( htmlFile, fullPath, metaTag, numToSkip, metaVal, propVal);
					if (status == 1)
					{
						retVal = 1;
						fprintf ( logFile,  "	ERROR Updating meta data \n");
						fflush( logFile );

					}
					else
					{
						fprintf ( logFile,  "	Changed %s to %s\n", metaVal, propVal);
					    fflush( logFile );
					}

					updatedFlag = 1;
				 }
				 //  already there and current - do notihing Close and get out
				 else
				 {
					fprintf ( logFile,  "	No changes to be made for %s \n", metaTag);
					fflush( logFile );
				 }
				 //  end of has value changed if statement

			  }	// end of the code dealing with fact that the meta string was found in the current string

		 }	   //  not a line feed.
		 else
		 //  add the character to the string and bump the pointer to get the next character
		 {
			 inString[ptr] = inChar;
			 ptr ++;
		 }

	} // end of big while loop which loops thru the html doc, char by char looking for the meta tag

	if (ptr > 4999)
	{
		fprintf ( logFile,  "	*** 5000 HTML file str limit reached!! Bad chars in it probably.  File not processed. \n");
		fflush( logFile );
		retVal = 9;
	}
	if (gotIt == 0)
	{
		// If control is here it means the meta data tag was not found in the document and needs to be
		// added.  KBAT uses a template for all their files which includes all
		// meta data tags but keywords and answer subject.
		// So, only code for these 2 properties.
		// The answer sub mata tag is really more than a tag: it's a hidden form.
		// Since the html code for a form spans several lines and each need a line feed,
		// I used a separate string variable for each line, and stuck them in the insertAnsSub
		// function.  The function call for the ans sub insertion contains the property value
		// instead of the meta tag.  The property value is contacenated to the appropriate html
		// line in the insertMetaData function.

		if (strstr(metaTag, "ANSWER") )
		{
			fprintf ( logFile,  "	Inserting Answer Sub Tag. Value : %s\n", propVal);
			fflush( logFile );
			status = insertMetaData( htmlFile,  propVal, "/BODY");
		}
		else
		if (strstr(metaTag, "EFFECTIVE") )
		{
			char  keywordString[254] =  "<META NAME=\"EFFECTIVE-DATE\" CONTENT=\"";
			strcat( keywordString, propVal);
			strcat( keywordString, "\"");          // tack on a dbl quote
			strcat( keywordString, ">");          // tack on a > tag delimiter
			// rewrite the html file and insert keyword string before the line
			// that contains the letters /HEAD

			fprintf ( logFile,  "	Inserting EFFECTIVE DATE Tag. Value : %s\n", propVal);
			fflush( logFile );
			status = insertMetaData( htmlFile,  keywordString, "/HEAD");
		}
		else
		if (strstr(metaTag, "keywords") )
		{
			strcat( keywordString, propVal);
			strcat( keywordString, "\"");          // tack on a dbl quote
			strcat( keywordString, ">");          // tack on a > tag delimiter

			// rewrite the html file and insert keyword string before the line
			// that contains the letters /HEAD
			fprintf ( logFile,  "	Inserting keywords Tag. Value : %s \n", propVal);
			fflush( logFile );
			status = insertMetaData(htmlFile,  keywordString, "/HEAD");
		}
		if (status == 0)
		{
				updatedFlag = 1;
		}
		else
		{
			retVal = status;   //  flow will fall to the end of the function - return bad code
			fprintf ( logFile,  "	ERROR Updating meta data \n");
			fflush( logFile );
		}

	}	// end of if got it id stmt - where inserting of meta tags is called

	fclose(htmlFile);
	// Now whether the mata data was inserted new or updated, we need to delete the html file with out the change,
	// and rename the temp html file , that contains the change, to the original file name.

	//printf(" stop here for test - rename %s to something and hit enter to continue \n", tempPath );
	//getchar();

	if (updatedFlag == 1)
	{
		retVal = 0;
		//i = remove (fullPath);
		i = rename ( fullPath, tempOld );   // backup the orig file if the following rename goes bad
		if (i == 0)
		{
			fprintf ( logFile,  "	Old file renamed to theOldFile.html. Now rename %s to %s\n", tempPath, fullPath);
			fflush( logFile );
			for ( dummy=0; dummy < 65000; dummy++ ) //  execute a for loop here to waste some time. Timing issue with rename.
			{
				killTime();
			}

			i = rename( tempPath, fullPath );

			if (i == 0)
			{
				fprintf ( logFile,  "	Temp html file renamed.\n");
				fflush( logFile );
				i = remove (tempOld);  //  Successful temp to full rename so get rid of the backup original file
			}
			else
			{
				fprintf ( logFile,  "	ERROR : Temp html file NOT renamed. Ret Code : %d. TRY AGAIN\n", i );
				fflush( logFile );
				i = rename( tempPath, fullPath);   // try again
				if ( i != 0 )
				{
					fprintf ( logFile,  "		Second try at renaming was also unsuccessful.\n");
					fflush( logFile );
					i = rename (  tempOld, fullPath ); // Restore the old file back
					retVal = 9;
				}
				else
				{
					fprintf ( logFile,  "		Second try at renaming was successful.\n");
					fflush( logFile );
					i = remove (tempOld);
					retVal = 0;
			    }
			}
		}
		else
		{
			fprintf ( logFile,  "	ERROR : Old html file NOT removed. Skipping this file.\n");
			fflush( logFile );
			retVal = 9;
		}
	}

	return (retVal);
}   //end insert metaTag function


/*******************************************************************************
	update file function

	copy contents of the file to a new file replacing the value of the metaTag
	with the new value.

	A new file is created with the new prop value.


*********************************************************************************/
int updateFile(FILE * htmlFile, char * fullPath, char * propName, int numToSkip, char * oldVal, char * newVal)
{
	int i;
	char inChar;
	char newName[200]= "";
	int ptr = 0;
	char inString[5000] = "";
	char *cPtr;
	int quoteCnt = 0;
	int newLen = 0;
	int numQuotes = 3;              //  initialize for keywords	property
	FILE * oFile;

    oFile = fopen("c:\\temp\\webUpdateTemp.html","w");
	if ( oFile == NULL )
	{
		fprintf ( logFile,  "		Error opening temp file in updateFile function.\n" );
		fflush( logFile );
		fprintf ( report,  "		ERROR opening temp file.  Skipping this file!!!!!\n" );
		fflush( report );
		return (1);
	}

	fprintf ( logFile,  "		Updating %s. Old : %s New : %s\n", propName, oldVal, newVal);
	fflush( logFile );

	rewind ( htmlFile );  // back to the top of the file
	while ( (inChar = fgetc(htmlFile) ) != EOF )// Get chars one at a time
	 {
		 if (inChar == 10)   // is it a line feed? ascii code for LF line feed
		 {
			 ptr = 0;
			 cPtr = strstr(inString,propName);	   // is the meta data in this string?
			 if ( cPtr == NULL )				   // meta data not found in the string
			 {
				 fputs ( inString,  oFile);		     // write the string to output file
				 fputc( 10, oFile);					 // write a line feed
				 for (i=0; i<5000; i++)              // Null the input string for next line
					inString[i] = NULL;
			 }
			 else
			 {
				 cPtr = strstr(inString, propName);	   // now look for value of property
				 cPtr = cPtr + numToSkip;			   // cPtr points to 1st char of meta data value
				 // Now write inString to out file char by char till the prop value
				 i=0;
				 quoteCnt = 0;
				 if ( strstr ( propName, "ANSWER") )
				 {
					 numQuotes = 5;  // I know this stinks - count 5 quotes for ans sub insertion
				 }
				 while (quoteCnt < numQuotes)
				 {
					 fputc( inString[i], oFile );
					 if (inString[i] == 34)
						quoteCnt++;
						i++;
				 }
				 //  Then write the meta value followed by dbl quote and > sign	& LF
				 newLen = strlen( newVal);
				 i = 0;
				 while (i < newLen)
				 {
					 fputc( newVal[i], oFile );
					 i++;
				 }
				 fputc( 34 , oFile);					// dbl quote
				 fputc( 62 , oFile);					// > sign
				 fputc( 10 , oFile);					// line feed

				 fflush(oFile);
				 for (i=0; i<5000; i++)                 // Null the string for next line
					inString[i] = NULL;

	 		  }	   // end of else - meta data not in this string

		 }	   //  not a line feed
		 else
		 //  add the character to the input string and bump the pointer
		 {
			 inString[ptr] = inChar;
			 ptr ++;
		 }
	 }	//  end of fgetc while loop

	 fclose( oFile);
	 return (0);
}  // end of function


/*******************************************************************************
	insert Meta Data
	args: ptr to html file

	copy contents of the file to a new file and insert the meta data string after
	the string containing the search string is found

	A new file is created with the new meta data tag inserted in its place


*********************************************************************************/
int insertMetaData(FILE * htmlFile, char * metaString, char * beforeString)
{
	int i;
	char inChar;
	char newName[200]= "";
	int ptr = 0;
	char inString[5000] = "";
	char *cPtr;
	int quoteCnt = 0;
	int newLen = 0;
	int gotIt = 0;

	FILE * oFile;
    oFile = fopen("c:\\temp\\webUpdateTemp.html","w");
	if ( oFile == NULL )
	{
		fprintf ( logFile,  "		Error opening temp file in insertMetaData\n" );
		fflush( logFile );
		fprintf ( report,  "		ERROR opening temp file.  Skipping this file!!!!!\n" );
		fflush( report );
		return (1);
	}


	fprintf ( logFile,  "		Inserting %s\n", metaString);
	fflush( logFile );

	rewind ( htmlFile );  // back to the top
	while ( (inChar = fgetc(htmlFile) ) != EOF )// Get chars one at a time
	{
		 if (inChar == 10)   // is it a line feed? ascii code for LF line feed
		 {
			 ptr = 0;
			 cPtr = strstr( inString, beforeString ); // is this the before string ?
			 if ( cPtr != NULL )				   // yes. Insert meta tag b4 copying string to output
			 {
				 gotIt = 1;
				 cPtr = strstr( beforeString, "BODY" ); // Do diff for ans sub
				 if ( cPtr == NULL )
					  cPtr = strstr( beforeString, "body" );   // could be lower case
				 if ( cPtr != NULL )
				 {
					insertAnsSub( oFile, metaString, inString );  // special ans sub routine
				 }
				 else								// not ans sub meta tag
				 {									// normal style meta tag - like keywords
					fputs( metaString,  oFile);		// write the meta tag to output file
					fputc( 10, oFile);				// write a line feed
					fputs ( inString,  oFile);		// ok the meta tag is in, now write the before string
					fputc( 10, oFile);				// write a line feed
			 	 }


			 } // not the before string, so just write it
			 else
			 {
				fputs ( inString,  oFile);		 // ok the meta tag is in, now write the before string
				fputc( 10, oFile);
			 }
			 for (i=0; i<5000; i++)              // Null the input string for next line
				inString[i] = NULL;
		 }
		 else
		 //    not a line feed - add the character to the string and bump the pointer
		 {
			 inString[ptr] = inChar;
			 ptr ++;
		 }
	}	//  end of fgetc while loop

	 fclose( oFile);
	 if (gotIt == 0)
	 {
		 fprintf ( logFile,  "	Insertion failed.  Before string : %s, not in html file.\n", beforeString);
		 fflush( logFile );
	 }

	 return (0);
}  // end of function

/*********************************************************************************************************************
   Answer Sub is a special case of insert meta data, because it needs to be inserted in the middle of
   an existing line, not before a whole line.  Also, it's not a 1 line html tag but a form requiring
   several lines of code to be inserted.

  */
int insertAnsSub( FILE * oFile, char * ansSubVal, char * inString)
{
	int i;
	int pos;
	int sLen;
	char ansSub1[7] = "<FORM>";
	char ansSub2[4] = "<P>";
	char ansSub3[100] = "<INPUT TYPE=\"HIDDEN\" NAME=\"BEGIN HIDDEN FORM\" VALUE=\"BAHR AUTHORING PROPERTIES\">";
	char ansSub4[150] = "<INPUT TYPE=\"HIDDEN\" NAME=\"ANSWER-SUBJECT\" VALUE=\"";
	char ansSub5[12] = "</P></FORM>";

	fflush ( oFile);
	strcat ( ansSub4, ansSubVal);    // complete line 4 with the ans sub value
	strcat ( ansSub4, "\">");


	// find position in string where the </BODY> tag is
	sLen = strlen(inString);
	for ( i=2; i<sLen; i++ )
	{
		if ( (inString[i] == 'O' || inString[i] == '0') &&
			 (inString[i-1] == 'B' || inString[i-1] == 'b') &&
			 (inString[i-2] == '/') )
			 pos = i;
	}
	pos = pos - 3;				// back up 3 to the beginning of <BODY>
	for (i=0; i<pos; i++)		   // write up to the </BODY> tag
	{
		putc(inString[i], oFile);
	}
	// then write the answer sub form
	fputc( 10, oFile);				 // line feed
	fputs( ansSub1,  oFile);		 // write the meta tag to output file
	fputc( 10, oFile);
	fputs( ansSub2,  oFile);		 // write the meta tag to output file
	fputc( 10, oFile);
	fputs( ansSub3,  oFile);		 // write the meta tag to output file
	fputc( 10, oFile);
	fputs( ansSub4,  oFile);		 // write the meta tag to output file
	fputc( 10, oFile);
	fputs( ansSub5,  oFile);		 // write the meta tag to output file
	for (i=pos; i<sLen; i++)		 // finish up the end of the inString
	{
		putc(inString[i], oFile);
	}

	fputc( 10, oFile);				 // lay a line feed at the end

	return (0);						 // later

} // end of function insertAnsSub

//***********************************************************************************
//		F U N C T I O N
//
//		convert date from filenet to mm/dd/yyyy format
//
//		Params:  							  0123456789
//				           filenet format :   1997-02-01T13:05:09 - date
//											  yyyy mm dd
//										   mm dd yyyy
//							format     :   01/02/1998		  -	 date
//										   0123456789
//**********************************************************************************
int changeDateFormat( char* filenetDate, char * date )
{

	date[0] = filenetDate[5];
	date[1] = filenetDate[6];
	date[2] = '/';
	date[3] = filenetDate[8];
	date[4] = filenetDate[9];
	date[5] = '/';
	date[6] = filenetDate[0];
	date[7] = filenetDate[1];
	date[8] = filenetDate[2];
	date[9] = filenetDate[3];





	return (0);

}

/***************************************************************************************************
  editFullPath

  In the IIS structure, the INFO folder sits under the path :
	C:\\srvapps\\Inetsrv\\WWWRoot\\Self_Serv\\

  In IDM, (MEZZ), INFO is the root, ie there is no C:\\srvapps\\Inetsrv\\WWWRoot\\Self_Serv\\.
  To compare the location (path), of a file between the 2 enviroments, this string ( path piece ),
  needs to be stripped off the IIS path.

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

int editFullPath( char* fullPath, char * halfPath )
{

	int i;
	int j;

	// initialize the half path value
	for ( i=0; i < 300; i++)
		halfPath[i] = NULL;

	j = 37;						  // skip to the INFO folder in the path
	i = 0;
	while ( fullPath[j] !=NULL )
	{
		halfPath[i] = fullPath[j];
		j++;
		i++;
	}

	return (0);
}

void killTime()
{
	int						status;
	char					runTime[22];
	char					fileNameTime[22];

	status = getSystemTime( runTime, fileNameTime );
}





////////////////////////////////////////////////////////////////////////////////////////////
// getFolderNum
//		 When a user adds a folder using IDM desktop, Mezzanine assigns it a number.
//		  The folder is recorded in the data base in the custom table, and the folder number
//			is in the co_key column.
//       This function finds the folder number of a folder for which the name is known.
//		 Calling func sends in a folder name and this function returns the folder's number.
//
//
///////////////////////////////////////////////////////////////////////////////////////////
int getFolderNum ( SPI_SCTX_HNDL sctx, char * folderName, char * folderNum )
{

	//SPI_SCTX_HNDL			sctx;

	SPI_STATUS		  		status;
	SPI_QUERY_HNDL			qhnd;
	unsigned long			count;
	SPI_OAB_HNDL			srOAB;
	SPI_OAB_HNDL			rowOAB;
	unsigned long	  		ii;
	SPI_ATTR_NO		        selectList[SPI_MAX_QRY_SHOW];
	SPI_QUERY_SELECTION     whereClause[SPI_MAX_QRY_SELECTIONS];

	int						isMoreRows;
	int						firstRow;
	char 					keybuf[SPI_MAXLEN_ITEM + 1];
	char					coKey[SPI_MAXLEN_STRING + 1];
	int						i = 0;
	char					name[32] = "";


	//make sure folder name is 32 chars or less, as that is the upper limit for folder names imposed
	// by mezzanine software.
	strncpy ( name, folderName, 32 );

	//OAB ALLOCATE FOR SEARCH REQUEST OBJECT
  	status= spiOABAlloc( sctx, SPI_OBJ_SEARCH_REQUEST, &srOAB );

	if ( status!= SPI_STS_SUCCESS ) {
 		fprintf ( logFile,    "Search OAB Alloc . Going EOJ. status = %d\n", status);
		fflush( logFile );

		return(1);
	}


	//BUILD THE SELECT, WHERE AND ORDER CLAUSES FOR THE QUERY
    selectList[0] = SPI_CO_ISV_ID;
	selectList[1] = SPI_CO_OBJECT_TYPE;
	selectList[2] = SPI_CO_KEY;
	selectList[3] = SPI_CO_STRING2;
	selectList[4] = 0;
	status = spiOABAttrPut( sctx, srOAB, SPI_SR_SHOW, selectList );
	if ( status!= SPI_STS_SUCCESS ) {

		fprintf ( logFile,   "OABAttrPut Failed-Select , status = %d\n", status);
		fflush( logFile );


		spiOABFree( sctx, srOAB );
		return(1);
	}

	whereClause[0].andOrStop = SPI_ANDOR_START;
	whereClause[0].nestingLevel = 0;
	whereClause[0].attrNo = SPI_CO_STRING2;
	whereClause[0].relOp = SPI_RELOP_EQ	;
	strcpy(whereClause[0].value, name);


	whereClause[1].andOrStop = SPI_ANDOR_STOP;
	whereClause[1].nestingLevel = 0;
	status = spiOABAttrPut( sctx, srOAB, SPI_SR_QUERY, whereClause );
	if ( status!= SPI_STS_SUCCESS ) {
 		fprintf ( logFile,  "OABAttrPut Failed-Where , status = %d\n", status);
		 fflush( logFile );


		spiOABFree( sctx, srOAB );
		return(1);
	}


	//PARTIAL OAB ALLOCATE FOR THE SEARCH REQUEST OBJECT
	status= spiOABRowAlloc( sctx, srOAB, &rowOAB );
	if ( status!= SPI_STS_SUCCESS ) {
 			fprintf ( logFile,  "Search OAB Row Alloc Failed, status = %d\n", status);
		 fflush( logFile );


		spiOABFree( sctx, srOAB );
		return(1);
	}

	//=====================================================================
	//ISSUE THE SEARCH -
	*keybuf = '\0';
	firstRow = 0;
	//ISSUE THE SEARCH.
	status= spiQuerySearchRequest( sctx, srOAB, SPI_QUERY_FORWARD,
					keybuf, (unsigned long)200, &count, &qhnd );

	if ((status != SPI_STS_SUCCESS) && (status != SPI_STS_MORE_ROWS))
	{
		fprintf ( logFile,   "Query Search Request Failed-Folder Number search, status = %d\n", status);
		fflush( logFile );
		spiQueryDone( sctx, qhnd );
		spiOABFree( sctx, srOAB );
		spiOABFree( sctx, rowOAB );
   		return(1);
	}

	isMoreRows = (status == SPI_STS_MORE_ROWS);

	fprintf ( logFile,  "Rows found-folder num search: %d%s\n", count,
			 ((firstRow == 0)? "" : "  (Note: Not displaying first row)") );
	fflush( logFile );

	//  Get the row
	status= spiQueryRow( sctx, ii, rowOAB, qhnd );
	if ( status!= SPI_STS_SUCCESS ) {
	 	fprintf ( logFile,   "QueryRow Failed-Effective Date search, status = %d\n", status);
	    fflush( logFile );
		spiQueryDone( sctx, qhnd );
		spiOABFree( sctx, srOAB );
		spiOABFree( sctx, rowOAB );
		return(1);
 	}
	// Get the values of the folder number (CO_KEY) prop of the item.
	status = spiOABAttrGet( sctx, rowOAB, SPI_CO_KEY, coKey, SPI_MAXLEN_STRING + 1 );
	strcpy ( folderNum, coKey );
	fprintf ( logFile,  "folderNumber is : %s \n", coKey );
	fflush( logFile );

	if ( status!= SPI_STS_SUCCESS ) {
		fprintf ( logFile,   "Attr Get Failed-Effective Date search, status = %d\n", status);
		fflush( logFile );
		spiQueryDone( sctx, qhnd );
		spiOABFree( sctx, srOAB );
		spiOABFree( sctx, rowOAB );
   		return(1);
 	}
	//IF MORE ROWS, GET ANOTHER RESULT SET CONTAINING UP TO 100 ROWS.
	if (isMoreRows) { /* start next search from end of this one */
		spiOABAttrGet(sctx, rowOAB, SPI_ITEM_ID, keybuf, SPI_MAXLEN_ITEM+1);
		firstRow = 1;
	}

	// CLOSE THE QUERY AND RELEASE RESOURCES
	status= spiQueryDone( sctx, qhnd );


	//FREE THE OAB'S
	status= spiOABFree( sctx, srOAB );
	if ( status!= SPI_STS_SUCCESS ) {
 		fprintf ( logFile,  "OAB Free Failed, status = %d\n", status);
		fflush( logFile );
		return(1);
	}

	status= spiOABFree( sctx, rowOAB );
 	if ( status!= SPI_STS_SUCCESS ) {
 		fprintf ( logFile, "OAB Free Failed, status = %d\n", status);
		fflush( logFile );
		return(1);
	}
	return (0);
}  //  end getFolderNum  function