/*
	File:		CEnvelope.10.1.cpp

	Contains:	C++ implemenation of the message envelope container class

	Copyright:	© 2003 by Apple Computer, Inc., all rights reserved.

 	NOT_FOR_OPEN_SOURCE <to be reevaluated at a later time>

	Change History:
*/


// App
#include <time.h>

#include "CEnvelope.10.1.h"
#include "CMessagePart.10.1.h"
#include "CSmallMsgPart.10.1.h"
#include "CMailSpool.10.1.h"
#include "Database.10.1.h"
#include "CRootObject.10.1.h"
#include "UHeaders.10.1.h"
#include "COSUtils.h"
#include "CUtils.h"
#include "CGlobals.h"


extern CRootObject_10_1 *gRootObj_10_1;

Boolean	CEnvelope_10_1::GetSetFields	(const eFieldDataRequest_10_1 inFieldRequest, const void *inObjDataPtr, void *outFieldData)
{
	Boolean	result = false;
	CEnvelopeData_10_1	*theData = (CEnvelopeData_10_1 *) inObjDataPtr;
	CEnvelope_10_1		*aTempObject	= NULL;
	ObjID			*anObjIDPtr = (ObjID *) outFieldData;

	switch (inFieldRequest)
	{
		case kSetObjID:
			if (theData != NULL)
			{
				theData->fEnvelopeID = *anObjIDPtr;
			}
			break;
		
		case k2ndIDRequest:
			if (theData != NULL)
			{
				if (theData->fViaCode == CEnvelope_10_1::kViaDoorNail)
				{
					if (gRootObj_10_1 != NULL)
					{
						if (gRootObj_10_1->GetEnvelopeDieSpoolID() != 0)
						{
							*anObjIDPtr = gRootObj_10_1->GetEnvelopeDieSpoolID();
							result = true;
						}
					}
				}
			}
			break;
					
		case kObjectPINGRequest:
			// cause the objects constructor to get called, so we force a check of
			// the struct alignment...
			aTempObject = new CEnvelope_10_1;
			delete aTempObject;
			break;

		case k2ndIDTargetChk:
			// fall through...
			
		default:
			result = false;
			break;
	}
	
	return result;
}

ObjID CEnvelope_10_1::GetObjectID	( void )
{
	return fEnvelopeData.fEnvelopeID;
}


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

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


CDBBaseObject_10_1 * CEnvelope_10_1::ObjectAllocNew	( void )
{
	return new CEnvelope_10_1;
}

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


void	CEnvelope_10_1::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:  CEnvelopeData_10_1		TINFO offset: 53490		(TINFO SYM file offset (hex): $1250F2)
			RecordOf
			offset 0 NamedTypeOf fDBHeader TypeDef of "Type ID 248"
			offset 12 NamedTypeOf fEnvelopeID 
			offset 16 NamedTypeOf fSenderID unsigned long 
			offset 20 NamedTypeOf fMsgTocID 
			offset 24 NamedTypeOf fVTwinReference unsigned long 
			offset 28 NamedTypeOf fRecipListHeadID 
			offset 32 NamedTypeOf fMsgPartListHeadID unsigned long 
			offset 36 NamedTypeOf fSmallMsgPartID 
			offset 40 NamedTypeOf fReserved1 unsigned long 
			offset 44 NamedTypeOf fReserved2 
			offset 48 NamedTypeOf fViaCode unsigned long 
			offset 52 NamedTypeOf fSendingHost 
			offset 308 NamedTypeOf fMessageSize unsigned long 
			offset 312 NamedTypeOf fCreationTime 
			offset 316 NamedTypeOf fWarningSentTime unsigned long 
			offset 320 NamedTypeOf fAttemptTime 
			offset 324 NamedTypeOf fTransports unsigned short 
			offset 326 NamedTypeOf fTOCEnvelopeStrOffset 
			offset 328 NamedTypeOf fTOCEnvelopeStrLength unsigned short 
			offset 330 NamedTypeOf fMessagePrefixLength 
			offset 332 NamedTypeOf fMessagePrefix TypeDef of "Type ID 288"
			offset 1356 NamedTypeOf fServerIPAddr 
			offset 1360 NamedTypeOf fFlags unsigned long 
			offset 1364 NamedTypeOf fSpoolRefCount 
			offset 1366 NamedTypeOf fHostRefCount unsigned short 
			offset 1368 NamedTypeOf fOriginalRecipientCount 
			offset 1370 NamedTypeOf fTotalRecipientCount unsigned short 
			offset 1372 NamedTypeOf fPendingRecipientCount 
			offset 1374 NamedTypeOf fDeliveredRecipients unsigned short 
			offset 1376 NamedTypeOf fErrorRecipientCount 
			offset 1378 NamedTypeOf fGroupRecipientCount unsigned short 
			offset 1380 NamedTypeOf fAutoForwardRecipientCount 
			offset 1382 NamedTypeOf fLocalRecipientCount unsigned short 
			offset 1384 NamedTypeOf fRemoteRecipientCount 
			offset 1386 NamedTypeOf fRemotePostingDone unsigned short 
			offset 1388 NamedTypeOf fMessagePartCount 
			offset 1392 NamedTypeOf fDBFooter TypeDef of "Type ID 250"
	*/

	static Boolean	aRunOnceFlag = false;	
	if (aRunOnceFlag == false)
	{
		//FileFormatSaftyChk(CEnvelopeData_10_1, fDBHeader,					0);
		//FileFormatSaftyChk(CEnvelopeData_10_1, fEnvelopeID,					12);
		//FileFormatSaftyChk(CEnvelopeData_10_1, fSenderID,					16);					// this is our sender recipient object
		//FileFormatSaftyChk(CEnvelopeData_10_1, fMsgTocID,					20);					// message table of contents ID
		//FileFormatSaftyChk(CEnvelopeData_10_1, fVTwinReference,				24);
		//FileFormatSaftyChk(CEnvelopeData_10_1, fRecipListHeadID,				28);			// 
		//FileFormatSaftyChk(CEnvelopeData_10_1, fMsgPartListHeadID,			32);			// 
		//FileFormatSaftyChk(CEnvelopeData_10_1, fSmallMsgPartID,				36);
		//FileFormatSaftyChk(CEnvelopeData_10_1, fReserved1,						40);
		//FileFormatSaftyChk(CEnvelopeData_10_1, fReserved2,						44);
		//FileFormatSaftyChk(CEnvelopeData_10_1, fViaCode,						48);							// how did we get it
		//FileFormatSaftyChk(CEnvelopeData_10_1, fSendingHost[0],				52);	// the sending host name
		//FileFormatSaftyChk(CEnvelopeData_10_1, fMessageSize,					308);						// size in bytes of message (cached)
		//FileFormatSaftyChk(CEnvelopeData_10_1, fCreationTime,				312);						// time created
		//FileFormatSaftyChk(CEnvelopeData_10_1, fWarningSentTime,				316);					// time the Warning was sent...
		//FileFormatSaftyChk(CEnvelopeData_10_1, fAttemptTime,					320);						// last attempt at delivery
		//FileFormatSaftyChk(CEnvelopeData_10_1, fTransports,					324);						// AppleTalk, TCP/IP, or Bounce
		//FileFormatSaftyChk(CEnvelopeData_10_1, fTOCEnvelopeStrOffset,		326);				// Offset for TOC Envelope string
		//FileFormatSaftyChk(CEnvelopeData_10_1, fTOCEnvelopeStrLength,		328);				// Lenght of TOC Envelope string
		//FileFormatSaftyChk(CEnvelopeData_10_1, fMessagePrefixLength,			330);				// Length of prepended headers
		//FileFormatSaftyChk(CEnvelopeData_10_1, fMessagePrefix[0],			332);// prepended headers + TOC Envelope string	
		//FileFormatSaftyChk(CEnvelopeData_10_1, fServerIPAddr,				1356);						// server IP Address (used for multihoming)
		//FileFormatSaftyChk(CEnvelopeData_10_1, fFlags,						1360);								// envelope flags
		//FileFormatSaftyChk(CEnvelopeData_10_1, fSpoolRefCount,				1364);				// Number of CEnvelopeInfo objects referring to me
		//FileFormatSaftyChk(CEnvelopeData_10_1, fHostRefCount,				1366);				// Number of Host Spool objects referring to me
		//FileFormatSaftyChk(CEnvelopeData_10_1, fOriginalRecipientCount,		1368);	// # Before routing expansions
		//FileFormatSaftyChk(CEnvelopeData_10_1, fTotalRecipientCount,			1370);		// # Currently
		//FileFormatSaftyChk(CEnvelopeData_10_1, fPendingRecipientCount,		1372);		// # Pending Routing
		//FileFormatSaftyChk(CEnvelopeData_10_1, fDeliveredRecipients,			1374);		// # Delivered To Successfully
		//FileFormatSaftyChk(CEnvelopeData_10_1, fErrorRecipientCount,			1376);		// # Routing or delivery unsuccessful
		//FileFormatSaftyChk(CEnvelopeData_10_1, fGroupRecipientCount,			1378);		// # of groups
		//FileFormatSaftyChk(CEnvelopeData_10_1, fAutoForwardRecipientCount,	1380);	// # of autoforwards
		//FileFormatSaftyChk(CEnvelopeData_10_1, fLocalRecipientCount,			1382);		// # of local recipients
		//FileFormatSaftyChk(CEnvelopeData_10_1, fRemoteRecipientCount,		1384);		// # of remote recipients
		//FileFormatSaftyChk(CEnvelopeData_10_1, fRemotePostingDone,			1386);			// true when the router is done posting the message to _ALL_ hosts
		//FileFormatSaftyChk(CEnvelopeData_10_1, fMessagePartCount,			1388);
		//FileFormatSaftyChk(CEnvelopeData_10_1, fDBFooter,					1392);
//		this->ReportBackwardCompatibility(sizeof(CEnvelopeData_10_1), 1396, "CEnvelopeData_10_1", "SIZEOF()");
//		this->ReportBackwardCompatibility(kEnvelopeDataSize,	 1396, "CEnvelopeData_10_1", "kEnvelopeDataSize");
	}
	
	aRunOnceFlag = true;
}



CEnvelope_10_1* CEnvelope_10_1::Create ( uInt32 inViaCode, const char* inSendingHost )
{
	OSStatus		result;
	ObjID			aNewID;
	CEnvelope_10_1	   *theEnvelope = NULL;

	try
	{
		theEnvelope = new CEnvelope_10_1;
		ThrowIfMemFail_ (theEnvelope);

		(gDB_10_1->GetBaseObjectCachePtr())->LockTheCache(CEnvelope_10_1::GetObjTypeConstant());
		
		result = gDB_10_1->CreateObj( kEnvelopeSignature, aNewID, theEnvelope->GetEnvelopeData() );
		if ( result == CMailDatabase::kDBNoErr )
		{
			theEnvelope->Use();
			theEnvelope->SetViaCode(inViaCode);
			theEnvelope->SetSendingHost (inSendingHost);
			theEnvelope->SetCreationTime();
			theEnvelope->SetDirty();
		}
		else
		{
			delete theEnvelope;
			theEnvelope = NULL;
		}
		
		// denormalize ID into CEnvelope_10_1 object

		if (theEnvelope != NULL)
		{
			const char* theViaCode = NULL;

			switch ( inViaCode )
			{
				case kViaSMTP:
					theViaCode = "SMTP";
					break;
				case kViaATalk:
					theViaCode = "ATalk";
					break;
				case kViaUUCP:
					theViaCode = "UUCP";
					break;
				case kViaNDR:
					theViaCode = "NDR";
					break;
				case kViaIMAP:
					theViaCode = "IMAP";
					break;
				case kViaUnknown:
				default:
					theViaCode = "Unknown";
					break;
			}

			if (gStatMgr != NULL)
			{
				gStatMgr->AddMessage();		// Maintain statistics
			}
		}

		(gDB_10_1->GetBaseObjectCachePtr())->UnLockTheCache(CEnvelope_10_1::GetObjTypeConstant());
	}
	catch ( ExceptionCode err )
	{
	}
	
	return (theEnvelope);
} // Create


void CEnvelope_10_1::SetDirty ( void )
{
	if ((this != NULL) && (this->GetEnvelopeID() != 0))
	{
		setDirty();
	}
}

CEnvelopeData_10_1* CEnvelope_10_1::GetEnvelopeData	( void )
{
	if ( this != NULL )
	{
		return &( this->fEnvelopeData );
	}
	else
	{
		return( NULL );
	}
} // GetEnvelopeData


Boolean CEnvelope_10_1::Delete ( CEnvelope_10_1 *inEnvelope )
{
	OSStatus	result;
	Boolean		deleted = false;

	try
	{
		if (inEnvelope != NULL)
		{
			(gDB_10_1->GetBaseObjectCachePtr())->LockTheCache(CEnvelope_10_1::GetObjTypeConstant());

			ObjID theEnvelopeID = inEnvelope->GetEnvelopeID();

#if TARGET_OS_MAC && TARGET_API_MAC_OS8
			// Remove this message from the VTwin index
			if ( gIndexing != nil )
			{
				// Has this message been added to the crrent index
				if ( inEnvelope->GetVTwinReference() == gIndexing->GetIndexRefNum() )
				{
					// We now owne it
					inEnvelope->SetVTwinReference( 0 );
					gIndexing->CleanIndex( inEnvelope );
				}
			}
#endif
			inEnvelope->DeleteSender();
			inEnvelope->DeleteAllRecipients();
			inEnvelope->DeleteAllMessageParts();
			inEnvelope->DeleteMessageTOC();
			
			result = gDB_10_1->RemoveObj( kEnvelopeSignature, inEnvelope->GetEnvelopeID() );
			deleted = (result == kNoErr);

			if ( deleted == true )
			{
				inEnvelope->fEnvelopeData.fEnvelopeID = 0;
			}

			if ( gStatMgr != NULL )
			{
				gStatMgr->RemoveMessage();		// Maintain statistics
			}

			(gDB_10_1->GetBaseObjectCachePtr())->UnLockTheCache(CEnvelope_10_1::GetObjTypeConstant());
		}
	}
	catch ( ExceptionCode err )
	{
		(gDB_10_1->GetBaseObjectCachePtr())->UnLockTheCache(CEnvelope_10_1::GetObjTypeConstant());
	}

	return( deleted );
} // Delete

void CEnvelope_10_1::DeleteMessageTOC ( void )
{
}


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

	result = gDB_10_1->GetObjectCount( kEnvelopeSignature, aCount );

	if (result != kNoErr)
	{
		aCount = 0;
	}
	
	return aCount;
} // Count



SDBIterator_10_1* CEnvelope_10_1::GetEnvelopeIterator ( void )
{
	OSErr			result;
	SDBIterator_10_1	   *aSDBIterator_10_1 = new SDBIterator_10_1(gDB_10_1);

	if ( aSDBIterator_10_1 != NULL )
	{
		result = gDB_10_1->CreateIterator( kEnvelopeInfoSignature, aSDBIterator_10_1 );
		if ( result != kNoErr )
		{
			delete aSDBIterator_10_1;
			aSDBIterator_10_1 = NULL;
		}
	}
	
	return aSDBIterator_10_1;
} // GetEnvelopeIterator


void CEnvelope_10_1::ReleaseEnvelopeIterator ( SDBIterator_10_1* &inIterator )
{
	OSErr			result;

	if (inIterator != NULL)
	{
		result = gDB_10_1->ReleaseIterator( inIterator );

		delete inIterator;
		inIterator = NULL;
	}
} // ReleaseEnvelopeIterator


#pragma mark -

CEnvelope_10_1::CEnvelope_10_1 ( void ) :
	CDBMailBaseObject_10_1(	&fEnvelopeData.fDBHeader,
							&fEnvelopeData.fDBFooter,
							&fEnvelopeData,
							CEnvelope_10_1::GetObjTypeConstant(),
							CEnvelope_10_1::GetObjVersConstant(),
							CEnvelope_10_1::GetObjSizeConstant() )
{
	fEnvelopeData.fEnvelopeID					= 0;	// this is us (denormalized)
	fEnvelopeData.fSenderID						= 0;	// this is our sender recipient object
	fEnvelopeData.fMsgTocID						= 0;	// message table of contents ID
	fEnvelopeData.fRecipListHeadID				= 0;	// 
	fEnvelopeData.fMsgPartListHeadID			= 0;	// 
	fEnvelopeData.fSmallMsgPartID				= 0;
	fEnvelopeData.fViaCode						= 0;	// how did we get it
	fEnvelopeData.fMessageSize					= 0;	// size in bytes of message (cached)
	fEnvelopeData.fCreationTime					= 0;	// time created
	fEnvelopeData.fWarningSentTime				= 0;	// time the Warning was sent...
	fEnvelopeData.fAttemptTime					= 0;	// last attempt at delivery
	fEnvelopeData.fTransports					= 0;	// AppleTalk, TCP/IP, or Bounce
	fEnvelopeData.fTOCEnvelopeStrOffset			= 0;	// TOC Envelope string offset
	fEnvelopeData.fTOCEnvelopeStrLength			= 0;	// TOC Envelope string length
	fEnvelopeData.fMessagePrefixLength			= 0;	// Length of prepended headers
	fEnvelopeData.fServerIPAddr					= 0;	// server IP Address (used for multihoming)
	fEnvelopeData.fFlags						= 0;	// envelope flags
	fEnvelopeData.fSpoolRefCount				= 0;	// Number of CEnvelopeInfo objects referring to me
	fEnvelopeData.fHostRefCount					= 0;	// Number of Host Spool objects referring to me
	fEnvelopeData.fOriginalRecipientCount		= 0;	// # Before routing expansions
	fEnvelopeData.fTotalRecipientCount			= 0;	// # Currently
	fEnvelopeData.fPendingRecipientCount		= 0;	// # Pending Routing
	fEnvelopeData.fDeliveredRecipients			= 0;	// # Delivered To Successfully
	fEnvelopeData.fErrorRecipientCount			= 0;	// # Routing or delivery unsuccessful
	fEnvelopeData.fGroupRecipientCount			= 0;	// # of groups
	fEnvelopeData.fAutoForwardRecipientCount	= 0;	// # of autoforwards
	fEnvelopeData.fLocalRecipientCount			= 0;	// # of local recipients
	fEnvelopeData.fRemoteRecipientCount			= 0;	// # of remote recipients
	fEnvelopeData.fRemotePostingDone			= 0;	// true when the router is done posting the message to _ALL_ hosts
	fEnvelopeData.fMessagePartCount				= 0;
	fEnvelopeData.fVTwinReference				= 0;
	::memset( fEnvelopeData.fSendingHost, 0, sizeof(fEnvelopeData.fSendingHost) );		// Sending host name
	::memset( fEnvelopeData.fMessagePrefix, 0, sizeof(fEnvelopeData.fMessagePrefix) );	// Message headers prefix

	// Reserved
	fEnvelopeData.fReserved1	= kReservedConst;
	fEnvelopeData.fReserved2	= kReservedConst;

	fCacheFullMessageSize		= 0;
	
	this->ChkCompilerStructAlignment();
} // CEnvelope_10_1

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

#pragma mark -

ObjID CEnvelope_10_1::GetEnvelopeID ( void )
{
	return ( fEnvelopeData.fEnvelopeID );
} // GetEnvelopeID


ObjID CEnvelope_10_1::GetSenderID ( void )
{
	return ( fEnvelopeData.fSenderID );
} // GetSenderID


void CEnvelope_10_1::SetSenderID ( ObjID inSenderID )
{
	fEnvelopeData.fSenderID = inSenderID;
	this->SetDirty();
} // SetSenderID


ObjID CEnvelope_10_1::GetMessageTocID ( void )
{
	return( fEnvelopeData.fMsgTocID );
} // GetMessageTocID


void CEnvelope_10_1::SetMessageTocID ( ObjID inMsgTocID )
{
	if ( fEnvelopeData.fMsgTocID != inMsgTocID )
	{
		fEnvelopeData.fMsgTocID = inMsgTocID;
		this->SetDirty();
	}
} // SetMessageTocID

#pragma mark -


uInt32 CEnvelope_10_1::GetViaCode ( void )
{
	return ( fEnvelopeData.fViaCode );
} // GetViaCode


void CEnvelope_10_1::SetViaCode ( uInt32 inViaCode )
{
	fEnvelopeData.fViaCode = inViaCode;
	this->SetDirty();
} // SetViaCode


const char* CEnvelope_10_1::GetSendingHost ( void )
{
	return( fEnvelopeData.fSendingHost );
} // GetSendingHost


void CEnvelope_10_1::SetSendingHost ( const char* inSendingHost )
{
	CUtils::Strncpy( fEnvelopeData.fSendingHost, inSendingHost, kMaxHostNameLength );
	this->SetDirty();
} // SetSendingHost



//--------------------------------------------------------------------------------------------------
//	* GetMessagePrefixLength
// 
//--------------------------------------------------------------------------------------------------

uInt16 CEnvelope_10_1::GetMessagePrefixLength ( void )
{
	return ( fEnvelopeData.fMessagePrefixLength );
} // GetMessagePrefixLength



//--------------------------------------------------------------------------------------------------
//	* GetMessagePrefix
// 
//--------------------------------------------------------------------------------------------------

char* CEnvelope_10_1::GetMessagePrefix ( void )
{
	return( fEnvelopeData.fMessagePrefix );
} // GetMessagePrefix



//--------------------------------------------------------------------------------------------------
//	* GetFullMessagePrefix
// 
//--------------------------------------------------------------------------------------------------

void CEnvelope_10_1::GetFullMessagePrefix ( CString &outMessagePrefix )
{
	outMessagePrefix.Clear();
	if ((this != NULL) && (this->GetMessagePrefixLength() != 0))
	{
		outMessagePrefix.Sprintf(this->GetMessagePrefix(),
									this->GetSendingHost(),
									this->GetEnvelopeID(),
									UHeaders_10_1::GetMsgviaString(this));
	}
} // GetFullMessagePrefix



//--------------------------------------------------------------------------------------------------
//	* SetMessagePrefix
// 
//--------------------------------------------------------------------------------------------------

void CEnvelope_10_1::SetMessagePrefix ( char* inData, uInt16 inLength )
{
	uInt16	storageLen;
	uInt16	dataLen;

	dataLen = inLength;

	// Determin the amount of room left for the header
	//	- This is only if the envelope string was placed here before the prefix (not bloody likely)
	storageLen	= (kMessagePrefixSize - 1) - (fEnvelopeData.fTOCEnvelopeStrLength + 1);
	if ( dataLen >= storageLen )
	{
		// We need the room taken by the Envelope String
		fEnvelopeData.fTOCEnvelopeStrOffset	= 0;
		fEnvelopeData.fTOCEnvelopeStrLength	= 0;

		// Nuke any prefious data
		::memset( fEnvelopeData.fMessagePrefix, 0, sizeof( fEnvelopeData.fMessagePrefix ) );
		if ( dataLen >= kMessagePrefixSize )
		{
			dataLen = kMessagePrefixSize - 1;
		}
	}

	// Eliminate previous length from the total message length (if any)
	if ( fEnvelopeData.fMessagePrefixLength != 0 )
	{
		fEnvelopeData.fMessageSize -= fEnvelopeData.fMessagePrefixLength;
	}

	fEnvelopeData.fMessagePrefixLength = dataLen;
	::memcpy( &fEnvelopeData.fMessagePrefix, inData, dataLen );
	fEnvelopeData.fMessagePrefix[ dataLen ] = '\0';

	// Increment by prefix length
	fEnvelopeData.fMessageSize += fEnvelopeData.fMessagePrefixLength;

	fCacheFullMessageSize = 0;
	this->SetDirty();

} // SetMessagePrefix



//--------------------------------------------------------------------------------------------------
//	* GetTOCEnvStringLength
// 
//--------------------------------------------------------------------------------------------------

uInt16 CEnvelope_10_1::GetTOCEnvStringLength ( void )
{
	return ( fEnvelopeData.fTOCEnvelopeStrLength );
} // GetTOCEnvStringLength



//--------------------------------------------------------------------------------------------------
//	* GetTOCEnvString
// 
//--------------------------------------------------------------------------------------------------

char* CEnvelope_10_1::GetTOCEnvString ( void )
{
	return( &fEnvelopeData.fMessagePrefix[ fEnvelopeData.fTOCEnvelopeStrOffset ] );
} // GetTOCEnvString



//--------------------------------------------------------------------------------------------------
//	* SetTOCEnvString
//
//		- Always put this tring at the end of the storage buffer
//
//--------------------------------------------------------------------------------------------------

void CEnvelope_10_1::SetTOCEnvString ( char *inData, uInt16 inLength )
{
	uInt16	storageLen = kMessagePrefixSize - (fEnvelopeData.fMessagePrefixLength + 1);

	// Determin if there is room for the envelope string
	//	- Add 1 to the length to account for the null termination
	if ( (inLength +1) > storageLen )
	{
		// Not enough room so we bail
		fEnvelopeData.fTOCEnvelopeStrOffset = 0;
		fEnvelopeData.fTOCEnvelopeStrLength = 0;
		return;
	}

	// Put it at the end of the storage buffer
	fEnvelopeData.fTOCEnvelopeStrOffset = kMessagePrefixSize - (inLength + 1);

	// Set the length of the data
	fEnvelopeData.fTOCEnvelopeStrLength = inLength;

	// Set the data in the storage
	::memcpy( &fEnvelopeData.fMessagePrefix[ fEnvelopeData.fTOCEnvelopeStrOffset ], inData, inLength );
	fEnvelopeData.fMessagePrefix[ kMessagePrefixSize - 1 ] = '\0';

	this->SetDirty();

} // SetTOCEnvString



//--------------------------------------------------------------------------------------------------
//	* GetMessageSize
// 
//--------------------------------------------------------------------------------------------------

uInt32	gTotalCalls = 0;
uInt32	gTotalCacheHits = 0;

uInt32 CEnvelope_10_1::GetMessageSize ( const Boolean inUseRawMsgPrefixSize )
{
	if (this != NULL)
	{
		if (inUseRawMsgPrefixSize == true)
		{
			return ( fEnvelopeData.fMessageSize );
		}
		else
		{
			gTotalCalls++;
			
			if (fCacheFullMessageSize == 0)
			{
				CString	junkFullMsgPrefix;
				uInt32	tempSize = fEnvelopeData.fMessageSize;
				
				tempSize -= this->GetMessagePrefixLength();
				this->GetFullMessagePrefix(junkFullMsgPrefix);
				tempSize += junkFullMsgPrefix.GetLength();
				
				fCacheFullMessageSize = tempSize;
				return (tempSize);
			}
			else
			{
				gTotalCacheHits++;
			}
		}
	}
	
	return (fCacheFullMessageSize);

} // GetMessageSize


void CEnvelope_10_1::SetMessageSize ( uInt32 inMessageSize )
{
	fEnvelopeData.fMessageSize = inMessageSize;
	fCacheFullMessageSize = 0;

	this->SetDirty();
} // SetMessageSize


void CEnvelope_10_1::AddReference ( uInt32 inType )
{
	if ( this != NULL )
	{
		if ( inType == kSpoolReference )
		{
			fEnvelopeData.fSpoolRefCount++;
		}
		else if ( inType == kHostReference )
		{
			fEnvelopeData.fHostRefCount++;
		}

		this->SetDirty();
		this->ReleaseObjectLock(true);
	}
} // AddReference


Boolean CEnvelope_10_1::GetRemotePostingFlag ( void )
{
	return ( this->fEnvelopeData.fRemotePostingDone == true );
} // GetRemotePostingFlag


void CEnvelope_10_1::SetRemotePostingFlag ( Boolean inPostingFlag )
{
	if ( this != NULL )
	{
		if ( inPostingFlag != this->fEnvelopeData.fRemotePostingDone )
		{
			this->fEnvelopeData.fRemotePostingDone = inPostingFlag;
			this->SetDirty();
		}

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

ObjID CEnvelope_10_1::GetRecipListHeadID ( void )
{
	return( fEnvelopeData.fRecipListHeadID );
} // GetRecipListHeadID


void CEnvelope_10_1::SetRecipientListHeadID ( ObjID inListHeadID )
{
	if ( fEnvelopeData.fRecipListHeadID != inListHeadID )
	{
		fEnvelopeData.fRecipListHeadID = inListHeadID;
		this->SetDirty();
	}
} // SetRecipientListHeadID


ObjID CEnvelope_10_1::GetMsgPartListHeadID ( void )
{
	return( fEnvelopeData.fMsgPartListHeadID );
} // GetMsgPartListHeadID


void CEnvelope_10_1::SetMsgPartListHeadID ( ObjID inListHeadID )
{
	if ( inListHeadID != fEnvelopeData.fMsgPartListHeadID )
	{
		fEnvelopeData.fMsgPartListHeadID = inListHeadID;
		this->SetDirty();
	}
} // SetMsgPartListHeadID


ObjID CEnvelope_10_1::GetSmallMsgPartID ( void )
{
	return( fEnvelopeData.fSmallMsgPartID );
} // GetSmallMsgPartID


void CEnvelope_10_1::SetSmallMsgPartID ( const ObjID inSmallMsgPartID )
{
	if ( inSmallMsgPartID != fEnvelopeData.fSmallMsgPartID )
	{
		fEnvelopeData.fSmallMsgPartID = inSmallMsgPartID;
		this->SetDirty();
	}
} // SetSmallMsgPartID

uInt32 CEnvelope_10_1::GetServerIPAddr ( void )
{
	return( fEnvelopeData.fServerIPAddr );
} // GetServerIPAddr


void CEnvelope_10_1::SetServerIPAddr ( uInt32 inServerIPAddr )
{
	if ( inServerIPAddr != fEnvelopeData.fServerIPAddr )
	{
		fEnvelopeData.fServerIPAddr = inServerIPAddr;
		this->SetDirty();
	}
} // SetServerIPAddr

void CEnvelope_10_1::RemoveReference ( uInt32 inType )
{
	if ( this != NULL )
	{
		if ( inType == kSpoolReference )
		{
			if (fEnvelopeData.fSpoolRefCount > 0)
			{
				fEnvelopeData.fSpoolRefCount--;
			}
		}
		else if ( inType == kHostReference )
		{
			if ( fEnvelopeData.fHostRefCount > 0 )
			{
				fEnvelopeData.fHostRefCount--;
			}
		}

		this->SetDirty();

		if ( (fEnvelopeData.fSpoolRefCount + fEnvelopeData.fHostRefCount) == 0 )
		{
			 this->SetViaCode(kViaDoorNail);
		}
		
		this->ReleaseObjectLock(true);
	}
} // RemoveReference


uInt32 CEnvelope_10_1::GetRefCount (uInt32 inType)
{
	if ( inType == kSpoolReference )
	{
		return ( fEnvelopeData.fSpoolRefCount );
	}
	else if ( inType == kHostReference )
	{
		return ( fEnvelopeData.fHostRefCount );
	}

	return( 0 );
} // GetRefCount


void CEnvelope_10_1::AddTransport ( uInt16 inTransport )
{
	fEnvelopeData.fTransports |= inTransport;
	this->SetDirty();
} // AddTransport


uInt16 CEnvelope_10_1::GetTransports ( void )
{
	return( fEnvelopeData.fTransports );
} // GetTransports


uInt32 CEnvelope_10_1::GetEnvWarningTime ( void )
{
	return( fEnvelopeData.fWarningSentTime );
} // GetTransports


void CEnvelope_10_1::SetEnvWarningTime ( const uInt32 inWarningSentTime )
{
	if (fEnvelopeData.fWarningSentTime != inWarningSentTime)
	{
		fEnvelopeData.fWarningSentTime = inWarningSentTime;
		this->SetDirty();
	}
} // GetTransports


#pragma mark -


void CEnvelope_10_1::AddRecipient ( ObjID inRecipientID )
{
} // AddRecipient



void CEnvelope_10_1::DeleteAllRecipients ( void )
{
} // DeleteAllRecipients



uInt16 CEnvelope_10_1::GetRecipientCount ( uInt32 inType )
{
	switch (inType)
	{
		case kOriginalCount:
			return( fEnvelopeData.fOriginalRecipientCount );
			break;
		case kTotalCount:
			return( fEnvelopeData.fTotalRecipientCount );
			break;
		case kPendingRoutingCount:
			return( fEnvelopeData.fPendingRecipientCount );
			break;
		case kDeliveredCount:
			return( fEnvelopeData.fDeliveredRecipients );
			break;
		case kErrorCount:
			return( fEnvelopeData.fErrorRecipientCount );
			break;
		case kGroupCount:
			return( fEnvelopeData.fGroupRecipientCount );
			break;
		case kAutoForwardCount:
			return( fEnvelopeData.fAutoForwardRecipientCount );
			break;
		case kLocalCount:
			return( fEnvelopeData.fLocalRecipientCount );
			break;
		case kRemoteCount:
			return( fEnvelopeData.fRemoteRecipientCount );
			break;
		default:
			return ( 0 );
			break;
	}
} // GetRecipientCount

void CEnvelope_10_1::SetRecipientCount ( uInt32 inType, uInt16 inCount )
{
	switch (inType)
	{
		case kOriginalCount:
			fEnvelopeData.fOriginalRecipientCount = inCount;
			break;
		case kTotalCount:
			fEnvelopeData.fTotalRecipientCount = inCount;
			break;
		case kPendingRoutingCount:
			fEnvelopeData.fPendingRecipientCount = inCount;
			break;
		case kDeliveredCount:
			fEnvelopeData.fDeliveredRecipients = inCount;
			break;
		case kErrorCount:
			fEnvelopeData.fErrorRecipientCount = inCount;
			break;
		case kGroupCount:
			fEnvelopeData.fGroupRecipientCount = inCount;
			break;
		case kAutoForwardCount:
			fEnvelopeData.fAutoForwardRecipientCount = inCount;
			break;
		case kLocalCount:
			fEnvelopeData.fLocalRecipientCount = inCount;
			break;
		case kRemoteCount:
			fEnvelopeData.fRemoteRecipientCount = inCount;
			break;
		default:
			return;
			break;
	}

	this->SetDirty();
} // SetRecipientCount


void CEnvelope_10_1::IncrementRecipientCount ( uInt32 inType )
{
	switch (inType)
	{
		case kOriginalCount:
			fEnvelopeData.fOriginalRecipientCount++;
			break;
		case kTotalCount:
			fEnvelopeData.fTotalRecipientCount++;
			break;
		case kPendingRoutingCount:
			fEnvelopeData.fPendingRecipientCount++;
			break;
		case kDeliveredCount:
			fEnvelopeData.fDeliveredRecipients++;
			break;
		case kErrorCount:
			fEnvelopeData.fErrorRecipientCount++;
			break;
		case kGroupCount:
			fEnvelopeData.fGroupRecipientCount++;
			break;
		case kAutoForwardCount:
			fEnvelopeData.fAutoForwardRecipientCount++;
			break;
		case kLocalCount:
			fEnvelopeData.fLocalRecipientCount++;
			break;
		case kRemoteCount:
			fEnvelopeData.fRemoteRecipientCount++;
			break;
		default:
			return;
			break;
	}

	this->SetDirty();
} // IncrementRecipientCount

void CEnvelope_10_1::DecrementRecipientCount ( uInt32 inType )
{
	switch (inType)
	{
		case kOriginalCount:
			if ( fEnvelopeData.fOriginalRecipientCount > 0 )
				fEnvelopeData.fOriginalRecipientCount--;
			break;
		case kTotalCount:
			if ( fEnvelopeData.fTotalRecipientCount > 0 )
				fEnvelopeData.fTotalRecipientCount--;
			break;
		case kPendingRoutingCount:
			if ( fEnvelopeData.fPendingRecipientCount > 0 )
				fEnvelopeData.fPendingRecipientCount--;
			break;
		case kDeliveredCount:
			if ( fEnvelopeData.fDeliveredRecipients > 0 )
				fEnvelopeData.fDeliveredRecipients--;
			break;
		case kErrorCount:
			if ( fEnvelopeData.fErrorRecipientCount > 0 )
				fEnvelopeData.fErrorRecipientCount--;
			break;
		case kGroupCount:
			if ( fEnvelopeData.fGroupRecipientCount > 0 )
				fEnvelopeData.fGroupRecipientCount--;
			break;
		case kAutoForwardCount:
			if ( fEnvelopeData.fAutoForwardRecipientCount > 0 )
				fEnvelopeData.fAutoForwardRecipientCount--;
			break;
		case kLocalCount:
			if ( fEnvelopeData.fLocalRecipientCount > 0 )
				fEnvelopeData.fLocalRecipientCount--;
			break;
		case kRemoteCount:
			if ( fEnvelopeData.fRemoteRecipientCount > 0 )
				fEnvelopeData.fRemoteRecipientCount--;
			break;
		default:
			return;
			break;
	}

	this->SetDirty();
} // DecrementRecipientCount


Boolean CEnvelope_10_1::DeleteSender ( void )
{
	return( true );
} // DeleteSender

#pragma mark -


void CEnvelope_10_1::AddMessagePart ( ObjID inMessagePartID, const Boolean inSmallMsgPartFlag )
{
	if (inSmallMsgPartFlag == false)
	{
		CMessagePart_10_1* theMessagePart = CMessagePart_10_1::FindByID( inMessagePartID );
		if (theMessagePart != NULL)
		{
			if (this->GetMsgPartListHeadID() == 0)
			{
				this->SetMsgPartListHeadID(inMessagePartID);
			}
		
			this->fEnvelopeData.fMessageSize += theMessagePart->GetDataLength();
			this->fEnvelopeData.fMessagePartCount++;
			theMessagePart->SetMsgHasBeenAttached(true);
			theMessagePart->Done(theMessagePart);
			fCacheFullMessageSize = 0;
		}
	}
	else
	{
		CSmallMsgPart_10_1 *theSmallMsgPart = CSmallMsgPart_10_1::FindByID(inMessagePartID);
		if (theSmallMsgPart != NULL)
		{
			this->SetSmallMsgPartID(inMessagePartID);
			this->fEnvelopeData.fMessageSize += theSmallMsgPart->GetDataLength();
			this->fEnvelopeData.fMessagePartCount++;
			theSmallMsgPart->SetMsgHasBeenAttached(true);
			theSmallMsgPart->Done(theSmallMsgPart);
			fCacheFullMessageSize = 0;
		}
	}

	this->SetDirty();
} // AddMessagePart


void CEnvelope_10_1::DeleteAllMessageParts ( void )
{
	Boolean				successful = false;

	try
	{
		ThrowIfNULL_(this);

		CMessagePart_10_1 *theMessagePart;
		ObjID theMsgPartID = this->GetMsgPartListHeadID();
		while ( theMsgPartID != 0 )
		{
			theMessagePart = CMessagePart_10_1::FindByID(theMsgPartID);
			if (theMessagePart != NULL)
			{
				theMsgPartID = theMessagePart->GetNextMessagePartID();

				// Deletion will move iterator forward if successful
				successful = CMessagePart_10_1::Delete( theMessagePart );
				theMessagePart->Done(theMessagePart);
				
				// If successfully deleted, update the envelope's count
				if ( successful )
				{
					if ( fEnvelopeData.fMessagePartCount > 0 )
					{
						fEnvelopeData.fMessagePartCount--;
						this->SetDirty();
					}
				}
			}
			else
			{
				theMsgPartID = 0;
			}
		}

		theMsgPartID = this->GetSmallMsgPartID();
		if (theMsgPartID != 0)
		{
			CSmallMsgPart_10_1* aSmallMsgPart = NULL;
			
			aSmallMsgPart = CSmallMsgPart_10_1::FindByID(theMsgPartID);
			if (aSmallMsgPart != NULL)
			{
				successful = CSmallMsgPart_10_1::Delete( aSmallMsgPart );
				aSmallMsgPart->Done(aSmallMsgPart);
				
				// If successfully deleted, update the envelope's count
				if ( successful )
				{
					if ( fEnvelopeData.fMessagePartCount > 0 )
					{
						fEnvelopeData.fMessagePartCount--;
						this->SetDirty();
					}
				}
			}
		}

		this->SetDirty();
	}
	catch ( ExceptionCode err )
	{
	}
} // DeleteAllMessageParts


uInt32 CEnvelope_10_1::GetMessagePartCount ( void )
{
	return ( fEnvelopeData.fMessagePartCount );
} // GetMessagePartCount



uInt32 CEnvelope_10_1::GetVTwinReference ( void )
{
	return ( fEnvelopeData.fVTwinReference );
} // GetVTwinReference


// Set the V-Twin reference

void CEnvelope_10_1::SetVTwinReference ( uInt32 inRef )
{
	if ( fEnvelopeData.fVTwinReference != inRef )
	{
		fEnvelopeData.fVTwinReference = inRef;
		this->SetDirty();
	}
} // SetVTwinReference


void CEnvelope_10_1::SetCreationTime ( void )
{
	fEnvelopeData.fCreationTime = ::time( NULL );
	this->SetDirty();
} // SetCreationTime


uInt32 CEnvelope_10_1::GetCreationTime ( void )
{
	return ( fEnvelopeData.fCreationTime );
} // GetCreationTime


void CEnvelope_10_1::SetLastAttemptTime ( void )
{
	fEnvelopeData.fAttemptTime = ::time( NULL );
	this->SetDirty();
} // SetLastAttemptTime


uInt32 CEnvelope_10_1::GetLastAttemptTime ( void )
{
	return ( fEnvelopeData.fAttemptTime );
} // GetLastAttemptTime



uInt32 CEnvelope_10_1::GetEnvelopeFlags ( void )
{
	return ( fEnvelopeData.fFlags );
} // GetEnvelopeFlags


void CEnvelope_10_1::SetEnvelopeFlags ( uInt32 inFlags )
{
	if ( fEnvelopeData.fFlags != inFlags )
	{
		fEnvelopeData.fFlags = inFlags;
		this->SetDirty();
	}
} // SetEnvelopeFlags


//--------------------------------------------------------------------------------------------------
//	* GetTOCSemaphore
//
//--------------------------------------------------------------------------------------------------

ExceptionCode CEnvelope_10_1::GetTOCSemaphore ( const Boolean inWaitForTOCFlag )
{
	return (this->GetObjectLock(inWaitForTOCFlag));
} // GetTOCSemaphore



//--------------------------------------------------------------------------------------------------
//	* SetTOCSemaphore
//
//--------------------------------------------------------------------------------------------------

void CEnvelope_10_1::ReleaseTOCSemaphore ( const Boolean inNotifyOtherThreadsFlag )
{
	this->ReleaseObjectLock(inNotifyOtherThreadsFlag);
} // SetTOCSemaphore



//--------------------------------------------------------------------------------------------------
//	* GetIndexSemaphore
//
//--------------------------------------------------------------------------------------------------

ExceptionCode CEnvelope_10_1::GetIndexSemaphore ( const Boolean inWaitForIndexFlag )
{
	ExceptionCode grabError;

	return( grabError = 0 );
} // GetIndexSemaphore



//--------------------------------------------------------------------------------------------------
//	* SetIndexSemaphore
//
//--------------------------------------------------------------------------------------------------

void CEnvelope_10_1::ReleaseIndexSemaphore ( const Boolean inNotifyOtherThreadsFlag )
{
} // SetIndexSemaphore


