/*
	$Id: CMailboxes.cpp,v 1.1 2003/04/20 23:30:51 dasenbro Exp $

	File:		CMailboxes.cpp

	Contains:	

	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: CMailboxes.cpp,v $
		Revision 1.1  2003/04/20 23:30:51  dasenbro
		Initial check-in.
		
		Revision 1.11  2002/07/26 00:55:38  dasenbro
		Fixed leak in POP server.
		
		Revision 1.10  2002/05/09 16:59:00  dasenbro
		Changed all str... calls to CUtils::Str... to be NULL safe.
		
		Revision 1.9  2002/03/21 16:41:32  dasenbro
		Updated file version information.
		
		Revision 1.8  2002/03/05 19:44:28  dasenbro
		Fixed logn rename problem.
		
		Revision 1.7  2002/01/14 17:20:35  dasenbro
		Initial S4 updates.
		
		Revision 1.6  2001/06/21 20:51:03  dasenbro
		Updated file header info.
		
		Revision 1.5  2001/06/21 19:33:23  dasenbro
		Added Change History.
		

	Projector History:

	 <ASM34>	 3/22/99	MED		Added an account ID to constructor and made fSession null safe.
	 <ASM33>	 2/11/99	MED		Break out of a while loop on quit.
		<32>	11/11/98	MED		What the hell was I thinking???
		<31>	11/11/98	MED		Fixed a wild card list bug.
		<30>	11/10/98	MED		Fixed the list command with multiple wild cards.
		<29>	10/28/98	DOR		Merged the change from 28 branch onto the main trunk.  We now
									reject renaming the User's INBOX.
		<28>	 9/14/98	MED		Added an IsShared flag to GetThisMailboxesID() to reject rename
									and create on shared hierarchies.
		<27>	 8/24/98	MED		Check-in just to fix that stupid large resource fork bug from
									CW.
		<26>	 8/24/98	MED		Addes support for x-list.
		<25>	 8/18/98	MED		Print the \Published flag.
		<24>	 8/10/98	MED		Added better support for ACLs.
		<23>	  8/3/98	MED		6.1 - Added ACL support.
		<22>	 6/16/98	MED		#2246044 - Added done to catch.
		<21>	  6/8/98	DOR		Fix VerifyMailboxPath to deal with "~/", and also make it so
									that Delete & Rename return the proper error string/code for
									non-existant path names.
		<20>	 5/12/98	MED		We can now delete the selected mailbox if there is only 1
									selection and we have it.
		<19>	 4/28/98	MED		We now check the spool ref-count to make sure that it is not
									selected before we try to rename or delete it.
		<18>	 4/25/98	MED		Added some checking for max # of mailboxes, max mailbox name
									lenght and max path depth.
		<17>	  4/8/98	MED		Added case sensitive mailbox namespace checking.
		<16>	 3/17/98	MED		Added MatchCase() to match the response mailbox path with that
									of the one on the command line.
		<15>	  3/2/98	MED		Fixed an output buffering bug in WriteMailboxPath().
		<14>	 2/25/98	MED		Made the target mailbox the newly created mailbox if we were
									renaming the inbox.
		<13>	 2/23/98	MED		Added CThread::SmartYield's to while and for loops.
		<12>	 2/11/98	MED		Added Delimiter constants.
		<11>	  2/9/98	MED		Write data to endpoint when size of CString is nearing capacity.
		<10>	  2/7/98	MED		Fixed some path selection bugs.
		 <9>	  2/5/98	MED		Fixed the FIND command to show only subscribed mailboxes.
		 <8>	  2/4/98	MED		Added checks for the Noselect and Deleted flags on the spools.
		 <7>	  2/3/98	MED		Cleaned OSUtil.cp into CUtils.cp, COSUtils.cp and
									CSmartYield.cp.
		 <6>	  2/2/98	MED		Simplified the user of the "Reference Name" argument in the list
									command.  We now concatenate the 2 args to form a single mailbox
									path.
		 <5>	 1/27/98	MED		Added list support for POP3 inbox in the IMAP mailbox list and
									proper error handling when trying to delete and create a POP3
									mailbox.
		 <4>	12/10/97	MED		We now handle a second command string literal.
		 <3>	 11/5/97	MED		Added check for unsubscribed folders and removed the leading "/"
									on folder lists.
		 <2>	10/22/97	MED		Made the LIST command with the % arg do the right thing.

	To Do:
*/

// 
#include <string.h>

// App
#include "CMailboxes.h"
#include "CTokenizer.h"
#include "CMailSpool.h"
#include "Database.h"
#include "IMAPErrors.h"
#include "CUtils.h"
#include "CGlobals.h"

//--------------------------------------------------------------------------------------------------
//	* CMailboxes ()
//
//--------------------------------------------------------------------------------------------------

CMailboxes::CMailboxes ( char *inSession, Boolean inIs8BitOn, ObjID inAcctID )
{
	Try_
	{
		if ( inSession != nil )
		{
		//	fSession = inSession;
		//	fAccountID = fSession->GetAccountID();
		}
		else
		{
		//	fSession = nil;
			fAccountID = inAcctID;
		}

		f8BitOn			= inIs8BitOn;
		fArg1			= nil;
		fArg2			= nil;
		fCommand		= nil;
		fCmdType		= 0;
		fFlags			= 0;
		::memset( &fFldrPrefix, 0, sizeof( fFldrPrefix ) );
		fActions		= nil;
	}

	Catch_( err )
	{
		Throw_( err );
	}
} // CMailboxes



//--------------------------------------------------------------------------------------------------
//	* ~CMailboxes ()
//
//--------------------------------------------------------------------------------------------------

CMailboxes::~CMailboxes ( void )
{
	if ( fCommand != nil )
	{
		delete( fCommand );
		fCommand = nil;
	}

	if ( fArg1 != nil )
	{
		delete( fArg1 );
		fArg1 = nil;
	}

	if ( fArg2 != nil )
	{
		delete( fArg2 );
		fArg2 = nil;
	}

	if ( fActions != nil )
	{
		delete( fActions );
		fActions = nil;
	}
} // ~CMailboxes


//--------------------------------------------------------------------------------------------------
//	* GetCurrentMailboxID
//
//--------------------------------------------------------------------------------------------------

ObjID CMailboxes::GetCurrentMailboxID ( void )
{
	ObjID			mailboxID = 0;
	CMailSpool	   *mailSpool;

//	if ( fSession != nil )
//	{
//		mailSpool = fSession->GetSelectedSpool();
//		if ( mailSpool != nil )
//		{
//			mailboxID = mailSpool->GetMailSpoolID();
//		}
//	}

	return( mailboxID );

} // GetCurrentMailboxID



//--------------------------------------------------------------------------------------------------
//	* Initialize
//
//		-	Return bad command format if necessare ...
//
//--------------------------------------------------------------------------------------------------

void CMailboxes::Initialize ( const char *arg1, const char *arg2, const char *inCommand, eCommand inCmdType )
{
	SetMailbox1( arg1 );
	SetMailbox2( arg2 );

	fCmdType = inCmdType;

	if ( inCommand != nil )
	{
		if ( fCommand == nil )
		{
			fCommand = new CString( inCommand );
		}
		else
		{
			fCommand->Set( inCommand );
		}
	}

	SetupCommand( inCmdType );

} // Initialize



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

ObjID CMailboxes::GetAccountID ( void )
{
	return( fAccountID );
} // GetAccountID



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

void CMailboxes::SetAccountID ( ObjID inAcctID )
{
	fAccountID = inAcctID;
} // SetAccountID



//--------------------------------------------------------------------------------------------------
//	* HasPrefix
//
//		-	Check the incomming string for a root prefis - ~, or the hierarchy delimiter - /
//			 Return return true if either exist at the start of the string
//
//--------------------------------------------------------------------------------------------------

Boolean CMailboxes::HasPrefix ( char *inData )
{
	Boolean		result = false;

	if ( *inData == kHierRootChar || *inData == kHierDelimChar )
	{
		result = true;
	}

	return( result );
}


//--------------------------------------------------------------------------------------------------
//	* SetPrefixString
//
//		- Set the prefix string.  This will be returned in the response
//
//--------------------------------------------------------------------------------------------------

void CMailboxes::SetPrefixString ( char inChar, uInt16 inWhere )
{
	if ( (inWhere > 0) && (inWhere < 10) )
	{
		fFldrPrefix[ inWhere ] = inChar;
	}
} // SetPrefixString



//--------------------------------------------------------------------------------------------------
//	* StripPrefix
//
//--------------------------------------------------------------------------------------------------

void CMailboxes::StripPrefix ( char *inData )
{
	char   *p		= inData;
	sInt16	count	= 0;
	sInt16   len		= CUtils::Strlen( inData );

	if ( len > 0 )
	{
		if ( *p == kHierRootChar )
		{
			count++;
			p++;
		}

		if ( *p == kHierDelimChar )
		{
			count++;
			p++;
		}

		if ( count > 0 )
		{
			::memmove( inData, &inData[count], len - count);
			inData[ len - count ] = '\0';
		}
	}
} // StripPrefix



//--------------------------------------------------------------------------------------------------
//	* SetPrefix
//
//--------------------------------------------------------------------------------------------------

char* CMailboxes::SetPrefix ( char *inData )
{
	char	   *p = inData;
	uInt16		i = 0;

	if ( *p == kHierRootChar )
	{
		fFlags |= kHasPrefix;
		SetPrefixString( *p, i );
		i++;
		p++;
	}

	if ( *p == kHierDelimChar )
	{
		fFlags |= kHasPrefix;
		SetPrefixString( *p, i );
		i++;
		p++;
	}

	return( p );

} // SetPrefix



//--------------------------------------------------------------------------------------------------
//	* SetupCommand
//
//--------------------------------------------------------------------------------------------------

sInt16 CMailboxes::SetupCommand ( eCommand inCmdType )
{
	char	   *p		= nil;
	uInt32		result	= kNoErr;

	switch( inCmdType )
	{
		case kCmdFind:
			if ( fCommand != nil )
			{
				fCommand->Set( "MAILBOX " );
			}

			if ( CUtils::Stricmp( fArg1->GetData(), "ALL.MAILBOXES" ) == 0 )
			{
				fFlags |= kListAll;
			}
			else if ( CUtils::Stricmp( fArg1->GetData(), "MAILBOXES" ) == 0 )
			{
				fFlags |= kListSubOnly;
			}
			else
			{
				return( kErrNoMboxFound );
			}

			fArg1->Clear();

			CombineArgs();

			result = VerifyArgs();
			break;

		case kCmdLsub:
			fFlags |= kListSubOnly;

		case kCmdList:
		case kCmd_X_List:
			CombineArgs();

			result = VerifyArgs();

			break;

		case kCmdCreate:
		case kCmdSelect:
		case kCmdExamine:
		case kCmdDelete:
		case kCmdRename:
		case kCmdStatus:
		case kCmdSubUnsub:
			p = SetPrefix( fArg1->GetData() );
			fArg1->Set( p );

			break;

		case kCmdCopy:
			break;
	}

	return( result );

} // SetupCommand



//--------------------------------------------------------------------------------------------------
//	* CombineArgs
//
//--------------------------------------------------------------------------------------------------

void CMailboxes::CombineArgs ( void )
{
	char	   *arg1	= fArg1->GetData();
	sInt32		len		= fArg1->GetLength();
	char	   *arg2	= fArg2->GetData();

	if ( len > 0 )
	{
		if ( (arg1[ len - 1 ] != kHierDelimChar ) && (*arg2 != kHierDelimChar) )
		{
			fArg1->Append( kHierDelimChar );
		}
		else if ( (arg1[ len - 1 ] == kHierDelimChar ) && (*arg2 == kHierDelimChar) )
		{
			fArg1->Set( fArg1->GetData(), len - 1 );
		}
	}

	fArg1->Append( fArg2->GetData() );

} // CombineArgs



//--------------------------------------------------------------------------------------------------
//	* VerifyArgs
//
//--------------------------------------------------------------------------------------------------

sInt16 CMailboxes::VerifyArgs ( void )
{
	sInt16	result	= kNoErr;

	Try_
	{
		char			c;
		sInt16			i				= 0;
		Boolean			wildChar		= false;
		sInt16			tmpActionCnt	= 0;

		// If the argument has a null mailbox name, then bail
		//	ie. inbox/temp//stuff
		
		if ( (fArg1->GetLength() > 1) && (CUtils::Strstr( fArg1->GetData(), kDoubleDelimStr ) != nil) )
		{
			return( kErrMBoxPathHasEmptyName );
		}

		// If the argument has a double *'s or double %'s
		//	ie. inbox/temp/**/stuff or inbox/temp/%%/stuff
		if ( (fArg1->GetLength() > 1) &&
			 ((CUtils::Strstr( fArg1->GetData(), kDoubleStarStr ) != nil) ||
			  (CUtils::Strstr( fArg1->GetData(), kStarPercentStr ) != nil) ||
			  (CUtils::Strstr( fArg1->GetData(), kPercentStarStr ) != nil) ||
			  (CUtils::Strstr( fArg1->GetData(), kDoublePercentStr ) != nil)) )
		{
			return( kNoErr );
		}

		fArg1->Set( SetPrefix( fArg1->GetData() ) );

		// Set the tokenizer for the arguments
		CTokenizer		tokenObj( *fArg1, kHierDelimStr );
		CString			cmdToken( 256 );

		fActionCnt = tokenObj.Count();
		if ( fActionCnt == 0 )
		{
			fFlags = kListRootOnly;
			fArg1->Clear();
		}
		else if ( fActionCnt > kMaxMailboxDepth )
		{
			result = kErrMboxDepthTooDeep;
			fArg1->Clear();
		}
		else
		{
			// Add 1 to fActionCnt for a possible list arg of "tag list "" inbox/star*"
			//	This will add the kMatchAll as the last action

			fActions = new eActions[ fActionCnt + 1 ];
			ThrowIfNULL_( fActions );
			::memset( fActions, 0, sizeof( *fActions ) * (fActionCnt + 1) );

			i = 0;
			tmpActionCnt = fActionCnt;
			while ( i < fActionCnt )
			{
				cmdToken.Set( tokenObj.Get( i ), tokenObj.GetLength( i ) );

				if ( cmdToken.GetLength() == 1 )
				{
					c = cmdToken.GetData()[0];
					if ( c == '*' )
					{
						fActions[ i ] = kMatchAll;
						wildChar = true;
					}
					else if ( c == '%' )
					{
						fActions[ i ] = kMatchOnly;
						wildChar = true;
					}
					else
					{
						fActions[ i ] = kMatchExact;
					}
				}
				else
				{
					if ( (CUtils::Strstr( cmdToken.GetData(), "%" ) != nil ) ||
						 (CUtils::Strstr( cmdToken.GetData(), "*" ) != nil ) )
					{
						wildChar = true;
						fActions[ i ] = kMatchBetween;

						if ( cmdToken.GetData()[ cmdToken.GetLength() - 1 ] == '*' )
						{
							// Are we on the last list token
							if ( i == (fActionCnt - 1) )
							{
								// Add the match all action to the end of the list
								tmpActionCnt = fActionCnt +1;

								fActions[ fActionCnt ] = kMatchAll;

							}
						}
					}
					else
					{
						fActions[ i ] = kMatchExact;
					}
				}
				i++;
			}

			// Temp action count _MUST NOT_ be more than the action count + 1
			fActionCnt = tmpActionCnt;

			if ( wildChar == false )
			{
				fFlags = kListOneMailbox;
			}
		}
	}

	Catch_ ( err )
	{
		result = err;

		if ( fActions != nil )
		{
			delete( fActions );
			fActions = nil;
		}
		fActionCnt = 0;
	}

	return( result );

} // VerifyArgs



//--------------------------------------------------------------------------------------------------
//	* SetMailbox1
//
//--------------------------------------------------------------------------------------------------

void CMailboxes::SetMailbox1 ( const char *inStr )
{
	if ( fArg1 == nil )
	{
		fArg1 = new CString( inStr );
	}
	ThrowIfNULL_( fArg1 );
} // SetMailbox1



//--------------------------------------------------------------------------------------------------
//	* SetMailbox2
//
//--------------------------------------------------------------------------------------------------

void CMailboxes::SetMailbox2 ( const char *inStr )
{
	if ( fArg2 == nil )
	{
		fArg2 = new CString( inStr );
	}
	ThrowIfNULL_( fArg2 );
} // SetMailbox2



//--------------------------------------------------------------------------------------------------
//	* GetMailbox1ObjID
//
//--------------------------------------------------------------------------------------------------

ObjID CMailboxes::GetMailbox1ObjID ( void )
{
	return( VerifyMailboxPath( fArg1->GetData() ) );
} // GetMailbox1ObjID



//--------------------------------------------------------------------------------------------------
//	* GetMailbox2ObjID
//
//--------------------------------------------------------------------------------------------------

ObjID CMailboxes::GetMailbox2ObjID ( void )
{
	return( VerifyMailboxPath( fArg2->GetData() ) );
} // GetMailbox2ObjID




//--------------------------------------------------------------------------------------------------
//	* CreateMailbox
//
//--------------------------------------------------------------------------------------------------

sInt16 CMailboxes::CreateMailbox ( Boolean inIsShared, ObjID inSharedSpoolID, ObjID *outNewSpoolID )
{
	Boolean			isShared	= false;
	int				i			= 0;
	int				tokenCnt	= 0;
	sInt32			result		= kNoErr;
	uInt32			flags		= 0;
	ObjID			mailboxID	= 0;
	ObjID			parentID	= CMailSpool::kRootParent;
	char		   *mbName		= nil;
	CMailSpool	   *mbSpool		= nil;
	CTokenizer		tokenObj( *fArg1, kHierDelimStr );
	ObjID			spoolList[ kMaxMailboxDepth ];

	Try_
	{
		// Set to null
		::memset( spoolList, 0, sizeof( spoolList ) );

		// Let's first check to see if they are trying to mess with the POP3 inbox
		CString	rootName( tokenObj.Get( 0 ), tokenObj.GetLength( 0 ) );
		if ( CUtils::Stricmp( rootName.GetData(), "POP3 INBOX" ) == 0 )
		{
			result = kErrCantCreatePOPInbox;
			if ( tokenObj.Count() > 1 )
			{
				result = kErrPOPInboxCantHaveSub;
			}
		}

		if ( result == kNoErr )
		{
			// Set default result code
			result = kErrCantCreateMbox;

			tokenCnt = tokenObj.Count();
			if ( tokenCnt <= kMaxMailboxDepth )
			{
				while ( (i < tokenCnt) && (result == kErrCantCreateMbox) )
				{
					mbName = tokenObj.Get( i );
					mbName[ tokenObj.GetLength( i ) ] = '\0';

					// Make sure that the name is not too long
					if ( tokenObj.GetLength( i ) <= kMailboxNameLen )
					{
						// Check to see if this mailbox already exists
						mailboxID = GetThisMailboxesID( mbName, parentID, isShared );
						if ( mailboxID == 0 )
						{
							if ( GetMailboxCount() <= kMaxMailboxCount )
							{
								// The mailbox does not exis, so let's create it
								mbSpool = CMailSpool::Create( CMailSpool::kIMAP4Spool,
																  mbName,
																  fAccountID,
																  parentID );
								ThrowIfNULL_( mbSpool );
								if ( inIsShared == true )
								{
									flags = mbSpool->GetFlags();
									mbSpool->SetFlags( flags & CMailSpool::kSharedFlag );
									mbSpool->SetACLHeadID( inSharedSpoolID );
									*outNewSpoolID = mbSpool->GetMailSpoolID();
								}
								parentID = mbSpool->GetMailSpoolID();
								spoolList[ i ] = mbSpool->GetMailSpoolID();
								if ( i == tokenObj.Count() - 1 )
								{
									// It created the one we wanted ...
									result = kRespCommandCompleted;
								}

								mbSpool->Done ( mbSpool );
							}
							else
							{
								// We need to delete the mailboxes we created because
								//	the command faild
								for ( i = 0; i < kMaxMailboxDepth; i++ )
								{
									if (  spoolList[ i ] != 0 )
									{
										mbSpool = CMailSpool::FindByID(  spoolList[ i ] );
										if ( mbSpool != nil )
										{
											CMailSpool::Delete( mbSpool );
											mbSpool->Done( mbSpool );
										}
										spoolList[ i ] = 0;
									}
								}
								result = kErrMaxNumberMboxExceeded;
							}
						}
						else
						{
							if ( isShared == true )
							{
								result = kErrCantCreateSharedMbox;
							}
							else if ( i == (tokenCnt - 1) )
							{
								mbSpool = CMailSpool::FindByID( mailboxID );
								if ( mbSpool != nil )
								{
									// check to see if the delete flag was set
									if ( mbSpool->GetFlags() & CMailSpool::kDeletedFlag )
									{
										// Lets bring this one back to life...
										flags = mbSpool->GetFlags();
										flags &= ~CMailSpool::kDeletedFlag;
										flags &= ~CMailSpool::kNoSelectFlag;
										mbSpool->SetFlags( flags );

										result = kRespCommandCompleted;
									}
									mbSpool->Done( mbSpool );
								}
							}
							parentID = mailboxID;
						}
						i++;
					}
					else
					{
						result = kErrMboxNameTooLong;
					}
				}
			}
			else
			{
				result = kErrMboxDepthTooDeep;
			}
		}
	}

	Catch_ ( err )
	{
		mbSpool->Done( mbSpool );

		result = err;
	}

	return( result );

} // CreateMailbox



//--------------------------------------------------------------------------------------------------
//	* DeleteMailbox
//
//--------------------------------------------------------------------------------------------------

OSErr CMailboxes::DeleteMailbox ( void )
{
	OSErr			result		= kNoErr;
	CMailSpool	   *mbSpool		= nil;
	CMailSpool	   *parentMb	= nil;
	uInt32			mailboxID	= GetMailbox1ObjID();

	Try_
	{
//		ThrowIfNULL_( fSession );

		if ( mailboxID == 0)
		{
			// Can't delete no existant folders
			result = kErrNoMboxFound;
		}
//		else if ( mailboxID == fSession->GetInBoxSpoolID() )
//		{
//			// Can't delete the imap inbox
//			result = kErrCantDeleteInbox;
//		}
//		else if ( mailboxID == fSession->GetPop3InBoxID() )
//		{
//			// Can't delete the pop inbox
//			result = kErrCantDeletePOPInbox;
//		}
		else
		{
			result = MailboxHasInferiors( mailboxID );

			// Lets try to delete this puppy (if we can)
			mbSpool = CMailSpool::FindByID( mailboxID );
			if ( mbSpool != nil )
			{
				if ( !(mbSpool->GetFlags() & CMailSpool::kSharedFlag) )
				{
//					if ( (mbSpool->GetRefCount() == 0) || 
//						 ((mbSpool->GetRefCount() == 1) && (fSession->GetSelectedID() == mailboxID)) )
					{
//						if ( fSession->GetSelectedID() == mailboxID )
//						{
//							fSession->CloseSelectMailbox();
//						}

						// Is the mailbox already deleted?
						if ( mbSpool->GetFlags() & CMailSpool::kDeletedFlag )
						{
							result = kErrNoMboxFound;
						}
						else
						{
							// Check for inferiors
							if ( result == kErrDeleteHasInferiors )
							{
								// First mark the mailbox as deleted, we will delete it
								//	later when it has no inferiors.
								//	Second delete all envelope info's
								mbSpool->SetFlags( mbSpool->GetFlags() | CMailSpool::kNoSelectFlag | CMailSpool::kDeletedFlag );
								mbSpool->DeleteAllEnvelopeInfos();
								mbSpool->ResetSpoolCounts();
							}
							else
							{
								// Delete this mailbox and any of its parents who
								//	no longer have non-deleted inferiors.

								Boolean		done		= false;
								ObjID		parentID	= mbSpool->GetParentID();
								CMailSpool::Delete( mbSpool );
								mbSpool->Done( mbSpool );

								while ( (parentID != CMailSpool::kRootParent) &&
										!done &&
										(CGlobals::QuitNow() == false) )
								{
									done = true;
									parentMb = CMailSpool::FindByID( parentID );
									if ( parentMb != nil )
									{
										if ( parentMb->GetFlags() & CMailSpool::kDeletedFlag )
										{
											result = MailboxHasInferiors( parentID );
											if ( result == kNoErr )
											{
												parentID = parentMb->GetParentID();
												CMailSpool::Delete( parentMb );
												done = false;
											}
										}
										parentMb->Done( parentMb );
									}
								}
							}
							result = kNoErr;
						}
					}
//					else
//					{
//						result = kErrMboxAccessDenied;
//					}
				}
				else
				{
					result = kErrUserDoesntHaveRights;
				}
				mbSpool->Done( mbSpool );
			}
//			else
//			{
//				result = kErrNoMboxFound;
//			}
		}
	}

	Catch_ ( err )
	{
		mbSpool->Done( mbSpool );
		parentMb->Done( parentMb );

		result = err;
	}

	return( result );

} // DeleteMailbox



//--------------------------------------------------------------------------------------------------
//	* MailboxHasInferiors
//
//--------------------------------------------------------------------------------------------------

OSStatus CMailboxes::MailboxHasInferiors ( ObjID inMbID )
{
	OSStatus		result	= kNoErr;
	Boolean			done	= false;
	ObjID			objID	= 0;
	CMailSpool	   *mbSpool	= nil;
	SDBIterator		iterator;

	Try_
	{
		// Look for inferiors
		result = gDB->CreateIterator( kMailSpoolSignature, &iterator, fAccountID );
		if ( result == kNoErr )
		{
			while ( (gDB->NextObject( &iterator, objID ) == kNoErr) && (!done) )
			{
				mbSpool = CMailSpool::FindByID( objID );
				if ( mbSpool != nil )
				{
					if ( mbSpool->GetParentID() == inMbID )
					{
						// We have inferiors, only delete the messages
						done = true;
						result = kErrDeleteHasInferiors;
					}
					mbSpool->Done( mbSpool );
				}
			}
		}
		gDB->ReleaseIterator( &iterator );
	}

	Catch_ ( err )
	{
		mbSpool->Done( mbSpool );

		gDB->ReleaseIterator( &iterator );

		result = err;
	}

	return( result );

} // MailboxHasInferiors



//--------------------------------------------------------------------------------------------------
//	* RenameMailbox
//
//--------------------------------------------------------------------------------------------------

sInt16 CMailboxes::RenameMailbox ( CMailSpool *inMbSpool )
{
	Boolean			isShared	= false;
	sInt16			i			= 0;
	sInt16			result		= kNoErr;
	sInt16			tokenCnt	= 0;
	ObjID			parentID	= CMailSpool::kRootParent;
	ObjID			mailboxID	= GetMailbox1ObjID();
	CMailSpool	   *mbSpool		= nil;
	CString			tmp( 64 );
	CString			csMbName;
	ObjID			spoolList[ kMaxMailboxDepth ];

	Try_
	{
//		ThrowIfNULL_( fSession );
		::memset( spoolList, 0, sizeof( spoolList ) );

		if ( mailboxID == 0)
		{
			return (kErrNoMboxFound);
		}
//		else  if ( mailboxID == fSession->GetPop3InBoxID() )
//		{
//			return( kErrCantRenamePOPInbox );
//		}

		// code was added by DaveO, this variable used to inited to zero..
		// but we now use it above, and init it to GetMailbox1ObjID();
		mailboxID = 0;

		tmp.Set( fArg2->GetData(), fArg2->GetLength() );
		StripPrefix( tmp.GetData() );

		CTokenizer		tokenObj( tmp, kHierDelimStr );

		tokenCnt = tokenObj.Count();

		if ( tokenCnt > 1 )
		{
			if ( tokenCnt <= kMaxMailboxDepth )
			{
				// First verify or create the path to the new mailbox name
				while ( (i < (tokenCnt - 1)) && (result == kNoErr) )
				{
					csMbName.Set( tokenObj.Get( i ), tokenObj.GetLength( i ) );

					// Make sure that the name is not too long
					if ( csMbName.GetLength() <= kMailboxNameLen )
					{
						// Can't have nil named mailboxes
						if ( csMbName.GetLength() > 0 )
						{
							// Check to see if this mailbox already exists
							mailboxID = GetThisMailboxesID( csMbName.GetData(), parentID, isShared );
							if ( mailboxID == 0 )
							{
								if ( GetMailboxCount() <= kMaxMailboxCount )
								{
									// The mailbox does not exis, so let's create it
									mbSpool = CMailSpool::Create( CMailSpool::kIMAP4Spool, csMbName.GetData(), fAccountID, parentID );
									ThrowIfNULL_( mbSpool );
	
									parentID = mbSpool->GetMailSpoolID();
									mbSpool->Done ( mbSpool );
								}
								else
								{
									// We need to delete the mailboxes we created because
									//	the command faild
									for ( i = 0; i < kMaxMailboxDepth; i++ )
									{
										if (  spoolList[ i ] != 0 )
										{
											mbSpool = CMailSpool::FindByID(  spoolList[ i ] );
											if ( mbSpool != nil )
											{
												CMailSpool::Delete( mbSpool );
												mbSpool->Done( mbSpool );
											}
											spoolList[ i ] = 0;
										}
									}
									result = kErrMaxNumberMboxExceeded;
									break;
								}
							}
							else
							{
								if ( isShared == true )
								{
									result = kErrCantCreateSharedMbox;
								}
								parentID = mailboxID;
							}
						}
						else
						{
							result = kErrMissingArg;
							break;
						}
					}
					else
					{
						result = kErrMboxNameTooLong;
					}
					i++;
				}
			}
			else
			{
				result = kErrMboxDepthTooDeep;
			}
		}

		if ( result	== kNoErr )
		{
			// Set the new mailbox name
			csMbName.Set( tokenObj.Get( tokenCnt - 1 ), tokenObj.GetLength( tokenCnt - 1 ) );

			if ( csMbName.GetLength() <= kMailboxNameLen )
			{
				// Special case inbox...
				if ( (CUtils::Stricmp( inMbSpool->GetMailSpoolName(), "INBOX" ) == 0) &&
					(inMbSpool->GetParentID() == CMailSpool::kRootParent) )
				{
					result = kErrCantRenameUsersInbox;
				}
				else
				{
					inMbSpool->SetMailSpoolName( csMbName.GetData() );
					inMbSpool->SetParentID( parentID );
				}
			}
			else
			{
				result = kErrMboxNameTooLong;
			}
		}
	}

	Catch_ ( err )
	{
		mbSpool->Done( mbSpool );

		result = err;
	}

	return( result );

} // RenameMailbox



//--------------------------------------------------------------------------------------------------
//	* GetThisMailboxesID
//
//--------------------------------------------------------------------------------------------------

ObjID CMailboxes::GetThisMailboxesID ( char *inMailbox, ObjID inParentID, Boolean &IsShared )
{
	Boolean			matchCase		= false;
	ObjID			outMailboxID	= 0;
	CMailSpool	   *mbSpool			= nil;

	Try_
	{
		IsShared = false;

		if ( (CUtils::Stricmp( inMailbox, "INBOX" ) == 0) || 
			 (CUtils::Stricmp( inMailbox, "POP3 INBOX" ) == 0) )
		{
			matchCase = matchCase;
		}
		else
		{
			matchCase = f8BitOn;
		}

		mbSpool = CMailSpool::FindByNameParentID( inMailbox, inParentID, fAccountID, matchCase );

		if ( mbSpool != nil )
		{
			outMailboxID = mbSpool->GetMailSpoolID();
			if ( mbSpool->GetFlags() & CMailSpool::kSharedFlag )
			{
				IsShared = true;
			}
			mbSpool->Done( mbSpool );
		}
	}

	Catch_ ( err )
	{
		mbSpool->Done( mbSpool );
	}

	return( outMailboxID );

} // GetThisMailboxesID



//--------------------------------------------------------------------------------------------------
//	* VerifyMailboxPath
//
//--------------------------------------------------------------------------------------------------

ObjID CMailboxes::VerifyMailboxPath ( char *inMailboxPath )
{
	Boolean		notUsed		= false;
	char	   *p			= inMailboxPath;
	sInt16		i			= 0;
	sInt16		strLength	= 0;
	ObjID		parentID	= CMailSpool::kRootParent;
	ObjID		mailboxID	= 0;
	CString		mailboxStr( 128 );

	if ( *p == kHierRootChar )
	{
		*p++;
	}

	if ( *p == kHierDelimChar )
	{
		*p++;
	}

	strLength = CUtils::Strlen(p);
	if ( (p[ strLength - 1] == kHierDelimChar ) && (strLength > 0) )
	{
		mailboxStr.Set( p, strLength - 1 );
	}
	else
	{
		mailboxStr.Set( p );
	}

	CTokenizer tokenObj( mailboxStr, kHierDelimStr );

	while ( i < tokenObj.Count() )
	{
		char	*mbName = tokenObj.Get( i );
		mbName[ tokenObj.GetLength( i ) ] = '\0';

		mailboxID = GetThisMailboxesID( mbName, parentID, notUsed );

		if ( mailboxID == 0 )
		{
			break;
		}
		else
		{
			parentID = mailboxID;
		}
		i++;
	}

	return( mailboxID );

} // VerifyMailboxPath



//--------------------------------------------------------------------------------------------------
//	* MatchCase
//
//--------------------------------------------------------------------------------------------------

void CMailboxes::MatchCase ( CString &outMailboxStr )
{
	Try_
	{
		sInt16			i = 0;
		CTokenizer		userStr( *fArg1, kHierDelimStr );
		CTokenizer		mbStr( outMailboxStr, kHierDelimStr );
		CString			str1( 32 );
		CString			str2( 32 );
		CString			newStr( kMailboxNameLen );

		sInt16	cnt = mbStr.Count();

		if ( fArg1->GetLength() > 0 )
		{
			while ( i < cnt )
			{
				Try_
				{
					str1.Set( userStr.Get( i ), userStr.GetLength( i ) );
				}
				Catch_ ( err )
				{
					str1.Clear();
				}

				Try_
				{
					str2.Set( mbStr.Get( i ), mbStr.GetLength( i ) );
				}
				Catch_ ( err )
				{
					str2.Clear();
				}

				if ( i > 0 )
				{
					newStr.Append( kHierDelimStr );
				}

				if ( CUtils::Stricmp( str1.GetData(), str2.GetData() ) == 0 )
				{
					newStr.Append( userStr.Get( i ), userStr.GetLength( i ) );
				}
				else
				{
					newStr.Append( mbStr.Get( i ), mbStr.GetLength( i ) );
				}
				i++;
			}
			outMailboxStr.Set( newStr.GetData() );
		}
	}
	Catch_ ( err )
	{
	}
} // MatchCase


//--------------------------------------------------------------------------------------------------
//	* WriteMailboxPath
//
//--------------------------------------------------------------------------------------------------

void CMailboxes::WriteMailboxPath ( CString &inMbPath,
									CString &outMbList,
									uInt32	 inMBFlags )
{
	Boolean		bAddQuote	= false;
	Boolean		bAddSpace	= false;
	CString		aString( 16 );

	if ( (outMbList.GetLength() + inMbPath.GetLength()) > (outMbList.GetAllocSize() - 32) )
	{
//		if ( fSession != nil )
//		{
//			CEndpoint  *endPt = fSession->GetEndpoint();
//			if ( endPt != nil )
//			{
//				endPt->WriteString( outMbList );
//				outMbList.Clear( kCEndpointMaxMessageSize );
//			}
//		}
	}

	// Echo character string
	MatchCase( inMbPath );

	if ( CUtils::Stricmp( inMbPath.GetData(), "INBOX" ) != 0 )
	{
		if ( fFlags & kHasPrefix )
		{
			inMbPath.Prepend( fFldrPrefix );
		}
	}

	// Check for space in the mailbox name.  If there are spaces, we need to quote
	//	the outgoing mailbox name.

	if ( CUtils::Strstr( inMbPath.GetData(), " " ) != nil )
	{
		bAddQuote = true;
	}

	if ( fCmdType != kCmdFind )
	{
		if ( bAddQuote )
		{
			inMbPath.Prepend( " \"/\" \"" );
		}
		else
		{
			inMbPath.Prepend( " \"/\" " );
		}

		aString.Set( "(" );
		if ( inMBFlags & CMailSpool::kNoSelectFlag )
		{
			aString.Append( "\\Noselect" );
			bAddSpace = true;
		}

		if ( inMBFlags & CMailSpool::kNoInferiorsFlag )
		{
			if ( bAddSpace == true )
			{
				aString.Append( " " );
			}
			aString.Append( "\\Noinferiors" );
			bAddSpace = true;
		}

		if ( fCmdType == kCmd_X_List )
		{
			if ( inMBFlags & CMailSpool::kSharedFlag )
			{
				if ( bAddSpace == true )
				{
					aString.Append( " " );
				}
				aString.Append( "\\Shared" );
				bAddSpace = true;
			}

			if ( inMBFlags & CMailSpool::kPublishedFlag )
			{
				if ( bAddSpace == true )
				{
					aString.Append( " " );
				}
				aString.Append( "\\Published" );
				bAddSpace = true;
			}
		}

		aString.Append( ")" );
		inMbPath.Prepend( aString.GetData() );
	}

	if ( fCommand != nil )
	{
		inMbPath.Prepend( fCommand->GetData() );
	}
	inMbPath.Prepend( "* " );

	if ( fCmdType != kCmdFind )
	{
		if ( bAddQuote )
		{
			inMbPath.Append( "\"\r\n" );
		}
		else
		{
			inMbPath.Append( "\r\n" );
		}
	}
	else
	{
		inMbPath.Append( "\r\n" );
	}

	outMbList.Append( inMbPath.GetData() );

} // WriteMailboxPath



//--------------------------------------------------------------------------------------------------
//	* OkToList
//
//--------------------------------------------------------------------------------------------------

Boolean CMailboxes::OkToList ( CMailSpool *inSpool, Boolean inListPopInbox )
{
	Boolean		result = true;

	if ( (fFlags & kListSubOnly) && 
		 (!(inSpool->GetFlags() & CMailSpool::kSubscribedFlag)) )
	{
		result = false;
	}

//	if ( (fSession != nil) && (inSpool->GetMailSpoolID() == fSession->GetPop3InBoxID()) && (inListPopInbox == false) )
//	{
//		result = false;
//	}

	if ( !(inSpool->GetACLRights() & CMailSpool::kACLLookup) )
	{
		result = false;
	}

	return( result );

} // OkToList


//--------------------------------------------------------------------------------------------------
//	* ListMailboxes
//
//		-	Respond with list of the mailboxs
//
//--------------------------------------------------------------------------------------------------

void CMailboxes::ListMailboxes ( CString &outMbList, Boolean inListPopInbox )
{
	OSErr			result;
	ObjID			objID;
	Boolean			listIt;
	Boolean			listDeleted;
	SDBIterator		iterator;
	CMailSpool	   *mbSpool;
	CString			mailboxPath( 32 );

	Try_
	{
		if ( fFlags & kListRootOnly )
		{
			ListRoot( outMbList );
		}
		else if ( fFlags & kListOneMailbox )
		{
			objID = VerifyMailboxPath( fArg1->GetData() );

			mbSpool = CMailSpool::FindByID( objID );
			if ( mbSpool != nil )
			{
				if ( OkToList( mbSpool, inListPopInbox ) == true )
				{
					this->GetFullPath( mailboxPath, mbSpool, kHierDelimStr );
					WriteMailboxPath( mailboxPath, outMbList, mbSpool->GetFlags() );
				}
				mbSpool->Done( mbSpool );
			}
		}
		else
		{
			Try_
			{
				result = gDB->CreateIterator( kMailSpoolSignature, &iterator, fAccountID );
				if ( result == kNoErr )
				{
					while ( gDB->NextObject( &iterator, objID ) == kNoErr )
					{
						mbSpool = CMailSpool::FindByID( objID );
						if ( mbSpool != nil )
						{
							if ( OkToList( mbSpool, inListPopInbox ) == true )
							{
								this->GetFullPath( mailboxPath, mbSpool, kHierDelimStr );

								listIt = CheckListConditions( mailboxPath, listDeleted );

								if ( (mbSpool->GetFlags() & CMailSpool::kDeletedFlag) &&
									 (listDeleted == false) )
								{
									listIt = false;
								}

								if ( listIt == true )
								{
									WriteMailboxPath( mailboxPath, outMbList, mbSpool->GetFlags() );
								}
							}
							mbSpool->Done( mbSpool );
						}
					}
				}
				gDB->ReleaseIterator( &iterator );
			}

			Catch_ ( err )
			{
				mbSpool->Done( mbSpool );

				gDB->ReleaseIterator( &iterator );
			}
		}
	}

	Catch_ ( err )
	{
		mbSpool->Done( mbSpool );
	}

} // ListMailboxes



//--------------------------------------------------------------------------------------------------
//	* CheckListConditions
//	
//--------------------------------------------------------------------------------------------------

Boolean CMailboxes::CheckListConditions ( CString &inMbPath, Boolean &outListDeleted )
{
	sInt16			i			= 0;
	Boolean			done		= false;
	Boolean			result		= true;
	CTokenizer		mbToken( inMbPath, kHierDelimStr );
	CString			mbName( 256 );
	CTokenizer		ListToken( *fArg1, kHierDelimStr );
	CString			ListName( 256 );

	outListDeleted = false;

	if ( mbToken.Count() < ListToken.Count() )
	{
		result = false;
		done = true;
	}

	while ( (i < mbToken.Count()) && !done )
	{
		if ( i >= fActionCnt )
		{
			result = false;
			done = true;
		}
		else
		{
			switch ( fActions[ i ] )
			{
				case kMatchExact:
					mbName.Set( mbToken.Get( i ), mbToken.GetLength( i ) );
					ListName.Set( ListToken.Get( i ), ListToken.GetLength( i ) );
					if ( f8BitOn == true )
					{
						if ( CUtils::Strcmp( mbName.GetData(), ListName.GetData() ) != 0 )
						{
							result = false;
							done = true;
						}
					}
					else
					{
						if ( CUtils::Stricmp( mbName.GetData(), ListName.GetData() ) != 0 )
						{
							result = false;
							done = true;
						}
					}
					break;

				case kMatchOnly:
					if ( (i+1 == mbToken.Count()) &&
						 (i+1 == ListToken.Count()) )
					{
						outListDeleted = true;
					}
					break;

				case kMatchAll:
					if ( i == (fActionCnt - 1) )
					{
						done = true;
					}
					break;

				case kMatchBetween:
					mbName.Set( mbToken.Get( i ), mbToken.GetLength( i ) );
					ListName.Set( ListToken.Get( i ), ListToken.GetLength( i ) );
					result = DoesThisMatch( ListName, mbName );
					if ( (result == false) || (i == (fActionCnt - 1)) )
					{
						if ( mbToken.Count() > i+1 )
						{
							result = false;
						}
						done = true;
					}
					break;

				default:
					result = false;
					done = true;
					break;
			}
		}
		i++;
	}

	return( result );

} // CheckListConditions



//--------------------------------------------------------------------------------------------------
//	* DoesThisMatch
//	
//--------------------------------------------------------------------------------------------------

Boolean CMailboxes::DoesThisMatch ( CString &inCmdArgs, CString &inMbName )
{
	Boolean			result		= true;
	Boolean			done		= false;
	sInt16			i			= 0;
	char		   *p			= inCmdArgs.GetData();
	char		   *n			= inMbName.GetData();
	CString			arg			( 16 );
	CString			tokenList	( 32 );

	while ( *p != nil )
	{
		if ( (*p == '*') || (*p == '%') )
		{
			if ( tokenList.GetLength() > 0 )
			{
				tokenList.Append( kHierDelimStr );
			}
			tokenList.Append( *p );
			if ( *(p+1) != nil )
			{
				tokenList.Append( kHierDelimStr );
			}
		}
		else
		{
			tokenList.Append( *p );
		}
		p++;
	}

	CTokenizer tokenObj( tokenList, kHierDelimStr );
	while ( (i < tokenObj.Count()) && !done )
	{
		if ( (n == nil) )
		{
			done	= true;
			result	= false;
			break;
		}

		arg.Set( tokenObj.Get( i ), tokenObj.GetLength( i ) );

		if ( (CUtils::Strcmp( "*", arg.GetData() ) != 0) && (CUtils::Strcmp( "%", arg.GetData() ) != 0) )
		{
			p = arg.GetData();
			if ( i == 0 )
			{
				if ( f8BitOn == true )
				{
					if ( ::strncmp( n, p, arg.GetLength() ) != 0 )
					{
						n = nil;
					}
				}
				else
				{
					if ( CUtils::Strincmp( n, p, arg.GetLength() ) != 0 )
					{
						n = nil;
					}
				}
			}
			else
			{
				if ( f8BitOn == true )
				{
					n = CUtils::Strstr( n, p );
				}
				else
				{
					n = CUtils::Stristr( n, p );
				}
			}

			if ( n == nil )
			{
				done	= true;
				result	= false;
				break;
			}

			if ( result == true )
			{
				n += arg.GetLength();
			}
		}
		i++;
	}

	// Check for a trailing wild card
	if ( (result == true ) && ( *n != nil ) )
	{
		i = tokenObj.Count();
		arg.Set( tokenObj.Get( i - 1 ), tokenObj.GetLength( i - 1 ) );
		if ( (CUtils::Strcmp( "*", arg.GetData() ) == 0) || (CUtils::Strcmp( "%", arg.GetData() ) == 0) )
		{
			result = true;
		}
		else
		{
			result = false;
		}
	}

	return( result );

} // DoesThisMatch



//--------------------------------------------------------------------------------------------------
//	* GetArgToken
//	
//--------------------------------------------------------------------------------------------------

Boolean CMailboxes::GetArgToken ( char *inData, CString &inCmdArgs )
{
	Boolean		result	= false;
	char	   *p		= inData;

	inCmdArgs.Clear();

	while ( (*p != '%') && (*p != '*') && (*p != nil) )
	{
		inCmdArgs.Append( *p );
		result = true;
		p++;
	}

	return( result );

} // GetArgToken



//--------------------------------------------------------------------------------------------------
//	* ListRoot
//	
//--------------------------------------------------------------------------------------------------

void CMailboxes::ListRoot ( CString &outMbList )
{
	CString		root( 64 );

	// Untagged response
	root.Set( "* " );

	if ( fCommand != nil )
	{
		// Set the command name, LIST, LSUB or FIND
		root.Append( fCommand->GetData(), fCommand->GetLength() );
	}

	root.Append( "(\\Noselect) " );	// This is a non-selectable forlder
	root.Append( kQuotedDelimStr );	// hierarchy delimiter	- "/"
	root.Append( " " );				// space
	root.Append( kEmptyFieldStr );	// empty string			- ""
	root.Append( kEOL );			// end of line marker	- "\r\n"

	outMbList.Append( root.GetData() );

} // ListRoot



//--------------------------------------------------------------------------------------------------
//	* GetFullPath
//
//--------------------------------------------------------------------------------------------------

void CMailboxes::GetFullPath ( CString &inMailboxPath, CMailSpool *inMailboxSpool, const char *inDelim )
{
	Boolean		root		= false;
	ObjID		parentID;
	CMailSpool *mbSpool		= nil;

	try
	{
		inMailboxPath.Set( (char *)inMailboxSpool->GetMailSpoolName() );

		parentID = inMailboxSpool->GetParentID();

		while ( parentID != 0 )
		{
			mbSpool = CMailSpool::FindByID( parentID );
			if ( mbSpool != nil )
			{
				const char *mbName = mbSpool->GetMailSpoolName();
				if ( mbName[ 0 ] == '\0' )
				{
					mbSpool->SetMailSpoolName( "Empty_Mailbox" );
				}

				inMailboxPath.Prepend( inDelim );
				inMailboxPath.Prepend( (char *)mbSpool->GetMailSpoolName() );

				if ( mbSpool->GetParentID() == CMailSpool::kRootParent )
				{
					parentID = 0;
				}
				else
				{
					parentID = mbSpool->GetParentID();
				}

				mbSpool->Done( mbSpool );
			}
			else
			{
				parentID = 0;
			}
		}
	}

	catch( long err )
	{
		mbSpool->Done( mbSpool );
	}

} // GetFullPath



//--------------------------------------------------------------------------------------------------
//	* IsInHierarchy
//
//--------------------------------------------------------------------------------------------------

Boolean CMailboxes::IsInHierarchy ( ObjID inTargetID, ObjID inParentID )
{
	Boolean			done	= false;
	Boolean			result	= false;
	ObjID			currID	= inParentID;
	CMailSpool	   *mbSpool	= nil;

	Try_
	{
		while ( !done )
		{
			if ( currID == inTargetID )
			{
				// This is what we are looking for
				result	= true;
				done	= true;
			}
			else
			{
				if ( currID == CMailSpool::kRootParent )
				{
					// We have reached the bottom of the list, time to bail
					done = true;
				}
				else
				{
					mbSpool = CMailSpool::FindByID( currID );
					if ( mbSpool != nil )
					{
						currID = mbSpool->GetParentID();
						mbSpool->Done( mbSpool );
					}
					else
					{
						done = true;
					}
				}
			}
		}
	}

	Catch_ ( err )
	{
		mbSpool->Done( mbSpool );
	}

	return( result );

} // IsInHierarchy



//--------------------------------------------------------------------------------------------------
//	* GetMailboxCount
//
//--------------------------------------------------------------------------------------------------

uInt32 CMailboxes::GetMailboxCount ( void )
{
	OSErr			result;
	uInt32			count	= 0;
	SDBIterator		iterator;

	result = gDB->CreateIterator( kMailSpoolSignature, &iterator, fAccountID );
	if ( result == kNoErr )
	{
		result = gDB->GetIteratorItemCnt( &iterator, count );
	}
	result = gDB->ReleaseIterator( &iterator );

	return( count );

} // GetMailboxCount

