omads/omadsextensions/adapters/sms/src/SMSAdapterMsvApi.cpp
changeset 0 dab8a81a92de
child 24 8e7494275d3a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omads/omadsextensions/adapters/sms/src/SMSAdapterMsvApi.cpp	Mon Nov 23 14:46:41 2009 +0200
@@ -0,0 +1,1162 @@
+/*
+* Copyright (c) 2005-2007 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 FILES
+#include <txtrich.h>
+#include <smsclnt.h>
+#include <smutset.h>
+#include <smuthdr.h>
+#include <smscmds.h>
+#include <sysutil.h> 
+#include <gsmuelem.h>
+#include <cntdb.h>
+#include <cntitem.h>
+#include <cntfldst.h>
+#include "SMSAdapterMsvApi.h"
+#include "Logger.h" 
+#include "VMessageParser.h"
+#include "SmsDataProviderDefs.h"
+
+
+// CONSTANTS
+
+_LIT16(KSmsNonUnicodeChars, "èéùìòÇØøÅåÆæßÉ£$¥¡ÄÖÑܧ¿äöñüà");
+        
+// OTHER DEFINITIONS
+
+
+
+// ============================= LOCAL FUNCTIONS ===============================
+
+
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CSmsAdapterMsvApi::NewL
+// -----------------------------------------------------------------------------
+//
+ CSmsAdapterMsvApi* CSmsAdapterMsvApi::NewL()
+    {
+    CSmsAdapterMsvApi* self = new( ELeave ) CSmsAdapterMsvApi;
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+    return self;
+    }
+    
+// -----------------------------------------------------------------------------
+// CSmsAdapterMsvApi::~CSmsAdapterMsvApi()
+// -----------------------------------------------------------------------------
+//
+CSmsAdapterMsvApi::~CSmsAdapterMsvApi()
+    {
+    LOGGER_ENTERFN( "CSmsAdapterMsvApi::~CSmsAdapterMsvApi" );
+    SAFEDELETE( iContactsDb );
+	SAFEDELETE( iMtm );
+	SAFEDELETE( iMtmReg );     
+    SAFEDELETE( iSession );
+    LOGGER_LEAVEFN( "CSmsAdapterMsvApi::~CSmsAdapterMsvApi" );
+    }
+       
+// -----------------------------------------------------------------------------
+// CSmsAdapterMsvApi::CSmsAdapterMsvApi
+// -----------------------------------------------------------------------------
+//
+CSmsAdapterMsvApi::CSmsAdapterMsvApi()
+    {     
+    }
+
+// -----------------------------------------------------------------------------
+// CSmsAdapterMsvApi::ConstructL
+// -----------------------------------------------------------------------------
+//
+void CSmsAdapterMsvApi::ConstructL()
+    {
+    LOGGER_ENTERFN( "CSmsAdapterMsvApi::ConstructL" );
+
+    iSession = CMsvSession::OpenSyncL( *this );
+    iMtmReg = CClientMtmRegistry::NewL( *iSession );    
+	iMtm = static_cast<CSmsClientMtm*>( iMtmReg->NewMtmL(KUidMsgTypeSMS) ); 
+
+	iFs = iSession->FileSession();
+	iMessageDrive = MessageServer::CurrentDriveL( iFs );
+	
+	iContactsDb = CContactDatabase::OpenL();
+
+    LOGGER_LEAVEFN( "CSmsAdapterMsvApi::ConstructL" ); 
+    }
+
+// -----------------------------------------------------------------------------
+// CSmsAdapterMsvApi::AddSML
+// -----------------------------------------------------------------------------
+//
+void CSmsAdapterMsvApi::AddSML(
+    CVMessageParser& aSm,
+    TMsvId aFolder,                                                                                                                                                                                                        
+    TMsvId& aSmId )
+    {
+    LOGGER_ENTERFN( "CSmsAdapterMsvApi::AddSML" );
+   
+    if (!ValidFolderL( aFolder ))
+        {
+		LOGGER_WRITE( "AddSML: wrong folder" );
+        User::Leave( KErrArgument );
+        }
+           
+    // Set first default flags  
+    TMsvEntry newEntry;  
+    newEntry.iType = KUidMsvMessageEntry;
+    newEntry.iServiceId = KMsvLocalServiceIndexEntryId;
+    newEntry.iMtm = KUidMsgTypeSMS;
+    newEntry.SetVisible(EFalse);
+    newEntry.SetInPreparation(ETrue);           
+
+    // Create new message entry
+    CMsvEntry* entry = iSession->GetEntryL( aFolder );
+    CleanupStack::PushL( entry );   
+    entry->CreateL( newEntry );
+    aSmId = newEntry.Id();  
+    entry->SetEntryL(newEntry.Id());
+    
+    // Create message header
+
+    CParaFormatLayer* paraFormatLayer = CParaFormatLayer::NewL();
+    CleanupStack::PushL( paraFormatLayer );
+    CCharFormatLayer* charFormatLayer = CCharFormatLayer::NewL();
+    CleanupStack::PushL( charFormatLayer );
+    CRichText* richText = CRichText::NewL( paraFormatLayer, charFormatLayer );
+    CleanupStack::PushL( richText ); 
+    
+    CSmsPDU::TSmsPDUType pduType;
+    
+    if (aFolder == KMsvGlobalInBoxIndexEntryId)
+        {
+        pduType = CSmsPDU::ESmsDeliver;
+        }
+    else if (aFolder == KMsvGlobalOutBoxIndexEntryId ||
+             aFolder == KMsvDraftEntryId ||
+             aFolder == KMsvSentEntryId)  
+        {
+        pduType = CSmsPDU::ESmsSubmit;
+        }
+    else if (aSm.iRecipients.Count() > 0)
+        {
+        pduType = CSmsPDU::ESmsSubmit;
+        }
+    else
+        {
+        pduType = CSmsPDU::ESmsDeliver;
+        }       
+    
+    CSmsHeader* smsHeader = CSmsHeader::NewL( pduType, *richText );
+    CleanupStack::PushL( smsHeader );
+    
+    // Set the message header in the entry's store
+    CMsvStore* store = entry->EditStoreL();
+    CleanupStack::PushL( store );
+    smsHeader->StoreL( *store );
+    store->StoreBodyTextL( *richText );
+    store->CommitL();
+    
+    CleanupStack::PopAndDestroy( store );
+    CleanupStack::PopAndDestroy( smsHeader );
+    CleanupStack::PopAndDestroy( richText );
+    CleanupStack::PopAndDestroy( charFormatLayer );
+    CleanupStack::PopAndDestroy( paraFormatLayer );
+    CleanupStack::PopAndDestroy( entry );
+   
+	DoUpdateSML( aSmId, aSm, ETrue );
+	LOGGER_LEAVEFN( "CSmsAdapterMsvApi::AddSML" );
+    }
+
+// -----------------------------------------------------------------------------
+// CSmsAdapterMsvApi::ReplaceSML
+// -----------------------------------------------------------------------------
+//
+ void CSmsAdapterMsvApi::ReplaceSML( TMsvId aSmId, CVMessageParser& aSm ) 
+    {
+    LOGGER_ENTERFN( "CSmsAdapterMsvApi::ReplaceSML" );
+	DoUpdateSML( aSmId, aSm, EFalse );
+	LOGGER_LEAVEFN( "CSmsAdapterMsvApi::ReplaceSML" );
+    }
+    
+// -----------------------------------------------------------------------------
+// CSmsAdapterMsvApi::DeleteSML
+// -----------------------------------------------------------------------------
+//
+ void CSmsAdapterMsvApi::DeleteSML( TMsvId aSmId )
+    {
+    LOGGER_ENTERFN( "CSmsAdapterMsvApi::DeleteSML" );
+    
+    iMtm->SwitchCurrentEntryL( aSmId );
+    
+    TMsvEntry tEntry = iMtm->Entry().Entry();  		
+    if (tEntry.iType != KUidMsvMessageEntry || tEntry.iMtm != KUidMsgTypeSMS)
+        {
+        LOGGER_WRITE( "Not SMS entry" );
+        User::Leave(KErrNotSupported);
+        }
+    
+	iMtm->SwitchCurrentEntryL( tEntry.Parent() );
+	iMtm->Entry().DeleteL( aSmId );
+	LOGGER_LEAVEFN( "CSmsAdapterMsvApi::DeleteSML" );
+    }
+    
+// -----------------------------------------------------------------------------
+// CSmsAdapterMsvApi::DeleteUserFolderL
+// -----------------------------------------------------------------------------
+//
+ TInt CSmsAdapterMsvApi::DeleteUserFolderL( TMsvId aUid )
+    {
+    LOGGER_ENTERFN( "CSmsAdapterMsvApi::DeleteUserFolderL" );
+    
+    iMtm->SwitchCurrentEntryL( aUid );
+    CMsvEntry& entry = iMtm->Entry();
+    TMsvEntry tEntry = entry.Entry();  		
+    
+    if (tEntry.iType != KUidMsvFolderEntry || tEntry.Parent() != KMsvMyFoldersEntryIdValue)
+        {
+        LOGGER_WRITE( "Not correct folder" );
+        User::Leave(KErrNotSupported);
+        }
+        
+    CMsvEntrySelection* children = entry.ChildrenL();
+    TInt count = children->Count();
+    delete children;
+    
+  	if (count > 0)
+	    {
+	    LOGGER_WRITE( "Folder not empty" );
+	    return KErrInUse;
+	    }
+	    
+	tEntry.SetReadOnly(EFalse);
+	entry.ChangeL( tEntry );
+       
+	iMtm->SwitchCurrentEntryL( tEntry.Parent() );	
+	iMtm->Entry().DeleteL( aUid );
+	
+	LOGGER_LEAVEFN( "CSmsAdapterMsvApi::DeleteUserFolderL" );
+	return KErrNone;
+    }   
+
+// -----------------------------------------------------------------------------
+// CSmsAdapterMsvApi::RetrieveSML
+// -----------------------------------------------------------------------------
+//
+ void CSmsAdapterMsvApi::RetrieveSML(
+    TMsvId aSmId,
+    TMsvId& aParent,
+    CVMessageParser& aSm,
+    TBool& aUnread)
+    {
+    LOGGER_ENTERFN( "CSmsAdapterMsvApi::RetrieveSML" );
+                          
+    iMtm->SwitchCurrentEntryL( aSmId );
+    iMtm->LoadMessageL();
+    
+    CRichText& mtmBody = iMtm->Body();
+	aSm.StoreMessageBodyL( mtmBody );
+       
+    TMsvEntry tEntry = iMtm->Entry().Entry();
+    
+    aUnread = tEntry.Unread();
+	if (aUnread)
+		{
+		aSm.iStatus = KVMsgStatusUnread;
+		}
+	else
+		{
+		aSm.iStatus = KVMsgStatusRead;
+		}
+	
+	aSm.iUniversalTime = tEntry.iDate;	
+	aSm.iHomeTime = HomeTimeFromUniversalTime( aSm.iUniversalTime );
+    
+	aParent = tEntry.Parent();	
+	switch (aParent)
+		{
+		case KMsvGlobalInBoxIndexEntryId:
+			aSm.iFolder = KFolderInbox;
+			break;
+		case KMsvGlobalOutBoxIndexEntryId:
+			aSm.iFolder = KFolderOutbox;
+			break;
+		case KMsvDraftEntryId:
+			aSm.iFolder = KFolderDraft;
+			break;
+		case KMsvSentEntryId:
+			aSm.iFolder = KFolderSent;
+			break;
+		case KMsvMyFoldersEntryIdValue:
+		    aSm.iFolder = KFolderMyFolders;    
+			break;
+		default:
+		    TPtrC folderName;
+		    TTime time;
+		    TBool found = FindUserFolderL(aParent, folderName, time);
+		    if (found && folderName.Length() <= KMaxFolderNameLength)
+		        {
+		        aSm.iFolder = folderName;
+		        }
+		    else
+		        {
+		        LOGGER_WRITE_1( "Not folder name found for folder: %d", aParent );
+		        }       	
+		}
+		LOG( aSm.iFolder );
+		
+	const CSmsHeader& smsHeader = iMtm->SmsHeader();
+	
+	if ( smsHeader.Type() == CSmsPDU::ESmsDeliver )
+	    {
+		TPtrC fromAddr = smsHeader.FromAddress();
+		aSm.ParseTelephoneNumber( fromAddr, aSm.iSender );
+		}
+	else
+		{
+		const CMsvRecipientList& recipients = iMtm->AddresseeList();
+		for (TInt i = 0; i < recipients.Count(); i++)
+			{
+			CVMessageParser::TTelephoneNumber recipientInfo;
+			aSm.ParseTelephoneNumber( recipients[i], recipientInfo );
+			aSm.iRecipients.Append( recipientInfo );
+			}
+		}	
+
+	LOGGER_LEAVEFN( "CSmsAdapterMsvApi::RetrieveSML" );
+    }
+
+// -----------------------------------------------------------------------------
+// CSmsAdapterMsvApi::SendSML
+// -----------------------------------------------------------------------------
+//
+ void CSmsAdapterMsvApi::SendSML( TMsvId aSmId )
+    {
+    LOGGER_ENTERFN( "CSmsAdapterMsvApi::SendSML" );
+   
+	iMtm->SwitchCurrentEntryL( aSmId );
+
+	TMsvEntry msvEntry = iMtm->Entry().Entry();	
+	
+	if (msvEntry.Parent() != KMsvGlobalOutBoxIndexEntryId)
+		{
+ 		LOGGER_WRITE_1( "Wrong folder, parent: %d", msvEntry.Parent() );
+ 		return;
+ 		}
+
+	iMtm->LoadMessageL();
+
+	msvEntry.SetInPreparation( EFalse );
+	msvEntry.SetSendingState( KMsvSendStateWaiting );
+	msvEntry.iDate.UniversalTime();
+	
+	iMtm->RestoreServiceAndSettingsL();
+	CSmsHeader& header = iMtm->SmsHeader();
+	
+	CSmsSettings* sendOptions = CSmsSettings::NewL();
+	CleanupStack::PushL( sendOptions );
+		
+	sendOptions->CopyL( iMtm->ServiceSettings() );
+	sendOptions->SetDelivery( ESmsDeliveryImmediately );
+
+	TSmsDataCodingScheme::TSmsAlphabet dataCoding = TSmsDataCodingScheme::ESmsAlphabet7Bit;
+	CRichText& msgBody = iMtm->Body();
+	HBufC* msgBodyBuf = HBufC::NewLC( msgBody.DocumentLength() );
+	TPtr16 ptrBody = msgBodyBuf->Des();
+	msgBody.Extract( ptrBody, 0, msgBody.DocumentLength() );
+	LOG(ptrBody);
+
+	for (TInt i = 0; i < ptrBody.Length(); i++)
+		{
+		if (IsUnicode( ptrBody[i] ))
+			{
+			LOGGER_WRITE_1( "Character %d is unicode", i );
+			dataCoding = TSmsDataCodingScheme::ESmsAlphabetUCS2;
+			break;
+			}
+		}
+
+	sendOptions->SetCharacterSet( dataCoding );
+	CleanupStack::PopAndDestroy( msgBodyBuf ); 
+		
+	header.SetSmsSettingsL( *sendOptions );
+	if( header.Message().ServiceCenterAddress().Length() == 0 )
+		{
+		LOGGER_WRITE( "header.Message().ServiceCenterAddress().Length() == 0" );    
+		
+		CSmsSettings* serviceSettings = &( iMtm->ServiceSettings() );
+        
+		if (!serviceSettings->ServiceCenterCount())
+			{
+			LOGGER_WRITE("Cervice Center not found, could not send message");
+			User::Leave( KErrCompletion );
+			}
+		else
+			{
+			CSmsServiceCenter* sc =  &serviceSettings->GetServiceCenter( serviceSettings->DefaultServiceCenter() );
+			header.Message().SetServiceCenterAddressL( sc->Address() );	
+			}				
+		}
+
+    const CMsvRecipientList& addrList = iMtm->AddresseeList();
+    if ( addrList.Count() == 0 )
+        {
+		LOGGER_WRITE( "SendSML: no recipient" );
+        User::Leave( KErrGeneral );
+        }
+   
+	CMsvEntry* entry = &( iMtm->Entry() );
+	entry->ChangeL( msvEntry );	
+	iMtm->SaveMessageL();
+
+	CMsvEntrySelection* sel = new (ELeave) CMsvEntrySelection;
+	CleanupStack::PushL( sel );
+	sel->AppendL( entry->EntryId() );
+
+	TBuf8<1> dummy;
+	CMsvOperationActiveSchedulerWait* waiter = CMsvOperationActiveSchedulerWait::NewLC();
+	waiter->iStatus = KRequestPending;
+	CMsvOperation* op = iMtm->InvokeAsyncFunctionL( ESmsMtmCommandScheduleCopy, *sel, dummy, waiter->iStatus );
+	CleanupStack::PushL( op );
+	waiter->Start();
+	
+	LOGGER_WRITE_1( "InvokeAsyncFunctionL: status %d", waiter->iStatus.Int());
+    
+	CleanupStack::PopAndDestroy( 4 ); // op, waiter, sel, sendOptions	
+	
+	LOGGER_LEAVEFN( "CSmsAdapterMsvApi::SendSML" );
+    }
+    
+// -----------------------------------------------------------------------------
+// CSmsAdapterMsvApi::HandleSessionEventL
+// -----------------------------------------------------------------------------
+//
+void CSmsAdapterMsvApi::HandleSessionEventL( TMsvSessionEvent aEvent, TAny*, TAny*, TAny* )
+    {
+    LOGGER_WRITE_1( "CSmsAdapterMsvApi::HandleSessionEventL: %d", aEvent);
+    
+    switch ( aEvent )
+        {
+        case EMsvCloseSession: // The client should immediately close the session with the Message Server.
+        case EMsvServerTerminated: // The Message Server has been terminated.
+                                   // All clients must close their sessions immediately. 
+            {
+            if (iSession)
+                {
+				SAFEDELETE( iMtm );
+				SAFEDELETE( iMtmReg );
+                SAFEDELETE( iSession );
+                }
+            }   
+            break;
+        
+        default:
+            // Nothing is done
+            break;
+        } 
+    }
+
+// -----------------------------------------------------------------------------
+// CSmsAdapterMsvApi::MsvSession
+// -----------------------------------------------------------------------------
+//
+CMsvSession* CSmsAdapterMsvApi::MsvSessionL()
+	{
+	if (!iSession)
+		{
+		User::Leave( KErrGeneral );
+		}
+	return iSession;
+	}
+
+// -----------------------------------------------------------------------------
+//	CSmsAdapterMsvApi::CleanFolderGetMsvIdsL
+// -----------------------------------------------------------------------------
+//
+CMsvEntrySelection* CSmsAdapterMsvApi::CleanFolderGetMsvIdsL(TMsvId aFolderId)
+    {
+    LOGGER_ENTERFN( "CMsvEntrySelection::CleanFolderGetMsvIdsL" );
+    
+    CMsvEntry* cEntry = iSession->GetEntryL( KMsvRootIndexEntryId );
+    CleanupStack::PushL( cEntry );
+    
+    cEntry->SetEntryL( aFolderId );
+    cEntry->SetSortTypeL( TMsvSelectionOrdering( KMsvNoGrouping, EMsvSortByNone, EFalse ) );
+    CMsvEntrySelection* msvEntrySelection = cEntry->ChildrenWithMtmL( KUidMsgTypeSMS );
+    
+    CleanupStack::PopAndDestroy( cEntry );
+    CleanupStack::PushL( msvEntrySelection );
+    
+    for (TInt i = 0; i < msvEntrySelection->Count(); i++)
+        {
+        CMsvEntry* entry = iSession->GetEntryL( msvEntrySelection->At(i) );
+        CleanupStack::PushL( entry );
+        TMsvEntry tEntry = entry->Entry();
+        tEntry.SetReadOnly( EFalse );
+        entry->ChangeL( tEntry );
+        DeleteSML( msvEntrySelection->At(i) );
+        CleanupStack::PopAndDestroy(); //entry
+        }
+        
+    CleanupStack::Pop(msvEntrySelection);
+    LOGGER_LEAVEFN( "CSmsAdapterMsvApi::CleanFolderGetMsvIdsL" );
+    return msvEntrySelection;
+    }
+    
+// -----------------------------------------------------------------------------
+//	CSmsAdapterMsvApi::CleanFolderL
+// -----------------------------------------------------------------------------
+//
+void CSmsAdapterMsvApi::CleanFolderL(TMsvId aFolderId)
+    {
+    CMsvEntrySelection* msvEntrySelection = CleanFolderGetMsvIdsL(aFolderId);
+    delete msvEntrySelection;
+    }
+    
+// -----------------------------------------------------------------------------
+// CSmsAdapterMsvApi::CleanUserFoldersL
+// Cleans all user folders from SMS messages
+// -----------------------------------------------------------------------------
+void CSmsAdapterMsvApi::CleanUserFoldersL() 
+    {
+    LOGGER_ENTERFN( "CSmsAdapterMsvApi::CleanUserFoldersL" );
+    
+    // Get the folder	
+	CMsvEntry* msvEntry = iSession->GetEntryL(KMsvMyFoldersEntryIdValue);
+	CleanupStack::PushL(msvEntry);
+	
+	// Find all of it's childs
+	CMsvEntrySelection* folders = msvEntry->ChildrenWithTypeL(KUidMsvFolderEntry);
+	CleanupStack::PopAndDestroy(msvEntry); 
+	CleanupStack::PushL(folders);
+	
+	TInt error(KErrNone);
+
+    for (TInt index = 0; index < folders->Count(); index++)
+        {
+        TMsvId folderId = folders->At(index);
+        
+        if (folderId != KMsvMyFoldersTemplatesFolderId)
+            {
+            CleanFolderL(folderId);
+            error = DeleteUserFolderL(folderId);
+            if (error != KErrNone)
+                {
+                // Note: folder is not deleted if contains other message items (like MMS)
+                // In this case DeleteUserFolderL returns KErrInUse.
+                LOGGER_WRITE_1("iMsvApi->DeleteUserFolderL failed with %d", error);
+                }
+            }
+        }
+	
+	CleanupStack::PopAndDestroy(folders);
+	
+	// Delete also SMS messages directly under My Folders
+	CleanFolderL(KMsvMyFoldersEntryIdValue);
+	LOGGER_LEAVEFN( "CSmsAdapterMsvApi::CleanUserFoldersL" );
+    }
+   
+// -----------------------------------------------------------------------------
+//	CSmsAdapterMsvApi::DiskSpaceBelowCriticalLevelL
+// -----------------------------------------------------------------------------
+//
+TBool CSmsAdapterMsvApi::DiskSpaceBelowCriticalLevelL( TInt aDataSize )
+    {
+    return SysUtil::DiskSpaceBelowCriticalLevelL( &iFs, aDataSize, iMessageDrive );
+    }
+
+// -----------------------------------------------------------------------------
+//	CSmsAdapterMsvApi::UpdateSMStatusL
+// -----------------------------------------------------------------------------
+//
+void CSmsAdapterMsvApi::UpdateSMStatusL( TMsvId aSmId, CVMessageParser &aSm )
+    {
+	LOGGER_ENTERFN( "CSmsAdapterMsvApi::UpdateSMStatusL" );
+
+	iMtm->SwitchCurrentEntryL( aSmId );
+
+	CMsvEntry& msvEntry = iMtm->Entry();
+	const TMsvEntry& oldEntry = msvEntry.Entry();
+	
+	TMsvEntry newEntry( oldEntry );
+
+	// STATUS
+	if (aSm.iStatus.Compare( KVMsgStatusUnread ) == 0)
+		{
+		newEntry.SetUnread( ETrue );
+		}
+	else if (aSm.iStatus.Compare( KVMsgStatusRead ) == 0)
+		{
+		newEntry.SetUnread( EFalse );
+		}
+	else 
+		{
+		LOGGER_WRITE( "Unexpected status, not updated" );
+		LOG( aSm.iStatus );
+		}
+
+	msvEntry.ChangeL( newEntry );
+	LOGGER_LEAVEFN( "CSmsAdapterMsvApi::UpdateSMStatusL" );
+    }
+
+// -----------------------------------------------------------------------------
+//	CSmsAdapterMsvApi::DoUpdateSML
+// -----------------------------------------------------------------------------
+//
+void CSmsAdapterMsvApi::DoUpdateSML( TMsvId aSmId, CVMessageParser &aSm, TBool aNewSm )
+    {
+	LOGGER_WRITE_1( "CSmsAdapterMsvApi::DoUpdateSML: %d", aSmId );
+	TInt i;
+
+	iMtm->SwitchCurrentEntryL( aSmId );
+	iMtm->LoadMessageL();	
+	CMsvEntry& msvEntry = iMtm->Entry();
+	const TMsvEntry& oldEntry = msvEntry.Entry();
+	TMsvEntry newEntry(oldEntry);
+
+	// Set message status
+	if (aSm.iStatus.Compare( KVMsgStatusUnread ) == 0)
+		{
+		newEntry.SetUnread( ETrue );
+		}
+	else if (aSm.iStatus.Compare( KVMsgStatusRead ) == 0)
+		{
+		newEntry.SetUnread( EFalse );
+		}
+	else if (aNewSm)
+		{
+		newEntry.SetUnread( EFalse ); // by default msg is not unread, if we don't know
+		}	
+
+	// Set time. store format is universal
+	if ( aSm.iUniversalTime.Int64() > 0 )
+		{
+		newEntry.iDate = aSm.iUniversalTime;
+		}
+	else if ( aSm.iHomeTime.Int64() > 0 )
+		{
+		newEntry.iDate = UniversalTimeFromHomeTime( aSm.iHomeTime );
+		}
+	else
+		{
+		newEntry.iDate.UniversalTime();
+		}	
+	
+	// ADDRESS INFORMATION
+	TMsvId parent = newEntry.Parent();
+	LOGGER_WRITE_1( "Parent is %d", parent );
+	
+	TBuf<KNameMaxLength> addrBookName;
+	
+	CSmsHeader& header = iMtm->SmsHeader();
+	
+	if (header.Type() == CSmsPDU::ESmsDeliver)
+		{
+		if (aSm.iSender.iName.Length() > 0)
+			{
+			newEntry.iDetails.Set( aSm.iSender.iName );
+			header.SetFromAddressL( aSm.iSender.iName );
+			}
+		else if (aSm.iSender.iNumber.Length() > 0)
+			{
+			FetchNameFromContactsL(aSm.iSender.iNumber, addrBookName);
+			if (addrBookName.Length() > 0)
+				{
+				newEntry.iDetails.Set( addrBookName );
+				header.SetFromAddressL( addrBookName );
+				}
+			else
+				{		
+				newEntry.iDetails.Set( aSm.iSender.iNumber );
+				header.SetFromAddressL( aSm.iSender.iNumber );
+				}
+			}
+		CSmsMessage& smsMsg = header.Message();
+		CSmsPDU& smsPdu = smsMsg.SmsPDU();
+		CSmsDeliver* smsDeliver = reinterpret_cast<CSmsDeliver*>( &smsPdu );	
+		smsDeliver->SetServiceCenterTimeStamp( newEntry.iDate );
+		}
+	else // message to be sent
+		{
+		if (!aNewSm)
+			{
+			const CMsvRecipientList& addrList = iMtm->AddresseeList();
+    		TInt numOldAddr = addrList.Count();		
+    		for (i = 0; i < numOldAddr; i++)
+    			{
+    			iMtm->RemoveAddressee( i );
+    			}	
+			}		
+		
+		TInt numRecipients = aSm.iRecipients.Count();
+		
+		if (numRecipients > 0)
+			{
+			if (aSm.iRecipients[0].iName.Length() > 0)
+				{
+				newEntry.iDetails.Set( aSm.iRecipients[0].iName );
+				}
+			else if (aSm.iRecipients[0].iNumber.Length() > 0)
+				{
+				FetchNameFromContactsL(aSm.iRecipients[0].iNumber, addrBookName);
+				if (addrBookName.Length() > 0)
+					{
+					newEntry.iDetails.Set( addrBookName );
+					}
+				else
+					{
+					newEntry.iDetails.Set( aSm.iRecipients[0].iNumber );
+					}	
+				}
+			}
+			
+		for (i = 0; i < numRecipients; i++)
+			{
+			if (aSm.iRecipients[i].iNumber.Length() > 0)
+				{
+				if (aSm.iRecipients[i].iName.Length() > 0)
+					{
+					iMtm->AddAddresseeL( aSm.iRecipients[i].iNumber, aSm.iRecipients[i].iName );
+					}
+				else
+					{
+					FetchNameFromContactsL( aSm.iRecipients[i].iNumber, addrBookName );
+					iMtm->AddAddresseeL( aSm.iRecipients[i].iNumber, addrBookName );
+					}	
+				}
+			} 			
+		} // else
+
+	// MESSAGE BODY
+	LOGGER_WRITE( "Add message body" );
+	CRichText& mtmBody = iMtm->Body();
+	mtmBody.Reset();
+	aSm.LoadMessageBodyL( mtmBody );
+
+    TBuf<KSmsDescriptionLength> description;
+	description.Zero();
+	if (aSm.iMessageBody)
+		{
+		TPtrC16 leftBody = aSm.iMessageBody->Left( KSmsDescriptionLength );	
+		description.Copy( leftBody );
+		
+		for (i = 0; i < description.Length(); i++)
+			{
+			if (description[i] == '\n' || description[i] == '\r')
+				{
+				description[i] = ' ';
+				}
+			}	
+		newEntry.iDescription.Set( description );
+		}
+		
+	newEntry.SetVisible( ETrue );
+    newEntry.SetComplete( ETrue );
+    newEntry.SetInPreparation( EFalse );    
+    newEntry.SetSendingState( KMsvSendStateUponRequest );		
+
+	msvEntry.ChangeL( newEntry );
+
+	LOGGER_WRITE( "Save message" );
+	iMtm->SaveMessageL(); 
+	
+	LOGGER_LEAVEFN( "CSmsAdapterMsvApi::DoUpdateSML" );		
+    }
+
+// -----------------------------------------------------------------------------
+// CSmsAdapterMsvApi::ValidUserFolder
+// -----------------------------------------------------------------------------
+//
+TBool CSmsAdapterMsvApi::ValidFolderL( TMsvId aFolder, TBool aOutboxValid )
+    {
+    TBool valid(EFalse);
+    
+    switch ( aFolder )
+        {
+        case KMsvGlobalInBoxIndexEntryId:
+            valid = ETrue;  
+            break;
+        case KMsvDraftEntryId:
+           valid = ETrue;  
+           break;        
+        case KMsvSentEntryId:
+           valid = ETrue;  
+           break;
+        case KMsvGlobalOutBoxIndexEntryId:
+            if (aOutboxValid)
+                {
+                valid = ETrue;
+                }
+            break;
+        case KMsvMyFoldersEntryIdValue:
+           valid = ETrue;  
+           break;             
+        default:
+            valid = FindUserFolderL(aFolder);
+        }
+    
+    return valid;          
+    }
+
+// -----------------------------------------------------------------------------
+// CSmsAdapterMsvApi::FindUserFolderL
+// -----------------------------------------------------------------------------
+//    
+TBool CSmsAdapterMsvApi::FindUserFolderL(TMsvId aFolder, TPtrC& aName, TTime& aDate)
+    {
+    TBool found(EFalse);
+    
+    CMsvEntry* entry = iSession->GetEntryL( KMsvMyFoldersEntryIdValue );
+    CleanupStack::PushL( entry );
+     
+    CMsvEntrySelection* selection = entry->ChildrenL();
+    CleanupStack::PushL( selection );
+    
+    TMsvId serviceId;
+    TMsvEntry entryT;
+
+    for( TInt i = 0; i < selection->Count(); i++ )
+        {
+        User::LeaveIfError( iSession->GetEntry( selection->At( i ), serviceId, entryT ) );
+        
+        if ( !entryT.Deleted() && entryT.iType == KUidMsvFolderEntry && entryT.Id() == aFolder )
+            {
+            found = ETrue;
+            aDate = entryT.iDate;
+            aName.Set(entryT.iDetails);
+            break;
+            }
+        }
+    
+    CleanupStack::PopAndDestroy( 2 ); // entry, selection    
+    
+    return found;        
+    }
+    
+// -----------------------------------------------------------------------------
+// CSmsAdapterMsvApi::FindUserFolderL
+// -----------------------------------------------------------------------------
+//    
+TBool CSmsAdapterMsvApi::FindUserFolderL(TMsvId aFolder)
+    {
+    TPtrC name;
+    TTime time;
+    
+    return FindUserFolderL(aFolder, name, time); 
+    }    
+    
+// -----------------------------------------------------------------------------
+// CSmsAdapterMsvApi::FindUserFolderL
+// -----------------------------------------------------------------------------
+//    
+TBool CSmsAdapterMsvApi::FindUserFolderL(const TDesC& aName, TMsvId& aFolder)
+    {
+    CMsvEntry* entry = iSession->GetEntryL( KMsvMyFoldersEntryIdValue );
+    CleanupStack::PushL( entry );
+     
+    CMsvEntrySelection* selection = entry->ChildrenL();
+    CleanupStack::PushL( selection );
+    
+    TBool found(EFalse);
+    TMsvId serviceId;
+    TMsvEntry entryT;
+
+    for( TInt i = 0; i < selection->Count(); i++ )
+        {
+        User::LeaveIfError( iSession->GetEntry( selection->At( i ), serviceId, entryT ) );
+        
+        if ( !entryT.Deleted() && entryT.iType == KUidMsvFolderEntry && 
+            aName.Compare(entryT.iDescription) == 0 )
+            {
+            found = ETrue;
+            aFolder = entryT.Id();
+            break;
+            }
+        }
+    
+    CleanupStack::PopAndDestroy( 2 ); // entry, selection    
+    
+    return found;           
+    }
+
+// -----------------------------------------------------------------------------
+// CSmsAdapterMsvApi::IsUnicode
+// -----------------------------------------------------------------------------
+//
+TBool CSmsAdapterMsvApi::IsUnicode( const TUint16 aValue )
+    {
+	if ( aValue > 0x7F && KSmsNonUnicodeChars().Locate( aValue ) < 0 )
+		{
+		LOGGER_WRITE_1( "IsUnicode: Found UC char %d", aValue );
+		return ETrue;
+		}
+	else
+		{
+		return EFalse;
+		}
+    }
+
+// -----------------------------------------------------------------------------
+// CSmsAdapterMsvApi::MoveSML
+// Moves SM to another folder.
+// -----------------------------------------------------------------------------
+void CSmsAdapterMsvApi::MoveSML( TMsvId aSmId, TMsvId aParentId )
+    {
+    LOGGER_ENTERFN( "CSmsAdapterMsvApi::MoveSML starts" );
+    
+    if ( !ValidFolderL( aParentId ) )
+        {
+		LOGGER_WRITE( "MoveSML: wrong folder" );
+        User::Leave( KErrArgument );
+        }
+	
+	// Find the parent
+	CMsvEntry* clientEntry( NULL );
+	
+	// Find this entry and put it to cleanup stack
+	clientEntry = iSession->GetEntryL( aSmId );
+	CleanupStack::PushL( clientEntry );
+	
+	// Check that this is a SMS message
+	TMsvEntry entryT = clientEntry->Entry();
+	if (entryT.iType != KUidMsvMessageEntry || entryT.iMtm != KUidMsgTypeSMS)
+	    {
+	    LOGGER_WRITE( "MoveSML: wrong entry type" );
+	    User::Leave( KErrArgument );
+	    }
+   
+	// Find parent id, we'll be moving it's childs
+	TMsvId parentId = entryT.Parent();
+	
+	// Make sure that the parent has changed
+	if (parentId != aParentId)
+		{
+	    // Set parent as context
+	    clientEntry->SetEntryL( parentId );
+
+		// Move the child item to another branch, use temporary waiter object
+		CMsvOperationActiveSchedulerWait* w = CMsvOperationActiveSchedulerWait::NewLC();
+		CMsvOperation* op = clientEntry->MoveL( aSmId, aParentId, w->iStatus );
+		w->Start();
+		SAFEDELETE( op );
+		CleanupStack::PopAndDestroy();
+		
+		}
+	else
+		{
+		LOGGER_WRITE( "CSmsAdapterMsvApi::MoveSML, identical parents." );
+		}		  
+	
+ 	CleanupStack::PopAndDestroy(); // entry
+ 	
+ 	LOGGER_LEAVEFN( "CSmsAdapterMsvApi::MoveSML" );
+    }
+
+// -----------------------------------------------------------------------------
+// CSmsAdapterMsvApi::AddUserFolderL
+// Creates new user folder
+// -----------------------------------------------------------------------------        
+TInt CSmsAdapterMsvApi::AddUserFolderL( TMsvId& aFolder, const TDesC& aName )
+    {
+    LOGGER_ENTERFN( "CSmsAdapterMsvApi::AddUserFolderL" );
+    LOG(aName);
+        
+    // Make sure that we are not going to add same folder twise
+    TBool found(EFalse);
+    found = FindUserFolderL(aName, aFolder);
+    if ( found )
+        {
+        LOGGER_WRITE( "Folder already exists" );
+        return KErrNone;
+        } 
+        
+    CMsvEntry* entry = iSession->GetEntryL(KMsvMyFoldersEntryIdValue);
+    CleanupStack::PushL( entry );
+    
+    TTime date;
+    date.UniversalTime();      
+    
+    TMsvEntry folderEntry;
+    folderEntry.iType = KUidMsvFolderEntry;
+    folderEntry.iMtm = KUidMsvLocalServiceMtm;
+    folderEntry.iDetails.Set(aName);   
+    folderEntry.iServiceId = KMsvLocalServiceIndexEntryIdValue;
+    folderEntry.iSize = sizeof(folderEntry);
+    folderEntry.iDate = date;
+    folderEntry.SetStandardFolder(EFalse);
+    folderEntry.SetVisible(ETrue);
+    folderEntry.SetComplete(ETrue);
+    folderEntry.SetInPreparation(EFalse); 
+    folderEntry.SetReadOnly(EFalse);  
+    
+    entry->CreateL(folderEntry);
+    CleanupStack::PopAndDestroy(entry);
+    
+    aFolder = folderEntry.Id();
+    LOGGER_LEAVEFN( "CSmsAdapterMsvApi::AddUserFolderL" );
+    return KErrNone;
+    }
+    
+// -----------------------------------------------------------------------------
+// CSmsAdapterMsvApi::UpdateUserFolderL
+// Updates user folder (changes name)
+// -----------------------------------------------------------------------------    
+TInt CSmsAdapterMsvApi::UpdateUserFolderL( TMsvId aFolder, const TDesC& aName )
+    {
+    LOGGER_ENTERFN( "CSmsAdapterMsvApi::UpdateUserFolderL" );
+    LOG(aName);
+    
+    CMsvEntry* entry = iSession->GetEntryL( aFolder );
+    CleanupStack::PushL( entry );
+    
+    TMsvEntry tEntry = entry->Entry();
+    
+    if ( tEntry.iType != KUidMsvFolderEntry )
+        {
+        CleanupStack::PopAndDestroy( entry );
+        LOGGER_WRITE( "No message folder" );
+        return KErrGeneral;
+        }
+       
+    tEntry.iDetails.Set(aName);   
+    tEntry.iDescription.Set(aName);
+    
+    entry->ChangeL(tEntry);
+    
+    CleanupStack::PopAndDestroy( entry );
+    LOGGER_LEAVEFN( "CSmsAdapterMsvApi::UpdateUserFolderL" );
+    return KErrNone;
+    } 
+
+// -----------------------------------------------------------------------------
+// CSmsAdapterMsvApi::UniversalTimeFromHomeTime
+// Converts local time to universal time.
+// -----------------------------------------------------------------------------    
+TTime CSmsAdapterMsvApi::UniversalTimeFromHomeTime( TTime aTime )
+	{	
+	TLocale locale;
+	locale.Refresh();
+	
+	TTimeIntervalSeconds universalTimeOffset = locale.UniversalTimeOffset();
+	aTime -= universalTimeOffset;
+	
+	if (locale.QueryHomeHasDaylightSavingOn())
+    	{
+    	TTimeIntervalHours daylightSaving( 1 );
+    	aTime -= daylightSaving;
+    	}	
+	
+	return aTime;
+	}
+
+// -----------------------------------------------------------------------------
+// CSmsAdapterMsvApi::HomeTimeFromUniversalTime
+// Converts universal time to local time.
+// -----------------------------------------------------------------------------    
+TTime CSmsAdapterMsvApi::HomeTimeFromUniversalTime( TTime aTime )
+	{
+	TLocale locale;
+	locale.Refresh();
+	
+	TTimeIntervalSeconds universalTimeOffset = locale.UniversalTimeOffset();
+	aTime += universalTimeOffset;
+	
+	if (locale.QueryHomeHasDaylightSavingOn())
+    	{
+    	TTimeIntervalHours daylightSaving( 1 );
+    	aTime += daylightSaving;
+    	}
+	
+	return aTime;
+	}
+	
+// -----------------------------------------------------------------------------
+// CSmsAdapterMsvApi::FetchNameFromContactsL
+// Searches contact name of given number from phone book
+// If not found, empty descriptor is returned.
+// -----------------------------------------------------------------------------    
+void CSmsAdapterMsvApi::FetchNameFromContactsL(const TDesC& aNumber, TDes& aName)
+	{
+	LOGGER_ENTERFN( "CSmsAdapterMsvApi::FetchNameFromContactsL" );
+	LOG(aNumber);
+	
+	aName.Zero(); 
+	
+	const TInt KNumDigitsToMatch(8);			
+	CContactIdArray* contactIds = iContactsDb->MatchPhoneNumberL(aNumber, KNumDigitsToMatch);		
+	if (contactIds->Count() != 1)
+		{
+		delete contactIds;
+		return;
+		}
+	CleanupStack::PushL(contactIds);		
+ 
+	CContactItem* item = iContactsDb->ReadContactLC((*contactIds)[0]);
+	CContactItemFieldSet& fieldSet = item->CardFields();
+		
+	TPtrC familyName;
+	TPtrC givenName;
+	TInt pos;
+	
+	pos = fieldSet.Find(KUidContactFieldFamilyName);
+	if (pos >= 0)
+		{
+		CContactItemField& itemField=fieldSet[pos];
+		if (!(itemField.IsHidden()) && !(itemField.IsDisabled()))
+			{
+			CContactTextField* textField = itemField.TextStorage();
+			familyName.Set(textField->Text());
+			}				
+		}
+	pos = fieldSet.Find(KUidContactFieldGivenName);
+	if (pos >= 0)
+		{
+		CContactItemField& itemField=fieldSet[pos];
+		if (!(itemField.IsHidden()) && !(itemField.IsDisabled()))
+			{
+			CContactTextField* textField = itemField.TextStorage();
+			givenName.Set(textField->Text());
+			}				
+		}	
+	
+	TInt spaceLeft = aName.MaxLength();
+	
+	if (familyName.Length() <= spaceLeft)
+		{
+		aName.Append(familyName);
+		aName.Trim();
+		spaceLeft -= aName.Length();
+		}
+		
+	if ((givenName.Length() + 1) <= spaceLeft)
+		{
+		aName.Append(' ');
+		aName.Append(givenName);
+		aName.Trim();
+		}
+		
+	LOG(aName);	
+	
+	CleanupStack::PopAndDestroy(2); // item, contactIds
+	LOGGER_LEAVEFN( "CSmsAdapterMsvApi::FetchNameFromContactsL" );
+	}
+		
+// End of file