/*
* Copyright (c) 2007-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:  IMAP4 fetch message operation
*
*/

#include "emailtrace.h"
#include "ipsplgheaders.h"

// Constants and defines
const TInt KFetchOpPriority = CActive::EPriorityStandard;
const TInt KIpsPlgSelectionGra = 16;

// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
EXPORT_C CIpsPlgImap4PopulateOp* CIpsPlgImap4PopulateOp::NewL(
    CMsvSession& aMsvSession,
    TRequestStatus& aObserverRequestStatus,
    TInt aPriority,
    TMsvId aService,
    CIpsPlgTimerOperation& aActivityTimer,
    const TImImap4GetPartialMailInfo& aPartialMailInfo,
    const CMsvEntrySelection& aSel,
    TFSMailMsgId aFSMailBoxId,
    MFSMailRequestObserver& aFSOperationObserver,
    TInt aFSRequestId,
    CIpsPlgEventHandler* aEventHandler,
    TBool aDoFilterSelection )
    {
    FUNC_LOG;
    CIpsPlgImap4PopulateOp* op = new (ELeave) CIpsPlgImap4PopulateOp(
        aMsvSession,
        aObserverRequestStatus,
        aPriority,
        aService,
        aActivityTimer,
        aPartialMailInfo,
        aFSMailBoxId,
        aFSOperationObserver,
        aFSRequestId,
        aEventHandler );
        
    CleanupStack::PushL(op);
    op->ConstructL( aSel, aDoFilterSelection );
    CleanupStack::Pop( op );
    return op;
    }

// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
CIpsPlgImap4PopulateOp::CIpsPlgImap4PopulateOp(
    CMsvSession& aMsvSession,
    TRequestStatus& aObserverRequestStatus,
    TInt aPriority,
    TMsvId aService,
    CIpsPlgTimerOperation& aActivityTimer,
    const TImImap4GetPartialMailInfo& aPartialMailInfo,
    TFSMailMsgId aFSMailBoxId,
    MFSMailRequestObserver& aFSOperationObserver,
    TInt aFSRequestId,
    CIpsPlgEventHandler* aEventHandler )
    :
    CIpsPlgOnlineOperation(
    aMsvSession,
    aPriority,
    aObserverRequestStatus,
    aActivityTimer,
    aFSMailBoxId,
    aFSOperationObserver,
    aFSRequestId),
    iPartialMailInfo(aPartialMailInfo),
    iSelection( KIpsPlgSelectionGra ),
    iEventHandler( aEventHandler )
    {
    FUNC_LOG;
    iService = aService;
    }

// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
CIpsPlgImap4PopulateOp::~CIpsPlgImap4PopulateOp()
    {
    FUNC_LOG;
    iSelection.Close();

    if ( iTempSelection )
    	{
    	iTempSelection->Reset();
   	delete iTempSelection;
    	}
    }

// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
void CIpsPlgImap4PopulateOp::ConstructL( 
        const CMsvEntrySelection& aSel,
        TBool aDoFilterSelection )
    {
    FUNC_LOG;
    BaseConstructL( KUidMsgTypeIMAP4 );
    
    if ( aDoFilterSelection )
        {
        FilterSelectionL( aSel );
        }
    else
        {
        for ( TInt i = 1; i < aSel.Count(); i++ )
            {
            if ( aSel[i] != iService )
                {
                iSelection.AppendL( aSel.At(i) );
                }
            }
        }
    iTempSelection = new ( ELeave ) CMsvEntrySelection();
    DoConnectL();
    }

// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
TInt CIpsPlgImap4PopulateOp::IpsOpType() const
    {
    FUNC_LOG;
    return EIpsOpTypeImap4PopulateOp;
    }

// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
void CIpsPlgImap4PopulateOp::DoConnectL()
    {
    FUNC_LOG;
    iState = EStateConnecting;
    iStatus = KRequestPending;

    CIpsPlgImap4ConnectOp* connOp = CIpsPlgImap4ConnectOp::NewL(
        iMsvSession,
        KFetchOpPriority,
        iStatus, 
        iService,
        *iActivityTimer,
        iFSMailboxId,
        iFSOperationObserver,
        iFSRequestId,
        iEventHandler,
        ETrue, // Do plain connect
        EFalse );
        
    delete iOperation;
    iOperation = connOp;

    SetActive();
    }
    
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
void CIpsPlgImap4PopulateOp::RunL()
    {
    FUNC_LOG;
    TRAPD(err, DoRunL());
    if(err != KErrNone )
        {
        iSyncProgress().iErrorCode = err;
        Complete();
        }
    }

// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
void CIpsPlgImap4PopulateOp::DoRunL()
    {
    FUNC_LOG;
    TInt err = iStatus.Int();
    delete iOperation;
    iOperation = NULL;
    
    switch( iState )
        {
        case EStateConnecting:
            {
            TMsvEntry tentry;
            TMsvId service;
            iMsvSession.GetEntry(iService, service, tentry );
            if( !tentry.Connected() )
                {
                CompleteObserver( KErrCouldNotConnect );
                return;
                }
            DoPopulateL();
            break;
            }
        case EStateFetching:         
            {
            if( err != KErrNone && iOperation )
                {
                iFetchErrorProgress = iOperation->ProgressL().AllocL();
                iState = EStateIdle;
                Complete();
                }
            else
                {
                
                }
            break;
            }
        case EStateInfoEntryChange:
            {
            DoPopulateL();
            break;
            }
        case EStateIdle:
        default:
            break;
        }
    }

// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
void CIpsPlgImap4PopulateOp::DoCancel()
    {
    FUNC_LOG;
    if( iOperation )
        {
        iOperation->Cancel();
        }
    CompleteObserver( KErrCancel );
    }

// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
const TDesC8& CIpsPlgImap4PopulateOp::ProgressL()
    {
    FUNC_LOG;
    if(iFetchErrorProgress && (iState == EStateIdle))
        {
        // Completed, but with an error during fetch.
        return *iFetchErrorProgress;
        }        
    TImap4SyncProgress progg;
    progg.iErrorCode = KErrNone;
    TPckgBuf<TImap4SyncProgress> param(progg);
    iSyncProgress.Copy(param);
    return iSyncProgress; 
    }

// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
const TDesC8& CIpsPlgImap4PopulateOp::GetErrorProgressL(TInt /*aError*/ )
    {
    FUNC_LOG;
    return *iFetchErrorProgress;
    }

// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
TFSProgress CIpsPlgImap4PopulateOp::GetFSProgressL() const
    {
    FUNC_LOG;
    // might not never called, but gives something reasonable if called
    TFSProgress result = { TFSProgress::EFSStatus_Waiting, 0, 0, KErrNone };
    switch( iState )
        {
        case EStateConnecting:
            result.iProgressStatus = TFSProgress::EFSStatus_Connecting;
            break;
        case EStateFetching:
            result.iProgressStatus = TFSProgress::EFSStatus_Connected;
            break;
        default:
            result.iProgressStatus = TFSProgress::EFSStatus_RequestComplete;
            break;
        }
    if ( iStatus.Int() == KErrCancel )
        {
        result.iProgressStatus = TFSProgress::EFSStatus_RequestCancelled;
        result.iError = KErrCancel;
        }
    return result;
    }

// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------    
TInt CIpsPlgImap4PopulateOp::GetEngineProgress( const TDesC8& aProgress )
    {
    FUNC_LOG;
    if( !aProgress.Length() )
        {
        return KErrNone;
        }
    else
        {
        TPckgBuf<TImap4CompoundProgress> paramPack;
        paramPack.Copy( aProgress );
        const TImap4GenericProgress& progress = paramPack().iGenericProgress;
        return progress.iErrorCode;        
        }    
    }    

// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
void CIpsPlgImap4PopulateOp::Complete()
    {
    FUNC_LOG;
    TRequestStatus* observer=&iObserverRequestStatus;
    User::RequestComplete(observer, KErrNone);
    }

// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
void CIpsPlgImap4PopulateOp::FilterSelectionL( 
        const CMsvEntrySelection& aSelection )
    {
    FUNC_LOG;
    iSelection.Reset();
    TMsvId messageId;
    // NOTE: this code is taken from symbian os source IMPCMTM.CPP
    // filter selection is in here because messages are
    // fetched separately then we dont have to make unneccessery imap 
    // client mtm calls

    for (TInt i=0; i<aSelection.Count(); i++)
        {
        messageId = (aSelection)[i];
        if ( messageId == iService )
            {
            continue;
            }
        TMsvEmailEntry entry;
        TMsvId service = KMsvNullIndexEntryId;          
        User::LeaveIfError(iMsvSession.GetEntry(messageId, service, entry));
        
        TBool isComplete = !(   ( entry.Complete() && entry.PartialDownloaded() ) 
                             || ( !entry.Complete() && ( !entry.BodyTextComplete() 
                             || ( iPartialMailInfo.iGetMailBodyParts == EGetImap4EmailBodyTextAndAttachments ) ) 
                                  && !entry.PartialDownloaded() ) );

        TBool isMsgEntry = entry.iType == KUidMsvMessageEntry;
        TBool isSizeUnderMax = entry.iSize <= iPartialMailInfo.iMaxEmailSize;
        TBool isParentComp = entry.Parent() == 
            iPartialMailInfo.iDestinationFolder && isComplete;
        
        if( IsPartialPopulate( )
              && !isComplete
              && entry.iType == KUidMsvMessageEntry )
            {
            iSelection.AppendL(messageId); 
            }
        else if ( isMsgEntry && isSizeUnderMax && !isParentComp )
            {
            iSelection.AppendL(messageId);
            }
        }
    }

// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
TBool CIpsPlgImap4PopulateOp::IsPartialPopulate( )
    {
    FUNC_LOG;
    // NOTE: this code is taken from symbian os source IMPCMTM.CPP
    // code is modified to this class purpose 
    
    TBool isPartialPopulate = EFalse;
    if(iPartialMailInfo.iPartialMailOptions == ENoSizeLimits &&
       iPartialMailInfo.iTotalSizeLimit == KMaxTInt &&
       iPartialMailInfo.iBodyTextSizeLimit == KMaxTInt && 
       iPartialMailInfo.iAttachmentSizeLimit == KMaxTInt && 
        (iPartialMailInfo.iGetMailBodyParts == EGetImap4EmailHeaders || 
         iPartialMailInfo.iGetMailBodyParts == EGetImap4EmailBodyText ||
         iPartialMailInfo.iGetMailBodyParts == EGetImap4EmailBodyTextAndAttachments ||
         iPartialMailInfo.iGetMailBodyParts == EGetImap4EmailAttachments ||
         iPartialMailInfo.iGetMailBodyParts == EGetImap4EmailBodyAlternativeText) )
        {
        isPartialPopulate = EFalse;
        }
    else
        {
        isPartialPopulate = ETrue;
        }

    return isPartialPopulate;
    }

// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
void CIpsPlgImap4PopulateOp::DoPopulateL( )
    {
    FUNC_LOG;
    if ( iSelection.Count() > 0 )
        {
        TMsvEmailEntry tEntry;
        TMsvId dummy;
        TInt lastIndex = iSelection.Count()-1;
        User::LeaveIfError( iMsvSession.GetEntry(
                iSelection[lastIndex], dummy, tEntry ) );
        
        iState = EStateFetching;

        iTempSelection->Reset();
        iTempSelection->AppendL( iService );
        iTempSelection->AppendL( iSelection[lastIndex] );
        iSelection.Remove(lastIndex);
        
        
        iStatus = KRequestPending;
    
        // Filters are not used when performing 'fetch'
        // operation, use normal getmail info instead
        TPckg<TImImap4GetPartialMailInfo> param(iPartialMailInfo);
        iBaseMtm->SwitchCurrentEntryL( iService );
        iOperation = iBaseMtm->InvokeAsyncFunctionL(
                KIMAP4MTMPopulateMailSelectionWhenAlreadyConnected, 
                *iTempSelection, param, this->iStatus);
        iState = EStateInfoEntryChange;
        SetActive();
        }
    else
        {
        iState = EStateIdle;
        CompleteObserver();
        }
    }

// End of File
