mmappcomponents/mmmtpdataprovider/mmmtpdprequestprocessor/src/csendobject.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 17 Dec 2009 08:55:47 +0200
changeset 0 a2952bb97e68
child 8 bee149131e4b
permissions -rw-r--r--
Revision: 200949 Kit: 200951

/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:  Implement the operation: SendObjectInfo/SendObjectPropList/SendObject
*
*/


#include <mtp/mmtpdataproviderframework.h>
#include <mtp/mmtpobjectmgr.h>
#include <mtp/cmtptypestring.h>
#include <mtp/cmtptypearray.h>
#include <mtp/cmtptypeobjectinfo.h>
#include <mtp/cmtptypefile.h>
#include <mtp/mmtpstoragemgr.h>
#include <mtp/cmtpobjectmetadata.h>
#include <bautils.h>
#include <mtp/cmtptypeobjectproplist.h>

#include "csendobject.h"
#include "mmmtpdpconfig.h"
#include "mmmtpdputility.h"
#include "tmmmtpdppanic.h"
#include "mmmtpdplogger.h"
#include "cmmmtpdpmetadataaccesswrapper.h"

// Verification data for the SendObjectInfo request
const TMTPRequestElementInfo KMTPSendObjectInfoPolicy[] =
    {
        {
        TMTPTypeRequest::ERequestParameter1,
        EMTPElementTypeStorageId,
        EMTPElementAttrWrite,
        1,
        0,
        0
        },

        {
        TMTPTypeRequest::ERequestParameter2,
        EMTPElementTypeObjectHandle,
        EMTPElementAttrDir | EMTPElementAttrWrite,
        2,
        KMTPHandleAll,
        KMTPHandleNone
        }
    };

// -----------------------------------------------------------------------------
// CSendObject::~CSendObject
// Destructor
// -----------------------------------------------------------------------------
//
EXPORT_C CSendObject::~CSendObject()
    {
    if ( ( iProgress == EObjectInfoSucceed
            || iProgress == EObjectInfoFail
            || iProgress == EObjectInfoInProgress )
        && !iNoRollback )
        {
        // Not finished SendObjectInfo \ SendObject pair detected.
        Rollback();
        PRINT( _L( "MM MTP <> CSendObject::~CSendObject, Rollback" ) );
        }

    delete iFileReceived;
    delete iParentSuid;
    delete iObjectInfo;
    delete iObjectPropList;
    delete iDateMod;
    delete iReceivedObjectInfo;

    PRINT( _L( "MM MTP <= CSendObject::~CSendObject" ) );
    }

// -----------------------------------------------------------------------------
// CSendObject::CSendObject
// Standard C++ Constructor
// -----------------------------------------------------------------------------
//
EXPORT_C CSendObject::CSendObject( MMTPDataProviderFramework& aFramework,
    MMTPConnection& aConnection,
    MMmMtpDpConfig& aDpConfig ) :
        CRequestProcessor( aFramework, aConnection, 0, NULL),
        iFs( iFramework.Fs() ),
        iObjectMgr( iFramework.ObjectMgr() ),
        iDpConfig( aDpConfig )
    {
    PRINT( _L( "Operation: SendObjectInfo/SendObject/SendObjectPropList(0x100C/0x100D/0x9808)" ) );
    }

// -----------------------------------------------------------------------------
// CSendObject::ConstructL
// 2nd Phase Constructor
// -----------------------------------------------------------------------------
//
EXPORT_C void CSendObject::ConstructL()
    {
    PRINT( _L( "MM MTP => CSendObject::ConstructL" ) );

    iExpectedSendObjectRequest.SetUint16( TMTPTypeRequest::ERequestOperationCode,
        EMTPOpCodeSendObject );

    iReceivedObjectInfo = CMTPObjectMetaData::NewL();
    iReceivedObjectInfo->SetUint( CMTPObjectMetaData::EDataProviderId,
        iFramework.DataProviderId() );

    PRINT1( _L( "MM MTP <> CSendObject::ConstructL DataProviderId = 0x%x" ), iFramework.DataProviderId());

    iNoRollback = EFalse;

    SetPSStatus();
    PRINT( _L( "MM MTP <= CSendObject::ConstructL" ) );
    }

// -----------------------------------------------------------------------------
// CSendObject::Match
// Override to match both the SendObjectInfo and SendObject requests
// @param aRequest    The request to match
// @param aConnection The connection from which the request comes
// @return ETrue if the processor can handle the request, otherwise EFalse
// -----------------------------------------------------------------------------
//
EXPORT_C TBool CSendObject::Match( const TMTPTypeRequest& aRequest,
    MMTPConnection& aConnection ) const
    {
    TBool result = EFalse;

    TUint16 operationCode = aRequest.Uint16( TMTPTypeRequest::ERequestOperationCode );
    if ( ( operationCode == EMTPOpCodeSendObjectInfo
            || operationCode == EMTPOpCodeSendObject
            || operationCode == EMTPOpCodeSendObjectPropList )
            && ( &iConnection == &aConnection ) )
        {
        result = ETrue;
        }

    return result;
    }

// -----------------------------------------------------------------------------
// CSendObject::CheckSendingState
// Helper Functions
// Verify if the SendObject request comes after SendObjectInfo request
// @return EMTPRespCodeOK if SendObject request comes after a valid SendObjectInfo request, otherwise
// EMTPRespCodeNoValidObjectInfo
// -----------------------------------------------------------------------------
//
TMTPResponseCode CSendObject::CheckSendingStateL()
    {
    PRINT( _L( "MM MTP => CSendObject::CheckSendingState" ) );

    TMTPResponseCode result = EMTPRespCodeOK;
    iOperationCode = Request().Uint16( TMTPTypeRequest::ERequestOperationCode );
    PRINT1( _L( "MM MTP <> CSendObject iOperationCode = 0x%x" ), iOperationCode );

    if ( iOperationCode == EMTPOpCodeSendObject )
        {
        // In ParseRouter everytime SendObject gets resolved then will be removed from Registry
        // right away therefore we need reRegister it here again in case possible cancelRequest
        // against this SendObject being raised.
        iExpectedSendObjectRequest.SetUint32( TMTPTypeRequest::ERequestSessionID,
            iSessionId );
        iFramework.RouteRequestRegisterL( iExpectedSendObjectRequest,
            iConnection );
        }

    if ( iProgress == EObjectNone )
        {
        if ( iOperationCode == EMTPOpCodeSendObject )
            {
            PRINT( _L( "MM MTP <> CSendObject::CheckSendingState  EMTPRespCodeNoValidObjectInfo" ) );
            result = EMTPRespCodeNoValidObjectInfo;
            }
        }
    else if ( iProgress == EObjectInfoSucceed )
        {
        if ( iOperationCode == EMTPOpCodeSendObjectInfo )
            {
            delete iObjectInfo;
            iObjectInfo = NULL;
            iProgress = EObjectNone;
            }
        else if ( iOperationCode == EMTPOpCodeSendObjectPropList )
            {
            delete iObjectPropList;
            iObjectPropList = NULL;
            iProgress = EObjectNone;
            }
        }
    else
        {
        Panic( EMmMTPDpSendObjectStateInvalid );
        }

    PRINT1( _L( "MM MTP <= CSendObject::CheckSendingState result = 0x%x" ), result );

    return result;
    }

// -----------------------------------------------------------------------------
// CSendObject::CheckRequestL
// Verify the reqeust
// -----------------------------------------------------------------------------
//
EXPORT_C TMTPResponseCode CSendObject::CheckRequestL()
    {
    PRINT( _L( "MM MTP => CSendObject::CheckRequestL" ) );

    TMTPResponseCode responseCode = CheckSendingStateL();

    if ( responseCode != EMTPRespCodeOK )
        {
        return responseCode;
        }

    if ( iProgress == EObjectNone )
    // Only SendObjectInfo/SendObjectPropList's request phase will enter into this function,
    // otherwise, state machine of fw should be wrong.
        {
        iElementCount = sizeof( KMTPSendObjectInfoPolicy ) / sizeof( TMTPRequestElementInfo );
        iElements = KMTPSendObjectInfoPolicy;
        }
    else if ( iProgress == EObjectInfoSucceed )
        {
        iElementCount = 0;
        iElements = NULL;
        }

    if ( iElements != NULL )
        {
        responseCode = CRequestProcessor::CheckRequestL();
        if ( responseCode != EMTPRespCodeOK )
            {
            return responseCode;
            }

        // Reserve storageId and parent into member data variables if they are matched.
        responseCode = MatchStoreAndParentL();
        if ( responseCode != EMTPRespCodeOK )
            {
            return responseCode;
            }

        if ( iOperationCode == EMTPOpCodeSendObjectPropList )
            {
            // check if it is what dp supported
            iObjectFormat = Request().Uint32( TMTPTypeRequest::ERequestParameter3 );
            if ( iObjectFormat != KMTPFormatsAll )
                {
                responseCode = EMTPRespCodeInvalidObjectFormatCode;

                const RArray<TUint>* format = iDpConfig.GetSupportedFormat();
                TInt count = format->Count();

                for ( TInt i = 0; i < count; i++ )
                    {
                    if ( iObjectFormat == ( *format )[i] )
                        {
                        responseCode = EMTPRespCodeOK;
                        break;
                        }
                    }
                if ( responseCode != EMTPRespCodeOK )
                    {
                    return responseCode;
                    }
                } // end of if ( iObjectFormat != KMTPFormatsAll )

            // check object size
            TUint32 objectSizeHigh = Request().Uint32( TMTPTypeRequest::ERequestParameter4 );
            TUint32 objectSizeLow = Request().Uint32( TMTPTypeRequest::ERequestParameter5 );
            iObjectSize = MAKE_TUINT64( objectSizeHigh, objectSizeLow );
            PRINT1( _L( "MM MTP <> CSendObject::CheckRequestL iObjectSize = %Lu" ), iObjectSize );

            if ( IsTooLarge( iObjectSize ) )
                {
                responseCode = EMTPRespCodeObjectTooLarge;
                }

            if ( ( responseCode != EMTPRespCodeOK ) && !CanStoreFileL( iStorageId, iObjectSize ) )
                {
                responseCode = EMTPRespCodeStoreFull;
                }
            }
        }

    PRINT1( _L( "MM MTP <= CSendObject::CheckRequestL, responseCode = 0x%x" ), responseCode );
    return responseCode;
    }

// -----------------------------------------------------------------------------
// CSendObject::HasDataphase
// Exception handling. CRequestProcessor will receive data if this operation
// won't by return ETrue.
// @return ETrue if there is data need to be received from initiator
// -----------------------------------------------------------------------------
//
EXPORT_C TBool CSendObject::HasDataphase() const
    {
    return ETrue;
    }

// -----------------------------------------------------------------------------
// CSendObject::ServiceL
// ServiceL request handler
// -----------------------------------------------------------------------------
//
EXPORT_C void CSendObject::ServiceL()
    {
    PRINT( _L( "MM MTP => CSendObject::ServiceL" ) );

    if ( iProgress == EObjectNone )
        {
        if ( iOperationCode == EMTPOpCodeSendObjectInfo )
            {
            ServiceInfoL();
            }
        else
            {
            ServicePropListL();
            }
        }
    else
        {
        PRINT1( _L( "MM MTP <> CSendObject::ServiceL, iProgress = %d" ), iProgress );
        ServiceObjectL();
        }
    PRINT( _L( "MM MTP <= CSendObject::ServiceL" ) );
    }

// -----------------------------------------------------------------------------
// CSendObject::ServiceInfoL
// ServiceL - Recieves the objectinfo data
// -----------------------------------------------------------------------------
//
void CSendObject::ServiceInfoL()
    {
    PRINT( _L( "MM MTP => CSendObject::ServiceInfoL" ) );

    iObjectInfo = CMTPTypeObjectInfo::NewL();
    ReceiveDataL( *iObjectInfo );
    iProgress = EObjectInfoInProgress;

    PRINT( _L( "MM MTP <= CSendObject::ServiceInfoL" ) );
    }

// -----------------------------------------------------------------------------
// CSendObject::ServicePropListL
// SendObjectPropList
// -----------------------------------------------------------------------------
//
void CSendObject::ServicePropListL()
    {
    PRINT( _L( "MM MTP => CSendObject::ServicePropListL" ) );

    iObjectPropList = CMTPTypeObjectPropList::NewL();
    ReceiveDataL( *iObjectPropList );
    iProgress = EObjectInfoInProgress;

    PRINT( _L( "MM MTP <= CSendObject::ServicePropListL" ) );
    }

// -----------------------------------------------------------------------------
// CSendObject::ServiceObjectL
// SendObject
// -----------------------------------------------------------------------------
//
void CSendObject::ServiceObjectL()
    {
    PRINT( _L( "MM MTP => CSendObject::ServiceObjectL" ) );

    delete iFileReceived;
    iFileReceived = NULL;

    PRINT2( _L( "MM MTP <> CSendObject::ServiceObjectL, iFullPath is %S, iObjectSize: %Lu" ), &iFullPath, iObjectSize );
    TRAPD( err, iFileReceived = CMTPTypeFile::NewL( iFs,
        iFullPath,
        EFileWrite ) );

    PRINT1( _L("MM MTP <> CSendObject::ServiceObjectL, Leave Code is: %d"), err );
    User::LeaveIfError( err );

    iFileReceived->SetSizeL( iObjectSize );

    ReceiveDataL( *iFileReceived );

    iProgress = ESendObjectInProgress;

    PRINT( _L( "MM MTP <= CSendObject::ServiceObjectL" ) );
    }

// -----------------------------------------------------------------------------
// CSendObject::DoHandleResponsePhaseL
// Response Phase Handler
// -----------------------------------------------------------------------------
//
EXPORT_C TBool CSendObject::DoHandleResponsePhaseL()
    {
    PRINT( _L( "MM MTP => CSendObject::DoHandleResponsePhaseL" ) );

    // check if the sending/receiving data is successful
    TBool successful = !iCancelled;
    if ( iProgress == EObjectInfoInProgress )
        {
        if ( iOperationCode == EMTPOpCodeSendObjectInfo )
            {
            successful = DoHandleResponsePhaseInfoL();
            }
        else if ( iOperationCode == EMTPOpCodeSendObjectPropList )
            {
            successful = DoHandleResponsePhasePropListL();
            }
        iProgress = ( successful ? EObjectInfoSucceed : EObjectInfoFail );
        iPreviousOperation = iOperationCode;
        }
    else if ( iProgress == ESendObjectInProgress )
        {
        successful = DoHandleResponsePhaseObjectL();
        iProgress = ( successful ? ESendObjectSucceed : ESendObjectFail );
        }
    PRINT1( _L( "MM MTP <= CSendObject::DoHandleResponsePhaseL iProgress = %d" ), iProgress );

    return EFalse;
    }

// -----------------------------------------------------------------------------
// CSendObject::DoHandleResponsePhaseInfoL
// Handle Response - Checks whether the request was successful
// -----------------------------------------------------------------------------
//
TBool CSendObject::DoHandleResponsePhaseInfoL()
    {
    PRINT( _L( "MM MTP => CSendObject::DoHandleResponsePhaseInfoL" ) );

    TBool result = ETrue;

    // cache the width and height of video file
    iObjectFormat = iObjectInfo->Uint16L( CMTPTypeObjectInfo::EObjectFormat );
    iWidth = iObjectInfo->Uint32L( CMTPTypeObjectInfo::EImagePixWidth );
    iHeight = iObjectInfo->Uint32L( CMTPTypeObjectInfo::EImagePixWidth );
    PRINT3( _L("MM MTP <> CSendObject::DoHandleResponsePhaseInfoL iObjectFormat = 0x%x, iWidth = %d, iHeight = %d"),
        iObjectFormat,
        iWidth,
        iHeight );

    // TODO: dateModified is reserved for extention usage.
    delete iDateMod;
    iDateMod = NULL;
    iDateMod = iObjectInfo->StringCharsL( CMTPTypeObjectInfo::EDateModified ).AllocL();

    // check if storage is full
    iObjectSize = iObjectInfo->Uint32L( CMTPTypeObjectInfo::EObjectCompressedSize );
    PRINT1( _L("MM MTP <> CSendObject::DoHandleResponsePhaseInfoL, iObjectSize = %Lu"), iObjectSize );

    if ( IsTooLarge( iObjectSize ) )
        {
        SendResponseL( EMTPRespCodeObjectTooLarge );
        result = EFalse;
        }

    if ( result && !CanStoreFileL( iStorageId, iObjectSize ) )
        {
        SendResponseL( EMTPRespCodeStoreFull );
        result = EFalse;
        }

    if ( result )
        {
        iProtectionStatus = iObjectInfo->Uint16L( CMTPTypeObjectInfo::EProtectionStatus );
        PRINT1( _L( "MM MTP <> CSendObject::DoHandleResponsePhaseInfoL iProtectionStatus = %d" ), iProtectionStatus );
        if ( iProtectionStatus != EMTPProtectionNoProtection
            && iProtectionStatus != EMTPProtectionReadOnly )
            {
            SendResponseL( EMTPRespCodeParameterNotSupported );
            result = EFalse;
            }
        }

    if ( result )
        {
        result = GetFullPathNameL( iObjectInfo->StringCharsL( CMTPTypeObjectInfo::EFilename ) );
        if ( !result )
            {
            // File and/or parent pathname invalid.
            SendResponseL( EMTPRespCodeInvalidDataset );
            }
        }

    if ( result )
        {
        if ( ExistsL( iFullPath ) )
            {
            // Object with the same name already exists.
            iNoRollback = ETrue;
            SendResponseL( EMTPRespCodeAccessDenied );
            result = EFalse;
            }
        }

    if ( result )
        ReserveObjectL();

    PRINT1( _L( "MM MTP <= CSendObject::DoHandleResponsePhaseInfoL result = %d" ), result );

    return result;
    }

// -----------------------------------------------------------------------------
// CSendObject::DoHandleResponsePhasePropListL
// SendObjectPropList
// -----------------------------------------------------------------------------
//
TBool CSendObject::DoHandleResponsePhasePropListL()
    {
    PRINT( _L("MM MTP => CSendObject::DoHandleResponsePhasePropListL" ) );

    TMTPResponseCode responseCode = EMTPRespCodeOK;

    TInt invalidParameterIndex = KErrNotFound;
    responseCode = VerifyObjectPropListL( invalidParameterIndex );

    if ( responseCode != EMTPRespCodeOK )
        {
        TUint32 parameters[4];
        parameters[0] = 0;
        parameters[1] = 0;
        parameters[2] = 0;
        parameters[3] = invalidParameterIndex;
        SendResponseL( responseCode, 4, parameters );
        }
    else if ( ExistsL( iFullPath ) )
        {
        // Object with the same name already exists.
        iNoRollback = ETrue;
        SendResponseL( EMTPRespCodeAccessDenied );
        }
    else
        ReserveObjectL();

    PRINT( _L( "MM MTP <= CSendObject::DoHandleResponsePhasePropListL" ) );
    return ( responseCode == EMTPRespCodeOK );
    }

// -----------------------------------------------------------------------------
// CSendObject::DoHandleResponsePhaseObjectL
// SendObject
// -----------------------------------------------------------------------------
//
TBool CSendObject::DoHandleResponsePhaseObjectL()
    {
    PRINT( _L( "MM MTP => CSendObject::DoHandleResponsePhaseObjectL" ) );

    TBool result = ETrue;

    delete iFileReceived;
    iFileReceived = NULL;

    TEntry fileEntry;
    User::LeaveIfError( iFs.Entry( iFullPath, fileEntry ) );
    if ( fileEntry.iSize != iObjectSize )
        {
        iFs.Delete( iFullPath );
        iObjectMgr.UnreserveObjectHandleL( *iReceivedObjectInfo );
        TMTPResponseCode responseCode = EMTPRespCodeObjectTooLarge;
        if ( fileEntry.iSize < iObjectSize )
            {
            responseCode = EMTPRespCodeIncompleteTransfer;
            }
        SendResponseL( responseCode );
        result = EFalse;
        }

    // SendObject is cancelled or connection is dropped.
    if ( result && iCancelled )
        {
        iFramework.RouteRequestUnregisterL( iExpectedSendObjectRequest,
            iConnection );
        Rollback();
        SendResponseL( EMTPRespCodeTransactionCancelled );
        }
    else if ( result && !iCancelled )
        {
        if ( iObjectSize > 0 ) // media file
            {
            AddMediaToStoreL();

            if( iPreviousOperation == EMTPOpCodeSendObjectPropList )
                {
                SetObjectPropListL( *iObjectPropList );
                }

            // Commits into MTP data object enumeration store the object handle and
            // storage space previously reserved for the specified object.
            iFramework.ObjectMgr().CommitReservedObjectHandleL( *iReceivedObjectInfo );
            }

        // Commit object to MTP data store
        iFramework.RouteRequestUnregisterL( iExpectedSendObjectRequest,
            iConnection );

        SendResponseL( EMTPRespCodeOK );
        }

    PRINT1( _L( "MM MTP <= CSendObject::DoHandleResponsePhaseObjectL result = %d" ), result );

    return result;
    }

// -----------------------------------------------------------------------------
// CSendObject::DoHandleCompletingPhaseL
// Completeing phase Handler
// -----------------------------------------------------------------------------
//
EXPORT_C TBool CSendObject::DoHandleCompletingPhaseL()
    {
    TBool result = ETrue;

    PRINT( _L( "MM MTP => CSendObject::DoHandleCompletingPhaseL" ) );

    CRequestProcessor::DoHandleCompletingPhaseL();
    //Ensure that, even though the SendObjectInfo was successul, the request responder is not deleted
    if ( iProgress == EObjectInfoSucceed )
        {
        result = EFalse;
        }
    else if ( iProgress == ESendObjectFail )
        {
        //Sending Object failed, but still do not delete request, can try again with current info
        iProgress = EObjectInfoSucceed;
        result = EFalse;
        }

    PRINT2( _L( "MM MTP <= CSendObject::DoHandleCompletingPhaseL iProgress= %d, result = %d" ),
        iProgress,
        result );

    return result;
    }

// -----------------------------------------------------------------------------
// Check if the property list is valid and extract necessary properties
// @param aInvalidParameterIndex if invalid, contains the index of the property.
//        Undefined, if it is valid.
// @return if error, one of the error response code; otherwise EMTPRespCodeOK
// -----------------------------------------------------------------------------
TMTPResponseCode CSendObject::VerifyObjectPropListL( TInt& aInvalidParameterIndex )
    {
    PRINT( _L( "MM MTP => CSendObject::VerifyObjectPropListL" ) );

    TMTPResponseCode responseCode( EMTPRespCodeOK );
    const TInt count = iObjectPropList->NumberOfElements();
    iObjectPropList->ResetCursor();
    for ( TInt i = 0; i < count; i++ )
        {
        const CMTPTypeObjectPropListElement& element( iObjectPropList->GetNextElementL() );
        const TUint32 handle( element.Uint32L( CMTPTypeObjectPropListElement::EObjectHandle ) );
        aInvalidParameterIndex = i;
        if ( handle != KMTPHandleNone )
            {
            responseCode = EMTPRespCodeInvalidObjectHandle;
            break;
            }

        responseCode = CheckPropCodeL( element );
        if ( responseCode != EMTPRespCodeOK )
            {
            break;
            }
        responseCode = ExtractPropertyL( element );
        if ( responseCode != EMTPRespCodeOK )
            {
            break;
            }
        }

    PRINT1( _L( "MM MTP <= CSendObject::VerifyObjectPropListL, responseCode = 0x%X" ), responseCode );
    return responseCode;
    }

// -----------------------------------------------------------------------------
// Validates the data type for a given property code.
// @param aElement an object property list element
// @param aPropertyCode MTP property code for the element
// @return EMTPRespCodeOK if the combination is valid, or another MTP response code if not
// -----------------------------------------------------------------------------
TMTPResponseCode CSendObject::CheckPropCodeL( const CMTPTypeObjectPropListElement& aElement )
    {
    PRINT( _L( "MM MTP => CSendObject::CheckPropCodeL" ) );
    TMTPResponseCode responseCode( EMTPRespCodeOK );

    // Checking if the propCode is supported first then check its type
    const RArray<TUint>* properties = iDpConfig.GetSupportedPropertiesL( iObjectFormat );
    TUint16 propCode = aElement.Uint16L( CMTPTypeObjectPropListElement::EPropertyCode );
    TUint16 dataType = aElement.Uint16L( CMTPTypeObjectPropListElement::EDatatype );
    PRINT2( _L( "MM MTP => CSendObject::CheckPropCodeL propCode = 0x%X, dataType = 0x%X" ), propCode, dataType );

    responseCode = EMTPRespCodeInvalidObjectPropCode;
    const TInt count = properties->Count();
    for ( TInt i = 0; i < count; i++ )
        {
        if ( ( *properties )[i] == propCode )
            {
            responseCode = EMTPRespCodeOK;
            break;
            }
        }

    if ( responseCode != EMTPRespCodeOK )
        return responseCode;

    // TODO: abstractmedia and media dp have different supported propCode, need check common prop code and check others in dp derived processors.
    // also need to check if the propCode is supported
    switch ( propCode )
        {
        case EMTPObjectPropCodeStorageID:
            if ( dataType != EMTPTypeUINT32 )
                {
                responseCode = EMTPRespCodeInvalidObjectPropFormat;
                }
            else if ( iStorageId != aElement.Uint32L( CMTPTypeObjectPropListElement::EValue ) )
                {
                responseCode = EMTPRespCodeInvalidDataset;
                }
            break;

        case EMTPObjectPropCodeObjectFormat:
            if ( dataType != EMTPTypeUINT16 )
                {
                responseCode = EMTPRespCodeInvalidObjectPropFormat;
                }
            else if ( iObjectFormat != aElement.Uint16L( CMTPTypeObjectPropListElement::EValue ) )
                {
                responseCode = EMTPRespCodeInvalidDataset;
                }
            break;

        case EMTPObjectPropCodeObjectSize:
            if ( dataType != EMTPTypeUINT64 )
                {
                responseCode = EMTPRespCodeInvalidObjectPropFormat;
                }
            else if ( iObjectSize != aElement.Uint64L( CMTPTypeObjectPropListElement::EValue ) )
                {
                responseCode = EMTPRespCodeInvalidDataset;
                }
            PRINT1(_L("MM MTP => CSendObject::CheckPropCodeL Checking ObjectSize %d"), responseCode );
            break;

        case EMTPObjectPropCodeParentObject:
            if ( dataType != EMTPTypeUINT32 )
                {
                responseCode = EMTPRespCodeInvalidObjectPropFormat;
                }
            else if ( ( iParentHandle != aElement.Uint32L( CMTPTypeObjectPropListElement::EValue ) )
                || ( KMTPHandleNone != aElement.Uint32L( CMTPTypeObjectPropListElement::EValue ) ) )
                // iParentHandle might be changed in CheckRequestL
                {
                responseCode = EMTPRespCodeInvalidDataset;
                }
            break;

        case EMTPObjectPropCodePersistentUniqueObjectIdentifier:    // read-only
            if ( dataType != EMTPTypeUINT128 )
                {
                responseCode = EMTPRespCodeInvalidObjectPropFormat;
                }
            break;

        case EMTPObjectPropCodeProtectionStatus:
            if ( dataType != EMTPTypeUINT16 )
                {
                responseCode = EMTPRespCodeInvalidObjectPropFormat;
                }
            break;

        case EMTPObjectPropCodeDateCreated:
            // TODO: this property is read-only, should response EMTPRespCodeAccessDenied or set nothing?
        case EMTPObjectPropCodeDateModified:
        case EMTPObjectPropCodeObjectFileName:
        case EMTPObjectPropCodeName:
            if ( dataType != EMTPTypeString )
                {
                responseCode = EMTPRespCodeInvalidObjectPropFormat;
                }
            break;

        case EMTPObjectPropCodeNonConsumable:
            if ( dataType != EMTPTypeUINT8 )
                {
                responseCode = EMTPRespCodeInvalidObjectPropFormat;
                }
            break;

        default:
            // check types of DP specific properties
            // TODO: Is there anything except datatype need to be checked?
            responseCode = CheckSepecificPropType( propCode, dataType );
            break;
        }

    PRINT1( _L( "MM MTP <= CSendObject::CheckPropCode, responseCode = 0x%X" ), responseCode );
    return responseCode;
    }

// -----------------------------------------------------------------------------
// Extracts the file information from the object property list element
// @param aElement an object property list element
// @param aPropertyCode MTP property code for the element
// @return MTP response code
// -----------------------------------------------------------------------------
TMTPResponseCode CSendObject::ExtractPropertyL( const CMTPTypeObjectPropListElement& aElement )
    {
    PRINT( _L ( "MM MTP => CSendObject::ExtractPropertyL" ) );
    TMTPResponseCode responseCode( EMTPRespCodeOK );
    switch ( aElement.Uint16L( CMTPTypeObjectPropListElement::EPropertyCode ) )
        {
        case EMTPObjectPropCodeObjectFileName:
            {
            const TDesC& fileName = aElement.StringL( CMTPTypeObjectPropListElement::EValue );
            if ( !GetFullPathNameL( fileName ) )
                {
                responseCode = EMTPRespCodeInvalidDataset;
                }
            }
            break;

        case EMTPObjectPropCodeProtectionStatus:
            {
            iProtectionStatus = aElement.Uint16L( CMTPTypeObjectPropListElement::EValue );
            if ( iProtectionStatus != EMTPProtectionNoProtection
                && iProtectionStatus != EMTPProtectionReadOnly )
                {
                responseCode = EMTPRespCodeParameterNotSupported;
                }
            }
            break;

        case EMTPObjectPropCodeDateModified:
            delete iDateMod;
            iDateMod = NULL;
            iDateMod = aElement.StringL( CMTPTypeObjectPropListElement::EValue ).AllocL();
            // Cache it for further usage.
            break;

        default:
            // Only extract necessary properties which conform to SendObjectInfo.
            break;
        }

    PRINT1( _L( "MM MTP <= CSendObject::ExtractPropertyL, responseCode = 0x%X" ), responseCode );
    return responseCode;
    }

// -----------------------------------------------------------------------------
// CSendObject::SetObjectPropListL
// Reserve object proplist into database
// -----------------------------------------------------------------------------
//
TMTPResponseCode CSendObject::SetObjectPropListL( const CMTPTypeObjectPropList& aPropList )
    {
    PRINT( _L( "MM MTP => CSendObject::SetObjectPropListL" ) );

    TMTPResponseCode responseCode( EMTPRespCodeOK );

    const TUint count( iObjectPropList->NumberOfElements() );
    iObjectPropList->ResetCursor();
    for ( TInt i = 0; i < count; i++ )
        {
        const CMTPTypeObjectPropListElement& element( iObjectPropList->GetNextElementL() );

        TUint16 propertyCode = element.Uint16L( CMTPTypeObjectPropListElement::EPropertyCode );
        TUint16 dataType = element.Uint16L( CMTPTypeObjectPropListElement::EDatatype );
        PRINT2( _L( "MM MTP <> SetObjectPropListL propertyCode = 0x%x, dataType = 0x%x" ),
            propertyCode, dataType );

        switch ( propertyCode )
            {
            case EMTPObjectPropCodeStorageID:
            case EMTPObjectPropCodeObjectFormat:
            case EMTPObjectPropCodeProtectionStatus:
            case EMTPObjectPropCodeObjectSize:
            case EMTPObjectPropCodeParentObject:
            case EMTPObjectPropCodePersistentUniqueObjectIdentifier:
                // Do nothing for those properties are already set.
                break;

            case EMTPObjectPropCodeNonConsumable:
            case EMTPObjectPropCodeDateAdded:
            case EMTPObjectPropCodeDateCreated:
            case EMTPObjectPropCodeDateModified:
            case EMTPObjectPropCodeObjectFileName:
                // TODO: Does anything need to be done on these read-only properties?
                /* spec:
                 * Object properties that are get-only (0x00 GET)
                 * should accept values during object creation by
                 * way of the SendObjectPropList command.
                 */
                break;

            case EMTPObjectPropCodeName:
                {
                CMTPTypeString* stringData = CMTPTypeString::NewLC( element.StringL( CMTPTypeObjectPropListElement::EValue ) );// + stringData

                responseCode = SetMetaDataToWrapperL( propertyCode,
                    *stringData,
                    *iReceivedObjectInfo );

                CleanupStack::PopAndDestroy( stringData );// - stringData
                }
                break;

            default:
                {
                responseCode = SetSpecificObjectPropertyL( propertyCode,
                    *iReceivedObjectInfo,
                    element );
                }
                break;
            } // end of switch
        } // end of for

    PRINT1( _L( "MM MTP <= CSendObject::SetObjectPropListL responseCode = 0x%x" ), responseCode );
    return responseCode;
    }

// -----------------------------------------------------------------------------
// CSendObject::SetMetaDataToWrapperL
//
// -----------------------------------------------------------------------------
//
EXPORT_C TMTPResponseCode CSendObject::SetMetaDataToWrapperL( const TUint16 aPropCode,
    MMTPType& aNewData,
    const CMTPObjectMetaData& aObjectMetaData )
    {
    TMTPResponseCode resCode = EMTPRespCodeOK;
    TRAPD( err, iDpConfig.GetWrapperL().SetObjectMetadataValueL( aPropCode,
            aNewData,
            aObjectMetaData ) );

    PRINT1( _L("MM MTP <> CSendObject::SetMetaDataToWrapperL err = %d"), err);

    if ( err == KErrNone )
        {
        resCode = EMTPRespCodeOK;
        }
    else if ( err == KErrTooBig )
    // according to the codes of S60
        {
        resCode = EMTPRespCodeInvalidDataset;
        }
    else if ( err == KErrPermissionDenied )
        {
        resCode = EMTPRespCodeAccessDenied;
        }
    else if ( err == KErrNotFound )
        {
        if ( MmMtpDpUtility::HasMetadata( aObjectMetaData.Uint( CMTPObjectMetaData::EFormatCode ) ) )
            SendResponseL( EMTPRespCodeAccessDenied );
        }
    else
        {
        err = HandleSpecificWrapperError( err, aObjectMetaData );

        if ( err != KErrNone )
            resCode = EMTPRespCodeGeneralError;
        }

    PRINT1( _L( "MM MTP <= CSendObject::SetMetaDataToWrapperL resCode = 0x%x" ), resCode );

    return resCode;
    }

// -----------------------------------------------------------------------------
// CSendObject::MatchStoreAndParentL
// -----------------------------------------------------------------------------
//
TMTPResponseCode CSendObject::MatchStoreAndParentL()
    {
    TMTPResponseCode responseCode = EMTPRespCodeOK;

    iStorageId = Request().Uint32( TMTPTypeRequest::ERequestParameter1 );
    iParentHandle = Request().Uint32( TMTPTypeRequest::ERequestParameter2 );
    PRINT2( _L( "MM MTP <> CSendObject::MatchStoreAndParentL, iStorageId = 0x%X, iParentHandle = 0x%X" ),
        iStorageId,
        iParentHandle );

    if ( iStorageId == KMTPStorageDefault )
        {
        iStorageId = iDpConfig.GetDefaultStorageIdL();
        PRINT1( _L( "MM MTP <> CSendObject::GetDefaultStorageIdL, iStorageId = 0x%X" ), iStorageId );
        }

    delete iParentSuid;
    iParentSuid = NULL;

    if( iParentHandle == KMTPHandleNone )   // parentHandle is not used by initiator, set it to root
        {
        iParentHandle = KMTPHandleAll;
        }
    if ( iParentHandle == KMTPHandleAll )   // According to spec, KMTPHandleAll means initiator wish to place in the root
        {
        PRINT( _L( "MM MTP <> CSendObject::MatchStoreAndParentL, iParentSuid = KMTPHandleAll" ) );
        iParentSuid = iFramework.StorageMgr().StorageL( iStorageId ).DesC( CMTPStorageMetaData::EStorageSuid ).AllocL();
        PRINT1( _L( "MM MTP <> CSendObject::MatchStoreAndParentL, iParentSuid = %S" ), iParentSuid );
        }
    else    // parentHandle is specified by initiator
        {
        // does not take owernship
        CMTPObjectMetaData* parentObjInfo = iRequestChecker->GetObjectInfo( iParentHandle );
        __ASSERT_DEBUG( parentObjInfo, Panic( EMmMTPDpObjectNull ) );

        if ( parentObjInfo->Uint( CMTPObjectMetaData::EStorageId ) != iStorageId )
            {
            responseCode = EMTPRespCodeInvalidObjectHandle;
            PRINT( _L( "MM MTP <> CSendObject::MatchStoreAndParentL, STORAGEID DOES NOT MATCH WITH PARENTHANDLE!" ) );
            }
        else
            {
            iParentSuid = parentObjInfo->DesC( CMTPObjectMetaData::ESuid ).AllocL();
            }
        }
    PRINT1( _L( "MM MTP <> CSendObject::MatchStoreAndParentL, iParentSuid = %S" ), iParentSuid );

    if ( ( responseCode == EMTPRespCodeOK ) && !BaflUtils::PathExists( iFramework.Fs(), *iParentSuid ) )
        {
        responseCode = EMTPRespCodeInvalidDataset;
        }

    return responseCode;
    }

// -----------------------------------------------------------------------------
// CSendObject::IsTooLarge
// Check if the object is too large
// @return ETrue if yes, otherwise EFalse
// -----------------------------------------------------------------------------
//
TBool CSendObject::IsTooLarge( TUint32 aObjectSize ) const
    {
    TBool ret = ( aObjectSize > KMaxTInt );
    PRINT2( _L( "MM MTP <> CSendObject::IsTooLarge aObjectSize = %d, ret = %d" ), aObjectSize, ret );
    return ret;
    }

// -----------------------------------------------------------------------------
// CSendObject::CanStoreFileL
// Check if we can store the file on the storage
// @return ETrue if yes, otherwise EFalse
// -----------------------------------------------------------------------------
//
TBool CSendObject::CanStoreFileL( TUint32 aStorageId,
    TInt64 aObjectSize ) const
    {
    PRINT( _L( "MM MTP => CSendObject::CanStoreFileL" ) );

    TBool result = ETrue;
    TVolumeInfo volumeInfo;
    TInt driveNo = iFramework.StorageMgr().DriveNumber( aStorageId );
    User::LeaveIfError( iFs.Volume( volumeInfo, driveNo ) );

    if ( volumeInfo.iFree < aObjectSize )
        {
        result = EFalse;
        }

    PRINT1( _L( "MM MTP <= CSendObject::CanStoreFileL , result = %d" ), result );

    return result;
    }

// -----------------------------------------------------------------------------
// CSendObject::GetFullPathNameL
// Get the full path name of the object to be saved
// @param aFileName, on entry, contains the file name of the object,
// on return, contains the full path name of the object to be saved
// -----------------------------------------------------------------------------
//
TBool CSendObject::GetFullPathNameL( const TDesC& aFileName )
    {
    PRINT1( _L("MM MTP => CSendObject::GetFullPathNameL aFileName = %S"), &aFileName );

    TBool result( EFalse );
    if ( aFileName.Length() > 0 )
        {
        iFullPath.Zero();
        iFullPath.Append( *iParentSuid );
        if ( ( iFullPath.Length() + aFileName.Length() ) < KMaxFileName )
            {
            iFullPath.Append( aFileName );
            PRINT1( _L( "MM MTP <> CSendObject::GetFullPathNameL iFullPath = %S" ), &iFullPath );
            result = iFramework.Fs().IsValidName( iFullPath );
            }
        }
    if ( result && ( iObjectFormat != MmMtpDpUtility::FormatFromFilename( iFullPath ) ) )
        {
        PRINT2( _L( "MM MTP <> %S does not match 0x%x" ), &iFullPath, iObjectFormat );
        result = EFalse;
        }

    PRINT1( _L( "MM MTP <= CSendObject::GetFullPathNameL result = %d" ), result );

    return result;
    }

// -----------------------------------------------------------------------------
// CSendObject::ExistsL
// Check if the file already exists on the storage.
// -----------------------------------------------------------------------------
//
TBool CSendObject::ExistsL( const TDesC& aName ) const
    {
    PRINT1( _L( "MM MTP => CSendObject::Exists aName = %S" ), &aName );
    // This detects both files and folders
    TBool ret( EFalse );
    ret = BaflUtils::FileExists( iFramework.Fs(), aName );

#ifdef MMMTPDP_REPLACE_EXIST_FILE
    if( ret )
        {
        // delete the old one and replace
        TInt delErr = iFramework.Fs().Delete( aName );
        PRINT1( _L( "MM MTP <> CSendObject::Exists delErr = %d" ), delErr );
        // delete from the metadata DB
        TRAPD( err, iFramework.ObjectMgr().RemoveObjectL( aName ) );
        PRINT1( _L( "MM MTP <> CSendObject::Exists err = %d" ), err );
        if( err == KErrNone )
            {
            // do nothing, ignore warning
            }
        // delete from video/mpx DB
        CMTPObjectMetaData* objectInfo = CMTPObjectMetaData::NewLC(); // + objectInfo
        if ( iFramework.ObjectMgr().ObjectL( aName, *objectInfo ) )
            {
            TRAP_IGNORE( iWrapper.DeleteObjectL( aName,
                    objectInfo->Uint( CMTPObjectMetaData::EFormatCode ) ) );
            }
        CleanupStack::PopAndDestroy( objectInfo ); // - objectInfo
        ret = EFalse;
        }
#endif
    PRINT1( _L( "MM MTP <= CSendObject::Exists ret = %d" ), ret );
    return ret;
    }

// -----------------------------------------------------------------------------
// CSendObject::ReserveObjectL
// -----------------------------------------------------------------------------
//
void CSendObject::ReserveObjectL()
    {
    PRINT( _L( "MM MTP => CSendObject::ReserveObjectL" ) );
    TInt err = KErrNone;

    iReceivedObjectInfo->SetUint( CMTPObjectMetaData::EStorageId, iStorageId );
    iReceivedObjectInfo->SetUint( CMTPObjectMetaData::EParentHandle,
        iParentHandle );
    iReceivedObjectInfo->SetDesCL( CMTPObjectMetaData::ESuid, iFullPath );
    iReceivedObjectInfo->SetUint( CMTPObjectMetaData::EFormatCode,
        iObjectFormat );

    // Reserves space for and assigns an object handle to the object described
    // by the specified object information record.
    TRAP( err, iObjectMgr.ReserveObjectHandleL( *iReceivedObjectInfo,
                iObjectSize ) );

    PRINT2( _L( "MM MTP => CSendObject::ReserveObjectL iObjectsize = %Lu, Operation: 0x%x" ), iObjectSize, iOperationCode );
    if ( err != KErrNone )
        PRINT1( _L( "MM MTP <> CSendObject::ReserveObjectL err = %d" ), err );
    if ( iObjectSize == 0 )
        {
        SaveEmptyFileL();
        iObjectMgr.CommitReservedObjectHandleL( *iReceivedObjectInfo );
        }

    iExpectedSendObjectRequest.SetUint32( TMTPTypeRequest::ERequestSessionID,
        iSessionId );
    iFramework.RouteRequestRegisterL( iExpectedSendObjectRequest, iConnection );

    TUint32 parameters[3];
    parameters[0] = iStorageId;
    parameters[1] = iParentHandle;
    parameters[2] = iReceivedObjectInfo->Uint( CMTPObjectMetaData::EHandle );
    SendResponseL( EMTPRespCodeOK, 3, parameters );

    PRINT( _L( "MM MTP <= CSendObject::ReserveObjectL" ) );
    }

// -----------------------------------------------------------------------------
// CSendObject::SetProtectionStatusL
// -----------------------------------------------------------------------------
//
void CSendObject::SetProtectionStatusL()
    {
    PRINT1( _L( "MM MTP => CSendObject::SetProtectionStatusL iProtectionStatus = %d" ), iProtectionStatus );

    if ( iProtectionStatus == EMTPProtectionNoProtection
        || iProtectionStatus == EMTPProtectionReadOnly )
        {
        // TODO: wait for review
        TInt err = KErrNone;
        if ( iProtectionStatus == EMTPProtectionNoProtection )
            {
            iFs.SetAtt( iFullPath, KEntryAttNormal, KEntryAttReadOnly );
            }
        else
            {
            iFs.SetAtt( iFullPath, KEntryAttReadOnly, KEntryAttNormal );
            }
        User::LeaveIfError( err );
        }
    PRINT( _L( "MM MTP <= CSendObject::SetProtectionStatusL" ) );
    }

// -----------------------------------------------------------------------------
// CSendObject::SaveEmptyFileL
// -----------------------------------------------------------------------------
//
void CSendObject::SaveEmptyFileL()
    {
    PRINT( _L( "MM MTP => CSendObject::SaveEmptyFileL" ) );

    RFile file;
    User::LeaveIfError( file.Create( iFs, iFullPath, EFileWrite ) );
    file.Close();

    // set entry protection status and modified date
    SetProtectionStatusL();

    // add playlist to MPX DB
    TParsePtrC parse( iFullPath );
    iDpConfig.GetWrapperL().SetStorageRootL( parse.Drive() );
    iDpConfig.GetWrapperL().AddObjectL( iFullPath );

    if ( EMTPFormatCodeAbstractAudioVideoPlaylist == iObjectFormat )
        {
        TInt err = KErrNone;
        err = iFs.SetAtt( iFullPath,
            KEntryAttSystem | KEntryAttHidden,
            KEntryAttReadOnly | KEntryAttNormal );
        if ( err != KErrNone )
            PRINT1( _L( "MM MTP <> CSendObject::SaveEmptyFileL err = %d" ), err );
        iDpConfig.GetWrapperL().AddDummyFileL( iFullPath );
        }

    PRINT( _L( "MM MTP <= CSendObject::SaveEmptyFileL" ) );
    }

// -----------------------------------------------------------------------------
// CSendObject::AddMediaToStoreL()
//
// -----------------------------------------------------------------------------
//
void CSendObject::AddMediaToStoreL()
    {
    PRINT( _L( "MM MTP => CSendObject::AddMediaToStoreL" ) );

    TBool isVideo = EFalse;
    switch ( iObjectFormat )
        {
        case EMTPFormatCode3GPContainer:
        case EMTPFormatCodeMP4Container:
        case EMTPFormatCodeASF:
            {
            TMmMtpSubFormatCode subFormatCode;

            if ( MmMtpDpUtility::IsVideoL( iFullPath ) )
                {
                subFormatCode = EMTPSubFormatCodeVideo;
                isVideo = ETrue;
                }
            else
                {
                subFormatCode = EMTPSubFormatCodeAudio;
                isVideo = EFalse;
                }

            iReceivedObjectInfo->SetUint( CMTPObjectMetaData::EFormatSubCode,
                ( TUint ) subFormatCode );
            }
            break;

            // put all just video format codes here
        case EMTPFormatCodeWMV:
            {
            isVideo = ETrue;
            }
            break;

        default:
            PRINT( _L( "MM MTP <> CSendObject::DoHandleResponsePhaseObjectL default" ) );
            break;
        }

    TPtrC suid( iReceivedObjectInfo->DesC( CMTPObjectMetaData::ESuid ) );
    PRINT1( _L( "MM MTP <> CSendObject::AddMediaToStoreL suid = %S" ), &suid );
    TParsePtrC parse( suid );
    iDpConfig.GetWrapperL().SetStorageRootL( parse.Drive() );
    iDpConfig.GetWrapperL().AddObjectL( iFullPath, isVideo );

    if ( isVideo )
        {
        TInt err = KErrNone;
            TRAP( err, iDpConfig.GetWrapperL().SetImageObjPropL( iFullPath, iWidth, iHeight ) );

        PRINT1( _L( "MM MTP <= CSendObject::AddVideoToStoreL err = %d" ), err );
        }

    PRINT( _L( "MM MTP <= CSendObject::AddMediaToStoreL" ) );
    }

// -----------------------------------------------------------------------------
// CSendObject::UsbDisconnect
//
// -----------------------------------------------------------------------------
//
EXPORT_C void CSendObject::UsbDisconnect()
    {
    PRINT( _L( "MM MTP => CSendObject::UsbDisconnect" ) );
    Rollback();
    PRINT( _L( "MM MTP <= CSendObject::UsbDisconnect" ) );
    }

// -----------------------------------------------------------------------------
// CSendObject::Rollback()
// delete the file, which transfer incompletely
// -----------------------------------------------------------------------------
//
void CSendObject::Rollback()
    {
    // Delete this object from file system.
    if ( iProgress == ESendObjectInProgress )
        {
        PRINT1( _L( "MM MTP <> CSendObject::Rollback ROLLBACK_FILE %S" ), &iFullPath );
        iFramework.Fs().Delete( iFullPath );
            TRAP_IGNORE( iFramework.ObjectMgr().UnreserveObjectHandleL( *iReceivedObjectInfo ) );
        iProgress = EObjectNone;
        }
    }

// end of file