mobilemessaging/unieditor/smsplugin/src/UniSmsPlugin.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Fri, 19 Feb 2010 22:47:38 +0200
branchRCL_3
changeset 9 1d7827e39b52
parent 2 0bf1d54f37d9
child 13 a9c7e5670d17
permissions -rw-r--r--
Revision: 201003 Kit: 201007

/*
* Copyright (c) 2005-2008 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:  
*       Provides UniEditor SMS Plugin methods.
*
*/




// INCLUDE FILES

// Symbian: 
#include <e32base.h>
#include <implementationproxy.h>
#include <ecom.h>
#include <txtetext.h>
#include <txtrich.h>

#include <mmsvattachmentmanager.h>
#include <mmsvattachmentmanagersync.h>
#include <gsmerror.h>                       // KErrGsmOfflineOpNotAllowed
#include <featmgr.h> 

#include <mtclreg.h>
#include <smsclnt.h>
#include <smscmds.h>
#include <smuthdr.h>
#include <csmsemailfields.h>
#include <csmsaccount.h>
#include <charconv.h>
#include <smut.h>
#include <smumutil.h>
#include <cmsvmimeheaders.h>
#include <badesca.h>
#include <e32cmn.h>
#include <muiumsvuiserviceutilitiesinternal.h> 
#include <gsmuset.h>

// S60
#include <mmsgenutils.h>
#include <MuiuOperationWait.h>
#include <vcard.h>
#include <SenduiMtmUids.h>
#include <MsgBioUids.h>
#include <MsgMimeTypes.h>
#include "UniSendingSettings.h"
#include "UniClientMtm.h"
#include "UniEditorUids.hrh"
#include "messagingvariant.hrh"
#include "UniSmsPlugin.h"
#include "UniSmsUtils.h"
#include "MsgAttachmentUtils.h" 
#include "UniMsvEntry.h"

// resources
#include <UniSmsPluginD.rsg>                   
#include <avkon.rsg>              

//LOGGING
#include "UniEditorLogging.h"

// CONSTANTS
const TImplementationProxy KImplementationTable[] = 
	{
	IMPLEMENTATION_PROXY_ENTRY( KUidUniEditorSmsPlugin, CUniSmsPlugin::NewL)
	};

// Used to set msg in unparsed state
const TInt KSmsPluginBioMsgUnparsed = 0;

// Description length for sms messages
const TInt KSmsMessageEntryDescriptionAmountOfChars = 60;

//used for descriptor array containing recipients
const TInt KRecipientsArrayGranularity = 8;

// For address information separation (start)
const TUint KMsgSmsAddressStartChar         ('<'); 

// For address information separation (end)
const TUint KMsgSmsAddressEndChar           ('>');

const TUint KUniSmsStartParenthesis ('(');
const TUint KUniSmsEndParenthesis (')');

// String length for Service centre name
const TInt KUniSmsSCStringLength = 50;

const TUid KUidMsvSMSHeaderStream_COPY_FROM_SMUTHDR_CPP  = {0x10001834};

// Amount of to be converted chars during extracting description
const TInt KSmsEdExtrDescReplaceCharacterCount = 3;

// Unicode char for linefeed regocnised by basic phones
const TUint KSmsEdUnicodeLFSupportedByBasicPhones = 0x000A;
// ========== LOCAL FUNCTIONS ==================================================
GLDEF_C void Panic( TInt aCategory );


// ============================ MEMBER FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CUniSmsPlugin* CUniSmsPlugin::NewL( TAny* aConstructionParameters )
    {
	TUniPluginParams* params = reinterpret_cast<TUniPluginParams*>( aConstructionParameters );
    CUniSmsPlugin* self = new ( ELeave ) CUniSmsPlugin( params->iSession, params->iUniMtm ); 
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    return self;
    }

// -----------------------------------------------------------------------------
// Destructor
// -----------------------------------------------------------------------------
//
CUniSmsPlugin::~CUniSmsPlugin()
    {
    delete iRichText;
    delete iParaFormatLayer;
    delete iCharFormatLayer;
    delete iSmsHeader;
    delete iSmsMtm;
    delete iMtmRegistry;
    delete iEmailOverSmsC;
    delete iRecipients;	
    }

// -----------------------------------------------------------------------------
// C++ default constructor
// -----------------------------------------------------------------------------
//
CUniSmsPlugin::CUniSmsPlugin( CMsvSession& aSession, CUniClientMtm& aUniMtm )
    : iSession( aSession ),
    iUniMtm( aUniMtm ),
    iBioMsg( EFalse ),
    iOfflineSupported( EFalse )
    {
    }

// -----------------------------------------------------------------------------
// Symbian 2nd phase constructor
// -----------------------------------------------------------------------------
//
void CUniSmsPlugin::ConstructL()
    {
    UNILOGGER_ENTERFN("CUniSmsPlugin::ConstructL");
    iParaFormatLayer = CParaFormatLayer::NewL();
    iCharFormatLayer = CCharFormatLayer::NewL();
    iRichText = CRichText::NewL( iParaFormatLayer, iCharFormatLayer );
    iEmailOverSmsC = CSmsNumber::NewL();
	
    CMsvEntry& entry = SmsMtmL()->Entry();
    entry.SetEntryL( KMsvRootIndexEntryId );
    
    TSmsUtilities::ServiceIdL( entry, iSmsServiceId );
    
    FeatureManager::InitializeLibL();
    if ( FeatureManager::FeatureSupported( KFeatureIdOfflineMode ) )
        {
        iOfflineSupported = ETrue;   
        }
    else
        {
        iOfflineSupported = EFalse;  
        }
    
    //Turkish SMS-PREQ2265 Specific
    if ( FeatureManager::FeatureSupported( KFeatureIdNltSupport ) )
        {
        iNLTFeatureSupport = ETrue;
        }
    else
        {
        iNLTFeatureSupport = EFalse;
        }
    
    FeatureManager::UnInitializeLib();
    iStoreChanged = EFalse;
    
    UNILOGGER_LEAVEFN("CUniSmsPlugin::ConstructL");
    }

// -----------------------------------------------------------------------------
// LoadHeadersL
// -----------------------------------------------------------------------------
//
void CUniSmsPlugin::LoadHeadersL( CMsvStore* aStore )
    {
    UNILOGGER_ENTERFN("CUniSmsPlugin::LoadHeadersL");
    delete iSmsHeader;
    iSmsHeader = NULL;

    if ( aStore && aStore->HasBodyTextL() )
        {
    	aStore->RestoreBodyTextL( *iRichText );
        }

	iSmsHeader = CSmsHeader::NewL( CSmsPDU::ESmsSubmit, *iRichText );
	
	if ( aStore && aStore->IsPresentL( KUidMsvSMSHeaderStream_COPY_FROM_SMUTHDR_CPP ) )
	    {
	    iSmsHeader->RestoreL( *aStore );
	    }
	else
	    {
        CSmsSettings* settings = CSmsSettings::NewLC();
    	CSmsAccount* account = CSmsAccount::NewLC();
    	account->LoadSettingsL( *settings );
    	CleanupStack::PopAndDestroy( account );
        iSmsHeader->SetSmsSettingsL( *settings );
        CleanupStack::PopAndDestroy( settings );
	    }
		TSmsUserDataSettings smsSettings;		
		smsSettings.SetTextCompressed( EFalse );
		TRAP_IGNORE(iSmsHeader->Message().SetUserDataSettingsL( smsSettings ));
    UNILOGGER_LEAVEFN("CUniSmsPlugin::LoadHeadersL");
    }

// -----------------------------------------------------------------------------
// SaveHeadersL 
// -----------------------------------------------------------------------------
//
void CUniSmsPlugin::SaveHeadersL( CMsvStore& aStore )
    {
    if ( iSmsHeader )
        {
        iSmsHeader->StoreL( aStore );
        }
    }
// -----------------------------------------------------------------------------
// ResetUniAddresselist
// -----------------------------------------------------------------------------
//
void CUniSmsPlugin::ResetUniAddresselist()
    {
    const CMsvRecipientList& uniRecipients = iUniMtm.AddresseeList();       
    while ( uniRecipients.Count() )
        {
        iUniMtm.RemoveAddressee( 0 );
        }  
    }
// -----------------------------------------------------------------------------
// ConvertFromL
// -----------------------------------------------------------------------------
//
TMsvId CUniSmsPlugin::ConvertFromL( TMsvId aId )
    {
    return DoConvertFromL( aId, EFalse );
    }

// -----------------------------------------------------------------------------
// DoConvertFromL
// -----------------------------------------------------------------------------
//
TMsvId CUniSmsPlugin::DoConvertFromL( TMsvId aId, TBool aIsForward )
	{
    UNILOGGER_ENTERFN("CUniSmsPlugin::ConvertFromL");
    UNILOGGER_WRITE_TIMESTAMP("CUniSmsPlugin::ConvertFromL start");
    SmsMtmL()->SwitchCurrentEntryL( aId );
    SmsMtmL()->LoadMessageL();
    iUniMtm.SwitchCurrentEntryL( aId );
    iUniMtm.LoadMessageL(); 
    ResetUniAddresselist();
    TPtrC name;
    TPtrC address;  


	const CSmsEmailFields& emailFields = SmsMtmL( )->SmsHeader( ).EmailFields();

	if( emailFields.HasAddress( ) && !aIsForward )
		{ // If email address set -> copy them here
	    const MDesCArray& emailRecipients = emailFields.Addresses();
		for( TInt id = 0; id < emailRecipients.MdcaCount( ); id++ )
			{
	        NameAndAddress( emailRecipients.MdcaPoint( id ), name, address );
	        iUniMtm.AddAddresseeL( 
	            EMsvRecipientTo,
	            address,
	            name );
			}
		}

    // Copy non-email over sms addresses if needed
    const CMsvRecipientList& smsRecipients = SmsMtmL()->AddresseeList();

    while ( smsRecipients.Count() )
        { // Go thru all the recipients
		if( !emailFields.HasAddress( ) && !aIsForward )
			{ // and copy them only if email addresses did not exist
	        NameAndAddress( smsRecipients[ 0 ], name, address );
	        iUniMtm.AddAddresseeL( 
	            EMsvRecipientTo,
	            address,
	            name );
			}
        SmsMtmL()->RemoveAddressee( 0 );
        }
    
    if( emailFields.Subject( ).Length( ) )
    	{ // If email subject exists -> copy it
    	iUniMtm.SetSubjectL( emailFields.Subject( ) );
    	}
    
    //Get sms entry 
    TMsvEntry smsTEntry = SmsMtmL()->Entry().Entry();
    
    if (  smsTEntry.iBioType == KMsgBioUidVCard.iUid
        || smsTEntry.iBioType == KMsgBioUidVCalendar.iUid )
        { 
        //We must check here if there is two attachments. This happens in case
        //if sending fails and message opened from drafts
        CMsvStore* store = iUniMtm.Entry().EditStoreL();
        CleanupStack::PushL( store );
        MMsvAttachmentManagerSync& managerSync = store->AttachmentManagerExtensionsL();        
        MMsvAttachmentManager& manager = store->AttachmentManagerL();
        if ( manager.AttachmentCount() == 2)
        	{
            managerSync.RemoveAttachmentL( 1 ); 	
        	}
        store->CommitL();  	
        CleanupStack::PopAndDestroy( store );
        }     
    else   //plain text
        {
        TInt totalLength( SmsMtmL()->Body().DocumentLength() );
        if ( totalLength > 0 )
            {
            HBufC* bodyText = HBufC::NewLC ( totalLength ); 
            TPtr bodyTextPtr ( bodyText->Des() ); 
            
            SmsMtmL()->Body().Extract( bodyTextPtr, 0, totalLength );
            
            iUniMtm.Body().InsertL( 0, bodyTextPtr );
                        
            CleanupStack::PopAndDestroy( bodyText );            
            }
        }
    
    SmsMtmL()->Body().Reset();
    SmsMtmL()->SaveMessageL();
    TMsvEntry uniTEntry = iUniMtm.Entry().Entry();
    CMsvStore* store = iUniMtm.Entry().EditStoreL();
    CleanupStack::PushL( store );
   
    iUniMtm.SaveMessageL(*store, uniTEntry);
    
    store->CommitL();
    CleanupStack::PopAndDestroy(store);  
    // Lets convert the bits to Uni mode
	TUniMsvEntry::SetForwardedMessage( uniTEntry, aIsForward );
	
    uniTEntry.iMtm.iUid = KUidUniMtm;
    iUniMtm.Entry().ChangeL( uniTEntry );
    UNILOGGER_LEAVEFN("CUniSmsPlugin::ConvertFromL");    
    UNILOGGER_WRITE_TIMESTAMP("CUniSmsPlugin::ConvertFromL end");
    return aId;
    }

TInt32 CUniSmsPlugin::AttachmentsSizeL( CMsvStore& aStore )
    {
    TInt32 size = 0;

    MMsvAttachmentManager& attachMan = aStore.AttachmentManagerL();
    TInt numAttachments = attachMan.AttachmentCount();

    for ( TInt i = 0; i < numAttachments; i++ )
        {
        CMsvAttachment* attachmentInfo = attachMan.GetAttachmentInfoL( i );
        CleanupStack::PushL( attachmentInfo );
        
        CMsvMimeHeaders* mimeHeaders = CMsvMimeHeaders::NewL();
        CleanupStack::PushL( mimeHeaders );
        
        mimeHeaders->RestoreL( *attachmentInfo );
        
        RFile attaFile = attachMan.GetAttachmentFileL( i );
        CleanupClosePushL( attaFile );
        TInt fileSize = 0;
        
        // If we cannot access the file, we are in trouble
        User::LeaveIfError( attaFile.Size( fileSize ) ); 
        
        // This adds up mime header size + actual attachment binary data
        size += mimeHeaders->Size() + fileSize;

        CleanupStack::PopAndDestroy( &attaFile );
        CleanupStack::PopAndDestroy( mimeHeaders );
        CleanupStack::PopAndDestroy( attachmentInfo );
        }

    return size;
    }
	
// -----------------------------------------------------------------------------
// ConvertToL
// -----------------------------------------------------------------------------
//
TMsvId CUniSmsPlugin::ConvertToL( TMsvId aId )
    {    
    UNILOGGER_ENTERFN("CUniSmsPlugin::ConvertToL");
    SmsMtmL()->SwitchCurrentEntryL( aId );
    SmsMtmL()->LoadMessageL();
    iUniMtm.SwitchCurrentEntryL( aId );
    iUniMtm.LoadMessageL();
 
    const CMsvRecipientList& uniRecipients = iUniMtm.AddresseeList();
    
    //Save for email over sms  
    if ( iRecipients )
    	{
    	delete iRecipients;
    	iRecipients = NULL;
    	}
    iRecipients = new ( ELeave ) CDesCArrayFlat( KRecipientsArrayGranularity );   
         
    CSmsEmailFields *emailFields = CSmsEmailFields::NewL();
    CleanupStack::PushL( emailFields );
   
    while ( uniRecipients.Count() )
        {
        if ( IsEmailAddress( TMmsGenUtils::PureAddress( uniRecipients[ 0 ] )))
            {
            emailFields->AddAddressL( TMmsGenUtils::PureAddress( uniRecipients[ 0 ] ) );
            }
        else
            {
            SmsMtmL()->AddAddresseeL( 
                TMmsGenUtils::PureAddress( uniRecipients[ 0 ] ),
                TMmsGenUtils::Alias( uniRecipients[ 0 ] ) );    
            }

        iRecipients->AppendL( uniRecipients[ 0 ]  );
        iUniMtm.RemoveAddressee( 0 );
        }   
    if ( iUniMtm.SubjectL().Length() )
        {
        emailFields->SetSubjectL( iUniMtm.SubjectL() );
        }
    
    SmsMtmL()->SmsHeader().SetEmailFieldsL( *emailFields );
    CleanupStack::PopAndDestroy( emailFields );        
    
    CMsvStore* store = iUniMtm.Entry().EditStoreL();
    CleanupStack::PushL( store );
    MMsvAttachmentManager& manager = store->AttachmentManagerL();
    MMsvAttachmentManagerSync& managerSync = store->AttachmentManagerExtensionsL();
    TUid bioType =
        {
        0 
        };
   
    CMsvAttachment* atta ( NULL );
    switch ( manager.AttachmentCount() )
        {
        case 0:
            {
            //In case of empty message.
            //There is not even smil.
            SmsMtmL()->Body().Reset();
            break;
            }
        case 1:  
        	{
        	atta = manager.GetAttachmentInfoL( 0 );
        	 if ( atta->MimeType() == KMsgMimeSmil )
                {                        
                managerSync.RemoveAttachmentL( 0 ); 
                delete atta;
                atta= NULL;
                }
        	 else
        	     CleanupStack::PushL(atta);
        	break;
        	}
        case 2:  //There is usually a SMIL also.
            {
            //In these case branch we assume that there is only one text atta
            //or one text atta and a SMIL
            //Everything else is a programming error in the caller

            CMsvAttachment* tempAtta1 = manager.GetAttachmentInfoL( 0 );
            CleanupStack::PushL(tempAtta1);
            CMsvAttachment* tempAtta2 = manager.GetAttachmentInfoL( 1 );
            CleanupStack::PushL(tempAtta2);
                   
            if ( tempAtta1->MimeType() == KMsgMimeSmil )
                {
                CleanupStack::Pop( tempAtta2 );
                CleanupStack::PopAndDestroy( tempAtta1 );
                CleanupStack::PushL( tempAtta2 );
                     
                managerSync.RemoveAttachmentL( 0 ); 
                atta=tempAtta2;
                }
            else if ( tempAtta2->MimeType() == KMsgMimeSmil )    
                {
                CleanupStack::PopAndDestroy( tempAtta2 );
                managerSync.RemoveAttachmentL( 1 ); 
                atta=tempAtta1;
                }
            else
                { 
                //Programming error in caller code
#ifdef _DEBUG 
                UNILOGGER_WRITEF(_L("PANIC: Two attas but no smil"));
                Panic ( EIllegalArguments );     
#endif 
                User::Leave( KErrArgument );
                
                }
            break;
            }
        default:
            {
            //Programming error in caller code
#ifdef _DEBUG 
            UNILOGGER_WRITEF(_L("PANIC: Two many attas"));
            Panic ( EIllegalArguments );
#endif            
            User::Leave( KErrArgument );
            break;
            }
        }

    if ( atta )
        {  	
        UNILOGGER_WRITEF8(_L8("Mime Type: %S"),&(atta->MimeType()));
        UNILOGGER_WRITEF(_L("Atta Name: %S"),&(atta->AttachmentName()));

        RFile file = manager.GetAttachmentFileL( 0 );
        CleanupClosePushL( file );
                   
        //Note that the attachments is not removed in case of smart messaging
        if ( atta->MimeType().CompareF( KMsgMimeTextPlain ) == 0 )
            {
            iBioMsg=EFalse;
            CreatePlainTextSMSL( file );
            managerSync.RemoveAttachmentL( 0 ); 
            }
        else if ( atta->MimeType().CompareF(KMsgMimeVCard) == 0 )
            {
            iBioMsg=ETrue;
            CreateVCardSMSL( file );
            bioType = KMsgBioUidVCard;
            SmsMtmL()->BioTypeChangedL( bioType );
            //Do not remove vCard atta here. 
            }
        else if ( atta->MimeType().CompareF(KMsgMimeVCal ) == 0 ||
                  atta->MimeType().CompareF(KMsgMimeICal ) == 0 )
            {
            iBioMsg=ETrue;
            CreateVCalSMSL( file );
            bioType = KMsgBioUidVCalendar;
            SmsMtmL()->BioTypeChangedL( bioType );
            //Do not remove vCal atta here. 
            }
        else
            {
            User::Leave( KErrArgument );
            } 
        CleanupStack::PopAndDestroy( &file );
        CleanupStack::PopAndDestroy( atta );
        }
        	
    TMsvEntry tEntry = SmsMtmL()->Entry().Entry();
    tEntry.SetAttachment( EFalse ); 
    tEntry.iMtm = KSenduiMtmSmsUid;
    tEntry.iType = KUidMsvMessageEntry;
    tEntry.iRelatedId = iSmsServiceId;
    tEntry.iServiceId = KMsvLocalServiceIndexEntryId;
    tEntry.iDate.UniversalTime();
    tEntry.SetInPreparation( ETrue );
    tEntry.SetVisible( EFalse );

    CSmsSettings* sendOptions = CSmsSettings::NewL();
    CleanupStack::PushL( sendOptions );
    
    // "ConvertToL" might be called right after constructor.
    // In this case iSmsHeader is still NULL. Need to initialise.
    if ( !iSmsHeader )
        {
        LoadHeadersL( store );
        }
  	iSmsHeader->GetSmsSettingsL( *sendOptions );
	
    sendOptions->CopyL( *sendOptions );
    
	if ( !iBioMsg )
	    {
	    if( iUnicodeMode )
		    {
		    sendOptions->SetCharacterSet( TSmsDataCodingScheme::ESmsAlphabetUCS2 );
		    }
	    else
		    {
		    sendOptions->SetCharacterSet( TSmsDataCodingScheme::ESmsAlphabet7Bit );
		    }
	    }
    else
        {
        // make sure bio messages have no conversion
        tEntry.iBioType = bioType.iUid;
        sendOptions->SetMessageConversion( ESmsConvPIDNone );
        sendOptions->SetCharacterSet( TSmsDataCodingScheme::ESmsAlphabet8Bit );
        }
    
    // Update some global SMS settings affecting all messages.
    // These might have changed from the ones retrieved when
    // the message was created and so needs to be updated.
    CSmsSettings* defaultSettings = CSmsSettings::NewLC();
	
	CSmsAccount* account = CSmsAccount::NewLC();
	account->LoadSettingsL( *defaultSettings );
	CleanupStack::PopAndDestroy( account );
    
    sendOptions->SetDeliveryReport( defaultSettings->DeliveryReport() );
    sendOptions->SetSmsBearer( defaultSettings->SmsBearer() );
    sendOptions->SetValidityPeriod( defaultSettings->ValidityPeriod() );
    sendOptions->SetReplyPath( defaultSettings->ReplyPath() );
    
    CleanupStack::PopAndDestroy( defaultSettings );
    
    iSmsHeader->SetSmsSettingsL( *sendOptions );

	// Move all the stuff from iSmsHeader::SmsSettings to SmsMtm::SmsHeader::SmsSettings
	SmsMtmL()->SmsHeader( ).SetSmsSettingsL( *sendOptions );
	SmsMtmL()->SmsHeader( ).Message( ).
		SetServiceCenterAddressL( iSmsHeader->Message( ).ServiceCenterAddress( ) );

    if(iNLTFeatureSupport)
        {
        //Turkish SMS-PREQ2265 Specific
        TSmsEncoding currAlternateEncoding = iSmsHeader->Message().Alternative7bitEncoding();
        SmsMtmL()->SmsHeader().Message().SetAlternative7bitEncoding(currAlternateEncoding);       
        }
	
    CleanupStack::PopAndDestroy( sendOptions ); 

    SmsMtmL()->SaveMessageL(*store, tEntry);
    store->CommitL();           
    tEntry.iSize = store->SizeL();
    if( AttachmentsSizeL( *store ) > 0 )
        {
        tEntry.SetAttachment( ETrue );
        }
    CleanupStack::PopAndDestroy( store );
    
    SmsMtmL()->Entry().ChangeL( tEntry );
    UNILOGGER_LEAVEFN("CUniSmsPlugin::ConvertToL");
    return aId;
    }

// -----------------------------------------------------------------------------
// CreateReplyL
// -----------------------------------------------------------------------------
//
TMsvId CUniSmsPlugin::CreateReplyL( TMsvId aSrc, TMsvId aDest, TMsvPartList aParts )
    {
    return DoCreateReplyOrForwardL( ETrue, aSrc, aDest, aParts );
    }

// -----------------------------------------------------------------------------
// CreateForwardL
// -----------------------------------------------------------------------------
//
TMsvId CUniSmsPlugin::CreateForwardL( TMsvId aSrc, TMsvId aDest, TMsvPartList aParts )
    {
    return DoCreateReplyOrForwardL( EFalse, aSrc, aDest, aParts );
    }
        
// -----------------------------------------------------------------------------
// SendL
// -----------------------------------------------------------------------------
//
void CUniSmsPlugin::SendL( TMsvId aId )
    {
    UNILOGGER_ENTERFN("CUniSmsPlugin::SendL");
    SmsMtmL()->SwitchCurrentEntryL( aId );
    SmsMtmL()->LoadMessageL();
    MoveMessagesToOutboxL();
    UNILOGGER_LEAVEFN("CUniSmsPlugin::SendL");
    }

// -----------------------------------------------------------------------------
// ValidateServiceL
// -----------------------------------------------------------------------------
//
TBool CUniSmsPlugin::ValidateServiceL( TBool aEmailOverSms )
    {
    TBool valid = ValidateSCNumberL();
    
    if ( aEmailOverSms )
        { 
        valid = ValidateSCNumberForEmailOverSmsL();
        }
    
    return valid;
    }
        
// -----------------------------------------------------------------------------
// GetSendingSettingsL
// -----------------------------------------------------------------------------
//
void CUniSmsPlugin::GetSendingSettingsL( TUniSendingSettings& aSettings )
    {
    // Modify only the settings this mtm plugin supports
    CSmsSettings* smsSettings = CSmsSettings::NewLC();
	iSmsHeader->GetSmsSettingsL( *smsSettings );

    switch ( smsSettings->ValidityPeriod().Int() )
        {
        case ESmsVPHour:
            aSettings.iValidityPeriod = TUniSendingSettings::EUniValidityPeriod1h;
            break;
        case ESmsVPSixHours:
            aSettings.iValidityPeriod = TUniSendingSettings::EUniValidityPeriod6h;
            break;
        case (3 * (TInt) ESmsVP24Hours):
            aSettings.iValidityPeriod = TUniSendingSettings::EUniValidityPeriod3Days;
            break;
        case ESmsVPWeek:
            aSettings.iValidityPeriod = TUniSendingSettings::EUniValidityPeriodWeek;
            break;
        case ESmsVPMaximum:
            aSettings.iValidityPeriod = TUniSendingSettings::EUniValidityPeriodMax;
            break;
        default: // default to 24h
        case ESmsVP24Hours:
            aSettings.iValidityPeriod = TUniSendingSettings::EUniValidityPeriod24h;
            break;
        }

	switch( smsSettings->MessageConversion( ) )
		{
		case ESmsConvFax:
			aSettings.iMessageType = TUniSendingSettings::EUniMessageTypeFax;
			break;
		case ESmsConvPaging:
			aSettings.iMessageType = TUniSendingSettings::EUniMessageTypePaging;
			break;
		default: // any other is text
			aSettings.iMessageType = TUniSendingSettings::EUniMessageTypeText;
			break;
		}

    aSettings.iDeliveryReport = smsSettings->DeliveryReport();
    aSettings.iReplyViaSameCentre = smsSettings->ReplyPath();
    CleanupStack::PopAndDestroy( smsSettings );
    }
    



// -----------------------------------------------------------------------------
// SetSendingSettingsL
// -----------------------------------------------------------------------------
//
void CUniSmsPlugin::SetSendingSettingsL( TUniSendingSettings& aSettings )
    {
    CSmsSettings* smsSettings = CSmsSettings::NewLC();
	iSmsHeader->GetSmsSettingsL( *smsSettings );

    TTimeIntervalMinutes validityPeriod = smsSettings->ValidityPeriod().Int();
    switch ( aSettings.iValidityPeriod )
        {
        case TUniSendingSettings::EUniValidityPeriod1h:
            validityPeriod = ( TInt ) ESmsVPHour;
            break;
        case TUniSendingSettings::EUniValidityPeriod6h:
            validityPeriod = ( TInt ) ESmsVPSixHours;
            break;
        case TUniSendingSettings::EUniValidityPeriod3Days:   
            validityPeriod = ( 3 * ( TInt ) ESmsVP24Hours );// Instead of modifying smutset.h
            break;
        case TUniSendingSettings::EUniValidityPeriodWeek:
            validityPeriod = ( TInt ) ESmsVPWeek;
            break;
        case TUniSendingSettings::EUniValidityPeriodMax:
            validityPeriod = ( TInt ) ESmsVPMaximum;
            break;
        default: // default to 24h
        case TUniSendingSettings::EUniValidityPeriod24h:
            validityPeriod = ( TInt ) ESmsVP24Hours;
            break;
        }
	switch( aSettings.iMessageType )
		{
		case TUniSendingSettings::EUniMessageTypeFax:
			smsSettings->SetMessageConversion( ESmsConvFax );
			break;
		case TUniSendingSettings::EUniMessageTypePaging:
			smsSettings->SetMessageConversion( ESmsConvPaging );
			break;
		default: // any other is text
			smsSettings->SetMessageConversion( ESmsConvPIDNone );
			break;
		}

    smsSettings->SetValidityPeriod( validityPeriod );
    smsSettings->SetDeliveryReport( aSettings.iDeliveryReport );
    smsSettings->SetReplyPath( aSettings.iReplyViaSameCentre );
    
	iSmsHeader->SetSmsSettingsL( *smsSettings );
    CleanupStack::PopAndDestroy( smsSettings );
    }

// -----------------------------------------------------------------------------
// IsServiceValidL
// -----------------------------------------------------------------------------
//
TBool CUniSmsPlugin::IsServiceValidL()
    {
    // Not implemented.
    return ETrue;
    }


// -----------------------------------------------------------------------------
// SmsMtmL
// -----------------------------------------------------------------------------
//
CSmsClientMtm* CUniSmsPlugin::SmsMtmL()
    {
    if ( !iSmsMtm )
        {        
        if ( !iMtmRegistry )
            {            
            iMtmRegistry = CClientMtmRegistry::NewL( iSession );
            }
        iSmsMtm = static_cast<CSmsClientMtm*>( iMtmRegistry->NewMtmL( KSenduiMtmSmsUid ) );
        }
    return iSmsMtm; 
    }
    
// -----------------------------------------------------------------------------
// DoCreateReplyOrForwardL
// -----------------------------------------------------------------------------
//
TMsvId CUniSmsPlugin::DoCreateReplyOrForwardL( 
    TBool aReply, 
    TMsvId aSrc, 
    TMsvId aDest, 
    TMsvPartList aParts )
    {
    SmsMtmL()->SwitchCurrentEntryL( aSrc );
    
    CMuiuOperationWait* wait = CMuiuOperationWait::NewLC();
    
    CMsvOperation* oper = aReply
        ? SmsMtmL()->ReplyL( aDest, aParts, wait->iStatus )
        : SmsMtmL()->ForwardL( aDest, aParts, wait->iStatus );
        
    CleanupStack::PushL( oper );
    wait->Start();

    TMsvId newId;
    TPckgC<TMsvId> paramPack( newId );
    const TDesC8& progress = oper->FinalProgress();
    paramPack.Set( progress );
    newId = paramPack();
    CleanupStack::PopAndDestroy( oper );
    CleanupStack::PopAndDestroy( wait );
    
    return DoConvertFromL( newId, !aReply );   
    }

// ----------------------------------------------------------------------------
// MoveMessagesToOutboxL
// ----------------------------------------------------------------------------
void CUniSmsPlugin::MoveMessagesToOutboxL()
    {
    iStoreChanged = EFalse;
    if ( !iRecipients || !iRecipients->Count() )
        {
        User::Leave( KErrGeneral );
        }

    //we must create an entry selection for message copies
    CMsvEntrySelection* selection = new ( ELeave ) CMsvEntrySelection;
    CleanupStack::PushL( selection );

    CMsvEntry& entry = SmsMtmL()->Entry();
    TMsvEntry msvEntry( entry.Entry() );
    
    if ( iOfflineSupported && MsvUiServiceUtilitiesInternal::IsPhoneOfflineL() )  
    	{
    	msvEntry.SetSendingState( KMsvSendStateSuspended );
        msvEntry.iError = KErrGsmOfflineOpNotAllowed;
    	}	
    else
    	{
    	msvEntry.SetSendingState( KMsvSendStateWaiting );
    	}	
     
    CSmsHeader& header = SmsMtmL()->SmsHeader();  
    TBuf<KSmsMessageEntryDescriptionAmountOfChars> buf;
    
    if (!iBioMsg  )
        {
        ExtractDescriptionFromMessageL( 
            header.Message(), 
            buf, 
            KSmsMessageEntryDescriptionAmountOfChars );
        msvEntry.iDescription.Set( buf );
        } 
    
    CSmsNumber* rcpt = CSmsNumber::NewL();
    CleanupStack::PushL( rcpt );

    TPtrC name;
    TPtrC address;
    TBool cantExit = ETrue; 
    while ( cantExit )
        {
        HBufC* addressBuf = NULL;
        TPtr addressPtr( 0, 0);
        
        NameAndAddress( iRecipients->MdcaPoint(0) , name, address );
        UNILOGGER_WRITEF( _L("iRecipients: %S"),   &iRecipients->MdcaPoint(0) );       
 
        // set To-field stuff into the Details of the entry
        if ( name.Length() )
            {
            msvEntry.iDetails.Set( name );
            }
        else
            {
            // Internal data structures always holds the address data in western format.
            // UI is responsible of doing language specific conversions.    
            addressBuf = HBufC::NewLC( address.Length() );
            addressPtr.Set( addressBuf->Des() );
            addressPtr.Copy( address );

            AknTextUtils::ConvertDigitsTo( addressPtr, EDigitTypeWestern );      
            msvEntry.iDetails.Set( addressPtr );
            }
        UNILOGGER_WRITEF( _L("TMsvEntry::iDetails: %S"),   &msvEntry.iDetails );
        UNILOGGER_WRITEF( _L("TMsvEntry::iDescription: %S"),  &msvEntry.iDescription ); 
        TMsvId copyId;
       
        if ( iRecipients->Count() == 1 )
            {
            //Note that we came here also in case of many recipients. ...eventually.
            
            if ( IsEmailAddress( address ) )
                {
                FillEmailInformationDataL( header, address );              
                //Let's remove the recipient and replace it with Email over SMS gateway address
                //But let's first cehck if it exists
                if( SmsMtmL( )->AddresseeList().Count() )
                	{
                    SmsMtmL( )->RemoveAddressee( 0 );	
                	}
                SmsMtmL()->AddAddresseeL( 
	            iEmailOverSmsC->Address( ) ,
		        KNullDesC( ) );
                iStoreChanged = ETrue;
                }
            else
                {                           
                InsertSubjectL( header, SmsMtmL()->Body() );                                 
                }

            entry.ChangeL( msvEntry );
            if( iStoreChanged )
                {
            	SmsMtmL()->SaveMessageL();
                }
            // Move it
            copyId = MoveMessageEntryL( KMsvGlobalOutBoxIndexEntryId );
            cantExit = EFalse;
            }
        else 
            {// Many recipients in array
            
            // Own copy function for Emails
            // This is because EmailOverSms messages can 
            // contain adresses longer than 21 digits
            if ( IsEmailAddress( address ) )
                {
                copyId = CreateMessageInOutboxL(
                msvEntry, address );

                }
            else // For MSISDN's
                {
                rcpt->SetAddressL( address );
                if ( name.Length() )
                    { // add name only if we have alias
                    rcpt->SetNameL( name );
                    }
                
                copyId = CreateMessageInOutboxL(
                    msvEntry, *rcpt, SmsMtmL()->Body());
 
                SmsMtmL()->RemoveAddressee( 0 );
                iStoreChanged = ETrue;
                }
            //If hundreds of recipient, make sure viewserver
            //timers are reseted
            if ( iRecipients->Count() > 100 && ( iRecipients->Count() ) % 30 == 0 )
                {
                User::ResetInactivityTime();
                }
                
            iRecipients->Delete(0);   
            }
        if ( addressBuf )
            {
            CleanupStack::PopAndDestroy( addressBuf );
            }
        
        // let's add the entry id into the cmsventryselection
        selection->AppendL( copyId );
        }
    CleanupStack::PopAndDestroy( rcpt );    

#ifdef USE_LOGGER 
    for ( TInt i=0; i<selection->Count(); i++ ) 
        {
        SmsMtmL()->SwitchCurrentEntryL( selection->At(i) );
        SmsMtmL()->LoadMessageL();
        const CMsvRecipientList& testRecipients = SmsMtmL()->AddresseeList(); 
        UNILOGGER_WRITEF( _L("Recipient: %S"), &(testRecipients[ 0 ]) ); 
        UNILOGGER_WRITEF( _L("Body: %S"), &(SmsMtmL()->Body().Read( 0,80 )  ));   
        UNILOGGER_WRITEF( _L("EmailOverSMS address: %S"), &iEmailOverSmsC->Address( ) );
    	UNILOGGER_WRITEF( _L("EmailOverSMS name : %S"),   &iEmailOverSmsC->Name( ) );
     
        CSmsHeader& testHeader = SmsMtmL()->SmsHeader();
        const CSmsEmailFields& testEmailFields = testHeader.EmailFields();
        
        if ( testEmailFields.Addresses().MdcaCount() )
            {
        	UNILOGGER_WRITEF( _L("CSmsEmailFields::iAddresses: %S"), &(testEmailFields.Addresses().MdcaPoint(0) ));
            }
        else
            {
            UNILOGGER_WRITEF(_L("CSmsEmailFields::iAddresses is empty"));	
            }    
        
        
        UNILOGGER_WRITEF( _L("CSmsEmailFields::iSubject : %S"),   &testEmailFields.Subject() );
        
        }  
#endif    
    
    //Let's free some memory
    if ( iRecipients )
        { 
        delete iRecipients;	
        iRecipients = NULL; 
        }
    
    SetScheduledSendingStateL( selection );
    CleanupStack::PopAndDestroy( selection ); 
    }


// ----------------------------------------------------------------------------
// MoveMessageEntryL
// ----------------------------------------------------------------------------
TMsvId CUniSmsPlugin::MoveMessageEntryL( TMsvId aTarget )
    {
    TMsvEntry msvEntry( SmsMtmL()->Entry().Entry() );
    TMsvId id = msvEntry.Id();
    
    if ( msvEntry.Parent() != aTarget )
        {
        TMsvSelectionOrdering sort;
        sort.SetShowInvisibleEntries( ETrue );
        CMsvEntry* parentEntry= CMsvEntry::NewL( iSession, msvEntry.Parent(), sort );
        CleanupStack::PushL( parentEntry );
        
        // Copy original from the parent to the new location
        CMuiuOperationWait* wait = CMuiuOperationWait::NewLC();

        CMsvOperation* op = parentEntry->MoveL(
            msvEntry.Id(), 
            aTarget, 
            wait->iStatus );
        
        CleanupStack::PushL( op );
        wait->Start();
        TMsvLocalOperationProgress prog = McliUtils::GetLocalProgressL( *op );
        User::LeaveIfError( prog.iError );

        id = prog.iId;
        
        CleanupStack::PopAndDestroy( op );
        CleanupStack::PopAndDestroy( wait );
        CleanupStack::PopAndDestroy( parentEntry );
        }
    
    return id;
    }

// ----------------------------------------------------------------------------
// CreateMessageInOutboxL
// Use this function for non-email messages
// ----------------------------------------------------------------------------
TMsvId CUniSmsPlugin::CreateMessageInOutboxL(
    const TMsvEntry& aEntry, 
    const CSmsNumber& aRecipient, 
    const CRichText& aBody )
    {
    // Initialize the richtext object
    CRichText* richText = CRichText::NewL( iParaFormatLayer, iCharFormatLayer );
    CleanupStack::PushL( richText );
    
    // Initialise header and store
    CSmsHeader* header = CSmsHeader::NewL( CSmsPDU::ESmsSubmit, *richText );
    CleanupStack::PushL( header );
    CMsvStore* sourceStore = SmsMtmL()->Entry().ReadStoreL();
    CleanupStack::PushL( sourceStore );
    
    // Read store
    header->RestoreL( *sourceStore );

    // Initialise number with parameters
    CSmsNumber* rcpt = CSmsNumber::NewL( aRecipient );
    CleanupStack::PushL( rcpt );
    header->Recipients().ResetAndDestroy();
    header->Recipients().AppendL( rcpt );
    CleanupStack::Pop( rcpt );  
    
    // Create entry to Outbox
    TMsvEntry entry( aEntry );
    entry.iMtmData3 = KSmsPluginBioMsgUnparsed;
    CMsvEntry* outbox = iSession.GetEntryL( KMsvGlobalOutBoxIndexEntryId );
    CleanupStack::PushL( outbox );
    outbox->CreateL( entry );
    iSession.CleanupEntryPushL( entry.Id() );
    outbox->SetEntryL( entry.Id());
    
    //Initialize target store
    CMsvStore* targetStore;
    targetStore = outbox->EditStoreL();
    CleanupStack::PushL( targetStore );
    
    //Add attachment  
    MMsvAttachmentManager& attaManager = sourceStore->AttachmentManagerL(); 
    RFile tmpFile;
     
    //Check if attachment exists and add it  
    if( sourceStore->AttachmentManagerL().AttachmentCount() )
    	{       	    		    		
        tmpFile = attaManager.GetAttachmentFileL( 0 );      
    	CleanupClosePushL( tmpFile );  
    		
    	MMsvAttachmentManager& targetAttaMan = targetStore->AttachmentManagerL();
		CMsvAttachment* targetAtta = CMsvAttachment::NewL( CMsvAttachment::EMsvFile );
		CleanupStack::PushL( targetAtta );

        CMuiuOperationWait* waiter = CMuiuOperationWait::NewLC(); 
		targetAttaMan.AddAttachmentL( tmpFile, targetAtta, waiter->iStatus );			
		waiter->Start();

     	CleanupStack::PopAndDestroy( waiter ); //waiter 
		CleanupStack::Pop(targetAtta );// targetAtta
		CleanupStack::Pop( &tmpFile );//tmpFile
    	}
    
    TInt totalLength( aBody.DocumentLength() );
    HBufC* bodyText = HBufC::NewLC ( totalLength ); 
    TPtr bodyTextPtr ( bodyText->Des() ); 
    
    aBody.Extract( bodyTextPtr, 0, totalLength );
    richText->InsertL( 0, bodyTextPtr );
    CleanupStack::PopAndDestroy( bodyText );

    InsertSubjectL( *header, *richText );
                
    targetStore->StoreBodyTextL( *richText );
    
    header->StoreL( *targetStore );
    targetStore->CommitL();
       
    // Usually SMCM takes care of updating iSize, but now when msg is
    // created to Outbox for several recipients this has to be done manually.
    entry.iSize = targetStore->SizeL();
    entry.iRelatedId = iSmsServiceId;
    entry.iServiceId = KMsvLocalServiceIndexEntryId;
    outbox->ChangeL( entry );
    CleanupStack::PopAndDestroy( targetStore );
    
    iSession.CleanupEntryPop();
    CleanupStack::PopAndDestroy( outbox ); 
    CleanupStack::PopAndDestroy( sourceStore );
    CleanupStack::PopAndDestroy( header );
    CleanupStack::PopAndDestroy( richText );
    return entry.Id();
    }

// ---------------------------------------------------------
// CMsgSmsEditorAppUi::CreateMessageInOutboxL
// Creates message in outbox in case of multiple recipients 
// with some e-mail over SMS addresses
// ---------------------------------------------------------
TMsvId CUniSmsPlugin::CreateMessageInOutboxL(
    const TMsvEntry& aEntry, 
    const TDesC& aAddress )
    {
    CRichText* richText = CRichText::NewL( iParaFormatLayer, iCharFormatLayer );
    CleanupStack::PushL( richText );
    // Initialise header and store
    CSmsHeader* header = CSmsHeader::NewL( CSmsPDU::ESmsSubmit, *richText );
    CleanupStack::PushL( header );
    CMsvStore* store = SmsMtmL()->Entry().ReadStoreL();
     
    CleanupStack::PushL( store );
    // Read store
    header->RestoreL( *store );
    CleanupStack::PopAndDestroy( store );
    // Initialise number
    CSmsNumber* rcpt = CSmsNumber::NewL();
    CleanupStack::PushL( rcpt );
    header->Recipients().ResetAndDestroy();
    // Save Email specific information in header
    FillEmailInformationDataL( *header, aAddress );
    // Fill the recipient data for Email
    // Address = Email gateway
    // Alias = The real address
    rcpt->SetAddressL( iEmailOverSmsC->Address()  );
    rcpt->SetNameL( aAddress ); // This takes only 21 chars

    header->Recipients().AppendL( rcpt );
    CleanupStack::Pop( rcpt );
    // Create entry to Outbox
    TMsvEntry entry( aEntry );
    entry.iMtmData3 = KSmsPluginBioMsgUnparsed;
     
    CMsvEntry* outbox = iSession.GetEntryL( KMsvGlobalOutBoxIndexEntryId );
    CleanupStack::PushL( outbox );
    outbox->CreateL( entry );
    iSession.CleanupEntryPushL( entry.Id());
    outbox->SetEntryL( entry.Id());
    // Save 
    store = outbox->EditStoreL();
    CleanupStack::PushL( store );
    header->StoreL( *store );
    
    richText->Reset();
    richText->InsertL( 0 , SmsMtmL()->Body().Read( 0 ) );
    
    store->StoreBodyTextL( *richText );
    store->CommitL();
    // Usually SMCM takes care of updating iSize, but now when msg is
    // created to Outbox for several recipients this has to be done manually.
    entry.iSize = store->SizeL();
    entry.iRelatedId = iSmsServiceId;
    entry.iServiceId = KMsvLocalServiceIndexEntryId;
    outbox->ChangeL( entry );
    
    CleanupStack::PopAndDestroy( store );
    iSession.CleanupEntryPop();
    CleanupStack::PopAndDestroy( outbox );
    CleanupStack::PopAndDestroy( header );
    CleanupStack::PopAndDestroy( richText );
    return entry.Id();
    }

// ----------------------------------------------------------------------------
// SetScheduledSendingStateL
// ----------------------------------------------------------------------------
void CUniSmsPlugin::SetScheduledSendingStateL( CMsvEntrySelection* aSelection )
    {
    const TMsvEntry msvEntry = SmsMtmL()->Entry().Entry();
    if ( msvEntry.SendingState() == KMsvSendStateWaiting )
        {
        // Add entry to task scheduler
        TBuf8<1> dummyParams;

        CMuiuOperationWait* waiter = CMuiuOperationWait::NewLC();
        waiter->iStatus = KRequestPending;

        CMsvOperation* op= SmsMtmL()->InvokeAsyncFunctionL(
            ESmsMtmCommandScheduleCopy,
            *aSelection,
            dummyParams,
            waiter->iStatus );
        CleanupStack::PushL( op );
        waiter->Start();
        
        CleanupStack::PopAndDestroy( op );  
        CleanupStack::PopAndDestroy( waiter );
        } 
    }

// ----------------------------------------------------------------------------
// NameAndAddress
// ----------------------------------------------------------------------------
void CUniSmsPlugin::NameAndAddress( const TDesC& aMsvAddress, TPtrC& aName, TPtrC& aAddress )
    {
    TInt addressStart = aMsvAddress.LocateReverse( KMsgSmsAddressStartChar );
    TInt addressEnd = aMsvAddress.LocateReverse( KMsgSmsAddressEndChar );

    if ( addressStart != KErrNotFound && addressEnd != KErrNotFound 
        && addressEnd > addressStart )
        {
        // verified address, will be used as selected from contacts manager
        aName.Set( aMsvAddress.Ptr(), addressStart );
        aAddress.Set( 
            aMsvAddress.Mid( addressStart + 1 ).Ptr(), 
            ( addressEnd - addressStart ) -1 );
        if ( !aAddress.Length())
            {
            aAddress.Set( aName );
            aName.Set( KNullDesC ); // empty string
            }
        }
    else
        {
        // unverified string, will be used as entered in the header field
        aName.Set( KNullDesC ); // empty string
        aAddress.Set( aMsvAddress.Ptr(), aMsvAddress.Length() ); // a whole string to address
        }
    
    if ( aName.CompareF( aAddress ) == 0 )
        {
        aName.Set( KNullDesC ); // empty string
        }
    }

// ----------------------------------------------------------------------------
// CUniSmsPlugin::ExtractDescriptionFromMessageL
// ----------------------------------------------------------------------------
void CUniSmsPlugin::ExtractDescriptionFromMessageL(
    const CSmsMessage& aMessage, 
    TDes& aDescription, 
    TInt aMaxLength)
    {  
    if ( iUniMtm.SubjectL().Length() )
        {
        aDescription.Copy( iUniMtm.SubjectL() );
        }
    else
        {// Extract from message body
        aMessage.Buffer().Extract(
            aDescription, 
            0, 
            Min( 
                aMaxLength, 
                aMessage.Buffer().Length()));
        }

    //replace paragraphs with spaces.
    TBuf<KSmsEdExtrDescReplaceCharacterCount> replaceChars;
    replaceChars.Zero();
    replaceChars.Append( CEditableText::EParagraphDelimiter );
    replaceChars.Append( KSmsEdUnicodeLFSupportedByBasicPhones );
    replaceChars.Append( CEditableText::ELineBreak );
    AknTextUtils::ReplaceCharacters(
        aDescription, 
        replaceChars, 
        CEditableText::ESpace );

    aDescription.Trim();
    }

// ----------------------------------------------------------------------------
// CreatePlainTextSMSL 
// ----------------------------------------------------------------------------
void CUniSmsPlugin::CreatePlainTextSMSL( RFile& aFile)
    {       
    RFileReadStream stream( aFile );
    CleanupClosePushL( stream );
          
    CPlainText::TImportExportParam param;
    param.iForeignEncoding = KCharacterSetIdentifierUtf8;
    param.iOrganisation = CPlainText::EOrganiseByParagraph; 
            
    CPlainText::TImportExportResult result;
    
    SmsMtmL()->Body().ImportTextL( 0, stream, param, result );
                    
    CleanupStack::PopAndDestroy( &stream );        
    }
    
// ----------------------------------------------------------------------------
// InsertSubjectL
// Insert subject for non email addresses into the body
// ----------------------------------------------------------------------------
void CUniSmsPlugin::InsertSubjectL( CSmsHeader& aHeader, CRichText& aText  ) 
    {
    if ( iUniMtm.SubjectL().Length() && !iBioMsg )
        {
        TPtrC subject = iUniMtm.SubjectL();
        TInt writePosition = subject.Length()+2;//+2 for the parentesis
    
        if ( subject.Locate( KUniSmsStartParenthesis )!= KErrNotFound ||
            subject.Locate( KUniSmsEndParenthesis ) != KErrNotFound)
            {
            HBufC* modifiableSubject = subject.Alloc();
            CleanupStack::PushL(modifiableSubject);
            TPtr ptr = modifiableSubject->Des();
            
            TBuf<1> replaceChars;
            replaceChars.Zero();
            replaceChars.Append( KUniSmsStartParenthesis );
            // Replace '(' chars with '<'
            AknTextUtils::ReplaceCharacters(
                ptr, 
                replaceChars, 
                TChar('<') );
            
            replaceChars.Zero();
            replaceChars.Append( KUniSmsEndParenthesis );    
        
            // Replace ')' chars with '>'
            AknTextUtils::ReplaceCharacters(
                ptr, 
                replaceChars, 
                TChar('>') );  
            
            aText.InsertL( 0, KUniSmsStartParenthesis );
            aText.InsertL( 1, ptr );
            aText.InsertL( writePosition-1, KUniSmsEndParenthesis );
            CleanupStack::PopAndDestroy( modifiableSubject );
            }
 
        else
            {
            aText.InsertL( 0, KUniSmsStartParenthesis );
            aText.InsertL( 1, subject );
            aText.InsertL( writePosition-1, KUniSmsEndParenthesis );
            }
        iStoreChanged = ETrue;
        }
    
    // Clears the CSmsHeaders EmailFields for non Email addresses
    CSmsEmailFields* emailFields = CSmsEmailFields::NewL();
    CleanupStack::PushL( emailFields );
    aHeader.SetEmailFieldsL( *emailFields );
    CleanupStack::PopAndDestroy( emailFields );  
        iStoreChanged = ETrue;
    }
           
// ----------------------------------------------------------------------------
// CreateVCardSMS
// ----------------------------------------------------------------------------
void CUniSmsPlugin::CreateVCardSMSL( RFile& aFile )
    {   
    TInt fileSize;
    TInt err ( aFile.Size( fileSize ) );
    User::LeaveIfError(err);
    
    // Create two buffers: 8-bit for reading from file and 16-bit for
    // converting to 16-bit format
    HBufC8* buf8 = HBufC8::NewLC( fileSize );
    TPtr8 ptr8 = buf8->Des();
    HBufC16* buf16 = HBufC16::NewLC( fileSize );
    TPtr16 ptr16 = buf16->Des();

    for (TInt err = aFile.Read(ptr8); 
        ptr8.Length() > 0; 
        err = aFile.Read(ptr8))
        {
        User::LeaveIfError(err);
        ptr16.Copy(ptr8);
        SmsMtmL()->Body().InsertL(SmsMtmL()->Body().DocumentLength(), ptr16);
        }

    // Cleanup and return
    CleanupStack::PopAndDestroy( buf16 );   
    CleanupStack::PopAndDestroy( buf8 );   
    }
        
// ----------------------------------------------------------------------------
// CreateVCalSMS
// ----------------------------------------------------------------------------
void CUniSmsPlugin::CreateVCalSMSL( RFile& aFile )
    {
    TInt err (KErrNone);
    TInt fileSize;
    err = aFile.Size( fileSize );
    User::LeaveIfError(err);
     
    HBufC8* buf8 = HBufC8::NewLC( fileSize );
    TPtr8 ptr8 = buf8->Des();
    
    err = aFile.Read( ptr8 );
    User::LeaveIfError(err);
    
    HBufC16* buf16 = HBufC16::NewLC( fileSize );
    TPtr16 ptr16 = buf16->Des();
   
    ptr16.Copy(ptr8);
    SmsMtmL()->Body().InsertL(0, ptr16);
    
    CleanupStack::PopAndDestroy( buf16 );
    CleanupStack::PopAndDestroy( buf8 );
    }

// ----------------------------------------------------------------------------
// CUniSmsPlugin::ValidateSCNumberL
// ----------------------------------------------------------------------------
TBool CUniSmsPlugin::ValidateSCNumberL()
    {
    TBool valid( ETrue );
    if ( iSmsHeader->Message().ServiceCenterAddress().Length() == 0 ||
         !iSmsHeader->ReplyPathProvided() )
        {
        if ( !SmsMtmL()->ServiceSettings().ServiceCenterCount() )
            {
            if ( !SmsScDialogL())
                {
                valid = EFalse;
                }
            else
                {
                valid = ETrue;    
                CSmsServiceCenter& sc = SmsMtmL()->ServiceSettings().GetServiceCenter( 0 );

			    // Update service settings' sc address list and set it to default.
	            SmsMtmL()->ServiceSettings().SetDefaultServiceCenter( 0 ); 
	                
	            CSmsAccount* smsAccount = CSmsAccount::NewLC();
	            smsAccount->SaveSettingsL( SmsMtmL()->ServiceSettings() );
	            CleanupStack::PopAndDestroy( smsAccount );  
	
			    // Set the SC addres for this message
                iSmsHeader->Message().SetServiceCenterAddressL( 
                	sc.Address() );
                }
            }
        else
            {
            //Else use the default - or then the first one on the sc address list.
            TInt index = Max( 0, SmsMtmL()->ServiceSettings().DefaultServiceCenter() );
            CSmsServiceCenter& sc = SmsMtmL()->ServiceSettings().GetServiceCenter( index );
            iSmsHeader->Message().SetServiceCenterAddressL( sc.Address() );
            }
        }
    return valid;
    }

// ---------------------------------------------------------
// CUniSmsPlugin::ValidateSCNumberForEmailOverSmsL
// ---------------------------------------------------------
TBool CUniSmsPlugin::ValidateSCNumberForEmailOverSmsL()
    {
    TBool confNeeded( EFalse );
    // Read the email settings
    TBuf<KUniSmsSCStringLength> emailSmscNumber;
    TBuf<KUniSmsSCStringLength> emailGateWayNumber;
    TBool notUsed( EFalse );
    // The file may not exist
    TInt readResult = SmumUtil::ReadEmailOverSmsSettingsL( 
                        emailSmscNumber,
                        emailGateWayNumber,
                        notUsed );
    if ( KErrNone == readResult )
        {
        // Check that both have valid values
        // In any otther case we need to show the conf pop-up window
        if ( emailSmscNumber == KNullDesC )
            {
            // Use the sms smsc as default
            CSmsSettings* serviceSettings = &( SmsMtmL()->ServiceSettings() );
            
            if ( SmsMtmL()->ServiceSettings().DefaultServiceCenter() > 0 )
                {
                emailSmscNumber = 
                	serviceSettings->GetServiceCenter( 
                	    SmsMtmL()->ServiceSettings().DefaultServiceCenter() ).Address();
                }
            else
                {
                emailSmscNumber = 
                	serviceSettings->GetServiceCenter( 0 ).Address();
                }
            confNeeded = ETrue;
            }
        if ( emailGateWayNumber == KNullDesC )
            {
            confNeeded = ETrue;
            }
        }
    else
        {
        confNeeded = ETrue;
        }
    if ( confNeeded ) // Show the query
        {
        CUniSmsEMultilineQueryDialog* dlg = 
            CUniSmsEMultilineQueryDialog::NewL( 
                emailGateWayNumber, 
                emailSmscNumber, 
                ETrue );
        if ( dlg->ExecuteLD( R_ADDEMAILSC_QUERY ) )
            {
            // Save settings to Smum
            SmumUtil::WriteEmailOverSmsSettingsL( 
                        emailSmscNumber,        
                        emailGateWayNumber,
                        ETrue );
            }
        else
            {
            return EFalse;
            }
        }
    // Use them
    iEmailOverSmsC->SetNameL( emailSmscNumber );
	iEmailOverSmsC->SetAddressL( emailGateWayNumber );
	return ETrue;
    }

// ----------------------------------------------------------------------------
// CUniSmsPlugin::SmsScDialogL
// ----------------------------------------------------------------------------
TBool CUniSmsPlugin::SmsScDialogL()
    {
    TBuf<KUniSmsSCStringLength> name;
    TBuf<KUniSmsSCStringLength> number;
    TBool retVal = EFalse;
     
    // Read the default name
    SmumUtil::FindDefaultNameForSCL( name, EFalse );
    CUniSmsEMultilineQueryDialog* dlg = 
        CUniSmsEMultilineQueryDialog::NewL( name, number );
    if ( dlg->ExecuteLD( R_ADDSC_QUERY ) )
        {	
        retVal = ETrue;
        if ( !name.Length())
            {
            // read default name again 
            SmumUtil::FindDefaultNameForSCL( name, EFalse );
            }        
        SmsMtmL()->ServiceSettings().AddServiceCenterL( name, number );
        }
    return retVal;
    }

// ---------------------------------------------------------
// CUniSmsPlugin::FillEmailInformationDataL
// ---------------------------------------------------------
void CUniSmsPlugin::FillEmailInformationDataL( 
    CSmsHeader& aHeader, 
    const TPtrC& aAddress ) 
    {
    UNILOGGER_ENTERFN( "CUniSmsPlugin::FillEmailInformationDataL()" )
 
    CSmsEmailFields* emailFields = CSmsEmailFields::NewL();
    CleanupStack::PushL( emailFields );

    // The Email SMSC may differ from sms SMSC
    UNILOGGER_WRITEF( _L("Set EMailOverSMS SC: %S"), &iEmailOverSmsC->Name() );
    aHeader.Message().SetServiceCenterAddressL( iEmailOverSmsC->Name() );
        
    // Check if there is need to save as EmailFieds with header
    if ( aAddress.Length() ) 
        {
        // Set the address
        UNILOGGER_WRITEF( _L("Recipient: %S"), &aAddress );
        emailFields->AddAddressL( aAddress );
        }
           
    if ( iUniMtm.SubjectL().Length() )
        { // Handle the subject
        HBufC* buf = iUniMtm.SubjectL().AllocL();
        CleanupStack::PushL( buf );
        TPtr text = buf->Des();    
           
        TBuf<1> replaceChars;
        replaceChars.Zero();
        replaceChars.Append( KUniSmsStartParenthesis );
        // Replace '(' chars with '<'
        AknTextUtils::ReplaceCharacters(
            text, 
            replaceChars, 
            TChar('<') );
            
        replaceChars.Zero();
        replaceChars.Append( KUniSmsEndParenthesis );
        // Replace ')' chars with '>'
        AknTextUtils::ReplaceCharacters(
            text, 
            replaceChars, 
            TChar('>') );
            
        // For Emails save it to CSmsEmailFields
        emailFields->SetSubjectL( text );
        CleanupStack::PopAndDestroy( buf ); 
        }  
     
        
    aHeader.SetEmailFieldsL( *emailFields );
    CleanupStack::PopAndDestroy( emailFields ); 
    UNILOGGER_LEAVEFN( "CUniSmsPlugin::FillEmailInformationDataL()" )
    } 



// ----------------------------------------------------
//  CUniSmsPlugin::IsEmailAddress()
// ----------------------------------------------------
TBool CUniSmsPlugin::IsEmailAddress( const TPtrC& aAddress ) const
    {
    UNILOGGER_ENTERFN( "CMsgSmsEmailOverSmsFunc::IsEmailAddress()" )
    TBool isEmailAddress( EFalse );
    if (  aAddress.Locate('@')  != KErrNotFound)
        {
        UNILOGGER_WRITEF(
            _L("IsEmailAddress - Address: %s"), aAddress.Ptr() );
        isEmailAddress = ETrue;
        }
    UNILOGGER_LEAVEFN( "CMsgSmsEmailOverSmsFunc::IsEmailAddress()" )
    return isEmailAddress;
    }
    
// ----------------------------------------------------------------------------
// Panic
// ----------------------------------------------------------------------------
GLDEF_C void Panic( TInt aCategory )
    {
    _LIT( KUniSmsPluginPanic, "CUniSmsPlugin-Panic" );
    User::Panic( KUniSmsPluginPanic, aCategory );
    }

// ========================== OTHER EXPORTED FUNCTIONS =========================

// ------------------------------------------------------------------------------------------------
// ImplementationProxy
// -----------------------------------------------------------------------------
//
EXPORT_C const TImplementationProxy* ImplementationGroupProxy( TInt& aTableCount )
	{
	aTableCount = sizeof( KImplementationTable ) / sizeof( TImplementationProxy );
	return KImplementationTable;
	}

//------------------------------------------------------------------------------
// CUniSmsPlugin::SetEncodingSetings
// Turkish SMS-PREQ2265 Specific
// To Set encoding settings like encoding type, character support
// and alternative encoding if any
// 
// IMPORTANT NOTE: 
// This function is usually called from UniEditorAppUI to reset/set alternative encoding or char support
// when corresponding feilds change. Hence aUnicodeMode is always set to false
//------------------------------------------------------------------------------
void CUniSmsPlugin::SetEncodingSettings( TBool aUnicodeMode, TSmsEncoding aAlternativeEncodingType, TInt aCharSupportType)
    {
    UNILOGGER_WRITE_TIMESTAMP("CUniSmsPlugin::SetEncodingSettings Start <<<---- ");
    TSmsUserDataSettings smsSettings;
    CSmsMessage& smsMsg = iSmsHeader->Message();
    TBool settingsChanged = EFalse;
    
    iCharSupportType = aCharSupportType;
    iAlternativeEncodingType = aAlternativeEncodingType;
    if( iUnicodeMode != aUnicodeMode )
        {
        iUnicodeMode = aUnicodeMode;
    if(iUnicodeMode)
        {
        smsSettings.SetAlphabet( TSmsDataCodingScheme::ESmsAlphabetUCS2 );
        }
    else
        {
        smsSettings.SetAlphabet( TSmsDataCodingScheme::ESmsAlphabet7Bit );
        }
        settingsChanged = ETrue;
        }
    if( smsSettings.TextCompressed())
        {
    smsSettings.SetTextCompressed( EFalse );
        settingsChanged = ETrue;
        }
    if( settingsChanged )
        {
    TRAP_IGNORE(smsMsg.SetUserDataSettingsL( smsSettings ));
#ifdef USE_LOGGER
        UNILOGGER_WRITE("SetEncodingSettings: SetUserDataSettingsL");
#endif /* USE_LOGGER */
        }
    //First try without any alternate encoding
    if( aAlternativeEncodingType != smsMsg.Alternative7bitEncoding() )
        {
        smsMsg.SetAlternative7bitEncoding( aAlternativeEncodingType );// Optimal
#ifdef USE_LOGGER
        UNILOGGER_WRITEF(_L("SetEncodingSettings: aAlternativeEncodingType-> %d"), aAlternativeEncodingType);
#endif /* USE_LOGGER */
    }
    UNILOGGER_WRITE_TIMESTAMP("CUniSmsPlugin::SetEncodingSettings End ---->>> ");
    }
//------------------------------------------------------------------------------
// CUniSmsPlugin::GetNumPDUsL
// Turkish SMS-PREQ2265 Specific
// To get PDU Info: extracts details of number of PDUs, number of remaining chars in last PDU
// and encoding types used.
//------------------------------------------------------------------------------
void CUniSmsPlugin::GetNumPDUsL( 
        TDesC& aBuf,
        TInt& aNumOfRemainingChars,
        TInt& aNumOfPDUs,
        TBool& aUnicodeMode, 
        TSmsEncoding & aAlternativeEncodingType )
    {
    UNILOGGER_WRITE_TIMESTAMP("<<<<<<<<---------------------CUniSmsPlugin::GetNumPDUsL Start: ");
    TInt numOfUnconvChars, numOfDowngradedChars, isAltEncSupported;
    TSmsEncoding currentAlternativeEncodingType;

    CSmsMessage& smsMsg = iSmsHeader->Message();
    
#ifdef USE_LOGGER
    HBufC* tempBuff = HBufC::NewL( aBuf.Length() + 2 );
    tempBuff->Des().Copy( aBuf );
    UNILOGGER_WRITEF(_L("GetNumPDUsL:->> Buf Length: %d"), aBuf.Length() );
    UNILOGGER_WRITEF(_L("GetNumPDUsL:->> buffer    : %s"), tempBuff->Des().PtrZ() );
    delete tempBuff;
#endif /* USE_LOGGER */
    // need to set the input buffer to SMS buffer through iRichText(which is reference to SMS Buffer object)
    iRichText->Reset();
    iRichText->InsertL(0, aBuf);
    
    //call SMS stack API to get PDU info
    smsMsg.GetEncodingInfoL( aNumOfPDUs, numOfUnconvChars, numOfDowngradedChars, aNumOfRemainingChars );
    
#ifdef USE_LOGGER
    UNILOGGER_WRITE(" ---Get Encoding Info details:--- ");
    UNILOGGER_WRITEF(_L("      aNumPdus     : %d"), aNumOfPDUs);
    UNILOGGER_WRITEF(_L("      numOfUnconvChars : %d"), numOfUnconvChars);
    UNILOGGER_WRITEF(_L("      numOfDowngradedChars: %d"), numOfDowngradedChars);
    UNILOGGER_WRITEF(_L("      aNumOfRemainingChars: %d"), aNumOfRemainingChars);
#endif /* USE_LOGGER */
    //Algo to switch to Unicode if required
    while( (numOfUnconvChars || numOfDowngradedChars) && !iUnicodeMode )
        {
        currentAlternativeEncodingType = smsMsg.Alternative7bitEncoding();
#ifdef USE_LOGGER
        UNILOGGER_WRITEF(_L("GetNumPDUsL: currAltEnc -> %d"), currentAlternativeEncodingType);
#endif /* USE_LOGGER */
        if( currentAlternativeEncodingType != iAlternativeEncodingType )
            {
            //try with this new alternative encoding type
            isAltEncSupported = smsMsg.SetAlternative7bitEncoding( iAlternativeEncodingType );
            if( isAltEncSupported == KErrNotSupported )
                {
                // if required alternative encoding plugin is not supported, retain the existing encoding mechanism.
                iAlternativeEncodingType = currentAlternativeEncodingType;
                continue;
                }
            }
        else if( numOfUnconvChars || (TUniSendingSettings::TUniCharSupport)iCharSupportType == TUniSendingSettings::EUniCharSupportFull)
            {
            //switch to Unicode
            //iUnicodeMode = ETrue;
            SetEncodingSettings( ETrue, /*ESmsEncodingNone*/ iAlternativeEncodingType, iCharSupportType);
            }
        else
            {
            //Get out of while loop and return the results
            break;
            }
        //get the PDU info with new settings
        iRichText->Reset();
        iRichText->InsertL(0, aBuf);
        smsMsg.GetEncodingInfoL( aNumOfPDUs, numOfUnconvChars, numOfDowngradedChars, aNumOfRemainingChars );
#ifdef USE_LOGGER
        UNILOGGER_WRITE("******* Get Encoding Info details (Again):***** ");
        UNILOGGER_WRITEF(_L("     aNumPdus     : %d"), aNumOfPDUs);
        UNILOGGER_WRITEF(_L("     numOfUnconvChars : %d"), numOfUnconvChars);
        UNILOGGER_WRITEF(_L("     numOfDowngradedChars: %d"), numOfDowngradedChars);
        UNILOGGER_WRITEF(_L("     aNumOfRemainingChars: %d"), aNumOfRemainingChars);
#endif /* USE_LOGGER */
        }

    /*
     * Enable the below code to debug if something wrong with characters sent even in unicode mode
     */
    /*
    If((numOfUnconvChars || numOfDowngradedChars) && iUnicodeMode)
        UNILOGGER_WRITEF("GOTCHA... some chars are not convertable in unicode mode as well...????");
    */
    aUnicodeMode = iUnicodeMode;
    aAlternativeEncodingType = iAlternativeEncodingType;
    if(iUnicodeMode)
        {
        //In case of Unicode mode, SMS Stack returns number of available free User Data units.
        //Need to convert them w.r.t characters(each char takse 2 UD units).
        aNumOfRemainingChars = aNumOfRemainingChars/2;
        }
    UNILOGGER_WRITE_TIMESTAMP("CUniSmsPlugin::GetNumPDUsL End -------------------->>>>>>>>>>> ");
    }

//  End of File