/*
	$Id: DSMailUserCache.cpp,v 1.1 2003/04/20 23:34:11 dasenbro Exp $

	File:		DSMailCache.cpp

	Contains:	C++ implementation of Apple Directory Services cache

	Version:	Apple Mail Server - Mac OS X :  $Revision: 1.1 $

	Written by:	Michael Dasenbrock

	Copyright:	© 2000-2001 by Apple Computer, Inc., all rights reserved.

	Change History:

		$Log: DSMailUserCache.cpp,v $
		Revision 1.1  2003/04/20 23:34:11  dasenbro
		Initial check-in.
		
		Revision 1.23  2002/05/30 17:16:18  dasenbro
		Expire individual cached user items after 30 seconds instead of 145.
		
		Revision 1.22  2002/05/09 16:58:56  dasenbro
		Changed all str... calls to CUtils::Str... to be NULL safe.
		
		Revision 1.21  2002/04/18 18:09:10  dasenbro
		Changed bool to Bool for word alignment.
		
		Revision 1.20  2002/04/16 05:53:50  dasenbro
		Removed error logs.
		
		Revision 1.19  2002/03/21 16:38:52  dasenbro
		Addes network transition support.
		
		Revision 1.18  2002/01/14 17:30:58  dasenbro
		Initial S4 updates.
		
		Revision 1.17  2001/06/21 20:50:55  dasenbro
		Updated file header info.
		
		Revision 1.16  2001/06/21 17:17:06  dasenbro
		Reduced cache TTL value.
		
		Revision 1.15  2001/06/21 17:13:21  dasenbro
		Added Change History.
		

	Projector History:

 */
 
#include <time.h>
#include <string.h>

#include "CUtils.h"
#include "DSMailUserCache.h"

const uInt32 kDSCacheExpireTime = 30; // in seconds

// ---------------------------------------------------------------------------
//	* DSCacheEntry ()
//
// ---------------------------------------------------------------------------

DSCacheEntry::DSCacheEntry ( void )
{
	fEntry		= NULL;
	fTimeStamp	= 0;
	fRecType	= kDSCUnknown;
} // DSCacheEntry


// ---------------------------------------------------------------------------
//	* DSMailCache ()
//
// ---------------------------------------------------------------------------

DSMailCache::DSMailCache ( void )
{
	for ( uInt32 i = 0; i < kMailCacheHashTableSize; ++i )
	{
		fNameHashTable[ i ].fEntry		= NULL;
		fNameHashTable[ i ].fTimeStamp	= 0;
		fNameHashTable[ i ].fRecType	= kDSCUnknown;
	}

	for ( uInt32 i = 0; i < kMailCacheHashTableSize; ++i )
	{
		fIDHashTable[ i ].fEntry		= NULL;
		fIDHashTable[ i ].fTimeStamp	= 0;
		fIDHashTable[ i ].fRecType		= kDSCUnknown;
	}
} // DSMailCache


// ---------------------------------------------------------------------------
//	* ~DSMailCache ()
//
// ---------------------------------------------------------------------------

DSMailCache::~DSMailCache ( void )
{
} // ~DSMailCache
	

// ---------------------------------------------------------------------------
//	* GetUserByName ()
//
// ---------------------------------------------------------------------------

DSMailUser* DSMailCache::GetUserByName ( const char *inName )
{
	uInt32		i			= 0;
	DSMailUser *pMailUser	= nil;

	if ( inName != NULL )
	{
		// Get the index
		i = HashString( inName ) % kMailCacheHashTableSize;

		// Is there a non-null entry in the list
		if ( fNameHashTable[ i ].fEntry != NULL )
		{
			// Is it the right record type
			if ( fNameHashTable[ i ].fRecType == kDSCUser )
			{
				// Is it the one we are looking for
				pMailUser = (DSMailUser *)fNameHashTable[ i ].fEntry;
				if ( (CUtils::Stricmp( pMailUser->GetUserName(), inName ) == 0) || ((CUtils::Stricmp( pMailUser->GetRealName(), inName ) == 0)) )
				{
					// found a match
					if ( fNameHashTable[ i ].fTimeStamp > (uTime_t)::time( NULL ) )
					{
						// Refresh the expire time
						fNameHashTable[ i ].fTimeStamp = ::time( NULL ) + kDSCacheExpireTime;
		
						// hasn't expired -- return a copy
						return( new DSMailUser( (DSMailUser *)fNameHashTable[ i ].fEntry ) );
					}
					else
					{
						// remove that entry -- it has expired
						delete( (DSMailUser *)fNameHashTable[ i ].fEntry );
						fNameHashTable[ i ].fEntry	= NULL;
						fNameHashTable[ i ].fTimeStamp	= 0;
						fNameHashTable[ i ].fRecType	= kDSCUnknown;
						return( NULL );
					}
				}
			}
		}
	}
	return( NULL );

} // GetUserByName


// ---------------------------------------------------------------------------
//	* GetUserByID ()
//
// ---------------------------------------------------------------------------

DSMailUser* DSMailCache::GetUserByID ( const uInt32 inID )
{
	uInt32		i			= 0;
	DSMailUser *pMailUser	= nil;

	// Get the index
	i = inID % kMailCacheHashTableSize;

	// Is there a non-null entry in the list
	if ( fIDHashTable[ i ].fEntry != NULL )
	{
		// Is it the right record type
		if ( fIDHashTable[ i ].fRecType == kDSCUser )
		{
			// Is it the one we are looking for
			pMailUser = (DSMailUser *)fIDHashTable[ i ].fEntry;
			if ( pMailUser->GetUserID() == inID )
			{
				// found a match
				if ( fIDHashTable[ i ].fTimeStamp > (uTime_t)::time( NULL ) )
				{
					// Refresh the expire time
					fIDHashTable[ i ].fTimeStamp = ::time( NULL ) + kDSCacheExpireTime;
	
					// hasn't expired -- return a copy
					return( new DSMailUser( (DSMailUser *)fIDHashTable[ i ].fEntry ) );
				}
				else
				{
					// remove that entry -- it expired
					delete( (DSMailUser *)fIDHashTable[ i ].fEntry );
					fIDHashTable[ i ].fEntry		= NULL;
					fIDHashTable[ i ].fTimeStamp	= 0;
					fIDHashTable[ i ].fRecType		= kDSCUnknown;
					return( NULL );
				}
			}
		}
	}

	return( NULL );

} // GetUserByID


// ---------------------------------------------------------------------------
//	* GetGroupByName ()
//
// ---------------------------------------------------------------------------

DSMailGroup* DSMailCache::GetGroupByName ( const char *inName )
{
	uInt32			i			= 0;
	DSMailGroup	   *pMailGroup	= nil;

	if ( inName != NULL )
	{
		// Get the index
		i = HashString( inName ) % kMailCacheHashTableSize;

		// Is there a non-null entry in the list
		if ( fNameHashTable[ i ].fEntry != NULL )
		{
			// Is it the right record type
			if ( fNameHashTable[ i ].fRecType == kDSCGroup )
			{
				// Is it the one we are looking for
				pMailGroup = (DSMailGroup *)fNameHashTable[ i ].fEntry;
				if ( CUtils::Strcmp( pMailGroup->GetName(), inName ) == 0 )
				{
					// found a match
					if ( fNameHashTable[ i ].fTimeStamp > (uTime_t)::time( NULL ) )
					{
						// Refresh the expire time
						fNameHashTable[ i ].fTimeStamp = ::time( NULL ) + kDSCacheExpireTime;
		
						// hasn't expired -- return a copy
						return( new DSMailGroup( (DSMailGroup *)fNameHashTable[ i ].fEntry ) );
					}
					else
					{
						// remove that entry -- it expired
						delete( (DSMailGroup *)fNameHashTable[ i ].fEntry );
						fNameHashTable[ i ].fEntry		= NULL;
						fNameHashTable[ i ].fTimeStamp	= 0;
						fNameHashTable[ i ].fRecType	= kDSCUnknown;
						return( NULL );
					}
				}
			}
		}
	}

	return( NULL );

} // GetGroupByName


// ---------------------------------------------------------------------------
//	* GetGroupByID ()
//
// ---------------------------------------------------------------------------

DSMailGroup* DSMailCache::GetGroupByID ( const uInt32 inID )
{
	uInt32			i			= 0;
	DSMailGroup	   *pMailGroup	= nil;

	// Get the index
	i = inID % kMailCacheHashTableSize;

	// Is there a non-null entry in the list
	if ( fIDHashTable[ i ].fEntry != NULL )
	{
		// Is it the right record type
		if ( fIDHashTable[ i ].fRecType == kDSCGroup )
		{
			// Is it the one we are looking for
			pMailGroup = (DSMailGroup *)fIDHashTable[ i ].fEntry;
			if ( pMailGroup->GetGroupID() == inID )
			{
				// found a match
				if ( fIDHashTable[ i ].fTimeStamp > (uTime_t)::time( NULL ) )
				{
					// Refresh the expire time
					fIDHashTable[ i ].fTimeStamp = ::time( NULL ) + kDSCacheExpireTime;
	
					// hasn't expired -- return a copy
					return( new DSMailGroup( (DSMailGroup *)fIDHashTable[ i ].fEntry ) );
				}
				else
				{
					// remove that entry -- it expired
					delete( (DSMailGroup *)fIDHashTable[ i ].fEntry );
					fIDHashTable[ i ].fEntry		= NULL;
					fIDHashTable[ i ].fTimeStamp	= 0;
					fIDHashTable[ i ].fRecType	= kDSCUnknown;
					return( NULL );
				}
			}
		}
	}

	return( NULL );

} // GetGroupByID


// ---------------------------------------------------------------------------
//	* AddUserToCache ()
//
// ---------------------------------------------------------------------------

void DSMailCache::AddUserToCache ( DSMailUser *inMailUser, const char *inName )
{
	uInt32	i		= 0;
	Bool	bName	= true;

	if ( inMailUser != NULL )
	{
		if ( inName != NULL )
		{
			if ( (inMailUser->GetRealName() != NULL) &&
				 (CUtils::Stricmp( inMailUser->GetRealName(), inName ) == 0) )
			{
				bName = false;
			}
		}

		if ( bName == true )
		{
			i = HashString( inMailUser->GetUserName() ) % kMailCacheHashTableSize;
		}
		else
		{
			i = HashString( inMailUser->GetRealName() ) % kMailCacheHashTableSize;
		}

		if ( fNameHashTable[ i ].fEntry != NULL )
		{
			// What type of entry are we deleteing
			if ( fNameHashTable[ i ].fRecType == kDSCUser )
			{
				delete( (DSMailUser *)fNameHashTable[ i ].fEntry );
			}
			else if ( fNameHashTable[ i ].fRecType == kDSCGroup )
			{
				delete( (DSMailGroup *)fNameHashTable[ i ].fEntry );
			}
			else
			{
			}

			fNameHashTable[ i ].fEntry		= NULL;
			fNameHashTable[ i ].fTimeStamp	= 0;
			fNameHashTable[ i ].fRecType	= kDSCUnknown;
		}
	
		// Store the copy of this user
		fNameHashTable[ i ].fEntry = new DSMailUser( inMailUser );
	
		// Set this entries expire time
		fNameHashTable[ i ].fTimeStamp = ::time( NULL ) + kDSCacheExpireTime;

		// Set the record type
		fNameHashTable[ i ].fRecType = kDSCUser;

		// ------------------
		// Add to number cache
		i = inMailUser->GetUserID() % kMailCacheHashTableSize;
		if ( fIDHashTable[ i ].fEntry != NULL )
		{
			// What type of entry are we deleteing
			if ( fIDHashTable[ i ].fRecType == kDSCUser )
			{
				delete( (DSMailUser *)fIDHashTable[ i ].fEntry );
			}
			else if ( fIDHashTable[ i ].fRecType == kDSCGroup )
			{
				delete( (DSMailGroup *)fIDHashTable[ i ].fEntry );
			}
			else
			{
			}

			fIDHashTable[ i ].fEntry		= NULL;
			fIDHashTable[ i ].fTimeStamp	= 0;
			fIDHashTable[ i ].fRecType		= kDSCUnknown;
		}
	
		// Store the copy of this user
		fIDHashTable[ i ].fEntry = new DSMailUser( inMailUser );
	
		// Set this entries expire time
		fIDHashTable[ i ].fTimeStamp = ::time( NULL ) + kDSCacheExpireTime;

		// Set the record type
		fIDHashTable[ i ].fRecType = kDSCUser;
	}
} // AddUserToCache


// ---------------------------------------------------------------------------
//	* AddGroupToCache ()
//
// ---------------------------------------------------------------------------

void DSMailCache::AddGroupToCache ( DSMailGroup *inMailGroup )
{
	uInt32	i		= 0;

	if ( inMailGroup != NULL )
	{
		i = HashString( inMailGroup->GetName() ) % kMailCacheHashTableSize;
		if ( fNameHashTable[ i ].fEntry != NULL )
		{
			// What type of entry are we deleteing
			if ( fNameHashTable[ i ].fRecType == kDSCUser )
			{
				delete( (DSMailUser *)fNameHashTable[ i ].fEntry );
			}
			else if ( fNameHashTable[ i ].fRecType == kDSCGroup )
			{
				delete( (DSMailGroup *)fNameHashTable[ i ].fEntry );
			}
			else
			{
			}
			fNameHashTable[ i ].fEntry		= NULL;
			fNameHashTable[ i ].fTimeStamp	= 0;
			fNameHashTable[ i ].fRecType	= kDSCUnknown;
		}
	
		// Store the copy of this Group
		fNameHashTable[ i ].fEntry = new DSMailGroup( inMailGroup );
	
		// Set this entries expire time
		fNameHashTable[ i ].fTimeStamp = ::time( NULL ) + kDSCacheExpireTime;

		// Set the record type
		fNameHashTable[ i ].fRecType = kDSCGroup;


		i = inMailGroup->GetGroupID() % kMailCacheHashTableSize;
		if ( fIDHashTable[ i ].fEntry != NULL )
		{
			// What type of entry are we deleteing
			if ( fIDHashTable[ i ].fRecType == kDSCUser )
			{
				delete( (DSMailUser *)fIDHashTable[ i ].fEntry );
			}
			else if ( fIDHashTable[ i ].fRecType == kDSCGroup )
			{
				delete( (DSMailGroup *)fIDHashTable[ i ].fEntry );
			}
			else
			{
			}
			fIDHashTable[ i ].fEntry		= NULL;
			fIDHashTable[ i ].fTimeStamp	= 0;
			fIDHashTable[ i ].fRecType		= kDSCUnknown;
		}
	
		// Store the copy of this Group
		fIDHashTable[ i ].fEntry = new DSMailGroup( inMailGroup );
	
		// Set this entries expire time
		fIDHashTable[ i ].fTimeStamp = ::time( NULL ) + kDSCacheExpireTime;

		// Set the record type
		fIDHashTable[ i ].fRecType = kDSCGroup;
	}
} // AddGroupToCache


// ---------------------------------------------------------------------------
//	* HashString ()
//
// ---------------------------------------------------------------------------

uInt32 DSMailCache::HashString ( const char *inString )
{
	uInt32 result = 0;

	if ( inString != NULL )
	{
		while ( *inString != '\0' )
		{
			result = (result << 1) ^ *inString;
			++inString;
		}
	}

	return( result );

} // HashString

