wvuing/wvuieng/EngSrc/CCAMessageHandler.cpp
changeset 0 094583676ce7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wvuing/wvuieng/EngSrc/CCAMessageHandler.cpp	Thu Dec 17 08:41:52 2009 +0200
@@ -0,0 +1,841 @@
+/*
+* Copyright (c) 2005 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:  Handler class for incoming and outgoing messages
+*
+*/
+
+
+#include "CCAMessageHandler.h"
+#include "MCAChatInterface.h"
+#include "MCAMessagesWriteInterface.h"
+#include "MCAMessageUtils.h"
+#include "MCAImpsImClient.h"
+#include "MCASettings.h"
+#include "MCAMessageErrorObserver.h"
+#include "MCAImpsFactory.h"
+#include "PublicEngineDefinitions.h"
+#include "impsbuilddefinitions.h"
+#include "mcabuffermemoryhandler.h"
+#include "camessageutil.h"
+
+#include <apmstd.h> // KMaxDataTypeLength
+#include <utf.h>    // CnvUtfConverter
+
+#include "ChatDebugPrint.h"
+
+#include "ImpsCSPAllErrors.h"
+
+// "test character identity and accents, ignore case"
+const TInt KCollationLevel = 1;
+const TInt KMemorySafeValue = 1024; // One kbyte for safe memory allocation.
+
+//-----------------------------------------------------------------------------
+// CCAMessageHandler::CCAMessageHandler
+// ( Other items commented in header )
+//-----------------------------------------------------------------------------
+CCAMessageHandler::CCAMessageHandler( MCAChatInterface& aChatInterface,
+                                      MCAMessageUtils& aMessageUtils,
+                                      MCAImpsFactory* aIMPSFactory )
+        : iMessageUtils( aMessageUtils ),
+        iChatInterface( aChatInterface ),
+        iImpsFactory( aIMPSFactory )
+    {
+    }
+
+//-----------------------------------------------------------------------------
+// CCAMessageHandler::~CCAMessageHandler
+// ( Other items commented in header )
+//-----------------------------------------------------------------------------
+CCAMessageHandler::~CCAMessageHandler()
+    {
+    CHAT_DP_FUNC_ENTER( "CCAMessageHandler::~CCAMessageHandler" );
+    delete iIdle;
+    if ( iSendBuffer )
+        {
+        iSendBuffer->SetObserver( NULL );
+        }
+    iErrorObservers.Close();
+    iHoldingMessages.Close();
+    CHAT_DP_FUNC_DONE( "CCAMessageHandler::~CCAMessageHandler" );
+    }
+
+//-----------------------------------------------------------------------------
+// CCAMessageHandler::NewL
+// ( Other items commented in header )
+//-----------------------------------------------------------------------------
+CCAMessageHandler* CCAMessageHandler::NewL(
+    MCAChatInterface& aChatInterface,
+    MCAMessageUtils& aMessageUtils,
+    MCAImpsFactory* aIMPSFactory )
+    {
+    CHAT_DP_FUNC_ENTER( "CCAMessageHandler::NewL" );
+    CCAMessageHandler* self = CCAMessageHandler::NewLC(
+                                  aChatInterface,
+                                  aMessageUtils,
+                                  aIMPSFactory );
+    CleanupStack::Pop( self );
+    CHAT_DP_FUNC_DONE( "CCAMessageHandler::NewL" );
+    return self;
+    }
+
+//-----------------------------------------------------------------------------
+// CCAMessageHandler::NewLC
+// ( Other items commented in header )
+//-----------------------------------------------------------------------------
+CCAMessageHandler* CCAMessageHandler::NewLC(
+    MCAChatInterface& aChatInterface,
+    MCAMessageUtils& aMessageUtils,
+    MCAImpsFactory* aIMPSFactory )
+    {
+    CHAT_DP_FUNC_ENTER( "CCAMessageHandler::NewLC" );
+    CCAMessageHandler* self = new ( ELeave ) CCAMessageHandler(
+        aChatInterface,
+        aMessageUtils,
+        aIMPSFactory );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CHAT_DP_FUNC_DONE( "CCAMessageHandler::NewLC" );
+    return self;
+    }
+
+//-----------------------------------------------------------------------------
+// CCAMessageHandler::ConstructL
+// ( Other items commented in header )
+//-----------------------------------------------------------------------------
+void CCAMessageHandler::ConstructL()
+    {
+    CHAT_DP_FUNC_ENTER( "CCAMessageHandler::ConstructL" );
+
+    iImpsImClient = iImpsFactory->CreateImClientL();
+
+    iSendBuffer = &iChatInterface.MessageReadInterfaceL( KNullDesC, KNullDesC );
+    iSendBuffer->SetObserver( this );
+    iIdle = CIdle::NewL( CActive::EPriorityIdle );
+    CHAT_DP_FUNC_DONE( "CCAMessageHandler::ConstructL" );
+    }
+
+//-----------------------------------------------------------------------------
+// CCAMessageHandler::HandleNewTextMessageL
+// ( Other items commented in header )
+//-----------------------------------------------------------------------------
+void CCAMessageHandler::HandleNewTextMessageL(  TInt aOpId,
+                                                const TDesC& /*aMessageId*/,
+                                                const TDesC& aSender,
+                                                const TDesC& aGroupId,
+                                                const MDesCArray& aRecipients,
+                                                const MDesCArray& aScreenNames,
+                                                const TDesC& aText,
+                                                TImpsCspIdentifier& aCspId )
+    {
+    CHAT_DP_FUNC_ENTER( "CCAMessageHandler::HandleNewTextMessageL" );
+
+    // Don't use memory handling if this is local echo message
+    MCAMessagesWriteInterface& messageContainer =
+        iChatInterface.MessageWriteInterfaceL(
+            aCspId.Sap(),
+            aCspId.UserId(),
+            ( aGroupId == KNullDesC ? aSender : aGroupId ) );
+
+    if ( !( aGroupId != KNullDesC &&
+            iLocalEchoInGroup &&
+            messageContainer.OwnScreenName().CompareC( aSender, KCollationLevel, NULL ) == 0 ) )
+        {
+        if ( !iMessageUtils.MemoryHandler().FreeMemoryIfNeededL( KMemorySafeValue + aText.Size() ) )
+            {
+            NotifyMessageError( KErrNoMemory, NULL );
+            User::Leave( KErrNoMemory );
+            }
+        }
+
+    HBufC* sap = aCspId.Sap().AllocLC();
+    HBufC* userId = aCspId.UserId().AllocLC();
+
+    MCAMessageCreator::SMessageData data =
+        {
+        KMessageDataVersion,
+        aOpId,
+        *sap,
+        *userId,
+        aSender,
+        ( aGroupId == KNullDesC ? aSender : aGroupId ),
+        &aRecipients,
+        &aScreenNames,
+        aText,
+        KNullDesC8,
+        KNullDesC8,
+        MCAMessage::EMessageReceived
+        };
+    HandleNewMessageL( data );
+
+    CleanupStack::PopAndDestroy( 2, sap );
+    CHAT_DP_FUNC_DONE( "CCAMessageHandler::HandleNewTextMessageL" );
+    }
+
+//-----------------------------------------------------------------------------
+// CCAMessageHandler::HandleNewContentMessageL
+// ( Other items commented in header )
+//-----------------------------------------------------------------------------
+void CCAMessageHandler::HandleNewContentMessageL(
+    TInt aOpId,
+    const TDesC& /*aMessageId*/,
+    const TDesC& aSender,
+    const TDesC& aGroupId,
+    const MDesCArray& aRecipients,
+    const MDesCArray& aScreenNames,
+    const TDesC& aContentType,
+    const TDesC8& aContent,
+    TImpsCspIdentifier& aCspId )
+    {
+    CHAT_DP_FUNC_ENTER( "CCAMessageHandler::HandleNewContentMessageL" );
+
+    // Don't use memory handling if this is local echo message
+    MCAMessagesWriteInterface& messageContainer =
+        iChatInterface.MessageWriteInterfaceL(
+            aCspId.Sap(),
+            aCspId.UserId(),
+            ( aGroupId == KNullDesC ? aSender : aGroupId ) );
+
+    if ( !( aGroupId != KNullDesC &&
+            iLocalEchoInGroup &&
+            messageContainer.OwnScreenName().CompareC( aSender, KCollationLevel, NULL ) == 0 ) )
+        {
+        if ( !iMessageUtils.MemoryHandler().FreeMemoryIfNeededL( KMemorySafeValue + aContent.Size() ) )
+            {
+            NotifyMessageError( KErrNoMemory, NULL );
+            User::Leave( KErrNoMemory );
+            }
+        }
+
+    HBufC* sap = aCspId.Sap().AllocLC();
+    HBufC* userId = aCspId.UserId().AllocLC();
+
+    TBuf8< KMaxDataTypeLength > mimeType;
+    CnvUtfConverter::ConvertFromUnicodeToUtf8( mimeType, aContentType );
+
+    MCAMessageCreator::SMessageData data =
+        {
+        KMessageDataVersion,
+        aOpId,
+        *sap,
+        *userId,
+        aSender,
+        ( aGroupId == KNullDesC ? aSender : aGroupId ),
+        &aRecipients,
+        &aScreenNames,
+        KNullDesC,
+        mimeType,
+        aContent,
+        MCAMessage::EMessageReceived
+        };
+    HandleNewMessageL( data );
+
+    CleanupStack::PopAndDestroy( 2, sap );
+    CHAT_DP_FUNC_DONE( "CCAMessageHandler::HandleNewContentMessageL" );
+    }
+
+
+//-----------------------------------------------------------------------------
+// CCAMessageHandler::HandleNewMessageL
+// ( Other items commented in header )
+//-----------------------------------------------------------------------------
+void CCAMessageHandler::HandleNewMessageL(
+    MCAMessageCreator::SMessageData& aData )
+    {
+    CHAT_DP_FUNC_ENTER( "CCAMessageHandler::HandleNewMessageL" );
+    if ( aData.iTargetId == KNullDesC )
+        {
+        // Invalid message.
+        User::Leave( KErrArgument );
+        }
+    MCAMessagesWriteInterface& messageContainer =
+        iChatInterface.MessageWriteInterfaceL( aData.iSapId,
+                                               aData.iUserId,
+                                               aData.iTargetId );
+
+    MCAMessage* message = iMessageUtils.MessageCreator().CreateMessageL( aData );
+
+    if ( iLocalEchoInGroup
+         && ( message->MessageType() == MCAMessage::EMessageGroup )
+         && ( messageContainer.OwnScreenName().CompareC( aData.iSender,
+                                                         KCollationLevel, NULL ) == 0 ) )
+        {
+        // Do not show message because it is already shown with local echo.
+        CHAT_DP( D_CHAT_LIT( "Group message not shown, because local echo." ) );
+        delete message;
+        return;
+        }
+
+    // set iTargetId to ScreenName if current received message type is EMessageWhisper
+    if ( message->MessageType() == MCAMessage::EMessageWhisper || message->MessageType() == MCAMessage::EMessageGroup )
+        {
+        TInt count = aData.iScreenNames->MdcaCount();
+        MCAMessageCreator::SMessageData data2 =
+            {
+            aData.iVersion,
+            aData.iOpId,
+            aData.iSapId,
+            aData.iUserId,
+            aData.iSender,
+            ( count > 0 ) ? aData.iScreenNames->MdcaPoint( 0 ) : aData.iTargetId,
+            aData.iRecipients,
+            aData.iScreenNames,
+            aData.iText,
+            aData.iContentType,
+            aData.iContentData,
+            aData.iMessager
+            };
+
+        MCAMessage* message2 = iMessageUtils.MessageCreator().CreateMessageL( data2 );
+
+        delete message;
+        message = message2;
+        }
+
+    // Message can get different process state during creation. For example
+    // EContentNotSupported
+    if ( message->ContentProcessState() == MCAMessage::EContentNotProcessed )
+        {
+        message->SetProcessState( MCAMessage::EContentReady );
+        }
+
+    // Add message
+    CAMessageUtil::AppendMessageWithDateStampL(
+        *message,
+        messageContainer,
+        iMessageUtils.MessageCreator() );
+
+    CHAT_DP_FUNC_DONE( "CCAMessageHandler::HandleNewMessageL" );
+    }
+
+//-----------------------------------------------------------------------------
+// CCAMessageHandler::HandleSendCompleteL
+// ( Other items commented in header )
+//-----------------------------------------------------------------------------
+void CCAMessageHandler::HandleSendCompleteL(	TInt aOpId,
+                                             TBool aDeliveryReportOrdered,
+                                             TImpsCspIdentifier& /*aCspId*/ )
+    {
+    CHAT_DP_FUNC_ENTER( "CCAMessageHandler::HandleSendCompleteL" );
+
+    CHAT_DP( D_CHAT_LIT( "Operationcode %d. Delivery ordered %d" ),
+             aOpId, aDeliveryReportOrdered );
+    HandleMessageSentL( KErrNone, aOpId, ETrue );
+    CHAT_DP_FUNC_DONE( "CCAMessageHandler::HandleSendCompleteL" );
+    }
+
+//-----------------------------------------------------------------------------
+// CCAMessageHandler::HandleDeliveryReportL
+// ( Other items commented in header )
+//-----------------------------------------------------------------------------
+void CCAMessageHandler::HandleDeliveryReportL(	const TDesC& /*aMessageId*/,
+                                               TInt /*aResult*/,
+                                               const TDesC* /*aDescription*/,
+                                               TImpsCspIdentifier& /*aCspId*/ )
+    {
+    CHAT_DP_FUNC_ENTER( "CCAMessageHandler::HandleDeliveryReportL" );
+    CHAT_DP_FUNC_DONE( "CCAMessageHandler::HandleDeliveryReportL" );
+    }
+
+//-----------------------------------------------------------------------------
+// CCAMessageHandler::HandleMessageEvent
+// ( Other items commented in header )
+//-----------------------------------------------------------------------------
+void CCAMessageHandler::HandleMessageEvent( TMessageEventType aEvent,
+                                            TInt /*aIndex*/ )
+    {
+    CHAT_DP_FUNC_ENTER( "CCAMessageHandler::HandleMessageEvent" );
+    switch ( aEvent )
+        {
+        case ENewMessage:
+            {
+            if ( !iIdle->IsActive() )
+                {
+                iIdle->Start( TCallBack( SendMessage, this ) );
+                }
+            break;
+            }
+        case EChatDeleted:
+            {
+            // send buffer was deleted
+            iSendBuffer = NULL;
+            break;
+            }
+        default:
+            break;
+        }
+    CHAT_DP_FUNC_DONE( "CCAMessageHandler::HandleMessageEvent" );
+    }
+
+//-----------------------------------------------------------------------------
+// CCAMessageHandler::SendMessage
+// ( Other items commented in header )
+//-----------------------------------------------------------------------------
+TInt CCAMessageHandler::SendMessage( TAny *aInstance )
+    {
+    CCAMessageHandler* handler = static_cast< CCAMessageHandler* >( aInstance );
+    handler->iSendLaunchLock = ETrue;
+    TInt retVal = handler->DoSendMessage();
+    handler->iSendLaunchLock = EFalse;
+    return retVal;
+    }
+
+//-----------------------------------------------------------------------------
+// CCAMessageHandler::DoSendMessage
+// ( Other items commented in header )
+//-----------------------------------------------------------------------------
+TInt CCAMessageHandler::DoSendMessage()
+    {
+    CHAT_DP_FUNC_ENTER( "CCAMessageHandler::DoSendMessage" );
+
+    if ( !iSendBuffer )
+        {
+        // send buffer was deleted, we're shutting down
+        CHAT_DP( D_CHAT_LIT( "There is no send buffer." ) );
+        return EFalse;
+        }
+
+    // 1. Check if there is message in holding.
+    MCAMessage* holdingMessage = NextHoldingMessage();
+    if ( !holdingMessage && !iSendBuffer->UnreadCount() )
+        {
+        CHAT_DP( D_CHAT_LIT( "There is not ready messages for sending." ) );
+        return EFalse;
+        }
+
+    // 2. Choose new message from sendbuffer or use holding message if exists.
+    MCAMessage& message = ( !holdingMessage ? iSendBuffer->ReadNextUnread()
+                            : *holdingMessage );
+
+    // 3. Add message to holding if needed
+    TBool appendedToHolding( EFalse );
+    TRAPD( error, appendedToHolding = AppendedToHoldingL( message ) );
+#ifndef RD_SEND_NOT_SUPPORTED_CONTENT
+    if ( error ) // Corrupted message, inform upstairs
+        {
+        NotifyMessageError(
+            error == KErrOverflow ? error : ECorruptedContent, &message );
+        // Remove sent message from send buffer, because answer will not come.
+        TInt index = iSendBuffer->FindIndex( message );
+        if ( index >= 0 )
+            {
+            iSendBuffer->DeleteMessage( index );
+            }
+        return ETrue;
+        }
+#endif //RD_SEND_NOT_SUPPORTED
+    if ( appendedToHolding )
+        {
+        return ETrue;
+        }
+
+    // 4. Send message
+    TInt opCode( 0 );
+    TRAP( error, opCode = SendMessageToServerL( message ) );
+    CHAT_DP( D_CHAT_LIT( "Send retval ( %d )" ), error );
+
+    if ( error == KErrServerBusy )
+        {
+        TRAPD( err, iHoldingMessages.AppendL( &message ) );
+        if ( err )
+            {
+            CActiveScheduler::Current()->Error( err );
+            }
+        return ETrue;
+        }
+    // 5. Local echo message
+    TRAPD( error2, LocalEchoMessageL( message ) );
+    if ( error2 != KErrNone )
+        {
+        NotifyMessageError( error2, &message );
+        }
+
+    // 6. Handle error
+    if ( error != KErrNone )
+        {
+        TRAP( error2, HandleMessageSentFailedL( message, error ) );
+        if ( error2 )
+            {
+            NotifyMessageError( error2, &message );
+            }
+        // Remove sent message from send buffer, because answer will not come.
+        TInt index = iSendBuffer->FindIndex( message );
+        if ( index >= 0 )
+            {
+            iSendBuffer->DeleteMessage( index );
+            }
+        }
+    else // Send succesfull. -> Local echo
+        {
+        CHAT_DP( D_CHAT_LIT( "Address: %s, UserId: %s, Recipient %s" ),
+                 &message.ServerAddress(),
+                 &message.UserId(),
+                 &message.Recipient() );
+        message.SetOperationCode( opCode );
+        }
+
+    // 7. Check need of
+    TInt unreadCount = iSendBuffer->UnreadCount();
+    TInt holdingMessages( iHoldingMessages.Count() );
+    CHAT_DP( D_CHAT_LIT( "Still %d messages to go. Send buffer has %d messages. \
+                          Holding %d messages" ),
+             unreadCount, iSendBuffer->MessageCount(), holdingMessages );
+
+    CHAT_DP_FUNC_DONE( "CCAMessageHandler::DoSendMessage" );
+    return Max( unreadCount, holdingMessages );
+    }
+
+//-----------------------------------------------------------------------------
+// CCAMessageHandler::HandleMessageSentL
+// ( Other items commented in header )
+//-----------------------------------------------------------------------------
+void CCAMessageHandler::HandleMessageSentL( TInt aStatus, TInt aOperationCode,
+                                            TBool aSuccess )
+    {
+    CHAT_DP_FUNC_ENTER( "CCAMessageHandler::HandleMessageSentL" );
+    CHAT_DP( D_CHAT_LIT( "OpCode = %d, Success = %d" ), aOperationCode, aSuccess );
+
+    if ( !iSendBuffer )
+        {
+        // send buffer was deleted, we're shutting down
+        CHAT_DP( D_CHAT_LIT( "There is no send buffer." ) );
+        return;
+        }
+
+    TInt index = User::LeaveIfError( iSendBuffer->FindIndex( aOperationCode ) );
+
+    if ( !aSuccess )
+        {
+        MCAMessage& message = iSendBuffer->Message( index );
+
+        message.SetContainerInfo( NULL );
+
+        MCAMessage* failedMessage =
+            iMessageUtils.MessageCreator().CreateFailedMessageL( &message );
+        CleanupDeletePushL( failedMessage );
+        MCAMessagesWriteInterface& messageContainer =
+            iChatInterface.MessageWriteInterfaceL( message.ServerAddress(),
+                                                   message.UserId(),
+                                                   message.Recipient() );
+        CleanupStack::Pop( failedMessage );
+        messageContainer.AppendL( failedMessage );
+        NotifyMessageError( aStatus, &message );
+        }
+    iSendBuffer->DeleteMessage( index );
+    CHAT_DP( D_CHAT_LIT( "Send buffer has %d messages." ),
+             iSendBuffer->MessageCount() );
+    CHAT_DP_FUNC_DONE( "CCAMessageHandler::HandleMessageSentL" );
+    }
+
+//-----------------------------------------------------------------------------
+// CCAMessageHandler::SetLocalEchoInGroup
+// ( Other items commented in header )
+//-----------------------------------------------------------------------------
+void CCAMessageHandler::SetLocalEchoInGroup( TBool aLocalEchoInGroup )
+    {
+    iLocalEchoInGroup = aLocalEchoInGroup;
+    }
+
+//-----------------------------------------------------------------------------
+// CCAMessageHandler::NotifyMessageError
+// ( Other items commented in header )
+//-----------------------------------------------------------------------------
+void CCAMessageHandler::NotifyMessageError( TInt aStatus, MCAMessage* aMessage )
+    {
+    TInt count( iErrorObservers.Count() );
+    for ( TInt a( 0 ); a < count; ++a )
+        {
+        iErrorObservers[ a ]->HandleMessageError( aStatus, aMessage );
+        }
+    }
+
+//-----------------------------------------------------------------------------
+// CCAMessageHandler::RegisterChatObserver
+// ( Other items commented in header )
+//-----------------------------------------------------------------------------
+void CCAMessageHandler::RegisterObserver( MCAMessageErrorObserver* aObserver )
+    {
+    TInt index = iErrorObservers.Find( aObserver );
+    if ( index == KErrNotFound )
+        {
+        iErrorObservers.Append( aObserver );
+        }
+    }
+
+//-----------------------------------------------------------------------------
+// CCAMessageHandler::RegisterChatObserver
+// ( Other items commented in header )
+//-----------------------------------------------------------------------------
+void CCAMessageHandler::UnregisterObserver( MCAMessageErrorObserver* aObserver )
+    {
+    TInt index = iErrorObservers.Find( aObserver );
+    if ( index >= 0 )
+        {
+        iErrorObservers.Remove( index );
+        }
+    }
+
+//-----------------------------------------------------------------------------
+// CCAMessageHandler::HandleProcessingComplete
+// ( Other items commented in header )
+//-----------------------------------------------------------------------------
+void CCAMessageHandler::HandleProcessingComplete(
+    MCAContentProcessor& /*aProcessor*/,
+    MCAMessage& /*aMessage*/,
+    TInt aStatus )
+    {
+    if ( !iIdle->IsActive() && aStatus == KErrNone && !iSendLaunchLock )
+        {
+        iIdle->Start( TCallBack( SendMessage, this ) );
+        }
+    }
+
+//-----------------------------------------------------------------------------
+// CCAMessageHandler::NextHoldingMessage
+// ( Other items commented in header )
+//-----------------------------------------------------------------------------
+MCAMessage* CCAMessageHandler::NextHoldingMessage()
+    {
+    TInt holdingMessages = iHoldingMessages.Count();
+    MCAMessage* message = NULL;
+    TInt index( 0 );
+    // Check if holding messages hold one ready message
+    for ( ; index < holdingMessages && !message; ++index )
+        {
+        MCAMessage* msg = iHoldingMessages[ index ];
+        if ( ( msg->ContentProcessState() >= MCAMessage::EContentReady ) ||
+             ( msg->ContentType() == MCAMessage::EContentText ) )
+            {
+            CHAT_DP( D_CHAT_LIT( "Ready holding message found. Index( %d )" ),
+                     index );
+            message = msg;
+            iHoldingMessages.Remove( index );
+            }
+        }
+    return message;
+    }
+
+//-----------------------------------------------------------------------------
+// CCAMessageHandler::NextHoldingMessage
+// ( Other items commented in header )
+//-----------------------------------------------------------------------------
+TBool CCAMessageHandler::AppendedToHoldingL( MCAMessage& aMessage )
+    {
+    switch ( aMessage.ContentType() )
+        {
+        case MCAMessage::EContentPicture: // add scaler
+            {
+            if ( aMessage.ContentProcessState() < MCAMessage::EContentReady )
+                {
+                CHAT_DP( D_CHAT_LIT( "Picture message not yet ready for \
+                                  sending. Put to holding." ) );
+                TInt added = User::LeaveIfError( aMessage.AddContentProcessor(
+                                                     iMessageUtils.ImageScaler(), this ) );
+                if ( added )
+                    {
+                    iHoldingMessages.AppendL( &aMessage );
+                    return ETrue;
+                    }
+                }
+            break;
+            }
+        default: // Flowthrough other types
+            {
+#ifdef RD_SEND_NOT_SUPPORTED_CONTENT
+            if ( aMessage.ContentProcessState() < MCAMessage::EContentReady )
+                {
+                CHAT_DP( D_CHAT_LIT( "Picture message not yet ready for \
+                                  sending. Put to holding." ) );
+                TInt added = User::LeaveIfError( aMessage.AddContentProcessor(
+                                                     iMessageUtils.ImageScaler(), this ) );
+                if ( added )
+                    {
+                    iHoldingMessages.AppendL( &aMessage );
+                    return ETrue;
+                    }
+                }
+#endif //RD_SEND_NOT_SUPPORTED_CONTENT            
+            break;
+            }
+        }
+    return EFalse;
+    }
+
+//-----------------------------------------------------------------------------
+// CCAMessageHandler::SendMessageToServerL
+// ( Other items commented in header )
+//-----------------------------------------------------------------------------
+TInt CCAMessageHandler::SendMessageToServerL( MCAMessage& aMessage )
+    {
+    CHAT_DP_FUNC_ENTER( "CCAMessageHandler::SendMessageToServerL" );
+
+    TInt opCode( 0 );
+    TBuf< KMaxDataTypeLength > mimeType;
+    CnvUtfConverter::ConvertToUnicodeFromUtf8( mimeType, aMessage.MimeType() );
+
+    // granularity of 1 because only one item appended to array
+    CDesCArrayFlat* tempArray = NULL;
+    const MDesCArray* recipients = NULL;
+
+    const TDesC* sender = NULL;
+    const TDesC* groupId = NULL;
+
+    if ( aMessage.ScreenNames() )
+        {
+        groupId = &aMessage.Recipient();
+        if ( aMessage.ScreenNames()->MdcaCount() > 0 )
+            {
+            recipients = aMessage.ScreenNames();
+            }
+        }
+    else
+        {
+        tempArray = new ( ELeave ) CDesCArrayFlat( 1 );
+        CleanupStack::PushL( tempArray );
+        tempArray->AppendL( aMessage.Recipient() );
+        }
+
+    if ( aMessage.ContentType() == MCAMessage::EContentText )
+        {
+        CHAT_DP( D_CHAT_LIT( "Send text message" ) );
+        opCode = iImpsImClient->SendTextMessageL(
+                     sender,
+                     tempArray,
+                     groupId,
+                     recipients,
+                     aMessage.Text(),
+                     EFalse );
+        }
+    else
+        {
+        CHAT_DP( D_CHAT_LIT( "Send content message" ) );
+        TInt size( aMessage.ContentData().Size() );
+        TInt maxSize( iImpsImClient->MaxTransactionContentLengthL() );
+        if ( size > maxSize )
+            {
+            // content too big => can't send
+            CHAT_DP( D_CHAT_LIT( "content too big: %d/%d" ), size, maxSize );
+            User::Leave( KErrOverflow );
+            }
+
+        opCode = iImpsImClient->SendContentMessageL(
+                     sender,
+                     tempArray,
+                     groupId,
+                     recipients,
+                     mimeType,
+                     aMessage.ContentData(),
+                     EFalse );
+        }
+
+    if ( tempArray )
+        {
+        CleanupStack::PopAndDestroy( tempArray );
+        }
+
+    CHAT_DP_FUNC_DONE( "CCAMessageHandler::SendMessageToServerL" );
+    return opCode;
+    }
+
+//-----------------------------------------------------------------------------
+// CCAMessageHandler::HandleMessageSentFailedL
+// ( Other items commented in header )
+//-----------------------------------------------------------------------------
+void CCAMessageHandler::HandleMessageSentFailedL( MCAMessage& aMessage,
+                                                  TInt aError )
+    {
+    CHAT_DP_FUNC_ENTER( "CCAMessageHandler::HandleMessageSentFailedL" );
+    MCAMessage* failMessage =
+        iMessageUtils.MessageCreator().CreateFailedMessageL( &aMessage );
+    CleanupDeletePushL( failMessage );
+    MCAMessagesWriteInterface& messageContainer =
+        iChatInterface.MessageWriteInterfaceL( aMessage.ServerAddress(),
+                                               aMessage.UserId(),
+                                               aMessage.Recipient() );
+    CleanupStack::Pop( failMessage );
+
+    // Notify observers for error.
+    NotifyMessageError( aError, &aMessage );
+    messageContainer.AppendL( failMessage );
+    CHAT_DP_FUNC_DONE( "CCAMessageHandler::HandleMessageSentFailedL" );
+    }
+
+//-----------------------------------------------------------------------------
+// CCAMessageHandler::LocalEchoMessageL
+// ( Other items commented in header )
+//-----------------------------------------------------------------------------
+void CCAMessageHandler::LocalEchoMessageL( MCAMessage& aMessage )
+    {
+    CHAT_DP_FUNC_ENTER( "CCAMessageHandler::LocalEchoMessageL" );
+
+    if ( aMessage.MessageType() == MCAMessage::EMessageGroup
+         && !iLocalEchoInGroup )
+        {
+        // Local echo is not allowed in groups.
+        CHAT_DP( D_CHAT_LIT( " Message not shown because local echo is not \
+                    allowed." ) );
+        return;
+        }
+
+    MCAMessagesWriteInterface& messageContainer =
+        iChatInterface.MessageWriteInterfaceL( aMessage.ServerAddress(),
+                                               aMessage.UserId(),
+                                               aMessage.Recipient() );
+
+    if ( aMessage.MessageType() == MCAMessage::EMessageWhisper )
+        {
+        // Local echo ones for all recipients
+        const MDesCArray* recipients = aMessage.ScreenNames();
+        TInt count( recipients->MdcaCount() );
+        for ( TInt a( 0 ); a < count; ++a )
+            {
+            MCAMessageCreator::SMessageData data =
+                {
+                KMessageDataVersion,
+                aMessage.OperationCode(),
+                aMessage.ServerAddress(),
+                aMessage.UserId(),
+                aMessage.Sender(),
+                recipients->MdcaPoint( a ),
+                aMessage.Recipients(),
+                recipients,
+                aMessage.Text(),
+                aMessage.MimeType(),
+                aMessage.ContentData(),
+                aMessage.MessagerType()
+                };
+            MCAMessage* message =
+                iMessageUtils.MessageCreator().CreateMessageL( data );
+            message->SetProcessState( MCAMessage::EContentReady );
+
+            // Append message
+            CAMessageUtil::AppendMessageWithDateStampL(
+                *message,
+                messageContainer,
+                iMessageUtils.MessageCreator() );
+            }
+        }
+    else
+        {
+        // Append message
+        CAMessageUtil::AppendMessageWithDateStampL(
+            aMessage,
+            messageContainer,
+            iMessageUtils.MessageCreator(),
+            ETrue );
+        }
+    CHAT_DP_FUNC_DONE( "CCAMessageHandler::LocalEchoMessageL" );
+    }
+
+
+// end of file