/*
* Copyright (c) 2002-2006 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:   Can be used to show "Send" list query and to create and send
*                messages via available sending services. Created messages are
*                sent directly or message editor is opened for editing,
*                depending on the type of the selected service.
*
*/


#include <coemain.h>
#include <Sendnorm.rsg>
#include <aknlistquerydialog.h>
#include <eikmenup.h>
#include <data_caging_path_literals.hrh>
#include <DRMHelper.h>
#include <centralrepository.h>
#include <e32cmn.h> // Uid
#include <e32property.h>
#include <barsread.h>
#include <akninputblock.h>
#include <centralrepository.h>
#include <miutset.h>
#include <MessagingDomainCRKeys.h>
#include <mtclreg.h>
#include <mtudreg.h>

// Features
#include <featmgr.h>    
#include <bldvariant.hrh>
#include <MsgMimeTypes.h>
#include <CSendingServiceInfo.h>
#include <CSendingService.h>
#include <CMessageData.h>
#include <SendUiConsts.h>
#include <senduisingleton.h>

#include "SendUiImpl.h"
#include "senduiserviceclient.h"
#include "SendUiCapabilityCheck.h"
#include "SendUiUtils.h"
#include "senduiserviceslog.h"              // Logging
#include "SendUiPrivateCRKeys.h"
#include "senduiproperty.h"
#include "propertyobserver.h"
#include "senduilauncher.h"
#include "SendUiInternalConsts.h"


const TInt KArrayGranularity = 2;
const TInt KSendUiServiceOrderArrayGranularity = 6;
const TInt KTitleBufLength = 64;
//Mail Tech Uid
const TUid KMailTechnologyTypeUid = { 0x10001671 };
//CMail Tech Uid
#define KUidMsgTypeFsMtmVal     0x2001F406


_LIT( KSendUiResourceFileName,"sendnorm.rsc" );

// ======== MEMBER FUNCTIONS ========
// -----------------------------------------------------------------------------
// CSendUiImpl::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CSendUiImpl* CSendUiImpl::NewL()
    {
    CSendUiImpl* self = new( ELeave ) CSendUiImpl;
    
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );

    return self;
    }

// -----------------------------------------------------------------------------
// Destructor
// -----------------------------------------------------------------------------
//
CSendUiImpl::~CSendUiImpl()
    {
    iResourceLoader.Close();
    TInt count = iSendingServices.Count();
    while ( count )
        {
        delete iSendingServices[--count];
        }
    iSendingServices.Close();
    delete iSendUiServicesOrderArray;
    delete iServicesToDim;
    delete iPropertyObserver;
    delete iSingleton;
    }

// -----------------------------------------------------------------------------
// AddTypedMenuItemL
//
// No menu item is added, if services are not found. This can happen if asyncronous
// sending service update is not yet finished.
// -----------------------------------------------------------------------------
//
void CSendUiImpl::AddTypedMenuItemL(
    CSendUi::TSendUiMenuType    aMenuType,
    CEikMenuPane&               aMenuPane,
    TInt                        aIndex,
    TInt                        aCommandId,
    TSendingCapabilities        aRequiredCapabilities )
    {
    TInt i(0);
    TBool menuItemAdded = EFalse;
    TBuf<KTitleBufLength> menuItemName;
    
     // Read the resources
    aMenuType == CSendUi::ESendMenu ? 
        i = R_SENDUI_MENUITEM_SEND : 
        i = R_SENDUI_MENUITEM_WRITE; // CSendUi::EWriteMenu
        
    iCoeEnv->ReadResourceL( menuItemName, i );
  
    for ( i = 0; i < iSendingServices.Count(); i++ )
    {
    TUid serviceUid = iSendingServices[i]->ServiceId();
    if ( QueryCapabilities( i, aRequiredCapabilities ) )
        {
        CEikMenuPaneItem::SData data;
        data.iCascadeId = NULL;
        data.iText = menuItemName;
        data.iCommandId = aCommandId;
        data.iFlags = 0;

        if ( aIndex == aMenuPane.NumberOfItemsInPane() )
            {
            aMenuPane.AddMenuItemL( data );
            }
        else
            {
            aMenuPane.InsertMenuItemL( data, aIndex );
            }
            
        menuItemAdded = ETrue;
        break;
        }
    }

    // Hide menu item if sending is already in progress.
    if ( menuItemAdded )
        {
        aMenuPane.SetItemDimmed( aCommandId, iIsSending);
        }        
    }

// -----------------------------------------------------------------------------
// ShowTypedQueryAndSendL
// First shows list query and then creates the message.
// Editor is launched for editing the message or the message is sent
// directly without opening the editor. Functionality depends on the
// type of selected sending service.
// -----------------------------------------------------------------------------
//
void CSendUiImpl::ShowTypedQueryAndSendL(
    CSendUi::TSendUiMenuType    aMenuType,
    const CMessageData*         aMessageData,
    TSendingCapabilities        aRequiredCapabilities,
    CArrayFix<TUid>*            aServicesToDim,
    TBool                       aLaunchEditorEmbedded,
    const TDesC&                aTitleText )
    {
    TUid serviceId = ShowTypedQueryL(
        aMenuType,
        aMessageData,
        aRequiredCapabilities,
        aServicesToDim,
        aTitleText );

    if ( serviceId != KNullUid )
        {
        // Process user selection.
        CreateAndSendMessageL(
            serviceId,
            aMessageData,
            aLaunchEditorEmbedded);
        }
    }

// -----------------------------------------------------------------------------
// ShowTypedQueryL
// Shows list query and returns the user selection.
// -----------------------------------------------------------------------------
//
TUid CSendUiImpl::ShowTypedQueryL(
    CSendUi::TSendUiMenuType    aMenuType,
    const CMessageData*         aMessageData,
    TSendingCapabilities        aRequiredCapabilities,
    CArrayFix<TUid>*            aServicesToDim,
    const TDesC&                aTitleText )
    {
	//validation of attachments is costly operation and hence better be done after showing services popup.
    // Implemented for CR # 401-1806 >>    
    // This section to enable/disable features (supported by feature manager) at run time, is to be revised,
    // once an observer class is available from feature manager side to intimate about feature state
		
    CRepository* repository = CRepository::NewLC( KCRUidSendUi );
    TInt oldFeatures(0);   
    TInt newFeatures(0); 
    TBool updateNeeded( EFalse );   
    
    if ( repository->Get( KKeySendUiFeatureManagerServices, oldFeatures ) != KErrNone )
    	{
    	updateNeeded = ETrue;
    	}
    FeatureManager::InitializeLibL();
    FeatureStatus( KFeatureIdMmsPostcard, newFeatures, KSendUiPostcard );
    FeatureStatus( KFeatureIdAudioMessaging, newFeatures, KSendUiAudioMessage );
    FeatureStatus( KFeatureIdSenduiMmsUpload, newFeatures, KSendUiMmsUpload );
    FeatureManager::UnInitializeLib();
    if ( newFeatures != oldFeatures )
        {
        repository->Set( KKeySendUiFeatureManagerServices, newFeatures );
        updateNeeded = ETrue;
        }

    CleanupStack::PopAndDestroy( repository );
    
    RProperty propertyUpdateOperation;
    TRequestStatus status;
    if ( updateNeeded )
        {
        RProperty::Set( 
            KPSUidSendUiProperty, 
            KSendUiUpdateRequest, 
            KSendUiUpdateRequested );
        User::LeaveIfError( propertyUpdateOperation.Attach( KPSUidSendUiProperty, KSendUiUpdateRequest ));
        propertyUpdateOperation.Subscribe( status );	
        User::WaitForRequest(status);
        TInt value = KErrNone;
        if(propertyUpdateOperation.Get( value ) !=KErrNotFound && value == KSendUiUpdated )
            {
            TRAPD( err, GetServicesL() );
            if ( err )
                {
#ifdef _DEBUG
                TBuf<256> buf;
                buf.Format(_L("SendUi err"));
                User::InfoPrint(buf);
#endif
                TUid serviceId( KNullUid );
                return serviceId;
                }
            }
        propertyUpdateOperation.Close();
        }
    // Implemented for CR # 401-1806 <<    
    // List items for list query.
    CDesCArrayFlat* listItems = new (ELeave) CDesCArrayFlat( KArrayGranularity );
    CleanupStack::PushL( listItems);

    // This array is used to map user selection to correct service.
    CArrayFix<TUid>* listItemUids = 
        new ( ELeave ) CArrayFixFlat<TUid>( KArrayGranularity );
    CleanupStack::PushL( listItemUids );

    iServicesToDim->Reset();

    TInt i = 0;
    if ( aServicesToDim )
        {
        for ( i = 0; i < aServicesToDim->Count(); i++  )
            {
            iServicesToDim->AppendL( (*aServicesToDim)[i] );
            }
        }
  
    // Get and filter ECom based services.
    FilterServicesL(
        *listItems,
        *listItemUids,
        aRequiredCapabilities,
        aMessageData,
        aMenuType );

    TUid serviceId( KNullUid );
    if ( listItems->Count() > 0 )
        {
        // Show list query.
        SortListL( *listItems, *listItemUids );

        serviceId = ShowListQueryL(
            listItems,
            *listItemUids,
            aTitleText,
            aMenuType );
        }

    CleanupStack::PopAndDestroy( 2, listItems );  // listItemUids, listItems

    return serviceId;
    }

// -----------------------------------------------------------------------------
// SendMessageL
// -----------------------------------------------------------------------------
TInt CSendUiImpl::SendMessageL(    
    TUid                    aServiceUid,
    const CMessageData*     aMessageData,
    TBool                   aLaunchEditorEmbedded)
    { 
    if ( iIsSending || aServiceUid == KNullUid )
        {
        return KErrNone;
        }
        
        CAknInputBlock* absorber = CAknInputBlock::NewLC( ); 
        // Ensures proper sending state if leave happens.
        iIsSending = ETrue;
        TInt success( KErrNone );
        CleanupStack::PushL( TCleanupItem( ResetIsSending, (TAny*)&iIsSending ) );

        // Create the requested ECom service.
        TInt i( ResolveServiceIndex( aServiceUid ));
        if ( i != KErrNotFound )
            {
            TRAP( success, 
                CSendingService* sendingService = CSendingService::NewL( 
                    iSendingServices[i]->ServiceProviderId(), *iCoeEnv, *iSingleton );
                CleanupStack::PushL( sendingService );  
                
                sendingService->CreateAndSendMessageL( aServiceUid, aMessageData, aLaunchEditorEmbedded );
                CleanupStack::PopAndDestroy( sendingService );
                    );
                
            }
        else
            {
            iIsSending = EFalse;
            }
    CleanupStack::PopAndDestroy( 2, absorber); // TCleanupItem, absorber
    return success;
    }

// -----------------------------------------------------------------------------
// SendMessageViaServer
// -----------------------------------------------------------------------------
//
void CSendUiImpl::SendMessageViaServerL( 
    TUid                    aServiceUid,
    const CMessageData*     aMessageData,
    TBool                   aLaunchEditorEmbedded )
    {
    TInt index( ResolveServiceIndex( aServiceUid ));
    TBool capabilitiesOk = ETrue;
    if ( index == KErrNotFound )
    	{
    	return;
    	}
    if ( iSendingServices[index]->ServiceFeatures() & CSendingServiceInfo::EServiceCanSendDirectly )
    	{
	    // Check sending rights
	    RProcess process;
	    TSecurityInfo securityInfo( process );
	    CSendUiCapabilityCheck* capabilityCheck = CSendUiCapabilityCheck::NewLC();

		capabilitiesOk = capabilityCheck->CheckCapabilitiesL( 
		    securityInfo, 
		    iSingleton->MsvSessionL(), 
		    KSenduiMtmMmsUid, 
		    iSendingServices[index]->ServiceName() );
		    
		CleanupStack::PopAndDestroy( capabilityCheck );
	    }
    
    if ( capabilitiesOk )
    	{
        TUid providerUid = iSendingServices[index]->ServiceProviderId();	
	    RSendUiServiceClient sendUiClient;
	    CleanupClosePushL( sendUiClient );
	    sendUiClient.ConnectChainedAppL( KSendUiLauncherAppUid );
	    // LaunchSendUiL is syncronous operation
	    sendUiClient.LaunchSendUiL( 
	        aServiceUid,
	        providerUid,
	        aLaunchEditorEmbedded, 
	        aMessageData ); 
	    CleanupStack::PopAndDestroy( &sendUiClient);
    	}
	    
    }

// -----------------------------------------------------------------------------
// CreateAndSendMessageL
// Creates the message and launches the editor for editing the message
// or sends the message directly without opening the editor. 
// Functionality depends on the type of selected sending service.
// -----------------------------------------------------------------------------
//
void CSendUiImpl::CreateAndSendMessageL(
    TUid                    aServiceUid,
    const CMessageData*     aMessageData,
    TBool                   aLaunchEditorEmbedded )
    {
    LOGTEXT(_L("CSendUiImpl::CreateAndSendMessageL >>"));
    TInt err(0); // initializing this to 0 helps debugging SendMessageViaServerL
    err = SendMessageL( aServiceUid, aMessageData, aLaunchEditorEmbedded );
    if ( !iServerAppLaunch && ( err == KErrPermissionDenied || err == KErrAccessDenied ) )
        {
        SendMessageViaServerL( aServiceUid, aMessageData, aLaunchEditorEmbedded );
        }
    else
       	{
        User::LeaveIfError( err );
       	}
    LOGTEXT(_L("CSendUiImpl::CreateAndSendMessageL <<"));
   }

// -----------------------------------------------------------------------------
// ServiceCapabilitiesL
// Returns sending capabilities of the sending service.
// -----------------------------------------------------------------------------
//
TInt CSendUiImpl::ServiceCapabilities(
    TUid                    aServiceUid,
    TSendingCapabilities&   aServiceCapabilities )
    {
    TInt i( ResolveServiceIndex( aServiceUid ));
    
    if ( i != KErrNotFound )
        {
        aServiceCapabilities = 
            iSendingServices[i]->ServiceCapabilities();
        i = KErrNone;        
        }
    return i;
    }

// -----------------------------------------------------------------------------
// AvailableServicesL
// Populates given list with the information about services
// provided by specified ECom service provider.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//

void CSendUiImpl::AvailableServicesL(
    RPointerArray<CSendingServiceInfo>& aServiceList,
    TUid aServiceProvider)
    {
    for ( TInt i(0); i < iSendingServices.Count(); i++ )
        {
        if ( iSendingServices[i]->ServiceProviderId() == aServiceProvider 
            || aServiceProvider == KNullUid )
            {
            CSendingServiceInfo* serviceInfo = iSendingServices[i]->CopyLC();
            aServiceList.AppendL( serviceInfo );
            CleanupStack::Pop( serviceInfo ); // serviceInfo
            }
        }
    }
// -----------------------------------------------------------------------------
// TechnologyType
// -----------------------------------------------------------------------------
//
TUid CSendUiImpl::TechnologyType( TUid aServiceUid )
    {
    TInt i = ResolveServiceIndex( aServiceUid );
    if ( i != KErrNotFound )
        {
        return iSendingServices[i]->TechnologyTypeId(); 
        }
    else
        {        
        return TUid::Null();
        }
    }

// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
//
TInt CSendUiImpl::ResolveServiceIndex( TUid aServiceUid )
    {
    TInt index( iSendingServices.Count() );
    
    while( --index >= 0)
        {
        if ( iSendingServices[index]->ServiceId() == aServiceUid )
            {
            return index;           
            }
        }
    return KErrNotFound;
    }

// -----------------------------------------------------------------------------
// QueryCapabilities
// -----------------------------------------------------------------------------
//
TBool CSendUiImpl::QueryCapabilities( 
    TInt index, 
    TSendingCapabilities aRequiredCapabilities )
    {
    if ( index == KErrNotFound )
    	{
    	return EFalse;
    	}

     if ( aRequiredCapabilities.iFlags == TSendingCapabilities::EAllServices )
        { 
        // No capabilities required from service
        return ETrue;
        }
    TSendingCapabilities serviceCap = iSendingServices[ index ]->ServiceCapabilities();
    
    if ( !(serviceCap.iMessageSize == 0 // no size limit set for the service
    || aRequiredCapabilities.iMessageSize == 0 ) // no size limit asked from the client
    && aRequiredCapabilities.iMessageSize > serviceCap.iMessageSize )
        {
        return EFalse;
        }
    
    // Check if support for attachments are required.
    if ( aRequiredCapabilities.iFlags & TSendingCapabilities::ESupportsAttachments
        && serviceCap.iFlags & TSendingCapabilities::ESupportsAttachments )
        {
        return ETrue;
        }

    // Check if support for body text is required.
    if ( aRequiredCapabilities.iFlags & TSendingCapabilities::ESupportsBodyText )
        {
        if ( serviceCap.iFlags & TSendingCapabilities::ESupportsBodyText )
            {
            if ( serviceCap.iBodySize > 0 && aRequiredCapabilities.iBodySize > serviceCap.iBodySize )
                {
                return EFalse; // size limit defined and it is enough
                }
            // no size limit in service for bodytext or required size below max size.
            return ETrue;
            }
        }
        
    
    // Check if support for BIO sending is required.
        if ( aRequiredCapabilities.iFlags & TSendingCapabilities::ESupportsBioSending 
             && serviceCap.iFlags & TSendingCapabilities::ESupportsBioSending )
            {
            return ETrue;
            }

    // Check if support for editor is required.
        if ( aRequiredCapabilities.iFlags & TSendingCapabilities::ESupportsEditor
             && serviceCap.iFlags & TSendingCapabilities::ESupportsEditor )
            {
            return ETrue;
            }
    return EFalse;
    }

// -----------------------------------------------------------------------------
// CSendUiImpl::GetServicesL
// 
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//

void CSendUiImpl::GetServicesL( )
{
    TInt value(0);
    TInt serviceCount;
    TInt cleanupItems(0);
    
    CRepository* rep = CRepository::NewLC( KCRUidSendUi );
    cleanupItems++;
    TInt err = rep->Get( KKeySendUiServiceCount, serviceCount );
    
    if ( err )
        {
        LOGTEXT(_L("SendUiImpl->GetServicesL: Cenrep init file missing"));
        CleanupStack::PopAndDestroy( rep );
        return;
        }
    else
        {
        if ( serviceCount == KSendUiNotInitialized )
            {
            // Services has not been initialized, launch service resolver in the bacground.
            CleanupStack::PopAndDestroy( rep);
            // iSendingServices are updated, when update is done.
            RProperty::Set( 
                KPSUidSendUiProperty, 
                KSendUiUpdateRequest, 
                KSendUiUpdateRequested); 

            return;            
            }
        }
    
    while ( iSendingServices.Count() )
        {
        delete iSendingServices[0];
        iSendingServices.Remove(0);
        }
        
    HBufC* text = HBufC::NewLC( KSendUiServiceMaxNameLength );
    cleanupItems++;
    TPtr ptr = text->Des();
    TInt key;
    for( TInt i(0); i < serviceCount; i++ )
        {
        key = KSendUiServiceIndex * i;
        CSendingServiceInfo* info = CSendingServiceInfo::NewLC();
    
        err = rep->Get( key | KSendUiServiceId, value );
        if (!err )
            {
            info->SetServiceId( TUid::Uid( value  ));
            }

        err = rep->Get( key | KSendUiServiceProviderId, value );
        if (!err )
            {
            info->SetServiceProviderId( TUid::Uid( value  ));
            }

       err = rep->Get( key | KSendUiServiceName, ptr );
        if (!err)
            {
            __ASSERT_DEBUG( ptr.Length() <= KSendUiServiceMaxNameLength, User::Invariant() );
            info->SetServiceNameL( ptr );
            }
        
        err = rep->Get( key | KSendUiServiceMenuName, ptr );
        if (!err)
            {
            __ASSERT_DEBUG( ptr.Length() <= KSendUiServiceMaxNameLength, User::Invariant() );
            info->SetServiceMenuNameL( ptr );
            }
        
        err = rep->Get( key | KSendUiServiceAddress, ptr );
        if (!err)
            {
            __ASSERT_DEBUG( ptr.Length() <= KSendUiServiceMaxNameLength, User::Invariant() );
            info->SetServiceAddressL( ptr );
            }
        
        TSendingCapabilities cap;
            
        err = rep->Get( key | KSendUiServiceFlags, value );
        if (!err)
            {
            cap.iFlags = value;
            }
        
        err = rep->Get( key | KSendUiServiceBodySize, value );
        if (!err)
            {
            cap.iBodySize = value;
            }
        
        err = rep->Get( key | KSendUiServiceMessageSize, value );
        if (!err)
            {
            cap.iMessageSize = value;
            }
    
    
        err = rep->Get( key | KSendUiServiceTechnologyType, value );
        if (!err )
            {
            info->SetTechnologyTypeId( TUid::Uid( value  ));
            }
        
        err = rep->Get( key | KSendUiServiceFeatures, value );
        if (!err)
            {
            info->SetServiceFeatures( value );
            }
    
        if (!err)
            {
            info->SetServiceCapabilities( cap );            
            iSendingServices.Append( info );
            CleanupStack::Pop( info);
            }

        }
    
    CleanupStack::PopAndDestroy( cleanupItems, rep); // text, rep
    
}

// ---------------------------------------------------------
// ShowListQueryL(
// Displays list query.
// (other items were commented in a header).
// ---------------------------------------------------------
// 
TUid CSendUiImpl::ShowListQueryL(
    MDesCArray*                 aListItems,
    const CArrayFix<TUid>&      aListItemUids,
    const TDesC&                aTitleText,
    CSendUi::TSendUiMenuType    aMenuType )
    {
    // Show list query.
    TInt choice = KErrNotFound;
    CAknListQueryDialog* dlg = new (ELeave) CAknListQueryDialog( &choice );
    TInt ret = 0;
    TRAPD( err, 
    dlg->PrepareLC( R_SENDUI_LIST_QUERY );
    dlg->SetItemTextArray( aListItems );
    dlg->SetOwnershipType( ELbmDoesNotOwnItemArray );

    // Set title
    CAknPopupHeadingPane* heading = dlg->Heading();

    if ( aTitleText != KNullDesC )
        {
        heading->SetTextL( aTitleText );
        }
    else 
        {
        HBufC* title;
        TInt titleId(0);
        if (aMenuType == CSendUi::ESendMenu )
            {
            titleId = R_SENDUI_LIST_QUERY_TITLE ;
            }
        else if ( aMenuType == CSendUi::EWriteMenu )
            {
            titleId = R_SENDUI_LIST_QUERY_TITLE_WRITE;
            }
        
        if ( titleId )
            {
            title = iCoeEnv->AllocReadResourceLC( titleId );
            heading->SetTextL( *title );
            CleanupStack::PopAndDestroy( title );
            }
        }
    
    ret = dlg->RunLD();
    ); //end of TRAPD
    
    if( err == KLeaveExit )
        {
        delete dlg;
        dlg = NULL;
        }
    
    if ( !ret )
        {
        return KNullUid;
        }
    return aListItemUids.At( choice );
    }


// -----------------------------------------------------------------------------
// CanSendContentL
// -----------------------------------------------------------------------------
//
TBool CSendUiImpl::CanSendContentL(
    TUid                    aServiceUid,
    TUid                    aServiceProviderId,
    const CMessageData*     aMessageData,
    TDataType*              aMimeType )
    {
    // Other ecoms are filtered by their base provider, but versitile MTMs under 
    // GenericMtmPlugin have filtering by their serviceUid    
    if ( aServiceProviderId != KGenericMtmPlugin )
    {
        aServiceUid = aServiceProviderId;
    }
    // Content based filtering is done only for some selected services.
    // Cannot filter with no data, certain services and audio message (if no audiomessage support)
    if ( !aMessageData ||
         !( aServiceUid == KDrmLinkSender || 
            aServiceUid == KSenduiMtmPostcardUid ||
            aServiceUid == KMmsDirectUpload ||
            aServiceUid == KMmsIndirectUpload ||
            aServiceUid == KSenduiMtmAudioMessageUid ||
            aServiceUid == KSenduiMtmSmsUid ) )                            
        {
        return ETrue;
        }


    const CDesCArray& attachmentPaths = aMessageData->AttachmentArray();
    const RArray<RFile>& attachments = aMessageData->AttachmentHandleArray();

    TInt attachmentCount = attachmentPaths.Count() + attachments.Count();

    if ( attachmentCount == 0 )
        { // No content to send
        
        if ( aServiceUid == KDrmLinkSender )
            {
            return EFalse;
            }
        TInt bodyTextLength = aMessageData->BodyText()->DocumentLength();
        // Dim MMS Upload services, if there is no bodytext
        if ( ( aServiceUid == KMmsDirectUpload 
            || aServiceUid == KMmsIndirectUpload ) 
            && bodyTextLength == 0 )
            {
            return EFalse; // bodytext will be converted into attachment
            }
        // Dim Audio message, if there is bodytext    
        if ( aServiceUid == KSenduiMtmAudioMessageUid 
            && bodyTextLength > 0 )
            {
            return EFalse;
            }
        return ETrue;
        }
    else if ( attachmentCount == 1  )
        {
        TBool result = ETrue;
        
        switch ( aServiceUid.iUid )
            {
            case KSenduiMtmSmsUidValue: 
                {
                if ( aMimeType->Des8().CompareF( KMsgMimeVCard ) != 0 &&
                     aMimeType->Des8().CompareF( KMsgMimeVCal ) != 0 )
                    {
                    result = EFalse;
                    }
                break;
                }
            case KSenduiMtmPostcardUidValue:
                {
                if( aMimeType->Des8().CompareF( KMsgMimeImageJpeg ) != 0 &&
                    aMimeType->Des8().CompareF( KMsgMimeImageGif ) != 0 &&
                    aMimeType->Des8().CompareF( KMsgMimeImagePng ) != 0 &&
                    aMimeType->Des8().CompareF( KMsgMimeTextPlain ) != 0 )
                    {
                    // Supported types: jpeg, png, gif, plain text
                    result = EFalse;
                    }
                }
                break;   
            case KSenduiMtmAudioMessageUidValue:
                {
                if( aMimeType->Des8().CompareF( KMsgMimeAudioAmr ) != 0 ||
                    aMessageData->BodyText()->DocumentLength() > 0 )
                    {
                    // Does not allow other than amr attachment and empty bodytext
                    result = EFalse;
                    }
                }    
                break;    
            case KDrmLinkSenderValue:
                {
                // Check OMA DRM level

                TInt drmMethod = 0;
                CDRMHelper::TDRMHelperOMALevel omaDRMLevel;
                CDRMHelper* drmHelper = NULL;
                TRAPD( error, drmHelper = CDRMHelper::NewL( iFs ) );
                if ( error != KErrNone )
                    {
                    return error;
                    }
                error = drmHelper->SupportedDRMMethods2( drmMethod, omaDRMLevel );
                if ( !(omaDRMLevel & CDRMHelper::EOMA_2_0 ))
                     {
                     result = EFalse;
                     break;
                     }
                delete drmHelper;


                if ( attachmentPaths.Count() )
                    {
                    RFile handle = SendUiUtils::OpenFileHandleL( attachmentPaths.MdcaPoint(0), iFs );
                    CleanupClosePushL( handle );
                    result = SendUiUtils::HasContentUrlL( handle );
                    CleanupStack::PopAndDestroy( &handle );
                    }
                else
                    {
                    result = SendUiUtils::HasContentUrlL( const_cast<RFile&>( attachments[0] ) );
                    }
                }
                break;
            default:
                // Should never end up here
                break;
            }
     
        return result;        
        }
    else if ( attachmentCount > 1  )
        {
        if ( aServiceUid == KDrmLinkSender ||
             aServiceUid == KSenduiMtmPostcardUid ||
             aServiceUid == KSenduiMtmAudioMessageUid ||
             aServiceUid == KSenduiMtmSmsUid )
            {
            // Currently supports sending of one file only
            // or no files (SMS)
            return EFalse;
            }
        return ETrue;
        }
   
   // Should never end up here
   return ETrue;
   }

// -----------------------------------------------------------------------------
// CSendUiImpl::FilterServicesL
// 
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CSendUiImpl::FilterServicesL(
    CDesCArrayFlat&         aListItems,
    CArrayFix<TUid>&        aListItemUids,
    TSendingCapabilities    aRequiredCapabilities,
    const CMessageData*     aMessageData,
    CSendUi::TSendUiMenuType    aMenuType  )
    {
    TInt i = 0;
    TInt cc = 0;
    TBool dimService = EFalse;
	TDataType* mimeType = NULL;
	TInt cleanupItems(0);
	
	 if(iEmailFramework)
	     {
	     if(!IsMailboxAvailableL())
	         iServicesToDim->AppendL(KSenduiMtmSmtpUid);
	     }
	    
    // Filter some services away if there is no content to be send.
    if ( !aMessageData )
        {
        iServicesToDim->AppendL( KDrmLinkSender );
        iServicesToDim->AppendL( KMmsDirectUpload );
        iServicesToDim->AppendL( KMmsIndirectUpload );
        iServicesToDim->AppendL( KShareOnline );
        }
    else if ( aMessageData->AttachmentArray().Count() == 1
            || aMessageData->AttachmentHandleArray().Count() == 1 )
    	{
    	// CanSendContent can recycle these in mime type resolving
    	// for all services that have attachments
		mimeType = new (ELeave) TDataType();
		CleanupStack::PushL( mimeType );
		cleanupItems++;
				
	    if ( aMessageData->AttachmentArray().Count() )
            {
            RFile handle = SendUiUtils::OpenFileHandleL(
                aMessageData->AttachmentArray().MdcaPoint( 0 ), iFs );
            CleanupClosePushL( handle );
            SendUiUtils::ResolveMimeTypeL( handle, *mimeType );
            CleanupStack::PopAndDestroy( &handle );
            }
        else
            {
            SendUiUtils::ResolveMimeTypeL( aMessageData->AttachmentHandleArray()[0], *mimeType );
            }
    	}
    TBool addMailService = EFalse;
    TUid integratedEmailClientMtmUid;
		
    if ( iEmailClientIntegration )
    	{
    	CRepository* repository = NULL;
    	TInt mtmPluginID = 0;
    	TRAPD( ret, repository = CRepository::NewL( KCRUidSelectableDefaultEmailSettings ) );
    	
    	if(ret == KErrNone)
    	    {
    	    //Get Email application mtm plugin ID
    	    repository->Get( KIntegratedEmailAppMtmPluginId, mtmPluginID ); 
    	    }

    	delete repository;
    	integratedEmailClientMtmUid = TUid::Uid(mtmPluginID);
    	for( i = 0 ; i < iSendingServices.Count(); i++ )
    		{
    		TUid serviceUid = iSendingServices[i]->ServiceId();
    		// Check if it is found in sendingServices and it's valid, then hide
    		if ( integratedEmailClientMtmUid == iSendingServices[i]->ServiceId() && 
    				CheckServiceCapabilities( serviceUid, aRequiredCapabilities ) &&
    				CanSendContentL( serviceUid, 
    							     iSendingServices[i]->ServiceProviderId(), 
    							     aMessageData, mimeType ) )
    			{
    			addMailService = ETrue;
    			}
    		}
    	
    	}

    // Filter available ECom services and add to list item array.
    // Capability based filtering: CheckServiceCapabilities
    // Content based filtering: CanSendContentL
    // "dimmable array" filtering: done here
    TInt serviceFeatures;
    for( i = 0 ; i < iSendingServices.Count(); i++ )
        {
        dimService = EFalse;
        TUid serviceUid = iSendingServices[i]->ServiceId();
        TUid serviceProviderUid = iSendingServices[i]->ServiceProviderId();
        
        if ( iSendingServices[i]->ServiceMenuName() == KNullDesC )
            {
            dimService = ETrue;
            }
        
        TUid serviceTechnologyType = iSendingServices[i]->TechnologyTypeId();
        TUid dimServiceUid;
        for ( cc = 0; cc < iServicesToDim->Count(); cc++ )
            {
			dimServiceUid = (*iServicesToDim)[cc];
            if ( dimServiceUid == serviceUid 
            || dimServiceUid == serviceProviderUid
            || dimServiceUid == serviceTechnologyType 
            )
                {
                dimService = ETrue;
                break;
                }
            }
        if ( iEmailClientIntegration )
            {
            //Hide Email application (not the platform email) from "send" menu
            if( integratedEmailClientMtmUid == iSendingServices[i]->ServiceId() )
                {
                dimService = ETrue;
                }  
            }
		serviceFeatures = iSendingServices[i]->ServiceFeatures();
        if ( iEmailClientIntegration )
        	{
        	//If there is a mailbox created by integrated mail client then 
        	//put SMTP MTM ("Email") in the "send" menu, by changing the 
        	//serviceFeature    
        	if ( addMailService && 
        		 ( iSendingServices[i]->ServiceId() == KUidMsgTypeSMTP ) )
        		{
        		serviceFeatures = 0;
        		addMailService = EFalse; //MailService must be added only once
        		}
        	}  
        
        //Check if the sending service is some third party email provider than hide from the Send menu.
        if( iEmailFramework  && (iSendingServices[i]->TechnologyTypeId() == KMailTechnologyTypeUid))
            {
            if(IsThirdPartyMailService(iSendingServices[i]->ServiceId()))
                dimService = ETrue;
            }
        
        if ( !dimService &&
             !( serviceFeatures & CSendingServiceInfo::EServiceInValid ) &&
             !( serviceFeatures & CSendingServiceInfo::EServiceHidden )
             &&  CheckServiceCapabilities( serviceUid, aRequiredCapabilities ) &&
             CanSendContentL( serviceUid, serviceProviderUid, aMessageData, mimeType ) )
            {
            if ( aMenuType == CSendUi::ESendMenu )
                {
                aListItems.AppendL(iSendingServices[i]->ServiceMenuName() );
                }
            else if ( aMenuType == CSendUi::EWriteMenu )
                {
                aListItems.AppendL(iSendingServices[i]->ServiceName() );
                }

            aListItemUids.AppendL( serviceUid );
            }
        }
    CleanupStack::PopAndDestroy( cleanupItems );
    }

// -----------------------------------------------------------------------------
// SortListL
// Sets ECom services to correct positions in "Send"-list query.
// -----------------------------------------------------------------------------
//
void CSendUiImpl::SortListL(
    CDesCArrayFlat&     aListItems,
    CArrayFix<TUid>&    aListItemUids )
    {
    TInt insertIndex(0);
    TUid positionUid;   
    TInt j;
    // set the services into correct order. The order is predefined in the resources.
    for ( TInt i = 0; i < iSendUiServicesOrderArray->Count() ; i++ )
        {
        positionUid = TUid::Uid( (*iSendUiServicesOrderArray)[i] );
        for (j = insertIndex; j < aListItems.Count(); j++ )
            {
            TUid tmp = aListItemUids[j];
            if ( positionUid == aListItemUids[j] ) 
                {
                if ( j >= insertIndex )
                    {
                    HBufC* serviceName = aListItems[j].AllocL();
                    CleanupStack::PushL( serviceName );

                    aListItemUids.Delete( j );
                    aListItems.Delete( j );

                    aListItemUids.InsertL( insertIndex, positionUid );
                    aListItems.InsertL( insertIndex, *serviceName );
                    CleanupStack::PopAndDestroy( serviceName );
                    insertIndex++;      
                    }
                else
                    {
                    // service already on the right place. Next.
                    insertIndex++;  
                    }
                    
                }
            }
        }
    }


// ---------------------------------------------------------
// ResetIsSending
// Resets sending state flag.
// ---------------------------------------------------------
//    
void CSendUiImpl::ResetIsSending( TAny* aAny )
    {
    *( (TBool*)aAny ) = EFalse;
    }

// -----------------------------------------------------------------------------
// CheckServiceCapabilities
// Compares ECom service sending capabilities to required capabilities.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CSendUiImpl::CheckServiceCapabilities(
    TUid                    aServiceUid,
    TSendingCapabilities    aRequiredCapabilities )
    {
    TInt i = 0;
    TSendingCapabilities serviceCapabilities;

    // No capabilities defined, uses content-based filtering
    // or no capabilities required from service
    if ( aServiceUid == KDrmLinkSender 
         || aRequiredCapabilities.iFlags == TSendingCapabilities::EAllServices )
        { 
        return ETrue;
        }

    i = ResolveServiceIndex( aServiceUid );

    if ( i != KErrNotFound )
        {
        return QueryCapabilities( i, aRequiredCapabilities );  
        }
    else
        {
        return EFalse;          
        }
    }

// -----------------------------------------------------------------------------
// CSendUiImpl
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CSendUiImpl::CSendUiImpl()
    :  iCoeEnv( CCoeEnv::Static() ),
        iFs( iCoeEnv->FsSession() ),
        iResourceLoader( *iCoeEnv ),
        iEmailFramework(EFalse)
        
    {
    }

// -----------------------------------------------------------------------------
// CSendUiImpl::FeatureStatus
// -----------------------------------------------------------------------------
//
void CSendUiImpl::FeatureStatus( TInt aFeature, TInt &aNewFeatures, TInt aFeatureFlag )
    {
    if ( FeatureManager::FeatureSupported( aFeature ) )
        {
        // If Postcard only is supported,     aFeatureFlag is 0x00000001 ==> aNewFeatures == 0x00000001
        // If Audio message is also supported aFeatureFlag is 0x00000002 ==> aNewFeatures == 0x00000003
        // If MMSUpload is also supported,    aFeatureFlag is 0x00000004 ==> aNewFeatures == 0x00000007
        aNewFeatures |= aFeatureFlag;
        }
    }
// ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CSendUiImpl::ConstructL()
    {
    iSingleton = CSendUiSingleton::NewL();
    //User::LeaveIfError( iFs.Connect() );
    iFs.ShareProtected();

    TParse* fp = new(ELeave) TParse(); 
    fp->Set( KSendUiResourceFileName, &KDC_RESOURCE_FILES_DIR, NULL );
    iResourceFileName = fp->FullName();
    delete fp;
    fp = NULL;
    
    iResourceLoader.OpenL( iResourceFileName );

    // Check for server launch
    RProcess process;
    TUid hostId = process.SecureId();
    if ( hostId == KSendUiLauncherAppUid ) 
        {
        iServerAppLaunch = ETrue;
        }
   else
        {
        iServerAppLaunch = EFalse;
        iSendUiServicesOrderArray = 
            new ( ELeave ) CArrayFixFlat<TInt32>( KSendUiServiceOrderArrayGranularity );

        TResourceReader reader;
        iCoeEnv->CreateResourceReaderLC( reader, R_SENDUISERVICEORDER_ARRAY );
        const TInt count = reader.ReadInt16();
        for ( TInt loop = 0; loop < count; loop++ )
            {
            iSendUiServicesOrderArray->AppendL( reader.ReadInt32() );
            }
        CleanupStack::PopAndDestroy( ); // reader 
        }

    iPropertyObserver = CPropertyObserver::NewL( this );
    TRAPD( err, GetServicesL() );
    
    if ( err )
        {
#ifdef _DEBUG
        TBuf<256> buf;
        buf.Format(_L("SendUi err"));
        User::InfoPrint(buf);
        LOGTEXT2(_L("Error %d while loading CenRep"), err );
#endif
        return;
        }
    iServicesToDim = new (ELeave) CArrayFixFlat<TUid>( KArrayGranularity );
    FeatureManager::InitializeLibL();
    
    if ( FeatureManager::FeatureSupported( KFeatureIdEmailMceIntegration ) )
    	{

    	iEmailClientIntegration = ETrue;
    	}
    else
    	{

    	iEmailClientIntegration = EFalse;
    	}   
    if ( FeatureManager::FeatureSupported( KFeatureIdFfEmailFramework ) )
    {
      iEmailFramework = ETrue;
    } 
    FeatureManager::UnInitializeLib();
    }
// -----------------------------------------------------------------------------
// CSendUiImpl::IsMailboxAvailableL
// -----------------------------------------------------------------------------
//
TBool CSendUiImpl::IsMailboxAvailableL(void)
{
    TBool mailbox = EFalse;
    
    CMsvSession& msv = iSingleton->MsvSessionL();
    CMsvEntry* entry = msv.GetEntryL( KMsvRootIndexEntryId );
    CleanupStack::PushL( entry );
    
    entry->SetSortTypeL( TMsvSelectionOrdering(
                             KMsvGroupByType | KMsvGroupByStandardFolders,
                             EMsvSortByDetailsReverse, ETrue ) );

     // Add others
     for ( TInt cc = entry->Count(); --cc >= 0; )
         {
         TMsvEntry tentry2 = (*entry)[cc];

         if ( tentry2.iType.iUid == KUidMsvServiceEntryValue &&
              tentry2.Id() != KMsvLocalServiceIndexEntryIdValue )
             {
             if ( IsEmailAppendableL(tentry2) )
                 {
                     mailbox = ETrue;
                     break;
                 }
             }
         }
     
         CleanupStack::PopAndDestroy( entry );

     return mailbox; 
}

// -----------------------------------------------------------------------------
// IsThirdPartyMailService
// Check if any Third Party Email Serivce is present or not
// -----------------------------------------------------------------------------
//

TBool CSendUiImpl::IsThirdPartyMailService( TUid aUid )
    {
    //If the Uid is other than SMTP and Cmail
    //than is a Third Party service
      if((aUid !=  KUidMsgTypeSMTP)&&
       ( aUid.iUid != KUidMsgTypeFsMtmVal ) )
        {
        return ETrue;
        }
      else
        return EFalse;
    }

// -----------------------------------------------------------------------------
// IsEmailAppendableL
// Check if Email entry is valid to be counted
// -----------------------------------------------------------------------------
//

TBool CSendUiImpl::IsEmailAppendableL(TMsvEntry atentry)
    {
    TBool appendEmail = EFalse;

    if ( atentry.Visible() )
        {
        appendEmail = ETrue;
        }
    else
        {
        if ( iSingleton->MtmUiDataRegistryL().IsPresent( atentry.iMtm ) &&
                iSingleton->MtmUiDataRegistryL().IsPresent( KUidMsgTypePOP3 ) )
            {
            TUid mailMTMTechType =
            iSingleton->MtmUiDataRegistryL().TechnologyTypeUid( KUidMsgTypePOP3 );
            if( iSingleton->MtmUiDataRegistryL().TechnologyTypeUid( atentry.iMtm ) ==
                                                mailMTMTechType )
                {
                appendEmail = ETrue;
                }
            }
        }
    return appendEmail;
    }
// -----------------------------------------------------------------------------
// AddTypedMenuItemToMenuPaneL
//
// No menu item is added, if services are not found. This can happen if 
// asyncronous sending service update is not yet finished.
// To inform caller about the API result, aResult param is added.
// so that caller application will know that its request is not succesfully 
// completed due to above reason.
// -----------------------------------------------------------------------------
//
void CSendUiImpl::AddTypedMenuItemToMenuPaneL(
    TBool&                      aResult,
    CSendUi::TSendUiMenuType    aMenuType,
    CEikMenuPane&               aMenuPane,
    TInt                        aIndex,
    TInt                        aCommandId,
    TSendingCapabilities        aRequiredCapabilities)
    {
    TInt i(0);
    TBuf<KTitleBufLength> menuItemName;
    aResult=EFalse;
    
     // Read the resources
    aMenuType == CSendUi::ESendMenu ? 
        i = R_SENDUI_MENUITEM_SEND : 
        i = R_SENDUI_MENUITEM_WRITE; // CSendUi::EWriteMenu
        
    iCoeEnv->ReadResourceL( menuItemName, i );
  
    for ( i = 0; i < iSendingServices.Count(); i++ )
    {
    TUid serviceUid = iSendingServices[i]->ServiceId();
    if ( QueryCapabilities( i, aRequiredCapabilities ) )
        {
        CEikMenuPaneItem::SData data;
        data.iCascadeId = NULL;
        data.iText = menuItemName;
        data.iCommandId = aCommandId;
        data.iFlags = 0;

        if ( aIndex == aMenuPane.NumberOfItemsInPane() )
            {
            aMenuPane.AddMenuItemL( data );
            }
        else
            {
            aMenuPane.InsertMenuItemL( data, aIndex );
            }
            
        aResult = ETrue;
        break;
        }
    }
    // Hide menu item if sending is already in progress.
    if ( aResult )
        {
        aMenuPane.SetItemDimmed( aCommandId, iIsSending);
        }    
    }
// end of file

