// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
//

#include <e32wins.h>

#include "TMsvServerStoreManager.h"
#include "MSVUTILS.H"
#include "MSVSERV.H"
#include "MSVPANIC.H"
#include "MSVAPI.H"
#include "msvindexadapter.h"
#include "msvpreferreddrivelist.h"

TMsvServerStoreManager::TMsvServerStoreManager() : iMsvServer(NULL),iFs(NULL)
	{
	}

void TMsvServerStoreManager::SetMsvServerAndFileSession(CMsvServer& aMsvServer,RFs& aFs)
	{
	iMsvServer = &aMsvServer;
	iFs = &aFs;
	}

/** Gets the filepath for the storage of binary files associated with the context

If the directory specified in the context does not exist, it is created.

@param aEntryId index id of the entry whose filepath is requested
@param aDirectory On return, contains the binary file directory path
@return KErrNone - success;
@return The server was unable to create the directory.- failure */
TInt TMsvServerStoreManager::GetFilePath(TMsvId aEntryId, TFileName& aDirectory) const
	{
	__ASSERT_ALWAYS(iMsvServer != NULL, PanicServer(EMsvServerNotValid));

	TMsvId owningService = KMsvNullIndexEntryId;
	GetOwningServiceAndFilePath(aEntryId,aDirectory,owningService);

	MsvUtils::ConstructEntryName(owningService, aEntryId, aDirectory, MsvUtils::EFolder);
	TInt error = iMsvServer->FileSession().MkDirAll(aDirectory);
	return (error==KErrAlreadyExists ? KErrNone : error);
	}

/** Gets the filestore name associated with the context

@param aEntryId Index id of the entry whose store filename is requested
@param aFileName On return, contains the store file name for the context
*/
void TMsvServerStoreManager::GetStoreFileName(TMsvId aEntryId, TFileName& aFileName) const
	{
	__ASSERT_ALWAYS(iMsvServer != NULL, PanicServer(EMsvServerNotValid));

	TMsvId owningService = KMsvNullIndexEntryId;
	GetOwningServiceAndFilePath(aEntryId,aFileName,owningService);

	MsvUtils::ConstructEntryName(owningService, aEntryId, aFileName, MsvUtils::EStore);
	}

void TMsvServerStoreManager::GetOwningServiceAndFilePath(TMsvId aEntryId,TDes& aFilePath,TMsvId& aOwningService) const
	{
	__ASSERT_ALWAYS(iMsvServer != NULL, PanicServer(EMsvServerNotValid));

#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
	//TUint driveId = MsvUtils::GetDriveId(aEntryId);
	TUint driveId = GetDriveId(aEntryId);
	TDriveNumber driveNum = EDriveC;
	CMsvPreferredDriveList::GetDriveList()->GetDriveNumber(driveId, driveNum);
	aFilePath.Zero();
	aFilePath.Append(TDriveUnit(driveNum).Name());
	TParse parse;
	parse.Set(iMsvServer->Context().MessageFolder(), NULL, NULL);
	aFilePath.Append(parse.Path());
#else
	aFilePath = iMsvServer->Context().MessageFolder();
#endif

	iMsvServer->IndexAdapter().OwningService(aEntryId, aOwningService);
	}

/** Checks if the filename length is greater than KMaxFileName(256)

If the filename is greater than KMaxFileName then it truncates the filename

@param aFilePath file path where the file is being created.
@param aFileName name of the file whose length if being checked.
@return ETrue if the filename is changed.
*/
TBool TMsvServerStoreManager::CheckFileNameLengthAndTrimL(const TDesC& aFilePath,TDes& aFileName)
	{
	__ASSERT_ALWAYS(iFs != NULL, PanicServer(EMsvFileSessionNotValid));

 	TParsePtrC filenamePPtr(aFileName);
 	TPtrC fileExtension(filenamePPtr.Ext());

#ifdef __WINS__
	TFileName winsFileName;
	TFileName mailStoreDrive;
	TDriveUnit drive(MessageServer::CurrentDriveL(*iFs));
	mailStoreDrive.Append(drive.Name());
	mailStoreDrive.Append(KPathDelimiter);
	MapEmulatedFileName(winsFileName, mailStoreDrive); // Ignoring return value
	TInt KEpocBasePathLen = winsFileName.Length();
	TInt maxFilenameLength = KMaxFileName-(aFilePath).Length()-fileExtension.Length()-KEpocBasePathLen;
#else
	TInt maxFilenameLength = KMaxFileName-(aFilePath).Length()-fileExtension.Length();
#endif
	TBool fileNameChanged = EFalse;
	// Truncate filename if too long.
	if (maxFilenameLength < aFileName.Length())
		{
		aFileName.SetLength(maxFilenameLength);
		aFileName.Append(fileExtension);

		fileNameChanged = ETrue;
		}
	return fileNameChanged;
	}

TBool TMsvServerStoreManager::GenerateFileNameIfExistsL(TDes& aFileName)
	{
	__ASSERT_ALWAYS(iFs != NULL, PanicServer(EMsvFileSessionNotValid));

	TParse fileParser;
	User::LeaveIfError(fileParser.Set(aFileName, NULL, NULL));
	TInt fileNameGenerator = 1;
	TBool fileNameChanged = EFalse;
	CDir* dir;
	TInt error =  iFs->GetDir(fileParser.DriveAndPath(), KEntryAttNormal, ESortNone, dir);
	if (error==KErrNone)
		{
		CleanupStack::PushL(dir);
		TInt fileCount=dir->Count();
		while(fileCount--)
			{
			TBool open;
			TFileName filePath(aFileName);
			TInt error = iFs->IsFileOpen(aFileName, open);
			// file exists
			if (error==KErrNone)
				{
				TFileName tempFileName(fileParser.DriveAndPath());
				tempFileName.Append(fileParser.Name());
				tempFileName.AppendNum(fileNameGenerator++);
				tempFileName.Append(fileParser.Ext());
				aFileName = tempFileName;
				fileNameChanged = ETrue;
				}
			else if (error==KErrNotFound)
				{
				break;
				}
			else
				{
				User::Leave(error);
				}
			}
		CleanupStack::PopAndDestroy(dir);
		}
	return fileNameChanged;
	}

// from MMsvStoreManager
TBool TMsvServerStoreManager::CreateAttachmentForWriteL(TMsvId aEntryId, TDes& aFilename, RFile& aFile)
	{
	__ASSERT_ALWAYS(iFs != NULL, PanicServer(EMsvFileSessionNotValid));

	return CreateAttachmentL(aEntryId, aFilename, aFile, *iFs);
	}

TBool TMsvServerStoreManager::CreateShareProtectedAttachmentForWriteL(TMsvId aEntryId, TDes& aFilename, RFile& aFile)
	{
	RFs fs;
	User::LeaveIfError(fs.Connect());
	User::LeaveIfError(fs.ShareProtected());

	return CreateAttachmentL(aEntryId, aFilename, aFile, fs, ETrue);
	}

TBool TMsvServerStoreManager::CreateAttachmentL(TMsvId aEntryId, TDes& aFilename, RFile& aFile, RFs& aFs,TBool aSharedAccess)
	{
	TFileName filePath;
	GetFilePath(aEntryId,filePath);
	TBool fileNameChanged = EFalse;

	if(CheckFileNameLengthAndTrimL(filePath,(TDes&)aFilename))
		{
		fileNameChanged = ETrue;
		}
		
	//for handling TBuf desc overflow
	RBuf newFilePath;
	TInt error = KErrNone;
 	newFilePath.CreateL(KMaxPath);
	newFilePath.CleanupClosePushL(); 
	newFilePath.Copy(filePath);
	if(aFilename.Length()+filePath.Length()>KMaxFileName)
		{
	newFilePath.ReAllocL(aFilename.Length()+filePath.Length());	
		}
	newFilePath.Append(aFilename);
	if (aSharedAccess)
		{
		//Shared access for reading and writing
		error = aFile.Create(aFs,newFilePath,EFileShareAny|EFileWrite);		
		}
	else
		{
		error = aFile.Create(aFs,newFilePath,EFileWrite);	
		}
	
	if(error == KErrAlreadyExists)
		{
		if(GenerateFileNameIfExistsL(newFilePath))
			{			
			fileNameChanged = ETrue;	
			}
			if (aSharedAccess)
				{
				//Shared access for reading and writing
				User::LeaveIfError(aFile.Create(aFs,newFilePath, EFileShareAny|EFileWrite)); 
				}
			else
				{
			 	User::LeaveIfError(aFile.Create(aFs,newFilePath,EFileWrite));		
				}
			
			aFilename.Copy(newFilePath);
				
		}
	else 
	   	{
		User::LeaveIfError(error);
		// return if error = KErrNone
		aFilename.Copy(newFilePath);
		}	
	CleanupStack::PopAndDestroy(&newFilePath);//newFilePath destroy 
	return fileNameChanged;
	}

void TMsvServerStoreManager::ReplaceAttachmentForWriteL(TMsvId aEntryId, TDes& aFilename, RFile& aFile)
	{
	__ASSERT_ALWAYS(iFs != NULL, PanicServer(EMsvFileSessionNotValid));

	TFileName filePath;
	GetFilePath(aEntryId, filePath);
	TParsePtrC fileName(aFilename);
	filePath.Append(fileName.NameAndExt());

	User::LeaveIfError(aFile.Replace(*iFs, filePath, EFileWrite));

	aFilename = filePath;
	}

void TMsvServerStoreManager::OpenAttachmentL(TMsvId aEntryId, const TDesC& aFilePath, RFile& aFile)
	{
	__ASSERT_ALWAYS(iFs != NULL,PanicServer(EMsvFileSessionNotValid));

	TFileName filePath;
	GetFilePath(aEntryId,filePath);
	TParsePtrC fileName(aFilePath);
	filePath.Append(fileName.NameAndExt());

	User::LeaveIfError(aFile.Open(*iFs,filePath,EFileRead|EFileShareReadersOnly));
	}

void TMsvServerStoreManager::OpenAttachmentForWriteL(TMsvId aEntryId, const TDesC& aFilePath, RFile& aFile)
	{
	__ASSERT_ALWAYS(iFs != NULL,PanicServer(EMsvFileSessionNotValid));

	TFileName filePath;
	GetFilePath(aEntryId,filePath);
	TParsePtrC fileName(aFilePath);
	filePath.Append(fileName.NameAndExt());

	User::LeaveIfError(aFile.Open(*iFs,filePath,EFileWrite));
	}


TInt TMsvServerStoreManager::DeleteAttachment(TMsvId aEntryId, const TDesC& aFilePath)
	{
	__ASSERT_ALWAYS(iFs != NULL, PanicServer(EMsvFileSessionNotValid));

	TFileName filePath;
	GetFilePath(aEntryId,filePath);
	TParsePtrC fileName(aFilePath);
	filePath.Append(fileName.NameAndExt());

	TInt error = iFs->Delete(filePath);

	if(error == KErrNotFound || error == KErrPathNotFound)
		return KErrNotFound;

	return error;
	}

TInt TMsvServerStoreManager::RenameAttachment(TMsvId aEntryId, const TDesC& aOldFilePath, const TDesC& aNewName)
	{
	__ASSERT_ALWAYS(iFs != NULL, PanicServer(EMsvFileSessionNotValid));

	TFileName filePath;
	TInt err = GetFilePath(aEntryId, filePath);

	TParsePtrC fileToRename(aOldFilePath);
	if(err==KErrNone)
		{
		filePath.Append(fileToRename.NameAndExt());
		TParse newPath;
		err = newPath.Set(aNewName, &fileToRename.FullName(), NULL);
		if( err==KErrNone )
			{
			err = iFs->Rename(filePath, newPath.FullName());
			}
		}

	return err;
	}

TBool TMsvServerStoreManager::FileExistsL(const TDesC& aFilePath)
	{
	// Use the Att method to check if file exists as it does change the
	// file and is a light-weight call
	TUint attValue = 0;
	TInt err = iFs->Att(aFilePath, attValue);

	TBool fileExists = EFalse;
	if (err == KErrNotFound || err == KErrPathNotFound)
		{
		fileExists = EFalse;
		}
	else if (err == KErrNone)
		{
		fileExists = ETrue;
		}
	else
		{
		User::Leave(err);
		}

	return fileExists;
	}

void TMsvServerStoreManager::AttachmentFilePathL(TMsvId aEntryId, TDes& aFilePath)
	{
	TFileName filePath;
	User::LeaveIfError(GetFilePath(aEntryId, filePath));

	aFilePath = filePath;
	}

TInt TMsvServerStoreManager::OpenFileStoreForRead(TMsvId aEntryId, RFile& aFile)
	{
	__ASSERT_ALWAYS(iFs != NULL, PanicServer(EMsvFileSessionNotValid));

	TFileName filePathAndName;
	GetStoreFileName(aEntryId,filePathAndName);

	TInt error = aFile.Open(*iFs,filePathAndName,EFileRead|EFileShareAny);
	if(error == KErrNotFound || error == KErrPathNotFound)
		return KErrNotFound;

	return error;
	}

void TMsvServerStoreManager::OpenTempStoreFileL(TMsvId aEntryId, RFile& aFile)
	{
	__ASSERT_ALWAYS(iFs != NULL, PanicServer(EMsvFileSessionNotValid));

	TFileName tempFilePathAndName;
	GetStoreFileName(aEntryId,tempFilePathAndName);

	tempFilePathAndName.Append(KMsvUtilsNewExtension);
	TInt error = iFs->MkDirAll(tempFilePathAndName);
	if(error == KErrNone || error == KErrAlreadyExists)
		error = aFile.Replace(*iFs,tempFilePathAndName,EFileShareExclusive|EFileWrite);

	User::LeaveIfError(error);
	}

void TMsvServerStoreManager::ReplaceFileStoreL(TMsvId aEntryId)
	{
	__ASSERT_ALWAYS(iFs != NULL, PanicServer(EMsvFileSessionNotValid));

	TFileName filePathAndName;
	
	GetStoreFileName(aEntryId,filePathAndName);
	TFileName tempFilePathAndName(filePathAndName);
	
	tempFilePathAndName.Append(KMsvUtilsNewExtension);

	TInt error = iFs->Replace(tempFilePathAndName,filePathAndName);
	

	if(error !=KErrNone)
		{
		iFs->Delete(tempFilePathAndName);
		User::Leave(error);
		}
	}

void TMsvServerStoreManager::DeleteFileStoreL(TMsvId aEntryId)
	{
	__ASSERT_ALWAYS(iFs != NULL, PanicServer(EMsvFileSessionNotValid));

	TFileName filePathAndName;
	GetStoreFileName(aEntryId,filePathAndName);

	TInt error = iFs->Delete(filePathAndName);
	if(error != KErrNone && error != KErrNotFound && error != KErrPathNotFound)
		User::Leave(error);

	// Delete the temporary store file if it exists
	filePathAndName.Append(KMsvUtilsNewExtension);
	error = iFs->Delete(filePathAndName);
	if(error != KErrNone && error != KErrNotFound && error != KErrPathNotFound)
		User::Leave(error);
	}

TBool TMsvServerStoreManager::FileStoreExistsL(TMsvId aEntryId) const
	{
	__ASSERT_ALWAYS(iMsvServer != NULL, PanicServer(EMsvServerNotValid));

	TMsvId owningService = KMsvNullIndexEntryId;
	TFileName filePathAndName;
	GetOwningServiceAndFilePath(aEntryId,filePathAndName,owningService);

	return User::LeaveIfError(MsvUtils::HasStore(iMsvServer->FileSession(),filePathAndName,owningService, aEntryId));
	}


/**
Gets the path for the file in message store for which the message Id is passed.
@param aBodyTextId The Id of the body text for which the path is required.
@param aFilepath The output parameter which contains filepath.
@return none.
*/
void TMsvServerStoreManager::BodyTextFilePathL(TMsvId aBodyTextId, TDes& aFilePath)
	{
	TFileName filePath;
	User::LeaveIfError(GetFilePath(aBodyTextId, filePath));
	aFilePath = filePath;
	}

/**
Opens the RFile for which the aFilepath is passed in read mode.
@param RFile   		Reference to RFile that needs to be opened.
@param aBodyTextId 	The Id of the bodytext.
@param aFilepath 	The path of the file to be opened.
@return none.
*/
void TMsvServerStoreManager::OpenBodyTextFileForReadL(RFile& aFile, TMsvId /*aBodyTextId*/, const TDesC& aFilePath)
	{
	__ASSERT_ALWAYS(iFs != NULL, PanicServer(EMsvFileSessionNotValid));
	
	User::LeaveIfError(aFile.Open(*iFs, aFilePath, EFileRead));
	}

/**
Creates the RFile in the aFilepath is passed.
@param RFile     	Reference to RFile that will be created.
@param aBodyTextId 	The Id of the bodytext.
@return none.
*/
void TMsvServerStoreManager::CreatePlainTextFileL(RFile& aFile, TMsvId aBodyTextId)
	{
	__ASSERT_ALWAYS(iFs != NULL, PanicServer(EMsvFileSessionNotValid));
	
	TFileName filePathAndName;
	GetFilePath(aBodyTextId, filePathAndName);
	
	TBuf<KFileNameFixedWidth> fileName;
	
	fileName.NumFixedWidth(aBodyTextId, EHex, KFileNameFixedWidth);
	filePathAndName.Append(fileName);
	
	TFileName tempFilePathAndName((filePathAndName));
	tempFilePathAndName.Append(KMsvUtilsNewExtension);
	User::LeaveIfError(aFile.Replace(*iFs, tempFilePathAndName, EFileShareExclusive|EFileWrite));
	}

/**
Deletes the RFile in the aFilepath passed.
@param aBodyTextId  The Id of the bodytext.
@return none.
*/	
void TMsvServerStoreManager::DeletePlainTextFileL(TMsvId aBodyTextId)
	{
	__ASSERT_ALWAYS(iFs != NULL, PanicServer(EMsvFileSessionNotValid));
	TFileName filePathAndName;
	GetFilePath(aBodyTextId, filePathAndName);
	
	TBuf<KFileNameFixedWidth> fileName;
	
	fileName.NumFixedWidth(aBodyTextId, EHex, KFileNameFixedWidth);
	filePathAndName.Append(fileName);
	
	TFileName tempFilePathAndName((filePathAndName));
	tempFilePathAndName.Append(KMsvUtilsNewExtension);
	// Remove the temporary file if it is there.
	TInt err = iFs->Delete(tempFilePathAndName);
	
	if (err != KErrNone && err != KErrNotFound)
		{
		User::Leave(err);
		}
	// There is no temporary file, delete the body text file.
	if (err == KErrNotFound)
		{
		TInt error = iFs->Delete(filePathAndName);
		if (error != KErrNone && error != KErrNotFound && error != KErrPathNotFound)
			{
			User::Leave(error);
			}		
		}
	}

/**
Replaces a temporary RFile with a new RFile.
@param aBodyTextId  The Id of the bodytext.
@return none.
*/
void TMsvServerStoreManager::ReplacePlainTextFileL(TMsvId aBodyTextId)
	{
	__ASSERT_ALWAYS(iFs != NULL, PanicServer(EMsvFileSessionNotValid));
	TFileName filePathAndName;
	GetFilePath(aBodyTextId, filePathAndName);
	
	TBuf<KFileNameFixedWidth> fileName;
	
	fileName.NumFixedWidth(aBodyTextId, EHex, KFileNameFixedWidth);
	filePathAndName.Append(fileName);
	
	TFileName tempFilePathAndName((filePathAndName));
	tempFilePathAndName.Append(KMsvUtilsNewExtension);
	TInt err = iFs->Replace(tempFilePathAndName,filePathAndName);
	if(err != KErrNone)
		{
		iFs->Delete(tempFilePathAndName);
		User::Leave(err);
		}
	}





#if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
/**
 * LoadHeaderL()
 * 
 * @param aMtmId : a MTM id.
 * @param aEntryId: Metadata entry Id of the message body.
 * @param iFieldPairList: Array of header fields.
 */

void TMsvServerStoreManager::LoadHeaderEntryL(const TUid& aMtmId, TMsvId aEntryId, RPointerArray<CHeaderFields>& aFieldPairList)
	{
	iMsvServer->MessageDBAdapter().LoadHeaderEntryL(aMtmId,aEntryId,aFieldPairList);
	}
	
/**
 * DeleteHeaderL()
 *
 * 
 * @param aMtmId : a MTM id.
 * @param aEntryId: Metadata entry Id of the message body.
 */

void TMsvServerStoreManager::DeleteHeaderEntryL(const TUid& aMtmId, TMsvId aEntryId)
	{
	iMsvServer->MessageDBAdapter().DeleteHeaderEntryL(aMtmId,aEntryId);	
	}


/**
 * UpdateHeaderL()
 *
 * 
 * @param aMtmId : a MTM id.
 * @param aEntryId: Metadata entry Id of the message body.
 * @param iFieldPairList: Array of header fields.
 */

void TMsvServerStoreManager::UpdateHeaderEntryL(const TUid& aMtmId, TMsvId aEntryId, const RPointerArray<CHeaderFields>& aFieldPairList)
	{
	iMsvServer->MessageDBAdapter().UpdateHeaderEntryL(aMtmId,aEntryId,aFieldPairList);
	}

/**
 * CreateHeaderEntryL()
 *
 * 
 * @param aMtmId : a MTM id.
 * @param aEntryId: Metadata entry Id of the message body.
 * @param iFieldPairList: Array of header fields.
 */

void TMsvServerStoreManager::CreateHeaderEntryL(const TUid& aMtmId, TMsvId aEntryId, const RPointerArray<CHeaderFields>& aFieldPairList)
	{
	iMsvServer->MessageDBAdapter().CreateHeaderEntryL(aMtmId,aEntryId,aFieldPairList);
	}



TBool TMsvServerStoreManager::DoesAnyStoreExists(TMsvId aId, TUid aMtmId)
	{
	TBool isStoreExists = EFalse;
	TRAPD(err, isStoreExists = iMsvServer->MessageDBAdapter().DoesAnyStoreExistsL(aId, aMtmId));
	if(err)
		{
		return EFalse;
		}
	else
		{
		return isStoreExists;
		}

	}

TBool TMsvServerStoreManager::DoesHeaderTableExist(const TUid& aMtmId)
	{
	TBool doesTableExists = EFalse;
	TRAPD(err, doesTableExists = iMsvServer->MessageDBAdapter().IsHeaderTableExistsL(aMtmId));
	if(err)
		{
		return EFalse;
		}
	else
		{
		return doesTableExists;
		}

	}






#endif			// #if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
