/*
	$Id: COSUtils.cpp,v 1.1 2003/04/20 23:29:40 dasenbro Exp $

	File:	COSUtils.cpp

	Contains: Implementation of the various OS Utilities

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

	Written by: Michael Dasenbrock

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

 	NOT_FOR_OPEN_SOURCE <to be reevaluated at a later time>

	Change History:

		$Log: COSUtils.cpp,v $
		Revision 1.1  2003/04/20 23:29:40  dasenbro
		Initial check-in.
		
		Revision 1.25  2002/06/11 05:05:58  dasenbro
		Changed kFolderLimit back to 32000 max files per folder.
		
		Revision 1.24  2002/06/04 17:36:57  dasenbro
		Fixed a memory leak in Create NewCurrentFolder().
		
		Revision 1.23  2002/05/09 16:59:04  dasenbro
		Changed all str... calls to CUtils::Str... to be NULL safe.
		
		Revision 1.22  2002/04/21 16:29:13  dasenbro
		Moved LogViewer calls to utils and added DoesFileExist() for simple
		file check.
		
		Revision 1.21  2002/04/18 18:09:16  dasenbro
		Changed bool to Bool for word alignment.
		
		Revision 1.20  2002/04/18 17:08:23  dasenbro
		Changed GetAppNameAndVers() to print Dev and Beta versions.
		
		Revision 1.19  2002/04/15 21:46:30  dasenbro
		Call CreateAndVerifyPath() when folder path updates.
		
		Revision 1.18  2002/03/21 16:41:47  dasenbro
		Updated file version information.
		
		Revision 1.17  2002/03/11 23:11:32  dasenbro
		Systax change.
		
		Revision 1.16  2002/02/20 20:29:11  dasenbro
		Added DoesDirectoryExist() and GetOldFullDBPath().
		
		Revision 1.15  2002/01/14 17:04:09  dasenbro
		Initial S4 updates.
		
		Revision 1.14  2001/07/25 18:19:49  dasenbro
		Syntax changes.
		
		Revision 1.13  2001/07/09 15:37:28  dasenbro
		Added GetMailLogFolder() to move the mail logs to their own folder.
		
		Revision 1.12  2001/06/27 22:04:26  dasenbro
		Changed some uInts to sInts.
		
		Revision 1.11  2001/06/21 20:51:10  dasenbro
		Updated file header info.
		
		Revision 1.10  2001/06/21 20:08:42  dasenbro
		Added Change History.
		

	Projector History:

		<11+>	07/23/98	ANC		Rhapsody (MaxOS X) changes
		<11>	  6/3/98	MED		::memset CInfoPBRec in GetNameToDirID().
		<10>	 4/28/98	MED		Added GetDBCachePercentage to get, well you guessed it, the DB
									Cache Percentage and did some handle locking.
		 <9>	 3/29/98	MED		Added GetNameToDirID().
		 <8>	 3/11/98	MED		Added GetGMT()>
		 <7>	  3/9/98	DOR		Get rid of a warning.
		 <6>	 2/25/98	DOR		Don't compare fingerprints on BCC user record checks....
		 <5>	 2/23/98	MED		Added GetMaxIMAPConnections() to get the max number of
									connections per IMAP user login.
		 <4>	 2/16/98	DOR		Bug hunt.
		 <3>	 2/13/98	DOR		Return boolean for success/fail in GetUserID, Make GetUserID
									safe if gADS is NULL.  Fix _SEVERAL_ memory leaks...tisk tisk
									tisk...
		 <2>	  2/9/98	MED		GetASDUserOrGroupName().
		 <1>	  2/3/98	MED		first checked in

	To Do:
		Change (up?) the limits and timeout parameters for Rhapsody.		
 */


// Stdlib
#include <sys/cdefs.h>
#include <string.h>
#include <stdlib.h>
#include <NSSystemDirectories.h>	// for NSSearchPath*()
#include <ppc/types.h>
#include <dirent.h>
#include <errno.h>

// App
#include "COSUtils.h"
#include "AppResources.h"
#include "AMSMailTool.h"
#include "CStatStr.h"
#include "CUtils.h"
#include "CGlobals.h"
#include "CTokenizer.h"

// System Headers
#include <time.h>
#include <sys/utsname.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <sys/mount.h>
#include <pwd.h>

// Statics
char	*COSUtils::fDBRootPath						= nil;
char	*COSUtils::fStaticDBFolder					= nil;
char	*COSUtils::fStaticMailFolder				= nil;
char	*COSUtils::fStaticMailStoreFolder			= nil;
char	*COSUtils::fStaticDailyMailStoreFolder		= nil;
char	*COSUtils::fStaticCurrentMailStorePath		= nil;
char	*COSUtils::fStaticDateFolder				= nil;
char	*COSUtils::fStaticTargetFolder				= nil;
char	*COSUtils::fStaticAccountsFolder			= nil;
char	*COSUtils::fStaticTempFolder				= nil;
char	*COSUtils::fDefaultDBPath					= nil;
char	*COSUtils::fFullDBPath						= nil;
char	*COSUtils::fFullOldDBPath					= nil;
char	*COSUtils::fLogFileFolder					= nil;
char	*COSUtils::fMailLogFolder					= nil;
char	*COSUtils::fMigrationFolder					= nil;
char	*COSUtils::fConfigFolder					= nil;


uInt32	COSUtils::fDay		= 0;
uInt32	COSUtils::fMonth	= 0;

extern	MailVersionInfo		gkAppVersion;

static const uInt32	kFolderLimit	= 32000;


// ---------------------------------------------------------------------------
//	* GetMachineName ()
//
//		- Get the computer name
//
// ---------------------------------------------------------------------------

void COSUtils::GetMachineName ( char *outBuffer )
{
	struct utsname system;
	int rc = 0;

	rc = ::uname( &system );
	if ( rc == 0 )
	{
		::memcpy( outBuffer, system.nodename, CUtils::Strlen(system.nodename) + 1 );
	}
} // GetMachineName


//--------------------------------------------------------------------------------------------------
//	* GetGMT ()
//
//		- Calculates the GMT and passes back hours and minutes
//
//--------------------------------------------------------------------------------------------------

void COSUtils::GetGMT ( char *ioEastWest, sInt32 *ioDeltaMin, sInt32 *ioDeltaHour )
{
	time_t		seconds		= ::time( nil );
	sInt32		gmtDelta	= 0;
	struct tm  *tms_static	= nil;
	struct tm	tmStruct;
	struct tm  *tms			= &tmStruct;

	tms_static = ::localtime( &seconds );

	// since localtime return a static var, make a copy of it and use the copy
	::memcpy( tms, tms_static, sizeof( struct tm ) );
	gmtDelta = tms->tm_gmtoff;		// the GMT offset in seconds

	// West or East of GMT?
	*ioEastWest = '+';

	if ( gmtDelta < 0 )
	{
		*ioEastWest = '-';
		gmtDelta = -gmtDelta;
	}

	// Hours
	*ioDeltaHour = gmtDelta / 3600;
	gmtDelta -= ( *ioDeltaHour * 3600 );

	// minutes
	*ioDeltaMin = gmtDelta / 60;

} // GetGMT


// ---------------------------------------------------------------------------
//	* GetPOP3ContextBatchLimit ()
//
// ---------------------------------------------------------------------------

uInt16 COSUtils::GetPOP3ContextBatchLimit ( void )
{
	return( 4096 );		// 2048 in MacOS version - MED -
} // GetPOP3ContextBatchLimit


// ---------------------------------------------------------------------------
//	* GetMaxRCPTCount ()
//
// ---------------------------------------------------------------------------

uInt16 COSUtils::GetMaxRCPTCount ( void )
{
	return( 2048 );
} // GetMaxRCPTCount


// ---------------------------------------------------------------------------
//	* GetMaxConnectTime ()
//
//		- Get max time server can spend per connection
//
// ---------------------------------------------------------------------------

uInt16 COSUtils::GetMaxConnectTime ( uInt32 inResID )
{
	return( 30 );	// - MED -
} // GetMaxConnectTime


// ---------------------------------------------------------------------------
//	* GetMaxTimeAttempt ()
//
//		- Get max time server can attempt a connection
//
// ---------------------------------------------------------------------------

uInt16 COSUtils::GetMaxTimeAttempt ( uInt32 inResID )
{
	return( 3 );	// - MED -
} // GetMaxTimeAttempt


// ---------------------------------------------------------------------------
//	* GetAppNameAndVers ()
//
// ---------------------------------------------------------------------------

CString& COSUtils::GetAppNameAndVers ( void )
{
	static bool		sNameInitiailzed = false;
	static CString	sAppNameAndVers;
	static CString	sAppName( kAppInfoListID, kStrAppName );

	if ( sNameInitiailzed == false )
	{
		if ( gkAppVersion.fix != 0 )
		{
			if ( gkAppVersion.fix > 10 )
			{
				sAppNameAndVers.Sprintf( "%s %d.%d.%d.Dev%d",
										sAppName.GetData(),
										gkAppVersion.major,
										gkAppVersion.minor,
										gkAppVersion.update,
										gkAppVersion.fix );
			}
			else
			{
				sAppNameAndVers.Sprintf( "%s %d.%d.%d.Beta%d",
										sAppName.GetData(),
										gkAppVersion.major,
										gkAppVersion.minor,
										gkAppVersion.update,
										gkAppVersion.fix );
			}
		}
		else
		{
			sAppNameAndVers.Sprintf( "%s %d.%d.%d.%d",
									sAppName.GetData(),
									gkAppVersion.major,
									gkAppVersion.minor,
									gkAppVersion.update,
									gkAppVersion.fix );
		}

		sNameInitiailzed = true;       
    }

	return( sAppNameAndVers );

} // GetAppNameAndVers


// ---------------------------------------------------------------------------
//	* GetShortVersion ()
//
// ---------------------------------------------------------------------------

CString& COSUtils::GetShortVersion ( void )
{
	static bool		sShortInitialized = false;
	static CString	sShortVers;
	
	if ( sShortInitialized == false ) {
		sShortVers.Sprintf("%d.%d.%d.%d", gkAppVersion.major,
						gkAppVersion.minor, gkAppVersion.update, gkAppVersion.fix);

		sShortInitialized = true;
	}

	return (sShortVers);
} // GetAppNameAndVers

//--------------------------------------------------------------------------------------------------
//	* GetFileSystemFreeSpace ()
//
//		- Returns the available free space (in bytes) of the file system specified.
//			If inFSName is NULL,	i.e. no file system is specified, then it checks
//			the root file system "/".
//
//		NOTE: return unit is BYTE
//--------------------------------------------------------------------------------------------------

long long COSUtils::GetFileSystemFreeSpace ( const char *inFSName )
{

	const char *checkFS = "/";
   	struct statfs	statbuf;
	register int	result = 0;
	int				freeKB = 0;
	
	if ( inFSName != NULL )
	{
		checkFS = inFSName;
    }

	result = ::statfs( checkFS, &statbuf );
	if ( result != 0 )
	{
		throw( -1 );
	}
	
	// Cast the two numbers to type long long before the calculation so the result will be a long long
	return( (long long)statbuf.f_bfree * (long long)statbuf.f_bsize );

} // GetFileSystemFreeSpace


//--------------------------------------------------------------------------------------------------
//	* DoesDirectoryExist ()
//
//		- returns:	true  - directory exists
//					false - directory does not exist
//
//--------------------------------------------------------------------------------------------------

bool COSUtils::DoesDirectoryExist ( const char *inPathName )
{
   	struct stat		statbuf;
	
	if ( inPathName == NULL )
	{
		return( false );
    }

	if ( ::stat( inPathName, &statbuf ) != 0 )
	{
		return( false );
	}

	return( true );

} // DoesDirectoryExist


//--------------------------------------------------------------------------------------------------
//	* DoesFileExist ()
//
//		- returns:	true  - file exists
//					false - file does not exist
//
//--------------------------------------------------------------------------------------------------

bool COSUtils::DoesFileExist ( const char *inPathName )
{
   	struct stat		statbuf;
	
	if ( inPathName == NULL )
	{
		return( false );
    }

	if ( ::stat( inPathName, &statbuf ) != 0 )
	{
		return( false );
	}

	return( true );

} // DoesFileExist


//--------------------------------------------------------------------------------------------------
// GetUID
//
// returns uid of the user specified by name. Returns -1 if user does not exist.
//--------------------------------------------------------------------------------------------------

sInt32 COSUtils::GetUID ( const char *inUserName )
{
	struct passwd *thePwd;
	uid_t theUID;

	if (!inUserName)
	{
		return -1;
	}

	COSUtils::Wait();
	thePwd = ::getpwnam(inUserName);
	if (!thePwd)
	{
		COSUtils::Signal();
		return -1;
	}

	theUID = thePwd->pw_uid;
	COSUtils::Signal();

	return (sInt32) theUID;
}

//--------------------------------------------------------------------------------------------------
//	* AuthenticateUser ()
//
//		- Authenticates the user with the given password.
//			Returns ture for success and false for failure.
//--------------------------------------------------------------------------------------------------

bool COSUtils::AuthenticateUser ( const char *inUserName, const char *inPasswd )
{
	register struct passwd	   *thePwd			= nil;
	bool						result			= false;
	char 					   *cryptedPasswd	= nil;
	static char					theSalt[3];

	if (!inUserName || !inPasswd)
	{
		return( result );
	}

	COSUtils::Wait();

	thePwd = ::getpwnam( inUserName );
	if ( !thePwd )
	{
		COSUtils::Signal();
		return result;
	}

	if (thePwd->pw_passwd[0] == '*')
	{
		return result;
	}

	::memset( theSalt, 0, 3 );
	theSalt[0] = thePwd->pw_passwd[0];
	theSalt[1] = thePwd->pw_passwd[1];
	theSalt[2] = '\0';

	cryptedPasswd = ::crypt( inPasswd, theSalt );

	if ( CUtils::Strcmp( cryptedPasswd, thePwd->pw_passwd ) == 0 )
    {
    	result = true;
	}
	else
	{
	}
	
	COSUtils::Signal();

	return result;
} // AuthenticateUser


// ---------------------------------------------------------------------------
//	* GetDBRootPath ()
//
// ---------------------------------------------------------------------------

const char* COSUtils::GetDBRootPath ( void )
{
	NSSearchPathEnumerationState	eState;
    char							localPath[ PATH_MAX + 1 ];

	if ( fDBRootPath == nil )
	{
		// Zero out the path holder
		::memset( localPath, 0, PATH_MAX + 1 );

		// Get the default location
		eState = NSStartSearchPathEnumeration( NSLibraryDirectory, NSLocalDomainMask );
		eState = NSGetNextSearchPathEnumeration( eState, localPath );

		// Create the new satatic global
		fDBRootPath = new char[ CUtils::Strlen( localPath ) + 1 ];
		if ( fDBRootPath != nil )
		{
			// Set the base path
			CUtils::Strcpy( fDBRootPath, localPath );
		}
	}

	return( fDBRootPath );

} // GetDBRootPath


// ---------------------------------------------------------------------------
//	* GetDBFolder ()
//
// ---------------------------------------------------------------------------

const char* COSUtils::GetDBFolder ( void )
{
	const char		   *pAppName	= nil;

	if ( fStaticDBFolder == nil )
	{
		CString		csTmpStr( PATH_MAX );

		// Set the base path
		csTmpStr.Set( COSUtils::GetDBRootPath() );

		// Get the application name
		csTmpStr.Append( "/" );
		csTmpStr.Append( CStatStr::GetStringFromList( kAppInfoListID, kStrAppName ) );

		fStaticDBFolder = (char *)::malloc( csTmpStr.GetLength() + 1 );
		if ( fStaticDBFolder != nil )
		{
			CUtils::Strcpy( fStaticDBFolder, csTmpStr.GetData() );
		}
	}

	return( fStaticDBFolder );

} // GetDBFolder


// ---------------------------------------------------------------------------
//	* GetFullDBPath ()
//
// ---------------------------------------------------------------------------

const char* COSUtils::GetFullDBPath ( void )
{
	const char		   *pDBName	= nil;

	if ( fFullDBPath == nil )
	{
		CString		csTmpStr( PATH_MAX );

		// Set the base path
		csTmpStr.Set( COSUtils:: GetDefaultDBPath() );

		// Append the Database filae name
		csTmpStr.Append( "/" );
		csTmpStr.Append( CStatStr::GetStringFromList( kAppInfoListID, kStrDatabaseFileName ) );

		fFullDBPath = (char *)::malloc( csTmpStr.GetLength() + 1 );
		if ( fFullDBPath != nil )
		{
			CUtils::Strcpy( fFullDBPath, csTmpStr.GetData() );
		}
	}

	return( fFullDBPath );

} // GetFullDBPath


// ---------------------------------------------------------------------------
//	* GetOldFullDBPath ()
//
// ---------------------------------------------------------------------------

const char* COSUtils::GetOldFullDBPath ( void )
{
	const char		   *pDBName	= nil;

	if ( fFullOldDBPath == nil )
	{
		CString		csTmpStr( PATH_MAX );

		// Set the base path
		csTmpStr.Set( COSUtils:: GetDefaultDBPath() );

		// Append the Database filae name
		csTmpStr.Append( "/" );
		csTmpStr.Append( CStatStr::GetStringFromList( kAppInfoListID, kStrOldMailDBFileName ) );

		fFullOldDBPath = (char *)::malloc( csTmpStr.GetLength() + 1 );
		if ( fFullOldDBPath != nil )
		{
			CUtils::Strcpy( fFullOldDBPath, csTmpStr.GetData() );
		}
	}

	return( fFullOldDBPath );

} // GetOldFullDBPath


// ---------------------------------------------------------------------------
//	* GetDefaultDBPath ()
//
// ---------------------------------------------------------------------------

const char* COSUtils::GetDefaultDBPath ( void )
{
	const char		   *pDBName	= nil;

	if ( fDefaultDBPath == nil )
	{
		CString		csTmpStr( PATH_MAX );

		// Set the base path
		csTmpStr.Set( COSUtils::GetDBFolder() );

		fDefaultDBPath = (char *)::malloc( csTmpStr.GetLength() + 1 );
		if ( fDefaultDBPath != nil )
		{
			CUtils::Strcpy( fDefaultDBPath, csTmpStr.GetData() );
		}
	}

	return( fDefaultDBPath );

} // GetDefaultDBPath


// ---------------------------------------------------------------------------
//	* SetDefaultDBPath ()
//
// ---------------------------------------------------------------------------

void COSUtils::SetDefaultDBPath ( const char *inStr )
{
	if ( inStr != nil )
	{
		if ( fDefaultDBPath != nil )
		{
			free( fDefaultDBPath );
			fDefaultDBPath = nil;
		}

		fDefaultDBPath = (char *)::malloc( CUtils::Strlen( inStr ) + 1 );
		if ( fDefaultDBPath != nil )
		{
			CUtils::Strcpy( fDefaultDBPath, inStr );
		}
	}
} // SetDefaultDBPath


// ---------------------------------------------------------------------------
//	* GetFullMailFolderPath ()
//
// ---------------------------------------------------------------------------

const char* COSUtils::GetFullMailFolderPath ( void )
{
	const char		   *pDBName	= nil;

	if ( fStaticMailFolder == nil )
	{
		CString		csTmpStr( PATH_MAX );

		// Set the base path
		csTmpStr.Set( COSUtils::GetDefaultDBPath() );

		// Append the mail folder name
		csTmpStr.Append( "/" );
		csTmpStr.Append( CStatStr::GetStringFromList( kAppInfoListID, kStrMailFolderName ) );

		fStaticMailFolder = (char *)::malloc( csTmpStr.GetLength() + 1 );
		if ( fStaticMailFolder != nil )
		{
			CUtils::Strcpy( fStaticMailFolder, csTmpStr.GetData() );
		}
	}

	return( fStaticMailFolder );

} // GetFullMailFolderPath


// ---------------------------------------------------------------------------
//	* GetMailStoreFolderPath ()
//
// ---------------------------------------------------------------------------

const char* COSUtils::GetMailStoreFolderPath ( void )
{
	const char		   *pDBName	= nil;

	if ( fStaticMailStoreFolder == nil )
	{
		CString		csTmpStr( PATH_MAX );

		// Set the base path
		csTmpStr.Set( COSUtils::GetDefaultDBPath() );

		// Append the mail folder name
		csTmpStr.Append( "/" );
		csTmpStr.Append( CStatStr::GetStringFromList( kAppInfoListID, kStrMailFolderName ) );

		// Append the mail store name
		csTmpStr.Append( "/" );
		csTmpStr.Append( CStatStr::GetStringFromList( kAppInfoListID, kStrMailStoreFolderName ) );

		fStaticMailStoreFolder = (char *)::malloc( csTmpStr.GetLength() + 1 );
		if ( fStaticMailStoreFolder != nil )
		{
			CUtils::Strcpy( fStaticMailStoreFolder, csTmpStr.GetData() );
		}
	}

	return( fStaticMailStoreFolder );

} // GetMailStoreFolderPath


// ---------------------------------------------------------------------------
//	* GetCurrentDayFolder ()
//
// ---------------------------------------------------------------------------

const char* COSUtils::GetCurrentDayFolder ( void )
{
	time_t				seconds			= ::time( nil );
	Str255				timeStr;
	struct  tm		   *pTmp			= nil;

	try
	{
		// Get today's date struct
		pTmp = ::localtime( &seconds );

		// Make sure the statics are set or check if the day changed
		if ( (fDay == 0) || (fMonth == 0) || (fDay =! pTmp->tm_mday) || (fMonth != pTmp->tm_mon + 1) )
		{
			fDay = pTmp->tm_mday;
			fMonth = pTmp->tm_mon + 1;

			if ( fStaticDailyMailStoreFolder != nil )
			{
				free( fStaticDailyMailStoreFolder );
				fStaticDailyMailStoreFolder = nil;
			}
			if ( fStaticDateFolder != nil )
			{
				free( fStaticDateFolder );
				fStaticDateFolder = nil;
			}
		}

		// Make the date-time string
		if ( fStaticDateFolder == nil )
		{
			// Get the date in dd-mm-yy format
			::memset( timeStr, 0, sizeof( Str255 ) );
			COSUtils::DateTimeString( ::time( nil ), kNumericDate, timeStr );

			fStaticDateFolder = (char *)::malloc( CUtils::Strlen( (char *)timeStr ) + 1 );
			if ( fStaticDateFolder != nil )
			{
				CUtils::Strcpy( fStaticDateFolder, (char *)timeStr );
			}

			
		}
	}

	catch ( ... )
	{
	}

	return( fStaticDateFolder );

} // GetCurrentDayFolder


// ---------------------------------------------------------------------------
//	* GetDailyMailStoreFolderPath ()
//
// ---------------------------------------------------------------------------

const char* COSUtils::GetDailyMailStoreFolderPath ( void )
{
	const char		   *pDBName			= nil;
    CString				csTmpStr( PATH_MAX );

	try
	{
		// Make the daily mail store folder
		if ( fStaticDailyMailStoreFolder == nil )
		{
			// Set the base path
			csTmpStr.Set( COSUtils::GetMailStoreFolderPath() );
	
			// Append the new date folder name
			csTmpStr.Append( "/" );
			csTmpStr.Append( GetCurrentDayFolder() );

			fStaticDailyMailStoreFolder = (char *)::malloc( csTmpStr.GetLength() + 1 );
			if ( fStaticDailyMailStoreFolder != nil )
			{
				CUtils::Strcpy( fStaticDailyMailStoreFolder, csTmpStr.GetData() );
			}

			CreateAndVerifyPath( csTmpStr.GetData(), 0, 0, 0100700 );
		}
	}

	catch ( ... )
	{
	}

	return( fStaticDailyMailStoreFolder );

} // GetDailyMailStoreFolderPath


// ---------------------------------------------------------------------------
//	* GetCurrentMailStoreFolderPath ()
//
// ---------------------------------------------------------------------------

const char* COSUtils::GetCurrentMailStoreFolderPath ( void )
{
	uInt32	uiCnt	= 0;

	COSUtils::Wait();

	// Intial startup check
	if ( CGlobals::GetCurrentMessageCount() == 0 )
	{
		COSUtils::FindCurrentFolder();
		if ( fStaticCurrentMailStorePath != nil )
		{
			uiCnt = COSUtils::CountEntires( fStaticCurrentMailStorePath );

			if ( uiCnt < kFolderLimit )
			{
				CGlobals::SetCurrentMessageCount( uiCnt );
			}
			else
			{
				CreateNewCurrentFolder();
				CGlobals::SetCurrentMessageCount( 1 );
			}
		}
	}
	else if ( CGlobals::GetCurrentMessageCount() > kFolderLimit )
	{
		CreateNewCurrentFolder();
		CGlobals::SetCurrentMessageCount( 1 );
	}
	else if ( fStaticCurrentMailStorePath == nil )
	{
		COSUtils::FindCurrentFolder();
	}

	COSUtils::Signal();

	return( fStaticCurrentMailStorePath );

} // GetCurrentMailStoreFolderPath


// ---------------------------------------------------------------------------
//	* GetFullAccountFolderPath ()
//
// ---------------------------------------------------------------------------

const char* COSUtils::GetFullAccountFolderPath ( void )
{
	const char		   *pDBName	= nil;
    CString				csTmpStr( PATH_MAX );

	if ( fStaticAccountsFolder == nil )
	{
		// Set the base path
		csTmpStr.Set( COSUtils::GetDefaultDBPath() );

		// Append the mail folder name
		csTmpStr.Append( "/" );
		csTmpStr.Append( CStatStr::GetStringFromList( kAppInfoListID, kStrMailFolderName ) );

		// Append users account folder name
		csTmpStr.Append( "/" );
		csTmpStr.Append( CStatStr::GetStringFromList( kAppInfoListID, kStrUserAccountsFolderName ) );

		fStaticAccountsFolder = (char *)::malloc( csTmpStr.GetLength() + 1 );
		if ( fStaticAccountsFolder != nil )
		{
			CUtils::Strcpy( fStaticAccountsFolder, csTmpStr.GetData() );
		}
	}

	return( fStaticAccountsFolder );

} // GetFullAccountFolderPath


// ---------------------------------------------------------------------------
//	* GetLogFileFolder ()
//
// ---------------------------------------------------------------------------

const char* COSUtils::GetLogFileFolder ( void )
{
	const char		   *pDBName	= nil;
    CString				csTmpStr( PATH_MAX );

	if ( fLogFileFolder == nil )
	{
		// Set the base path
		csTmpStr.Set( COSUtils::GetDBRootPath() );

		// Append log file folder name
		csTmpStr.Append( "/" );
		csTmpStr.Append( CStatStr::GetStringFromList( kAppInfoListID, kStrLogFileFolderName ) );

		fLogFileFolder = new char[ csTmpStr.GetLength() + 1 ];
		if ( fLogFileFolder != nil )
		{
			CUtils::Strcpy( fLogFileFolder, csTmpStr.GetData() );
		}
	}

	return( fLogFileFolder );

} // GetLogFileFolder


// ---------------------------------------------------------------------------
//	* GetMailLogFolder ()
//
// ---------------------------------------------------------------------------

const char* COSUtils::GetMailLogFolder ( void )
{
	const char		   *pDBName	= nil;
    CString				csTmpStr( PATH_MAX );

	if ( fMailLogFolder == nil )
	{
		// Set the base path
		csTmpStr.Set( COSUtils::GetDBRootPath() );

		// Append log file folder name
		csTmpStr.Append( "/" );
		csTmpStr.Append( CStatStr::GetStringFromList( kAppInfoListID, kStrLogFileFolderName ) );

		// Append mail log file folder name
		csTmpStr.Append( "/" );
		csTmpStr.Append( CStatStr::GetStringFromList( kAppInfoListID, kStrMailServiceLogFolderName ) );

		fMailLogFolder = new char[ csTmpStr.GetLength() + 1 ];
		if ( fMailLogFolder != nil )
		{
			CUtils::Strcpy( fMailLogFolder, csTmpStr.GetData() );
		}
	}

	return( fMailLogFolder );
                                                                                                                                                                                                                                                                                                                                                                                                                                    
} // GetMailLogFolder


// ---------------------------------------------------------------------------
//	* GetMigrationFolder ()
//
// ---------------------------------------------------------------------------

const char* COSUtils::GetMigrationFolder ( void )
{
	const char		   *pDBName	= nil;
    CString				csTmpStr( PATH_MAX );

	if ( fMigrationFolder == nil )
	{
		// Set the base path
		csTmpStr.Set( COSUtils::GetLogFileFolder() );

		// Get the application name
		csTmpStr.Append( "/" );
		csTmpStr.Append( CStatStr::GetStringFromList( kAppInfoListID, kStrMigrationLogFolderName ) );

		fMigrationFolder = new char[ csTmpStr.GetLength() + 1 ];
		if ( fMigrationFolder != nil )
		{
			CUtils::Strcpy( fMigrationFolder, csTmpStr.GetData() );
		}
	}

	return( fMigrationFolder );

} // GetMigrationFolder


// ---------------------------------------------------------------------------
//	* GetConfigFolder ()
//
// ---------------------------------------------------------------------------

const char* COSUtils::GetConfigFolder ( void )
{
	const char		   *pDBName	= nil;
    CString				csTmpStr( PATH_MAX );

	if ( fConfigFolder == nil )
	{
		// Set the base path
		csTmpStr.Set( COSUtils::GetDBRootPath() );

		// Get the application name
		csTmpStr.Append( "/" );
		csTmpStr.Append( CStatStr::GetStringFromList( kAppInfoListID, kStrPrefsFolderName ) );

		// Get the application name
		csTmpStr.Append( "/" );
		csTmpStr.Append( CStatStr::GetStringFromList( kAppInfoListID, kStrNewAppName ) );

		fConfigFolder = new char[ csTmpStr.GetLength() + 1 ];
		if ( fConfigFolder != nil )
		{
			CUtils::Strcpy( fConfigFolder, csTmpStr.GetData() );
		}
	}

	return( fConfigFolder );

} // GetConfigFolder


// ---------------------------------------------------------------------------
//	* GetTempFolder ()
//
// ---------------------------------------------------------------------------

const char* COSUtils::GetTempFolder ( void )
{
	const char		   *pDBName	= nil;
    CString				csTmpStr( PATH_MAX );

	if ( fStaticTempFolder == nil )
	{
		// Set the base path
		csTmpStr.Set( COSUtils::GetMailStoreFolderPath() );

		// Get the temp folder name
		csTmpStr.Append( "/" );
		csTmpStr.Append( CStatStr::GetStringFromList( kAppInfoListID, kStrTempFolderName ) );

		fStaticTempFolder = new char[ csTmpStr.GetLength() + 1 ];
		if ( fStaticTempFolder != nil )
		{
			CUtils::Strcpy( fStaticTempFolder, csTmpStr.GetData() );
		}
	}

	return( fStaticTempFolder );

} // GetTempFolder


// ---------------------------------------------------------------------------
//	* DateString ()
//
// ---------------------------------------------------------------------------

int COSUtils::DateString ( long dateTime, MSDateForm longFlag, Str255 outResult )
{
	register int		length		= 0;
	register struct tm *tmPtr		= NULL;

	tmPtr = ::localtime( &dateTime );

	switch ( longFlag )
	{
		case kLongDate:
			length = ::strftime( (char *)outResult, 255, "%A, %B %e, %Y", tmPtr );	// Friday, December 25, 1998
			break;

		case kAbbrevDate:
			length = ::strftime( (char *)outResult, 255, "%a, %b %e, %Y", tmPtr );	// Fri, Dec 25, 1998
			break;

		case kShortDate:
		default:
			length = ::strftime( (char *)outResult, 255, "%x", tmPtr );				// 12/25/98
			break;
	}

	return( length );

} // DateString


//--------------------------------------------------------------------------------------------------
//	* TimeString
//
//--------------------------------------------------------------------------------------------------

int COSUtils::TimeString ( long dateTime, bool wantSeconds, Str255 outResult )
{
	register int		length		= 0;
	register struct tm *tmPtr		= NULL;

	tmPtr = ::localtime( &dateTime );

	if ( wantSeconds == true )
	{
		length = ::strftime( (char *)outResult, 255, "%X", tmPtr );
	}
	else
	{
		length = ::strftime( (char *)outResult, 255, "%R", tmPtr );
	}

	return( length );

} // TimeString


//--------------------------------------------------------------------------------------------------
//	* DateTimeString
//
//--------------------------------------------------------------------------------------------------

int COSUtils::DateTimeString ( long dateTime, MSDateForm longFlag, Str255 outResult )
{
	register int		length		= 0;
	register struct tm *tmPtr		= NULL;

	tmPtr = ::localtime( &dateTime );

	switch ( longFlag )
	{
		case kLongDate:
			length = ::strftime( (char *)outResult, 255, "%A %B %e %Y %X", tmPtr );	// Friday, December 25, 1998, 12:00:00
			break;

		case kNumericDate:
			length = ::strftime( (char *)outResult, 255, "%m-%d-%Y", tmPtr );	// 05-12-01
			break;

		case kMailBoxDate:
			length = ::strftime( (char *)outResult, 255, "%a %b %e %X %Y", tmPtr );		// Wed Dec 25 12:00:00 1998
			break;

		case kShortDate:
		case kAbbrevDate:
		default:
			length = ::strftime( (char *)outResult, 255, "%b %e %Y %X", tmPtr );		// Dec 25 1998 12:00:00
			break;
	}

	return( length );

} // DateTimeString


//--------------------------------------------------------------------------------------------------
//	* InitializeGlobals ()
//
//		- this static function must be called during app startup after the thread table exists and
//		  after daemonization, but before additional threads have started. This ensures proper
//		  initialization of the static semaphore.
//--------------------------------------------------------------------------------------------------

void COSUtils::InitializeGlobals ( void )
{
} // InitializeGlobals


// ---------------------------------------------------------------------------
//	* Signal ()
//
// ---------------------------------------------------------------------------

void COSUtils::Signal ( void )
{
} // Signal


// ---------------------------------------------------------------------------
//	* Wait ()
//
// ---------------------------------------------------------------------------

ExceptionCode COSUtils::Wait ( sInt32 milliSecs )
{
	return 0;
} // Wait


// ---------------------------------------------------------------------------
//	* CreateAndVerifyPath ()
//
// ---------------------------------------------------------------------------

sInt32 COSUtils::CreateAndVerifyPath ( const char *inPath, uid_t inUID, gid_t inGID, mode_t inPermission, bool inCreateAll )
{
	sInt32		siResult	= kUnknownDirectoryError;
	char	   *p			= (char *)inPath;
	char	   *s			= (char *)inPath;
	bool		done		= false;
	CString		csFullPath( "/" );

	if ( p != nil )
	{
		if ( *p == '/' )
		{
			p++;
			s++;
		}

		while ( !done )
		{
			p = ::strchr( p, '/' );
			if ( p != nil )
			{
				csFullPath.Append( s, p - s );

				siResult = COSUtils::CreateDirectory( csFullPath.GetData(), inUID, inGID, inPermission );
				if ( (siResult != kNoErr) && (siResult != kDirectoryCreated) )
				{
					done = true;
				}

				csFullPath.Append( "/" );

				// Skip past the '/' char
				p ++;
				s = p;
			}
			else
			{
				if ( inCreateAll == true )
				{
					csFullPath.Append( s );
	
					siResult = COSUtils::CreateDirectory( csFullPath.GetData(), inUID, inGID, inPermission );
				}
				done = true;
			}
		};
	}

	return( siResult );

} // CreateAndVerifyPath
        

// ---------------------------------------------------------------------------
//	* VerifyDirectory ()
//
// ---------------------------------------------------------------------------

sInt32 COSUtils::VerifyDirectory ( const char *inPath )
{
	sInt32			siResult	= kUnknownDirectoryError;
	int				result		= 0;
	struct stat		statbuf;

	// check if the directory exists
	result = ::stat( inPath, &statbuf );
	if ( result == 0 )
	{
		// This is a good thing
		siResult = kNoErr;
	}

	return( siResult );

} // VerifyDirectory


// ---------------------------------------------------------------------------
//	* CreateDirectory ()
//
// ---------------------------------------------------------------------------

sInt32 COSUtils::CreateDirectory ( const char *inPath, uid_t inUID, gid_t inGID, mode_t inPermission )
{
	sInt32			siResult	= kUnknownDirectoryError;
	int				iResult		= 0;
	struct stat		statbuf;

	// check if the directory already exists
	iResult = ::stat( inPath, &statbuf );
	if ( iResult == 0 )
	{
		// This is a good thing
		siResult = kNoErr;
	}
	else
	{
		switch ( errno )
		{
			case ENOENT:
				// Directory does not exist, create it
				iResult = ::mkdir( inPath, inPermission );
				if ( iResult == 0 )
				{
					siResult = kDirectoryCreated;

					// Set the permissions, gid and uid
			
					::chmod( inPath, inPermission );
					::chown( inPath, inUID, inGID );
				}
				else
				{
					siResult = kFailedToCreateDirectory;
				}
				break;
	
			case EACCES:
				siResult = kDirectoryAccessDenied;
				break;
	
			default:
				siResult = kOtherDirectoryError;
				break;
	
		} // switch
	}

	return( siResult );

} // CreateDirectory


// ---------------------------------------------------------------------------
//	* CountEntires ()
//
// ---------------------------------------------------------------------------

uInt32 COSUtils::CountEntires ( const char *inPath )
{
			uInt32		uiResult	= 0;
	struct	dirent	   *dp			= nil;
			DIR		   *dirp		= nil;

	dirp = ::opendir( inPath );

	while ( (dp = ::readdir( dirp )) != NULL )
	{
		uiResult++;
	}

	(void)::closedir( dirp );

	return( uiResult );

} // CountEntires


// ---------------------------------------------------------------------------
//	* FindCurrentFolder ()
//
// ---------------------------------------------------------------------------

const char* COSUtils::FindCurrentFolder ( void )
{
	bool		done	= false;
	uInt32		uiCntr	= 1;
	CString		csPath1;
	CString		csPath2;
	char		pTmpStr[ 16 ];

	while ( !done )
	{
		::sprintf( pTmpStr, "%04d", uiCntr );

		csPath1.Sprintf( "%s/%s", COSUtils::GetDailyMailStoreFolderPath(), pTmpStr );

		if ( COSUtils::VerifyDirectory( csPath1.GetData() ) != kNoErr )
		{
			done = true;
			if ( uiCntr == 1 )
			{
				COSUtils::CreateNewCurrentFolder();
			}
			else
			{
				if ( fStaticCurrentMailStorePath != nil )
				{
					free( fStaticCurrentMailStorePath );
					fStaticCurrentMailStorePath = nil;
				}

				fStaticCurrentMailStorePath = (char *)::malloc( csPath2.GetLength() + 1 );

				CUtils::Strcpy( fStaticCurrentMailStorePath, csPath2.GetData() );

				SetTargetFolder( uiCntr - 1 );
			}
		}
		else
		{
			csPath2.Set( csPath1.GetData() );
		}
		uiCntr++;
	}

	return( fStaticCurrentMailStorePath );

} // FindCurrentFolder


// ---------------------------------------------------------------------------
//	* CreateNewCurrentFolder ()
//
// ---------------------------------------------------------------------------

void COSUtils::CreateNewCurrentFolder ( void )
{
	bool		done	= false;
	uInt32		uiCntr	= 1;
	CString		csPath;
	char		pTmpStr[ 16 ];

	while ( !done )
	{
		::sprintf( pTmpStr, "%04d", uiCntr );

		csPath.Sprintf( "%s/%s", COSUtils::GetDailyMailStoreFolderPath(), pTmpStr );

		if ( COSUtils::VerifyDirectory( csPath.GetData() ) != kNoErr )
		{
			done = true;

			if ( CreateAndVerifyPath( csPath.GetData(), 0, 0, 0100700 ) == kDirectoryCreated )
			{
				if ( fStaticCurrentMailStorePath != nil )
				{
					free( fStaticCurrentMailStorePath );
					fStaticCurrentMailStorePath = nil;
				}

				fStaticCurrentMailStorePath = (char *)::malloc( ::strlen( csPath.GetData() ) + 1 );

				CUtils::Strcpy( fStaticCurrentMailStorePath, csPath.GetData() );

				if ( fStaticTargetFolder == nil )
				{
					fStaticTargetFolder = (char *)::malloc( 32 );
				}

				CUtils::Strcpy( fStaticTargetFolder, pTmpStr );
			}
		}
		uiCntr++;
	}
} // CreateNewCurrentFolder


// ---------------------------------------------------------------------------
//	* GetTargetFolder ()
//
// ---------------------------------------------------------------------------

const char* COSUtils::GetTargetFolder ( void )
{
	if ( fStaticTargetFolder == nil )
	{
		fStaticTargetFolder = (char *)::malloc( 16 );

		::sprintf( fStaticTargetFolder, "%04d", 1 );
	}

	return( fStaticTargetFolder );

} // GetTargetFolder


// ---------------------------------------------------------------------------
//	* SetTargetFolder ()
//
// ---------------------------------------------------------------------------

void COSUtils::SetTargetFolder ( uInt32 inNumber )
{
	if ( fStaticTargetFolder == nil )
	{
		fStaticTargetFolder = (char *)::malloc( 16 );
	}

	if ( fStaticTargetFolder != nil )
	{
		::sprintf( fStaticTargetFolder, "%04d", inNumber );
	}
} // SetTargetFolder


// ---------------------------------------------------------------------------
//	* GetPath ()
//
// ---------------------------------------------------------------------------

CString * COSUtils::GetPath ( CString &inPath, uid_t inUID, gid_t inGID, mode_t inPermission )
{
	int				i			= 0;
	int				iResult		= 0;
	CString		   *pOutPath	= nil;
	CString			csToken;
	CString			csTmp;
	struct stat		statbuf;

	try
	{
		CTokenizer	token( inPath, "/" );

		pOutPath = new CString( PATH_MAX );
		if ( pOutPath != nil )
		{
			pOutPath->Clear();

			for ( i = 1; i < token.Count(); i++ )
			{
				csToken.Set(  token.Get( i ), token.GetLength( i ) );
				if ( (i == 3) && (CUtils::Stricmp( csToken.GetData(), "INBOX" ) == 0) )
				{
					csTmp.Sprintf( "%s/Inbox_Subfolder", pOutPath->GetData() );
				}
				else
				{
					csTmp.Sprintf( "%s/%s", pOutPath->GetData(), csToken.GetData() );
				}
	
				pOutPath->Set( csTmp.GetData() );

				if ( i < token.Count() )
				{
					// Does it already exist
					iResult = ::stat( pOutPath->GetData(), &statbuf );
					if ( iResult == 0 )
					{
					}
					else
					{
						COSUtils::CreateAndVerifyPath( pOutPath->GetData(), inUID, inGID, 0755 );
					}
				}
				else
				{
				}
			}
		}
	}
	catch ( ... )
	{
	}
} // GetPath




