simpleengine/engine/src/simplewatcher.cpp
changeset 0 c8caa15ef882
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/simpleengine/engine/src/simplewatcher.cpp	Tue Feb 02 01:05:17 2010 +0200
@@ -0,0 +1,610 @@
+/*
+* Copyright (c) 2006,2007 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:    Simple Engine
+*
+*/
+
+
+
+
+// INCLUDE FILES
+
+#include <e32std.h>
+#include <s32mem.h>
+
+// own simple
+#include "msimpleconnection.h"
+#include "simpleconnection.h"
+#include "simplecommon.h"
+#include "simpleenginerequest.h"
+#include "msimpledocument.h"
+#include "msimplefilterdocument.h"
+#include "msimplewatcherobserver.h"
+#include "msimplepresencelist.h"
+#include "simplewatcher.h"
+#include "simpleerrors.h"
+#include "simplexmlfactory.h"
+
+#include "simplesipconnection.h"
+
+#ifdef _DEBUG
+#include "simpledebugutils.h"
+#endif
+
+const TInt KExpandSize = 512;
+
+
+// ================= MEMBER FUNCTIONS =======================
+//
+
+// ----------------------------------------------------------
+// CSimpleWatcher::CSimpleWatcher
+// ----------------------------------------------------------
+//
+CSimpleWatcher::CSimpleWatcher(
+    MSimpleConnection& aConn,
+    MSimpleWatcherObserver& aObserver )
+: CSimpleClient( aConn ),
+  iObserver( aObserver ),
+  iResCount(0), iComplete( EFalse ),
+  iBuffer(NULL)
+    {
+    }
+
+// ----------------------------------------------------------
+// CSimpleWatcher::~CSimpleWatcher
+// ----------------------------------------------------------
+//
+CSimpleWatcher::~CSimpleWatcher()
+    {
+#ifdef _DEBUG
+    TSimpleLogger::Log(_L("Watcher: Destructor this=%d" ), (TInt)this );
+#endif
+    delete iBuffer;
+    }
+
+// ----------------------------------------------------------
+// CSimpleWatcher::ConstructL
+// ----------------------------------------------------------
+//
+void CSimpleWatcher::ConstructL()
+    {
+    BaseConstructL();
+    iBuffer = CBufFlat::NewL(KExpandSize);   
+    }
+
+// ----------------------------------------------------------
+// CSimpleWatcher::NewL
+// ----------------------------------------------------------
+//
+CSimpleWatcher* CSimpleWatcher::NewL(
+    MSimpleConnection& aConn,
+    MSimpleWatcherObserver& aObserver )
+    {
+    CSimpleWatcher* self = new (ELeave) CSimpleWatcher(
+        aConn, aObserver );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+#ifdef _DEBUG
+    TSimpleLogger::Log(_L("Watcher: NewL this=%d" ), (TInt)self );
+#endif     
+    return self;
+    }
+
+// ----------------------------------------------------------
+// CSimpleWatcher::Connection
+// ----------------------------------------------------------
+//
+const MSimpleConnection& CSimpleWatcher::Connection()
+    {
+    return iConn;
+    }
+
+// ----------------------------------------------------------
+// CSimpleWatcher::SIPStatus
+// ----------------------------------------------------------
+//
+TUint CSimpleWatcher::SIPStatus()
+    {
+    return DoSIPStatus();
+    }
+    
+// ----------------------------------------------------------
+// CSimpleWatcher::SIPRetryAfter
+// ----------------------------------------------------------
+//
+TUint CSimpleWatcher::SIPRetryAfter()
+    {
+    return DoRetryAfter();
+    }
+    
+// ----------------------------------------------------------
+// CSimpleWatcher::SipSubscriptionState
+// ----------------------------------------------------------
+//
+MSimpleWatcher::TSimpleSipSubscriptionState CSimpleWatcher::SipSubscriptionState()
+    {
+    MSimpleWatcher::TSimpleSipSubscriptionState retVal = ESimpleStateNone;
+    
+    // get the old request
+    CSimpleEngineRequest* req = SearchRequests( iSubsId );
+    if ( req )
+        {
+        CSimpleConnection* conn = STATIC_CAST( CSimpleConnection*, &iConn); //lint !e826
+        CSimpleSipConnection* engine = conn->Connection();                       
+        MSimpleEngineRequest::TSimpleSipSubscriptionState intVal = engine->SipSubscriptionState( *req );
+        switch ( intVal )
+            {
+            case MSimpleEngineRequest::ESimpleStateNone:
+                retVal = MSimpleWatcher::ESimpleStateNone;
+                break;
+            case MSimpleEngineRequest::ESimpleStatePending:
+                retVal = MSimpleWatcher::ESimpleStatePending;
+                break;
+            case MSimpleEngineRequest::ESimpleStateActive:
+                retVal = MSimpleWatcher::ESimpleStateActive;
+                break;            
+            case MSimpleEngineRequest::ESimpleStateTerminated:
+            default:
+                retVal = MSimpleWatcher::ESimpleStateTerminated;
+                break;            
+            }
+        }  
+    return retVal;
+    }    
+      
+
+// ----------------------------------------------------------
+// CSimpleWatcher::Close
+// ----------------------------------------------------------
+//
+void CSimpleWatcher::Close( )
+    {
+    delete this;
+    }
+
+// ----------------------------------------------------------
+// CSimpleWatcher::NewRequestL
+// ----------------------------------------------------------
+//
+void CSimpleWatcher::NewRequestL( MSimpleEngineRequest& aReq )
+    {
+    TPtrC8 content = aReq.ResponseData();
+    TPtrC8 contType = aReq.ResponseContentType();
+    TPtrC8 p8;
+    p8.Set( KSimpleDocumentType );
+    TInt mySize = p8.Length();
+    p8.Set( KSimpleMultipartType );
+    TInt mySize2 = p8.Length();
+    if (!contType.Left(mySize).CompareF(KSimpleDocumentType))
+        {
+        MSimpleDocument* d = TSimpleXmlFactory::NewDocumentL( content );
+        CleanupClosePushL( *d );
+#ifdef _DEBUG
+        TSimpleLogger::Log(_L("Watcher: call WatcherNotificationL"));
+#endif
+        iObserver.WatcherNotificationL( *d );
+        CleanupStack::PopAndDestroy( d );
+        }
+    else if ( !(contType.Left(mySize2).CompareF( KSimpleMultipartType )))
+        {
+    // Detect the difference between multipart/related cases
+    // application/pidf+xml and application/rlmi+xml
+        if ( contType.FindF( KSimpleDocumentType ) > 0 )  
+            {
+            // Multipart for a single presentity having a direct content.            
+            MSimpleDocument* d = TSimpleXmlFactory::NewDocumentInMultiPartL(
+                content, aReq.ResponseBoundary(), aReq.ResponseStart() );            
+            CleanupClosePushL( *d );
+#ifdef _DEBUG
+            TSimpleLogger::Log(_L("Watcher: call WatcherNotificationL (content)"));
+#endif
+            iObserver.WatcherNotificationL( *d );
+            CleanupStack::PopAndDestroy( d );            
+            }
+        else
+            {
+            // Multipart for a presence list.
+            MSimplePresenceList* l = TSimpleXmlFactory::NewPresenceListL( 
+                content, aReq.ResponseBoundary(), aReq.ResponseStart() );
+            CleanupClosePushL( *l );
+#ifdef _DEBUG
+            TSimpleLogger::Log(_L("Watcher: call WatcherListNotificationL"));
+#endif            
+            iObserver.WatcherListNotificationL( *l );
+            CleanupStack::PopAndDestroy( l );            
+            }    
+        }
+    else
+        {
+        // Unsupported content type, ignore it.
+        }
+    }
+
+// ----------------------------------------------------------
+// CSimpleWatcher::Complete
+// ----------------------------------------------------------
+//
+void CSimpleWatcher::Complete(
+    TInt aOpId, TInt aStatus, MSimpleEngineRequest& aReq )
+    {   
+#ifdef _DEBUG
+    TSimpleLogger::Log(_L("Watcher: Complete opid=%d status=%d" ),
+    aOpId, aStatus );
+#endif
+
+    // FUNCTIONALITY
+    // Get
+    // - SIP ok + terminated -> WatcherReqCompleteL(ok) + WatcherNotificationL(terminated)
+    // - terminated + SIP ok -> WatcherNotificationL(terminated) + WatcherReqCompleteL(ok)
+    //
+    // Stop
+    // - terminated + SIP ok -> WatcherReqCompleteL(ok)
+    // - SIP ok + terminated -> WatcherReqCompleteL(ok)    
+    //
+    // Subscribe
+    // - SIP error -> WatcherReqCompleteL(error)
+    // - SIP ok + terminated ->
+    //    WatcherReqCompleteL(ok) + WatcherNotificationL(terminated) + WatcherTerminated()
+    // - SIP ok + active + terminated ->
+    //        WatcherReqCompleteL(ok) + WatcherNotificationL(active) +
+    //        WatcherNotificationL(terminated) + WatcherTErminated
+    // - active + SIP ok + terminated ->
+    //        WatcherNotificationL(active) + WatcherReqCompleteL(ok) +
+    //        WatcherNotificationL(terminated) + WatcherTerminated
+    //
+
+    TBool completeNow( EFalse );
+    MSimpleEngineRequest::TSimpleRequest orig = aReq.RequestType();
+
+    if ( orig == MSimpleEngineRequest::EDestroyStart )
+        {
+        // It's time to delete the request of delayed deletion from both DLLs.
+        // Delete immediately from another DLL.
+        aReq.ModifyType( MSimpleEngineRequest::EDestroy );
+        TRAP_IGNORE( SendReqL( aReq ));
+        // Delete from this DLL,
+        aReq.Destroy();
+        return;
+        }
+
+    GetSIPStatus( aOpId );
+
+    // Reset data buffer
+    iBuffer->Reset();
+
+    // Set the member to point to stack variable
+    TBool destroyed( EFalse );
+    iDestroyedPtr = &destroyed;
+
+    MSimpleEngineRequest::TSimpleSIPResponse respMet = aReq.ResponseMethod();
+
+    // Convert KSimpleErrPending to OK when needed
+    if ( aStatus == KSimpleErrPending )
+        {
+        aStatus = KErrNone;
+        }
+
+    // Handle SIP notification first
+    if ( respMet == MSimpleEngineRequest::ENotify )
+        {
+        // This is true in notifications. Ignore some responses.
+        if ( aStatus == KErrCompletion )
+            {
+            iResCount++;
+            }
+        if ( orig != MSimpleEngineRequest::ESubscribeStop )
+            {
+            TRAP_IGNORE( NewRequestL( aReq ) );
+            // Check whether an application has called destructor in callback method.
+            // Destructor will handle deletion of all the open requests.
+            if ( destroyed )
+                {
+                return;
+                }
+            } 
+        else if ( iResCount > 1  )
+            {
+            // Stop request is not completed until ok + Notify(terminated) received.  
+            // Error completes the stop reqest without Notification.        
+            completeNow = ETrue;
+            if ( DoCallReqComplete( aOpId, KErrNone ))
+                {
+                return;
+                }            
+            }    
+        }
+    else
+        {
+        // SIP Status response or client originated cancellation
+        iResCount++;
+        if ( aStatus != KErrNone )        
+            {
+            iResCount++;
+            if ( orig == MSimpleEngineRequest::ESubscribeStop )     
+                {
+                // Any response to stop subscribe is ok.
+                aStatus = KErrNone;
+                }
+            }
+               
+        if ( !iComplete && 
+              ( orig != MSimpleEngineRequest::ESubscribeStop || 
+                orig == MSimpleEngineRequest::ESubscribeStop && iResCount > 1 ) )
+            {
+            // Stop request is not completed until ok + Notify(terminated) received.  
+            // Error completes the stop reqest without Notification.        
+            completeNow = ETrue;
+            if ( DoCallReqComplete( aOpId, aStatus ))
+                {
+                return;
+                }
+            }
+        }
+
+    // Delete request when not needed
+    if ( iResCount > 1 )
+        {
+        iRequest = MSimpleEngineRequest::ENone;
+        iComplete = EFalse;
+        TInt reason = ResponseReason( aReq );
+        // Delete corresponding request from another DLL with delay. This decreases
+        // the counter of active subscriptions there.
+        aReq.ModifyType( MSimpleEngineRequest::EDestroyStart );
+        TRAP_IGNORE( SendReqL( aReq ));
+        // call WatcherTerminatedL when needed, i.e. no Stop or Get
+        if ( orig != MSimpleEngineRequest::ESubscribeStop &&
+             orig != MSimpleEngineRequest::ESubscribeGet &&
+             !completeNow )
+            {
+#ifdef _DEBUG
+            TSimpleLogger::Log(_L("Watcher: call WatcherTerminatedL opid=%d"),
+                aOpId );
+#endif
+            TRAP_IGNORE( iObserver.WatcherTerminatedL( aOpId, reason ));
+            // Check whether an application has called destructor in callback method.
+            // Destructor of CSimpleClient base class will handle deletion of
+            // all the open requests.
+            if ( destroyed )
+                {
+                return;
+                }
+            }
+        // delete request from this DLL later
+        }
+
+    iDestroyedPtr = NULL;
+    }
+
+// ----------------------------------------------------------
+// CSimpleWatcher::SubscribeL
+// ----------------------------------------------------------
+//
+TInt CSimpleWatcher::SubscribeL(
+    const TDesC8& aURI,
+    MSimpleFilterDocument* aFilter,
+    TBool aRefresh,
+    TBool aAnonymous  )
+    {
+
+    if ( iRequest != MSimpleEngineRequest::ENone )
+        {
+#ifdef _DEBUG
+        TSimpleLogger::Log(_L("Watcher: SubscribeL IN-USE **" ) );
+#endif
+        User::Leave( KErrInUse );
+        }
+
+    IncreaseOpId();
+
+#ifdef _DEBUG
+    TSimpleLogger::Log(_L("Watcher: SubscribeL opid=%d" ), iOpId );
+#endif
+
+    CSimpleEngineRequest* req = CSimpleEngineRequest::NewL(
+        *this, MSimpleEngineRequest::ESubscribe, iOpId );
+    CleanupStack::PushL( req );
+    req->SetRemoteURIL( aURI );
+    req->SetRefresh( aRefresh );
+    if ( aAnonymous )
+        {
+        req->SetAux( 1 );
+        }
+
+    // handle optional filter document
+    if ( aFilter )
+        {
+        StreamDocumentL( *req, *aFilter );
+        }
+
+    SendReqL( *req );
+    iRequestList.AddLast( *req );
+    CleanupStack::Pop( req );
+
+    iRequest = MSimpleEngineRequest::ESubscribe;
+    iResCount = 0;
+    iSubsId = iOpId;
+
+    return iOpId;
+    }
+
+// ----------------------------------------------------------
+// CSimpleWatcher::SubscribeListL
+// ----------------------------------------------------------
+//
+TInt CSimpleWatcher::SubscribeListL(
+    const TDesC8& aURI,
+    MSimpleFilterDocument* aFilter,
+    TBool aRefresh,
+    TBool aAnonymous )
+    {
+    if ( iRequest != MSimpleEngineRequest::ENone )
+        {
+#ifdef _DEBUG
+        TSimpleLogger::Log(_L("Watcher: SubscribeListL IN-USE **" ) );
+#endif
+        User::Leave( KErrInUse );
+        }
+
+    IncreaseOpId();
+#ifdef _DEBUG
+    TSimpleLogger::Log(_L("Watcher: SubscribeListL opid=%d" ), iOpId);
+#endif
+
+    CSimpleEngineRequest* req = CSimpleEngineRequest::NewL(
+        *this, MSimpleEngineRequest::ESubscribeLista, iOpId );
+    CleanupStack::PushL( req );
+    req->SetRemoteURIL( aURI );
+    req->SetRefresh( aRefresh );
+    if ( aAnonymous )
+        {
+        req->SetAux( 1 );
+        }
+
+    // handle optional filter document
+    if ( aFilter )
+        {
+        StreamDocumentL( *req, *aFilter );
+        }
+
+    SendReqL( *req );
+    iRequestList.AddLast( *req );
+    CleanupStack::Pop( req );
+
+    iRequest = MSimpleEngineRequest::ESubscribeLista;
+    iResCount = 0;
+    iSubsId = iOpId;
+
+    return iOpId;
+    }
+
+// ----------------------------------------------------------
+// CSimpleWatcher::GetPresenceL
+// ----------------------------------------------------------
+//
+TInt CSimpleWatcher::GetPresenceL(
+    const TDesC8& aURI,
+    MSimpleFilterDocument* aFilter,
+    TBool aAnonymous  )
+    {
+    if ( iRequest != MSimpleEngineRequest::ENone )
+        {
+#ifdef _DEBUG
+        TSimpleLogger::Log(_L("Watcher: GetPresenceL IN-USE **" ) );
+#endif
+        User::Leave( KErrInUse );
+        }
+
+    IncreaseOpId();
+#ifdef _DEBUG
+    TSimpleLogger::Log(_L("Watcher: GetPresenceL opid=%d" ), iOpId );
+#endif
+
+    CSimpleEngineRequest* req = CSimpleEngineRequest::NewL(
+        *this, MSimpleEngineRequest::ESubscribeGet, iOpId );
+    CleanupStack::PushL( req );
+    req->SetRemoteURIL( aURI );
+    if ( aAnonymous )
+        {
+        req->SetAux( 1 );
+        }
+
+    // handle optional filter document
+    if ( aFilter )
+        {
+        StreamDocumentL( *req, *aFilter );
+        }
+
+    SendReqL( *req );
+    iRequestList.AddLast( *req );
+    CleanupStack::Pop( req );
+
+    iRequest = MSimpleEngineRequest::ESubscribeGet;
+    iResCount = 0;
+
+    return iOpId;
+    }
+
+// ----------------------------------------------------------
+// CSimpleWatcher::UnsubscribeL
+// ----------------------------------------------------------
+//
+TInt CSimpleWatcher::UnsubscribeL( )
+    {
+
+#ifdef _DEBUG
+    TSimpleLogger::Log(_L("Watcher: UnsubscribeL opid=%d" ), iSubsId);
+#endif
+    // use the old opid and request
+    CSimpleEngineRequest* req = SearchRequests( iSubsId );
+    if ( !req )
+        {
+        User::Leave( KErrNotFound );
+        }
+    req->ModifyType( MSimpleEngineRequest::ESubscribeStop );
+
+    SendReqL( *req );
+
+    iRequest = MSimpleEngineRequest::ESubscribeStop;
+    iComplete = EFalse;
+    iResCount = 0;
+
+    return iOpId;
+    }
+
+// ----------------------------------------------------------
+// CSimpleWatcher::StreamDocumentL
+// ----------------------------------------------------------
+//
+void CSimpleWatcher::StreamDocumentL(
+    CSimpleEngineRequest& aReq,
+    MSimpleFilterDocument& aFilter )
+    {
+    // add request data
+    // externalize the document a stream
+    iBuffer->Reset();
+    RBufWriteStream stream( *iBuffer );
+    stream.Open( *iBuffer );
+    aFilter.ExternalizeL( stream );
+    stream.Close();
+    aReq.SetRequestData( iBuffer->Ptr(0) );
+    }
+    
+// ----------------------------------------------------------
+// CSimpleWatcher::DoCallReqComplete
+// ----------------------------------------------------------
+//
+TInt CSimpleWatcher::DoCallReqComplete(
+    TInt aOpId, TInt aStatus )
+    {
+    // Set the member to point to stack variable
+    TBool destroyed( EFalse );
+    iDestroyedPtr = &destroyed;
+        
+    iComplete = ETrue;    
+#ifdef _DEBUG
+    TSimpleLogger::Log(_L("Watcher: call WatcherReqCompleteL opid=%d status=%d"),
+        aOpId, aStatus);
+#endif
+    TRAP_IGNORE( iObserver.WatcherReqCompleteL( aOpId, aStatus ));
+    // Check whether an application has called destructor in callback method.
+    // Destructor will handle deletion of all the open requests.
+    if ( destroyed )
+        {
+        return KErrGeneral;
+        }
+    return KErrNone; 
+    }
+