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

	File:		CMailSpool.cpp

	Contains:	C++ implementation of generic mail spool objects

	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: CMailSpool.cpp,v $
		Revision 1.1  2003/04/20 23:45:34  dasenbro
		Initial check-in.
		
		Revision 1.14  2002/06/04 17:57:59  dasenbro
		Added UnLockTheCache() to the catch().
		
		Revision 1.13  2002/05/09 16:58:58  dasenbro
		Changed all str... calls to CUtils::Str... to be NULL safe.
		
		Revision 1.12  2002/03/21 16:41:23  dasenbro
		Updated file version information.
		
		Revision 1.11  2002/01/14 17:45:23  dasenbro
		Initial S4 updates.
		
		Revision 1.10  2001/06/21 17:48:33  dasenbro
		Added Change History.


	Projector History:

	 <ASM12>	  3/1/99	MED		Removed the member functions that handled the unseen count.  It
									is now calculated on the fly.
	 <ASM11>	 1/29/99	DOR		More changes.
	 <ASM10>	 1/29/99	DOR		CMailSpool::Remove no longer throws if it can't find the
									CEnvelopeObject...this cleans up the spool in the event that the
									original message is missing.
	  <ASM9>	 1/24/99	MED		Added getters and setters for the TOC mark.
	  <ASM8>	 1/11/99	DOR		Remove some unused code, fix some race conditions...
		 <7>	11/12/98	DOR		Tighten up some code to prevent race conditions in Key value
									changes on MacOS X
		 <6>	10/30/98	DOR		Fix it so that when the object's 2nd ID changes that it is
									immediately flushed to the Database so that the 2nd ID iteration
									table is updated, even before the object's final "Done" is
									called.
		 <5>	10/21/98	DOR		Fix it so that we properly calculate the message size...
		 <4>	10/22/98	MED		Added RemoveUser() to remove the user even if the shared spool
									doesn't exist.
		 <3>	10/13/98	DOR		Lock the cache when deleting an object.
		 <2>	10/12/98	MED		Added RemoveGroupSharedSpools() to delete all shared group
									mailboxes.
		<43>	 10/7/98	MED		Fix a projector problem.
		<42>	 10/6/98	MED		Added IsSpoolInList().
		<41>	 9/21/98	DOR		Change all uses of "Assert_" to "MailAssert"..
		<40>	 9/21/98	DOR		Don't use NULL pointers!!
		<39>	 9/17/98	MED		Changed CanSetACL to IsAdmin.
		<38>	 9/14/98	MED		Added more ACL member functions.
		<37>	  9/8/98	MED		Added FindSharedByName() and a shared spool type.
		<36>	 8/31/98	MED		Constructor now takes an account ID arg to force a 2nd ID page
									creation in the db.
		<35>	 8/10/98	MED		Added more support for ACLs and removed the usage for the recent
									count (it is now calculated when needed).
		<34>	  8/3/98	MED		6.1 - Added ACL support calls.
		<33>	 7/25/98	MED		Added Get/SetRights for ACL.
		<32>	 6/15/98	MED		#2245243 - Added a change flag to spool for updating env-info
									flags.
		<31>	  6/4/98	MED		Moved yield into data loop.
		<30>	  6/1/98	DOR		Fix "GetSetFields"
		<29>	  6/1/98	DOR		Remove the "kAdd" argument from Create since we no longer use
									it.Remove the "kAdd" argument from Create since we no longer use
									it.
		<28>	  6/1/98	MED		Changed ::Create to be a more kinder and gentler ::Create.
		<27>	 5/19/98	MED		Added future expansion data members.
		<26>	 4/28/98	MED		Added a refcount to keep track of number of IMAP "Selects"
									against each mailbox.
		<25>	 4/25/98	MED		Added a SmartYield() to FindByNameParentID().
		<24>	 4/14/98	MED		Decrement the spool's recent count when it is removed by POP3.
		<23>	  4/8/98	MED		FindByParentID now takes a boolean to check for case sensitive
									name matching or not.
		<22>	  4/8/98	DOR		Fix warnings.
		<21>	  4/8/98	DOR		Change from using ::strncpy to CUtils::strncpy
		<20>	  4/8/98	DOR		Fix some ::strcpy's to be ::strncpy's
		<19>	  4/2/98	DOR		Change call to gDB->removeObject
		<18>	 3/28/98	MED		Set the pop lock to false in the constructor.
		<17>	03/23/98	DOR		Get rid of next MXRecord
		<16>	 3/14/98	DOR		Close up a race condition in ::Create..
		<14>	 3/11/98	MED		Changed FindByID() to do a Use() only if it created the object,
									FindMe() now does an explicit Use().
		<13>	 3/10/98	DOR		CMailSpool::Remove changed, make adjustments in how we call it &
									fix DeleteAllEnvInfo's to do it correctly, {sigh}
		<12>	 3/10/98	DOR		Remove IMAP processing spool, and outgoing spool.
		<11>	  3/3/98	MED		Added a "Recent" marker to keep track of the recent count of
									mail messages posted to this spool since the last IMAP session.
		<10>	  3/2/98	MED		Added an Unseen count to the persistent data and its getters and
									setters.
		 <9>	 2/23/98	MED		Added a ->Done in FindByNameParentID to stop a leak and set the
									subscribed flag on the POP3 inbox.
		 <8>	  2/4/98	MED		Added ResetSpoolCounts().
		 <7>	  2/3/98	MED		Cleaned OSUtil.cp into CUtils.cp, COSUtils.cp and
									CSmartYield.cp.
		 <6>	 1/27/98	MED		Fixed MoveEnvelopes() to "Done" the envelop info object and
									iterate across the list properly and modified GetSetFields to
									include the POP inbox in the second ID list.
		 <5>	12/15/97	DOR		Update the object version to "include" the size of the
									dataportion of the object, and add an assert to "FindByID" that
									checks the version of the object.
		 <4>	 12/3/97	MED		Added outEnvInfoID arg to Post() to return the newly created
									envelope info.
		 <3>	 11/5/97	MED		Added spool flags.
		 <2>	 10/9/97	MED		Modified the session stamp.

	To Do:
*/


// System
#include <string.h>
#include <time.h>
#include <unistd.h>

// App
#include "CMailDatabase.h"
#include "CMailSpool.h"
#include "CEnvelopeInfo.h"
#include "CEnvelope.h"
#include "Database.h"
#include "CUtils.h"
#include "CRootObject.h"
#include "UException.h"
#include "CGlobals.h"
#include "DSMailUser.h"

// ACL
#include "CACLObject.h"
#include "CSharedFlags.h"

extern uInt32 gSyncFoldersStamp;


//--------------------------------------------------------------------------------------------------
//	* GetSetFields
//
//--------------------------------------------------------------------------------------------------

Boolean	CMailSpool::GetSetFields (	const eFieldDataRequest inFieldRequest,
									const void *inObjDataPtr,
									void *outFieldData )
{
	Boolean			result = false;
	CMailSpoolData	*aMailSpoolDataPtr = (CMailSpoolData *) inObjDataPtr;
	CMailSpool		*aTempObject	= NULL;
	ObjID			*anObjIDPtr = (ObjID *) outFieldData;

	switch ( inFieldRequest )
	{
		case kSetObjID:
			if (aMailSpoolDataPtr != NULL)
			{
				aMailSpoolDataPtr->fMailSpoolID = *anObjIDPtr;
			}
			break;

		case k2ndIDRequest:
			if ( aMailSpoolDataPtr != NULL )
			{
				if ( aMailSpoolDataPtr->fAccountID != 0 )
				{
					switch ( aMailSpoolDataPtr->fSpoolType )
					{
						case CMailSpool::kPOP3Spool:
						case CMailSpool::kIMAP4InBoxSpool:
						case CMailSpool::kIMAP4Spool:
							*anObjIDPtr = aMailSpoolDataPtr->fAccountID;
							result = true;
							break;
					}
				}
			}
			break;

		case kObjectPINGRequest:
			// cause the objects constructor to get called, so we force a check of
			// the struct alignment...
			aTempObject = new CMailSpool;
			delete aTempObject;
			break;

		case k2ndIDTargetChk:
			result = true;
			break;

		case kStringNameRequest:
		default:
			result = false;
			break;
	}

	return( result );
} // GetSetFields



//--------------------------------------------------------------------------------------------------
//	* GetMyID
//
//--------------------------------------------------------------------------------------------------

ObjID CMailSpool::GetObjectID	( void )
{
	return (this->GetMailSpoolID());
}

//--------------------------------------------------------------------------------------------------
//	 Done
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::Done ( CMailSpool* &inPtr )
{
	CDBBaseObject *aDBObject = (CDBBaseObject *) inPtr;
	aDBObject->Done(aDBObject);
	inPtr = (CMailSpool *)aDBObject;

}

//--------------------------------------------------------------------------------------------------
//	* FindByID
//
//--------------------------------------------------------------------------------------------------

CDBBaseObject * CMailSpool::ObjectAllocNew	( void )
{
	return new CMailSpool;
}

CMailSpool* CMailSpool::FindByID ( const ObjID inObjectID )
{
	return (CMailSpool *) CDBMailBaseObject::MailUniversalFindByID(	inObjectID,
														CMailSpool::GetObjTypeConstant(),
														CMailSpool::GetObjVersConstant(),
														CMailSpool::GetObjSizeConstant(),
														CMailSpool::ObjectAllocNew		);
} // FindByID


//--------------------------------------------------------------------------------------------------
//	* GetMailSpoolData
//
//--------------------------------------------------------------------------------------------------

CMailSpoolData* CMailSpool::GetMailSpoolData ( void )
{
	CMailSpoolData* result = NULL;
	if ( this != NULL )
	{
		result = &( this->fMailSpoolData );
	}

	return( result );
} // GetMailSpoolData



//--------------------------------------------------------------------------------------------------
//	* FindSystemSpool
//
//--------------------------------------------------------------------------------------------------

CMailSpool* CMailSpool::FindSystemSpool ( uInt32 inSystemSpoolType )
{
	try
	{
		CMailSpool* theMailSpool = NULL;
		ObjID		theSpoolID = 0;

		// xxx change this to a search...
		switch ( inSystemSpoolType )
		{
			case kIncomingSpool:
				if ( gRootObj != NULL )
				{
					theSpoolID = gRootObj->GetSysSpoolID( inSystemSpoolType );
				}
				break;
			default:
				break;
		}

		if ( theSpoolID != 0 )
		{
			theMailSpool = FindByID( theSpoolID );
		}
		return( theMailSpool );
	}

	catch( ... )
	{
		return( NULL );
	}
} // FindSystemSpool



//--------------------------------------------------------------------------------------------------
//	* FindByNameParentID
//
//--------------------------------------------------------------------------------------------------

CMailSpool* CMailSpool::FindByNameParentID ( char *inName,
											 ObjID inParentID,
											 ObjID inAccountID,
											 Boolean inCaseSensitive )
{
	Boolean			success		= false;
	OSErr			result		= kNoErr;
	ObjID			objID		= 0;
	CMailSpool	   *mailSpool	= nil;
	SDBIterator		iterator(gDB);

	result = gDB->CreateIterator( kMailSpoolSignature, &iterator, inAccountID );
	if ( result == kNoErr )
	{
		while ( !success && (gDB->NextObject( &iterator, objID ) == kNoErr) )
		{
			mailSpool = CMailSpool::FindByID( objID );
			if ( mailSpool != nil )
			{
				if ( mailSpool->GetParentID() == inParentID )
				{
					if ( inCaseSensitive == true )
					{
						success = (CUtils::Strcmp( mailSpool->GetMailSpoolName(), inName ) == 0);
					}
					else
					{
						success = (CUtils::Stricmp( mailSpool->GetMailSpoolName(), inName ) == 0);
					}
				}

				if ( success == false )
				{
					mailSpool->Done( mailSpool );
				}
			}
		}
	}
	result = gDB->ReleaseIterator( &iterator );

	return( mailSpool );

} // FindByNameParentID






//--------------------------------------------------------------------------------------------------
//	* FindByName
//
//--------------------------------------------------------------------------------------------------

CMailSpool* CMailSpool::FindSharedByName ( char *inName, Boolean inCaseSensitive )
{
	Boolean			success		= false;
	OSErr			result		= kNoErr;
	ObjID			objID		= 0;
	CMailSpool	   *mailSpool	= nil;
	SDBIterator		iterator(gDB);

	result = gDB->CreateIterator( kMailSpoolSignature, &iterator );
	if ( result == kNoErr )
	{
		while ( !success && (gDB->NextObject( &iterator, objID ) == kNoErr) )
		{
			mailSpool = CMailSpool::FindByID( objID );
			if ( mailSpool != nil )
			{
				if ( (mailSpool->GetParentID() == kSharedParent) && 
					 (mailSpool->GetAccountID() == kSharedAccountID) )
				{
					if ( inCaseSensitive == true )
					{
						success = (CUtils::Strcmp( mailSpool->GetMailSpoolName(), inName ) == 0);
					}
					else
					{
						success = (CUtils::Stricmp( mailSpool->GetMailSpoolName(), inName ) == 0);
					}
				}

				if ( success == false )
				{
					mailSpool->Done( mailSpool );
				}
			}
		}
	}
	result = gDB->ReleaseIterator( &iterator );

	return( mailSpool );

} // FindByName



//--------------------------------------------------------------------------------------------------
//	* Create
//
//--------------------------------------------------------------------------------------------------

CMailSpool* CMailSpool::Create ( uInt32		 inMailSpoolType,	// spool type
								 const char *inMailSpoolName,	// spool name
								 ObjID		 inAccountID,		// user account ID
								 ObjID		 inParentID )
{
	CMailSpool	   *spoolObj	= new CMailSpool( inAccountID, inMailSpoolType );		// creates a reference
	OSErr			result		= kNoErr;
	ObjID			aNewID		= 0;
	const char*		theType		= NULL;

	try
	{
		ThrowIfMemFail_( spoolObj );

		(gDB->GetBaseObjectCachePtr())->LockTheCache( CMailSpool::GetObjTypeConstant() );

		result = gDB->CreateObj( kMailSpoolSignature, aNewID, spoolObj->GetMailSpoolData() );
		if ( result == CMailDatabase::kDBNoErr )
		{
			spoolObj->Use();
//			spoolObj->SetMailSpoolType( inMailSpoolType );
			spoolObj->SetMailSpoolName( inMailSpoolName );
			spoolObj->SetParentID( inParentID );

			switch ( inMailSpoolType )
			{
				case kPOP3Spool:
					theType = "POP3";
					spoolObj->SetFlags( kSubscribedFlag );
					break;

				case kIMAP4InBoxSpool:
					theType = "IMAP4 Inbox";
					spoolObj->SetFlags( kSubscribedFlag );
					break;

				case kIMAP4Spool:
					theType = "IMAP4 Mailbox";
					spoolObj->SetFlags( 0 );
					break;

				case kIncomingSpool:
					theType = "Incoming";
					break;

				case kHostSpool:
					theType = "Host";
					break;

				case kSharedSpool:
					theType = "Shared";
					break;

				case kSystemSpool:
					theType = "System";
					break;

				case kUnknownSpool:
				default:
					theType = "Unknown";
					break;
			}

			spoolObj->SetDirty();
		}
		else
		{
			delete spoolObj;
			spoolObj = NULL;
		}

		(gDB->GetBaseObjectCachePtr())->UnLockTheCache(CMailSpool::GetObjTypeConstant());

		if ( spoolObj != NULL )
		{
			// Display in the Log
		}
	}

	catch( ... )
	{
		(gDB->GetBaseObjectCachePtr())->UnLockTheCache(CMailSpool::GetObjTypeConstant());
	}

	return( spoolObj );

} // Create



//--------------------------------------------------------------------------------------------------
//	* Delete
//
//--------------------------------------------------------------------------------------------------

Boolean CMailSpool::Delete ( CMailSpool *inMailSpool )
{
	Boolean deleted = false;
	OSErr	result;

	try
	{
		if ( inMailSpool != NULL )
		{
			(gDB->GetBaseObjectCachePtr())->LockTheCache(CMailSpool::GetObjTypeConstant());

			inMailSpool->DeleteAllEnvelopeInfos();			// first delete all of the envelope infos
			inMailSpool->DeleteAllSharedSpools();			// next, delete any shared spools
			inMailSpool->RemoveGroupSharedSpools();			// next, delete this spool's shared reference to any group

			result = gDB->RemoveObj( kMailSpoolSignature, inMailSpool->GetMailSpoolID() );				// then remove the mail spool from the db
			deleted = ( result == kNoErr );
			if ( deleted )
			{
				inMailSpool->fMailSpoolData.fMailSpoolID = 0;
			}

			(gDB->GetBaseObjectCachePtr())->UnLockTheCache(CMailSpool::GetObjTypeConstant());
		}
	}

	catch( ... )
	{
		(gDB->GetBaseObjectCachePtr())->UnLockTheCache(CMailSpool::GetObjTypeConstant());
	}

	return( deleted );

} // Delete



//--------------------------------------------------------------------------------------------------
//	* Count
//
//--------------------------------------------------------------------------------------------------

uInt32 CMailSpool::Count ( void )
{
	OSErr	result;
	uInt32	aCount = 0;

	if ( gDB != NULL )
	{
		result = gDB->GetObjectCount( kMailSpoolSignature, aCount );
	}

	return( aCount );
} // Count



//--------------------------------------------------------------------------------------------------
//	* VerifyAll
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::VerifyAll( void )
{
} // VerifyAll

#pragma mark -

//--------------------------------------------------------------------------------------------------
//	* CMailSpool
//
//--------------------------------------------------------------------------------------------------

CMailSpool::CMailSpool ( ObjID inAccountID, uInt32 inMailSpoolType ) :
	CDBMailBaseObject(	&fMailSpoolData.fDBHeader,
				&fMailSpoolData.fDBFooter,
				&fMailSpoolData,
				CMailSpool::GetObjTypeConstant(),
				CMailSpool::GetObjVersConstant(),
				CMailSpool::GetObjSizeConstant() )

{
	fPopLock		= false;
	fRefCount		= 0;
	fSessionStamp	= 0;
	fChangeFlag		= 0;

	fMailSpoolData.fMailSpoolID		= 0;	// this is us (denormalized)
	fMailSpoolData.fParentID		= 0;	// this is our parent (or kRootParent if we are at root)
	fMailSpoolData.fAccountID		= 0;	// this is the account that owns us
	fMailSpoolData.fSpoolType		= 0;
	fMailSpoolData.fSpoolCount		= 0;
	fMailSpoolData.fSpoolSize		= 0;
	fMailSpoolData.fSharedFlags		= 0;
	fMailSpoolData.fLastEnvIDPosted	= 0;	// this is used for duplicate supression, prevents us from having
	fMailSpoolData.fRecentCount		= 0;
	fMailSpoolData.fDeletedCount	= 0;
	fMailSpoolData.fUnseenCount		= 0;
	fMailSpoolData.fRecentMark		= 0;
	fMailSpoolData.fNextUID			= 1;
	fMailSpoolData.fFlags			= 0;
	fMailSpoolData.fACLHeadID		= 0;

	fMailSpoolData.fReserved1		= kReservedConst;
	fMailSpoolData.fReserved2		= kReservedConst;

	::memset(fMailSpoolData.fSpoolName, 0, sizeof(fMailSpoolData.fSpoolName));
	fMailSpoolData.fAccountID = inAccountID;
	fMailSpoolData.fSpoolType = inMailSpoolType;

	this->ChkCompilerStructAlignment();
} // CMailSpool



//--------------------------------------------------------------------------------------------------
//	* ~CMailSpool
//
//--------------------------------------------------------------------------------------------------

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

void	CMailSpool::ChkCompilerStructAlignment	( void )
{
	/*
		this dump was aquired by using the MPW command DumpSYM - TTE from the .xsym file produced
		from a Code Warrior Pro 1 Release Build of the AppleShare IP Mail Server for MacOS version 6.2

		this version of the structure is consider the "reference" standard for all future ASIP Mail Servers.
		If the structure does NOT match these offsets the version of the Mail Server that 
		you are compiling will _NOT_ be compatible with AppleShare IP 6.0, 6.1, or 6.2 (this also effects
		the AppleShare IP Mail Tool, and to a more limited extent the AppleShare IP Mail Admin since some
		of these structures are passed across the wire..)

		If _ANY_ of these Asserts "fire" you've got a backwards compatibility problem that _MUST_ be fixed!!

		this code wasn't put here for my personal amusement, this code was put here from a hard earned lesson
		that simple changes to headers/compilers _WILL_ break this stuff, better to know now than after we
		ship.  Look upon this code as a debugging AIDE, not an impediment.

		Type Name:  CMailSpoolData		TINFO offset: 50442		(TINFO SYM file offset (hex): $12450A)
			RecordOf 
			offset 0 NamedTypeOf fDBHeader TypeDef of "Type ID 248"
			offset 12 NamedTypeOf fMailSpoolID 
			offset 16 NamedTypeOf fParentID unsigned long 
			offset 20 NamedTypeOf fAccountID 
			offset 24 NamedTypeOf fReserved1 unsigned long 
			offset 28 NamedTypeOf fReserved2 
			offset 32 NamedTypeOf fSpoolType unsigned long 
			offset 36 NamedTypeOf fSpoolName 
			offset 292 NamedTypeOf fSpoolCount unsigned long 
			offset 296 NamedTypeOf fSpoolSize unsigned long 
			offset 300 
			offset 304 NamedTypeOf fLastEnvIDPosted unsigned long 
			offset 308 
			offset 312 NamedTypeOf fDeletedCount signed long 
			offset 316 NamedTypeOf fUnseenCount 
			offset 320 NamedTypeOf fRecentMark unsigned long 
			offset 324 NamedTypeOf fNextUID 
			offset 328 NamedTypeOf fFlags unsigned long 
			offset 332 NamedTypeOf fDBFooter 
	*/

	static Boolean	aRunOnceFlag = false;
	if (aRunOnceFlag == false)
	{
		//FileFormatSaftyChk(CMailSpoolData, fDBHeader, 			0);
		//FileFormatSaftyChk(CMailSpoolData, fMailSpoolID,		12);		// this is us (denormalized)
		//FileFormatSaftyChk(CMailSpoolData, fParentID,			16);			// this is our parent (or kRootParent if we are at root)
		//FileFormatSaftyChk(CMailSpoolData, fAccountID,			20);			// this is the account that owns us
		//FileFormatSaftyChk(CMailSpoolData, fReserved1,			24);			// Head pointer to ACL object list
		//FileFormatSaftyChk(CMailSpoolData, fReserved2,			28);
		//FileFormatSaftyChk(CMailSpoolData, fSpoolType,			32);
		//FileFormatSaftyChk(CMailSpoolData, fSpoolName[0],		36);
		//FileFormatSaftyChk(CMailSpoolData, fSpoolCount,			292);
		//FileFormatSaftyChk(CMailSpoolData, fSpoolSize, 			296);
		//FileFormatSaftyChk(CMailSpoolData, fSharedFlags,		300);		// Now used for Shared folder rights ( was fChangeCount )
		//FileFormatSaftyChk(CMailSpoolData, fLastEnvIDPosted,	304);	// this is used for duplicate supression, prevents
		//FileFormatSaftyChk(CMailSpoolData, fRecentCount, 		308);
		//FileFormatSaftyChk(CMailSpoolData, fDeletedCount, 		312);
		//FileFormatSaftyChk(CMailSpoolData, fUnseenCount,		316);
		//FileFormatSaftyChk(CMailSpoolData, fRecentMark, 		320);
		//FileFormatSaftyChk(CMailSpoolData, fNextUID, 			324);
		//FileFormatSaftyChk(CMailSpoolData, fFlags, 				328);
		//FileFormatSaftyChk(CMailSpoolData, fDBFooter, 			332);
//		this->ReportBackwardCompatibility(sizeof(CMailSpoolData), 336, "CMailSpoolData" , "SIZEOF()");
//		this->ReportBackwardCompatibility(kMailSpoolDataSize, 336, "CMailSpoolData" , "kMailSpoolDataSize");
	}

	aRunOnceFlag = true;
}
#pragma mark -



//--------------------------------------------------------------------------------------------------
//	* SetDirty
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::SetDirty	( void )
{
	if ( ( this != NULL ) && ( this->GetMailSpoolID() != 0 ) )
	{
		this->setDirty();
	}
} // SetDirty



//--------------------------------------------------------------------------------------------------
//	* GetMailSpoolID
//
//--------------------------------------------------------------------------------------------------

ObjID CMailSpool::GetMailSpoolID ( void )
{
	return( fMailSpoolData.fMailSpoolID );
} // GetMailSpoolID



//--------------------------------------------------------------------------------------------------
//	* GetMailSpoolID
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::SetMailSpoolID ( ObjID inSpoolID )
{
	if ( fMailSpoolData.fMailSpoolID != inSpoolID )
	{
		fMailSpoolData.fMailSpoolID = inSpoolID;
		this->SetDirty();
	}
} // GetMailSpoolID



//--------------------------------------------------------------------------------------------------
//	* GetParentID
//
//--------------------------------------------------------------------------------------------------

ObjID CMailSpool::GetParentID ( void )
{
	return( fMailSpoolData.fParentID );
} // GetParentID



//--------------------------------------------------------------------------------------------------
//	* SetParentID
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::SetParentID ( ObjID inParentID )
{
	if ( fMailSpoolData.fParentID != inParentID )
	{
		fMailSpoolData.fParentID = inParentID;
		this->SetDirty();
	}
} // SetParentID



//--------------------------------------------------------------------------------------------------
//	* GetAccountID
//
//--------------------------------------------------------------------------------------------------

ObjID CMailSpool::GetAccountID ( void )
{
	return( fMailSpoolData.fAccountID );
} // GetAccountID



//--------------------------------------------------------------------------------------------------
//	* SetAccountID
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::SetAccountID ( ObjID inAccountID )
{
	// the account ID is used as a CMailDatabase 2nd-ID object.  We need to flush
	// this through to the mail db immediately so that any iteration that is
	// going on will reflect the proper list iteration...
	// if you don't understand why this is important you don't understand the
	// Mail server's DB & our caching code and you shouldn't be changing it.

	try
	{
			if ( fMailSpoolData.fAccountID != inAccountID )
		{
			(gDB->GetBaseObjectCachePtr())->LockTheCache(CMailSpool::GetObjTypeConstant());
	
			fMailSpoolData.fAccountID = inAccountID;
			this->SetDirty();
			this->setDirty(true);	// call the CDBObject base class function, which will force a
									// write through to the Mail DB
	
			(gDB->GetBaseObjectCachePtr())->UnLockTheCache(CMailSpool::GetObjTypeConstant());
		}
	}

	catch ( ... )
	{
		(gDB->GetBaseObjectCachePtr())->UnLockTheCache(CMailSpool::GetObjTypeConstant());
	}

} // SetAccountID



//--------------------------------------------------------------------------------------------------
//	* GetLastEnvIDPosted
//
//--------------------------------------------------------------------------------------------------

ObjID CMailSpool::GetLastEnvIDPosted ( void )
{
	return( fMailSpoolData.fLastEnvIDPosted );
} // GetLastEnvIDPosted



//--------------------------------------------------------------------------------------------------
//	* SetLastEnvIDPosted
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::SetLastEnvIDPosted ( ObjID inEnvelopeID )
{
	if ( fMailSpoolData.fLastEnvIDPosted != inEnvelopeID )
	{
		fMailSpoolData.fLastEnvIDPosted = inEnvelopeID;
		this->SetDirty();
	}
} // SetLastEnvIDPosted


#pragma mark -



//--------------------------------------------------------------------------------------------------
//	* GetMailSpoolType
//
//--------------------------------------------------------------------------------------------------

OSType CMailSpool::GetMailSpoolType ( void )
{
	return( fMailSpoolData.fSpoolType );
} // GetMailSpoolType



//--------------------------------------------------------------------------------------------------
//	* SetMailSpoolType
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::SetMailSpoolType ( OSType inType )
{
	if ( fMailSpoolData.fSpoolType != inType )
	{
		fMailSpoolData.fSpoolType = inType;
		this->SetDirty();
	}
} // SetMailSpoolType



//--------------------------------------------------------------------------------------------------
//	* GetMailSpoolName
//
//--------------------------------------------------------------------------------------------------

const char* CMailSpool::GetMailSpoolName ( void )
{
	return( fMailSpoolData.fSpoolName );
} // GetMailSpoolName



//--------------------------------------------------------------------------------------------------
//	* SetMailSpoolName
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::SetMailSpoolName ( const char* inName )
{

	if (CUtils::Stricmp(fMailSpoolData.fSpoolName, inName) != 0)
	{
		CUtils::Strncpy ( fMailSpoolData.fSpoolName, (char *) inName, kMaxSpoolNameLength );
		this->SetDirty();
	}
} // SetMailSpoolName



//--------------------------------------------------------------------------------------------------
//	* IncrementSpoolCount
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::IncrementSpoolCount ( void )
{
	if ( this != NULL )
	{
		fMailSpoolData.fSpoolCount++;
		this->SetDirty();

		this->ReleaseObjectLock(true);
	}
} // IncrementSpoolCount



//--------------------------------------------------------------------------------------------------
//	* DecrementSpoolCount
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::DecrementSpoolCount ( void )
{

	if ( this != NULL )
	{
		if ( fMailSpoolData.fSpoolCount != 0 )
		{
			fMailSpoolData.fSpoolCount--;
			this->SetDirty();
		}
		else
		{
		}

		this->ReleaseObjectLock(true);
	}
} // DecrementSpoolCount



//--------------------------------------------------------------------------------------------------
//	* IncrementSpoolSize
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::IncrementSpoolSize ( uInt32 inAmount )
{

	if ( this != NULL )
	{
		fMailSpoolData.fSpoolSize += inAmount;
		this->SetDirty();
		this->ReleaseObjectLock(true);
	}
} // IncrementSpoolSize



//--------------------------------------------------------------------------------------------------
//	* DecrementSpoolSize
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::DecrementSpoolSize ( uInt32 inAmount )
{

	if ( this != NULL )
	{
		if ( inAmount <= fMailSpoolData.fSpoolSize )
		{
			fMailSpoolData.fSpoolSize -= inAmount;
			this->SetDirty();
		}
		else
		{
			// this is due to the message being posted before the 822 headers were sanitized.
			fMailSpoolData.fSpoolSize = 0;
		}

		this->ReleaseObjectLock(true);
	}
} // DecrementSpoolSize



//--------------------------------------------------------------------------------------------------
//	* GetSpoolCount
//
//--------------------------------------------------------------------------------------------------

uInt32 CMailSpool::GetSpoolCount ( void )
{
	return( fMailSpoolData.fSpoolCount );
} // GetSpoolCount



//--------------------------------------------------------------------------------------------------
//	* GetSpoolSize
//
//--------------------------------------------------------------------------------------------------

uInt32 CMailSpool::GetSpoolSize ( void )
{
	return( fMailSpoolData.fSpoolSize );
} // GetSpoolSize



//--------------------------------------------------------------------------------------------------
//	* CalcRecentCount
//
//--------------------------------------------------------------------------------------------------

uInt32 CMailSpool::CalcRecentCount ( ObjID inRecentMark )
{
	uInt32			count		= 0;
	SDBIterator*	iterator	= nil;
	ObjID			objID;

	try
	{
		ThrowIfNULL_( this );

		iterator = this->GetEnvelopeInfoIterator();
		ThrowIfNULL_( iterator );

		while ( gDB->NextObject( iterator, objID ) == kNoErr )
		{
			if ( objID >= inRecentMark )
			{
				count++;
			}
			else
			{
				break;
			}
		}
	}
	catch( ... )
	{
	}

	if ( ( this != nil ) && ( iterator != nil ) )
	{
		this->ReleaseEnvelopeInfoIterator ( iterator );
	}

	return( count );

} // CalcRecentCount


//--------------------------------------------------------------------------------------------------
//	* GetUnseenCount
//
//--------------------------------------------------------------------------------------------------

uInt32 CMailSpool::GetUnseenCount ( void )
{
	return( fMailSpoolData.fUnseenCount );
} // GetUnseenCount


//--------------------------------------------------------------------------------------------------
//	* SetUnseenCount
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::SetUnseenCount ( uInt32 inCount )
{
	if ( fMailSpoolData.fUnseenCount != inCount )
	{
		fMailSpoolData.fUnseenCount = inCount;
		this->SetDirty();
	}
} // SetUnseenCount


//--------------------------------------------------------------------------------------------------
//	* IncrementUnseenCount
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::IncrementUnseenCount ( void )
{
	fMailSpoolData.fUnseenCount++;
	this->SetDirty();
} // IncrementUnseenCount


//--------------------------------------------------------------------------------------------------
//	* DecrementUnseenCount
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::DecrementUnseenCount ( void )
{
	if ( fMailSpoolData.fUnseenCount >= 0 )
	{
		fMailSpoolData.fUnseenCount--;
		this->SetDirty();
	}
} // DecrementUnseenCount


//--------------------------------------------------------------------------------------------------
//	* SetTOCMark
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::SetTOCMark ( ObjID inTocMark )
{
	if ( fMailSpoolData.fRecentCount != inTocMark )
	{
		fMailSpoolData.fRecentCount = inTocMark;
		this->SetDirty();
	}
} // SetTOCMark



//--------------------------------------------------------------------------------------------------
//	* GetTOCMark
//
//--------------------------------------------------------------------------------------------------

ObjID CMailSpool::GetTOCMark ( void )
{
	return( (ObjID)fMailSpoolData.fRecentCount );
} // GetTOCMark



//--------------------------------------------------------------------------------------------------
//	* GetDeletedCount
//
//--------------------------------------------------------------------------------------------------

uInt32 CMailSpool::GetDeletedCount ( void )
{
	return( fMailSpoolData.fDeletedCount );
} // GetDeletedCount



//--------------------------------------------------------------------------------------------------
//	* SetDeletedCount
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::SetDeletedCount ( uInt32 inCount )
{
	if ( this != NULL )
	{
		if ( fMailSpoolData.fDeletedCount != inCount )
		{
			if ( inCount < 0 )
			{
				fMailSpoolData.fDeletedCount = 0;
			}
			else if ( inCount > fMailSpoolData.fSpoolCount )
			{
				fMailSpoolData.fDeletedCount = fMailSpoolData.fSpoolCount;
			}
			else
			{
				fMailSpoolData.fDeletedCount = inCount;
			}
			this->SetDirty();
		}

		this->ReleaseObjectLock(true);
	}
} // SetDeletedCount



//--------------------------------------------------------------------------------------------------
//	* IncrementDeletedCount
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::IncrementDeletedCount ( void )
{
	if ( this != NULL )
	{
		fMailSpoolData.fDeletedCount++;
		this->SetDirty();
		this->ReleaseObjectLock(true);
	}
} // IncrementDeletedCount



//--------------------------------------------------------------------------------------------------
//	* DecrementDeletedCount
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::DecrementDeletedCount ( void )
{
	if ( this != NULL )
	{
		if ( fMailSpoolData.fDeletedCount > 0 )
		{
			fMailSpoolData.fDeletedCount--;
			this->SetDirty();
		}

		this->ReleaseObjectLock(true);
	}
} // DecrementDeletedCount



//--------------------------------------------------------------------------------------------------
//	* IncrementRefCount
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::IncrementRefCount ( void )
{
	if ( this != NULL )
	{
		fRefCount++;
		this->ReleaseObjectLock(true);
	}
} // IncrementRefCount



//--------------------------------------------------------------------------------------------------
//	* DecrementRefCount
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::DecrementRefCount ( void )
{
	if ( this != NULL )
	{
		if ( fRefCount > 0 )
		{
			fRefCount--;
		}
		this->ReleaseObjectLock(true);
	}
} // DecrementRefCount



//--------------------------------------------------------------------------------------------------
//	* GetRefCount
//
//--------------------------------------------------------------------------------------------------

sInt16 CMailSpool::GetRefCount ( void )
{
	return( fRefCount );
} // GetRefCount



//--------------------------------------------------------------------------------------------------
//	* ResetSpoolCounts
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::ResetSpoolCounts ( void )
{
	if ( this != NULL )
	{
		fMailSpoolData.fSpoolCount		= 0;
		fMailSpoolData.fSpoolSize		= 0;
		fMailSpoolData.fDeletedCount	= 0;
		fMailSpoolData.fNextUID			= 1;

		this->ReleaseObjectLock(true);
	}
} // ResetSpoolCounts



//--------------------------------------------------------------------------------------------------
//	* GetNextUID
//
//--------------------------------------------------------------------------------------------------

uInt32 CMailSpool::GetNextUID ( void )
{
	return( fMailSpoolData.fNextUID );
} // GetNextUID



//--------------------------------------------------------------------------------------------------
//	* SetNextUID
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::SetNextUID ( uInt32 inNextUID )
{
	if ( this != NULL )
	{
		if ( fMailSpoolData.fNextUID < inNextUID )
		{
			fMailSpoolData.fNextUID = inNextUID;
			this->SetDirty();
		}

		this->ReleaseObjectLock(true);
	}
} // SetNextUID



//--------------------------------------------------------------------------------------------------
//	* GetSpoolStamp
//
//--------------------------------------------------------------------------------------------------

uInt32 CMailSpool::GetSpoolStamp ( Boolean inReset )
{
	if ( inReset == true )
	{
		SetSpoolStamp();
	}

	return( fSessionStamp );

} // GetSpoolStamp



//--------------------------------------------------------------------------------------------------
//	* SetSpoolStamp
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::SetSpoolStamp ( void )
{
	fSessionStamp = ::time( nil );
} // SetSpoolStamp



//--------------------------------------------------------------------------------------------------
//	* GetChangeFlag
//
//--------------------------------------------------------------------------------------------------

uInt32 CMailSpool::GetChangeFlag ( Boolean inReset )
{
	if ( inReset == true )
	{
		SetChangeFlag();
	}

	return( fChangeFlag );

} // GetChangeFlag



//--------------------------------------------------------------------------------------------------
//	* SetChangeFlag
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::SetChangeFlag ( void )
{
	fChangeFlag = ::time( nil );
} // SetChangeFlag



//--------------------------------------------------------------------------------------------------
//	* GetRecentMark
//
//--------------------------------------------------------------------------------------------------

ObjID CMailSpool::GetRecentMark ( Boolean inReset )
{
	if ( this != NULL )
	{
		ObjID	outRecentMark	= fMailSpoolData.fRecentMark;

		if ( inReset == true )
		{
			if ( fMailSpoolData.fRecentMark != gDB->GetCurrentObjID() )
			{
				fMailSpoolData.fRecentMark = gDB->GetCurrentObjID();
				this->SetDirty();
			}
		}

		this->ReleaseObjectLock(true);
		return( outRecentMark );
	}

	return (0);
} // GetRecentMark



//--------------------------------------------------------------------------------------------------
//	* SetFlags
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::SetFlags ( uInt32 inFlags )
{
	if ( this != NULL )
	{
		fMailSpoolData.fFlags = inFlags;
		this->SetDirty();
		this->ReleaseObjectLock(true);
	}
} // SetFlags



//--------------------------------------------------------------------------------------------------
//	* GetFlags
//
//--------------------------------------------------------------------------------------------------

uInt32 CMailSpool::GetFlags ( void )
{
	return( fMailSpoolData.fFlags );
} // GetFlags



//--------------------------------------------------------------------------------------------------
//	* VerifyData
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::VerifyData ( void )
{
} // VerifyData

#pragma mark -



//--------------------------------------------------------------------------------------------------
//	* Post
//
//--------------------------------------------------------------------------------------------------

Boolean CMailSpool::Post ( ObjID inEnvelopeID, DSMailUser *inUser, Boolean inDoSuppress, ObjID &outEnvInfoID )
{
	CEnvelopeInfo  *pEnvInfoObj		= nil;
	CEnvelope	   *pEnvObj			= nil;
//	CString			csSrcPath( 128 );
//	CString			csDestPath( 128 );

	try
	{
		if (  this != NULL  )
		{
			if ( inDoSuppress == true )
			{
				// Check to see if it already exists in this spool, suppress duplicates here( POP3 only )
				if ( inEnvelopeID == this->GetLastEnvIDPosted() )
				{
					this->ReleaseObjectLock( true );
					return( true );
				}

				this->SetLastEnvIDPosted( inEnvelopeID );
			}

			// Next find the envelope
			pEnvObj = CEnvelope::FindByID( inEnvelopeID );
			ThrowIfNULL_( pEnvObj );

			// Create a new CEnvelopeInfo as a reference to this envelope
			pEnvInfoObj = CEnvelopeInfo::Create( this->GetMailSpoolID(), inEnvelopeID, pEnvObj->GetMessageSize() );
			ThrowIfNULL_( pEnvInfoObj );

//			csSrcPath.Set( pEnvObj->GetDataFilePath() );
//			csDestPath.Set( inUser->GetMailLocation() );

//			int symlink(const char *name1, const char *name2)

			// Update our cached values
			IncrementSpoolCount();							//	fSpoolCount++
			IncrementSpoolSize( pEnvObj->GetMessageSize() );	//	fSpoolSize += pEnvObj->GetMessageSize()
			IncrementUnseenCount();							//	fUnseenCount++
															//	this->SetDirty();

			if ( this->GetMailSpoolType() == kHostSpool )
			{
				pEnvObj->AddReference( CEnvelope::kHostReference );
			}

			// This now affects all spools because of the Admin port
			if ( pEnvObj->GetViaCode() != CEnvelope::kViaIMAP )
			{
				pEnvInfoObj->SetFlags( pEnvInfoObj->GetFlags() );
			}

//			SetNextUID( pEnvInfoObj->GetEnvelopeInfoID() + 1 );
			pEnvInfoObj->SetMessageUID( this->GetNextUID() );
			SetNextUID( this->GetNextUID() + 1 );

			outEnvInfoID = pEnvInfoObj->GetEnvelopeInfoID();

			// Update envelope's spool reference count
			pEnvObj->AddReference( CEnvelope::kSpoolReference );

			pEnvObj->Done( pEnvObj );
			pEnvInfoObj->Done( pEnvInfoObj );

			this->SetDirty();

			this->ReleaseObjectLock(true);
			return( true );
		}
	}

	catch( ... )
	{
		if ( pEnvObj != nil )
		{
			pEnvObj->Done( pEnvObj );
			pEnvObj = nil;
		}

		if ( pEnvInfoObj != nil )
		{
			pEnvInfoObj->Done( pEnvInfoObj );
			pEnvInfoObj = nil;
		}

		this->ReleaseObjectLock(true);

		return( false );
	}

	return( false );

} // Post



//--------------------------------------------------------------------------------------------------
//	* Remove
//
//--------------------------------------------------------------------------------------------------

Boolean CMailSpool::Remove ( CEnvelopeInfo *inEnvInfo )
{
	CEnvelopeInfo*	envInfoObj	= NULL;
	CEnvelope*		envObj		= NULL;
	CMailSpool*		outSpoolObj	= NULL;


	try
	{
		if ( this != NULL )
		{
			envInfoObj = inEnvInfo;

			if ( envInfoObj == NULL )	// it wasn't found, this is an error
			{
				this->ReleaseObjectLock(true);
				return( false );
			}

			envInfoObj->Use();

			if ( inEnvInfo->GetEnvelopeID() == this->GetLastEnvIDPosted() )	// hmmm, we should clear the lastID Posted if that's the actual message we're deleting.
			{
				this->SetLastEnvIDPosted( 0 );
			}

			// Next find the envelope
			envObj = CEnvelope::FindByID( inEnvInfo->GetEnvelopeID() );
			if (envObj != NULL)
			{
				if ( this->GetMailSpoolType() == kHostSpool )
				{
					envObj->RemoveReference( CEnvelope::kHostReference );
				}

				// Update envelope's reference count
				envObj->RemoveReference( CEnvelope::kSpoolReference );
				DecrementSpoolSize( envObj->GetMessageSize() );			//	fMailSpoolData.fSpoolSize -= envObj->GetMessageSize();
																		//	this->SetDirty();
				envObj->Done( envObj );
			}
			else
			{
				DecrementSpoolSize( envInfoObj->GetMessageSize(false) );	//	fMailSpoolData.fSpoolSize -= envObj->GetMessageSize();
																			//	this->SetDirty();
			}

			// Update our cached values
			DecrementSpoolCount();									//	fMailSpoolData.fSpoolCount--;

			if ( envInfoObj->GetFlags() & CEnvelopeInfo::kIMAP4Deleted )
			{
				this->DecrementDeletedCount();
			}

			if ( !(envInfoObj->GetFlags() & CEnvelopeInfo::kIMAP4Seen) )
			{
				this->DecrementUnseenCount();
			}

			// Now remove the envelope info reference from the database
			CEnvelopeInfo::Delete( envInfoObj );
			envInfoObj->Done( envInfoObj );

			this->SetDirty();
			this->ReleaseObjectLock( true );

			return( true );
		}
	}

	catch( ... )
	{
		if ( outSpoolObj != nil )
		{
			outSpoolObj->Done( outSpoolObj );
			outSpoolObj = nil;
		}

		if ( envObj != nil )
		{
			envObj->Done( envObj );
			envObj = nil;
		}

		if ( envInfoObj != nil )
		{
			envInfoObj->Done( envInfoObj );
			envInfoObj = nil;
		}

		this->ReleaseObjectLock(true);
		return( false );
	}

	return (false);
} // Remove

#pragma mark -



//--------------------------------------------------------------------------------------------------
//	* GetEnvelopeInfoIterator
//
//--------------------------------------------------------------------------------------------------

SDBIterator* CMailSpool::GetEnvelopeInfoIterator ( void )
{
	OSErr	result;
	SDBIterator	*aSDBIterator = new SDBIterator(gDB);

	if ( aSDBIterator != NULL )
	{
		result = gDB->CreateIterator( kEnvelopeInfoSignature, aSDBIterator, this->GetMailSpoolID() );
		if ( result != kNoErr )
		{
			delete aSDBIterator;
			aSDBIterator = NULL;
		}
	}

	return( aSDBIterator );
} // GetEnvelopeInfoIterator



//--------------------------------------------------------------------------------------------------
//	* ReleaseEnvelopeInfoIterator
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::ReleaseEnvelopeInfoIterator ( SDBIterator* &inIterator )
{
	OSErr aResult = kNoErr;
	if ( inIterator != NULL )
	{
		aResult = gDB->ReleaseIterator( inIterator );
		if (aResult != kNoErr)
		{
		}

		delete inIterator;
		inIterator = NULL;
	}
} // ReleaseEnvelopeInfoIterator



//--------------------------------------------------------------------------------------------------
//	* DeleteAllEnvelopeInfos
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::DeleteAllEnvelopeInfos ( void )
{
	SDBIterator*	theIterator = NULL;
	CEnvelopeInfo	*aEnvInfo = NULL;
	Boolean			successful = false;
	ObjID			anEnvInfoID;

	try
	{
		ThrowIfNULL_( this );

		theIterator = this->GetEnvelopeInfoIterator();
		ThrowIfNULL_( theIterator );

		while ( gDB->GetCurObject( theIterator, anEnvInfoID ) == kNoErr )
		{
			aEnvInfo = CEnvelopeInfo::FindByID(anEnvInfoID);
			if (aEnvInfo != NULL)
			{
				this->Remove(aEnvInfo);
				aEnvInfo->Done(aEnvInfo);
			}
		}

	}

	catch( ... )
	{
	}

	if ( ( this != NULL ) && ( theIterator != NULL ) )
	{
		this->ReleaseEnvelopeInfoIterator ( theIterator );
	}
} // DeleteAllEnvelopeInfos



//--------------------------------------------------------------------------------------------------
//	* DeleteAllSharedSpools
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::DeleteAllSharedSpools ( void )
{
	ObjID			objID		= 0;
	CACLObject	   *aclObj		= nil;

	if ( !(this->GetFlags() & kSharedFlag) )
	{
		objID = this->GetACLHeadID();
		aclObj = (CACLObject *)CACLObject::FindByID( objID );
		while ( aclObj != nil )
		{
			aclObj->DeleteAllSpools();

			objID = aclObj->GetNextObjectID();

			CACLObject::Delete( aclObj );
			aclObj->Done( aclObj );

			aclObj = (CACLObject *)CACLObject::FindByID( objID );
		}
	}
} // DeleteAllSharedSpools



//--------------------------------------------------------------------------------------------------
//	* RemoveGroupSharedSpools
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::RemoveGroupSharedSpools ( void )
{
	OSErr			result;
	Boolean			removed		= false;
	Boolean			deleted		= false;
	ObjID			objID		= 0;
	CACLObject	   *aclObj		= nil;
	CMailSpool	   *spoolObj	= nil;
	SDBIterator		iterator(gDB);

	if ( gRootObj != nil )
	{
		spoolObj = CMailSpool::FindByID( gRootObj->GetAnyoneObjID() );
		if ( spoolObj != nil )
		{
			aclObj = (CACLObject *)CACLObject::FindByID( spoolObj->GetACLHeadID() );
			while ( aclObj != nil )
			{
				removed |= aclObj->RemoveSpoolRef( this->GetMailSpoolID() );
				if ( removed == true )
				{
					gSyncFoldersStamp = ::time( nil );
				}

				objID = aclObj->GetNextObjectID();

				aclObj->Done( aclObj );

				aclObj = (CACLObject *)CACLObject::FindByID( objID );
			}
			spoolObj->Done( spoolObj );

			if ( removed == true )
			{
				result = gDB->CreateIterator( kMailSpoolSignature, &iterator );
				if ( result == kNoErr )
				{
					gDB->GetCurObject( &iterator, objID );
					while ( objID != 0 )
					{
						removed	= false;
						spoolObj = CMailSpool::FindByID( objID );
						if ( spoolObj != nil )
						{
							if ( (spoolObj->GetFlags() & kSharedFlag) && (spoolObj->GetACLHeadID() == this->GetMailSpoolID()) )
							{
								(gDB->GetBaseObjectCachePtr())->LockTheCache(CMailSpool::GetObjTypeConstant());

								result = gDB->RemoveObj( kMailSpoolSignature, spoolObj->GetMailSpoolID() );				// then remove the mail spool from the db
								deleted = ( result == kNoErr );
								if ( deleted )
								{
									spoolObj->fMailSpoolData.fMailSpoolID = 0;
								}
								removed = true;

								(gDB->GetBaseObjectCachePtr())->UnLockTheCache(CMailSpool::GetObjTypeConstant());
							}
							spoolObj->Done( spoolObj );
							objID = 0;

							if ( removed == true )
							{
								if ( gDB->GetCurObject( &iterator, objID ) != kNoErr )
								{
									objID = 0;
								}
							}
							else
							{
								if ( gDB->NextObject( &iterator, objID ) != kNoErr )
								{
									objID = 0;
								}
							}
						}
					}
				}
				result = gDB->ReleaseIterator( &iterator );
			}
		}
	}
} // RemoveGroupSharedSpools



//--------------------------------------------------------------------------------------------------
//	* MoveEnvelopes
//
//		- Move emvelope infos from this spool to the target spool passed in
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::MoveEnvelopes ( CMailSpool *inTargetSpool )
{
	SDBIterator	   *iterator	= nil;
	Boolean			successful	= false;
	ObjID			envInfoID;
	ObjID			targetID	= inTargetSpool->GetMailSpoolID();
	CEnvelopeInfo  *envInfoObj	= nil;

	try
	{
		iterator = this->GetEnvelopeInfoIterator();
		ThrowIfNULL_( iterator );

		gDB->ResetIterator( iterator, envInfoID );

		while ( gDB->GetCurObject( iterator, envInfoID ) == kNoErr )
		{
			envInfoObj = CEnvelopeInfo::FindByID( envInfoID );
			if ( envInfoObj != nil )
			{
				envInfoObj->SetMailSpoolID( targetID );

				this->DecrementSpoolSize( envInfoObj->GetMsgSize() );
				inTargetSpool->IncrementSpoolSize( envInfoObj->GetMsgSize() );

				this->DecrementSpoolCount();
				inTargetSpool->IncrementSpoolCount();

				// If deleted
				if ( (envInfoObj->GetFlags() & CEnvelopeInfo::kIMAP4Deleted) != 0 )
				{
					this->DecrementDeletedCount();
					inTargetSpool->IncrementDeletedCount();
				}

				// If not seen
				if ( !(envInfoObj->GetFlags() & CEnvelopeInfo::kIMAP4Seen) )
				{
					this->DecrementUnseenCount();
					inTargetSpool->IncrementUnseenCount();
				}

				envInfoObj->SetMessageUID( inTargetSpool->GetNextUID() );
				inTargetSpool->SetNextUID( inTargetSpool->GetNextUID() + 1 );

//				inTargetSpool->SetNextUID( envInfoID );

				gDB->ResetIterator( iterator, envInfoID );

				envInfoObj->Done( envInfoObj );
			}
		}
	}

	catch( ... )
	{
	}

	if ( ( this != NULL ) && ( iterator != NULL ) )
	{
		this->ReleaseEnvelopeInfoIterator( iterator );
	}
} // MoveEnvelopes



//--------------------------------------------------------------------------------------------------
//	* CopyEnvelopInfos ()
//
//		- copy emvelope infos from this spool to the target spool passed in
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::CopyEnvelopInfos ( CMailSpool *inTargetSpool, DSMailUser *inUser )
{
	ObjID			envInfoID;
	ObjID			notUsed		= 0;
	SDBIterator	   *iterator	= nil;
	CEnvelopeInfo  *envInfoObj	= nil;

	try
	{
		iterator = this->GetEnvelopeInfoIterator();
		ThrowIfNULL_( iterator );

		while ( gDB->NextObject( iterator, envInfoID ) == kNoErr )
		{
			envInfoObj = CEnvelopeInfo::FindByID( envInfoID );
			if ( envInfoObj != nil )
			{
				inTargetSpool->Post( envInfoObj->GetEnvelopeID(), inUser, false, notUsed );
				envInfoObj->Done( envInfoObj );
			}
		}
	}

	catch( ... )
	{
	}

	if ( (this != nil ) && (iterator != nil) )
	{
		this->ReleaseEnvelopeInfoIterator( iterator );
	}
} // CopyEnvelopInfos



#pragma mark -
#pragma mark * ACL

//--------------------------------------------------------------------------------------------------
//	* GetACLHeadID
//
//--------------------------------------------------------------------------------------------------

uInt32 CMailSpool::GetACLHeadID ( void )
{
	return( fMailSpoolData.fACLHeadID );
} // GetACLHeadID


//--------------------------------------------------------------------------------------------------
//	* SetACLHeadID
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::SetACLHeadID ( uInt32 inNewValue )
{
	if ( fMailSpoolData.fACLHeadID != inNewValue )
	{
		fMailSpoolData.fACLHeadID = inNewValue;
		this->SetDirty();
	}
} // SetACLHeadID


//--------------------------------------------------------------------------------------------------
//	* GetSharedID
//
//--------------------------------------------------------------------------------------------------

uInt32 CMailSpool::GetSharedID ( void )
{
	return( fMailSpoolData.fSharedID );
} // GetSharedID


//--------------------------------------------------------------------------------------------------
//	* SetSharedID
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::SetSharedID ( uInt32 inNewValue )
{
	if ( fMailSpoolData.fSharedID != inNewValue )
	{
		fMailSpoolData.fSharedID = inNewValue;
		this->SetDirty();
	}
} // SetSharedID


//--------------------------------------------------------------------------------------------------
//	* GetACLRights
//
//--------------------------------------------------------------------------------------------------

uInt32 CMailSpool::GetACLRights ( void )
{
	uInt32	result = 0;

	if ( fMailSpoolData.fFlags & kSharedFlag )
	{
		result = fMailSpoolData.fSharedFlags;
	}
	else
	{
		result = kACLAllRights;
	}

	return( result );

} // GetACLRights



//--------------------------------------------------------------------------------------------------
//	* SetACLRights
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::SetACLRights ( uInt32 inNewRights )
{
	if ( fMailSpoolData.fSharedFlags != inNewRights )
	{
		if ( !(inNewRights & kACLCreate) )
		{
			fMailSpoolData.fFlags |= kNoInferiorsFlag;
		}
		else
		{
			fMailSpoolData.fFlags &= ~kNoInferiorsFlag;
		}

		fMailSpoolData.fSharedFlags = inNewRights;
		this->SetDirty();
	}
} // SetACLRights




//--------------------------------------------------------------------------------------------------
//	* IsAdmin
//
//--------------------------------------------------------------------------------------------------

Boolean CMailSpool::IsAdmin ( void )
{
	Boolean		result = false;

	if ( !(fMailSpoolData.fFlags & kSharedFlag) )
	{
		// Always true if folder ins't shared
		result = true;
	}
	else
	{
		// Is the "Admin" right set
		if ( fMailSpoolData.fSharedFlags & kACLAdmin )
		{
			result = true;
		}
	}
	return( result );

} // IsAdmin



//--------------------------------------------------------------------------------------------------
//	* GetNextACLObj
//
//--------------------------------------------------------------------------------------------------

Boolean CMailSpool::GetNextACLObj ( CACLObject **inObjPtr, Boolean inCreate )
{
	Boolean			result		= false;
	ObjID			objID		= 0;
	CACLObject	   *objPtr		= nil;

	if ( *inObjPtr == nil )
	{
		objID = this->GetACLHeadID();
	}
	else
	{
		objID = (*inObjPtr)->GetNextObjectID();
	}

	objPtr = (CACLObject *)CExpansion::FindByID( objID );

	if ( (objPtr == nil) && (inCreate == true) )
	{
		objPtr = (CACLObject *)CExpansion::Create( fMailSpoolData.fMailSpoolID, sizeof( SACLInfo ) );
		if ( objPtr != nil )
		{
			objID = this->GetACLHeadID();
			objPtr->SetNextObjectID( objID );
			objID = objPtr->GetMyObjectID();
			this->SetACLHeadID( objID );
		}
	}

	(*inObjPtr)->Done( *inObjPtr );
	*inObjPtr = objPtr;

	if ( *inObjPtr != nil )
	{
		result = true;
	}

	return( result );

} // GetNextACLObj



//--------------------------------------------------------------------------------------------------
//	* DeleteACL
//
//--------------------------------------------------------------------------------------------------

Boolean CMailSpool::DeleteACL ( ObjID inUserID, ObjID inShrdSpoolID )
{
	Boolean			success			= false;
	uInt32			flags			= 0;
	ObjID			prevACLObjID	= 0;
	CACLObject	   *aclObj			= nil;
	CACLObject	   *prevAclObj		= nil;

	while ( (!success) && (this->GetNextACLObj( &aclObj ) == true) )
	{
		success = aclObj->DeleteACLInfo( inUserID, inShrdSpoolID );
		if ( success == true )
		{
			if ( aclObj->GetItemCount() == 0 )
			{
				// Are we at the head of the list
				if ( this->GetACLHeadID() == aclObj->GetMyObjectID() )
				{
					if ( (aclObj->GetNextObjectID() != 0) && (aclObj->GetNextObjectID() != 0xF0F0F0F0) )
					{
						this->SetACLHeadID( aclObj->GetNextObjectID() );
						CACLObject::Delete( aclObj );
					}
					else
					{
						flags = this->GetFlags();
						flags &= ~CMailSpool::kPublishedFlag;
						this->SetFlags( flags );
					}
				}
				else
				{
					// We must be in the middle or at the end
					prevAclObj = (CACLObject *)CACLObject::FindByID( prevACLObjID );
					if ( prevAclObj != nil )
					{
						prevAclObj->SetNextObjectID( aclObj->GetNextObjectID() );
						CACLObject::Delete( aclObj );
						prevAclObj->Done( prevAclObj );
					}
				}
			}
		}
		prevACLObjID = aclObj->GetMyObjectID();
	}
	aclObj->Done( aclObj );

	return( success );

} // DeleteACL



//--------------------------------------------------------------------------------------------------
//	* SetACL
//
//--------------------------------------------------------------------------------------------------

Boolean CMailSpool::SetACL ( ObjID inUserID, ObjID inShrdSpoolID, uInt32 inRights )
{
	Boolean			result		= false;
	Boolean			success		= false;
	uInt32			flags		= 0;
	CACLObject	   *aclObj		= nil;

	// Set the existing ACL data if any
	while ( (!success) && (this->GetNextACLObj( &aclObj ) == true) )
	{
		success = aclObj->SetExistingACLInfo( inUserID, inShrdSpoolID, inRights );
	}
	aclObj->Done( aclObj );

	// Set new ACL data field
	while ( (!success) && (this->GetNextACLObj( &aclObj, true ) == true) )
	{
		success = aclObj->SetNewACLInfo( inUserID, inShrdSpoolID, inRights );
		if ( success == true )
		{
			result = true;
		}
	}

	if ( success == true )
	{
		flags = this->GetFlags();
		flags |= CMailSpool::kPublishedFlag;
		this->SetFlags( flags );
	}

	aclObj->Done( aclObj );

	return( result );

} // SetACL



//--------------------------------------------------------------------------------------------------
//	* RemoveUser
//
//--------------------------------------------------------------------------------------------------

Boolean CMailSpool::RemoveUser ( ObjID inUserID )
{
	Boolean			success			= false;
	uInt32			flags			= 0;
	ObjID			prevACLObjID	= 0;
	CACLObject	   *aclObj			= nil;
	CACLObject	   *prevAclObj		= nil;

	while ( this->GetNextACLObj( &aclObj ) == true )
	{
		if ( aclObj->RemoveUserRef( inUserID ) == true )
		{
			success = true;
			if ( aclObj->GetItemCount() == 0 )
			{
				// Are we at the head of the list
				if ( this->GetACLHeadID() == aclObj->GetMyObjectID() )
				{
					if ( (aclObj->GetNextObjectID() != 0) && (aclObj->GetNextObjectID() != 0xF0F0F0F0) )
					{
						this->SetACLHeadID( aclObj->GetNextObjectID() );
						CACLObject::Delete( aclObj );
					}
					else
					{
						flags = this->GetFlags();
						flags &= ~CMailSpool::kPublishedFlag;
						this->SetFlags( flags );
					}
				}
				else
				{
					// We must be in the middle or at the end
					prevAclObj = (CACLObject *)CACLObject::FindByID( prevACLObjID );
					if ( prevAclObj != nil )
					{
						prevAclObj->SetNextObjectID( aclObj->GetNextObjectID() );
						CACLObject::Delete( aclObj );
						prevAclObj->Done( prevAclObj );
					}
				}
			}
		}
		prevACLObjID = aclObj->GetMyObjectID();
	}
	aclObj->Done( aclObj );

	return( success );

} // RemoveUser



//--------------------------------------------------------------------------------------------------
//	* IsObjectInACLList
//
//--------------------------------------------------------------------------------------------------

Boolean CMailSpool::IsUserInACLList ( ObjID inUserID, SACLInfo *outACLData )
{
	Boolean			success		= false;
	CACLObject	   *aclObj		= nil;

	while ( (!success) && (this->GetNextACLObj( &aclObj ) == true) )
	{
		success = aclObj->IsUserInList( inUserID, outACLData );
	}
	aclObj->Done( aclObj );

	return( success );

} // IsObjectInACLList



//--------------------------------------------------------------------------------------------------
//	* IsSpoolInList
//
//--------------------------------------------------------------------------------------------------

Boolean CMailSpool::IsSpoolInList ( ObjID inSpoolID )
{
	Boolean			success		= false;
	CACLObject	   *aclObj		= nil;

	while ( (!success) && (this->GetNextACLObj( &aclObj ) == true) )
	{
		success = aclObj->IsSpoolInList( inSpoolID );
	}
	aclObj->Done( aclObj );

	return( success );

} // IsSpoolInList



//--------------------------------------------------------------------------------------------------
//	* IsObjectInSeenList
//
//--------------------------------------------------------------------------------------------------

Boolean CMailSpool::IsObjectInSeenList ( ObjID inObjID )
{
	Boolean			success		= false;
	CSharedFlags   *sharedObj	= nil;

	while ( (!success) && (this->GetNextSharedObj( &sharedObj ) == true) )
	{
		success = sharedObj->IsObjectInList( inObjID );
	}
	sharedObj->Done( sharedObj );

	return( success );

} // IsObjectInSeenList



//--------------------------------------------------------------------------------------------------
//	* GetACLData
//
//--------------------------------------------------------------------------------------------------

Boolean CMailSpool::GetACLData ( ObjID inUserID, SACLInfo &outData )
{
	Boolean			result		= false;
	CACLObject	   *aclObj		= nil;

	while ( (!result) && (this->GetNextACLObj( &aclObj ) == true) )
	{
		result = aclObj->GetACLData( inUserID, outData );
	}
	aclObj->Done( aclObj );

	return( result );

} // GetACLData



//--------------------------------------------------------------------------------------------------
//	* GetNextSharedObj
//
//--------------------------------------------------------------------------------------------------

Boolean CMailSpool::GetNextSharedObj ( CSharedFlags **inObjPtr, Boolean inCreate )
{
	Boolean			result		= false;
	ObjID			objID		= 0;
	CSharedFlags   *objPtr		= nil;

	if ( *inObjPtr == nil )
	{
		objID = this->GetSharedID();
	}
	else
	{
		objID = (*inObjPtr)->GetNextObjectID();
	}

	objPtr = (CSharedFlags *)CExpansion::FindByID( objID );

	if ( (objPtr == nil) && (inCreate == true) )
	{
		objPtr = (CSharedFlags *)CExpansion::Create( fMailSpoolData.fMailSpoolID, sizeof( SFlags ) );
		if ( objPtr != nil )
		{
			objID = this->GetSharedID();
			objPtr->SetNextObjectID( objID );
			objID = objPtr->GetMyObjectID();
			this->SetSharedID( objID );
		}
	}

	(*inObjPtr)->Done( *inObjPtr );
	*inObjPtr = objPtr;

	if ( *inObjPtr != nil )
	{
		result = true;
	}

	return( result );

} // GetNextSharedObj



//--------------------------------------------------------------------------------------------------
//	* AddToSeenList
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::AddToSeenList ( ObjID inObjID )
{
	Boolean			success		= false;
	CSharedFlags   *sharedObj	= nil;

	// Set the existing ACL data if any
	while ( (!success) && (this->GetNextSharedObj( &sharedObj, true ) == true) )
	{
		success = sharedObj->SetSharedInfo( inObjID );
	}
	sharedObj->Done( sharedObj );

} // AddToSeenList



//--------------------------------------------------------------------------------------------------
//	* RemoveFromSeenList
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::RemoveFromSeenList ( ObjID inObjID )
{
	Boolean			success		= false;
	CSharedFlags   *sharedObj	= nil;

	// Set the existing ACL data if any
	while ( (!success) && (this->GetNextSharedObj( &sharedObj ) == true) )
	{
		success = sharedObj->DeleteSharedInfo( inObjID );
	}
	sharedObj->Done( sharedObj );

} // RemoveFromSeenList




//--------------------------------------------------------------------------------------------------
//	* ClearSeenFlags
//
//--------------------------------------------------------------------------------------------------

void CMailSpool::ClearSeenFlags ( void )
{
	ObjID			objID		= 0;
	CSharedFlags   *objPtr		= nil;

	objID = this->GetSharedID();

	objPtr = (CSharedFlags *)CExpansion::FindByID( objID );
	objID = 0;
	if ( objPtr != nil )
	{
		objPtr->ClearIDs();
		objID = objPtr->GetNextObjectID();
		objPtr->SetNextObjectID( 0 );
		objPtr->Done( objPtr );
	}

	if ( objID != 0 )
	{
		objPtr = (CSharedFlags *)CExpansion::FindByID( objID );
		while ( objPtr != nil )
		{
			objID = objPtr->GetNextObjectID();
			CSharedFlags::Delete( objPtr );
			objPtr->Done( objPtr );
			objPtr = (CSharedFlags *)CExpansion::FindByID( objID );
		}
	}

} // RemoveFromSeenList

