xdmprotocols/XcapProtocol/src/XcapDirectory.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:23:14 +0100
branchRCL_3
changeset 35 fbd2e7cec7ef
parent 0 c8caa15ef882
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201027 Kit: 201035

/*
* Copyright (c) 2005 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: CXcapDirectory
*
*/




// INCLUDE FILES
#include <utf.h>
#include <f32file.h>
#include "XcapAppUsageDef.h"
#include "XdmProtocol.h"
#include "XcapDocument.h"
#include "XcapProtocol.h"
#include "XcapAppUsage.h"
#include "XcapRetrieval.h"
#include "XcapDirectory.h"
#include "XdmXmlParser.h"
#include "XcapHttpReqGet.h"
#include "XdmDocumentNode.h"
#include "XdmNodeAttribute.h"
#include "XcapHttpTransport.h"
#include "XdmOperationFactory.h"

// ----------------------------------------------------------
// CXcapDirectory::CXcapDirectory
// 
// ----------------------------------------------------------
//
CXcapDirectory::CXcapDirectory( CXdmDocument*& aDirectoryDoc,
                                CXdmEngine& aXdmEngine,
                                CXcapProtocol& aXcapProtocol ) :
                                CXdmDirectory( aXdmEngine ),
                                iDirectoryDoc( ( CXcapDocument* )aDirectoryDoc ),
                                iXcapProtocol( aXcapProtocol )                                             
    { 
    }

// ----------------------------------------------------------
// CXcapDirectory::NewL
// 
// ----------------------------------------------------------
//
CXcapDirectory* CXcapDirectory::NewL( const TDesC& aAUID,
                                      CXdmEngine& aXdmEngine,
                                      CXdmDocument*& aDirectoryDoc,
                                      CXcapProtocol& aXcapProtocol )
    {
    CXcapDirectory* self = new ( ELeave ) CXcapDirectory( aDirectoryDoc, aXdmEngine, aXcapProtocol );
    CleanupStack::PushL( self );
    self->ConstructL( aAUID );
    CleanupStack::Pop();
    return self;
    }

// ----------------------------------------------------
// CXcapDirectory::~CXcapDirectory
// 
// ----------------------------------------------------
//
CXcapDirectory::~CXcapDirectory()
    {
    #ifdef _DEBUG
        iXcapProtocol.WriteToLog( _L8( "CXcapDirectory::~CXcapDirectory()" ) );
    #endif
    Cancel();
    delete iAUID;
    delete iDirectoryDoc;
    delete iHttpRetrieval;
    iUpdateList.Close();
    iDocumentList.Close();
    }
    
// ----------------------------------------------------------
// CXcapDirectory::ConstructL
// 
// ----------------------------------------------------------
//
void CXcapDirectory::ConstructL( const TDesC& aAUID )
    {
    if( aAUID.Length() > 0 )
        {
        _LIT( KNodePath,    "xcap-directory/folder" );
        iAUID = HBufC::NewL( aAUID.Length() );
        iAUID->Des().Copy( aAUID );
        CXdmDocumentNode* node = iDirectoryDoc->DocumentSubsetL( KNodePath );
        CleanupStack::PushL( node );
        CXdmNodeAttribute* auid = node->CreateAttributeL( KAuidAttribute );
        CleanupStack::PushL( auid );
        auid->SetAttributeValueL( aAUID );
        iDirectoryDoc->FetchDataL( node );
        //Set the option that prohibits caching
        iDirectoryDoc->SetOption( KXdmOption3 );
        CleanupStack::Pop( 2 );  //auid, node
        }
    else iDirectoryDoc->FetchDataL();
    CActiveScheduler::Add( this );
    }

// ----------------------------------------------------------
// CXcapDirectory::StartUpdateL
// 
// ----------------------------------------------------------
//
void CXcapDirectory::StartUpdateL()
    
    {
    #ifdef _DEBUG
        iXcapProtocol.WriteToLog( _L8( "CXcapDirectory::StartUpdateL()" ) );
    #endif
    switch( iUpdatePhase )
        {
        case EDirPhaseIdle:
            User::RequestComplete( iClientStatus, KErrArgument );
            break;
        case EUpdateDocumentList:
            HandleDocumentListRequestL();
            break;
        case ERefreshDocuments:
            HandleRefreshRequestL();
            break;
        default:
            break;
        } 
    }

// ----------------------------------------------------------
// CXcapDirectory::SaveRequestData
// 
// ----------------------------------------------------------
//
void CXcapDirectory::SaveRequestData( TDirUpdatePhase aUpdatePhase,
                                      TRequestStatus& aClientStatus )
    {
    iUpdatePhase = aUpdatePhase;
    iClientStatus = &aClientStatus;
    }
    
// ----------------------------------------------------
// CXcapDirectory::HandleDocumentListRequestL
// 
// ----------------------------------------------------
//
void CXcapDirectory::HandleDocumentListRequestL()
    {
    #ifdef _DEBUG
        iXcapProtocol.WriteToLog( _L8( "CXcapDirectory::HandleDocumentListRequestL()" ) );
    #endif
    if( !IsActive() )
        {
        CXcapDocument* doc = ( CXcapDocument* )iDirectoryDoc;
        doc->StartInternalL( iStatus );
        iUpdatePhase = EUpdateDocumentList;
        SetActive();
        }
    }
    
// ----------------------------------------------------
// CXcapDirectory::HandleRefreshRequestL
// 
// ----------------------------------------------------
//
void CXcapDirectory::HandleRefreshRequestL()
    {
    #ifdef _DEBUG
        iXcapProtocol.WriteToLog( _L8( "CXcapDirectory::HandleRefreshRequestL()" ) );
    #endif
    if( iUpdatePhase == EUpdateDocumentList )
        {
        if( iUpdateList.Count() > 0 )
            {
            iUpdateIndex = -1;
            iHttpRetrieval = iXcapProtocol.Transport().GetL( TPtrC() );
            UpdateNextDocumentL();
            iUpdatePhase = ERefreshDocuments;
            }
        else
            {
            #ifdef _DEBUG
                iXcapProtocol.WriteToLog( _L8( "  All documents are up to date" ) );
            #endif
            User::RequestComplete( iClientStatus, KErrNone );
            }
        }
    else
        {
        #ifdef _DEBUG
            iXcapProtocol.WriteToLog( _L8( "  Wrong state [%d]" ), iUpdatePhase );
        #endif
        User::RequestComplete( iClientStatus, KErrNotReady );
        }
    }

// ----------------------------------------------------
// CXcapDirectory::UpdateNextDocumentL
// 
// ----------------------------------------------------
//
void CXcapDirectory::UpdateNextDocumentL()
    {
    #ifdef _DEBUG
        iXcapProtocol.WriteToLog( _L8( "CXcapDirectory::UpdateNextDocumentL()" ) );
    #endif
    iUpdateIndex++;
    if( iUpdateIndex < iUpdateList.Count() )
        {
        CXdmDocumentNode* node = iUpdateList[iUpdateIndex];
        #ifdef _DEBUG
            iXcapProtocol.WriteToLog( _L8( "  Index: %d  Document: %x" ), iUpdateIndex, node );
        #endif
        TPtrC8 root = iXcapProtocol.Transport().RootUri();
        TPtrC docUri( ExtractDocumentUriL( root, node ) );
        HBufC* uri = HBufC::NewLC( root.Length() + docUri.Length() );
        uri->Des().Copy( root );
        uri->Des().Append( docUri );
        iHttpRetrieval->ResetUriL( uri->Des() );
        iHttpRetrieval->SetExpiryTimeL( NULL, KDefaultHttpRequestTimeout * 1000000 );
        iHttpRetrieval->DispatchRequestL( iStatus );
        CleanupStack::PopAndDestroy();  //uri
        SetActive();
        }
    else
        {
        #ifdef _DEBUG
            iXcapProtocol.WriteToLog( _L8( "  Directory sync complete" ) );
        #endif
        User::RequestComplete( iClientStatus, KErrNone );
        }
    }

// ---------------------------------------------------------
// CXcapDirectory::RunL()
// 
// ---------------------------------------------------------
//
void CXcapDirectory::RunL()
    {
    #ifdef _DEBUG
        iXcapProtocol.WriteToLog( _L8( "CXcapDirectory::RunL() - Request: %d" ), iStatus.Int() );
    #endif
    if( iStatus == KErrNone )
        {
        switch( iUpdatePhase )
            {
            case EUpdateDocumentList:
                {
                iDocumentCount = iDirectoryDoc->Find( KDirectoryEntry, iDocumentList );
                if( iDocumentCount > 0 )
                    {
                    TInt index = 0;
                    while( index < iDocumentCount )
                        {
                        TBool uptodate = CheckLocalCopyL( iDocumentList[index] );
                        #ifdef _DEBUG
                            iXcapProtocol.WriteToLog( _L8( "  Cache: %d" ), uptodate );
                        #endif
                        if( !uptodate )
                            User::LeaveIfError( iUpdateList.Append( iDocumentList[index] ) );
                        index++;
                        }
                    }
                User::RequestComplete( iClientStatus, iStatus.Int() );
                }
                break;
            case ERefreshDocuments:
                {
                CXdmDocumentNode* node = iUpdateList[iUpdateIndex];
                #ifdef _DEBUG
                    iXcapProtocol.WriteToLog( _L8( "  Index:    %d" ), iUpdateIndex );
                    iXcapProtocol.WriteToLog( _L8( "  Document: %x" ), node );
                    iXcapProtocol.WriteToLog( _L8( "  Error:    %d" ), iStatus.Int() );
                #endif
                TPtrC8 root = iXcapProtocol.Transport().RootUri();
                TPtrC docName = ExtractDocumentUriL( root, node );
                TXdmCompletionData* data = iHttpRetrieval->ResponseData();
                TPtrC8 responseData( data->iResponseData->Des() );
                TPtrC8 eTag( data->iETag->Des() );
                RXcapCache* cache = iXcapProtocol.Cache();
                cache->Store( eTag, docName, root, responseData  );
                iHttpRetrieval->ReleaseResponseData();
                UpdateNextDocumentL();
                }
                break;
            default:
                #ifdef _DEBUG
                    iXcapProtocol.WriteToLog( _L8( "  Default case, unknown state %d - Status: %d" ),
                                               iUpdatePhase, iStatus.Int() );
                #endif
                if( iClientStatus != NULL )
                    User::RequestComplete( iClientStatus, KErrUnknown );  
                break;
            }   
        }
    else
        {
        #ifdef _DEBUG
            iXcapProtocol.WriteToLog( _L8( "  Operation failed with %d" ), iStatus.Int() );
        #endif
        User::RequestComplete( iClientStatus, iStatus.Int() );
        }
    }

// ---------------------------------------------------------
// CXcapDirectory::CheckLocalCopyL
// 
// ---------------------------------------------------------
//
TBool CXcapDirectory::CheckLocalCopyL( const CXdmDocumentNode* aDocumentNode )
    {
    /*#ifdef _DEBUG
        iXcapProtocol.WriteToLog( _L8( "CXcapDirectory::CheckLocalCopyL()" ) );
    #endif*/
    TBool ret = EFalse;
    TPtrC8 root = iXcapProtocol.Transport().RootUri();
    TPtrC docName = ExtractDocumentUriL( root, aDocumentNode );
    TPtrC etag( aDocumentNode->Attribute( KDocumentETag )->AttributeValue() );
    HBufC8* etag8 = CnvUtfConverter::ConvertFromUnicodeToUtf8L( etag );
    CleanupStack::PushL( etag8 );
    RXcapCache* cache = iXcapProtocol.Cache();
    ret = cache != NULL ? cache->IsCurrent( etag8->Des(), docName, root ) == KErrNone : ETrue;
    CleanupStack::PopAndDestroy();  //etag8
    return ret;
    }

// ---------------------------------------------------------
// CXcapDirectory::ExtractDocumentUriL
// 
// ---------------------------------------------------------
//
TPtrC CXcapDirectory::ExtractDocumentUriL( const TDesC8& aRootUri,
                                           const CXdmDocumentNode* aDocumentNode )
    {
    /*#ifdef _DEBUG
        iXcapProtocol.WriteToLog( _L8( "CXcapDirectory::ExtractDocumentUri()" ) );
    #endif*/
    const TUint8 KHttpHostSeparator = 47;
    _LIT8( KHttpDoubleHostSeparator,  "//" );
    TPtrC uri( aDocumentNode->Attribute( KDocumentUri )->AttributeValue() );
    if( uri[0] == KHttpHostSeparator ) //Relative URI
        return uri;
    else
        {
        TInt index = aRootUri.Find( KHttpDoubleHostSeparator );
        TPtrC8 root( aRootUri.Right( aRootUri.Length() - index - 2 ) );
        HBufC8* uri8 = CnvUtfConverter::ConvertFromUnicodeToUtf8L( uri );
        CleanupStack::PushL( uri8 );
        TPtr8 desc( uri8->Des() );
        index = desc.Find( root );
        CleanupStack::PopAndDestroy();  //uri8
        return index >= 0 ? uri.Right( uri.Length() - root.Length() - index ) : TPtrC();
        }
    }

// ----------------------------------------------------
// CXcapDirectory::DocumentCount
// 
// ----------------------------------------------------
//
TInt CXcapDirectory::DocumentCount()
    {
    return iDocumentCount;
    }

// ----------------------------------------------------
// CXcapDirectory::DocumentType
// 
// ----------------------------------------------------
//
TXdmDocType CXcapDirectory::DocumentTypeL( TInt aIndex ) const
    {
    TXdmDocType type = EXdmDocGeneral;
    if( iUpdatePhase <= EDirPhaseIdle )
        User::Leave( KErrNotReady );
    else if( iDocumentCount > 0 && ( aIndex >= 0 && aIndex < iDocumentCount ) )
        type = FindAUID( *iDocumentList[aIndex] );
    return type;
    } 

// ----------------------------------------------------
// CXcapDirectory::FindAUID
// 
// ----------------------------------------------------
//
TXdmDocType CXcapDirectory::FindAUID( const CXdmDocumentNode& aEntryNode ) const
    {
    TXdmDocType documentType = EXdmDocGeneral;
    HBufC8* buf = aEntryNode.Attribute( KDocumentUri )->EightBitValueLC();
    if( buf )
        {
        TPtrC8 uri( buf->Des() );
        if( uri.Find( KXdmCapabilityUsageAUID ) >= 0 )
            documentType = EXdmCapabilities;
        else if( uri.Find( KXdmPocUserAccessUsageAUID ) >= 0 )
            documentType = EXdmPoCUserAccessPolicy;
        else if( uri.Find( KXdmPocGroupUsageAUID ) >= 0 )
            documentType = EXdmPoCGroup;
        else if( uri.Find( KXdmResourceListsUsageAUID ) >= 0 )
            documentType = EXdmResourceLists;
        else if( uri.Find( KXdmOmaPresRulesUsageAUID ) >= 0 )
            documentType = EXdmIetfPresenceRules;
        else if( uri.Find( KXdmDirectoryUsageAUID ) >= 0 )
            documentType = EXdmDirectory;
        else if( uri.Find( KXdmSharedXDMUsageAUID ) >= 0 )
            documentType = EXdmSharedXdm;
        else if( uri.Find( KXdmRlsServicesUsageAUID ) >= 0 )
            documentType = EXdmRlsServices;
        CleanupStack::PopAndDestroy();  //EightBitValueLC()
        }
    return documentType;
    }
                 
// ----------------------------------------------------
// CXcapDirectory::Document
// 
// ----------------------------------------------------
//
TPtrC CXcapDirectory::Document( TInt aIndex ) const
    {
    #ifdef _DEBUG
        iXcapProtocol.WriteToLog( _L8( "CXcapDirectory::Document() - Index: %d" ), aIndex );
    #endif
    TChar slash = 47;
    if( aIndex >= 0 && aIndex < iDocumentList.Count() ) 
        {
        TPtrC ret;
        TPtrC uri = iDocumentList[aIndex]->Attribute( KDocumentUri )->AttributeValue();
        TInt index = uri.LocateReverse( slash );
        index > 0 ? ret.Set( uri.Right( uri.Length() - index - 1 ) ) : ret.Set( uri );
        return ret;
        }
    else return TPtrC();
    }
        
// ----------------------------------------------------
// CXcapDirectory::DirectoryPath
// 
// ----------------------------------------------------
//
TPtrC CXcapDirectory::DirectoryPath() const
    {
    return iAUID != NULL ? iAUID->Des() : TPtrC();
    }

// ----------------------------------------------------
// CXcapDirectory::CancelUpdate
// 
// ----------------------------------------------------
//
void CXcapDirectory::CancelUpdate()
    {
    #ifdef _DEBUG
        iXcapProtocol.WriteToLog( _L8( "CXcapDirectory::CancelUpdate()" ) );
    #endif
    Cancel();
    }
    
// ---------------------------------------------------------
// CXcapDirectory::DoCancel
// 
// ---------------------------------------------------------
//
void CXcapDirectory::DoCancel()
    {
    #ifdef _DEBUG
        iXcapProtocol.WriteToLog( _L8( "CXcapDirectory::DoCancel()" ) );
    #endif
    switch( iUpdatePhase )
        {
        case EDirPhaseIdle:
            break;
        case EUpdateDocumentList:
            {
            CXcapDocument* doc = ( CXcapDocument* )iDirectoryDoc;
            doc->CancelUpdate();
            }
            break;
        case ERefreshDocuments:
            iHttpRetrieval->CancelRequest();
            break;
        default:
            break;
        }
    User::RequestComplete( iClientStatus, KErrCancel );
    }