omads/omadsextensions/adapters/sms/src/smsdatastore.cpp
changeset 36 9ba7f05d28a5
child 42 1eb2293b4d77
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omads/omadsextensions/adapters/sms/src/smsdatastore.cpp	Tue Jul 06 14:06:02 2010 +0300
@@ -0,0 +1,1362 @@
+/*
+* Copyright (c) 2005-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:  Part of SyncML Data Synchronization Plug In Adapter
+*
+*/
+
+
+#include <e32base.h>
+#include <msvstd.h>
+#include <msvapi.h>
+#include <msvids.h>
+#include <mtclreg.h>
+#include <centralrepository.h>
+#include "smsdatastore.h"
+#include "smsdataproviderdefs.h"
+#include "logger.h"
+#include "smsadaptermsvapi.h"
+#include "vmessageparser.h"
+#include "omadsfolderobject.h"
+
+// This is used, when databuffer is not initialized
+const TInt KDataBufferNotReady = -1;
+// Size for internal CBufFlat, used to buffer SMS messages
+const TInt KDataBufferSize = 1024;
+
+_LIT8(KSmsMimeType, "text/x-vMessage");
+_LIT8(KSmsMimeVersion, "1.2");
+_LIT8(KFolderMimeType, "application/vnd.omads-folder+xml");
+_LIT8(KFolderMimeVersion, "1.2");
+
+
+// -----------------------------------------------------------------------------
+// CSmsDataStore::CSmsDataStore
+// C++ default constructor can NOT contain any code, that might leave.
+// -----------------------------------------------------------------------------
+CSmsDataStore::CSmsDataStore():
+    iHasHistory(EFalse),
+    iDataBaseOpened(EFalse),
+    iKey(TKeyArrayFix(_FOFF(TSnapshotItem, ItemId()), ECmpTInt))
+    { 
+    }
+  
+// -----------------------------------------------------------------------------
+// CSmsDataStore::ConstructL
+// Symbian 2nd phase constructor, can leave.
+// -----------------------------------------------------------------------------
+void CSmsDataStore::ConstructL()
+    {
+	LOGGER_ENTERFN("CSmsDataStore::ConstructL");
+    
+    iMsvApi = CSmsAdapterMsvApi::NewL();
+    
+	// Item UID sets, used to transfer change info
+    iNewItems = new (ELeave) CNSmlDataItemUidSet;
+    iDeletedItems = new (ELeave) CNSmlDataItemUidSet;
+    iUpdatedItems = new (ELeave) CNSmlDataItemUidSet;
+    iMovedItems = new (ELeave) CNSmlDataItemUidSet;
+    iSoftDeletedItems = new (ELeave) CNSmlDataItemUidSet;
+	
+	iMessageParser = CVMessageParser::NewL();
+	iFolderObjectParser = COMADSFolderObject::NewL();
+	
+	LOGGER_LEAVEFN("CSmsDataStore::ConstructL");
+    }
+
+// -----------------------------------------------------------------------------
+// CSmsDataStore::NewLC
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+CSmsDataStore* CSmsDataStore::NewLC()
+    {
+    CSmsDataStore* self = new (ELeave) CSmsDataStore;
+    
+	CleanupStack::PushL(self);
+  	self->ConstructL();
+
+    return self;    
+    }
+
+    
+// -----------------------------------------------------------------------------
+// CSmsDataStore::~CSmsDataStore
+// Destructor
+// -----------------------------------------------------------------------------
+CSmsDataStore::~CSmsDataStore()
+    {
+    LOGGER_ENTERFN("CSmsDataStore::~CSmsDataStore()");
+    
+    SAFEDELETE(iFolderObjectParser);
+    SAFEDELETE(iMessageParser);
+    
+    SAFEDELETE(iMsvApi);
+	SAFEDELETE(iChangeFinder); 	
+ 
+	// UID sets
+	SAFEDELETE(iNewItems);
+	SAFEDELETE(iDeletedItems);
+	SAFEDELETE(iSoftDeletedItems);
+	SAFEDELETE(iUpdatedItems);
+	SAFEDELETE(iMovedItems);
+	
+	SAFEDELETE(iDataBuffer);
+	
+	LOGGER_LEAVEFN("CSmsDataStore::~CSmsDataStore()");
+    }
+
+// -----------------------------------------------------------------------------
+// CSmsDataStore::DoOpenL
+// Opens database. This operation is performed SYNCHRONOUSLY
+// -----------------------------------------------------------------------------
+void CSmsDataStore::DoOpenL(const TDesC& /*aStoreName*/, MSmlSyncRelationship& aContext, 
+    TRequestStatus& aStatus)
+    {
+	LOGGER_ENTERFN("CSmsDataStore::DoOpenL");
+	
+	iCallerStatus = &aStatus;
+	*iCallerStatus = KRequestPending;
+	
+	if (iDataBaseOpened)
+		{
+		User::RequestComplete(iCallerStatus, KErrInUse);
+		LOGGER_WRITE("CSmsDataStore::DoOpenL failed with KErrInUse.");
+		return;
+		}
+	
+    *iContext = aContext;
+
+	// Create ChangeFinder object
+    iChangeFinder = CChangeFinder::NewL(aContext, iKey, iHasHistory, KSmsDataProviderImplUid);
+    
+    RegisterSnapshotL();
+  
+    iDataBaseOpened = ETrue;
+    iCurrentState = ESmsOpenAndWaiting;
+	User::RequestComplete(iCallerStatus, KErrNone);	
+	
+	LOGGER_LEAVEFN("CSmsDataStore::DoOpenL");
+	}
+
+// -----------------------------------------------------------------------------
+// CSmsDataStore::DoCancelRequest
+// Not supported, does nothing.
+// -----------------------------------------------------------------------------
+void CSmsDataStore::DoCancelRequest()
+	{
+	LOGGER_ENTERFN("CSmsDataStore::DoCancelRequestL");
+	LOGGER_LEAVEFN("CSmsDataStore::DoCancelRequestL");
+	}
+
+// -----------------------------------------------------------------------------
+// CSmsDataStore::DoStoreName
+// Returns the name of the DataStore
+// -----------------------------------------------------------------------------
+const TDesC& CSmsDataStore::DoStoreName() const
+	{
+	LOGGER_ENTERFN("CSmsDataStore::DoStoreName");
+	
+	if (iDataBaseOpened)
+		{
+		LOGGER_LEAVEFN("CSmsDataStore::DoStoreName");
+	    return KNSmlDefaultLocalDbName;
+	    }
+
+	LOGGER_LEAVEFN("CSmsDataStore::DoStoreName");
+    return KNullDesC;
+	}
+
+// -----------------------------------------------------------------------------
+// CSmsDataStore::DoBeginTransactionL
+// Transactions are not supported.
+// -----------------------------------------------------------------------------
+void CSmsDataStore::DoBeginTransactionL()
+ 	{
+ 	LOGGER_ENTERFN("CSmsDataStore::DoBeginTransactionL");
+ 	LOGGER_WRITE("CSmsDataStore::DoBeginTransactionL leaved with KErrNotSupported.")
+ 	User::Leave(KErrNotSupported);
+	}
+
+// -----------------------------------------------------------------------------
+// CSmsDataStore::DoCommitTransactionL
+// Transactions are not supported.
+// -----------------------------------------------------------------------------
+void CSmsDataStore::DoCommitTransactionL(TRequestStatus& aStatus)
+    {
+	LOGGER_ENTERFN("CSmsDataStore::DoCommitTransactionL"); 
+	LOGGER_WRITE("CSmsDataStore::DoCommitTransactionL failed with KErrNotSupported.");
+	
+	iCallerStatus = &aStatus;
+	User::RequestComplete(iCallerStatus, KErrNotSupported);
+	
+	LOGGER_LEAVEFN("CSmsDataStore::DoCommitTransactionL");
+	}
+
+// -----------------------------------------------------------------------------
+// CSmsDataStore::DoRevertTransaction
+// Transactions are not supported.
+// -----------------------------------------------------------------------------
+void CSmsDataStore::DoRevertTransaction(TRequestStatus& aStatus)
+    {
+	LOGGER_ENTERFN("CSmsDataStore::DoRevertTransaction"); 
+	iCallerStatus = &aStatus;
+	User::RequestComplete(iCallerStatus, KErrNone);	
+	LOGGER_LEAVEFN("CSmsDataStore::DoRevertTransaction");
+	}
+
+// -----------------------------------------------------------------------------
+// CSmsDataStore::DoBeginBatchL
+// Batching is not supported.
+// -----------------------------------------------------------------------------
+void CSmsDataStore::DoBeginBatchL()
+	{
+	LOGGER_ENTERFN("CSmsDataStore::DoBeginBatchL");
+	LOGGER_WRITE("CSmsDataStore::DoBeginBatchL leaved with KErrNotSupported.");
+	User::Leave(KErrNotSupported);	
+	}
+
+// -----------------------------------------------------------------------------
+// CSmsDataStore::DoCommitBatchL
+// Batching is not supported
+// -----------------------------------------------------------------------------
+//
+void CSmsDataStore::DoCommitBatchL(RArray<TInt>& /*aResultArray*/, TRequestStatus& aStatus)
+	{
+	LOGGER_ENTERFN("CSmsDataStore::DoCommitBatchL");	
+	LOGGER_WRITE("CSmsDataStore::DoCommitBatchL failed with KErrNotSupported");
+	
+	iCallerStatus = &aStatus;
+	User::RequestComplete(iCallerStatus, KErrNotSupported);
+	
+	LOGGER_LEAVEFN("CSmsDataStore::DoCommitBatchL");
+	}
+
+// -----------------------------------------------------------------------------
+// CSmsDataStore::DoCancelBatch
+// Batching is not supported
+// -----------------------------------------------------------------------------
+void CSmsDataStore::DoCancelBatch()
+	{
+	LOGGER_ENTERFN("CSmsDataStore::DoCancelBatch");
+	LOGGER_LEAVEFN("CSmsDataStore::DoCancelBatch");
+	}
+
+// -----------------------------------------------------------------------------
+// CSmsDataStore::DoSetRemoteStoreFormatL
+// Not supported
+// -----------------------------------------------------------------------------
+//
+void CSmsDataStore::DoSetRemoteStoreFormatL(const CSmlDataStoreFormat& /*aServerDataStoreFormat*/)
+	{
+	LOGGER_ENTERFN("CSmsDataStore::DoSetRemoteStoreFormatL");
+	LOGGER_LEAVEFN("CSmsDataStore::DoSetRemoteStoreFormatL");
+	}
+
+// -----------------------------------------------------------------------------
+// CSmsDataStore::DoSetRemoteMaxObjectSize
+// Not supported
+// -----------------------------------------------------------------------------
+void CSmsDataStore::DoSetRemoteMaxObjectSize(TInt /*aServerMaxObjectSize*/)
+ 	{
+	LOGGER_ENTERFN("CSmsDataStore::DoSetRemoteMaxObjectSize");
+	LOGGER_LEAVEFN("CSmsDataStore::DoSetRemoteMaxObjectSize");
+	}
+
+// -----------------------------------------------------------------------------
+// CSmsDataStore::DoMaxObjectSize
+// 
+// -----------------------------------------------------------------------------
+TInt CSmsDataStore::DoMaxObjectSize() const
+	{
+	LOGGER_ENTERFN("CSmsDataStore::DoMaxObjectSize");
+    LOGGER_LEAVEFN("CSmsDataStore::DoMaxObjectSize");
+    return 0;
+	}
+
+// -----------------------------------------------------------------------------
+// CSmsDataStore::DoOpenItemL
+// Opens item in the DataStore, reads it (either completely or partially) 
+// to the temporary buffer where it can be later read to the remote database.
+// -----------------------------------------------------------------------------
+void CSmsDataStore::DoOpenItemL(TSmlDbItemUid aUid, TBool& aFieldChange, 
+	TInt& aSize, TSmlDbItemUid& aParent, TDes8& aMimeType, 
+	TDes8& aMimeVer, TRequestStatus& aStatus)
+	{
+	LOGGER_ENTERFN("CSmsDataStore::DoOpenItemL");
+
+    LOGGER_WRITE_1("Opening item %d.", aUid);
+    
+	// Store these for later use
+	iCallerStatus = &aStatus;
+	*iCallerStatus = KRequestPending;
+	
+	// Check that we're in a proper state
+	if (iCurrentState != ESmsOpenAndWaiting)
+		{
+		LOGGER_WRITE_1("CSmsDataStore::DoOpenItemL, Incorrect state: %d", iCurrentState);
+		}
+    
+    // Allocate new buffer
+    SAFEDELETE(iDataBuffer);
+    iDataBuffer = CBufFlat::NewL(KDataBufferSize);
+
+    TBool userFolderFound(EFalse);
+    TTime timeStamp;
+    TPtrC folderName;
+    userFolderFound = iMsvApi->FindUserFolderL(aUid, folderName, timeStamp);
+    if (userFolderFound)
+        {
+        iMimeType = EMessageFolder;
+        iParentId = KMsvMyFoldersEntryIdValue;
+        
+        iFolderObjectParser->SetName(folderName);
+        iFolderObjectParser->SetCreatedDate(timeStamp.DateTime());
+        iFolderObjectParser->SetModifiedDate(timeStamp.DateTime());
+        iFolderObjectParser->ExportFolderXmlL(*iDataBuffer); 
+        }
+    else
+        {
+        iMimeType = ESmsMessage;        
+        iMessageParser->ResetAll();
+        
+        TBool unread;
+        TMsvId parent;
+        TRAPD(error, iMsvApi->RetrieveSML(aUid, parent, *iMessageParser, unread));
+        if(error != KErrNone)
+		    {
+		    User::RequestComplete(iCallerStatus, KErrNotFound); 
+		    LOGGER_WRITE_1("RetrieveSML(aUid, &parser, flags) leaved with %d.", error);
+		    return;
+		    }
+		    
+        iParentId = parent;
+        iMessageParser->ConstructMessageL(*iDataBuffer);
+        }
+    
+    // Adjust buffer
+    iDataBuffer->Compress();
+    iReaderPosition = 0;
+    iCurrentState = ESmsItemOpen;		
+
+	// Return these
+	aFieldChange = EFalse;
+	aParent = iParentId;
+    aSize = iDataBuffer->Size();
+    	
+    if (iMimeType == EMessageFolder)
+        {
+        TInt targetLength = KFolderMimeType().Length();
+    	if (aMimeType.MaxLength() < targetLength)
+    	    targetLength = aMimeType.MaxLength();
+    	aMimeType.Copy(KFolderMimeType().Ptr(), targetLength);
+
+        // Set mime version (do not exceed the allocated buffer)
+    	targetLength = KFolderMimeVersion().Length();
+    	if (aMimeVer.MaxLength() < targetLength)
+    	    targetLength = aMimeVer.MaxLength();
+    	aMimeVer.Copy(KFolderMimeVersion().Ptr(), targetLength);
+        }
+    else // ESmsMessage
+        {   
+    	TInt targetLength = KSmsMimeType().Length();
+    	if (aMimeType.MaxLength() < targetLength)
+    	    targetLength = aMimeType.MaxLength();
+    	aMimeType.Copy(KSmsMimeType().Ptr(), targetLength);
+
+        // Set mime version (do not exceed the allocated buffer)
+    	targetLength = KSmsMimeVersion().Length();
+    	if (aMimeVer.MaxLength() < targetLength)
+    	    targetLength = aMimeVer.MaxLength();
+    	aMimeVer.Copy(KSmsMimeVersion().Ptr(), targetLength);
+        }
+		
+   	// Signal we're complete
+	User::RequestComplete(iCallerStatus, KErrNone); 
+
+	LOGGER_LEAVEFN("CSmsDataStore::DoOpenItemL");
+	}
+
+// -----------------------------------------------------------------------------
+// CSmsDataStore::DoCreateItemL
+// Create new item to the message store.
+// Return the id number of the newly created item
+// -----------------------------------------------------------------------------
+void CSmsDataStore::DoCreateItemL(TSmlDbItemUid& aUid, TInt aSize, 
+    TSmlDbItemUid aParent, const TDesC8& aMimeType, const TDesC8& /*aMimeVer*/, 
+    TRequestStatus& aStatus)
+	{
+	LOGGER_ENTERFN("CSmsDataStore::DoCreateItemL");
+	
+	// Store some variables for further use
+	iCallerStatus = &aStatus;
+	*iCallerStatus = KRequestPending;
+	
+	// Ensure that we're in proper state
+	if (iCurrentState != ESmsOpenAndWaiting)
+		{
+		LOGGER_WRITE_1("Incorrect state: %d", iCurrentState);
+		}	
+
+	// Check MIME type
+	LOG(aMimeType);
+	if (aMimeType.Compare( KFolderMimeType() ) == 0)	
+		{
+		iMimeType = EMessageFolder;
+		}
+	else if (aMimeType.Compare( KSmsMimeType() ) == 0)
+		{
+		iMimeType = ESmsMessage;
+		}
+	else
+		{
+		User::RequestComplete( iCallerStatus, KErrNotSupported );
+		LOGGER_WRITE("Bad MIME type");
+		return;
+		}
+	
+	LOGGER_WRITE_1( "Parent folder: %d", aParent);
+	if ((iMimeType == EMessageFolder && aParent != KMsvMyFoldersEntryIdValue) ||
+	    (iMimeType == ESmsMessage && !iMsvApi->ValidFolderL(aParent)))
+	    {
+		User::RequestComplete( iCallerStatus, KErrNotSupported );
+		LOGGER_WRITE( "Bad parent folder");
+		return;	    
+	    }
+
+	// Ensure that we've got enough disk space for the item
+	if(iMsvApi->DiskSpaceBelowCriticalLevelL(aSize))
+		{
+		User::RequestComplete(iCallerStatus, KErrDiskFull);
+		LOGGER_WRITE("Disk full");
+		return;
+		}	
+			
+    // Store uid values
+    iCreatedUid = &aUid;
+	iParentId = aParent; 
+    
+    // Create message buffer, item will be written into this buffer
+	SAFEDELETE(iDataBuffer);
+	iDataBuffer = CBufFlat::NewL(KDataBufferSize);
+	iWriterPosition = 0;
+	iCurrentState = ESmsItemCreating;
+	
+	// Signal we're complete
+	User::RequestComplete( iCallerStatus, KErrNone );
+    
+    LOGGER_LEAVEFN("CSmsDataStore::DoCreateItemL");
+	}
+
+// -----------------------------------------------------------------------------
+// CSmsDataStore::DoReplaceItemL
+// Begin the replace operation, ensure that the item really exists
+// -----------------------------------------------------------------------------
+void CSmsDataStore::DoReplaceItemL(TSmlDbItemUid aUid, TInt aSize, TSmlDbItemUid aParent, 
+    TBool /*aFieldChange*/, TRequestStatus& aStatus)
+	{
+	LOGGER_ENTERFN("CSmsDataStore::DoReplaceItemL");
+	LOGGER_WRITE_1("Replacing item %d.", aUid);
+	LOGGER_WRITE_1("Parent folder: %d.", aParent);
+	
+	// Store some variables for further use
+	iCallerStatus = &aStatus;
+	*iCallerStatus = KRequestPending;
+	
+	// Ensure proper state
+	if (iCurrentState != ESmsOpenAndWaiting)
+		{
+		LOGGER_WRITE_1("Incorrect state: %d", iCurrentState);
+		}
+	 
+	// Ensure that we've got enough disk space for the item
+	if (iMsvApi->DiskSpaceBelowCriticalLevelL(aSize))
+		{
+		User::RequestComplete(iCallerStatus, KErrDiskFull);
+		LOGGER_WRITE("Disk full");
+		return;
+		}
+			 
+	// Find entry
+	CMsvEntry* entry(NULL);
+	TRAPD(error, entry = iMsvApi->MsvSessionL()->GetEntryL(aUid));
+	if (error != KErrNone)
+		{
+		User::RequestComplete(iCallerStatus, KErrNotFound);
+		LOGGER_WRITE("Item not found");
+		return;
+		}
+
+	// This is the representation of the actual message
+	TMsvEntry tEntry = entry->Entry();
+	
+	// Not needed anymore
+	SAFEDELETE(entry);	
+	
+	// Check entry type
+	if (tEntry.iType == KUidMsvFolderEntry)
+	    {
+	    iMimeType = EMessageFolder;
+	    LOGGER_WRITE("Type: folder");
+	    }
+	else
+	    {
+	    iMimeType = ESmsMessage;
+	    LOGGER_WRITE("Type: SMS message");
+	    }   
+    
+    if ((iMimeType == EMessageFolder && aParent != KMsvMyFoldersEntryIdValue) ||
+        (iMimeType == ESmsMessage && !iMsvApi->ValidFolderL(aParent) ||
+        (aParent != tEntry.Parent())))
+        {
+        User::RequestComplete(iCallerStatus, KErrNotSupported);
+        LOGGER_WRITE_1("Bad parent folder, message entry parent is %d", tEntry.Parent());
+        return;    
+        }    
+	
+	// Store these for further use
+	iParentId = aParent;
+	iCurrentId = aUid;
+
+	// Create temporary buffer for message data, item will be written here
+    SAFEDELETE(iDataBuffer);
+    iDataBuffer = CBufFlat::NewL(KDataBufferSize);
+	iWriterPosition = 0;
+	iCurrentState = ESmsItemUpdating;
+	
+	// Signal we're complete
+	User::RequestComplete(iCallerStatus, KErrNone);
+
+	LOGGER_LEAVEFN("CSmsDataStore::DoReplaceItemL");
+	}
+
+// -----------------------------------------------------------------------------
+// CSmsDataStore::DoReadItemL
+// Read specified amount of data from the temporary buffer
+// -----------------------------------------------------------------------------
+void CSmsDataStore::DoReadItemL(TDes8& aBuffer)
+	{
+	LOGGER_ENTERFN("CSmsDataStore::DoReadItemL");
+	
+	// Check that we're in proper state
+	if (iCurrentState != ESmsItemOpen || !iDataBuffer)
+		{
+		LOGGER_WRITE("CSmsDataStore::DoReadItemL leaved with KErrNotReady.");
+		User::Leave(KErrNotReady);
+		}
+
+	if (iReaderPosition == KDataBufferNotReady)
+		{
+		LOGGER_WRITE("CSmsDataStore::DoReadItemL leaved with KErrEof.");
+		User::Leave(KErrEof);
+		}
+		
+	// This is how much we've got left in the buffer
+	TInt left = iDataBuffer->Size() - iReaderPosition;
+	
+	// Make sure that there's something to read
+	if(left > 0)
+		{
+		// This is how much there's space in the destination buffer
+		TInt destSize = aBuffer.MaxSize();
+
+		// This is how much we can read
+		TInt toRead = destSize < left ? destSize : left;
+
+		// Read the data from the buffer, then update the position
+		iDataBuffer->Read(iReaderPosition, aBuffer, toRead);
+		iReaderPosition += toRead;
+		}
+	else
+		{
+		iReaderPosition = KDataBufferNotReady;
+		LOGGER_WRITE("CSmsDataStore::DoReadItemL leaved with KErrEof.");
+		User::Leave(KErrEof);
+		}
+
+	LOGGER_LEAVEFN("CSmsDataStore::DoReadItemL");	
+	}
+
+// -----------------------------------------------------------------------------
+// CSmsDataStore::DoWriteItemL
+// Write specified amount of data to the temporary buffer
+// -----------------------------------------------------------------------------
+void CSmsDataStore::DoWriteItemL(const TDesC8& aData)
+	{
+	LOGGER_ENTERFN("CSmsDataStore::DoWriteItemL");
+
+	// Ensure that we're in proper state
+    if ( iCurrentState != ESmsItemCreating && iCurrentState != ESmsItemUpdating )
+    	{
+    	LOGGER_WRITE("CSmsDataStore::DoWriteItemL leaved with KErrNotReady.");
+    	User::Leave( KErrNotReady );
+    	}
+    		
+	// Calculate total size
+	TInt totalSize = aData.Size() + iDataBuffer->Size();
+	    
+    // Check that we have enough disk space to store this much data
+	if ( iMsvApi->DiskSpaceBelowCriticalLevelL( totalSize ) )
+	    {
+	    LOGGER_WRITE("CSmsDataStore::DoWriteItemL leaved with KErrDiskFull.");
+	    User::Leave(KErrDiskFull);
+	    }
+	    
+	// Add data to buffer
+    iDataBuffer->InsertL( iWriterPosition, aData );
+    iWriterPosition += aData.Size();
+
+	LOGGER_LEAVEFN("CSmsDataStore::DoWriteItemL");	
+	}
+
+// -----------------------------------------------------------------------------
+// CSmsDataStore::DoCommitItemL
+// Commits item from temporary buffer to the message store
+// -----------------------------------------------------------------------------
+void CSmsDataStore::DoCommitItemL(TRequestStatus& aStatus)
+	{
+	LOGGER_ENTERFN("CSmsDataStore::DoCommitItemL");
+	TInt error(KErrNone);
+	
+	// Store some variables
+	iCallerStatus = &aStatus;
+	*iCallerStatus = KRequestPending;
+	
+	// Check that we're in proper state
+	if ((iCurrentState != ESmsItemCreating && iCurrentState != ESmsItemUpdating) || !iDataBuffer)
+		{
+		User::RequestComplete(iCallerStatus, KErrNotReady);
+		LOGGER_WRITE_1("Bad state: %d", iCurrentState);
+		return;
+		}
+
+	iDataBuffer->Compress();
+	TInt size = iDataBuffer->Size();
+	
+	// Variable to hold the information whether SMS message is unread or not for Change Finder.
+	// For message folders this information is not relevant and value is EFalse by default.	
+	TBool unread(EFalse);
+	
+	if ( iMimeType == ESmsMessage )
+		{
+		// Reset parser
+        iMessageParser->ResetAll();
+        
+        // This function returns the index, where the parsing ends (>=0)
+        // (the error codes are in the range below 0)
+        error = iMessageParser->ParseMessageL(iDataBuffer->Ptr(0));
+        
+		if ( error >= 0 )
+		    {
+    		unread = iMessageParser->iStatus.Compare(KVMsgStatusUnread) == 0 ? ETrue : EFalse;
+    		    		
+    		// Check the datastore state. We're either creating or updating an item.
+    		if (iCurrentState == ESmsItemCreating)
+    			{
+    			TMsvId id;
+    			TMsvId temporaryParent = iParentId;
+    			// in message sending case, save message first to drafts folder
+    			if ( iParentId == KMsvGlobalOutBoxIndexEntryId )
+    			    {
+    			    temporaryParent = KMsvDraftEntryId;
+    			    }
+    			
+    			TRAP(error, iMsvApi->AddSML(*iMessageParser, temporaryParent, id));
+    			if ( error == KErrNone )
+    				{
+        			*iCreatedUid = id;
+        			iCurrentId = id;
+    				}
+    			else
+        			{
+    				LOGGER_WRITE_1("iMsvApi->AddSML leaved with %d.", error);
+    	    		}
+    			}
+    		else // EItemUpdating
+    			{
+    		    if ( iParentId == KMsvGlobalInBoxIndexEntryId )
+    		    	{
+    		    	// For arrived message in Inbox only status is updated
+    		    	TRAP(error, iMsvApi->UpdateSMStatusL( iCurrentId, *iMessageParser));
+    		    	}
+    		    else
+    		    	{
+	    			TRAP(error, iMsvApi->ReplaceSML(iCurrentId, *iMessageParser));
+    		    	}
+    			if(error != KErrNone)
+    			    {
+    				LOGGER_WRITE_1("iMsvApi->ReplaceSML leaved with %d.", error);
+    				}
+    			}
+		    }
+    	else
+    	    {
+   		    LOGGER_WRITE_1("iMessageParser->ParseMessageL failed with %d.", error);
+   		    }
+		} // if (iMimeType == ESmsMessage)
+		
+	else // EMessageFolder
+	    {
+	    error = iFolderObjectParser->ImportFolderXml(iDataBuffer->Ptr(0));
+	    
+	    if ( error == KErrNone )
+	        {
+	        const TDesC& name = iFolderObjectParser->GetName();
+	        
+	        if ( name.Length() > 0 )
+	            {
+	            if ( iCurrentState == ESmsItemCreating )
+	                {
+	                TMsvId id;
+	                error = iMsvApi->AddUserFolderL( id, name );
+	                if ( error == KErrNone )
+	                    {
+	                    *iCreatedUid = id;
+	                    iCurrentId = id;
+	                    }
+	                else
+	                    {
+	                    LOGGER_WRITE_1("iMsvApi->AddFolderL failed with %d", error);
+	                    }    
+	                }
+	            else // Updating
+	                {
+	                error = iMsvApi->UpdateUserFolderL( iCurrentId, name );
+	                if ( error != KErrNone )
+	                    {
+	                    LOGGER_WRITE_1("iMsvApi->UpdateFolderL failed with %d", error);
+	                    }
+	                }    
+	            }
+	        else
+	            {
+	            LOGGER_WRITE("No folder name available");
+	            error = KErrArgument;
+	            }    
+	        }
+	    }
+	
+	// Send the message if the parent folder is outbox
+    if( iParentId == KMsvGlobalOutBoxIndexEntryId &&
+        iMimeType == ESmsMessage &&
+        iCurrentState == ESmsItemCreating &&
+        error == KErrNone )
+		{
+		LOGGER_WRITE("CSmsDataStore::DoCommitItemL, sending message.");
+		
+		TRAP( error, iMsvApi->MoveSML( iCurrentId, iParentId ) );
+		if( error != KErrNone )
+			{
+			LOGGER_WRITE_1("Moving to folder failed with %d", error);
+			iMsvApi->DeleteSML( iCurrentId );
+			}
+		else
+			{
+			TRAP( error, iMsvApi->SendSML(iCurrentId) );
+			if ( error != KErrNone )
+				{
+				LOGGER_WRITE_1("iMsvApi->SendSML failed with %d.", error);
+				iMsvApi->DeleteSML( iCurrentId );
+				}
+			}
+		}   
+    
+    if ( error == KErrNone ) // Update Change Finder
+        {
+        CMsvSession* msvSession = iMsvApi->MsvSessionL();   
+        TMsvId service;
+        TMsvEntry msgEntry;
+        
+        // Inform ChangeFinder of added item
+        TSnapshotItem snapshotItem( iCurrentId, iParentId, unread );
+        error = msvSession->GetEntry( iCurrentId, service, msgEntry );
+   
+        if ( error == KErrNone )
+            {
+            snapshotItem.SetLastChangedDate( msgEntry.iDate );
+            if ( iMimeType == EMessageFolder )
+                {
+                snapshotItem.SetFolderNameL( msgEntry.iDetails );
+                }
+        
+            if ( iCurrentState == ESmsItemCreating )
+                {
+                iChangeFinder->ItemAddedL( snapshotItem );
+                }
+            else
+                {
+                iChangeFinder->ItemUpdatedL( snapshotItem );
+                }    
+            }
+        else
+            {
+            LOGGER_WRITE_1("CMsvSession::GetEntry failed with %d", error);
+            }    
+        }
+		
+	// Reset and destroy write buffer, it's no longer needed
+	iWriterPosition = KDataBufferNotReady;
+	SAFEDELETE(iDataBuffer);
+		
+	// We'll be waiting for next event, signal we're done
+	iCurrentState = ESmsOpenAndWaiting;
+	User::RequestComplete(iCallerStatus, error);
+ 
+ 	LOGGER_LEAVEFN("CSmsDataStore::DoCommitItemL");
+	}
+
+// -----------------------------------------------------------------------------
+// CSmsDataStore::DoCloseItem
+// Closes open item in the data store
+// -----------------------------------------------------------------------------
+void CSmsDataStore::DoCloseItem()
+	{
+	LOGGER_ENTERFN("CSmsDataStore::DoCloseItem");
+	
+	// Make sure that we're opened an item
+	if ( iCurrentState == ESmsItemOpen )
+		{
+		// Reset read buffer 
+		iReaderPosition = KDataBufferNotReady;
+		SAFEDELETE(iDataBuffer);
+		
+		// Start to wait for the next operation		
+		iCurrentState = ESmsOpenAndWaiting;
+		}
+	else 
+		{
+		LOGGER_WRITE_1("CSmsDataStore::DoCloseItem, invalid state %d.", iCurrentState);
+		}
+	
+	LOGGER_LEAVEFN("CSmsDataStore::DoCloseItem");
+	}
+
+// -----------------------------------------------------------------------------
+// CSmsDataStore::DoMoveItemL
+// Moves item from one folder to another in the message store
+// -----------------------------------------------------------------------------
+void CSmsDataStore::DoMoveItemL(TSmlDbItemUid aUid, TSmlDbItemUid aNewParent, TRequestStatus& aStatus)
+	{
+	LOGGER_ENTERFN("CSmsDataStore::DoMoveItemL");
+	
+	LOGGER_WRITE_1("Moving item %d.", aUid);
+	
+	// Store some variables for further use
+	iCallerStatus = &aStatus;
+	*iCallerStatus = KRequestPending;
+
+    // Check that we're in proper state
+	if (iCurrentState != ESmsOpenAndWaiting) 
+		{
+		LOGGER_WRITE_1("CSmsDataStore::DoMoveItemL, Incorrect state: %d", iCurrentState);
+		}
+
+    TInt error_move(KErrNone);
+	TRAP(error_move, iMsvApi->MoveSML(aUid, aNewParent));
+	if(error_move != KErrNone)
+		{
+		User::RequestComplete(iCallerStatus, error_move); 
+		LOGGER_WRITE_1("iMsvApi->MoveSML leaved with %d.", error_move);
+		return;
+		}
+
+	// Inform ChangeFinder of the moved item
+	TSnapshotItem snapshotItem(aUid, aNewParent);
+	iChangeFinder->ItemMovedL(snapshotItem);
+
+   	// Signal we're done
+    User::RequestComplete(iCallerStatus, KErrNone);
+    
+    LOGGER_LEAVEFN("CSmsDataStore::DoMoveItemL");
+	}
+
+// -----------------------------------------------------------------------------
+// CSmsDataStore::DoDeleteItemL
+// Removes item from the message store
+// -----------------------------------------------------------------------------
+void CSmsDataStore::DoDeleteItemL(TSmlDbItemUid aUid, TRequestStatus& aStatus)
+	{
+	LOGGER_ENTERFN("CSmsDataStore::DoDeleteItemL");
+
+	// Store some variables for further use
+	iCallerStatus = &aStatus;
+	*iCallerStatus = KRequestPending;
+    
+    // Check that we're in proper state
+	if (iCurrentState != ESmsOpenAndWaiting) 
+		{
+		LOGGER_WRITE_1("CSmsDataStore::DoDeleteItemL, Incorrect state: %d", iCurrentState);
+		}
+		
+    TInt error(KErrNone);	
+		
+	// Check if this is a user folder
+	TBool userFolder = iMsvApi->FindUserFolderL(aUid);
+	
+	if (userFolder)
+	    {
+	    LOGGER_WRITE_1("Delete user folder %d", aUid);
+	    
+	    // First delete SMS messages under the folder
+	    CMsvEntrySelection* deletedItems = iMsvApi->CleanFolderGetMsvIdsL(aUid);
+	    CleanupStack::PushL(deletedItems);
+	    
+	    for (TInt i = 0; i < deletedItems->Count(); i++)
+	        {
+	        TMsvId id = deletedItems->At(i);
+	        TSnapshotItem item(id);
+	        iChangeFinder->ItemDeletedL(item);
+	        }
+	    CleanupStack::PopAndDestroy(deletedItems);    
+	    
+	    // Then delete the actual folder
+	    // Note: folder is not deleted if it contains other message items (like MMS)
+        TRAP(error, iMsvApi->DeleteUserFolderL(aUid));
+	    }
+	else
+	    {
+    	LOGGER_WRITE_1("Delete SMS message %d", aUid);
+    	TRAP(error, iMsvApi->DeleteSML(aUid))
+	    }
+	    
+	if ( error != KErrNone )
+	    {
+		User::RequestComplete(iCallerStatus, error); 
+		LOGGER_WRITE_1("iMsvApi function call leaved with %d", error);
+		return;	    
+	    }
+	    
+	// Inform ChangeFinder of the removed item
+	TSnapshotItem item(aUid);
+	iChangeFinder->ItemDeletedL(item);
+    	
+	// Signal we're done
+	User::RequestComplete(iCallerStatus, KErrNone);
+
+	LOGGER_LEAVEFN("CSmsDataStore::DoDeleteItemL");
+	}
+
+// -----------------------------------------------------------------------------
+// CSmsDataStore::DoSoftDeleteItemL
+// Soft delete is not supported.
+// -----------------------------------------------------------------------------
+void CSmsDataStore::DoSoftDeleteItemL(TSmlDbItemUid /*aUid*/, TRequestStatus& aStatus)
+	{
+	LOGGER_ENTERFN("CSmsDataStore::DoSoftDeleteItemL");	
+	
+	iCallerStatus = &aStatus;
+	*iCallerStatus = KRequestPending;
+	
+	User::RequestComplete(iCallerStatus, KErrNotSupported);
+	
+	LOGGER_LEAVEFN("CSmsDataStore::DoSoftDeleteItemL");
+	}
+
+// -----------------------------------------------------------------------------
+// CSmsDataStore::DoDeleteAllItemsL
+// Deletes all items in the standard folders of message store
+// -----------------------------------------------------------------------------
+void CSmsDataStore::DoDeleteAllItemsL(TRequestStatus& aStatus)
+	{
+	LOGGER_ENTERFN("CSmsDataStore::DoDeleteAllItemsL");
+	
+	// Store some variables for further use	
+	iCallerStatus = &aStatus;
+	*iCallerStatus = KRequestPending;
+	
+   // Check that we're in proper state
+	if (iCurrentState != ESmsOpenAndWaiting) 
+		{
+		LOGGER_WRITE_1("CSmsDataStore::DoDeleteAllItemsL, Incorrect state: %d", iCurrentState);
+		}	
+	
+	// Delete all messages in the standard folders (except outbox)
+	iMsvApi->CleanFolderL(KMsvGlobalInBoxIndexEntryId);
+	iMsvApi->CleanFolderL(KMsvDraftEntryId);
+	iMsvApi->CleanFolderL(KMsvSentEntryId);
+	
+	iMsvApi->CleanUserFoldersL();
+	
+	iChangeFinder->ResetL();
+	
+    User::RequestComplete(iCallerStatus, KErrNone);
+    
+    LOGGER_LEAVEFN("CSmsDataStore::DoDeleteAllItemsL");
+	}
+
+
+// -----------------------------------------------------------------------------
+// CSmsDataStore::DoHasSyncHistory
+// This method returns ETrue if Data Store has history information. 
+// Slow-sync will be used if Data Store does not have history information.
+// -----------------------------------------------------------------------------
+TBool CSmsDataStore::DoHasSyncHistory() const
+	{
+	LOGGER_WRITE_1("CSmsDataStore::DoHasSyncHistory return %d", (TInt)iHasHistory );	
+	
+	// iHasHistory is initialized in DoOpenL method
+	return iHasHistory;
+	}
+
+// -----------------------------------------------------------------------------
+// CSmsDataStore::DoAddedItems
+// This method returns UIDs of added items. Those items are added after previous
+// synchronization with current synchronization relationship. 
+// -----------------------------------------------------------------------------
+const MSmlDataItemUidSet& CSmsDataStore::DoAddedItems() const
+	{
+	LOGGER_ENTERFN("CSmsDataStore::DoAddedItems");	
+	
+	// Ensure that we're in a proper state
+	if (iCurrentState != ESmsOpenAndWaiting)
+		{
+		LOGGER_WRITE_1("CSmsDataStore::DoAddedItems, invalid state %d.", iCurrentState);
+		}
+		
+	TInt error(KErrNone);
+
+	// Clear new-items array
+	iNewItems->Reset();
+	
+    // Search for new items
+    TRAP( error, iChangeFinder->FindNewItemsL(*iNewItems) );
+    if ( error != KErrNone )
+        {
+        LOGGER_WRITE_1("CSmsDataStore::DoAddedItems, iChangeFinder->FindNewItemsL leaved with %d.", error);
+        }
+	
+	LOGGER_WRITE_1("New item count: %d.", iNewItems->ItemCount());
+	LOGGER_LEAVEFN("CSmsDataStore::DoAddedItems");		
+	
+	return *iNewItems;
+	}
+
+// -----------------------------------------------------------------------------
+// CSmsDataStore::DoDeletedItems
+//
+// -----------------------------------------------------------------------------
+const MSmlDataItemUidSet& CSmsDataStore::DoDeletedItems() const
+	{
+	LOGGER_ENTERFN("CSmsDataStore::DoDeletedItemsL");	
+	
+	// Ensure that we're in a proper state
+	if (iCurrentState != ESmsOpenAndWaiting)
+	    {
+	    LOGGER_WRITE_1("CSmsDataStore::DoDeletedItems, invalid state %d.", iCurrentState);
+	    }
+
+	TInt error(KErrNone);
+	
+	// Clear deleted-items array
+	iDeletedItems->Reset();
+	
+    // Search for deleted items
+    TRAP( error, iChangeFinder->FindDeletedItemsL(*iDeletedItems) );
+    if ( error != KErrNone )
+        {
+        LOGGER_WRITE_1("CSmsDataStore::DoDeletedItems, iChangeFinder->FindDeletedItemsL leaved with %d.", error);
+        }
+	
+	
+	LOGGER_WRITE_1("Deleted item count: %d.", iDeletedItems->ItemCount());
+	LOGGER_LEAVEFN("CSmsDataStore::DoDeletedItemsL");
+	return *iDeletedItems;
+	}
+
+// -----------------------------------------------------------------------------
+// CSmsDataStore::DoSoftDeletedItems
+// Not directly supported, equals to "hard" delete
+// -----------------------------------------------------------------------------
+const MSmlDataItemUidSet& CSmsDataStore::DoSoftDeletedItems() const
+	{
+	TRACE_FUNC;
+	
+    // Return empty array as a result
+    iSoftDeletedItems->Reset();
+	return *iSoftDeletedItems;
+	}
+
+// -----------------------------------------------------------------------------
+// CSmsDataStore::DoModifiedItems
+// Finds all modified items in the data store
+// -----------------------------------------------------------------------------
+const MSmlDataItemUidSet& CSmsDataStore::DoModifiedItems() const
+	{
+	LOGGER_ENTERFN("CSmsDataStore::DoModifiedItems");	
+	
+	// Ensure that we're in a proper state
+	if (iCurrentState != ESmsOpenAndWaiting)
+		{
+		LOGGER_WRITE_1("CSmsDataStore::DoModifiedItems, invalid state %d.", iCurrentState);
+		}
+
+	TInt error(KErrNone);
+
+	// Clear updated-items array
+	iUpdatedItems->Reset();
+	
+    // Search for updated items
+    TRAP( error, iChangeFinder->FindChangedItemsL(*iUpdatedItems) )
+    if ( error != KErrNone )
+        {
+        LOGGER_WRITE_1("CSmsDataStore::DoModifiedItems, iChangeFinder->FindChangedItemsL leaved with %d.", error);
+        }
+    else
+        {
+        TRAP( error, iChangeFinder->FindMovedItemsL(*iUpdatedItems) );
+        if( error != KErrNone )
+            {
+            LOGGER_WRITE_1("CSmsDataStore::DoModifiedItems, iChangeFinder->FindMovedItemsL leaved with %d.", error);
+            }		    
+        }
+	
+	LOGGER_WRITE_1("Modified item count: %d.", iUpdatedItems->ItemCount());
+	LOGGER_LEAVEFN("CSmsDataStore::DoModifiedItems");		
+	return *iUpdatedItems;
+	}
+
+// -----------------------------------------------------------------------------
+// CSmsDataStore::DoMovedItems
+// Moved items not supported (handled as replaced items)
+// -----------------------------------------------------------------------------
+const MSmlDataItemUidSet& CSmsDataStore::DoMovedItems() const
+	{
+	TRACE_FUNC;	
+	
+	// Clear moved-items array
+	iMovedItems->Reset();
+	
+	return *iMovedItems;	
+	}
+
+// -----------------------------------------------------------------------------
+// CSmsDataStore::DoResetChangeInfoL
+// Resets change history in the data store. All content is considered
+// new in the data store point of view.
+// -----------------------------------------------------------------------------
+void CSmsDataStore::DoResetChangeInfoL(TRequestStatus& aStatus)
+	{
+	LOGGER_ENTERFN("CSmsDataStore::DoResetChangeInfoL");	
+	
+	iCallerStatus = &aStatus;
+	*iCallerStatus = KRequestPending;
+	
+    // Check that we're in proper state
+	if (iCurrentState != ESmsOpenAndWaiting) 
+		{
+		LOGGER_WRITE_1("CSmsDataStore::DoResetChangeInfoL, invalid state %d.", iCurrentState);
+		}	
+			
+	// Reset change info in ChangeFinder
+	iChangeFinder->ResetL();
+	iHasHistory = EFalse;
+	
+    // Signal we're done
+    User::RequestComplete(iCallerStatus, KErrNone);	
+    
+    LOGGER_LEAVEFN("CSmsDataStore::DoResetChangeInfoL");
+	}
+		
+// -----------------------------------------------------------------------------
+// CSmsDataStore::DoCommitChangeInfoL
+// Commits change info. These items are no longer reported, when change
+// information is being queried.
+// -----------------------------------------------------------------------------
+void CSmsDataStore::DoCommitChangeInfoL(TRequestStatus& aStatus, const MSmlDataItemUidSet& aItems)
+	{
+	LOGGER_ENTERFN("CSmsDataStore::DoCommitChangeInfoL(MSmlDataItemUidSet)");	
+	LOGGER_WRITE_1("Item count: %d", aItems.ItemCount());
+	
+	iCallerStatus = &aStatus;
+    *iCallerStatus = KRequestPending;
+    
+    // Ensure that we're in a proper state
+    if (iCurrentState != ESmsOpenAndWaiting) 
+	    {
+		LOGGER_WRITE_1("CSmsDataStore::DoCommitChangeInfoL, invalid state %d.", iCurrentState);
+		}
+
+	// Notify ChangeFinder
+    iChangeFinder->CommitChangesL(aItems);
+    iHasHistory = ETrue;
+	    
+	// Signal we're done
+	User::RequestComplete(iCallerStatus, KErrNone);
+	    
+	LOGGER_LEAVEFN("CSmsDataStore::DoCommitChangeInfoL");
+	}
+		
+	
+// -----------------------------------------------------------------------------
+// CSmsDataStore::DoCommitChangeInfoL
+// Commits change info. There is no more nothing to report when change
+// information is being queried. 
+// -----------------------------------------------------------------------------
+void CSmsDataStore::DoCommitChangeInfoL(TRequestStatus& aStatus)
+	{
+	LOGGER_ENTERFN("CSmsDataStore::DoCommitChangeInfoL");
+	
+	iCallerStatus = &aStatus;
+	*iCallerStatus = KRequestPending;
+	
+	// Ensure that we're in a proper state
+	if (iCurrentState != ESmsOpenAndWaiting) 
+	    {
+		LOGGER_WRITE_1("CSmsDataStore::DoCommitChangeInfoL, invalid state %d.", iCurrentState);
+		}
+	
+	// Notify ChangeFinder
+	iChangeFinder->CommitChangesL();
+	iHasHistory = ETrue;
+	    
+	// Signal we're done
+	User::RequestComplete(iCallerStatus, KErrNone);
+	
+	LOGGER_LEAVEFN("CSmsDataStore::DoCommitChangeInfoL");
+	}
+		
+
+// -----------------------------------------------------------------------------
+// CSmsDataStore::RegisterSnapshotL
+// Sets Changefinder to compare against current message store content
+// -----------------------------------------------------------------------------
+void CSmsDataStore::RegisterSnapshotL() const
+	{
+	LOGGER_ENTERFN("CSmsDataStore::RegisterSnapshotL");
+	
+    CSnapshotArray* snapshot = new (ELeave) CSnapshotArray( KSnapshotGranularity );
+    CleanupStack::PushL(snapshot);
+	
+	// Use only standard folders (outbox isn't synchronized)
+	LOGGER_WRITE( "KMsvGlobalInBoxIndexEntryId" );
+	RegisterFolderL(snapshot, KMsvGlobalInBoxIndexEntryId);
+	LOGGER_WRITE( "KMsvDraftEntryId" );
+	RegisterFolderL(snapshot, KMsvDraftEntryId);
+	LOGGER_WRITE( "KMsvSentEntryId" );
+	RegisterFolderL(snapshot, KMsvSentEntryId);
+	LOGGER_WRITE( "KMsvGlobalOutBoxIndexEntryId" );
+	RegisterFolderL(snapshot, KMsvGlobalOutBoxIndexEntryId);
+	RegisterUserFoldersL(snapshot);
+	
+	// Set new snapshot to compare against
+	iChangeFinder->SetNewSnapshot(snapshot);
+
+	// Changefinder takes ownership of the snapshot
+	CleanupStack::Pop();
+	
+	LOGGER_LEAVEFN("CSmsDataStore::RegisterSnapshotL");	
+	}
+
+// -----------------------------------------------------------------------------
+// CSmsDataStore::RegisterFolderL
+// Adds a single folder into the snapshot array
+// -----------------------------------------------------------------------------
+TInt CSmsDataStore::RegisterFolderL(CSnapshotArray* aSnapshot, const TMsvId& aId) const
+	{
+	LOGGER_ENTERFN("CSmsDataStore::RegisterFolderL");	
+	
+	CMsvSession* msvSession = iMsvApi->MsvSessionL();
+
+	// Get the folder	
+	CMsvEntry* msvEntry = msvSession->GetEntryL(aId);
+	CleanupStack::PushL(msvEntry);
+	
+	// Find all of it's childs
+	CMsvEntrySelection* messages = msvEntry->ChildrenWithTypeL(KUidMsvMessageEntry);
+	CleanupStack::PopAndDestroy(); // msvEntry
+	CleanupStack::PushL(messages);
+	
+    TMsvId id;
+    TMsvEntry msg;
+    LOGGER_WRITE_1( "messages count %d", messages->Count() );
+	for(TInt index=0; index<messages->Count(); index++)
+		{
+		TInt result = msvSession->GetEntry(messages->At(index), id, msg);
+		User::LeaveIfError(result);
+		
+		// We're only interested about the SMS content
+		if(msg.iMtm == KUidMsgTypeSMS)
+			{
+			// Create snapshot item
+			TKeyArrayFix key(iKey);
+			TSnapshotItem item((TUint) msg.Id(), msg.Parent(), msg.Unread());
+			
+			item.SetLastChangedDate(msg.iDate);
+			LOGGER_WRITE_1( "item id %d", msg.Id() );
+			// Add to snapshot
+			aSnapshot->InsertIsqL(item, key);
+			}
+	    else
+	        {
+	        LOGGER_WRITE("Wrong type");
+	        }
+		}
+
+	CleanupStack::PopAndDestroy(); // messages
+	
+    LOGGER_LEAVEFN("CSmsDataStore::RegisterFolderL");	
+
+	return KErrNone;
+	}
+	
+// -----------------------------------------------------------------------------
+// CSmsDataStore::RegisterUserFoldersL
+// Adds user folder messages into the snapshot array
+// -----------------------------------------------------------------------------
+TInt CSmsDataStore::RegisterUserFoldersL(CSnapshotArray* aSnapshot) const
+    {
+ 	LOGGER_ENTERFN("CSmsDataStore::RegisterUserFoldersL");	   
+    
+    CMsvSession* msvSession = iMsvApi->MsvSessionL();
+    
+    // Get the folder	
+	CMsvEntry* msvEntry = msvSession->GetEntryL(KMsvMyFoldersEntryIdValue);
+    CleanupStack::PushL(msvEntry);
+    
+    // Find all of it's childs
+    CMsvEntrySelection* folders = msvEntry->ChildrenWithTypeL( KUidMsvFolderEntry );
+    CleanupStack::PopAndDestroy( msvEntry ); 
+    CleanupStack::PushL( folders );
+    LOGGER_WRITE_1("Folders: %d", folders->Count());
+    for ( TInt index = 0; index < folders->Count(); index++ )
+        {
+        TMsvId folderId = folders->At(index);
+        
+        if ( folderId != KMsvMyFoldersTemplatesFolderId )
+            {
+            TMsvId service;
+            TMsvEntry folderEntry;
+            TInt result = msvSession->GetEntry(folderId, service, folderEntry);
+            User::LeaveIfError( result );
+            
+            TKeyArrayFix key(iKey);
+            TBool unread(EFalse);
+            TSnapshotItem item( (TUint) folderId, folderEntry.Parent(), unread );
+            item.SetLastChangedDate( folderEntry.iDate );
+            item.SetFolderNameL( folderEntry.iDetails );
+            
+            aSnapshot->InsertIsqL( item, key );
+            
+            RegisterFolderL( aSnapshot, folderId );
+            }
+        }
+    
+    CleanupStack::PopAndDestroy( folders );
+	
+	// Register also SMS messages directly under My Folders
+    RegisterFolderL( aSnapshot, KMsvMyFoldersEntryIdValue );
+    
+	LOGGER_LEAVEFN("CSmsDataStore::RegisterUserFoldersL");	   
+    
+    return KErrNone;
+    }
+