/*

The contents of this file are subject to the Mozilla Public License
Version 1.1 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/

Software distributed under the License is distributed on an "AS IS"
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
License for the specific language governing rights and limitations
under the License.

The Original Code is a portion of the Path Development API developed
by CygnaCom Solutions, Inc.

Portions created by CygnaCom Solutions, Inc. are Copyright (C) CygnaCom 
Solutions, Inc. All Rights Reserved.

Contributor(s): ______________________________________.

*/

/*------------------------------------------------------------------------*\
|  Project Name  :   Path Development API
|  File Name     :   cpl.cpp
|  Creation Date :   May 17, 1999
|  Author        :   Matt Cooper (mcooper@cygnacom.com)
|  Last Mode Date:   May 17, 1999
|  Modification History:
|--------------------------------------------------------------------------
|
|     Known Bugs:   None
|                   
|--------------------------------------------------------------------------
| Cryptographic devices and technical data regarding them are subject to
| Federal Government export controls as specified in Title 22, Code of
| Federal Regulations, Parts 121 through 128.  Cryptographic devices
| implementing the Data Encryption Standard (DES) and technical data
| regarding them must comply with these Federal regulations
|--------------------------------------------------------------------------
| Copyright (c) 1999, CygnaCom Solutions, Inc.
| All Rights Reserved.
\*------------------------------------------------------------------------*/

// cpdlib.cpp : Defines the entry point for the DLL application.
//
#if defined(_WIN32)
	#if defined(_AFXDLL)
		#include "stdafx.h"
	#else
		#include "windows.h"
	#endif
#endif

#ifdef VX /* Added by Masanori Satake. */
#include "vxWorks.h"
#include "vxdbg.h"
#endif

#if defined(WIN32) && defined(_MEMCHECK)
	#include <crtdbg.h>			/* For memory debugging */
#endif

#include "Defines.h"
#include "utils.h"
#include "CMAPIInterface.h"
#include "CertCache.h"
#include "PathCache.h"
#include "PathDev.h"
#include "stdio.h"

/*
extern "C"
{
*/
//extern int stricmp(const char *,const char *);
#if defined (_WIN32)
#if !defined(_AFXDLL)
CDumpClass afxDump = CDumpClass::CDumpClass(".\\cpl_log.txt");
#endif
#endif

//#define _NO_ERR_ON_BAD_DISK_PATH

#define MAX_ERR_MSG_SIZE	128


CCMAPIInterface *pCMAPIInterface;
CCertCache *pCertCache = NULL;
CPathCache *pPathCache = NULL;
char errorMsg[MAX_ERR_MSG_SIZE+2];

// define to do read access checking under ms-win32 in this file only
#define _USE_WIN32_PTR_VALIDATION

int init_success = 0;
int init_called = 0;
int term_called = 0;
long last_session_in_use = 0;

LOCAL_SESSION_INFO sessionInfoArr[CPL_MAX_SESSION];

extern "C" long CPL_InitializeLibrary( 	char* diskCacheDirectory );

extern "C" long CPL_BeginPathDevelopment(long* session, 
					char* subjectDN, 
					CPL_SESSION_INFO *sessionInfo,
					CertPath_struct *partialPath = NULL,
					int inhibitPolicyMapping = 0,
					int requireExplicitPolicy = 0,
					char** desiredAlgOIDArray = NULL, 
					unsigned short keyUsage = 0, 
					Bytes_struct* skid = NULL);

extern "C" long CPL_DoPathDevelopment(	long session, 
					CPL_SESSION_INFO * sessionInfo,
					CertPath_struct **certPath   );

extern "C" long CPL_EndPathDevelopment(	long session, 
					CPL_SESSION_INFO *sessionInfo,
					CertPath_struct **certPath,
					int pathStatus   );


extern "C" long CPL_TerminateLibrary();


void CPL_FreeCertPath(CertPath_struct **certPath);

#if defined(WIN32)
/* Added 8/26/99 Matt Cooper
	- Have to handle DLL unload to save cert path cache data  */

#pragma warning( disable : 4100 )  

BOOL WINAPI DllMain(
  HINSTANCE hinstDLL,  // handle to DLL module
  DWORD fdwReason,     // reason for calling function
  LPVOID lpvReserved   // reserved
)
{
	BOOL rv = FALSE;

	#if defined(_DEBUG)
			afxDump << "DllMain called.. fdwReason == " << fdwReason << "\n";
	#endif

	switch( fdwReason )
	{
	case DLL_PROCESS_ATTACH:
		/* Could perform initialization here */
		rv = TRUE;
		break;
	case DLL_THREAD_ATTACH:
		/* Nothing to do here */
		rv = TRUE;
		break;
	case DLL_THREAD_DETACH:
		/* Again, nothing */
		rv = TRUE;
		break;
	case DLL_PROCESS_DETACH:
		/* Shut down library */

		#if defined(_DEBUG)
			afxDump << "DllMain: DLL_PROCESS_DETACH\n";
		#endif

		CPL_TerminateLibrary();
		rv = TRUE;
		break;
	default:
		break;
	}

	return rv;
}
 
#pragma warning( default : 4100 )  

/* End 8-26-99 mods */
#endif // WIN32



long CPL_InitializeLibrary( char* diskCacheDirectory )
{
#if defined(WIN32) && defined(_MEMCHECK)
	int debugFlag;
	static long memAllocNum = 0;
	
    _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG);
    _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG);
    _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);

	debugFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
	debugFlag = _CrtSetDbgFlag(debugFlag | _CRTDBG_LEAK_CHECK_DF);

#ifdef _EXTRA_MEMCHECK
	debugFlag = _CrtSetDbgFlag(debugFlag | _CRTDBG_DELAY_FREE_MEM_DF | 
		_CRTDBG_CHECK_ALWAYS_DF);
#endif /* _EXTRA_MEMCHECK */

	/* Set a breakpoint on the allocation request number */
	_CrtSetBreakAlloc(memAllocNum);

#endif /* WIN32 and _MEMCHECK */

	memset(&errorMsg,0,MAX_ERR_MSG_SIZE);

	long rv = 0;
	if( init_called && !term_called )
	{
		CPL_TerminateLibrary();
	}
	init_called = 1;
	term_called = 0;

	#if defined(_DEBUG)
                #ifdef _WIN32 /* Added by Masanori Satake. */
		afxDump << "Initialize called..\nDisk Path == " << diskCacheDirectory << "\n";
                #else /* _UNIX or VX */
		PRINTERR("Initialize called..\nDisk Path == ");
		PRINTERR(diskCacheDirectory);
		PRINTERR("\n");
                #endif /* #ifdef _WIN32 */
	#endif

	memset(&sessionInfoArr,0,CPL_MAX_SESSION * sizeof(LOCAL_SESSION_INFO) );
/*
	for( int ii = 0; ii < CPL_MAX_SESSION; ii++ )
	{
		sessionInfoArr[ii].mask = CPLI_get_bit_mask(ii+1);
	}
*/

	if( !pCMAPIInterface )
		pCMAPIInterface = new CCMAPIInterface;
	
	if( !pCMAPIInterface )
		return CPL_ALLOC_FAILURE;

	if( !pCertCache )
		pCertCache = new CCertCache;

	if( !pCertCache )
	{
		delete pCMAPIInterface;	pCMAPIInterface = NULL;
		return CPL_ALLOC_FAILURE;
	}

	if( !pPathCache )
		pPathCache = new CPathCache;
	
	if( !pPathCache )
	{
		delete pCMAPIInterface;	pCMAPIInterface = NULL;
		delete pCertCache;	pCertCache = NULL;
		return CPL_ALLOC_FAILURE;
	}
#ifdef _WINDOWS
	#if defined(_DEBUG)
		#ifdef _MEMCHECK
			rv = pCMAPIInterface->LoadCMAPILibrary("cmapi_md.dll");
		#else
			rv = pCMAPIInterface->LoadCMAPILibrary("cmapi_d.dll");
		#endif
	#else
		rv = pCMAPIInterface->LoadCMAPILibrary("cmapi.dll");
	#endif
#else
#ifndef VX /* Added by Masanori Satake. */
	#if defined (UNIX_DEBUG)
		rv = pCMAPIInterface->LoadCMAPILibrary("libcmapi_d.so");
	#else
		rv = pCMAPIInterface->LoadCMAPILibrary("libcmapi.so");
	#endif
#else /* Added by Masanori Satake. */
		rv = pCMAPIInterface->LoadCMAPILibrary("libcmapi");
#endif /* #ifndef VX */
#endif

	if( 0 != rv )
	{
		sprintf(errorMsg,"CPL_InitializeLibrary: Failed to load the CMAPI library.");
		#if defined(_DEBUG)
                        #ifdef _WIN32 /* Added by Masanori Satake. */
			afxDump << "ERROR: " << errorMsg << "\n";
                        #else /* _UNIX or VX */
			PRINTERR("ERROR: ");
			PRINTERR(errorMsg);
			PRINTERR("\n");
                        #endif /* #ifdef _WIN32 */
		#endif
		delete pCMAPIInterface;	pCMAPIInterface = NULL;
		delete pCertCache;	pCertCache = NULL;
		delete pPathCache; pPathCache = NULL;
		return rv;
	}

	#if defined(_DEBUG)
                #ifdef _WIN32 /* Added by Masanori Satake. */
		afxDump << "CMAPI library load success\n";	
                #else /* _UNIX or VX */
		PRINTERR("CMAPI library load success\n");
                #endif /* #ifdef _WIN32 */
	#endif

	rv = pCertCache->Initialize();

	if( 0 != rv )
	{
		sprintf(errorMsg,"Certificate Cache initialization failed code %li", rv );
		#if defined(_DEBUG)
                        #ifdef _WIN32 /* Added by Masanori Satake. */
			afxDump << "ERROR: " << errorMsg << "\n";
                        #else /* _UNIX or VX */
			PRINTERR("ERROR: ");
			PRINTERR(errorMsg);
			PRINTERR("\n");
                        #endif /* #ifdef _WIN32 */
		#endif
		delete pCMAPIInterface;	pCMAPIInterface = NULL;
		delete pCertCache;	pCertCache = NULL;
		delete pPathCache; pPathCache = NULL;
		return rv;
	}

	#if defined(_DEBUG)
                #ifdef _WIN32 /* Added by Masanori Satake. */
		afxDump << "Cert Cache init success\n";	
                #else /* _UNIX or VX */
		PRINTERR("Cert Cache init success\n");
                #endif /* #ifdef _WIN32 */
	#endif

	rv = pPathCache->Initialize(diskCacheDirectory);

	#if defined(_DEBUG)
	if( 0 == rv )
        #ifdef _WIN32 /* Added by Masanori Satake. */
	{	afxDump << "Path Cache init success\n";	}
        #else /* _UNIX or VX */
	{       PRITERR("Path Cache init success\n"); }
        #endif /* #ifdef _WIN32 */
	else
        #ifdef _WIN32 /* Added by Masanori Satake. */
	{	afxDump << "ERROR: Path Cache init failed code " << rv << "\n";	}
        #else /* _UNIX or VX */
	{
	  PRITERR("ERROR: Path Cache init failed code ");
	  PRITERR(rv);
	  PRITERR("\n");
	}
        #endif /* #ifdef _WIN32 */
	#endif

	if( PATHCACHE_INCOMPATABLE_VER == rv ||
		PATHCACHE_FILENOTFOUND == rv ||
		PATHCACHE_FILE_CORRUPT == rv ||
		PATH_CACHE_NO_DISK_PATH == rv )
	{
		// Non critical error - ignore it.
		rv = 0;
	}

	if( 0 == rv )
	{
		init_success = -1;
	}
	else
	{
		sprintf(errorMsg,"Path Cache initialization failed code %li", rv );
		delete pCMAPIInterface;	pCMAPIInterface = NULL;
		delete pCertCache;	pCertCache = NULL;
		delete pPathCache; pPathCache = NULL;
	}

	return rv;
}


long CPL_BeginPathDevelopment(	long* session, 
								char* subjectDN, 
								CPL_SESSION_INFO *sessionInfo,
								CertPath_struct *partialPath,
								int inhibitPolicyMapping,
								int requireExplicitPolicy, 
								char** desiredAlgOIDArray, 
								unsigned short keyUsage, 
								Bytes_struct* skid				)
{
	errorMsg[0] = '\0';

	long rv = 0;

	if( !init_success )
	{
		sprintf(errorMsg,"CPL_BeginPathDevelopment: Library not initialized.");
		#if defined(_DEBUG)
                        #ifdef _WIN32 /* Added by Masanori Satake. */
			afxDump << "ERROR: " << errorMsg << "\n";
                        #else /* _UNIX or VX */
			PRINTERR("ERROR: ");
			PRINTERR(errorMsg);
			PRINTERR("\n");
                        #endif /* #ifdef _WIN32 */
		#endif
		return CPL_LIBRARY_NOT_INIT;
	}

	// Check parameters
	if( NULL == session || NULL == sessionInfo )
	{
		sprintf(errorMsg,"CPL_BeginPathDevelopment: Required session related parameter is NULL.");
		#if defined(_DEBUG)
                        #ifdef _WIN32 /* Added by Masanori Satake. */
			afxDump << "ERROR: " << errorMsg << "\n";
                        #else /* _UNIX or VX */
			PRINTERR("ERROR: ");
			PRINTERR(errorMsg);
			PRINTERR("\n");
                        #endif /* #ifdef _WIN32 */
		#endif
		return CPL_PARAM_MISSING;
	}

	if( NULL == subjectDN && NULL == partialPath )
	{
		sprintf(errorMsg,"CPL_BeginPathDevelopment: Required target entity parameter is NULL.");
		#if defined(_DEBUG)
                        #ifdef _WIN32 /* Added by Masanori Satake. */
			afxDump << "ERROR: " << errorMsg << "\n";
                        #else /* _UNIX or VX */
			PRINTERR("ERROR: ");
			PRINTERR(errorMsg);
			PRINTERR("\n");
                        #endif /* #ifdef _WIN32 */
		#endif
		return CPL_PARAM_MISSING;
	}

	if( NULL == sessionInfo->freeCerts || NULL == sessionInfo->getCerts )
	{
		sprintf(errorMsg,"CPL_BeginPathDevelopment: Missing callback function pointer.");
		#if defined(_DEBUG)
                        #ifdef _WIN32 /* Added by Masanori Satake. */
			afxDump << "ERROR: " << errorMsg << "\n";
                        #else /* _UNIX or VX */
			PRINTERR("ERROR: ");
			PRINTERR(errorMsg);
			PRINTERR("\n");
                        #endif /* #ifdef _WIN32 */
		#endif
		return CPL_PARAM_MISSING;
	}

	if(  NULL == sessionInfo->rootDN  )
	{
		sprintf(errorMsg,"CPL_BeginPathDevelopment: Missing trusted root distinguished name.");
		#if defined(_DEBUG)
                        #ifdef _WIN32 /* Added by Masanori Satake. */
			afxDump << "ERROR: " << errorMsg << "\n";
                        #else /* _UNIX or VX */
			PRINTERR("ERROR: ");
			PRINTERR(errorMsg);
			PRINTERR("\n");
                        #endif /* #ifdef _WIN32 */
		#endif
		return CPL_PARAM_MISSING;
	}

	#if defined(_WIN32) && defined(_USE_WIN32_PTR_VALIDATION)
	// validate ptrs
	rv = 1;
	do
	{
		if( IsBadReadPtr( session, sizeof(ULONG) ) )
			break;

		if(  NULL != subjectDN && IsBadStringPtr( subjectDN, 1024 ))
			break;

		if( IsBadReadPtr( sessionInfo, sizeof(CPL_SESSION_INFO) ) )
			break;

		int XX = 0;
		while(sessionInfo->rootDN[XX] != NULL)
		{
			if( IsBadStringPtr( sessionInfo->rootDN[XX], 1024 ) )
				break;

			XX++;
		}

		// broke on bad ptr?
		if( sessionInfo->rootDN[XX] )
			break;


		if( NULL != partialPath )
		{

			if( IsBadReadPtr(partialPath,sizeof(CertPath_struct) ) )
				break;

			if( NULL == partialPath->asn1cert.data )
				break;

			if( IsBadReadPtr(partialPath->asn1cert.data, partialPath->asn1cert.num ) )
				break;

			if( NULL != partialPath->cert && IsBadCert(partialPath->cert) )
				break;
		}

		rv = 0;
	}
	while(FALSE);
	
	if( 0 != rv )
	{
		sprintf(errorMsg,"CPL_BeginPathDevelopment: Invalid pointer detected.");

		#if defined(_DEBUG)
                        #ifdef _WIN32 /* Added by Masanori Satake. */
			afxDump << "ERROR: " << errorMsg << "\n";
                        #else /* _UNIX or VX */
			PRINTERR("ERROR: ");
			PRINTERR(errorMsg);
			PRINTERR("\n");
                        #endif /* #ifdef _WIN32 */

			#if defined(_WIN32)
				ASSERT(FALSE);
			#endif
		#endif

		return CPL_PTR_INVALID;
	}

	#endif

	rv = CPLI_CreateNewSession(	session,
								subjectDN, 
								sessionInfo,
								partialPath,
								inhibitPolicyMapping,
								requireExplicitPolicy,
								desiredAlgOIDArray, 
								keyUsage, 
								skid					);

	#if defined(_DEBUG)
		ASSERT( 0 == rv );
	#endif

	last_session_in_use = *session;

	return CPLI_TranslateErrorNumber(rv);
}



long CPL_DoPathDevelopment(	long session, 
							CPL_SESSION_INFO * sessionInfo,
							CertPath_struct **certPath   )
{
	errorMsg[0] = '\0';

	long rv = 0;

	if( !init_success )
	{
		sprintf(errorMsg,"CPL_DoPathDevelopment: Library not initialized.");
		#if defined(_DEBUG)
                        #ifdef _WIN32 /* Added by Masanori Satake. */
			afxDump << "ERROR: " << errorMsg << "\n";
                        #else /* _UNIX or VX */
			PRINTERR("ERROR: ");
			PRINTERR(errorMsg);
			PRINTERR("\n");
                        #endif /* #ifdef _WIN32 */
		#endif
		return CPL_LIBRARY_NOT_INIT;
	}

	if( NULL == sessionInfo || NULL == certPath )
	{
		sprintf(errorMsg,"CPL_DoPathDevelopment: Required paramter missing.");
		#if defined(_DEBUG)
                        #ifdef _WIN32 /* Added by Masanori Satake. */
			afxDump << "ERROR: " << errorMsg << "\n";
                        #else /* _UNIX or VX */
			PRINTERR("ERROR: ");
			PRINTERR(errorMsg);
			PRINTERR("\n");
                        #endif /* #ifdef _WIN32 */
		#endif
		return CPL_PARAM_MISSING;
	}

	if( 0 >= session || session > CPL_MAX_SESSION )
		return CPL_INVALID_SESSION_HANDLE;

//	if( NULL != *certPath )
//		return CPL_PATH_MUST_BE_NULL;

	LPLOCAL_SESSION_INFO pLocalInfo = CPLI_GetSessionInfo(session);

	if( NULL == pLocalInfo)
		return CPL_NO_SUCH_SESSION;
// In CML1.57 we want to load the DN List by default
#ifdef CML156
	if( session != last_session_in_use )
	{
		pCertCache->SortCerts(sessionInfo->rootDN[0],sessionInfo->acceptablePolicySetArray);
	}
#else
		pCertCache->SortCerts(sessionInfo->rootDN[0],sessionInfo->acceptablePolicySetArray);
#endif
	if( pLocalInfo->usePathCache )
	{
		if( *certPath != NULL )
		{
			CPL_FreeCertPath(certPath);
		}
		rv = CPLI_DevelopPathFromCache(session, pLocalInfo, sessionInfo, certPath );
	}
	else
	{
		rv = CPLI_DevelopPath(session, pLocalInfo, sessionInfo, certPath );
	}

	while( CPLI_GET_NEXT_TARGET_CERT == rv )
	{
		rv = CPLI_DevelopPath(session, pLocalInfo, sessionInfo, certPath );
	}

	if( 0 != rv  )
	{
		if( *certPath != NULL )
		{
#ifndef VX /* Added by Masanori Satake. */
			try
			{
#endif
				CPL_FreeCertPath(certPath);
#ifndef VX /* Added by Masanori Satake. */
			}
			catch(...)
			{}
#endif
		}

		if( CERTCACHE_NO_MORE_CERTS == rv )
		{
			sprintf(errorMsg,"No more paths found");
			rv = CPL_NO_MORE_PATHS;
		}
	}


	return CPLI_TranslateErrorNumber(rv);
}


long CPL_EndPathDevelopment(	long session, 
								CPL_SESSION_INFO *sessionInfo,
								CertPath_struct **certPath,
								int pathStatus   )
{
	errorMsg[0] = '\0';

	long rv = 0;

	#if defined(_DEBUG)
                #ifdef _WIN32 /* Added by Masanori Satake. */
		afxDump << "CPL_EndPathDevelopment(" << session << ", " << sessionInfo << ", " << pathStatus << ")\n";
                #else /* _UNIX or VX */
		PRINTERR("CPL_EndPathDevelopment(");
		PRINTERR(session);
		PRINTERR(", ");
		PRINTERR(sessionInfo);
		PRINTERR(", ");
		PRINTERR(pathStatus);
		PRINTERR("\n");
                #endif /* #ifdef _WIN32 */
	#endif

	if( !init_success )
	{
		sprintf(errorMsg,"CPL_EndPathDevelopment: Library not initialized.");
		#if defined(_DEBUG)
                        #ifdef _WIN32 /* Added by Masanori Satake. */
			afxDump << "ERROR: " << errorMsg << "\n";
                        #else /* _UNIX or VX */
			PRINTERR("ERROR: ");
			PRINTERR(errorMsg);
			PRINTERR("\n");
                        #endif /* #ifdef _WIN32 */
		#endif
		return CPL_LIBRARY_NOT_INIT;
	}

	if( NULL == sessionInfo || 0 == pathStatus )
	{	
		if( NULL == sessionInfo )
			sprintf(errorMsg,"CPL_EndPathDevelopment: sessionInfo pointer is NULL.");
		if( 0 == pathStatus )
			sprintf(errorMsg,"CPL_EndPathDevelopment: Invalid value for pathStatus.");

		#if defined(_DEBUG)
                        #ifdef _WIN32 /* Added by Masanori Satake. */
			afxDump << "ERROR: " << errorMsg << "\n";
                        #else /* _UNIX or VX */
			PRINTERR("ERROR: ");
			PRINTERR(errorMsg);
			PRINTERR("\n");
                        #endif /* #ifdef _WIN32 */
		#endif

		return CPL_PARAM_MISSING;
	}

	if( 0 >= session || session > CPL_MAX_SESSION )
	{
		sprintf(errorMsg,"CPL_EndPathDevelopment: Invalid session handle passed.");
		#if defined(_DEBUG)
                        #ifdef _WIN32 /* Added by Masanori Satake. */
			afxDump << "ERROR: " << errorMsg << "\n";
                        #else /* _UNIX or VX */
			PRINTERR("ERROR: ");
			PRINTERR(errorMsg);
			PRINTERR("\n");
                        #endif /* #ifdef _WIN32 */
		#endif
		return CPL_INVALID_SESSION_HANDLE;
	}

	if( NULL == CPLI_GetSessionInfo(session) )
	{
		sprintf(errorMsg,"CPL_EndPathDevelopment: The specified session does not exist.");
		#if defined(_DEBUG)
                        #ifdef _WIN32 /* Added by Masanori Satake. */
			afxDump << "ERROR: " << errorMsg << "\n";
                        #else /* _UNIX or VX */
			PRINTERR("ERROR: ");
			PRINTERR(errorMsg);
			PRINTERR("\n");
                        #endif /* #ifdef _WIN32 */
		#endif
		return CPL_NO_SUCH_SESSION;
	}

	if( certPath && *certPath )
	{
		// save path info if good
		if( CPL_LAST_PATH_VALID == pathStatus  )
		{
			#if defined(_DEBUG)
                                #ifdef _WIN32 /* Added by Masanori Satake. */
				afxDump << "CPL_EndPathDevelopment: Saving path to path cache";
                                #else /* _UNIX or VX */
				PRINTERR("CPL_EndPathDevelopment: Saving path to path cache");
                                #endif /* #ifdef _WIN32 */
			#endif
			CertPath_struct *pPath = *certPath;
			while( pPath && pPath->next )
			{
				#if defined(_DEBUG)
                                        #ifdef _WIN32 /* Added by Masanori Satake. */
					afxDump << ".";
                                        #else /* _UNIX or VX */
					PRINTERR(".");
                                        #endif /* #ifdef _WIN32 */
				#endif
				pPathCache->AddEntry(pPath->cert,pPath->next->cert);
				pPath = pPath->next;
			}
			#if defined(_DEBUG)
                                #ifdef _WIN32 /* Added by Masanori Satake. */
				afxDump << "\n";
                                #else /* _UNIX or VX */
				PRINTERR("\n");
                                #endif /* #ifdef _WIN32 */
			#endif
		}

		// free cert path if it exists
		CPL_FreeCertPath(certPath);
	}
	#if defined(_DEBUG)
	else
	{
                #ifdef _WIN32 /* Added by Masanori Satake. */
		afxDump << "\t*certPath == NULL\n";
                #else /* _UNIX or VX */
		PRINTERR("\t*certPath == NULL\n");
                #endif /* #ifdef _WIN32 */
	}
	#endif

	CPLI_DestroySession(session);

	return CPLI_TranslateErrorNumber(rv);
}

void CPL_FreeCertPath(CertPath_struct **certPath)
{
	errorMsg[0] = '\0';

	if( NULL == certPath )
		return;

#ifndef VX /* Added by Masanori Satake. */
	try
	{
#endif
		#if defined(_DEBUG)
                        #ifdef _WIN32 /* Added by Masanori Satake. */
			afxDump << "CPL_FreeCertPath: Freeing certs";
                        #else /* _UNIX or VX */
			PRINTERR("CPL_FreeCertPath: Freeing certs");
                        #endif /* #ifdef _WIN32 */
		#endif

		CertPath_struct *pTmp = *certPath;
		CertPath_struct *pDel = NULL;

		while( NULL != pTmp )
		{
			delete [](pTmp->asn1cert.data);
			pCMAPIInterface->FreeCert(&(pTmp->cert));
			pDel = pTmp;
			pTmp = pTmp->next;
			delete pDel;

			#if defined(_DEBUG)
                                #ifdef _WIN32 /* Added by Masanori Satake. */
				afxDump << ".";
                                #else /* _UNIX or VX */
				PRINTERR(".");
                                #endif /* #ifdef _WIN32 */
			#endif
		}

		#if defined(_DEBUG)
                        #ifdef _WIN32 /* Added by Masanori Satake. */
			afxDump << "done.\n";
                        #else /* _UNIX or VX */
			PRINTERR("done.\n");
                        #endif /* #ifdef _WIN32 */
		#endif
#ifndef VX /* Added by Masanori Satake. */
	}
	catch(...)
	{
		#if defined(_DEBUG)
                        #ifdef _WIN32 /* Added by Masanori Satake. */
			afxDump << "ERROR: Exception caught in CPL_FreeCertPath\n";
                        #else /* _UNIX or VX */
			PRINTERR("ERROR: Exception caught in CPL_FreeCertPath\n");
                        #endif /* #ifdef _WIN32 */
		#if defined(_WIN32)
			ASSERT(FALSE);
		#endif
		#endif
	}
#endif
	*certPath = NULL;

}



long CPL_TerminateLibrary()
{
	errorMsg[0] = '\0';

	long rv = 0;
	term_called = 1;

	#if defined(_DEBUG)
                #ifdef _WIN32 /* Added by Masanori Satake. */
		afxDump << "CPL_TerminateLibrary()\n";
		afxDump.Flush();
                #else /* _UNIX or VX */
		PRINTERR("CPL_TerminateLibrary()\n");
                #endif /* #ifdef _WIN32 */
	#endif

	if( !init_success )
	{
		sprintf(errorMsg,"CPL_TerminateLibrary: Library not initialized.");
		#if defined(_DEBUG)
                        #ifdef _WIN32 /* Added by Masanori Satake. */
			afxDump << "ERROR: " << errorMsg << "\n";
                        #else /* _UNIX or VX */
			PRINTERR("ERROR: ");
			PRINTERR(errorMsg);
			PRINTERR("\n");
                        #endif /* #ifdef _WIN32 */
		#endif
		return CPL_LIBRARY_NOT_INIT;
	}

	// Clean up sessions if exist
	for( int XX = 0; XX < CPL_MAX_SESSION;XX++ )
	{
		CPLI_DestroySession(XX+1);
	}

#ifndef VX /* Added by Masanori Satake. */
	try
	{
#endif
		init_success = 0;

		rv = pPathCache->Serialize();

		#if defined(_NO_ERR_ON_BAD_DISK_PATH)
			if( PATH_CACHE_NO_DISK_PATH == rv )
				rv = 0;
		#endif

		if( 0 != rv )
		{
			sprintf(errorMsg,"An error occurred while writing the path cache file.");
			#if defined(_DEBUG)
                                #ifdef _WIN32 /* Added by Masanori Satake. */
				afxDump << "ERROR: " << errorMsg << "\n";
                                #else /* _UNIX or VX */
				PRINTERR("ERROR: ");
				PRINTERR(errorMsg);
				PRINTERR("\n");
                                #endif /* #ifdef _WIN32 */
			#endif
		}

		delete pCertCache;	pCertCache = NULL;
		delete pPathCache;  pPathCache = NULL;
		delete pCMAPIInterface; pCMAPIInterface = NULL;
#ifndef VX /* Added by Masanori Satake. */
	}
	catch(...)
	{
		#if defined(_DEBUG)
                        #ifdef _WIN32 /* Added by Masanori Satake. */
			afxDump << "ERROR: Exception caught in CPL_FreeCertPath\n";
                        #else /* _UNIX or VX */
			PRINTERR("ERROR: Exception caught in CPL_FreeCertPath\n");
                        #endif /* #ifdef _WIN32 */
		#if defined(_WIN32)
			ASSERT(FALSE);
		#endif
		#endif
	}
#endif
	return CPLI_TranslateErrorNumber(rv);
}


#ifdef _DEBUG_VERBOSE
#undef _DEBUG_VERBOSE
#endif

#undef _USE_WIN32_PTR_VALIDATION

/*
 } 

*/
