messagingfw/sendas/server/src/csendasmessage.cpp
changeset 0 8e480a14352b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/messagingfw/sendas/server/src/csendasmessage.cpp	Mon Jan 18 20:36:02 2010 +0200
@@ -0,0 +1,1126 @@
+// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include "csendasmessage.h"
+
+#include <u32std.h>
+#include <mtclbase.h>
+#include <msvuids.h>
+#include <mtmuids.h>
+#include <txtrich.h>
+#include <mturutils.h>
+
+#include "csendassender.h"
+#include "csendassession.h"
+#include "csendasattachment.h"
+#include "csendasmtmmanager.h"
+#include "sendasserverdefs.h"
+#include "csendasactivecontainer.h"
+#include "csendaseditwatcher.h"
+#include "tsendasserverpanic.h"
+
+// max index for incoming RMessage parameters
+const TInt KSendAsMaxMessageIndex = 3;
+
+CSendAsMessage* CSendAsMessage::NewL(CSendAsSession& aSession)
+	{
+	CSendAsMessage* self = new(ELeave) CSendAsMessage(aSession);
+	return self;
+	}
+	
+CSendAsMessage::~CSendAsMessage()
+	{
+	delete iSender;
+	delete iClientMtm;
+	delete iAttachment;
+	}
+	
+CSendAsMessage::CSendAsMessage(CSendAsSession& aSession)
+: iSession(aSession)
+	{
+	// the data members of iProgress are defined such that when they
+	// are zero initialised (like being embedded in a C-Class) this is
+	// the same as the default progress structure.
+	}
+
+/** Dispatch the subsession message to the correct handler.
+ 
+The return value indicates to the owner session if we are doing an
+asynchronous operation.  ETrue is async: EFalse is sync.
+Errors can only be returned by leaving.  This method should be encapsulated
+in a trap harness to prevent the server AO from leaving during a ServiceL.
+
+@param	aMesasge
+The IPC message.
+
+@return
+A value of true if the request is asynchronous, otherwise a value of false
+indicating that the request is synchronous.
+*/
+TBool CSendAsMessage::DoSubSessionServiceL(const RMessage2& aMessage)
+	{
+	TBool async = EFalse;
+
+	switch( aMessage.Function() )
+		{
+	case ESAMCreateForAccount:
+		{
+		CreateMessageForAccountL(aMessage);
+		} break;
+	case ESAMCreateByType:
+		{
+		CreateMessageByTypeL(aMessage);
+		} break;
+	case ESAMGetProgress:
+		{
+		ProgressL(aMessage);
+		} break;
+	case ESAMDelete:
+		{
+		DeleteMessageL(aMessage);
+		} break;
+	case ESAMSetBodyFirst:
+		{
+		SetBodyTextL(aMessage, ETrue);
+		} break;
+	case ESAMSetBodyNext:
+		{
+		SetBodyTextL(aMessage, EFalse);
+		} break;
+	case ESAMSetSubject:
+		{
+		SetSubjectL(aMessage);
+		} break;
+	case ESAMSetBioType:
+		{
+		SetBioTypeL(aMessage);
+		} break;
+	case ESAMAddRecipient:
+		{
+		AddRecipientL(aMessage);
+		} break;
+	case ESAMAddRecipientWithAlias:
+		{
+		AddRecipientWithAliasL(aMessage);
+		} break;
+	case ESAMTransferAttachmentFile:
+		{
+		TransferAttachmentFileL(aMessage);
+		} break;
+	case ESAMAddAttachment:
+		{
+		AddAttachmentL(aMessage);
+		async = ETrue;
+		} break;
+	case ESAMAddAttachmentWithType:
+		{
+		AddAttachmentWithMimeTypeL(aMessage);
+		async = ETrue;
+		} break;
+	case ESAMAddLinkedAttachment:
+		{
+		AddLinkedAttachmentL(aMessage);
+		async = ETrue;
+		} break;
+	case ESAMAddLinkedAttachmentWithType:
+		{
+		AddLinkedAttachmentWithMimeTypeL(aMessage);
+		async = ETrue;
+		} break;
+	case ESAMCreateAttachment:
+		{
+		// Message will complete upon transfering ownership of file to client.
+		CreateAttachmentL(aMessage);
+		async = ETrue;
+		} break;
+	case ESAMCreateAttachmentWithType:
+		{
+		// Message will complete upon transfering ownership of file to client.
+		CreateAttachmentWithMimeTypeL(aMessage);
+		async = ETrue;
+		} break;
+	case ESAMCancel:
+		{
+		Cancel();
+		} break;
+	case ESAMLaunchEditor:
+		{
+		LaunchEditorL(aMessage);
+		} break;
+	case ESAMSendMessageConfirmed:
+		{
+		async = ETrue;
+		// drop through to next case...
+		}
+	case ESAMSendMessageConfirmedBackground:
+		{
+		SendMessageL(aMessage, ETrue, !async);
+		} break;
+	case ESAMSendMessage:
+		{
+		async = ETrue;
+		// drop through to next case...
+		}
+	case ESAMSendMessageBackground:
+		{
+		SendMessageL(aMessage, EFalse, !async);
+		} break;
+	case ESAMSaveMessage:
+		{
+		__ASSERT_ALWAYS( iState == EMessageCreated, PanicClientL(aMessage, ESendAsClientPanicNoCurrentMessage));
+		__ASSERT_DEBUG( iClientMtm != NULL, User::Invariant() );
+		
+		DoSaveMessageL();
+		} break;
+	case ESAMSetCharacterSet:
+		{
+		// For setting the charset encoding value for the message.
+		SetMessageCharacterSetL(aMessage);	
+		}break;
+	
+	case ESAMCharSetInfoForAttachment:
+		{
+		// For setting the charset encoding value for the message.
+		SetCharsetInfoForAttachment(aMessage);	
+		}break;
+	default:
+		PanicClientL(aMessage, ESendAsClientPanicBadRequest);
+		break;
+		}
+	return async;
+	}
+	
+/** Cancels any asynchronous activity being done by the message.
+*/
+void CSendAsMessage::CancelMessage()
+	{
+	// cancelling is a safe thing to do, like closing.
+	switch( iState )
+		{
+	case EAddingOrCreatingAttachment:
+		{
+		__ASSERT_DEBUG( iAttachment != NULL, User::Invariant() );
+		
+		// cancel and then delete the attachment object.
+		iAttachment->Cancel();
+		
+		delete iAttachment;
+		iAttachment = NULL;
+		} break;
+	case ESendingMessage:
+		{
+		__ASSERT_DEBUG( iSender != NULL, User::Invariant() );
+
+		// cancel and then delete the sender object.
+		iSender->Cancel();
+		
+		delete iSender;
+		iSender = NULL;
+		} break;
+	case EIdle:
+	case EMessageCreated:
+	case ESendingMessageComplete:
+	case EMessageDeleted:
+	case EPendingClose:
+	default:
+		// do nothing as cancel is a safe thing...
+		break;		
+		}
+	}
+
+/** Allocate a heap buffer to hold a descriptor parameter and copy it in.
+
+This method leaves if the desciptor is not valid. This method pushes the buffer
+onto the cleanup stack and leaves it there when it returns.
+
+@param	aMessage
+The IPC message.
+
+@param	aIndex
+The index of the parameter to read from the IPC message.
+
+@return
+A pointer to an array populated with the descriptor data. A copy of the pointer
+is left on the cleanup stack.
+*/
+HBufC* CSendAsMessage::GetDesParamLC(const RMessage2& aMessage, TInt aIndex)
+	{
+	__ASSERT_DEBUG((aIndex >=0 && aIndex <=KSendAsMaxMessageIndex), PanicClientL(aMessage, ESendAsClientPanicBadRequestArgument));
+	
+	TInt len = User::LeaveIfError(aMessage.GetDesLength(aIndex));
+	HBufC* buffer = HBufC::NewLC(len);
+	TPtr ptr(buffer->Des());
+	aMessage.Read(aIndex, ptr);
+	return buffer;
+	}
+
+/** Allocate a heap buffer to hold a descriptor parameter and copy it in.
+
+This method leaves if the desciptor is not valid. This method pushes the buffer
+onto the cleanup stack and leaves it there when it returns.
+
+@param	aMessage
+The IPC message.
+
+@param	aIndex
+The index of the parameter to read from the IPC message.
+
+@return
+A pointer to an array populated with the descriptor data. A copy of the pointer
+is left on the cleanup stack.
+*/
+HBufC8* CSendAsMessage::GetDesParam8LC(const RMessage2& aMessage, TInt aIndex)
+	{
+	__ASSERT_DEBUG((aIndex >=0 && aIndex <=KSendAsMaxMessageIndex), PanicClientL(aMessage, ESendAsClientPanicBadRequestArgument));
+	
+	TInt len = User::LeaveIfError(aMessage.GetDesLength(aIndex));
+	HBufC8* buffer = HBufC8::NewLC(len);
+	TPtr8 ptr(buffer->Des());
+	aMessage.Read(aIndex, ptr);
+	return buffer;
+	}
+
+/**
+Create a message in the drafts folder and set up this CSendAsMessage instance to
+operate on it.
+
+This method requires either an MTM UID or a valid account ID. 
+
+If the MTM UID is NULL, then the account ID must be valid otherwise the method will
+leave. If the account ID is valid, then the MTM of the account is used.
+
+@param	aMtm
+The UID of the MTM for the new message.
+
+@param	aAccount
+The account ID under which the message is created.
+
+@leave	KErrNotFound
+The MTM UID is NULL and the account ID is not valid.
+*/
+void CSendAsMessage::DoCreateMessageL(TUid aMtm, TSendAsAccount aAccount)
+	{
+	// new context 
+	CMsvEntry* msvEntry = CMsvEntry::NewL(iSession.GetMsvSessionL(), aAccount, TMsvSelectionOrdering());
+	CleanupStack::PushL(msvEntry);
+	if( aMtm == KNullUid )
+		{
+		if( aAccount == KMsvRootIndexEntryId || msvEntry->Entry().iType != KUidMsvServiceEntry )
+			{
+			// not a valid account
+			User::Leave(KErrNotFound);
+			}
+		// get associated mtm uid
+		aMtm = msvEntry->Entry().iMtm;
+		}
+
+	// create mtm by uid	
+	DeleteClientMtm();
+	iClientMtm = iSession.GetClientMtmL(aMtm);
+	
+	// if no account provided, get default for this MTM
+	if( aAccount == KMsvRootIndexEntryId )
+		{
+		aAccount = iClientMtm->DefaultServiceL();
+		}
+	
+	// create message in drafts folder
+	msvEntry->SetEntryL(KMsvDraftEntryId);
+	
+	// mtm takes ownership of entry context	
+	CleanupStack::Pop(msvEntry);
+	iClientMtm->SetCurrentEntryL(msvEntry);
+
+	// create message
+	iClientMtm->CreateMessageL(aAccount);
+	iMessageType = aMtm;
+
+	// Change the context of the client MTM to the newly created message entry
+	iClientMtm->SwitchCurrentEntryL(iClientMtm->Entry().EntryId());
+
+	// Load the message created so far into the client MTMs cache. This ensures
+	// that SendAs will not overwrite any body text added during the
+	// CreateMessageL routine (such as signature text).
+	// Some MTMs don't actually write anything to store during the
+	// CreateMessageL phase, so the LoadMessageL can leave with KErrNotFound.
+	// It is safe to trap and ignore this as it just means there is no message
+	// body text to be loaded.
+	TRAPD(err, iClientMtm->LoadMessageL());
+
+	if (err != KErrNone && err != KErrNotFound)
+		{
+		User::Leave(err);
+		}
+
+	iState = EMessageCreated;
+	}
+
+/** Create a new message in the drafts folder, using the specified account.
+
+The account to use is passed from the client in a package buffer, held in
+parameter 0 of the message.
+
+@param	aMessage
+The IPC message.
+*/
+void CSendAsMessage::CreateMessageForAccountL(const RMessage2& aMessage)
+	{
+	__ASSERT_ALWAYS( iState == EIdle, PanicClientL(aMessage, ESendAsClientPanicSubsessionInUse) );
+
+	TPckgBuf<TSendAsAccount> accountBuf;
+	aMessage.Read(0, accountBuf);
+
+	DoCreateMessageL(KNullUid, accountBuf()); 
+	}
+	
+/** Create a new message in the drafts folder, of the specified type.
+
+The message type (a TUid) to create is passed from the client in a package buffer,
+held in parameter 0 of the message.
+
+@param	aMessage
+The IPC message.
+*/
+void CSendAsMessage::CreateMessageByTypeL(const RMessage2& aMessage)
+	{
+	__ASSERT_ALWAYS( iState == EIdle, PanicClientL(aMessage, ESendAsClientPanicSubsessionInUse) );
+	
+	// extract mtm uid
+	TPckgBuf<TUid> uidBuf;
+	aMessage.Read(0, uidBuf);
+
+	// create message using default account for this mtm
+	DoCreateMessageL(uidBuf());
+	}
+	
+/** Delete the open message from the drafts folder.
+@param aMessage
+The IPC message.
+*/
+void CSendAsMessage::DeleteMessageL(const RMessage2& aMessage)
+	{
+	// Client code should cancel any outstanding requests prior to deleting
+	// the message. Failure to do so will result in the client being panicked.
+	switch (iState)
+		{
+	case EMessageCreated:
+		{
+		__ASSERT_DEBUG( iClientMtm != NULL, User::Invariant() );
+		
+		iClientMtm->Session().RemoveEntry(iClientMtm->Entry().EntryId());
+		iState = EMessageDeleted;
+		} break;
+	case EIdle:
+	case ESendingMessageComplete:
+	case EPendingClose:
+		break;
+	case ESendingMessage:
+		{
+		PanicClientL(aMessage, ESendAsClientPanicSendingMessage);
+		} break;
+	case EAddingOrCreatingAttachment:
+		{
+		PanicClientL(aMessage, ESendAsClientPanicAddingCreatingAttachment);
+		} break;
+	case EMessageDeleted:
+	default:
+		PanicClientL(aMessage, ESendAsClientPanicMessageAlreadyDeleted);
+		break;
+		}
+
+	DeleteClientMtm();
+	}
+	
+/** Set the body text of the open message.
+
+The body text is specified using a CRichText object. This object is streamed 
+into a descriptor which is passed over the IPC boundary in parameter 0 of the
+message. The CRichText object is then internalised by the server.
+
+@param	aMessage
+The IPC message.
+
+@param	aFirstChunk
+A flag that indicates whether this is the first chunk of rich text received 
+from the client.
+*/
+void CSendAsMessage::SetBodyTextL(const RMessage2& aMessage, TBool aFirstChunk)
+	{
+	__ASSERT_ALWAYS( iState == EMessageCreated, PanicClientL(aMessage, ESendAsClientPanicNoCurrentMessage) );
+	__ASSERT_DEBUG( iClientMtm != NULL, User::Invariant() );
+
+	TInt response = 0;
+	User::LeaveIfError(iClientMtm->QueryCapability(KUidMtmQuerySupportedBody, response));
+
+	// This location in the body text at which the text is to be inserted.
+	TInt insertLoc = 0;
+
+	if( aFirstChunk )
+		{
+		// Store the size of the signature text. This is added to the body
+		// text on creation of the message by the client MTM.
+		// All added body text is to be added before the signature text.
+		iSignatureSize = iClientMtm->Body().DocumentLength();
+		}
+	else
+		{
+		// insert added text before the signature text.
+		insertLoc = iClientMtm->Body().DocumentLength() - iSignatureSize;
+		}
+
+	TInt chunkLength = User::LeaveIfError(aMessage.GetDesLength(0));
+	HBufC* textBuffer = GetDesParamLC(aMessage, 0);
+	// Append the next chunk to the mtm's CRichText object.
+	TRAPD(insertError, iClientMtm->Body().InsertL(insertLoc, *textBuffer));
+	if( insertError != KErrNone )
+		{
+		iClientMtm->Body().Reset();
+		User::Leave(insertError);
+		}
+	CleanupStack::PopAndDestroy(textBuffer);
+	}
+
+/** Set the subject of the open message.
+
+The subject is plain text, held in a descriptor passed in parameter 0 of the
+message.
+
+@param	aMessage
+The IPC message.
+*/
+void CSendAsMessage::SetSubjectL(const RMessage2& aMessage)
+	{
+	__ASSERT_ALWAYS( iState == EMessageCreated, PanicClientL(aMessage, ESendAsClientPanicNoCurrentMessage) );
+	__ASSERT_DEBUG( iClientMtm != NULL, User::Invariant() );
+
+	HBufC* subject = GetDesParamLC(aMessage, 0);
+	iClientMtm->SetSubjectL(*subject);
+		
+	CleanupStack::PopAndDestroy(subject);
+	}
+	
+/** Set the BIO type of the message.
+
+The BIO type is passed from the client in a package buffer, pointed to by 
+parameter 0 of the message.
+
+@param	aMessage
+The IPC message.
+*/
+void CSendAsMessage::SetBioTypeL(const RMessage2& aMessage)
+	{
+	__ASSERT_ALWAYS( iState == EMessageCreated, PanicClientL(aMessage, ESendAsClientPanicNoCurrentMessage) );
+	__ASSERT_DEBUG( iClientMtm != NULL, User::Invariant() );
+
+	TPckgBuf<TUid> uidBuf;
+	aMessage.Read(0, uidBuf);
+	iClientMtm->BioTypeChangedL(uidBuf());
+	
+	TUid bioTypeUid = uidBuf();
+	iClientMtm->SaveMessageL();
+
+	TMsvEntry tempEntry = iClientMtm->Entry().Entry(); 
+	tempEntry.iBioType = bioTypeUid.iUid;
+	iClientMtm->Entry().ChangeL(tempEntry);	
+	}
+
+/** Add a recipient (plus alias) to the message.
+
+The recipient's address is passed in a descriptor, pointed to by parameter 0 of
+the message.  The alias is also passed in as a descriptor, this time pointed to
+by parameter 1.
+
+The recipient type (which indicates if a recipient is a To, Cc or Bcc type) is
+passed inside a package buffer pointed to by parameter 2.
+
+@param	aMessage
+The IPC message.
+*/
+void CSendAsMessage::AddRecipientWithAliasL(const RMessage2& aMessage)
+	{
+	__ASSERT_ALWAYS( iState == EMessageCreated, PanicClientL(aMessage, ESendAsClientPanicNoCurrentMessage) );
+	__ASSERT_DEBUG( iClientMtm != NULL, User::Invariant() );
+	
+	HBufC* address = GetDesParamLC(aMessage, 0);
+	HBufC* alias = GetDesParamLC(aMessage, 1);
+
+	TPckgBuf<RSendAsMessage::TSendAsRecipientType> recipientTypeBuf;
+	aMessage.Read(2, recipientTypeBuf);
+
+	// client MTM manages handling of Bcc recipients
+	iClientMtm->AddAddresseeL(recipientTypeBuf(), *address, *alias);
+	
+	CleanupStack::PopAndDestroy(2, address); // alias, address
+	}
+	
+/** Add a recipient to the message.
+
+The recipient's address is passed in a descriptor, pointed to by parameter 0 of
+the message.
+
+The recipient type (which indicates if a recipient is a To, Cc or Bcc type) is
+passed inside a package buffer pointed to by parameter 1.
+
+@param	aMessage
+The IPC message.
+*/
+void CSendAsMessage::AddRecipientL(const RMessage2& aMessage)
+	{
+	__ASSERT_ALWAYS( iState == EMessageCreated, PanicClientL(aMessage, ESendAsClientPanicNoCurrentMessage) );
+	__ASSERT_DEBUG( iClientMtm != NULL, User::Invariant() );
+
+	HBufC* address = GetDesParamLC(aMessage, 0);
+	
+	TPckgBuf<RSendAsMessage::TSendAsRecipientType> recipientTypeBuf;
+	aMessage.Read(1, recipientTypeBuf);
+
+	// call new implementation - let it manage handling of Bcc recipients
+	iClientMtm->AddAddresseeL(recipientTypeBuf(), *address);
+
+	CleanupStack::PopAndDestroy(address);
+	}
+	
+/** Prepare the message for subsequent add or create attachment operations.
+
+@param	aMessage
+The IPC message.
+*/
+void CSendAsMessage::PrepareAddCreateAttachmentL(const RMessage2& aMessage)
+	{
+	__ASSERT_DEBUG( iClientMtm != NULL, User::Invariant() );
+	
+	// delete any orphaned attachment object.
+	delete iAttachment;
+	iAttachment = NULL;
+
+	// queue the IPC message - used to notify the client when the attachment 
+	// operation is complete.
+	iQueuedMessage = aMessage;
+	iAttachment = CSendAsAttachment::NewL(*this, *iClientMtm);
+	}
+
+/** Take ownership of the RFile attachment
+
+@param	aMessage
+The IPC message.
+*/
+void CSendAsMessage::TransferAttachmentFileL(const RMessage2& aMessage)
+	{
+	// Close if left open previously.
+	iAttachmentFile.Close();
+
+	// need to adopt the file from the client.
+	User::LeaveIfError(iAttachmentFile.AdoptFromClient(aMessage, 0, 1));
+	}
+	
+/** Add an attachment to the message.
+
+The attachment added to the message is copied into a new attachment by the
+message server.  The new attachment lives in the message store which is private
+to the msg server.
+
+The client must pass a file handle over to the server.  The server assumes that
+this handle allows it to have read access to the open file once it has been adopted.
+
+The file handles are passed over in the usual manner.
+
+@param	aMessage
+The IPC message.
+*/
+void CSendAsMessage::AddAttachmentL(const RMessage2& aMessage)
+	{
+	__ASSERT_ALWAYS( iState == EMessageCreated, PanicClientL(aMessage, ESendAsClientPanicNoCurrentMessage) );
+
+	PrepareAddCreateAttachmentL(aMessage);
+	iAttachment->AddExistingFileAttachmentL(iAttachmentFile);
+	iState = EAddingOrCreatingAttachment;
+	}
+	
+/** Add an attachment to the message.
+
+The attachment added to the message is copied into a new attachment by the
+message server.  The new attachment lives in the message store which is private
+to the msg server.
+
+The client must pass a file handle over to the server.  The server assumes that
+this handle allows it to have read access to the open file once it has been adopted.
+
+The mime type of the attachment is specified in aMessage parameter 2.
+
+The file handles are passed over in the usual manner.
+
+@param	aMessage
+The IPC message.
+*/
+void CSendAsMessage::AddAttachmentWithMimeTypeL(const RMessage2& aMessage)
+	{
+	__ASSERT_ALWAYS( iState == EMessageCreated, PanicClientL(aMessage, ESendAsClientPanicNoCurrentMessage) );
+
+	HBufC8* mimeType = GetDesParam8LC(aMessage, 0);
+	TUint charset = aMessage.Int1();
+
+	PrepareAddCreateAttachmentL(aMessage);
+	iAttachment->AddExistingFileAttachmentWithMimeTypeL(iAttachmentFile, *mimeType, charset);
+	iState = EAddingOrCreatingAttachment;
+
+	CleanupStack::PopAndDestroy(mimeType);
+	}
+	
+/** Add an attachment to the message.
+
+The filename of the attachment is linked to the message.
+
+The file must be in a location which the message server is able to read and it
+must also remain until the message has been sent or deleted.
+
+@param	aMessage
+The IPC message.
+*/
+void CSendAsMessage::AddLinkedAttachmentL(const RMessage2& aMessage)
+	{
+	__ASSERT_ALWAYS( iState == EMessageCreated, PanicClientL(aMessage, ESendAsClientPanicNoCurrentMessage) );
+
+	HBufC* fileName = GetDesParamLC(aMessage, 0);
+	
+	PrepareAddCreateAttachmentL(aMessage);
+	iAttachment->AddFileLinkAttachmentL(*fileName);
+	iState = EAddingOrCreatingAttachment;
+	
+	CleanupStack::PopAndDestroy(fileName);
+	}
+
+/** Add an attachment to the message.
+
+The filename of the attachment is linked to the message.
+
+The file must be in a location which the message server is able to read and it
+must also remain until the message has been sent or deleted.
+
+The mime type of the linked file is supplied.
+
+@param	aMessage
+The IPC message.
+*/
+void CSendAsMessage::AddLinkedAttachmentWithMimeTypeL(const RMessage2& aMessage)
+	{
+	__ASSERT_ALWAYS( iState == EMessageCreated, PanicClientL(aMessage, ESendAsClientPanicNoCurrentMessage) );
+
+	HBufC* fileName = GetDesParamLC(aMessage, 0);
+	HBufC8* mimeType = GetDesParam8LC(aMessage, 1);
+	TUint charset = aMessage.Int2();
+	
+	PrepareAddCreateAttachmentL(aMessage);
+	iAttachment->AddFileLinkAttachmentWithMimeTypeL(*fileName, *mimeType, charset);
+	iState = EAddingOrCreatingAttachment;
+	
+	CleanupStack::PopAndDestroy(2, fileName); // mimeType, fileName
+	}
+	
+/** Create an empty attachment in the open message.
+
+The SendAs server makes the empty attachment and returns a file handle to the
+client ready for writing.
+
+@param	aMessage
+The IPC message.
+*/
+void CSendAsMessage::CreateAttachmentL(const RMessage2& aMessage)
+	{
+	__ASSERT_ALWAYS( iState == EMessageCreated, PanicClientL(aMessage, ESendAsClientPanicNoCurrentMessage) );
+
+	HBufC* fileName = GetDesParamLC(aMessage, 1);
+
+	PrepareAddCreateAttachmentL(aMessage);
+	iAttachment->CreateNewFileAttachmentL(iAttachmentFile, *fileName);
+	iState = EAddingOrCreatingAttachment;
+
+	CleanupStack::PopAndDestroy(fileName);
+	}
+
+/** Create an empty attachment in the open message.
+
+The mime type of the attachment is specified.
+
+The SendAs server makes the empty attachment and returns a file handle to the
+client ready for writing.
+
+@param	aMessage
+The IPC message.
+*/
+void CSendAsMessage::CreateAttachmentWithMimeTypeL(const RMessage2& aMessage)
+	{
+	__ASSERT_ALWAYS( iState == EMessageCreated, PanicClientL(aMessage, ESendAsClientPanicNoCurrentMessage) );
+
+	HBufC* fileName = GetDesParamLC(aMessage, 1);
+		
+	HBufC8* mimeType = GetDesParam8LC(aMessage, 2);
+		
+	PrepareAddCreateAttachmentL(aMessage);
+	iAttachment->CreateNewFileAttachmentWithMimeTypeL(iAttachmentFile, *fileName, *mimeType, iCharSet);
+	iState = EAddingOrCreatingAttachment;
+		
+	CleanupStack::PopAndDestroy(2, fileName); // mimeType, fileName
+	}	
+
+void CSendAsMessage::SetCharsetInfoForAttachment(const RMessage2& aMessage)
+	{
+	iCharSet = aMessage.Int0();
+	}	
+
+
+/** Cancel any asynchronous activity being done by the message.
+
+@param	aMessage
+The IPC message.
+*/
+void CSendAsMessage::Cancel()
+	{
+	CancelMessage();
+	}
+	
+/** Launch the message editor for the open message.
+
+@param	aMessage
+The IPC message.
+*/
+void CSendAsMessage::LaunchEditorL(const RMessage2& aMessage)
+	{
+	__ASSERT_ALWAYS( iState == EMessageCreated, PanicClientL(aMessage, ESendAsClientPanicNoCurrentMessage) );
+	__ASSERT_DEBUG( iClientMtm != NULL, User::Invariant() );
+
+	iClientMtm->SaveMessageL();
+		
+	// the observer and owner is the SendAs Server, via active container.
+	CSendAsEditWatcher* editWatcher = CSendAsEditWatcher::NewL(iSession.ActiveContainer(), iSession.EditUtilsPluginUid());
+	iSession.ActiveContainer().AddEditWatcherL(*editWatcher);
+
+	TMsvId entryId = iClientMtm->Entry().EntryId();	
+	DeleteClientMtm();
+	editWatcher->LaunchEditorL(entryId);
+
+	iState = EPendingClose;
+	}
+		
+/** Send the message.
+
+This method handles both confirmed and unconfirmed sends. If an unconfirmed send
+is attempted but the client does not have the MTM-required capabilities then the
+send will be downgraded to a confirmed send.
+
+@param	aMessage
+The IPC message.
+
+@param	aConfirmed
+A value of true indicates that the send should be confirmed.
+
+@param	aBackground
+A value of true indicates that the send should be done in the background. This
+implies that the client does not wish to be notified of the progress of the send.
+
+@leave KErrNotSupported
+The client MTM does not support SendAs message sending.
+*/
+void CSendAsMessage::SendMessageL(const RMessage2& aMessage, TBool aConfirmed, TBool aBackground)
+	{
+	__ASSERT_ALWAYS( iState == EMessageCreated, PanicClientL(aMessage, ESendAsClientPanicNoCurrentMessage) );
+	__ASSERT_DEBUG( iClientMtm != NULL, User::Invariant() );
+
+#if (defined SYMBIAN_USER_PROMPT_SERVICE)		
+	TBool hasCapability = EFalse;	
+#endif
+	// for unconfirmed send, check capabilities of client
+	if( !aConfirmed )
+		{
+		VerifyCallerCapabilitiesL(aMessage, aConfirmed);
+#if (defined SYMBIAN_USER_PROMPT_SERVICE)		
+		if(!aConfirmed)
+			{
+			hasCapability = ETrue;
+			}
+#endif			
+		}
+		
+
+	TBool result = KErrNone;
+	if( iClientMtm->QueryCapability(KUidMtmQuerySendAsMessageSendSupport, result) == KErrNotSupported )
+		{
+		User::Leave(KErrNotSupported);
+		}
+	// save message	
+	DoSaveMessageL();
+
+	// create the sender obejct
+	CSendAsSender* sender = NULL;
+	if( aBackground )
+		{
+		// this a background send - the observer and owner is the active container.
+		sender = CSendAsSender::NewL(iSession.ActiveContainer());
+		iSession.ActiveContainer().AddSenderL(*sender);
+		
+		iState = ESendingMessageComplete;
+		}
+	else
+		{
+		// this is a non-background send - the observer and owner is the send-as
+		// message.
+		delete iSender;
+		iSender = NULL;
+		
+		sender	= CSendAsSender::NewL(*this);
+		iSender = sender;
+		
+		// queue the IPC message - used to notify the client when the send is complete
+		iQueuedMessage = aMessage;
+		
+		iState = ESendingMessage;
+		}
+	// new sender takes ownership of the client MTM
+	sender->SetClientMtm(*iClientMtm);
+		
+#if (defined SYMBIAN_USER_PROMPT_SERVICE)	
+	TRAPD(err, sender->SendMessageL(aMessage, hasCapability));
+	if(err!=KErrNone)
+		{
+		// There was a error while sending the message... so delete the entry
+		iClientMtm->Session().RemoveEntry(iClientMtm->Entry().EntryId());
+		iClientMtm = NULL;
+		iState = ESendingMessageComplete;
+		User::Leave(err);
+		}
+	iClientMtm = NULL;	
+#else
+	iClientMtm = NULL;
+	if( aConfirmed )
+		{
+		TSecurityInfo securityInfo(aMessage);
+		sender->SendMessage(securityInfo, iSession.NotifierUid());
+		}
+	else
+		{
+		sender->SendMessage();
+		}
+#endif	
+	}
+	
+void CSendAsMessage::DeleteClientMtm()
+	{
+	delete iClientMtm;
+	iClientMtm = NULL;
+	}
+
+/** Get progress information 
+
+Used to provide progress information to the client. 
+
+1. Before sending, the progress is set to ESendStateInPreparation.
+ 
+2. Whilst sending, the progress is obtained from the send operation.
+
+3. After sending, the final progress is returned to the client (always a TMsvSendOperationProgress).
+
+@param	aMessage
+The IPC message.
+*/
+void CSendAsMessage::ProgressL(const RMessage2& aMessage)
+	{
+	switch( iState )
+		{
+	case EIdle:
+	case EMessageCreated:
+	case EAddingOrCreatingAttachment:
+	case EMessageDeleted:
+	case EPendingClose:
+		{
+		iProgress().iState = CMsvSendOperation::ESendStateInPreparation;
+		iProgress().iError = KErrNone;
+		iProgress().iProgressMax = 0;
+		iProgress().iProgress = 0;
+		} break;
+	case ESendingMessage:
+		{
+		__ASSERT_DEBUG( iSender != NULL, User::Invariant() );
+
+		iSender->ProgressL(iProgress);
+		} break;
+	case ESendingMessageComplete:
+		{
+		// return the final progress 
+		if( iProgress().iError == KErrNone )
+			{
+			iProgress().iState = CMsvSendOperation::ESendStateDone;
+			}
+		else
+			{
+			iProgress().iState = CMsvSendOperation::ESendStateFailed;
+			}
+		} break;
+	default:
+		User::Invariant();
+		break;
+		}
+
+	aMessage.WriteL(0, iProgress);
+	}
+
+/** Verify that the client has the required capabilities to use the server MTM
+to send this message unconfirmed. Otherwise changes request to confirmed send.
+
+@param	aMessage
+The IPC message.
+*/
+void CSendAsMessage::VerifyCallerCapabilitiesL(const RMessage2& aMessage, TBool& aConfirmed)
+	{
+	// get required capabilities
+	TCapabilitySet caps;
+	iClientMtm->Session().GetMtmRequiredCapabilitiesL(iMessageType, caps);
+
+	// get client thread capabilities
+	TSecurityInfo securityInfo(aMessage);
+	
+	// check client capabilities with required capabilities
+	if( !securityInfo.iCaps.HasCapabilities(caps) )
+		{
+		// fail capability check...
+		caps.Remove(securityInfo.iCaps);
+		PlatSec::CapabilityCheckFail(aMessage, caps, __PLATSEC_DIAGNOSTIC_STRING("Unconfirmed send downgraded to confirmed by CSendAsMessage::VerifyCallerCapabilitiesL"));
+		aConfirmed = ETrue;
+		}
+	}
+
+/** Panic the client
+
+@param	aMessage
+The IPC message.
+
+@param aPanic
+The panic code.
+*/
+void CSendAsMessage::PanicClientL(const RMessage2& aMessage, TSendAsClientPanic aPanic) const
+	{
+	iSession.PanicClient(aMessage, aPanic);
+	}
+
+/*
+ *	Methods from MSendAsSenderObserver
+ */
+ 
+/** Notify the client that the send has completed
+
+@param	aError
+The error code.
+*/
+void CSendAsMessage::SenderComplete(TInt aError)
+	{
+	__ASSERT_ALWAYS( iState == ESendingMessage, User::Invariant() );
+	__ASSERT_DEBUG( iSender != NULL, User::Invariant() );
+
+	// get final progress from the sender.
+	iSender->FinalProgress(iProgress);
+	
+	// capture error
+	if( iProgress().iError == KErrNone )
+		{
+		iProgress().iError = aError;
+		}
+	// notify the client that the send has completed - always complete with 
+	// KErrNone as actual error is in the progress.
+	iQueuedMessage.Complete(KErrNone);
+	
+	// Set the state to complete so we can call FinalProgress
+	iState = ESendingMessageComplete;
+	}
+
+/*
+ *	Methods from MSendAsAttachmentObserver
+ */
+
+/** Notify the client that the attachment operation has completed
+
+If the message is complete, the client is notified, otherwise the created
+attachment is transferred to the client.
+
+@param	aError
+The error code.
+
+@param	aCompleteMessage
+Indicates if the message is complete.
+*/
+void CSendAsMessage::AttachmentCompleteL(TInt aError, TBool aCompleteMessage)
+	{
+	__ASSERT_ALWAYS( iState == EAddingOrCreatingAttachment, User::Invariant() );
+	
+	// notify the client that the attachment operation has completed - if an
+	// error has occurred the error code is returned in the complete status.
+	if (aCompleteMessage)
+		{
+		iQueuedMessage.Complete(aError);
+		}
+	else
+		{
+		// transfer the created file to the client. Argument 0 of iQueuedMessage
+		// contains the address to which the client should receive the file handle.
+		User::LeaveIfError(iAttachmentFile.TransferToClient(iQueuedMessage, 0));
+		iAttachmentFile.Close();
+		}
+	// the attachment file is now closed - set it to a blank RFile so that any 
+	// later closes don't panic.
+	iAttachmentFile = RFile();
+	
+	// The client can continue editing the message - move to appropriate state
+	// and delete attachment object
+
+	// Delete the attachment object after use. If this is a notification of a 
+	// cancel then the delete should happen after the cancel operation to avoid
+	// a second cancel in the attachment object's destructor.
+	if( aError != KErrCancel )
+		{
+		delete iAttachment;
+		iAttachment = NULL;
+		}
+
+	iState = EMessageCreated;
+	}
+
+/** Sets the message entry's Visible flag to ETrue and inPreparation flag to EFalse 
+saves the message, commits the changes  
+*/
+
+void CSendAsMessage::DoSaveMessageL() 
+    {     
+    iClientMtm->SaveMessageL();
+  
+    // set the InPreparation to false and visible to true
+    TMsvEntry tempEntry= iClientMtm->Entry().Entry();
+    tempEntry.iDate.UniversalTime();
+    tempEntry.SetVisible(ETrue);
+    tempEntry.SetInPreparation(EFalse);
+     
+    iClientMtm->Entry().ChangeL(tempEntry);
+    }
+
+/** 
+Sets the character encoding value. The character encoding value options are 7-bit,
+8-bit and 16-Bit Unicode. By default the character set encoding is 7 bit encoding.
+It call the MTM functionality for setting the charset value.
+@param	aMessage	The IPC message.
+@return void
+*/
+   
+void CSendAsMessage::SetMessageCharacterSetL(const RMessage2& aMessage)
+	{
+	TInt err =	iClientMtm->SetMessageCharacterSet(aMessage.Int0());
+	TPckgBuf<TInt> pckg = err;
+	aMessage.WriteL(1,pckg);
+	}