/*

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     :   CertCache.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.
\*------------------------------------------------------------------------*/


// CertCache.cpp: implementation of the CCertCache class.
//
//////////////////////////////////////////////////////////////////////

#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"
#ifdef KCM_MEMDBG
#include "stdio.h"
#endif
#endif

#include "CertCache.h"
#include "CMAPIInterface.h"
#include "utils.h"
#include "Defines.h"

#if !defined(_WIN32)
#include "stristr.h"
#endif

#if defined(_DEBUG) && defined(_AFXDLL)
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//#define _DEBUG_VERBOSE

extern CCMAPIInterface *pCMAPIInterface;

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CCertCache::CCertCache()
{

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

	m_entryCount = 0;
	m_lpCertTable = NULL;
	m_lpszErrorString = new char[256];
	memset(m_lpszErrorString,0,sizeof(char) * 256);
	m_lpszLastTrustedRootDN = NULL;
	m_lpLastArrPolicySet = NULL;
	m_policyCount = 0;
	m_lastEntryNum = 0;
}

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

	if( NULL != m_lpCertTable )
	{
		delete m_lpCertTable;
		m_lpCertTable = NULL;
	}
	if( NULL != m_lpszErrorString )
	{
		delete m_lpszErrorString;
		m_lpszErrorString = NULL;
	}
	if( NULL != m_lpszLastTrustedRootDN )
	{
		delete []m_lpszLastTrustedRootDN;
		m_lpszLastTrustedRootDN = NULL;
	}
	if( NULL != m_lpLastArrPolicySet )
	{
		CPLI_FreeStringArray(&m_lpLastArrPolicySet);
	}
}

/*-------------------------------------------------------------------------*\
|  Function Name :   SortCerts(char *trustedRootDN, char **acceptablePolicySet)
|  Creation Date :   May 17, 1999
|  Author        :   Matt Cooper
|  Last Mode Date:   May 17, 1999
|---------------------------------------------------------------------------
|	        
|  Purpose:	Sorts the certificate list according to the rules specified in
|	        the CPL ICD.  
|  Exception Handling: None
|---------------------------------------------------------------------------
|  Inputs Params:   trustedRootDN - the DN to which a path will be developed
|	                acceptablePolicySet - NULL terminated string array of
|							policy oids in the user specified acceptable set
|  Pre-Conditions:  
|  Post-Conditions: 
|  Return values:   
|	                
\*-------------------------------------------------------------------------*/
long CCertCache::SortCerts(char *trustedRootDN, char **acceptablePolicySet)
{

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

	long rv = 0;
	long vPos = 0;
	BOOL sortAll = FALSE;
	int pCount = 0;
	int XX;

	#if defined(_WIN32) && defined (_DEBUG) && defined(_DEBUG_VERBOSE)
	int col = 0;
	#endif
	CCertsRec *pRec = NULL;

	// determine if sorting is required as a result of the root dn changing
	if( NULL != trustedRootDN )
	{
		#if defined(_DEBUG) && defined(_DEBUG_VERBOSE)
                #ifdef _WIN32 /* Added by Masanori Satake. */
			afxDump << trustedRootDN << ", ";
                #else /* _UNIX or VX */
			PRINTERR(trustedRootDN);
			PRINTERR(",");
                #endif /* #ifdef _WIN32 */
		#endif

		do
		{
			if( NULL != m_lpszLastTrustedRootDN )
			{
				if( CPLI_IsSameDN(m_lpszLastTrustedRootDN,trustedRootDN) )
				{
					// no change
					break;
				}
				else
				{	
					// changing the trust root
					delete []m_lpszLastTrustedRootDN;
				}
			}

			m_lpszLastTrustedRootDN  = new char[strlen(trustedRootDN)+2];
			if( NULL == m_lpszLastTrustedRootDN  )
			{
				return CERTCACHE_ALLOC_FAIL;
			}
			strcpy(m_lpszLastTrustedRootDN,trustedRootDN);
			CPLI_SquashSpacesInDN(m_lpszLastTrustedRootDN);
			sortAll = TRUE;

		}
		while(FALSE);
	}
	// else leave old root in place
	#if defined(_DEBUG) && defined(_DEBUG_VERBOSE)
	else
        #ifdef _WIN32 /* Added by Masanori Satake. */
		afxDump << "NULL, ";
        #else /* _UNIX or VX */
	        PRINTERR("NULL,");
        #endif /* #ifdef _WIN32 */
	#endif


	// Has the acceptable policy set changed?
	if( NULL != acceptablePolicySet )
	{
		#if defined(_DEBUG) && defined(_DEBUG_VERBOSE)
                #ifdef _WIN32 /* Added by Masanori Satake. */
			afxDump << *acceptablePolicySet << ")\n";
                #else /* _UNIX or VX */
			PRINTERR(*acceptablePolicySet);
			PRINTERR(")\n");
                #endif /* #ifdef _WIN32 */
		#endif

		do
		{
			for( ;;pCount++)
			{
				if( acceptablePolicySet[pCount] == NULL )
					break;
			}


			if( NULL != m_lpLastArrPolicySet )
			{
				if( m_policyCount != pCount )
				{
					for( XX = 0; XX < m_policyCount; XX++ )
					{
						if( m_lpLastArrPolicySet[XX] )
							delete [](m_lpLastArrPolicySet[XX]);
					}
					delete []m_lpLastArrPolicySet;
					m_lpLastArrPolicySet = NULL;
				}
				else
				{
					for( XX = 0; XX < m_policyCount; XX++ )
					{
						if( m_lpLastArrPolicySet[XX] && 0 != strcmp(acceptablePolicySet[XX],m_lpLastArrPolicySet[XX] ) )
						{
							break;
						}
					}

					if( XX < m_policyCount )
					{
						if( m_lpLastArrPolicySet )
						{
							for( XX = 0; XX < m_policyCount; XX++ )
							{
								if( m_lpLastArrPolicySet[XX] )
									delete [](m_lpLastArrPolicySet[XX]);
							}
							delete []m_lpLastArrPolicySet;
							m_lpLastArrPolicySet = NULL;
						}

						m_policyCount = 0;
					}
				}

			}

			if( NULL == m_lpLastArrPolicySet )
			{
				m_lpLastArrPolicySet = new char*[pCount+1];
				if( NULL == m_lpLastArrPolicySet )
						return CERTCACHE_ALLOC_FAIL;

				m_policyCount = pCount;
				m_lpLastArrPolicySet[pCount] = NULL;

				for( XX = 0; XX < m_policyCount; XX++ )
				{
					m_lpLastArrPolicySet[XX] = new char[strlen(acceptablePolicySet[XX])+2];
					if( NULL == m_lpLastArrPolicySet[XX] )
						return CERTCACHE_ALLOC_FAIL;
					
					strcpy( m_lpLastArrPolicySet[XX], acceptablePolicySet[XX] );
					m_lpLastArrPolicySet[XX+1] = NULL;
				}

				sortAll = TRUE;
			}

		}
		while(FALSE);
	}
	else
	{
		#if defined(_DEBUG) && defined(_DEBUG_VERBOSE)
                #ifdef _WIN32 /* Added by Masanori Satake. */
			afxDump << "NULL)\n";
                #else /* _UNIX or VX */
			PRINTERR("NULL)\n");
                #endif /* #ifdef _WIN32 */
		#endif

		if(m_lpLastArrPolicySet)
		{
			for( XX = 0; XX < m_policyCount; XX++ )
			{
				if( m_lpLastArrPolicySet[XX] )
					delete [](m_lpLastArrPolicySet[XX]);
			}
			delete []m_lpLastArrPolicySet;
			m_lpLastArrPolicySet = NULL;
		}
		m_policyCount = 0;
	}


	// loop through all records and sort any cert list which requires sorting.
	for( ; vPos < CERTCACHE_TABLE_SIZE; vPos++ )
	{
		pRec = m_lpCertTable->HashVector[vPos];
		while( NULL != pRec )
		{
			if( sortAll || pRec->m_modified)
			{
				pRec->SortCerts(m_lpszLastTrustedRootDN,m_lpLastArrPolicySet);

				#if defined(_WIN32) && defined (_DEBUG) && defined(_DEBUG_VERBOSE)
				afxDump << pRec->m_entryNumber << ", ";
				if( ++col > 20 )
				{
					afxDump << "\n";
					col = 0;
				}
				Sleep(1);
				afxDump.Flush();
				#endif
			}

			#if defined(_WIN32) && defined (_DEBUG)
			if( pRec->m_entryNumber > m_lastEntryNum )
				afxDump << "**** ERROR: pRec->m_entryNumber > m_lastEntryNum!\n"; 
			#endif

			pRec = pRec->NextRec;
		}
	}

	return 0;
}


/*-------------------------------------------------------------------------*\
|  Function Name :   Initialize()
|  Creation Date :   May 17, 1999
|  Author        :   Matt Cooper
|  Last Mode Date:   May 17, 1999
|---------------------------------------------------------------------------
|	        
|  Purpose:	Allocates the cert cache table
|	        
|  Exception Handling: 
|---------------------------------------------------------------------------
|  Inputs Params:   N/A
|	                
|	                
|  Pre-Conditions:  Allocated, or not
|  Post-Conditions: Allocated
|  Return values:   0
|	                
\*-------------------------------------------------------------------------*/
long CCertCache::Initialize()
{
	#if defined(_DEBUG) && defined(_DEBUG_VERBOSE)
        #ifdef _WIN32 /* Added by Masanori Satake. */
		afxDump << "CCertCache::Initialize()\n";
        #else /* _UNIX or VX */
		PRINTERR("CCertCache::Initialize()\n");
        #endif /* #ifdef _WIN32 */
	#endif

	if( NULL == m_lpCertTable )
	{
		m_lpCertTable = new CMemCache<CCertsRec>(CERTCACHE_TABLE_SIZE);
		if( NULL == m_lpCertTable )
			return CERTCACHE_ALLOC_FAIL;
	}

	return 0;
}


/*-------------------------------------------------------------------------*\
|  Function Name :   ReindexEntryNums()
|  Creation Date :   May 17, 1999
|  Author        :   Matt Cooper
|  Last Mode Date:   May 17, 1999
|---------------------------------------------------------------------------
|	        
|  Purpose:	Reindex all the cert records so that the record numbers start
|	        with 1 and go through m_lastEntryNum
|  Exception Handling: 
|---------------------------------------------------------------------------
|  Inputs Params:   N/A
|	                
|	                
|  Pre-Conditions:  Entry nums in order or not
|  Post-Conditions: Entry numbers in order
|  Return values:   
|	                
\*-------------------------------------------------------------------------*/
long CCertCache::ReindexEntryNums()
{

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

	CCertsRec *pRec = NULL;
	CCertsRec **pRecs = NULL;

#undef RETURN
#ifndef VX /* Added by Masanori Satake. */
#define RETURN(r){ if( NULL != pRecs ){	try{ delete []pRecs; pRecs = NULL; }catch(...){} } return r; }
#else
#define RETURN(r){ if( NULL != pRecs ){	delete []pRecs; pRecs = NULL; } return r; }
#endif

	#if defined(_WIN32) && defined (_DEBUG)
	DWORD startt = GetTickCount();
	#endif

	long vPos = 0;
	long errVal = 0;
	long nullCount = 0;
	long entryCount = 0;

	if( m_entryCount >= CERTCACHE_MAX_ENTRY_COUNT + CERTCACHE_MAX_ENTRY_FLUX)
	{
		return RemoveOldItems();
	}

	#if defined(_WIN32) && defined (_DEBUG)
	afxDump << "Reindexing cert cache entry numbers..\n";
	#endif

	pRecs = new CCertsRec*[m_lastEntryNum + 8];
	if( NULL == pRecs )
		RETURN(CERTCACHE_ALLOC_FAIL);

	memset(pRecs,0,sizeof(CCertsRec*)*(m_lastEntryNum + 8));


	#if defined(_WIN32) && defined (_DEBUG) && defined(_DEBUG_VERBOSE)
	afxDump << "Adding entries to index vector:\n";
	int col = 0;
	#endif

	for( ; vPos < CERTCACHE_TABLE_SIZE; vPos++ )
	{
		pRec = m_lpCertTable->HashVector[vPos];
		while( NULL != pRec )
		{
			#if defined(_WIN32) && defined (_DEBUG) && defined(_DEBUG_VERBOSE)
			afxDump << pRec->m_entryNumber << ", ";
			if( ++col > 20 )
			{
				afxDump << "\n";
				col = 0;
			}
			Sleep(3);
			afxDump.Flush();
			#endif

			if( pRec->m_entryNumber <= m_lastEntryNum )
			{
				#if defined(_WIN32) && defined (_DEBUG)
				if( NULL != pRecs[pRec->m_entryNumber] )
				{
					ASSERT(FALSE);
				}
				#endif

				pRecs[pRec->m_entryNumber] = pRec;
			}
			#if defined(_WIN32) && defined (_DEBUG)
			else
			{	afxDump << "**** ERROR: pRec->m_entryNumber > m_lastEntryNum!\n"; }
			#endif

			pRec = pRec->NextRec;
		}
	}

	#if defined(_WIN32) && defined (_DEBUG) && defined(_DEBUG_VERBOSE)
	afxDump << "\n";
	#endif

	#if defined(_WIN32) && defined(_DEBUG) && defined(_DEBUG_VERBOSE)
	int lf = 17;
	afxDump << "Vector completed.\nAssigning numbers";
	#endif

	for( vPos = 1; vPos <= m_lastEntryNum; vPos++ )
	{
		if( NULL == pRecs[vPos] )
			nullCount++;
		else
		{
			pRecs[vPos]->m_entryNumber -= nullCount;
			entryCount++;
			#if defined(_WIN32) && defined(_DEBUG) && defined(_DEBUG_VERBOSE)
			afxDump << ".";
			if( ++lf == 60 )
			{
				afxDump << "\n";
				lf = 0;
			}
			#endif
		}

	}

	m_lastEntryNum = entryCount;
	m_entryCount = entryCount;

	#if defined(_WIN32) && defined(_DEBUG) && defined(_DEBUG_VERBOSE)
	afxDump << "\nReturning from CCertCache::ReindexEntryNums()\n";
	#endif

	#if defined(_WIN32) && defined (_DEBUG)
	DWORD stopt = GetTickCount();
	stopt -= startt;
	afxDump << "\nElapsed: " << stopt << " milliseconds.\n";
	#endif


	RETURN(0);
}


/*-------------------------------------------------------------------------*\
|  Function Name :   RemoveOldItems()
|  Creation Date :   May 17, 1999
|  Author        :   Matt Cooper
|  Last Mode Date:   May 17, 1999
|---------------------------------------------------------------------------
|	        
|  Purpose:	Deletes lowest indexed items from cache
|	        
|  Exception Handling: 
|---------------------------------------------------------------------------
|  Inputs Params:   None
|	                
|	                
|  Pre-Conditions:  > CERTCACHE_MAX_ENTRY_COUNT + CERTCACHE_MAX_ENTRY_FLUX records
|					in cache, or not
|  Post-Conditions: CERTCACHE_MAX_ENTRY_COUNT - CERTCACHE_MAX_ENTRY_FLUX records
|					in cache
|  Return values:   0 on success
|	                
\*-------------------------------------------------------------------------*/
long CCertCache::RemoveOldItems()
{
	#if defined(_DEBUG) && defined(_DEBUG_VERBOSE)
        #ifdef _WIN32 /* Added by Masanori Satake. */
		afxDump << "CCertCache::RemoveOldItems()\n";
        #else /* _UNIX or VX */
		PRINTERR("CCertCache::\n");
        #endif /* #ifdef _WIN32 */
	#endif

	#if defined(_WIN32) && defined (_DEBUG)
	DWORD startt = GetTickCount();
	#endif

	CCertsRec *pRec = NULL;
	long vPos = 0;
	long doubleFlux = 0;
	CCertsRec *pRecList = NULL;
	CCertsRec *pListEnd = NULL;
	long errVal = 0;
	long delCount = 0;
	CCertsRec **pRecs = NULL;
	long nullCount = 0;
	long entryCount = 0;

#undef RETURN
#ifndef VX /* Added by Masanori Satake. */
#define RETURN(r){ if( NULL != pRecList ){	try{ delete pRecList; pRecList = NULL; }catch(...){} } if( NULL != pRecs ) {	try{ delete []pRecs; pRecs = NULL; }catch(...){} } return r; }	
#else
#define RETURN(r){if(NULL != pRecList){ delete pRecList; pRecList = NULL;} if( NULL != pRecs ){delete []pRecs; pRecs = NULL;} return r; }
#endif
	if( m_entryCount < CERTCACHE_MAX_ENTRY_COUNT + CERTCACHE_MAX_ENTRY_FLUX)
		return 0;

	#if defined(_WIN32) && defined (_DEBUG)
	afxDump << "Dumping old path entries..\n";
	#endif

	doubleFlux = 2 * CERTCACHE_MAX_ENTRY_FLUX;

	pRecList = new CCertsRec;
	if( NULL == pRecList )
	{	return CERTCACHE_ALLOC_FAIL; }

	pRecs = new CCertsRec*[m_lastEntryNum + 8];
	if( NULL == pRecs )
		RETURN(CERTCACHE_ALLOC_FAIL);

	memset(pRecs,0,sizeof(CCertsRec*)*(m_lastEntryNum + 8));

/*
	pRecs = new CCertsRec*[CERTCACHE_MAX_ENTRY_COUNT+CERTCACHE_MAX_ENTRY_FLUX+8];
	if( NULL == pRecs )
		RETURN(CERTCACHE_ALLOC_FAIL);

	memset(pRecs,0,sizeof(CCertsRec*)*(CERTCACHE_MAX_ENTRY_COUNT+CERTCACHE_MAX_ENTRY_FLUX+8));
*/
	pListEnd = pRecList;


	do
	{

		for( ; vPos < CERTCACHE_TABLE_SIZE; vPos++ )
		{
			pRec = m_lpCertTable->HashVector[vPos];
			while( NULL != pRec )
			{
				if( pRec->m_entryNumber <= doubleFlux )
				{
					#if defined(_WIN32) && defined (_DEBUG) && defined(_DEBUG_VERBOSE)
					afxDump << pRec->m_entryNumber << " tagged for deletion.\n";
					Sleep(5);
					afxDump.Flush();
					#endif
					//pRec->m_entryNumber = 0;
					delCount++;

					pListEnd->CopyFrom(pRec);
					pListEnd->NextRec = new CCertsRec;
					pListEnd = pListEnd->NextRec;

					if( NULL == pListEnd)
					{
						vPos = CERTCACHE_TABLE_SIZE + 100;
						errVal = CERTCACHE_ALLOC_FAIL;
						break;
					}
				}
				else
				{

					#if defined(_WIN32) && defined (_DEBUG) && defined(_DEBUG_VERBOSE)
					afxDump << "EntryNumber " << pRec->m_entryNumber;
					#endif

					pRec->m_entryNumber -= doubleFlux;

					#if defined(_WIN32) && defined (_DEBUG) && defined(_DEBUG_VERBOSE)
					afxDump << " to " << pRec->m_entryNumber << "\n";
					Sleep(5);
					afxDump.Flush();
					#endif

					if( pRec->m_entryNumber <= m_lastEntryNum  )
					{
						#if defined(_WIN32) && defined (_DEBUG)
						if( NULL != pRecs[pRec->m_entryNumber] )
						{
							ASSERT(FALSE);
						}
						#endif

						pRecs[pRec->m_entryNumber] = pRec;
					}
					#if defined(_WIN32) && defined (_DEBUG)
					else
					{
						afxDump << "**** ERROR: pRec->m_entryNumber > m_lastEntryNum!\n"; 
						afxDump << "pRec->m_entryNumber == " << pRec->m_entryNumber << "\n";
						Sleep(5);
						afxDump.Flush();
					}
					#endif

				}

				pRec = pRec->NextRec;
			}
		}

		if( 0 != errVal )
			RETURN(errVal);
	}
	while(FALSE);

	#if defined(_WIN32) && defined(_DEBUG)
	int lf = 8;
	afxDump << delCount << " entries tagged for deletion..\nDeleting";
	#endif

	pListEnd = pRecList;
	for( vPos = 0; vPos < delCount; vPos++ )
	{
		if( NULL == pListEnd )
		{
			#if defined(_WIN32) && defined(_DEBUG)
			afxDump << "**** Error: pListEnd == NULL ****\n****   vPos == " << vPos << "\n****   delCount == " << delCount << "\n";
			#endif
			break;
		}

		#if defined(_WIN32) && defined(_DEBUG) && defined(_DEBUG_VERBOSE)
		afxDump << ".";
		if( ++lf >= 60 )
		{
			afxDump << "\n";
			lf = 0;
		}
		afxDump.Flush();
		#endif

		m_lpCertTable->Delete(*pListEnd);

		pListEnd = pListEnd->NextRec;

	}

	#if defined(_WIN32) && defined(_DEBUG)
	afxDump << "\nDone deleting entries, beginning time re-index\n";
	#endif

	for( vPos = 1; vPos <= m_lastEntryNum; vPos++ )
	{
		if( NULL == pRecs[vPos] )
			nullCount++;
		else
		{

			#if defined(_WIN32) && defined(_DEBUG) && defined(_DEBUG_VERBOSE)
			afxDump << "Index " << pRecs[vPos]->m_entryNumber << " to " << pRecs[vPos]->m_entryNumber - nullCount << "\n";
			Sleep(5);
			afxDump.Flush();
			Sleep(0);
			#endif
			pRecs[vPos]->m_entryNumber -= nullCount;
			entryCount++;
		}

	}

	m_lastEntryNum = entryCount;
	m_entryCount = entryCount;

	#if defined(_WIN32) && defined(_DEBUG) && defined(_DEBUG_VERBOSE)
	afxDump << "-------------------------------------------\nReturning from CCertCache::RemoveOldItems()\n";
	#endif

	#if defined(_WIN32) && defined (_DEBUG)
	DWORD stopt = GetTickCount();
	stopt -= startt;
	afxDump << "Elapsed: " << stopt << " milliseconds.\n-------------------------------------------\n";
	#endif

	RETURN(0);
}

  
/*-------------------------------------------------------------------------*\
|  Function Name :   AddEntry(Bytes_struct *pBinCert, long type, CCertsRec **pNewRec )
|  Creation Date :   May 17, 1999
|  Author        :   Matt Cooper
|  Last Mode Date:   May 17, 1999
|---------------------------------------------------------------------------
|	        
|  Purpose:	Adds one cert to the cache, creates a new record if needed
|	        
|  Exception Handling: 
|---------------------------------------------------------------------------
|  Inputs Params:   pBinCert - binary der encoded certificate
|	                type - e.g. CA_CERT_TYPE - directory entry retrieved from
|	                (OPTIONAL) pNewRec - returns record pointer for entry
|  Pre-Conditions:  Initialize()
|  Post-Conditions: Cert added
|  Return values:   0 on success
|	                
\*-------------------------------------------------------------------------*/
long CCertCache::AddEntry(Bytes_struct *pBinCert, long type, CCertsRec **pNewRec )
{
	#if defined(_DEBUG) && defined(_DEBUG_VERBOSE)
        #ifdef _WIN32 /* Added by Masanori Satake. */
		afxDump << "CCertCache::AddEntry(...)\n";
        #else /* _UNIX or VX */
		PRINTERR("CCertCache::AddEntry(...)\n");
        #endif /* #ifdef _WIN32 */
	#endif

	m_lpszErrorString[0] = '\0';
	long rv = 0;
	CCertsRec *pRec = NULL;
	Cert_struct *pCert = NULL;

#undef RETURN
#ifndef VX /* Added by Masanori Satake. */
#define RETURN(r){if( NULL != pCert ) {	try{ pCMAPIInterface->FreeCert(&pCert); }catch(...){} } return r; } 
#else
#define RETURN(r){if( NULL != pCert ) {pCMAPIInterface->FreeCert(&pCert);} return r; } 
#endif

	if( !IsValid() )
		return CERTCACHE_NOT_INITIALIZED;

	if( m_entryCount > CERTCACHE_MAX_ENTRY_FLUX + CERTCACHE_MAX_ENTRY_COUNT )
	{
		rv = RemoveOldItems();
		if( 0 != rv )
			return rv;
	}

	tmpCertRec.FreeEntry();

	rv = pCMAPIInterface->DecodeCert(pBinCert->data, &pCert);

	if( 0 != rv )
	{
		strcpy( m_lpszErrorString, pCMAPIInterface->m_lpszErrorString );
		RETURN(rv);
	}

	if( IsBadCert(pCert) )
	{
		RETURN(CERTCACHE_INVALID_CERT_DATA);
	}

	rv = tmpCertRec.set_entry(pCert->subject);
	if( 0 != rv )
	{
		RETURN(rv);
	}

//	CacheRec* Search(const CacheRec &search_rec);
	pRec = m_lpCertTable->Search(tmpCertRec);

	if( NULL == pRec )
	{
		if( !m_lpCertTable->Insert(tmpCertRec) )
		{
			RETURN(CERTCACHE_INSERT_ERROR);
		}

		pRec = m_lpCertTable->Search(tmpCertRec);

		if( NULL == pRec )
		{
			RETURN(CERTCACHE_INSERT_ERROR);
		}

		pRec->m_entryNumber = ++m_lastEntryNum;
		m_entryCount++;
	}

	rv = pRec->AddCert(pCert,pBinCert,type);

	if( CCERTSREC_DUPLICATE_CERT == rv )
	{
		pCMAPIInterface->FreeCert(&pCert);
		rv = 0; 
	}

	if( 0 != rv  )
	{
		RETURN(rv);
	}


	// CCertsRec will take care of cert now..
	pCert = NULL;

	if( NULL != pNewRec )
	{
		*pNewRec = pRec;
	}

//	
	RETURN(0);
}

/*-------------------------------------------------------------------------*\
|  Function Name :   IsValid()  
|  Creation Date :   May 17, 1999
|  Author        :   Matt Cooper
|  Last Mode Date:   May 17, 1999
|---------------------------------------------------------------------------
|	        
|  Purpose:	Validates that the cache is allocated and reindexes the entry
|	        numbers if needed.
|  Exception Handling: 
|---------------------------------------------------------------------------
|  Inputs Params:   None
|	                
|	                
|  Pre-Conditions:  None
|  Post-Conditions: See ReindexEntryNums if m_lastEntryNum >= ( 2*CERTCACHE_MAX_ENTRY_COUNT ) 
|  Return values:   0 if innvalid
|	                1 if valid     (Boolean return)
\*-------------------------------------------------------------------------*/
long CCertCache::IsValid()
{
	#if defined(_DEBUG) && defined(_DEBUG_VERBOSE)
        #ifdef _WIN32 /* Added by Masanori Satake. */
		afxDump << "CCertCache::IsValid()\n";
        #else /* _UNIX or VX */
		PRINTERR("CCertCache::IsValid()\n");
        #endif /* #ifdef _WIN32 */
	#endif

	if( NULL == m_lpCertTable )
		return 0;

	if( m_lastEntryNum >= ( 2*CERTCACHE_MAX_ENTRY_COUNT ) )
	{
		ReindexEntryNums();
	}

	return 1;
}



/*-------------------------------------------------------------------------*\
|  Function Name :   GetNextCert
|  Creation Date :   May 17, 1999
|  Author        :   Matt Cooper
|  Last Mode Date:   May 17, 1999
|---------------------------------------------------------------------------
|	        
|  Purpose:	Returns first and next certs from a record specified by subject
|	        Uses user provided callback functions to obtain certificates
|			and adds the certificates to the cache.
|  Exception Handling: 
|---------------------------------------------------------------------------
|  Inputs Params:   subject - DN of the subject for which a cert is needed
|	                sessMask - the user session mask ( from local info struct )
|	                sessInfo - user supplied session info pointer
|					pEntry - return parameter - pointer to cert data
|  Pre-Conditions:  Initialize and presumably
|  Post-Conditions: Certificate marked as checked for the user within the cache
|  Return values:   0 on success
|	                
\*-------------------------------------------------------------------------*/
long CCertCache::GetNextCert(char *subject, ULONG sessMask, LPCPL_SESSION_INFO sessInfo, LPCERTCACHE_ENTRY_STRUCT *pEntry)
{
#undef RETURN
#define RETURN(r){return r; }


  // Validate params
	if( NULL == subject || NULL == sessInfo || 0 == sessMask || NULL == pEntry )
	{
		#if defined(_WIN32) && defined(_DEBUG)
		ASSERT(!( NULL == subject || NULL == sessInfo || 0 == sessInfo || NULL == pEntry ));
		#endif

		return CERTCACHE_REQUIRED_PARAM;
	}

	if( NULL == sessInfo->getCerts )
	{
		#if defined(_WIN32) && defined(_DEBUG)
		ASSERT(NULL != sessInfo->getCerts);
		#endif
		return CERTCACHE_NO_CALLBACK_PTR;
	}

	#if defined(_DEBUG) && defined(_DEBUG_VERBOSE)
        #ifdef _WIN32 /* Added by Masanori Satake. */
		afxDump << "CCertCache::GetNextCert(" << subject << ", " << sessMask << ", " << sessInfo << ", " << pEntry << ")\n";
		Sleep(2);
        #else /* _UNIX or VX */
		PRINTERR("CCertCache::GetNextCert(");
		PRINTERR(subject);PRINTERR(",");
		PRINTERR(sessMash);PRINTERR(",");
		PRINTERR(sessInfo);PRINTERR(",");
		PRINTERR(pEntry);PRINTERR(")\n");
        #endif /* #ifdef _WIN32 */
	#endif

  	CCertsRec *pRec = NULL;	// ptr to cache rec
	*pEntry = NULL;	// init return ptr to NULL
	long rv = 0;

	rv = tmpCertRec.set_entry(subject);
	if( 0 != rv )
	{
		RETURN(rv);
	}

//typedef short (CM_CALLBACK *CPL_GET_CERTS_CALLBACK)(void*,char*,long,short,EncObject_LL **);
/*
short 
CM_CALLBACK ext_get_objects (	void* extHandle, 
								char* DN, 
								long typeMask, 
								short locMask, 
								EncObject_LL **objectList	);
*/
	pRec = m_lpCertTable->Search(tmpCertRec);
	if( NULL == pRec )
	{
		if( !m_lpCertTable->Insert(tmpCertRec) )
		{
			RETURN(CERTCACHE_INSERT_ERROR);
		}

		pRec = m_lpCertTable->Search(tmpCertRec);

		if( NULL == pRec )
		{
			RETURN(CERTCACHE_INSERT_ERROR);
		}

		pRec->m_entryNumber = ++m_lastEntryNum;
		m_entryCount++;

		#if defined(_DEBUG) && defined(_DEBUG_VERBOSE)
                #ifdef _WIN32 /* Added by Masanori Satake. */
			afxDump << "\tAdded new entry to table.\n";
                #else /* _UNIX or VX */
			PRINTERR("\tAdded new entry to table.\n");
                #endif /* #ifdef _WIN32 */
		#endif

	}


//	CacheRec* Search(const CacheRec &search_rec);

	do
	{
		*pEntry = pRec->GetNextUncheckedCert(sessMask,sessInfo);
		
		if( NULL != *pEntry )
		{
			break; 
		}

		if( IsAllSearched(pRec->m_searched) )
		{
			#if defined(_DEBUG) && defined(_DEBUG_VERBOSE)
                        #ifdef _WIN32 /* Added by Masanori Satake. */
				afxDump << "\tNo locations left to search.\n";
                        #else /* _UNIX or VX */
				PRINTERR("\tNo locations left to search.\n");
                        #endif /* #ifdef _WIN32 */
			#endif
			break;
		}

		#if defined(_DEBUG) && defined(_DEBUG_VERBOSE)
                #ifdef _WIN32 /* Added by Masanori Satake. */
			afxDump << "\tCalling SearchForMoreCerts(pRec,sessInfo," << subject << ")\n";
                #else /* _UNIX or VX */
			PRINTERR("\tCalling SearchForMoreCerts(pRec,sessInfo,");
			PRINTERR(subject);
			PRINTERR(")\n");
                #endif /* #ifdef _WIN32 */
		#endif

		rv = SearchForMoreCerts(pRec,sessInfo,subject);

		if( 0 != rv )
		{
			break;
		}

	}
	while( TRUE );

	if( 0 != rv && CERTCACHE_NO_MORE_CERTS != rv )
	{
		#if defined(_DEBUG) && defined(_DEBUG_VERBOSE)
                #ifdef _WIN32 /* Added by Masanori Satake. */
			afxDump << "\tError - " << rv << "\n";
                #else /* _UNIX or VX */
			PRINTERR("\nError - ");
			PRINTERR(rv);
			PRINTERR("\n");
                #endif /* #ifdef _WIN32 */
		#endif

		RETURN(rv);
	}

	if( NULL == *pEntry )
	{
		#if defined(_DEBUG) && defined(_DEBUG_VERBOSE)
                #ifdef _WIN32 /* Added by Masanori Satake. */
			afxDump << "\tNo more certs, flags cleared.\n";
                #else /* _UNIX or VX */
			PRINTERR("\tNo more certs, flags cleard.\n");
                #endif /* #ifdef _WIN32 */
		#endif
		pRec->ClearCheckedFlags(sessMask);
		RETURN(CERTCACHE_NO_MORE_CERTS);
	}

	#if defined(_DEBUG) && defined(_DEBUG_VERBOSE)
        #ifdef _WIN32 /* Added by Masanori Satake. */
		afxDump << "\tReturning a cert\n";
        #else /* _UNIX or VX */
		PRINTERR("\tReturning a cert\n");
        #endif /* #ifdef _WIN32 */
	#endif


	RETURN(0);
}

/*
#define RAM_LOC			0x00000001
#define CLIENT_LOC		0x00000002
#define SERVER_LOC		0x00000004
#define DSA_LOC			0x00000008

#define CA_CERT_TYPE	0x00010000
#define USER_CERT_TYPE	0x00020000
#define CROSS_CERT_TYPE	0x00040000
  */

int CCertCache::IsAllSearched(ULONG search_flag)
{
	if( (ALL_LOC) == (search_flag & (ALL_LOC)))
		return -1;

	return 0;
}

#define COMBINE_RAM_AND_CLIENT_SEARCH

/*-------------------------------------------------------------------------*\
|  Function Name :   SearchForMoreCerts
|  Creation Date :   May 17, 1999
|  Author        :   Matt Cooper
|  Last Mode Date:   May 17, 1999
|---------------------------------------------------------------------------
|	        
|  Purpose:	Called internally - calls user provided callbacks to obtain more certs
|	        and populates the record passed in as pRec
|  Exception Handling: 
|---------------------------------------------------------------------------
|  Inputs Params:   pRec - cert cache record pointer for the subject
|	                sessInfo - user provided session struct
|	                subject - DN of the certs needed
|  Pre-Conditions:  pRec allocated
|  Post-Conditions: pRec filled with new certs, or not.
|  Return values:   0 on success - 0 if no certs found, but other locations are 
|	                left to search - CERTCACHE_NO_MORE_CERTS of there are no more certs
\*-------------------------------------------------------------------------*/
long CCertCache::SearchForMoreCerts(CCertsRec *pRec, LPCPL_SESSION_INFO sessInfo, char* subject)
{

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


	short locMask = 0;
	long typeMask = 0;
	EncObject_LL *pCertList = NULL;
	EncObject_LL *pTmp = NULL;
	Bytes_struct forwardCert;
	long rv = 0;


	pRec->m_searched |= (CPLI_invert_mask(sessInfo->boundsMask));

	if( IsAllSearched(pRec->m_searched)  )
	{
		#if defined(_DEBUG) && defined(_DEBUG_VERBOSE)
                #ifdef _WIN32 /* Added by Masanori Satake. */
			afxDump << "\tNothing more to search.\n";
                #else /* _UNIX or VX */
			PRINTERR("/tNothing more to search.\n");
                #endif /* #ifdef _WIN32 */
		#endif

		return CERTCACHE_NO_MORE_CERTS;
	}

	#if defined(COMBINE_RAM_AND_CLIENT_SEARCH)
	// search disk and ram at same time
	else if( !CPLI_is_bit_set(pRec->m_searched, RAM_LOC ) || !CPLI_is_bit_set(pRec->m_searched, CLIENT_LOC ))
	{
		if( CPLI_is_bit_set(sessInfo->boundsMask, RAM_LOC ) )
			locMask = RAM_LOC;
		if( CPLI_is_bit_set(sessInfo->boundsMask, CLIENT_LOC ) )
			locMask |= CLIENT_LOC;

		CPLI_set_bit(&(pRec->m_searched),RAM_LOC | CLIENT_LOC);
	}
	#else
	//  search disk and ram separately
	else if( !CPLI_is_bit_set(pRec->m_searched, RAM_LOC ) )
	{
		locMask = RAM_LOC;
		CPLI_set_bit(&(pRec->m_searched),RAM_LOC);
	}
	else if( !CPLI_is_bit_set(pRec->m_searched, CLIENT_LOC ) )
	{
		locMask = CLIENT_LOC;
		CPLI_set_bit(&(pRec->m_searched),CLIENT_LOC);
	}
	#endif
	else if(  !CPLI_is_bit_set(pRec->m_searched, SERVER_LOC )  )
	{
		locMask = SERVER_LOC;
		CPLI_set_bit(&(pRec->m_searched),SERVER_LOC);
	}
	else
	{
		#if defined(_WIN32) && defined(_DEBUG)
		ASSERT(!CPLI_is_bit_set(pRec->m_searched, DSA_LOC ));
		#endif

		locMask = DSA_LOC;
		CPLI_set_bit(&(pRec->m_searched),DSA_LOC);
	}

	typeMask = CA_CERT_TYPE | USER_CERT_TYPE | CROSS_CERT_TYPE;

#ifndef VX /* Added by Masanori Satake. */
	try
	{
#endif
		rv = sessInfo->getCerts(sessInfo->callbackHandle,subject,typeMask,locMask,&pCertList );
#ifndef VX /* Added by Masanori Satake. */
	}
	catch(...)
	{
		rv = CERTCACHE_FATAL_EXCEPTION;
		#if defined(_WIN32) && defined(_DEBUG)
		ASSERT(rv != CERTCACHE_FATAL_EXCEPTION);
		#endif
	}
#endif

	if( 0 != rv )
	{
		#if defined(_DEBUG_VERBOSE) && defined(_DEBUG)
                #ifdef _WIN32 /* Added by Masanori Satake. */
				afxDump << "\t*** CMAPI returned a non zero from getCerts indicating a critical error!! ***\n";
                #else /* _UNIX or VX */
				PRINTERR("\t*** CMAPI returned a non zero from getCerts indicating a critical error!! ***\n");
                #endif /* #ifdef _WIN32 */
		#endif
		RETURN(rv);
	}

	if( NULL != pCertList )
	{
		pTmp = pCertList;

		#if defined(_DEBUG) && defined(_DEBUG_VERBOSE)
                #ifdef _WIN32 /* Added by Masanori Satake. */
			afxDump << "\tpRec->m_lpCerts == " << pRec->m_lpCerts << "\n";
                #else /* _UNIX or VX */
			PRINTERR("\tpRec->m_lpCerts ==");
			PRINTERR(pRec->m_lpCerts);
			PRINTERR("\n");
                #endif /* #ifdef _WIN32 */
		#endif

		#if defined(_DEBUG) && defined(_DEBUG_VERBOSE)
                #ifdef _WIN32 /* Added by Masanori Satake. */
			afxDump << "\tAdding cert(s)\n";
                #else /* _UNIX or VX */
			PRINTERR("\tAdding cert(s)\n");
                #endif /* #ifdef _WIN32 */
		#endif

		do
		{
			if( CROSS_CERT_TYPE == pTmp->typeMask )
			{
				#if defined(_DEBUG) && defined(_DEBUG_VERBOSE)
                                #ifdef _WIN32 /* Added by Masanori Satake. */
					afxDump << "\tCross cert returned... ";
                                #else /* _UNIX or VX */
					PRINTERR("\tCross cert returned...");
                                #endif /* #ifdef _WIN32 */
				#endif
				//long CPLI_GetForwardCrossCert( Bytes_struct *pCrossCertPair, Bytes_struct *pForwardCert )
				if( 0 == CPLI_GetForwardCrossCert(&pTmp->encObj, &forwardCert) )
				{
					#if defined(_DEBUG) && defined(_DEBUG_VERBOSE)
                                        #ifdef _WIN32 /* Added by Masanori Satake. */
						afxDump << "Forward cert extracted.\n";
                                        #else /* _UNIX or VX */
						PRINTERR("Forward cert extracted.\n");
                                        #endif /* #ifdef _WIN32 */
					#endif
					pRec->AddCert( &forwardCert,CROSS_CERT_TYPE );
				}
				#if defined(_DEBUG) && defined(_DEBUG_VERBOSE)
				else {
                                  #ifdef _WIN32 /* Added by Masanori Satake. */
					afxDump << "No forward cert or parse error. Forward cert NOT extracted.\n"; }
                                #else /* _UNIX or VX */
				        PRINTERR("No forward cert or parse error. Forward cert NOT extracted.\n");
                                #endif /* #ifdef _WIN32 */
				#endif
			}
			else
			{
				pRec->AddCert( &(pTmp->encObj),pTmp->typeMask );
			}

			pTmp = pTmp->next;

		}
		while(NULL != pTmp);

		#if defined(_DEBUG) && defined(_DEBUG_VERBOSE)
                #ifdef _WIN32 /* Added by Masanori Satake. */
			afxDump << "\tpRec->m_lpCerts == " << pRec->m_lpCerts << "\n";
                #else /* _UNIX or VX */
			PRINTERR("\tpRec->m_lpCerts == ");
			PRINTERR(pRec->m_lpCerts);
			PRINTERR("\n");
                #endif /* #ifdef _WIN32 */
		#endif

#ifndef VX /* Added by Masanori Satake. */
		try
		{
#endif
			sessInfo->freeCerts( sessInfo->callbackHandle, &pCertList);
#ifndef VX /* Added by Masanori Satake. */
		}
		catch(...)
		{
			rv = CERTCACHE_FATAL_EXCEPTION;
			#if defined(_WIN32) && defined(_DEBUG)
			ASSERT(rv != CERTCACHE_FATAL_EXCEPTION);
			#endif
		}
#endif
	}

    return rv;

}

// if def'd, cert will be marked checked when obtained
// through this function, otherwise not
//#define _MARK_CHECKED_ON_CERT_GET << DO NOT DEFINE!!

long CCertCache::GetCert(char *subject, char *issuer, Bytes_struct *serial, ULONG sessMask, LPCPL_SESSION_INFO sessInfo, LPCERTCACHE_ENTRY_STRUCT *pEntry )
{

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

  // Validate params
	if( NULL == subject || NULL == sessInfo || 0 == sessMask || NULL == pEntry || NULL == issuer || NULL == serial )
	{
		#if defined(_WIN32) && defined(_DEBUG)
		ASSERT(!( NULL == subject || NULL == sessInfo || 0 == sessInfo || NULL == pEntry || NULL == issuer || NULL == serial ));
		#endif

		return CERTCACHE_REQUIRED_PARAM;
	}

	if( NULL == serial->data || 0 == serial->num )
	{
		#if defined(_WIN32) && defined(_DEBUG)
		ASSERT(!( NULL == serial->data || 0 == serial->num ));
		#endif

		return CERTCACHE_REQUIRED_PARAM;
	}

	if( NULL == sessInfo->getCerts )
	{
		#if defined(_WIN32) && defined(_DEBUG)
		ASSERT(NULL != sessInfo->getCerts);
		#endif
		return CERTCACHE_NO_CALLBACK_PTR;
	}

	#if defined(_WIN32) && defined(_DEBUG) && defined(_DEBUG_VERBOSE)
        #ifdef _WIN32 /* Added by Masanori Satake. */
	afxDump << "Getting specific cert for " << subject << "\n";
	Sleep(2);
        #else /* _UNIX or VX */
	PRINTERR("Getting specific cert for ");
	PRINTERR(subject);
	PRINTERR("\n");
        #endif /* #ifdef _WIN32 */
	#endif

  	CCertsRec *pRec = NULL;	// ptr to cache rec
	*pEntry = NULL;	// init return ptr to NULL
	long rv = 0;

	rv = tmpCertRec.set_entry(subject);
	if( 0 != rv )
	{
		RETURN(rv);
	}

//typedef short (CM_CALLBACK *CPL_GET_CERTS_CALLBACK)(void*,char*,long,short,EncObject_LL **);
/*
short 
CM_CALLBACK ext_get_objects (	void* extHandle, 
								char* DN, 
								long typeMask, 
								short locMask, 
								EncObject_LL **objectList	);
*/
	pRec = m_lpCertTable->Search(tmpCertRec);
	if( NULL == pRec )
	{
		if( !m_lpCertTable->Insert(tmpCertRec) )
		{
			RETURN(CERTCACHE_INSERT_ERROR);
		}

		pRec = m_lpCertTable->Search(tmpCertRec);

		if( NULL == pRec )
		{
			RETURN(CERTCACHE_INSERT_ERROR);
		}

		pRec->m_entryNumber = ++m_lastEntryNum;
		m_entryCount++;
	}


//	CacheRec* Search(const CacheRec &search_rec);
	LPCERTCACHE_ENTRY_STRUCT pStruct = NULL;

	do
	{
		pStruct = pRec->m_lpCerts;
		while( NULL != pStruct && NULL == *pEntry )
		{
			do
			{
				if( pStruct->pCert->serial_num.num != serial->num )
					break;
				if( 0 != memcmp(pStruct->pCert->serial_num.data, serial->data, serial->num )  )
					break;
				if( !CPLI_IsSameDN( issuer, pStruct->pCert->issuer ) )
					break;

				*pEntry = pStruct;

				#if defined(_MARK_CHECKED_ON_CERT_GET)
					pStruct->flag |= sessMask;
				#endif
			}
			while(FALSE);

			pStruct = pStruct->pNext;
		}

		if( NULL != *pEntry )
		{
			break; 
		}

		if( IsAllSearched(pRec->m_searched) )
		{
			break;
		}

		rv = SearchForMoreCerts(pRec,sessInfo,subject);

		if( 0 != rv )
		{
			break;
		}

	}
	while( TRUE );

	if( 0 != rv && CERTCACHE_NO_MORE_CERTS != rv )
	{
		RETURN(rv);
	}

	if( NULL == pEntry )
	{
		RETURN(CERTCACHE_NO_MORE_CERTS);
	}


	RETURN(0);

	return rv;
}


void CCertCache::ClearAllFlags(ULONG sessionMask)
{
	CCertsRec *pRec = NULL;
	int vPos = 0;
	for( ; vPos < CERTCACHE_TABLE_SIZE; vPos++ )
	{
		pRec = m_lpCertTable->HashVector[vPos];
		while( NULL != pRec )
		{
			pRec->ClearCheckedFlags(sessionMask);
			pRec = pRec->NextRec;
		}
	}
}

#ifdef _DEBUG_VERBOSE
#undef _DEBUG_VERBOSE
#endif
