email/mail/UtilsSrc/MsgMailAppUi.cpp
branchRCL_3
changeset 27 7fdbb852d323
parent 0 72b543305e3a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/email/mail/UtilsSrc/MsgMailAppUi.cpp	Wed Sep 01 12:31:54 2010 +0100
@@ -0,0 +1,1424 @@
+/*
+* Copyright (c) 2002 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:  A common base class for Mail application ui classes.
+*
+*/
+
+
+// INCLUDE FILES
+#include <akntitle.h>
+#include <AknsUtils.h>
+#include <aknlayoutscalable_apps.cdl.h>
+#include <aknlayoutscalable_avkon.cdl.h>
+#include <gulicon.h>
+
+#include <msgmailutils.mbg>
+#include <miuthdr.h>                    // CImHeader
+#include <msvapi.h>                     // CMsvEntry
+#include <miutmsg.h>                    // CImEmailMessage
+#include <mmsvattachmentmanager.h>
+#include <cmsvattachment.h>
+#include <ConeResLoader.h>              // RConeResourceLoader
+#include <CommonContentPolicy.h>        // ContentPolicy
+#include <muiumsvuiserviceutilitiesinternal.h>  // MUIU MTM utils 
+
+
+
+
+#include <AknWaitNoteWrapper.h>
+#include <AknWaitDialog.h>
+#include <featmgr.h>                    // FeatureManager
+#include <bldvariant.hrh>
+#include <coeutils.h>
+#include <data_caging_path_literals.hrh> 
+#include <messaginginternalcrkeys.h>
+#include <messagingvariant.hrh>
+
+// Editor base classes:
+#include <MsgAttachmentInfo.h>
+#include <MsgAttachmentModel.h>
+#include <MsgEditorView.h>
+#include <MsgBodyControl.h>
+#include <MsgAddressControl.h>
+#include <MsgRecipientItem.h>
+
+#include <MuiuOperationWait.h>              // CMuiuOperationWait
+#include <StringLoader.h>
+
+#include <MsgMailUtils.rsg>
+#include "MsgMailAppUi.h"
+#include "MsgMailDocument.h"
+#include "MsgMailPreferences.h"
+#include "MailUtils.h"
+
+// Mail Central Repository handler
+#include "CMailCRHandler.h"
+
+// LOCAL CONSTANTS AND MACROS
+
+_LIT(KResourcesWithDir,"z:MsgMailUtils.rSC");
+_LIT( KMsgMailMBMFileName, "z:msgmailutils.mbm" );
+/// Message details item separator.
+_LIT( KMsgDetailsSeparator, "; " );
+/// Max length used for message details.
+const TInt KMsgMaxDetailsLength    = 128;
+
+// LOCAL FUNCTION PROTOTYPES
+typedef TBool (*TParseFunc)( TLex& aLex );
+LOCAL_C TBool DoOrReverse( TParseFunc aFunc, TLex& aLex );
+LOCAL_C TBool Star( TParseFunc aFunc, TLex& aLex );
+LOCAL_C TBool Plus( TParseFunc aFunc, TLex& aLex );
+LOCAL_C TBool NoWSCtl( TLex& aLex );
+LOCAL_C TBool WSP( TLex& aLex );
+LOCAL_C TBool FWS( TLex& aLex );
+LOCAL_C TBool CText( TLex& aLex );
+LOCAL_C TBool QuotedPair( TLex& aLex );
+LOCAL_C TBool FWSCContent( TLex& aLex );
+LOCAL_C TBool CContent( TLex& aLex );
+LOCAL_C TBool Comment( TLex& aLex );
+LOCAL_C TBool CFWS( TLex& aLex );
+LOCAL_C TBool AText( TLex& aLex );
+LOCAL_C TBool Atom( TLex& aLex );
+LOCAL_C TBool DotAtomText( TLex& aLex );
+LOCAL_C TBool DotAtom( TLex& aLex );
+LOCAL_C TBool DotPlusAText( TLex& aLex );
+LOCAL_C TBool QText( TLex& aLex );
+LOCAL_C TBool QContent( TLex& aLex );
+LOCAL_C TBool FWSQContent( TLex& aLex );
+LOCAL_C TBool QuotedString( TLex& aLex );
+LOCAL_C TBool LocalPart( TLex& aLex );
+LOCAL_C TBool DText( TLex& aLex );
+LOCAL_C TBool DContent( TLex& aLex );
+LOCAL_C TBool DomainLiteral( TLex& aLex );
+LOCAL_C TBool Domain( TLex& aLex );
+LOCAL_C TBool FWSDContent( TLex& aLex );
+LOCAL_C TBool AddrSpec( TLex& aLex );
+LOCAL_C TBool Word( TLex& aLex );
+LOCAL_C TBool DisplayName( TLex& aLex );
+LOCAL_C TBool CommaMailbox( TLex& aLex );
+LOCAL_C TBool AngleAddr( TLex& aLex );
+LOCAL_C TBool NameAddr( TLex& aLex );
+LOCAL_C TBool Mailbox( TLex& aLex );
+LOCAL_C TBool MailboxList( TLex& aLex );
+LOCAL_C TBool Group( TLex& aLex );
+LOCAL_C TBool Address( TLex& aLex );
+
+// ==================== LOCAL FUNCTIONS ====================
+
+// ----------------------------------------------------
+// DoOrReverse()
+// Calls aFunc. If it fails, the lexer is returned to 
+// the state before calling DoOrReverse().
+// ----------------------------------------------------
+//
+LOCAL_C TBool DoOrReverse( TParseFunc aFunc, TLex& aLex )
+	{
+	TLexMark mark;
+	aLex.Mark( mark );
+	if( (*aFunc)(aLex) )
+		{
+		return ETrue;
+		}
+	else
+		{
+		aLex.UnGetToMark( mark );
+		return EFalse;
+		}
+	}
+
+// ----------------------------------------------------
+// Star()
+// Calls aFunc repeatedly until aFunc returns EFalse.
+// The lexer is left to the state where it was after
+// the last succesful aFunc call. Returns ETrue if
+// at least one call to aFunc succeeded.
+// ----------------------------------------------------
+//
+LOCAL_C TBool Star( TParseFunc aFunc, TLex& aLex )
+	{
+	TBool hasMore( ETrue );
+	TBool hasOne( EFalse );
+	while( hasMore )
+		{
+		if( DoOrReverse( aFunc, aLex ) )
+			{
+			hasOne = ETrue;	
+			}
+		else
+			{
+			hasMore = EFalse;
+			}
+		}
+
+	return hasOne;
+	}
+
+// ----------------------------------------------------
+// Like Star() except enforces one succesful call
+// to aFunc.
+// ----------------------------------------------------
+//
+LOCAL_C TBool Plus( TParseFunc aFunc, TLex& aLex )
+	{
+	if( !DoOrReverse( aFunc, aLex ) )
+		{
+		return EFalse;
+		}
+
+	Star( aFunc, aLex );
+	return ETrue;
+	}
+
+// ----------------------------------------------------
+// NO-WS-CTL := %d1-8 / %d11 / %d12 / %d14-31 / %d127 ; US-ASCII 
+// control characters that do not include the carriage return, 
+// line feed, and white space characters
+// ----------------------------------------------------
+//
+LOCAL_C TBool NoWSCtl( TLex& aLex )
+	{
+	TChar ch( aLex.Get() );
+	return ( (ch >= 1 && ch <= 8)			// CSI: 47 # See a comment above.
+		|| ch == 11							// CSI: 47 # See a comment above.
+		|| ch == 12							// CSI: 47 # See a comment above.
+		|| (ch >= 14 && ch <= 31)			// CSI: 47 # See a comment above.
+		|| ch == 127 );						// CSI: 47 # See a comment above.
+	}
+
+
+// ----------------------------------------------------
+// text := %d1-9 / %d11 / %d12 / %d14-127 / obs-text ; Characters excluding CR and LF
+// ----------------------------------------------------
+//
+LOCAL_C TBool Text( TLex& aLex )
+	{
+	TChar ch( aLex.Get() );
+	return ( (ch >= 1 && ch <= 9)			// CSI: 47 # See a comment above.
+		|| ch == 11							// CSI: 47 # See a comment above.
+		|| ch == 12							// CSI: 47 # See a comment above.
+		|| (ch >= 14 && ch <= 127) );		// CSI: 47 # See a comment above.
+	}
+
+// ----------------------------------------------------
+// quoted-pair := ("\" text) / obs-qp
+// ----------------------------------------------------
+//
+LOCAL_C TBool QuotedPair( TLex& aLex )
+	{
+	if( aLex.Get() != '\\' )
+		{
+		return EFalse;
+		}
+
+	return Text( aLex );
+	}
+
+// ----------------------------------------------------
+// WSP = SPACE / HTAB
+// ----------------------------------------------------
+//
+LOCAL_C TBool WSP( TLex& aLex )
+	{
+	TChar ch( aLex.Get() );
+	return ch == EKeySpace || ch == EKeyTab;
+	}
+
+// ----------------------------------------------------
+// FWS := ([*WSP CRLF] 1*WSP) / obs-FWS ; Folding white space
+// ----------------------------------------------------
+//
+LOCAL_C TBool FWS( TLex& aLex )
+	{
+	return Plus( WSP, aLex );
+	}
+
+// ----------------------------------------------------
+// ctext := NO-WS-CTL / %d33-39 / %d42-91 / %d93-126 ; Non white space 
+// controls and The rest of the US-ASCII characters not including "(", ")", or "\"
+// ----------------------------------------------------
+//
+LOCAL_C TBool CText( TLex& aLex )
+	{
+	if( !DoOrReverse( NoWSCtl, aLex ) )
+		{
+		TChar ch( aLex.Get() );
+		return( (ch >= 33 && ch <= 39)				// CSI: 47 # See a comment above.
+			|| (ch >= 42 && ch <= 91)				// CSI: 47 # See a comment above.
+			|| (ch >= 93 && ch <= 126) );			// CSI: 47 # See a comment above.
+		}
+	else
+		{
+		return ETrue;
+		}
+	}
+
+// ----------------------------------------------------
+// ccontent := ctext / quoted-pair / comment
+// ----------------------------------------------------
+//
+LOCAL_C TBool CContent( TLex& aLex )
+	{
+	return DoOrReverse( CText, aLex ) || DoOrReverse( QuotedPair, aLex ) || Comment( aLex );
+	}
+
+// ----------------------------------------------------
+// [FWS] ccontent
+// ----------------------------------------------------
+//
+LOCAL_C TBool FWSCContent( TLex& aLex )
+	{
+	FWS( aLex );
+	return CContent( aLex );
+	}
+
+// ----------------------------------------------------
+// comment := "(" *([FWS] ccontent) [FWS] ")"
+// ----------------------------------------------------
+//
+LOCAL_C TBool Comment( TLex& aLex )
+	{
+	if( aLex.Get() != '(' )
+		{
+		return EFalse;
+		}
+
+	Star( FWSCContent, aLex );
+	FWS( aLex );
+	return aLex.Get() == ')';
+	}
+
+// ----------------------------------------------------
+// [FWS] comment
+// ----------------------------------------------------
+//
+LOCAL_C TBool FWSComment( TLex& aLex )
+	{
+	FWS( aLex );
+	return Comment( aLex );
+	}
+
+// ----------------------------------------------------
+// CFWS := *([FWS] comment) (([FWS] comment) / FWS)
+// ----------------------------------------------------
+//
+LOCAL_C TBool CFWS( TLex& aLex )
+	{
+	TBool hasOne( Star( FWSComment, aLex ) );
+
+	return hasOne || FWS( aLex );
+	}
+
+// ----------------------------------------------------
+// atext := ALPHA / DIGIT / "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / 
+// "-" / "/" / "=" / "?" "^" / "_" / "`" / "{" / "|" / "}" / "~"; Any 
+// character except controls, SP, and specials. Used for atoms
+// ----------------------------------------------------
+//
+LOCAL_C TBool AText( TLex& aLex )
+	{
+	//ALPHA / DIGIT / "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "/" / "=" / "?" "^" / "_" / 
+	//	"`" / "{" / "|" / "}" / "~"
+	TChar ch( aLex.Get() );
+	return( (ch >= 'a' && ch <= 'z' )
+		|| (ch >= 'A' && ch <= 'Z' )
+		|| (ch >= '0' && ch <= '9' )
+		|| ch == '!'
+		|| ch == '#'
+		|| ch == '$'
+		|| ch == '%'
+		|| ch == '&'
+		|| ch == '\''
+		|| ch == '*'
+		|| ch == '+'
+		|| ch == '-'
+		|| ch == '/'
+		|| ch == '='
+		|| ch == '?'
+		|| ch == '^'
+		|| ch == '_'
+		|| ch == '`'
+		|| ch == '{'
+		|| ch == '|'
+		|| ch == '}'
+		|| ch == '~' );
+	}
+
+// ----------------------------------------------------
+// atom := [CFWS] 1*atext [CFWS]
+// ----------------------------------------------------
+//
+LOCAL_C TBool Atom( TLex& aLex )
+	{
+	DoOrReverse( CFWS, aLex );
+
+	if( !Plus( AText, aLex ) )
+		{
+		return EFalse;
+		}
+
+	DoOrReverse( CFWS, aLex );
+	return ETrue;
+	}
+
+// ----------------------------------------------------
+// dot-atom := [CFWS] dot-atom-text [CFWS]
+// ----------------------------------------------------
+//
+LOCAL_C TBool DotAtom( TLex& aLex )
+	{
+	DoOrReverse( CFWS, aLex );
+	if( !DoOrReverse( DotAtomText, aLex ) )
+		{
+		return EFalse;
+		}
+	DoOrReverse( CFWS, aLex );
+
+	return ETrue;
+	}
+
+// ----------------------------------------------------
+// "." 1*atext
+// ----------------------------------------------------
+//
+LOCAL_C TBool DotPlusAText( TLex& aLex )
+	{
+	return aLex.Get() == '.' && Plus( AText, aLex );
+	}
+
+// ----------------------------------------------------
+// dot-atom-text := 1*atext *("." 1*atext)
+// ----------------------------------------------------
+//
+LOCAL_C TBool DotAtomText( TLex& aLex )
+	{
+	if( !Plus( AText, aLex ) )
+		{
+		return EFalse;
+		}
+
+	Star( DotPlusAText, aLex );
+	return ETrue;
+	}
+
+// ----------------------------------------------------
+// qtext := NO-WS-CTL / %d33 / %d35-91 / %d93-126 ; Non white space 
+// controls and The rest of the US-ASCII characters not including "\" 
+// or the quote character
+// ----------------------------------------------------
+//
+LOCAL_C TBool QText( TLex& aLex )
+	{
+	if( DoOrReverse( NoWSCtl, aLex ) )
+		{
+		return ETrue;
+		}
+
+	TChar ch( aLex.Get() );
+	return ch == 33						// CSI: 47 # See a comment above.
+		|| (ch >= 35 && ch <= 91)		// CSI: 47 # See a comment above.
+		|| (ch >= 93 && ch <= 126);		// CSI: 47 # See a comment above.
+	}
+
+// ----------------------------------------------------
+// qcontent := qtext / quoted-pair
+// ----------------------------------------------------
+//
+LOCAL_C TBool QContent( TLex& aLex )
+	{
+	return DoOrReverse( QText, aLex ) || QuotedPair( aLex );
+	}
+
+// ----------------------------------------------------
+// [FWS] qcontent
+// ----------------------------------------------------
+//
+LOCAL_C TBool FWSQContent( TLex& aLex )
+	{
+	FWS( aLex );
+	return QContent( aLex );
+	}
+
+// ----------------------------------------------------
+// quoted-string := [CFWS] DQUOTE *([FWS] qcontent) [FWS] DQUOTE [CFWS]
+// ----------------------------------------------------
+//
+LOCAL_C TBool QuotedString( TLex& aLex )
+	{
+	DoOrReverse( CFWS, aLex );
+
+	if( aLex.Get() != '"' )
+		{
+		return EFalse;
+		}
+
+	Star( FWSQContent, aLex );
+
+	DoOrReverse( FWS, aLex );
+
+	if( aLex.Get() != '"' )
+		{
+		return EFalse;
+		}
+
+	DoOrReverse( CFWS, aLex );
+	return ETrue;
+	}
+
+// ----------------------------------------------------
+// word := atom / quoted-string
+// ----------------------------------------------------
+//
+LOCAL_C TBool Word( TLex& aLex )
+	{
+	return DoOrReverse( Atom, aLex ) || QuotedString( aLex );
+	}
+
+// ----------------------------------------------------
+// address := mailbox / group
+// ----------------------------------------------------
+//
+LOCAL_C TBool Address( TLex& aLex )
+	{
+	return DoOrReverse( Mailbox, aLex ) || Group( aLex );
+	}
+
+// ----------------------------------------------------
+// mailbox := name-addr / addr-spec
+// ----------------------------------------------------
+//
+LOCAL_C TBool Mailbox( TLex& aLex )
+	{
+	return DoOrReverse( NameAddr, aLex ) || AddrSpec( aLex );
+	}
+
+// ----------------------------------------------------
+// name-addr := [display-name] angle-addr
+// ----------------------------------------------------
+//
+LOCAL_C TBool NameAddr( TLex& aLex )
+	{
+	DoOrReverse( DisplayName, aLex );
+	return AngleAddr( aLex );
+	}
+
+// ----------------------------------------------------
+// angle-addr := [CFWS] "<" addr-spec ">" [CFWS] / obs-angle-addr
+// ----------------------------------------------------
+//
+LOCAL_C TBool AngleAddr( TLex& aLex )
+	{
+	DoOrReverse( CFWS, aLex );
+	if( aLex.Get() != '<' )
+		{
+		return EFalse;
+		}
+
+	if( !DoOrReverse( AddrSpec, aLex ) )
+		{
+		return EFalse;
+		}
+
+	if( aLex.Get() != '>' )
+		{
+		return EFalse;
+		}
+
+	DoOrReverse( CFWS, aLex );
+	return ETrue;
+	}
+
+// ----------------------------------------------------
+// group := display-name ":" [mailbox-list / CFWS] ";" [CFWS]
+// ----------------------------------------------------
+//
+LOCAL_C TBool Group( TLex& aLex )
+	{
+	if( !DisplayName( aLex ) )
+		{
+		return EFalse;
+		}
+
+	if( aLex.Get() != ':' )
+		{
+		return EFalse;
+		}
+
+	if( !DoOrReverse( MailboxList, aLex ) )
+		{
+		DoOrReverse( CFWS, aLex );
+		}
+
+	if( aLex.Get() != ';' )
+		{
+		return EFalse;
+		}
+
+	DoOrReverse( CFWS, aLex );
+	return ETrue;
+	}
+
+// ----------------------------------------------------
+// display-name := phrase
+// phrase := 1*word / obs-phrase
+// ----------------------------------------------------
+//
+LOCAL_C TBool DisplayName( TLex& aLex )
+	{
+	return Plus( Word, aLex );
+	}
+
+// ----------------------------------------------------
+// "," mailbox
+// ----------------------------------------------------
+//
+LOCAL_C TBool CommaMailbox( TLex& aLex )
+	{
+	return aLex.Get() == ',' && Mailbox( aLex );
+	}
+
+// ----------------------------------------------------
+// mailbox-list := (mailbox *("," mailbox)) / obs-mbox-list
+// ----------------------------------------------------
+//
+LOCAL_C TBool MailboxList( TLex& aLex )
+	{
+	if( !DoOrReverse( Mailbox, aLex ) )
+		{
+		return EFalse;
+		}
+
+	Star( CommaMailbox, aLex );
+
+	return ETrue;
+	}
+
+// ----------------------------------------------------
+// addr-spec := local-part "@" domain
+// ----------------------------------------------------
+//
+LOCAL_C TBool AddrSpec( TLex& aLex )
+	{
+	if( !LocalPart( aLex ) )
+		{
+		return EFalse;
+		}
+
+	if( aLex.Get() != '@' )
+		{
+		return EFalse;
+		}
+
+	return Domain( aLex );
+	}
+
+// ----------------------------------------------------
+// local-part := dot-atom / quoted-string / obs-local-part
+// ----------------------------------------------------
+//
+LOCAL_C TBool LocalPart( TLex& aLex )
+	{
+	return DoOrReverse( DotAtom, aLex ) || QuotedString( aLex );
+	}
+
+// ----------------------------------------------------
+// domain := dot-atom / domain-literal / obs-domain
+// ----------------------------------------------------
+//
+LOCAL_C TBool Domain( TLex& aLex )
+	{
+	return DoOrReverse( DotAtom, aLex ) || DomainLiteral( aLex );
+	}
+
+// ----------------------------------------------------
+// [FWS] dcontent
+// ----------------------------------------------------
+//
+LOCAL_C TBool FWSDContent( TLex& aLex )
+	{
+	FWS( aLex );
+	return DContent( aLex );
+	}
+
+// ----------------------------------------------------
+// domain-literal := [CFWS] "[" *([FWS] dcontent) [FWS] "]" [CFWS]
+// ----------------------------------------------------
+//
+LOCAL_C TBool DomainLiteral( TLex& aLex )
+	{
+	DoOrReverse( CFWS, aLex );
+	if( aLex.Get() != '[' )
+		{
+		return EFalse;
+		}
+
+	Star( FWSDContent, aLex );
+
+	DoOrReverse( FWS, aLex );
+	if( aLex.Get() != ']' )
+		{
+		return EFalse;
+		}
+
+	DoOrReverse( CFWS, aLex );
+	return ETrue;
+	}
+
+// ----------------------------------------------------
+// dcontent := dtext / quoted-pair
+// ----------------------------------------------------
+//
+LOCAL_C TBool DContent( TLex& aLex )
+	{
+	return DoOrReverse( DText, aLex ) || QuotedPair( aLex );
+	}
+
+// ----------------------------------------------------
+// dtext := NO-WS-CTL / %d33-90 / %d94-126 ; Non white space controls and 
+// the rest of the US-ASCII characters not including "[", "]", or "\"
+// ----------------------------------------------------
+//
+LOCAL_C TBool DText( TLex& aLex )
+	{
+	if( DoOrReverse( NoWSCtl, aLex ) )
+		{
+		return ETrue;
+		}
+
+	TChar ch( aLex.Get() );
+	return (ch >= 33 && ch <= 90)				// CSI: 47 # See a comment above.
+		|| (ch >= 94 && ch <= 126);				// CSI: 47 # See a comment above.
+	}
+
+// ================= MEMBER FUNCTIONS =======================
+
+// C++ default constructor cannot contain any code that might leave
+EXPORT_C CMsgMailAppUi::CMsgMailAppUi()
+    : iResource(*iCoeEnv)
+    {
+    }
+
+// Symbian OS default constructor can leave.
+EXPORT_C void CMsgMailAppUi::ConstructL()
+    {
+    // the implementation of this virtual function must call 
+    // CEikAppUi::ConstructL or CEikAppUi::BaseConstructL 
+    // before calling any other leaving function    
+    CMsgEditorAppUi::ConstructL();
+    SetSmallIconL();
+        
+	TParse* fp = new(ELeave) TParse(); 
+	fp->Set(KResourcesWithDir, &KDC_RESOURCE_FILES_DIR, NULL); 
+
+	TFileName fileName(fp->FullName());
+	delete fp;
+	iResource.OpenL(fileName);
+    
+    // Used in derived AppUI classes
+    if (FeatureManager::FeatureSupported( KFeatureIdHelp ))
+    	{
+    	iCommonFlags |= EHelpSupported;
+    	}
+    if (FeatureManager::FeatureSupported( KFeatureIdAvkonELaf ))
+    	{
+    	iCommonFlags |= EWestern;
+    	}
+    
+    // Call PrepareToLaunchL if opened as standalone
+    if( !iEikonEnv->StartedAsServerApp( ) )
+    	{
+       	Document()->PrepareToLaunchL( this );
+       	}
+  
+    }
+
+    
+// Destructor
+EXPORT_C CMsgMailAppUi::~CMsgMailAppUi()
+    {
+    delete iBannedChars;
+    iResource.Close();
+    }
+
+
+// ----------------------------------------------------------------------------
+// CMsgMailAppUi::MsgSaveL()
+// Saves message header, body, attachments and send options
+// in message store.
+// Argument:
+// TBool       aInPreparation
+// In certain cases (e.g. printing) new message has to be saved temporarily,
+// then aInPreparation flag is set to ETrue (default is EEalse) so automatic
+// cleanup is made by the server if something goes wrong.
+// ----------------------------------------------------------------------------
+//
+EXPORT_C TBool CMsgMailAppUi::MsgSaveL(const TBool aInPreparation, 
+                                      const TBool aReply /*= EFalse*/)
+    {
+    TBool saved(ETrue);
+    if ( Document()->MediaAvailable() )
+        {
+        saved = DoSaveMessageL( aInPreparation, aReply );
+        }
+    return saved;    
+    }
+
+// -----------------------------------------------------------------------------
+// CMsgMailAppUi::CheckStoreSpaceL()
+// -----------------------------------------------------------------------------
+//
+void CMsgMailAppUi::CheckStoreSpaceL( TMsvEmailEntry aMessage, TBool aReply )
+    {
+    // calculate message size
+    // if forwarding HTML message, all attachments are copied.
+    TBool countAttachments( ( aMessage.MHTMLEmail() && !aReply ) );
+    TInt docSize( MessageSizeL( countAttachments ) );
+    LOG1( "CMsgMailAppUi::CheckStoreSpaceL: %d", docSize );
+    
+    MailDocument()->DiskSpaceBelowCriticalLevelL( docSize );
+    }
+
+// -----------------------------------------------------------------------------
+// CMsgMailAppUi::SetServiceIdL()
+// -----------------------------------------------------------------------------
+//
+TBool CMsgMailAppUi::SetServiceIdL( 
+    TMsvEmailEntry& aEntry, CMsgMailDocument& aDocument )
+	{
+	TBool returnValue( ETrue );
+
+	// set related service ID
+	CMsvEntry* rootEntry = 
+		aDocument.Session().GetEntryL(KMsvRootIndexEntryIdValue);
+	CleanupStack::PushL(rootEntry);
+	rootEntry->SetSortTypeL(TMsvSelectionOrdering(KMsvNoGrouping,
+		EMsvSortByNone,ETrue));    
+	
+	TMsvEntry serviceEntry;
+	TRAPD(err, serviceEntry = rootEntry->ChildDataL(aEntry.iServiceId));
+	CMsgMailPreferences& pref = aDocument.SendOptions();
+	if (err == KErrNotFound) // mailbox deleted, look for default
+		{
+		const TMsvId defaultId(
+            MsvUiServiceUtilitiesInternal::DefaultServiceForMTML(
+				aDocument.Session(), KUidMsgTypeSMTP, ETrue));
+		if (defaultId == KMsvUnknownServiceIndexEntryId)
+			{ // no mailboxes defined
+			returnValue = EFalse;
+			}
+		else // set default mailbox's values to entry
+			{
+			serviceEntry = rootEntry->ChildDataL(defaultId);
+			aEntry.iServiceId = defaultId;
+			pref.SetServiceId(defaultId);
+			}
+		}
+    aEntry.iRelatedId = serviceEntry.iRelatedId;        
+
+	CleanupStack::PopAndDestroy(); // rootEntry
+	return returnValue;
+	}
+
+// -----------------------------------------------------------------------------
+// CMsgMailAppUi::SetEntryTimeL()
+// -----------------------------------------------------------------------------
+//
+void CMsgMailAppUi::SetEntryTimeL( TMsvEntry& aEntry )
+    {
+    TInt muiuFlags(0);
+	MailDocument()->MailCRHandler()->GetCRInt(
+		KCRUidMuiuVariation, 
+		KMuiuMceFeatures, muiuFlags);
+	
+	if ( (muiuFlags & KMceFeatureIdUseUtcTime) )
+		{
+		LOG( "CMsgMailAppUi::SetEntryTimeL UTC" );
+		aEntry.iDate.UniversalTime();
+		}
+	else
+		{
+		aEntry.iDate.HomeTime(); 
+		}    
+    }
+
+// -----------------------------------------------------------------------------
+// CMsgMailAppUi::SetEntryFlagsL()
+// -----------------------------------------------------------------------------
+//
+void CMsgMailAppUi::SetEntryFlagsL( 
+    TMsvEmailEntry& aEntry, TMsvId aOrigMessageId )
+    {
+    CMsgMailDocument* doc = MailDocument();
+    // buf must be available when ChangeL() is called
+    HBufC* buf = NULL;
+    // update entry details
+    CMsgAddressControl* control = AddressControl( EMsgComponentIdTo );    
+    if( control )
+        {
+        buf = MakeDetailsLC( *control );
+        aEntry.iDetails.Set( *buf );
+        }
+    else 
+        {
+        control = AddressControl( EMsgComponentIdFrom );
+        if( control )
+            {
+            buf = MakeDetailsLC( *control );
+            TPtr bufPtr( buf->Des() );
+            StripIllegalCharsL( bufPtr );    
+            aEntry.iDetails.Set( bufPtr );
+            }
+        }
+    
+    // calculate new message size 
+    aEntry.iSize = MessageSizeL( ETrue );
+    //aEntry.iSize += doc->Header().DataSize();
+    LOG1( "CMsgMailAppUi::SetEntryFlagsL entry size: %d", aEntry.iSize );
+    
+    // changed flag
+    doc->SetChanged(EFalse);
+
+    if (aOrigMessageId != doc->Entry().Id())
+        {
+        doc->SetEntryL( aOrigMessageId );
+        }
+    doc->CurrentEntry().ChangeL( aEntry );
+    //  LockEntryL();
+
+    // buf must be available when ChangeL() is called
+    if (buf)
+        {
+        CleanupStack::PopAndDestroy();
+        }
+    LOG1( "CMsgMailAppUi::SetEntryFlagsL entry size final: %d", aEntry.iSize );        
+    }
+
+// -----------------------------------------------------------------------------
+// CMsgMailAppUi::SetHeaderFieldsL()
+// -----------------------------------------------------------------------------
+//
+void CMsgMailAppUi::SetHeaderFieldsL( TMsvEmailEntry& aMessage )
+    {
+    CMsgMailDocument* doc = MailDocument();
+    CImHeader& header = doc->HeaderL();
+    // set subject to header & entry description
+    if (SubjectControl())
+    	{
+    	CRichText& subject = SubjectControl()->TextContent();
+    	header.SetSubjectL(subject.Read(0, subject.DocumentLength()));
+        
+        // update entry description
+    	aMessage.iDescription.Set(subject.Read(0, subject.DocumentLength()));
+    	}
+    else
+        {
+        header.SetSubjectL(KNullDesC);
+        aMessage.iDescription.Set(KNullDesC);
+        }
+
+    iNeedRefresh = EFalse;
+    
+    TInt recipientCount(0); 
+    CMsgAddressControl* toControl = AddressControl(EMsgComponentIdTo);
+    AppendRecipientsL( toControl, header.ToRecipients() );
+    recipientCount += header.ToRecipients().Count();
+    
+	CMsgAddressControl* ccControl = AddressControl(EMsgComponentIdCc);
+	AppendRecipientsL( ccControl, header.CcRecipients() );
+    recipientCount += header.CcRecipients().Count();
+            
+    CMsgAddressControl* bccControl = AddressControl(EMsgComponentIdBcc);
+    AppendRecipientsL( bccControl, header.BccRecipients() );
+    recipientCount += header.BccRecipients().Count();
+    
+    // Set multiblerecipient flag 
+    aMessage.SetMultipleRecipients( ( recipientCount > 1 ) );
+        
+    CMsgAddressControl* fromControl = AddressControl(EMsgComponentIdFrom);
+    if (fromControl)
+        {
+        CMsgRecipientArray* fromAddress = fromControl->GetRecipientsL();
+        if (fromAddress->Count() > 0)
+            {
+            CMsgRecipientItem* recItem = fromAddress->At(0);
+            HBufC* fullAddress = ConstructAddressStringLC(recItem);
+            header.SetFromL(*fullAddress);
+            CleanupStack::PopAndDestroy(); // fullAddress
+            }
+        if (iNeedRefresh)
+            {
+            fromControl->RefreshL(*fromAddress);
+            iNeedRefresh = EFalse;
+            }
+        }
+
+    // save CImHeader information to current entry's store
+    doc->SaveHeaderToStoreL();
+    }
+
+// -----------------------------------------------------------------------------
+// CMsgMailAppUi::SetSmallIconL()
+// -----------------------------------------------------------------------------
+//
+void CMsgMailAppUi::SetSmallIconL()
+    {
+    CAknTitlePane* titlePane = static_cast<CAknTitlePane*>
+        ( StatusPane()->ControlL( TUid::Uid( EEikStatusPaneUidTitle ) ) );    
+    if( titlePane )
+        {
+        TParse fileParse;
+        fileParse.Set( KMsgMailMBMFileName, &KDC_APP_BITMAP_DIR, NULL );     
+        CGulIcon* image = AknsUtils::CreateGulIconL(
+            AknsUtils::SkinInstance(),
+            KAknsIIDQgnPropMceEmailTitle,
+            fileParse.FullName(),
+            EMbmMsgmailutilsQgn_prop_mce_email_title,
+            EMbmMsgmailutilsQgn_prop_mce_email_title_mask
+            );
+        TRect mainPane;
+        AknLayoutUtils::LayoutMetricsRect( AknLayoutUtils::ETitlePane, mainPane );
+        TAknLayoutRect titleIconPaneLayoutRect;
+        titleIconPaneLayoutRect.LayoutRect(
+            mainPane,
+            AknLayoutScalable_Avkon::title_pane_g2( 0 ).LayoutLine() );
+    	TSize iconSize = titleIconPaneLayoutRect.Rect( ).Size( );
+    	AknIconUtils::SetSize( image->Bitmap(), iconSize, EAspectRatioPreserved );
+
+        image->SetBitmapsOwnedExternally( ETrue );	
+    	// takes ownership of bitmaps. Be sure nothing leaves before this
+    	titlePane->SetSmallPicture( image->Bitmap(), image->Mask(), ETrue );
+        delete image;    	
+        }
+    }    
+// -----------------------------------------------------------------------------
+// CMsgMailAppUi::MailDocument()
+// -----------------------------------------------------------------------------
+//
+CMsgMailDocument* CMsgMailAppUi::MailDocument()
+    {
+    return static_cast<CMsgMailDocument*> ( Document() );    
+    }
+
+// -----------------------------------------------------------------------------
+// CMsgMailAppUi::DoSaveMessageL()
+// -----------------------------------------------------------------------------
+//
+TBool CMsgMailAppUi::DoSaveMessageL( TBool aInPreparation, TBool aReply )
+    {
+    CMsgMailDocument* doc = MailDocument();
+    if ( doc->CurrentEntry().Entry().Id() != iMessageID )
+        {
+        doc->SetEntryL( iMessageID );
+        }
+    TMsvEmailEntry entry(doc->CurrentEntry().Entry());  
+    LOG1( "CMsgMailAppUi::DoSaveMessageL entry size: %d", entry.iSize );
+    entry.SetBodyTextComplete( ETrue );
+    
+    ASSERT( entry.Id() == iMessageID );
+    CheckStoreSpaceL( entry, aReply );
+
+    // set preparation flag
+    if (!entry.MHTMLEmail() && !aReply)
+        {
+        entry.SetInPreparation(aInPreparation);    
+        // set visible if not in preparation state
+        entry.SetVisible(!aInPreparation);
+        UnlockEntry();
+        doc->CurrentEntry().ChangeL(entry);
+        }
+    //-------------------------------
+    // 1. set variables
+    //-------------------------------        
+    TBool returnValue(ETrue);
+        
+    //-------------------------------------
+    // 2. create new message id, if needed
+    //-------------------------------------    
+    const TMsvId origMessageId(entry.Id());
+
+    entry.iType = KUidMsvMessageEntry;   
+	CMsgMailPreferences& pref = doc->SendOptions();    
+	
+        
+	// EMail type       
+	entry.iMtm = KUidMsgTypeSMTP;
+	// set related service ID
+	returnValue = SetServiceIdL( entry, *doc );
+        
+    // set Send options
+    pref.ImportSendOptionsL(entry);        
+	// set entry time
+    SetEntryTimeL( entry );
+
+    //-------------------------------
+    // 3. set CImHeader fields
+    //-------------------------------    
+    SetHeaderFieldsL( entry );
+
+    // store message body
+    CMsgBodyControl* bodyControl = BodyControl();
+    if (bodyControl)
+    	{
+    	CMuiuOperationWait* wait = CMuiuOperationWait::NewLC();
+    	doc->MessageL().StoreBodyTextL( 
+    	    origMessageId,
+        	bodyControl->TextContent(), 
+        	wait->iStatus);
+        	
+    	wait->Start();
+    	CleanupStack::PopAndDestroy(); //wait
+    	}
+
+    //-------------------------------
+    // 5. update the entry
+    //-------------------------------
+    SetEntryFlagsL( entry, origMessageId );
+
+    return returnValue;
+    }
+
+// -----------------------------------------------------------------------------
+// CMsgMailAppUi::ConstructAddressStringLC()
+// -----------------------------------------------------------------------------
+//
+HBufC* CMsgMailAppUi::ConstructAddressStringLC(CMsgRecipientItem* aRecItem)
+    {   
+    HBufC* fullAddress = NULL;    
+
+    // remove illegal characters from user inputted addresses
+    if (!aRecItem->Name()->Length())
+        {
+        TPtr address(aRecItem->Address()->Des());
+        // won't overflow, only removing characters
+        if (StripIllegalCharsL(address))
+            {
+            aRecItem->SetAddressL(address);
+            }
+        }
+    
+    // check that address item has alias and address and they are not the same
+    if (aRecItem->Name()->Length() &&
+        aRecItem->Name()->Compare(*(aRecItem->Address())) != 0)
+        {
+        // 2 Array for name and address
+        CDesCArrayFlat* strings = new(ELeave) CDesCArrayFlat( 2 );		// CSI: 47 # See a comment above.
+        CleanupStack::PushL( strings );
+        
+        strings->AppendL( *aRecItem->Name() );
+        strings->AppendL( *aRecItem->Address() );
+
+        fullAddress = StringLoader::LoadL(
+            R_MAIL_ADDRESS_FORMAT_STRING, *strings, iCoeEnv);
+        CleanupStack::PopAndDestroy(); // strings
+        CleanupStack::PushL( fullAddress );
+        }
+    // otherwise return just address
+    else
+        {
+        fullAddress = aRecItem->Address()->AllocLC();
+        }
+    return fullAddress;
+    }
+    
+// -----------------------------------------------------------------------------
+// CMsgMailAppUi::StripIllegalCharsL()
+// -----------------------------------------------------------------------------
+//
+TBool CMsgMailAppUi::StripIllegalCharsL(TDes& aString)
+    {
+    TBool returnValue(EFalse);
+    // initialise array when called for the 1st time
+    if (!iBannedChars)
+        {   
+        iBannedChars = iEikonEnv->ReadDesC16ArrayResourceL(
+            R_MAIL_BANNED_CHARS );
+        iBannedChars->Compress();
+        }
+
+    // Check that inputted address does not contain illegal characters
+    // These characters would mess up address inputting if they were saved
+    const TInt count(iBannedChars->Count());
+    for (TInt i = 0; i < count; i++)
+        {    
+        TInt pos(aString.Find((*iBannedChars)[i]));    
+        while (pos != KErrNotFound)
+            {
+            aString.Delete(pos, 1);
+            pos = aString.Find((*iBannedChars)[i]);
+            iNeedRefresh = ETrue;
+            returnValue = ETrue;
+            }
+        }
+
+	aString.Trim();
+    return returnValue;
+    }
+
+// -----------------------------------------------------------------------------
+// CMsgMailAppUi::AppendRecipientsL()
+// -----------------------------------------------------------------------------
+//
+void CMsgMailAppUi::AppendRecipientsL( 
+    CMsgAddressControl* aField, CDesCArray& aArray )
+	{
+    aArray.Reset();	
+	
+	if ( aField )
+	    {
+    	const CMsgRecipientArray* recipients = aField->GetRecipientsL();
+    	const TInt count(recipients->Count());
+    	for (TInt i=0; i < count; i++)
+    		{
+    		CMsgRecipientItem* recItem = recipients->At(i);
+    		HBufC* fullAddress = ConstructAddressStringLC(recItem);
+    		aArray.AppendL(*fullAddress);
+    		CleanupStack::PopAndDestroy(); // fullAddress
+    		}
+
+    	if (iNeedRefresh)
+    		{
+    		aField->RefreshL(*recipients);
+    		iNeedRefresh = EFalse;
+    		}
+	    }
+	}
+
+// -----------------------------------------------------------------------------
+// CMsgMailAppUi::CheckFFSL()
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TBool CMsgMailAppUi::CheckFFSL(const TInt aSize)
+    {
+    return MailDocument()->DiskSpaceBelowCriticalLevelL( aSize );
+    }
+
+// -----------------------------------------------------------------------------
+// CMsgMailAppUi::IsBannedMimeL()
+// -----------------------------------------------------------------------------
+//    
+EXPORT_C TBool CMsgMailAppUi::IsBannedMimeL(const TDesC& /*aBuf*/) const
+    {
+    // Use MailUtils::IsClosedFileL instead of this 
+    User::Leave( KErrNotSupported );
+    return EFalse;
+    }
+// -----------------------------------------------------------------------------
+// CMsgMailAppUi::IsValidAddress()
+// -----------------------------------------------------------------------------
+// 
+EXPORT_C TBool CMsgMailAppUi::IsValidAddress( const TDesC& aAddress ) const
+	{
+	TLex lex( aAddress );
+	return Address( lex ) && lex.Eos();
+	}
+
+// -----------------------------------------------------------------------------
+// CMsgMailAppUi::CheckIfBannedL()
+// -----------------------------------------------------------------------------
+// 
+EXPORT_C TBool CMsgMailAppUi::CheckIfBannedL(const TDesC& /*aMimeType*/)
+    {
+    // Use MailUtils::IsClosedFileL instead of this
+    User::Leave( KErrNotSupported );
+    return EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CMsgMailAppUi::CheckIfBannedL()
+// -----------------------------------------------------------------------------
+// 
+EXPORT_C TBool CMsgMailAppUi::CheckIfBannedL(RFile& /*aFile*/)
+    {
+    // Use MailUtils::IsClosedFileL instead of this
+    User::Leave( KErrNotSupported );
+    return EFalse;		
+    }    
+
+// -----------------------------------------------------------------------------
+// CMsgMailAppUi::CleanupWaitNoteWrapper()
+// -----------------------------------------------------------------------------
+// 
+EXPORT_C void CMsgMailAppUi::CleanupWaitNoteWrapper(TAny* aAny)
+    {
+    CAknWaitNoteWrapper** wrapper = STATIC_CAST(CAknWaitNoteWrapper**, aAny);
+    if (wrapper && *wrapper)
+        {
+        delete *wrapper;
+        *wrapper = NULL;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CMsgMailAppUi::CleanupWaitDialog()
+// -----------------------------------------------------------------------------
+// 
+EXPORT_C void CMsgMailAppUi::CleanupWaitDialog(TAny* aAny)
+    {
+    CAknWaitDialog** dialog = STATIC_CAST(CAknWaitDialog**, aAny);
+    if (dialog && *dialog)
+        {
+        delete *dialog;
+        *dialog = NULL;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CMsgMailAppUi::MessageSizeL()
+// -----------------------------------------------------------------------------
+//     
+EXPORT_C TInt CMsgMailAppUi::MessageSizeL( TBool aCountAttachments )	// CSI: 40 # We must return 
+																		// the integer value although this 
+																		// is a leaving method.
+    {
+    // calculate message size 
+    const TInt multibleByTwoForUnicode(2);
+
+    TInt fieldSize(0);
+    TInt count;
+
+    CMsgAddressControl* addressField;
+    
+    addressField = AddressControl( EMsgComponentIdTo );
+    if (addressField)
+        {
+        addressField->GetSizeOfAddresses(count, fieldSize);
+        }
+    TInt docSize(fieldSize);
+    addressField = AddressControl( EMsgComponentIdCc );
+    if (addressField)
+        {
+        addressField->GetSizeOfAddresses(count, fieldSize);
+        docSize += fieldSize;
+        }
+
+    addressField = AddressControl( EMsgComponentIdBcc );
+    if (addressField)
+        {
+        addressField->GetSizeOfAddresses(count, fieldSize);
+        docSize += fieldSize;
+        }
+
+    if( SubjectControl() )
+        {
+        docSize += SubjectControl()->TextContent().DocumentLength() 
+            * multibleByTwoForUnicode;
+        }    
+    CRichText& rtf = BodyControl()->TextContent();
+    docSize += rtf.DocumentLength() * multibleByTwoForUnicode;
+    
+    // Attachments
+    if ( aCountAttachments )
+        {        
+        CMsgAttachmentModel& attModel = Document()->AttachmentModel();
+        const TInt attCount( attModel.NumberOfItems() );    
+        
+        for (TInt cc=0; cc < attCount; cc++)
+            {
+            docSize += attModel.AttachmentInfoAt(cc).Size();
+            }
+        }    
+    
+    LOG1( "CMsgMailAppUi::MessageSizeL: %d", docSize );
+    return docSize;     
+    }
+
+// -----------------------------------------------------------------------------
+// CMsgMailAppUi::SetDialerEnabled()
+// -----------------------------------------------------------------------------
+// 
+EXPORT_C void CMsgMailAppUi::SetDialerEnabled( TBool aEnable )
+    {
+    if( aEnable )
+        {
+        // send key handling enabled
+        SetKeyEventFlags( 0 );
+        }
+    else
+        {
+        // send key handling disabled
+        SetKeyEventFlags( 
+            CAknAppUiBase::EDisableSendKeyShort | 
+            CAknAppUiBase::EDisableSendKeyLong );        
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CMsgMailAppUi::MakeDetailsLC()
+// -----------------------------------------------------------------------------
+// 
+HBufC* CMsgMailAppUi::MakeDetailsLC( CMsgAddressControl& aControl )
+    {
+    // Array is owned by the control
+    CMsgRecipientArray* recipients = aControl.GetRecipientsL();
+    TInt recipCount = recipients->Count();
+    
+    LOG1( "CMsgMailAppUi::MakeDetailsLC: %d Recipient(s)", recipCount );        
+    if( recipCount == 0 )
+        {
+        // no recipients
+        return KNullDesC().AllocLC();
+        }
+    
+    // Append recipients to text.
+    HBufC* detailsBuf = HBufC::NewLC( KMsgMaxDetailsLength );
+    TPtr details( detailsBuf->Des() );
+    TInt separatorLen = KMsgDetailsSeparator().Length();
+    
+    for( TInt i = 0; i < recipCount; ++i )
+        {
+        CMsgRecipientItem* item = recipients->At(i);
+
+        // Select name or address (prefer name if available)
+        HBufC* textToAdd = item->Name();
+        if( !textToAdd )
+            {
+            textToAdd = item->Address();
+            }
+        else if( textToAdd->Length() == 0 )
+            {
+            textToAdd = item->Address();
+            }
+        
+        if( textToAdd )
+            {
+            TInt textSpace = KMsgMaxDetailsLength - details.Length();
+            
+            // Append separator
+            if( textSpace < separatorLen )
+                {
+                // no space for separator -> all done
+                break;
+                }
+            if( details.Length() > 0 )
+                {
+                // not a first recipient -> add separator
+                details.Append( KMsgDetailsSeparator );
+                textSpace -= separatorLen;
+                }
+            
+            // Append recipient's name or address
+            details.Append( textToAdd->Left( textSpace ) );
+            
+            if( KMsgMaxDetailsLength - details.Length() <= 0 )
+                {
+                // No more space -> all done
+                break;
+                }
+            }
+        }
+    
+    return detailsBuf;
+    }
+
+
+//  End of File