voipplugins/sipconnectionprovider/src/scppresencehandler.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Mon, 15 Mar 2010 12:39:55 +0200
branchRCL_3
changeset 11 bddb6d4447db
parent 10 7117cbf1600a
child 15 ed1e38b404e5
permissions -rw-r--r--
Revision: 201009 Kit: 201010

/*
* Copyright (c) 2002-2010 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:  Presence handler.
*
*/
#include <ximperrors.hrh>
#include <ximpcontext.h>
#include <presenceinfo.h> //MximpPresenceInfo
#include <presenceinfofilter.h> //info filtter
#include <presenceinfofield.h> //MximpPresenceInfoField
#include <ximpobjectfactory.h>
#include <presenceobjectfactory.h>
#include <servicepresenceinfo.h> //MximpServicePresenceInfo
#include <presenceinfofieldvalueenum.h> //MximpPresenceInfoFieldValueEnum
#include <presenceinfofieldcollection.h> //MximpPresenceInfoFieldCollection
#include <presenceinfofieldvaluetext.h> //MximpPresenceInfoFieldValueText
#include <personpresenceinfo.h> // MximpPersonPresenceInfo
#include <presencepublishing.h>//MPresencePublishing
#include <ximpfeatureinfo.h>
#include <presencefeatures.h>
#include <ximpidentity.h> //for MXIMPIdentity
#include <presentitygroups.h>

#include <ximprequestcompleteevent.h>
#include <ximpcontextstateevent.h>
#include <ownpresenceevent.h>
#include <ximpclient.h>
#include <ximpcontext.h>
#include <ximpstatus.h>
#include <pressettingsapi.h> //presence settings
#include <xdmsettingsapi.h>
#include <cvimpstsettingsstore.h>

#include "scppresencehandler.h"
#include "scpsubservice.h"
#include "scpservicestorage.h"
#include "scplogger.h"
#include "scputility.h"
#include "scpservice.h"
#include "scpprofilehandler.h"
#include "scpsettinghandler.h"
#include "scppresencehandlerrequest.h"

const TInt KXdmDmMaxIntLength      = 10;   // max length of 32bit integer
const TInt KMaxPresenceEnableCount = 5;
const TInt KCustomMessageMaxLength = 75;
const TInt KBufSize255 = 255;

// -----------------------------------------------------------------------------
// CScpPresenceHandler::NewL
// -----------------------------------------------------------------------------
//
CScpPresenceHandler* CScpPresenceHandler::NewL( CScpSubService& aSubService )
    {
    SCPLOGSTRING( "CScpPresenceHandler::NewL" );
    CScpPresenceHandler* self = new ( ELeave ) CScpPresenceHandler( aSubService );
    CleanupStack::PushL( self );    
    self->ConstructL();    
    CleanupStack::Pop( self );
    return self;
    }

// -----------------------------------------------------------------------------
// CScpPresenceHandler::CCScpPresenceHandler
// -----------------------------------------------------------------------------
//
CScpPresenceHandler::CScpPresenceHandler( CScpSubService& aSubService ) :
    CScpServiceHandlerBase( aSubService ),
    iPresenceState( ENoBind ),
    iDisableAfterXimpRequestsCompleted( EFalse )
    {
    SCPLOGSTRING2( "CScpPresenceHandler[0x%x]::CScpPresenceHandler", this );
    }

// -----------------------------------------------------------------------------
// CScpPresenceHandler::ConstructL
// -----------------------------------------------------------------------------
//
void CScpPresenceHandler::ConstructL()
    {
    SCPLOGSTRING2( "CScpPresenceHandler[0x%x]::ConstructL", this );

    BaseConstructL();
    GetPresencePropertyIdL( ESubPropertyPresenceSettingsId, iPresenceSettingsId );
    
    iPresClient = MXIMPClient::NewClientL();
    SCPLOGSTRING2( "CScpPresenceHandler::ConstructL, iPresClient [0x%x]", iPresClient );

    if ( iPresClient )
        {
        // Set presence handler as observer of Voip subservice
        CScpSubService* voipSubService = GetVoipSubService();
        if ( voipSubService )
            {
            voipSubService->SetSubServiceObserver( this );
            }
        
        MXIMPContext* tmp = iPresClient->NewPresenceContextLC();        
        iFeature = MPresenceFeatures::NewL( tmp );
        
        RArray<TInt32> eventFilter;   
        CleanupClosePushL( eventFilter );

        eventFilter.Append( XIMP_IF_ID_REQUEST_COMPLETE_EVENT );     
        eventFilter.Append( XIMP_IF_ID_CONTEXT_STATE_EVENT );
        
        TArray<TInt32> eventFilterArray = eventFilter.Array();
        tmp->RegisterObserverL( *this, &eventFilterArray );
        
        CleanupStack::PopAndDestroy( &eventFilter );

        CleanupStack::Pop(); // tmp
        iPresenceCtx = tmp;
        tmp = NULL; 
        }
    else
        {
        User::Leave( KErrGeneral );
        }
    }

// -----------------------------------------------------------------------------
// CScpPresenceHandler::~CScpPresenceHandler
// -----------------------------------------------------------------------------
//
CScpPresenceHandler::~CScpPresenceHandler()
    {
    SCPLOGSTRING2( "CScpPresenceHandler[0x%x]::~CScpPresenceHandler", this );

    CancelDisableTimer();
    
    iReqIdArray.Close();
    
    delete iFeature;
    delete iPresenceCtx;
    
    // Set observer of Voip subservice to NULL
    CScpSubService* voipSubService = GetVoipSubService();
    if ( voipSubService )
        {
        voipSubService->SetSubServiceObserver( NULL );
        }
    
    delete iPresClient;
    }


// ====================== From CScpServiceHandlerBase ==========================

// -----------------------------------------------------------------------------
// CScpPresenceHandler::EnableSubServiceL
// -----------------------------------------------------------------------------
//
void CScpPresenceHandler::EnableSubServiceL()
    {
    SCPLOGSTRING4( "CScpPresenceHandler[0x%x]::EnableSubServiceL: 0x%x type: %i", 
                   this, &iSubService, iSubService.SubServiceType() );
       
    __ASSERT_DEBUG( iSubService.SubServiceType() == ECCHPresenceSub,
                    User::Panic( KNullDesC, KErrGeneral ) );     

    CScpServiceHandlerBase::RegisterProfileL();
    }

// -----------------------------------------------------------------------------
// CScpPresenceHandler::DisableSubService
// -----------------------------------------------------------------------------
//
TInt CScpPresenceHandler::DisableSubService()
    {
    SCPLOGSTRING2( "CScpPresenceHandler[0x%x]::DisableSubService", this );
    __ASSERT_DEBUG( iSubService.SubServiceType() == ECCHPresenceSub,
                    User::Panic( KNullDesC, KErrGeneral ) );  

    TInt result = KErrNone;
    // Publish offline and unbind presence context
    TRAP( result, HandleDeregistrationL( ETrue ) );
    
    if ( KErrNone == result  )
        {
        // Deregister if still connecting
        if ( iSubService.State() == ECCHConnecting )
            {
            DeregisterNow();            
            }
        else
            {
            StartForcedDisableTimer( CScpPresenceHandler::ForcePresenceServiceDisable );
            }
        }
    else
        {
        
        // Wait for XIMP request to be completed and handle 
        // de-registration after that or after force disable timer expires
        if ( iReqIdArray.Count() )
            {
            iDisableAfterXimpRequestsCompleted = ETrue;
            StartForcedDisableTimer( CScpPresenceHandler::ForcePresenceServiceDisable );
            }
        else
            {
            DeregisterNow();
            }
        }

    return result;
    }

// -----------------------------------------------------------------------------
// CScpPresenceHandler::SubServiceType
// -----------------------------------------------------------------------------
//
TCCHSubserviceType CScpPresenceHandler::SubServiceType() const
    {
    SCPLOGSTRING2( "CScpPresenceHandler[0x%x]::SubServiceType", this );
    return ECCHPresenceSub;
    }

// -----------------------------------------------------------------------------
// CScpPresenceHandler::HandleSipConnectionEvent
// -----------------------------------------------------------------------------
//
void CScpPresenceHandler::HandleSipConnectionEvent( const TUint32 aProfileId,
                                                    TScpConnectionEvent aEvent )
    {
    SCPLOGSTRING4( "CScpPresenceHandler[0x%x]::HandleSipConnectionEvent id: %d event: %d",
                   this, aProfileId, aEvent );
    
    if ( iSubService.SipProfileId() == aProfileId &&
        iSubService.EnableRequestedState() != CScpSubService::EScpNoRequest )
        {
        //if network lost, unbind context
        if ( EScpNetworkLost == aEvent )
            {
            SCPLOGSTRING( "CScpPresenceHandler - EScpNetworkLost -> unbind" );
            TRAPD( err, HandleDeregistrationL( EFalse ) );
            
            if ( KErrNotReady == err )
                {
                SCPLOGSTRING( "CScpPresenceHandler - EScpNetworkLost -> note ready: unbind" );
                TRAP_IGNORE( ServerUnBindL() );
                }
            }
        
        if ( EScpRoaming == aEvent )
            {
            SCPLOGSTRING( "CScpPresenceHandler - EScpRoaming -> unbind" );
            TRAP_IGNORE( ServerUnBindL() );
            }
        
        //if registered, time to bind context
        if ( EScpRegistered == aEvent &&
             CScpSubService::EScpEnabled == iSubService.EnableRequestedState() )
            {
            SCPLOGSTRING( "CScpPresenceHandler - EScpRegistered -> update iap and bind" );
            // update xmd settings 
            TRAPD( err, UpdateXdmSettingsL() );
            
            if ( KErrNone == err )
                {
                // Subscribe
                TRAP( err, ServerBindL() );
                iRebind = EFalse;
                
                if( KErrNone == err )
                    {
                    // Still connecting the service
                    aEvent = EScpNetworkFound;    
                    }
                else
                    {
                    SCPLOGSTRING2( "ServerBindL failed: %d", err );
                    aEvent = EScpRegistrationPending;
                    if ( KErrAlreadyExists == err )
                        {
                        // Ximp does not set request to queue, so we have to do rebind later
                        SCPLOGSTRING( "CScpPresenceHandler - rebind later" ); 
                        iRebind = ETrue;
                        }
                    }
                }
            else
                {
                SCPLOGSTRING2( "UpdateXdmSettingsL: %d", err );
                aEvent = EScpRegistrationFailed;
                }
            }
        else if ( EScpDeregistered == aEvent &&
                 iSubService.EnableRequestedState() == CScpSubService::EScpDisabled ||
                 iSubService.EnableRequestedState() == CScpSubService::EScpRefreshed )
            {
            if ( EScpRegistered != aEvent && ECCHDisconnecting != iSubService.State() )
                {
                CancelDisableTimer();
                }
            
            // If this flag is still true, it could be that presence server
            // has not given answer -> ximp requests cannot be completed.
            // But still have to unbind from ximp context
            if ( iDisableAfterXimpRequestsCompleted )
                {
                TRAP_IGNORE( ServerUnBindL() );
                }
            
            // When SIP is deregistered, change presence state to no bind
            iPresenceState = ENoBind;
            }
        iSubService.HandleConnectionEvent( aEvent );
        }
    SCPLOGSTRING( "CScpPresenceHandler::HandleSipConnectionEvent OUT" );
    }    

// -----------------------------------------------------------------------------
// CScpPresenceHandler::HandleSipConnectionEvent
// -----------------------------------------------------------------------------
//
TBool CScpPresenceHandler::IsSipProfileAllowedToStartAlr()
    {
    return EFalse;
    }

// ======================= From MXIMPContextObserver ===========================

// -----------------------------------------------------------------------------
// CScpPresenceHandler::HandlePresenceContextEvent
// -----------------------------------------------------------------------------
//   
void CScpPresenceHandler::HandlePresenceContextEvent(
    const MXIMPContext& /*aContext*/,
    const MXIMPBase& aEvent )
    {
    SCPLOGSTRING2( "CScpPresenceHandler[0x%x]::HandlePresenceContextEvent", this );

    const TInt32 eventType = aEvent.GetInterfaceId();
    
    switch ( eventType )
        {
        case MXIMPContextStateEvent::KInterfaceId:
            {
            HandleContextStateEvent( aEvent );
            break;
            }

        case MXIMPRequestCompleteEvent::KInterfaceId:
            {
            HandleRequestCompleteEvent( aEvent );
            break;
            }
              
        default:
            {
            break;
            }
        }
    SCPLOGSTRING( "CScpPresenceHandler::HandlePresenceContextEvent end" ); 
    }



// ===================== From MScpSubServiceObserver ===========================

// -----------------------------------------------------------------------------
// CScpPresenceHandler::HandleSubServiceChange
// -----------------------------------------------------------------------------
//
void CScpPresenceHandler::HandleSubServiceChange( TCCHSubserviceState aState, TInt aError )
    {
    SCPLOGSTRING4( "CScpPresenceHandler::HandleSubServiceChange presence subservice state: %d, aState: %d, aError: %d", 
                    iSubService.State(), aState, aError );
                    
    if ( iSubService.State() == ECCHEnabled && ( aError == KCCHErrorBandwidthInsufficient || aError == KErrNone ) )
        {
        if( aState == ECCHEnabled && aError == KErrNone )
            {
            if ( EPresenceOffline == iPresenceState )
                {
                SCPLOGSTRING( "CScpPresenceHandler::HandleSubServiceChange PublishOnline" );
                TRAP_IGNORE( PublishPresenceL( ETrue ) );
                }
            }
        else
            {
            if ( EPresenceOnline == iPresenceState && aState != ECCHConnecting )
                {
                SCPLOGSTRING( "CScpPresenceHandler::HandleSubServiceChange PublishOffline" );
                // Unsubscribe from the list first
                TRAP_IGNORE( UnsubscribePresentityGroupL() );
                TRAP_IGNORE( PublishPresenceL( EFalse ) );
                }
            }
        }
    }
 
// ========================= Other member funcions =============================


// -----------------------------------------------------------------------------
// CScpPresenceHandler::GetVoipSubService
// -----------------------------------------------------------------------------
//
CScpSubService* CScpPresenceHandler::GetVoipSubService()
    {
    CScpSubService* voipSubService = NULL;
    CScpServiceStorage& serviceStorage = iSubService.ServiceStorage();
    CScpService* service = serviceStorage.GetServiceByServiceId( iSubService.SubServiceId() );

    if ( service )
        {
        voipSubService = service->GetSubServiceByType( ECCHVoIPSub );
        }
    
    return voipSubService;
    }

// -----------------------------------------------------------------------------
// CScpPresenceHandler::DeregisterNow
// -----------------------------------------------------------------------------
//
void CScpPresenceHandler::DeregisterNow()
    {
    SCPLOGSTRING2( "CScpPresenceHandler[0x%x]::DeregisterNow",
                   this );
    
    CancelDisableTimer();
  
    iReqIdArray.Reset();
    iPresenceState = ENoBind;

    // Check if disable was not requested
    if ( iSubService.EnableRequestedState() == CScpSubService::EScpEnabled )
        {
        // Check the last ximp error
        if ( KErrNoMemory == iLastXimpError && 
            KMaxPresenceEnableCount < iSubService.EnableCounter() )
            {
            // No memory means 401 Unauthorized, we are trying to enable  
            // KMaxPresenceEnableCount times -> no more, this is truly
            // autentication failed.
            iSubService.HandleConnectionEvent( EScpAuthenticationFailed );
            }
        else
            {
            iSubService.HandleConnectionEvent( EScpDeregistered );
            }
        }
    else
        {
        DeregisterProfile();
        }
    }

// -----------------------------------------------------------------------------
// CScpPresenceHandler::ForcePresenceServiceDisable
// -----------------------------------------------------------------------------
//
TInt CScpPresenceHandler::ForcePresenceServiceDisable( TAny* aSelf )
    {
    SCPLOGSTRING( "CScpPresenceHandler::ForcePresenceServiceDisable" );

    CScpPresenceHandler* self = static_cast<CScpPresenceHandler*>( aSelf );

    self->DeregisterNow();

    return 1;
    }

// -----------------------------------------------------------------------------
// CScpPresenceHandler::UpdateXdmSettingsL
// -----------------------------------------------------------------------------
//
void CScpPresenceHandler::UpdateXdmSettingsL()
    {
    SCPLOGSTRING2( "CScpPresenceHandler[0x%x]::UpdateXdmSettingsL", this );
    
    // Get IAP id of sip profile
    CScpProfileHandler& profileHandler = iSubService.ProfileHandler();
    CScpSipConnection* sipConnection = profileHandler.GetSipConnection( iSubService.SipProfileId() );
    if ( !sipConnection )
        {
        User::Leave( KErrNotFound );
        }
    
    TUint32 apId = 0;
    User::LeaveIfError( sipConnection->GetIap( apId ) );
    
    SCPLOGSTRING2( "CScpPresenceHandler::UpdateXdmSettingsL apId is %d", apId );
    
    TPresSettingsSet mySet;
    User::LeaveIfError( PresSettingsApi::SettingsSetL( iPresenceSettingsId, mySet ));
        
    // set iap id to xdm settings
    HBufC* idBuf = HBufC::NewLC( KXdmDmMaxIntLength );
    TPtr ptrBuf = idBuf->Des();
    ptrBuf.AppendNum( apId );
        
    TXdmSettingsApi::UpdatePropertyL( mySet.iXDMSetting, *idBuf, EXdmPropToNapId );
    CleanupStack::PopAndDestroy( idBuf );

    SCPLOGSTRING( "CScpPresenceHandler::UpdateXdmSettingsL status online end" );
    }

// -----------------------------------------------------------------------------
// CScpPresenceHandler::GetPresencePropertyIdL
// -----------------------------------------------------------------------------
//
void CScpPresenceHandler::GetPresencePropertyIdL( TServicePropertyName aProperty,
                                                    TInt& aValue ) const
    {
    SCPLOGSTRING2( "CScpPresenceHandler[0x%x]::GetPresenceSettingsId", this );
    
    CScpServiceStorage& serviceStorage = iSubService.ServiceStorage();
    CScpSettingHandler& settingHandler = serviceStorage.SettingsHandler();
    
    settingHandler.GetSPSettingsIntPropertyL( iSubService.SubServiceId(),
        aProperty, 
        aValue );
    }

// -----------------------------------------------------------------------------
// CScpPresenceHandler::PublishPresenceL
// Publishes presence according to given parameter.
// -----------------------------------------------------------------------------
//
void CScpPresenceHandler::PublishPresenceL( TBool aPublishOnline )
    {
    SCPLOGSTRING3( "CScpPresenceHandler[0x%x]::PublishPresenceL, aPublishOnline = %d",
        this, aPublishOnline );

    // Get the management interface
    MPresencePublishing* presPub = &( iFeature->PresencePublishing() );
    // publish own presence in here
    MPresenceInfo* info = CreateInfoLC( aPublishOnline );
    TScpReqId reqId;
    
    if ( aPublishOnline )
        {
        reqId.SetType( EPublishOnlineReq );
        iPresenceState = EPublishing;
        }
    else
        {
        reqId.SetType( EPublishOfflineReq );
        iPresenceState = EPresenceOffline;
        }
        
    reqId.SetId( presPub->PublishOwnPresenceL( *info ) ); 
    iReqIdArray.Append( reqId );
    
    CleanupStack::PopAndDestroy( 1 );
    
    SCPLOGSTRING( "CScpPresenceHandler::PublishPresenceL end" ); 
    }


// -----------------------------------------------------------------------------
// CScpPresenceHandler::ServerBindL
// Binds the presence context
// -----------------------------------------------------------------------------
//
void CScpPresenceHandler::ServerBindL()
    {
    SCPLOGSTRING2( "CScpPresenceHandler[0x%x]::ServerBindL", this );
    SCPLOGSTRING2( "CScpPresenceHandler::ServerBindL -> bind service: %d", 
        iSubService.SubServiceId() );
    
    //Bind context to desired presence service
    TInt propertyId = 0;
    GetPresencePropertyIdL( EPropertyPCSPluginId, propertyId );
    TUid protocolUid = TUid::Uid( propertyId );
    
    TScpReqId reqId;
    reqId.SetType( EBindReq );
    reqId.SetId( iPresenceCtx->BindToL( protocolUid, iSubService.SubServiceId() ) );
    iReqIdArray.Append( reqId );
    iPresenceState = EBinding;
    SCPLOGSTRING( "CScpPresenceHandler::ServerBindL end" );
    }

// -----------------------------------------------------------------------------
// CScpPresenceHandler::ServerUnBindL
// Unbinds the presence context
// -----------------------------------------------------------------------------
//
void  CScpPresenceHandler::ServerUnBindL()
    {
    SCPLOGSTRING2( "CScpPresenceHandler[0x%x]::ServerUnBindL", this );
    TScpReqId reqId;
    reqId.SetType( EUnBindReq );
    reqId.SetId( iPresenceCtx->UnbindL() );
    iReqIdArray.Append( reqId ); 
    iPresenceState = EUnBinding;
    SCPLOGSTRING( "CScpPresenceHandler::ServerUnBindL end" );
    }
    
// -----------------------------------------------------------------------------
// CScpPresenceHandler::HandleDeregistrationL
// Handles the deregistration of presence.
// -----------------------------------------------------------------------------
//    
void CScpPresenceHandler::HandleDeregistrationL( TBool aDoStopPublish )
    {
     SCPLOGSTRING4( "CScpPresenceHandler[0x%x]::HandleDeregistrationL, aDoStopPublish: %d, iPresenceState: %d",
             this, aDoStopPublish, iPresenceState );

    if ( EPresenceOnline == iPresenceState 
        && aDoStopPublish && 
        iSubService.LastReportedError() == KErrNone )
        {
        // Get the management interface
        MPresencePublishing* presPub = &( iFeature->PresencePublishing() );
        // publish own presence in here
        MPresenceInfo* info = CreateInfoLC( EFalse );
        TScpReqId reqId;
        // After publishing offline, we need to unbind because we are
        // deregistering, so offline request id needs to be saved and handled
        reqId.SetType( EPublishOfflineReq );
        reqId.SetId( presPub->PublishOwnPresenceL( *info ) );
        iPresenceState = EPresenceOffline;
        iReqIdArray.Append( reqId );
        CleanupStack::PopAndDestroy( 1 );  // info
        }
    else
        {
        //unbind if there are no other requests going on. 
        //in case of ongoing unprocessed requests, 
        //reset array (further events ignored) and
        //leave here to deregister properly
        if ( iReqIdArray.Count() > 0 )
            {
            User::Leave( KErrNotReady );
            }
        else
            {
            ServerUnBindL();
            }
        }

    SCPLOGSTRING( "CScpPresenceHandler::HandleDeregistrationL end" );
    } 

// -----------------------------------------------------------------------------
// CScpPresenceHandler::CreateInfoLC
// Creates presence info item
// -----------------------------------------------------------------------------
//  
MPresenceInfo* CScpPresenceHandler::CreateInfoLC( TBool aState )
    {
    SCPLOGSTRING2( "CScpPresenceHandler[0x%x]::CreateInfoLC", this );
    
    MPresenceInfo* info = 
        iFeature->PresenceObjectFactory().NewPresenceInfoLC();
    // fill service info
    MServicePresenceInfo* srvInfo = 
        iFeature->PresenceObjectFactory().NewServicePresenceInfoLC();
    srvInfo->SetServiceTypeL( 
        NPresenceInfo::NServiceType::KVoip );  // voip

    MPresenceInfoField* infoField = 
        iFeature->PresenceObjectFactory().NewInfoFieldLC();
    
    MPresenceInfoFieldValueEnum* enumField = 
       iFeature->PresenceObjectFactory().NewEnumInfoFieldLC();
       
    // Set the textfield's value according to aState    
    if ( aState )
        {  
        enumField->SetValueL( NPresenceInfo::EAvailable );
        }
     else
        {
        enumField->SetValueL( NPresenceInfo::ENotAvailable );
        }
    
    infoField->SetFieldTypeL( 
        NPresenceInfo::NFieldType::KAvailabilityEnum ); // "availability"
    infoField->SetFieldValue( enumField );
    CleanupStack::Pop(); // enumField
    
    srvInfo->Fields().AddOrReplaceFieldL( infoField );
    CleanupStack::Pop(); // infoField 

    info->AddServicePresenceL( srvInfo );
    CleanupStack::Pop(); // srvInfo 

    // fill person info
    MPersonPresenceInfo* persInfo = 
        iFeature->PresenceObjectFactory().NewPersonPresenceInfoLC();
    
    MPresenceInfoField* infoField2 = 
        iFeature->PresenceObjectFactory().NewInfoFieldLC();
    
    MPresenceInfoFieldValueEnum* enumField2 = 
        iFeature->PresenceObjectFactory().NewEnumInfoFieldLC();
    TInt availabilityEnum(0);
    RBuf customMessage;
    CleanupClosePushL( customMessage );
    customMessage.Create( KCustomMessageMaxLength );
    GetStoredPresenceValuesL( availabilityEnum, customMessage );
    
    switch( availabilityEnum )
        {
        case NPresenceInfo::EAvailable:
            {
            enumField2->SetValueL( NPresenceInfo::EAvailable );
            break;
            }

        case NPresenceInfo::ENotAvailable:
            {
            enumField2->SetValueL( NPresenceInfo::ENotAvailable );
            break;
            }
            
        case NPresenceInfo::EBusy:
            {
            enumField2->SetValueL( NPresenceInfo::EBusy );
            break;
            }
            
        case NPresenceInfo::EDoNotDisturb:
            {
            enumField2->SetValueL( NPresenceInfo::EDoNotDisturb );
            break;
            }
                
        case NPresenceInfo::EAway:
            {
            enumField2->SetValueL( NPresenceInfo::EAway );
            break;
            }
            
        // if presence availability is not stored     
        default:
            {
            if ( aState )
                {  
                enumField2->SetValueL( NPresenceInfo::EAvailable );
                }
            else
                {
                enumField2->SetValueL( NPresenceInfo::ENotAvailable );
                }
            break;
            }
        }
    
    // set custom message if available
    if( customMessage.Length() ) 
        {
        MPresenceInfoField* customMessageinfoField = 
            iFeature->PresenceObjectFactory().NewInfoFieldLC();
                
        MPresenceInfoFieldValueText* textField = 
            iFeature->PresenceObjectFactory().NewTextInfoFieldLC();
        textField->SetTextValueL( customMessage );
        customMessageinfoField->SetFieldTypeL( 
        NPresenceInfo::NFieldType::KStatusMessage );
        customMessageinfoField->SetFieldValue( textField );
        CleanupStack::Pop(); //textField
        persInfo->Fields().AddOrReplaceFieldL( customMessageinfoField );
        CleanupStack::Pop(); //customMessageinfoField
        }
    
    CleanupStack::PopAndDestroy( &customMessage );
   
    infoField2->SetFieldTypeL( 
        NPresenceInfo::NFieldType::KAvailabilityEnum );
    infoField2->SetFieldValue( enumField2 );
    CleanupStack::Pop(); // enumField2

    persInfo->Fields().AddOrReplaceFieldL( infoField2 );
    CleanupStack::Pop(); // infoField2

    info->SetPersonPresenceL( persInfo );
    CleanupStack::Pop(); // persInfo

    return info;
    } 


// -----------------------------------------------------------------------------
// CScpPresenceHandler::HandleContextStateEvent
// Handles the XIMP context state events
// -----------------------------------------------------------------------------
//
void CScpPresenceHandler::HandleContextStateEvent( const MXIMPBase& aEvent )
    {
    const MXIMPContextStateEvent* event =
    TXIMPGetInterface< const MXIMPContextStateEvent >::From( aEvent, MXIMPBase::EPanicIfUnknown );

    MXIMPContextState::TState ctxState = event->ContextState().ContextState();
    SCPLOGSTRING2( "CScpPresenceHandler: MXIMPContextStateEvent: %d", (TInt)ctxState );
    
    const MXIMPStatus* status = event->StateChangeReason();
    if ( status )
        {
        iLastXimpError = status->ResultCode();
        }
    SCPLOGSTRING2( "CScpPresenceHandler -> context ximp error: %d", iLastXimpError );
        
    // Go through the reqid array to see, if unbind has been requested
    TBool unBindRequested( EFalse );
    for ( TInt i = 0; i < iReqIdArray.Count(); i++ )
        {
        if ( iReqIdArray[i].Type() == EUnBindReq )
            {
            unBindRequested = ETrue;
            }
        }
    
    if ( ctxState == MXIMPContextState::EInactive && 
        iReqIdArray.Count() > 0 &&
        !unBindRequested )
        {
        //Unbind was not requested, but EInactive state event received => try forced unbind
        TRAPD( binderr, HandleDeregistrationL( EFalse ) );
        SCPLOGSTRING2( "CScpPresenceHandler::HandleContextStateEvent: Unbind err:%d", binderr );
        if ( KErrNone != binderr )
            {
            DeregisterNow();
            }
        }
    }


// -----------------------------------------------------------------------------
// CScpPresenceHandler::HandleRequestCompleteEvent
// Handles the XIMP request complete events
// -----------------------------------------------------------------------------
//
void CScpPresenceHandler::HandleRequestCompleteEvent( const MXIMPBase& aEvent )
    {
    SCPLOGSTRING( "CScpPresenceHandler::HandleRequestCompleteEvent event MximpRequestCompleteEvent" );
    const MXIMPRequestCompleteEvent* event =
        TXIMPGetInterface< const MXIMPRequestCompleteEvent >::From( aEvent, MXIMPBase::EPanicIfUnknown );

    const TXIMPRequestId& reqId = event->RequestId();
    const MXIMPStatus& status = event->CompletionResult();
    if ( &status )
        {
        iLastXimpError = status.ResultCode();
        }
    SCPLOGSTRING2( "CScpPresenceHandler -> request ximp error: %d", iLastXimpError );
       
    if ( iLastXimpError == KXIMPErrServicRequestTimeouted )
        {
        iSubService.HandleConnectionEvent( EScpRegistrationFailed );
        }
    
    // Find the reqId from the reqid array and store it's type
    TInt index( KErrNotFound );
    TScpReqType reqType( EUnknownReq );
    for ( TInt i = 0; i < iReqIdArray.Count(); i++ )
        {
        if ( iReqIdArray[i].ReqId() == reqId )
            {
            index = i;
            reqType = iReqIdArray[i].Type();
            }
        }
    
    if ( index != KErrNotFound )
        {
        iReqIdArray.Remove( index );             
        }
    
    SCPLOGSTRING2( "CScpPresenceHandler -> request type: %d", reqType );

    // Bind complete event
    if ( ( reqType == EBindReq ) &&
        ( EBinding == iPresenceState ) &&
        ( iLastXimpError == KErrNone ) )
        {
        HandleBindCompleteEvent();
        }
    // Published online request complete
    else if ( ( reqType == EPublishOnlineReq ) && 
        ( iLastXimpError == KErrNone ) )
        {
        TRAP_IGNORE( SubscribePresentityGroupL() );
        iPresenceState = ESubscribing;
        }
    
    else if ( ( reqType == ESubscribeReq ) &&
        ( iLastXimpError == KErrNone ) )
        {
        // Set subservice enabled after subscribe is successfully done
        iPresenceState = EPresenceOnline;
        iSubService.HandleConnectionEvent( EScpRegistered );
        }
    
    // Published offline request complete
    else if ( reqType == EPublishOfflineReq )
        {
        SCPLOGSTRING( "CScpPresenceHandler::HandleRequestCompleteEvent status offline Unbind now" );
        TRAPD( err, ServerUnBindL() );
        // Deregistration ongoing, so if unbind fails, deregisterNow is called
        if ( err )
            {
            DeregisterNow();
            SCPLOGSTRING2( "CScpPresenceHandler::HandleRequestCompleteEvent status offline Unbind now end, err %d", err );
            }
        }
    
    // Unbind request complete
    else if ( reqType == EUnBindReq && EUnBinding == iPresenceState )
        {
        SCPLOGSTRING( "CScpPresenceHandler::HandleRequestCompleteEvent status offline" );
        
        // Do not send info to our client if roaming is ongoing 
        if ( !iSubService.IsRoaming() )
            {
            DeregisterNow();
            }
		// Inform SIP to start ALR migration
        else
            {
            iSubService.ProfileHandler().StartAlrMigration( iSubService.SipProfileId() );
            }
        
        SCPLOGSTRING( "CScpPresenceHandler::HandleRequestCompleteEvent status offline end" );
        }
    
    if ( iRebind )
        {
         TRAPD( err, ServerBindL() );
         iRebind = EFalse;
         SCPLOGSTRING2( "CScpPresenceHandler - ServerBindL failed: %d", err );
         
         if ( KErrAlreadyExists == err )
             {
             iRebind = ETrue;
             }
        }
    
    if ( iDisableAfterXimpRequestsCompleted && !iReqIdArray.Count() )
        {
        iDisableAfterXimpRequestsCompleted = EFalse;
        DeregisterNow();
        }
    
    SCPLOGSTRING( "CScpPresenceHandler::HandleRequestCompleteEvent OUT" ); 
    }


// -----------------------------------------------------------------------------
// CScpPresenceHandler::HandleBindCompleteEvent
// Handles the bind complete event
// -----------------------------------------------------------------------------
//
void CScpPresenceHandler::HandleBindCompleteEvent()
    {
    SCPLOGSTRING( "CScpPresenceHandler::HandleBindCompleteEvent" );
    
    iPresenceState = EBindComplete;
    
    TInt err( KErrNone );
    CScpSubService* voipSubService = GetVoipSubService();
    if ( voipSubService )
        {
        if ( voipSubService->State() == ECCHEnabled &&
            voipSubService->LastReportedError() == KErrNone )
            {
            SCPLOGSTRING( "CScpPresenceHandler::HandleBindCompleteEvent PublishOnline");
            TRAP( err, PublishPresenceL( ETrue ) );
            }
        else
            {
            SCPLOGSTRING( "CScpPresenceHandler::HandleBindCompleteEvent PublishOffline");
            TRAP( err, PublishPresenceL( EFalse ) );
            }
        }
    else
        {
        SCPLOGSTRING( "CScpPresenceHandler::HandleBindCompleteEvent PublishOffline, no VoIP");
        TRAP( err, PublishPresenceL( EFalse ) );
        err = KErrNotFound;
        }
     
    if ( err )
        {
        SCPLOGSTRING2( "CScpPresenceHandler::HandleBindCompleteEvent err %d", err );
        }   
    }


// -----------------------------------------------------------------------------
// CScpPresenceHandler::SubscribePresentityGroupL
// 
// -----------------------------------------------------------------------------
//
void CScpPresenceHandler::SubscribePresentityGroupL()
    {
    SCPLOGSTRING( "CScpPresenceHandler::SubscribePresentityGroupL subsribe buddies" );
    MXIMPObjectFactory& objFactoryFromXIMP = iPresenceCtx->ObjectFactory();
    
    //First we have to make identity
    SCPLOGSTRING( "CScpPresenceHandler::SubscribePresentityGroupL create buddy list identity" );
    MXIMPIdentity* groupIdentity = objFactoryFromXIMP.NewIdentityLC();
    groupIdentity->SetIdentityL( _L("buddylist") ); // NEEDS TO BE DEFINED IN XIMP API
    
    SCPLOGSTRING( "CScpPresenceHandler::SubscribePresentityGroupL subsribe group content" );
    TScpReqId reqId;

    reqId.SetType( ESubscribeReq );
    reqId.SetId( iFeature->PresentityGroups().SubscribePresentityGroupContentL(
        *groupIdentity ) );
    SCPLOGSTRING( "CScpPresenceHandler::SubscribePresentityGroupL append req to array" );
    iReqIdArray.Append( reqId );

    SCPLOGSTRING( "CScpPresenceHandler::SubscribePresentityGroupL subsribe group content ok" );
    CleanupStack::PopAndDestroy( 1 ); // groupIdentity
    }


// -----------------------------------------------------------------------------
// CScpPresenceHandler::UnsubscribePresentityGroupL
// 
// -----------------------------------------------------------------------------
//
void CScpPresenceHandler::UnsubscribePresentityGroupL()
    {
    MXIMPObjectFactory& objFactoryFromXIMP = iPresenceCtx->ObjectFactory();
    
    //First we have to make identity
    MXIMPIdentity* groupIdentity = objFactoryFromXIMP.NewIdentityLC();
    groupIdentity->SetIdentityL( _L("buddylist") ); // NEEDS TO BE DEFINED IN XIMP API
    
    TScpReqId reqId;
    // Set type to Unknown, because we don't need to handle the
    // request complete event
    reqId.SetType( EUnknownReq );
    reqId.SetId( iFeature->PresentityGroups().UnsubscribePresentityGroupContentL(
        *groupIdentity ) );
    iReqIdArray.Append( reqId );
    
    CleanupStack::PopAndDestroy( 1 );
    }

// -----------------------------------------------------------------------------
// CScpPresenceHandler::GetStoredPresenceValuesL
// 
// -----------------------------------------------------------------------------
//
void CScpPresenceHandler::GetStoredPresenceValuesL( TInt& aAvailabilityEnum, RBuf& aCustomMessage )
    {
    MVIMPSTSettingsStore* settings = CVIMPSTSettingsStore::NewLC();
        
    TInt serviceId = iSubService.SubServiceId();
    RBuf8 documentId;
    CleanupClosePushL( documentId );
    documentId.CreateL( KBufSize255 );
    TInt error = settings->GetL( 
        serviceId, EServicePresenceSessionIdentifier, documentId );
    TInt i = documentId.Length();
    TInt err1(0);
    TInt err2(0);
    
    if( documentId.Length() )
        {
        err1 = settings->GetL( 
            serviceId, EServicePresenceAvailablilityValue, aAvailabilityEnum );
        err2 = settings->GetL( 
            serviceId, EServiceCustomStatusMessage, aCustomMessage );
        
        // if other GetL fails -> clear both
        if( err1 || err2 )
            {
            aAvailabilityEnum = KErrNotFound;
            aCustomMessage.Zero();
            }
        }   
    else 
        {
        aAvailabilityEnum = KErrNotFound;
        }

    CleanupStack::PopAndDestroy( &documentId );
    CleanupStack::PopAndDestroy(); //settings
    }

//  End of File