Example IETF Profile Agent Plug-in

The IETF Profile Agent plug-in is an ECOM plug-in that uses the SIP Profile Agent plug-in API. The IETF Profile Agent plug-in enters the IETF registration details in the request headers.

The main functions of the ECom plug-in are:

  • to register, update, and deregister IETF SIP profiles that use the SIP Client API

  • to handle many SIP connections when several SIP profiles are enabled at the same time but, do not use the same Internet Access Point (IAP)

  • to provide HTTP Digest settings from SIP Profiles to the SIP Client API

The plug-in uses the SIP Profile Finite State Machine (FSM) API which implements a state machine for SIP Profiles. The FSM API responds to registration events and notifies the client about changes in the profile registration status. It also provides common error handling and handling of connection state changes.

The following sections provide information about the uses of the plug-in and the source code for the plug-in:

Typical uses of the IETF Profile Agent plug-in

Registering an IETF profile

Load the IETF Profile Agent plug-in and register an IETF profile. The following steps describe the IETF profile registration process:

  1. The SIP Profile Server sends a profile registration request to the IETF plug-in.

  2. The plug-in finds a context for the profile that use the connection context and passes the registration request to the profile context class.

  3. The profile context class passes the request to the SIP Profile FSM class, which sets the profile state to RegistrationInProgressState and passes the request to the SIP Stack.

  4. The SIP Stack responds to the profile context after the registration process is complete.

  5. The profile state is changed to RegisteredState and the SIP Profile Server is notified.

The following sequence diagram shows the call flow of IETF profile registration process.

Figure 1. IETF profile registration sequence diagram

Updating an IETF profile

To update an IETF profile, the IETF Profile Agent plug-in is loaded and the profile is in the RegisteredState state. The following steps describe how to update the IETF profile:

  1. The SIP Profile Server sends a request to the IETF plug-in to update the IETF profile.

  2. The plug-in finds a context for the profile that use the connection context and passes the profile update request to the profile context class.

  3. The profile context class initiates a request to deregister the old profile, sets the profile state to DeregistrationInProgressState and passes the request to the SIP Stack.

  4. The SIP Stack responds to the profile context after the deregistration process is complete and the profile state is set to DeregisteredState.

  5. The updated profile is registered and the SIP Profile Server is notified.

The following sequence diagram shows the call flow of updating the IETF profile:

Figure 2. IETF profile update sequence diagram

Deregistering an IETF profile

To deregister an IETF profile, the IETF Profile Agent plug-in is loaded and the profile is in the RegisteredState. The following steps describe the IETF profile deregistration process:

  1. The SIP Profile Server sends a profile deregistration request to the IETF plug-in.

  2. The plug-in finds a context for the profile that use the connection context and passes the deregistration request to the profile context class.

  3. The profile context class passes the request to the SIP Profile FSM class, which sets the profile state as DeregistrationInProgressState and passes the request to the SIP Stack.

  4. The SIP Stack responds to the profile context after the deregistration process is complete.

  5. The profile state is changed to DeregisteredState and the SIP Profile Server is notified.

The following sequence diagram shows the call flow of IETF profile deregistration process:

Figure 3. IETF profile deregistration sequence diagram

Source code

Here is the source for the IETF Profile Agent plug-in:

sipietfprofileagent.h

// sipietfprofileagent.h

#ifndef CSIPIETFPROFILEAGENT_H
#define CSIPIETFPROFILEAGENT_H

//  INCLUDES
#include <e32base.h>
#include "sipprofileagent.h"
#include "sipprofileagentobserver.h"
#include "sipprofilefsmuser.h"
#include "sipobserver.h"
#include "siphttpdigestchallengeobserver2.h"


//FORWARD DECLARATIONS
class CSIP;
class CSIPHttpDigest;
class TSIPProfileTypeInfo;
class CSIPIetfConnectionContext;
class CSIPPrflInitState;
class CSIPPrflResolvingProxiesState;
class CSIPPrflRegisterRequestedState;
class CSIPPrflRegistrationInProgressState;
class CSIPPrflRegisteredState;
class CSIPPrflDeregisterRequestedState;
class CSIPPrflDeregistrationInProgressState;
class CSIPPrflRegisterDelayRequestedState;
class CSIPIetfProfileContext;
class CSIPProfileQueueHandling;

// CLASS DECLARATION
/**
*  Registers profiles and maintains
*  profile registrations as per RFC3261.
*  
*  @lib n/a
*/
class CSIPIetfProfileAgent: 
    public CSIPProfileAgent, 
    public MSIPProfileAgentObserver,
    public MSIPProfileFSMUser,
    public MSIPObserver,
    public MSIPHttpDigestChallengeObserver2
    {
    public: // Constructors and destructor
           
        /**
        * Two-phased constructor.
        * @param aInitParams parameters passed in the construction
        */
        static CSIPIetfProfileAgent* NewL(TAny* aInitParams);
    
        /**
        * Destructor.
        */
        virtual ~CSIPIetfProfileAgent();

    public: // From CSIPProfileAgent

        const TSIPProfileTypeInfo& Type() const;
        
        CSIPConcreteProfile* CreateL();
    
        void RegisterL(
            CSIPConcreteProfile& aSIPConcreteProfile);

        void UpdateL(
            CSIPConcreteProfile& aNewProfile, 
            CSIPConcreteProfile& aOldProfile);

        void DeregisterL(
            CSIPConcreteProfile& aSIPConcreteProfile);

        TInt GetProfileState(
            CSIPConcreteProfile::TStatus& aState, 
            CSIPConcreteProfile& aProfile) const;

        TBool IsIdle();
        
        TBool RegisterPending(CSIPConcreteProfile& aSIPProfile) const;

        TInt TerminateHandling(CSIPConcreteProfile& aProfile);

        TInt Extension(TInt aOperationCode, TAny* aParams); 

    public: // From MSIPProfileAgentObserver
    
        void SIPProfileStatusEvent(
            CSIPConcreteProfile& aProfile,
            TUint32 aContextId);

        void SIPProfileErrorEvent(
            CSIPConcreteProfile& aProfile,
            TInt aError);

        TBool ProceedRegistration(CSIPConcreteProfile& aProfile);
        
        void GetFailedProfilesL( 
            const TSIPProfileTypeInfo& aType,
            RPointerArray<CSIPConcreteProfile>& aFailedProfiles) const;    


    public: // From MSIPProfileFSMUser

        void RegisterProfileL(
            CSIPConcreteProfile& aSIPConcreteProfile);

        void DeregisterProfileL(
            CSIPConcreteProfile& aSIPConcreteProfile);

        void RetryProfileRegistrationL( 
            CSIPConcreteProfile& aSIPProfile );

        TBool AddProfileIntoQueue( 
            CSIPConcreteProfile& aSIPConcreteProfile ) const;

        void RegisterProfileAfterQueueL( 
            CSIPConcreteProfile& aSIPConcreteProfile );

        void DeregisterProfileAfterQueueL( 
            CSIPConcreteProfile& aSIPConcreteProfile );

        void RetryProfileRegistrationAfterQueueL( 
            CSIPConcreteProfile& aSIPConcreteProfile );
            
        TBool IsInQueue( 
            CSIPConcreteProfile& aSIPProfile ) const;

        void SetInterimProfile( CSIPConcreteProfile* 
                                            aSIPConcreteProfile );

    public: // From MSIPObserver

        void IncomingRequest(
            TUint32 aIapId,
            CSIPServerTransaction* aTransaction);

        void TimedOut(CSIPServerTransaction& aTransaction);

    public: // From MSIPHttpDigestChallengeObserver2
    
        void ChallengeReceived(const CSIPClientTransaction& aTransaction);

        void ChallengeReceived(const CSIPRefresh& aRefresh);


    private: // Constructors

        /**
        * C++ default constructor.
        */
        CSIPIetfProfileAgent(TSIPProfileAgentInitParams* aInitParams);

        /**
        * By default Symbian 2nd phase constructor is private.
        */
        void ConstructL();

        
    private: // New functions        

        /**
        * Provides profile context
        * @param aProfile a profile
        * @return a profile context
        */
        CSIPIetfProfileContext& ProvideProfileContextL(CSIPConcreteProfile& aProfile);

        /**
        * Finds profile context
        * @param aSIPConcreteProfile a profile
        * @return profile context, the ownership is not transferred
        */
        CSIPIetfProfileContext* FindProfileContext(CSIPConcreteProfile& aSIPConcreteProfile) const;

        /**
        * Finds profile context
        * @param aProfileId identifier of the profile
        * @return profile context, the ownership is not transferred
        */
        CSIPIetfProfileContext* FindProfileContext(TUint32 aProfileId) const;

        /**
        * Finds connection context
        * @param aPriofile a profile
        * @return a connection context
        */
        CSIPIetfConnectionContext* FindConnectionContext(CSIPConcreteProfile& aProfile) const;
    
        /**
        * Destroys idle connection contexts
        */
        void CleanIdleConnectionContexts();
                
        TBool DeregisterToWaitingQueueL( CSIPIetfProfileContext* aContext );
        
        void HandleRegisterQueue( CSIPIetfProfileContext* aContext, TBool aReportError );
        
        void RegisterQueue( CSIPConcreteProfile& aProfile, TBool aReportError );
    
        TBool AllowedTakeFromQueue( CSIPConcreteProfile& aSIPConcreteProfile );
    
    
    private: //  Data

        CSIP*                                    iSIP;
        CSIPHttpDigest*                         iHttpDigest;
        MSIPProfileAgentObserver&                iSIPProfileAgentObserver;
        CDeltaTimer&                            iDeltaTimer;
        TSIPProfileTypeInfo                        iType;
        CSIPPrflInitState*                        iInit;
        CSIPPrflResolvingProxiesState*            iResolvingProxies;
        CSIPPrflRegisterRequestedState*            iRegRequested;
        CSIPPrflRegistrationInProgressState*    iRegInProgress;
        CSIPPrflRegisteredState*                iRegistered;
        CSIPPrflDeregisterRequestedState*        iDeregRequested;
        CSIPPrflDeregistrationInProgressState*    iDeregInProgress;
        CSIPPrflRegisterDelayRequestedState*    iRegDelayRequested;
        RPointerArray<CSIPIetfConnectionContext> iConnectionCtxArray;
        CSIPProfileQueueHandling*                 iProfileQueueHandling;


#ifdef CPPUNIT_TEST    
        friend class CSIPIetfProfileAgentTest;
#endif
    };

#endif CSIPIETFPROFILEAGENT_H

sipietfprofilecontext.h

// sipietfprofilecontext.h

#ifndef SIPIETFPRROFILECONTEXT_H
#define SIPIETFPRROFILECONTEXT_H

//INCLUDES 
#include "sipprofilecontextbase.h"
#include "sipietfconnectioncontext.h"

// FORWARD DECLARATIONS
class CSIPConcreteProfile;


// CLASS DECLARATION
/**
*  Class for maintaining the information related
*  to a particular IETF type profile. Class stores
*  related registration, sip connection and transactions.
*
*  @lib n/a.
*/
class CSIPIetfProfileContext : public CSIPProfileContextBase
    {
    public:
           
        /**
        * Two-phased constructor.
        * @param aSIP a handle to SIP server
        * @param aConnection a SIP connection
        * @param aInitState a init state
        * @param aProfile a profile
        */
        static CSIPIetfProfileContext* NewL(
            CSIP& aSIP,
            CSIPIetfConnectionContext& aConnection,
            MSIPProfileAgentObserver& aObserver,
            CSIPPrflStateBase& aInitState,
            CSIPConcreteProfile& aProfile,
            CDeltaTimer& aDeltaTimer);
        /**
        * Two-phased constructor.
        * @param aSIP a handle to SIP server
        * @param aConnection a SIP connection
        * @param aInitState a init state
        * @param aProfile a profile
        */
        static CSIPIetfProfileContext* NewLC(
            CSIP& aSIP,
            CSIPIetfConnectionContext& aConnection,
            MSIPProfileAgentObserver& aObserver,
            CSIPPrflStateBase& aInitState,
            CSIPConcreteProfile& aProfile,
            CDeltaTimer& aDeltaTimer);
        /**
        * Destructor.
        */
        ~CSIPIetfProfileContext();


    public: // From MSIPProfileContext

        void DestroyRegistration();

        void CreateRegistrationL();

        CSIPMessageElements* CreateMsgElementsLC();
        
        CSIPMessageElements* CreateDeRegisterElementsL();
        
        void UpdateContactHeaderParamsL(CSIPConcreteProfile& aNewProfile);
        
        void SetRegisteredAORsL();    
        
        void ResolveProxyL();
        
        void CancelProxyResolving();    
        
        
    public: // New functions

        /**
        * Deregisters SIP profile according to the profile type.
        * @param aSIPConcreteProfile sip profile to deregister
        */
        void DeregisterL();

         /**
        * Updates SIP profile. This can lead to profile de-registration
        * and registration. Function leaves with KErrArgument if profiles 
        * are the same.
        * @param aNewProfile sip profile to update
        */
        void UpdateL(CSIPConcreteProfile& aNewProfile);

        /**
        * A SIP response creating a registration binding or an error response 
        * that is related to an refreshed registration binding  
        * has been received from the network.
        * @param aTransaction contains response elements.
        * The ownership is transferred.
        * @param aRegistration associated registration
        * @param aHandled, returned ETrue if response handled
        */
        void IncomingResponse(CSIPClientTransaction& aTransaction,
                              CSIPRegistrationBinding& aRegistration,
                              TBool& aHandled);
                              
        TBool RetryTimerInUse();                      
        
        TUint DelayTime();
        TBool RetryAfterTimer();
        
    private: // Constructor
    
        CSIPIetfProfileContext(
            CSIP& aSIP,
            CSIPIetfConnectionContext& iConnection,
            MSIPProfileAgentObserver& aObserver,
            CSIPPrflStateBase& aInitState,
            CSIPConcreteProfile& aProfile,
            CDeltaTimer& aDeltaTimer);
            
        void ConstructL();


    private: // From CSIPProfileContextBase

        void ConnectionStateChangedImpl(CSIPConnection::TState aState);
        
        TBool RetryRegister(CSIPClientTransaction* aTransaction, 
                            TInt aError);
                             
        TBool ShouldRetryRegistration(TInt aError);                     

        void InitializeRetryTimerValue();


    private: // New functions
    
        CSIPMessageElements* CreateMsgElementsForUpdateLC(
            CSIPConcreteProfile& aProfile);
        TUint RandomPercent();
        TBool IsAddressSIPSURIL(const TDesC8& aValue) const;
        HBufC8* SetAddressToSIPSURIL(const TDesC8& aValue);
        TBool SetTlsToSecurityClientL();
        TBool IsDynamicNumericIPAddress( const TDesC8& aValue );
        TBool IsConfiguredOutboundProxySIPURIL( const TDesC8& aValue );
        RStringF TransportProtocol(const CUri8& aUri) const;

    private: // Data
    
        CSIPIetfConnectionContext&    iConnectionContext;
        RStringF iStrNATTraversalRequired;
        TInt64                         iRandomSeed;
        TUint                          iRetryTime;
        TUint                        iRetryCounter;
        TUint                        iRetryCounterSum;
        TBool                        iRetryTimerUse;

    private: // For testing purposes

        friend class CSIPIetfProfileContextTest;
        friend class CSIPIetfConnectionContextTest;
        friend class CSIPIetfProfileAgentTest;
    };

#endif

sipietfconnectioncontext.h

// sipietfconnectioncontext.h

#ifndef    CSIPIETFCONNECTIONCONTEXT_H
#define CSIPIETFCONNECTIONCONTEXT_H

//  INCLUDES
#include <e32base.h>
#include <bamdesca.h>
#include "sipconnectionobserver.h"
#include "MSIPProxyResolverObserver.h"

// FORWARD DECLARATIONS
class CSIPIetfProfileContext;
class CSIPRegistrationBinding;
class CSIPClientTransaction;
class CSIPDialogAssocBase;
class CSIPProxyResolver;
class CSIPHttpDigest;

// CLASS DECLARATION

/**
* Class maintains associations between the SIP connection
* and related SIP profiles. 
* 
*/
class CSIPIetfConnectionContext: public CBase, public MSIPConnectionObserver,
    public MSIPProxyResolverObserver
    {
    public: // Constructors and destructor
           
        /**
        * Two-phased constructor.
        */
        static CSIPIetfConnectionContext* NewL();

        /**
        * Two-phased constructor.
        */
        static CSIPIetfConnectionContext* NewLC();

        /**
        * Destructor.
        */
        ~CSIPIetfConnectionContext();

    public://new functions

        /**
        * Gets connection, the ownership is not transferred
        * @return connection
        */
        CSIPConnection* Connection();

        /**
        * Add profile context, ownership transferred
        * @param aContext, profile context using the connection
        */
        void AddProfileContextL(CSIPIetfProfileContext* aContext);

        /**
        * Find context of the profile, the ownership is not transferred
        * @param aProfileId, profile stored in context
        */
        CSIPIetfProfileContext* FindContext(TUint32 aProfileId);

        /**
        * Delete idle contexts
        */
        void CleanIdleContexts();

        /**
        * Set connection for the context
        * @param aConnection, connection of the context
        */
        void SetConnection(CSIPConnection* aConnection);

        /**
        * Checks if connection idle
        * @return ETrue, if contains no profile contexts, otherwise EFalse
        */
        TBool IsIdle() const;

        /**
        * starts resolving proxy
        */
        void ResolveL();

        /**
        * Cleans dynamic proxy addresses and cancels any
        * pending requests
        */
        void CleanProxyResolving();
        
        /**
        * Checks if registration/deregistration should be put
        * in queue to wait, because there is registration/deregistration
        * with same registrar address pending.
        * @return ETrue if should be put into queue to wait.
        */
        TBool AddIntoQueue( const TDesC8& aValue );

        /**
        * Sets HTTP Digest credentials from the profile
        * if the given transaction was found from one 
        * of the profiles related to this connection.
        * @return ETrue if the transaction was found and credentials were set.
        */
        TBool SetCredentials(
            const CSIPClientTransaction& aTransaction,
            CSIPHttpDigest& aDigest);

        /**
        * Sets HTTP Digest credentials from the profile
        * if the given refresh was found from one 
        * of the profiles related to this connection.
        * @return ETrue if the refresh was found and credentials were set.
        */
        TBool SetCredentials(
            const CSIPRefresh& aRefresh,
            CSIPHttpDigest& aDigest);

    public://functions from base class

        /**
        * A SIP request outside a dialog has been received from the network.
        * @param aTransaction SIP server transaction
        * The ownership is transferred.
        */
        void IncomingRequest (CSIPServerTransaction* 
                                      aTransaction);

        /**
        * A SIP request within a dialog has been received from the network.
        * The client must resolve the actual dialog association to which
        * this request belongs.
        * @param aTransaction SIP server transaction
        * The ownership is transferred.
        * @param aDialog the dialog  that
        *        this transaction belongs to.
         */
        void IncomingRequest (
                    CSIPServerTransaction* aTransaction,
                    CSIPDialog& aDialog);

        /**
        * A SIP response received from the network.
        * @param aTransaction contains response elements.
        * The ownership is transferred.
        */
        void IncomingResponse (CSIPClientTransaction& 
                                       aTransaction);

        /**
        * A SIP response that is within a dialog association or creates
        * a dialog association.
        * @param aTransaction contains response elements.
        * The ownership is transferred.
        * @param aDialogAssoc a dialog association
        */
        void IncomingResponse (
                    CSIPClientTransaction& aTransaction,
                    CSIPDialogAssocBase& aDialogAssoc);

        /**
        * A SIP response creating a registration binding or an error response 
        * that is related to an refreshed registration binding  
        * has been received from the network.
        * @param aTransaction contains response elements.
        * The ownership is transferred.
        * @param aSIPRegistration associated registration
        */
        void IncomingResponse (
                    CSIPClientTransaction& aTransaction,
                    CSIPRegistrationBinding& aRegistration);

        /**
        * A SIP response related a registration binding or an error response
        * that is related to registration binding has been received
        * from the network.
        *
        * @param aTransaction contains response elements.
        * @param aRegistration registration this transaction belongs to
        */
        void IncomingResponse (
                    CSIPClientTransaction& aTransaction,
                    CSIPInviteDialogAssoc* aDialogAssoc);

        /**
        * An asynchronous error has occurred related to a periodical refresh 
        * that relates to a registration.
        * @param aError error code
        * @param aSIPRegistration associated registration
        */
        void ErrorOccured (
                    TInt aError,
                    CSIPRegistrationBinding& aRegistration);
        /**
        * An asynchronous error has occurred in the stack related
        * to the request indicated by the given transaction.
        * @param aError error code
        * @param aTransaction the failed transaction
        * @param aRegistration the failed registration
        */
        void ErrorOccured (
                    TInt aError,
                    CSIPClientTransaction& aTransaction,
                    CSIPRegistrationBinding& aRegistration);

        /**
        * An asynchronous error has occurred in the stack related to the
        * request indicated by the given transaction.
        * @param aError error code
        * @param aTransaction failed transaction
        */
        void ErrorOccured (
                    TInt aError,
                    CSIPTransactionBase& aTransaction);
    
        /**
        * An asynchronous error has occured related to a request within
        * an existing dialog.
        * @param aError error code
        * @param aTransaction the failed transaction
        * @param aDialogAssoc the failed dialog association
        */
        void ErrorOccured (
                    TInt aError,
                    CSIPTransactionBase& aTransaction,
                    CSIPDialogAssocBase& aDialogAssoc);

        /**
        * An asynchronous error has occured related to a refresh 
        * @param aError error code
        * @param aSIPRefresh original refresh object
        */
        void ErrorOccured (
                    TInt aError,
                    CSIPRefresh& aRefresh);

        /**
        * An asynchronous error has occured related to a periodical refresh 
        * that belongs to SIP dialog association.
        * @param aError error code
        * @param aDialogAssoc SIP dialog association
        */
        void ErrorOccured (
                    TInt aError,
                    CSIPDialogAssocBase& aDialogAssoc);

        /**
        * Connection state has changed.
        * @param aState indicates the current connection state
        */
        void ConnectionStateChanged (
                    CSIPConnection::TState aState);

        /**
        * SIP stack has completed UAC core INVITE transaction 64*T1 seconds
        * after the reception of the first 2xx response. No more 2xx responses
        * can be received to the issued single INVITE.
        *
        * @param aTransaction a complete UAC core INVITE transaction
        */
        void InviteCompleted (CSIPClientTransaction& aTransaction);
        
        /**
        * Invite was cancelled with the CANCEL
        * @param aTransaction a cancelled INVITE UAS transaction
        */
        void InviteCanceled (CSIPServerTransaction& aTransaction);


        /**
        * An asynchronous proxy resolving request has been completed.
        * @param aRequestId the id of the resolving request.
        * @param aProxies a list of proxy addresses.
        *        The ownership is transferred.
        */
        void ProxyResolvingRequestComplete (TUint aRequestId,
                                                MDesC8Array* aProxies);

        /**
        * An asynchronous proxy resolving request has failed.
        * @param aRequestId the id of the resolving request.
        * @param aError a reason why the request failed.
        */
        void ProxyResolvingRequestFailed (TUint aRequestId, TInt aError);

        /**
        * starts resolving proxy
        */
        void ResolveProxyL();

    private:
        /**
        * Default constructor.
        */
        CSIPIetfConnectionContext();

        /**
        * By default Symbian 2nd phase constructor is private.
        */
        void ConstructL();


    private:
        CSIPConnection* iConnection;

        CSIPProxyResolver* iProxyResolver;
        TUint iProxyResolveRequestId;

        RPointerArray<CSIPIetfProfileContext> iContexts;

        friend class CSIPIetfProfileContextTest;
        friend class CSIPIetfConnectionContextTest;
    };

#endif

sipietfprofileagent.cpp

//sipietfprofileagent.cpp

// INCLUDE FILES
#include    "sipietfprofileagent.h"
#include    "sipconcreteprofile.h"
#include    "sipprofileagentobserver.h"
#include    "sipconnection.h"
#include    "sipprflinitstate.h"
#include    "sipprflresolvingproxiesstate.h"
#include    "sipprflregisterrequestedstate.h"
#include    "sipprflregisterdelayrequestedstate.h"
#include    "sipprflregistrationinprogressstate.h"
#include    "sipprflregisteredstate.h"
#include    "sipprflderegistrationinprogressstate.h"
#include    "sipprflderegisterrequestedstate.h"
#include    "sipprflstatebase.h"
#include    "sipietfprofilecontext.h"
#include    "sipgendefs.h"
#include    "SipProfileLog.h"
#include    "sipstrings.h"
#include    "sipstrconsts.h"
#include    "sipprofilequeuehandling.h"
#include    "sip.h"
#include    "siphttpdigest.h"
#include    "sipservertransaction.h"
#include    <sipprofile.h>

_LIT8(KSIPIETFProfileType, "IETF");

// ============================ MEMBER FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CSIPIetfProfileAgent* CSIPIetfProfileAgent::NewL(TAny* aInitParams)
    {
    CSIPIetfProfileAgent* self = new (ELeave) CSIPIetfProfileAgent(
        static_cast<TSIPProfileAgentInitParams*>(aInitParams));
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop(self);
    return self;
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::CSIPIetfProfileAgent
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CSIPIetfProfileAgent::CSIPIetfProfileAgent(TSIPProfileAgentInitParams* aInitParams)
    : iSIPProfileAgentObserver(aInitParams->iSIPProfileAgentObserver),
      iDeltaTimer(aInitParams->iDeltaTimer)
    {
    iType.iSIPProfileClass = TSIPProfileTypeInfo::EInternet;
    iType.iSIPProfileName = KSIPIetfType();
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CSIPIetfProfileAgent::ConstructL()
    {
    SIPStrings::OpenL();
    iInit = CSIPPrflInitState::NewL(*this);
    iResolvingProxies = CSIPPrflResolvingProxiesState::NewL(*this);
    iRegRequested = CSIPPrflRegisterRequestedState::NewL(*this);
    iRegInProgress = CSIPPrflRegistrationInProgressState::NewL(*this);
    iRegistered = CSIPPrflRegisteredState::NewL(*this);
    iDeregRequested = CSIPPrflDeregisterRequestedState::NewL(*this);
    iDeregInProgress = CSIPPrflDeregistrationInProgressState::NewL(*this);
    iRegDelayRequested = CSIPPrflRegisterDelayRequestedState::NewL(*this);
    iInit->LinkStates(*iResolvingProxies, *iRegRequested, *iRegInProgress);
    iResolvingProxies->LinkStates(*iInit, *iRegRequested, *iRegInProgress);
    iRegRequested->LinkStates(*iInit, *iResolvingProxies, *iRegInProgress);
    iRegInProgress->LinkStates(*iRegRequested, *iInit, *iRegistered,
                               *iRegDelayRequested);
    iRegistered->LinkStates(*iDeregRequested, *iDeregInProgress,
                             *iInit, *iRegRequested,*iRegDelayRequested);
    iDeregRequested->LinkStates(*iInit, *iRegistered, *iDeregInProgress);
    iDeregInProgress->LinkStates(*iInit);
    iRegDelayRequested->LinkStates(*iInit);
    iProfileQueueHandling = CSIPProfileQueueHandling::NewL(*this);
    
    iSIP = CSIP::NewL(TUid::Null(),*this);
    iHttpDigest = CSIPHttpDigest::NewL(*iSIP,*this);
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::~CSIPIetfProfileAgent
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
CSIPIetfProfileAgent::~CSIPIetfProfileAgent()
    {
    delete iInit;
    delete iResolvingProxies;
    delete iRegRequested;
    delete iRegistered;
    delete iRegInProgress;
    delete iDeregRequested;
    delete iDeregInProgress;
    delete iRegDelayRequested;
    delete iProfileQueueHandling;
    iConnectionCtxArray.ResetAndDestroy();
    iConnectionCtxArray.Close();
    SIPStrings::Close();
    delete iHttpDigest;
    delete iSIP;
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::SIPProfileAgentType
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
const TSIPProfileTypeInfo& CSIPIetfProfileAgent::Type() const
    {
    return iType;
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::CreateL
// -----------------------------------------------------------------------------
//
CSIPConcreteProfile* CSIPIetfProfileAgent::CreateL()
    {
    TSIPProfileTypeInfo type;        
    type.iSIPProfileClass = TSIPProfileTypeInfo::EInternet;
    type.iSIPProfileName = KSIPIETFProfileType;

    CSIPConcreteProfile* profile = CSIPConcreteProfile::NewL();
    profile->SetProfileType(type);
    return profile;
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::RegisterL
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CSIPIetfProfileAgent::RegisterL(
    CSIPConcreteProfile& aSIPConcreteProfile)
    {
    __ASSERT_ALWAYS (aSIPConcreteProfile.AOR().Length() > 0, 
        User::Leave(KErrArgument));
    __ASSERT_ALWAYS (aSIPConcreteProfile.Server(KSIPRegistrar).Length(),
        User::Leave(KErrArgument));

    PROFILE_DEBUG3("CSIPIetfProfileAgent::RegisterL", aSIPConcreteProfile.Id())
    
    if (!iProfileQueueHandling->AddRegisterToQueueL( aSIPConcreteProfile, 
                                                     EFalse ))
        {
        CSIPIetfProfileContext* context = FindProfileContext(aSIPConcreteProfile);
        if (!context)
            {
            context = &ProvideProfileContextL(aSIPConcreteProfile);
            }        
        context->RegisterL();
        }
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::UpdateL
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CSIPIetfProfileAgent::UpdateL(
    CSIPConcreteProfile& aNewProfile, 
    CSIPConcreteProfile& aOldProfile)
    {
    PROFILE_DEBUG3("CSIPIetfProfileAgent::UpdateL", aOldProfile.Id())
    iProfileQueueHandling->Cleanup(aOldProfile,&aNewProfile);
    CSIPIetfProfileContext* context = FindProfileContext(aOldProfile);
    if (!context)
        {
        User::Leave(KErrNotFound);
        }
    context->UpdateL(aNewProfile);
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::DeregisterL
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CSIPIetfProfileAgent::DeregisterL(
    CSIPConcreteProfile& aSIPConcreteProfile)
    {
    PROFILE_DEBUG3("CSIPIetfProfileAgent::DeregisterL", aSIPConcreteProfile.Id())
    CSIPIetfProfileContext* context = FindProfileContext(aSIPConcreteProfile);
    if ( context )
        {
        if ( !DeregisterToWaitingQueueL( context ))
            {
            context->DeregisterL();
            }
        }
    else
        {
        iProfileQueueHandling->RemoveProfileFromRegQueueL(aSIPConcreteProfile);
        }     
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::GetProfileState
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TInt CSIPIetfProfileAgent::GetProfileState(
    CSIPConcreteProfile::TStatus& aState, 
    CSIPConcreteProfile& aProfile) const
    {
    CSIPIetfProfileContext* context = FindProfileContext(aProfile);
    if (context)
        {
        aState = context->CurrentMappedState();
        return KErrNone;
        }
    else
        {
        return KErrNotFound;
        }
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::IsIdle
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CSIPIetfProfileAgent::IsIdle()
    {
    CleanIdleConnectionContexts();
    return (iConnectionCtxArray.Count()==0);
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::RegisterPending
// -----------------------------------------------------------------------------
//    
TBool CSIPIetfProfileAgent::RegisterPending(
    CSIPConcreteProfile& aSIPProfile) const
    {
    PROFILE_DEBUG3("CSIPIetfProfileAgent::IsRegisterPending", aSIPProfile.Id()) 
    
    CSIPIetfProfileContext* context = FindProfileContext(aSIPProfile);
    if (context)
        {
        return context->IsRegisterPending();
        }
    return EFalse;
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::TerminateHandling
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TInt CSIPIetfProfileAgent::TerminateHandling(CSIPConcreteProfile& aProfile)
    {
    CSIPIetfProfileContext* context = FindProfileContext(aProfile);
    if (context)
        {
        PROFILE_DEBUG3("CSIPIetfProfileAgent::TerminateHandling", aProfile.Id())
        context->SetNextState(*iInit);
        context->TerminateHandling();
        return KErrNone;
        }
    else
        {
        return KErrNotFound;
        }
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::Extension
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TInt CSIPIetfProfileAgent::Extension(TInt /*aOperationCode*/, TAny* /*aParams*/)
    {
    return KErrNotSupported;
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::SIPProfileStatusEvent
// -----------------------------------------------------------------------------
//
void CSIPIetfProfileAgent::SIPProfileStatusEvent(
    CSIPConcreteProfile& aProfile,
    TUint32 aContextId)
    {
    PROFILE_DEBUG4("CSIPIetfProfileAgent::SIPProfileStatusEvent",\
        aProfile.Id(), aContextId)
        
    CSIPIetfProfileContext* context = FindProfileContext( aProfile.Id() );
    
    HandleRegisterQueue( context, ETrue );
    
    iSIPProfileAgentObserver.SIPProfileStatusEvent( aProfile, aContextId );
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::SIPProfileErrorEvent
// -----------------------------------------------------------------------------
//
void CSIPIetfProfileAgent::SIPProfileErrorEvent(
    CSIPConcreteProfile& aProfile,
    TInt aError)
    {
    PROFILE_DEBUG4("CSIPIetfProfileAgent::ErrorEvent", aProfile.Id(), aError)
    CSIPIetfProfileContext* context = FindProfileContext(aProfile.Id());

    if (context && context->IgnoreErrorEvent())
        {
        PROFILE_DEBUG4("CSIPIetfProfileAgent::Error ignored",\
                       aProfile.Id(), aError)    
        }
    else
        {
        PROFILE_DEBUG4("CSIPIetfProfileAgent::Error sent", 
                       aProfile.Id(), aError)
            
        RegisterQueue( aProfile, EFalse );
            
        iSIPProfileAgentObserver.SIPProfileErrorEvent(aProfile,aError);
        }
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::ProceedRegistration
// -----------------------------------------------------------------------------
//
TBool CSIPIetfProfileAgent::ProceedRegistration(
    CSIPConcreteProfile& aProfile)
    {
    PROFILE_DEBUG3("CSIPIetfProfileAgent::ProceedRegistration", aProfile.Id())
    return iSIPProfileAgentObserver.ProceedRegistration(aProfile);
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::GetFailedProfilesL
// -----------------------------------------------------------------------------
//
void CSIPIetfProfileAgent::GetFailedProfilesL(
    const TSIPProfileTypeInfo& /*aType*/,
    RPointerArray<CSIPConcreteProfile>& /*aFailedProfiles*/) const
    {
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::RegisterProfileL
// From MSIPProfileFSMUser
// -----------------------------------------------------------------------------
//    
void CSIPIetfProfileAgent::RegisterProfileL(
    CSIPConcreteProfile& aSIPProfile)
    {
    RegisterL(aSIPProfile);
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::DeregisterProfileL
// From MSIPProfileFSMUser
// -----------------------------------------------------------------------------
//
void CSIPIetfProfileAgent::DeregisterProfileL(
    CSIPConcreteProfile& aSIPProfile)
    {
    DeregisterL(aSIPProfile);
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::RetryProfileRegistrationL
// From MSIPProfileFSMUser
// -----------------------------------------------------------------------------
//
void CSIPIetfProfileAgent::RetryProfileRegistrationL( 
    CSIPConcreteProfile& aSIPProfile)
    {
    PROFILE_DEBUG3("CSIPIetfProfileAgent::RetryProfileRegistrationL", 
                   aSIPProfile.Id())

    if (!iProfileQueueHandling->AddRegisterToQueueL(aSIPProfile, ETrue))
        {
        CSIPIetfProfileContext* context = FindProfileContext(aSIPProfile);
        if (!context)
            {
            User::Leave(KErrNotFound);
            }        
        context->RetryRegistration();
        }    
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::AddProfileIntoQueue
// From MSIPProfileFSMUser
// -----------------------------------------------------------------------------
//
TBool CSIPIetfProfileAgent::AddProfileIntoQueue(
    CSIPConcreteProfile& aSIPProfile) const
    {
    PROFILE_DEBUG3("CSIPIetfProfileAgent::AddProfileIntoQueue", 
                   aSIPProfile.Id())
    
    TBool found = EFalse;
    for (TInt i=0; i < iConnectionCtxArray.Count() && !found; i++)
        {
        found = iConnectionCtxArray[i]->AddIntoQueue(
            aSIPProfile.Server(KSIPRegistrar));
        }
    return found;
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::RegisterProfileAfterQueueL
// From MSIPProfileFSMUser
// -----------------------------------------------------------------------------
//
void CSIPIetfProfileAgent::RegisterProfileAfterQueueL(
    CSIPConcreteProfile& aSIPProfile)
    {
    PROFILE_DEBUG3("CSIPIetfProfileAgent::RegisterProfileAfterQueueL", 
                   aSIPProfile.Id())    
    
    CSIPIetfProfileContext* context = FindProfileContext(aSIPProfile);
    if (!context)
        {
        context = &ProvideProfileContextL(aSIPProfile);
        } 
    context->RegisterL();   
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::DeregisterProfileAfterQueueL
// From MSIPProfileFSMUser
// -----------------------------------------------------------------------------
//
void CSIPIetfProfileAgent::DeregisterProfileAfterQueueL(
    CSIPConcreteProfile& aSIPProfile)
    {
    PROFILE_DEBUG3("CSIPIetfProfileAgent::DeregisterProfileAfterQueueL", 
                   aSIPProfile.Id())    
    
    CSIPIetfProfileContext* context = FindProfileContext(aSIPProfile);
    __ASSERT_ALWAYS(context != NULL, User::Leave(KErrNotFound));
    context->DeregisterL();
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::RetryProfileRegistrationAfterQueueL
// From MSIPProfileFSMUser
// -----------------------------------------------------------------------------
//
void CSIPIetfProfileAgent::RetryProfileRegistrationAfterQueueL(
    CSIPConcreteProfile& aSIPProfile)
    {
    PROFILE_DEBUG3("CSIPIetfProfileAgent::RetryProfileRegistrationAfterQueueL", 
                   aSIPProfile.Id())    
    
    CSIPIetfProfileContext* context = FindProfileContext(aSIPProfile);
    __ASSERT_ALWAYS(context != NULL, User::Leave(KErrNotFound));
    context->RetryRegistration();   
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::IsInQueue
// From MSIPProfileFSMUser
// -----------------------------------------------------------------------------
//
TBool CSIPIetfProfileAgent::IsInQueue(
    CSIPConcreteProfile& aSIPProfile) const
    {
    PROFILE_DEBUG1("CSIPIetfProfileAgent::IsInQueue")
    PROFILE_DEBUG3("CSIPIetfProfileAgent::IsInQueue", 
                   aSIPProfile.Id())    
    return iProfileQueueHandling->IsInQueue(aSIPProfile);
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::SetInterimProfile
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CSIPIetfProfileAgent::SetInterimProfile( CSIPConcreteProfile* /*aSIPConcreteProfile*/ )
    {

    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::IncomingRequest
// From MSIPObserver
// -----------------------------------------------------------------------------
//
void CSIPIetfProfileAgent::IncomingRequest(
    TUint32 /*aIapId*/,
    CSIPServerTransaction* aTransaction)
    {
    // Should not be called, because CSIP is created with a NULL UID
    // Delete the transaction to prevent a memory leak
    delete aTransaction;
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::TimedOut
// From MSIPObserver
// -----------------------------------------------------------------------------
//
void CSIPIetfProfileAgent::TimedOut(CSIPServerTransaction& /*aTransaction*/)
    {
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::ChallengeReceived
// From MSIPHttpDigestChallengeObserver2
// -----------------------------------------------------------------------------
//
void CSIPIetfProfileAgent::ChallengeReceived(
    const CSIPClientTransaction& aTransaction)
    {
    TBool found = EFalse;
    for (TInt i=0; i < iConnectionCtxArray.Count() && !found; i++)
        {
        found = 
            iConnectionCtxArray[i]->SetCredentials(aTransaction,*iHttpDigest);
        }
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::ChallengeReceived
// From MSIPHttpDigestChallengeObserver2
// -----------------------------------------------------------------------------
//
void CSIPIetfProfileAgent::ChallengeReceived(const CSIPRefresh& aRefresh)
    {
    TBool found = EFalse;
    for (TInt i=0; i < iConnectionCtxArray.Count() && !found; i++)
        {
        found = iConnectionCtxArray[i]->SetCredentials(aRefresh,*iHttpDigest);
        }
    }

// ----------------------------------------------------------------------------
// CSIPIetfProfileAgent::HandleRegisterQueue
// ----------------------------------------------------------------------------
//
void CSIPIetfProfileAgent::HandleRegisterQueue( 
    CSIPIetfProfileContext* aContext,
    TBool aReportError )
    {
    PROFILE_DEBUG1("CSIPIetfProfileAgent::HandleRegisterQueue") 
    
    if ( !aContext || !aContext->Profile() )
        {
        return;
        }
    
       RegisterQueue( *aContext->Profile(), aReportError );
    }
        
// ----------------------------------------------------------------------------
// CSIPIetfProfileAgent::RegisterQueue
// ----------------------------------------------------------------------------
//
void CSIPIetfProfileAgent::RegisterQueue( 
    CSIPConcreteProfile& aProfile,
    TBool aReportError )
    {
    PROFILE_DEBUG3("CSIPIetfProfileAgent::RegisterQueue", aProfile.Id())    

    TInt err( KErrNone );
    
    if ( AllowedTakeFromQueue( aProfile ) )
        {
        TRAP( err, iProfileQueueHandling->RegisterFromQueueL( aProfile ) );
        }
        
    if ( err && aReportError )
        {
        iSIPProfileAgentObserver.SIPProfileErrorEvent( aProfile, err );
        }
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::AllowedTakeFromQueue
// -----------------------------------------------------------------------------
//    
TBool CSIPIetfProfileAgent::AllowedTakeFromQueue(
    CSIPConcreteProfile& aSIPConcreteProfile )
    {
    PROFILE_DEBUG3("CSIPIetfProfileAgent::AllowedTakeFromQueueL", 
                   aSIPConcreteProfile.Id())     

    return !AddProfileIntoQueue( aSIPConcreteProfile );
    }
    
// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::DeregisterToWaitingQueueL
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//    
TBool CSIPIetfProfileAgent::DeregisterToWaitingQueueL( 
    CSIPIetfProfileContext* aContext )
    {
    PROFILE_DEBUG3("CSIPIetfProfileAgent::DeregisterToWaitingQueueL", 
                   aContext->Profile()->Id())
                   
    if (!aContext->AddDeregisterIntoQueue())
        {
        return EFalse;
        }
    return iProfileQueueHandling->AddDeregisterToQueueL( *aContext->Profile() );
    }    

// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::FindProfileContext
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
CSIPIetfProfileContext* CSIPIetfProfileAgent::FindProfileContext(
    CSIPConcreteProfile& aSIPConcreteProfile) const
    {
    return FindProfileContext(aSIPConcreteProfile.Id());
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::FindProfileContext
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
CSIPIetfProfileContext* CSIPIetfProfileAgent::FindProfileContext(
    TUint32 aProfileId) const
    {
    for (TInt i=0; i < iConnectionCtxArray.Count(); i++)
        {
        CSIPIetfProfileContext *context = 
            iConnectionCtxArray[i]->FindContext(aProfileId);
        if (context)
            {
            return context;
            }
        }
    return 0;
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::FindConnectionContext
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
CSIPIetfConnectionContext* CSIPIetfProfileAgent::FindConnectionContext(
    CSIPConcreteProfile& aProfile) const
    {
    CSIPIetfConnectionContext* context =0;
    TBool found = EFalse;
    for (TInt i=0; i < iConnectionCtxArray.Count() && !found; i++)
        {
        if (iConnectionCtxArray[i]->Connection()->IapId() == aProfile.IapId())
            {
            context = iConnectionCtxArray[i];
            found = ETrue;
            }
        }
    return context;
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::ProvideContextL
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
CSIPIetfProfileContext& CSIPIetfProfileAgent::ProvideProfileContextL(
    CSIPConcreteProfile& aProfile)
    {
    PROFILE_DEBUG3("CSIPIetfProfileAgent::ProvideProfileContextL", 
                   aProfile.Id())
    
    CSIPIetfConnectionContext* connContext = FindConnectionContext(aProfile);
    if (!connContext)
        {
        //must create connection first
        connContext = CSIPIetfConnectionContext::NewLC();
        CSIPConnection* connection = CSIPConnection::NewL(
            *iSIP, aProfile.IapId(), *connContext);
        connContext->SetConnection(connection);
        User::LeaveIfError(iConnectionCtxArray.Append(connContext));
        CleanupStack::Pop();//connContext
        }
    CSIPIetfProfileContext* profilectx = CSIPIetfProfileContext::NewLC(
        *iSIP, *connContext, *this,
        *iInit, aProfile, iDeltaTimer);
    connContext->AddProfileContextL(profilectx);
    CleanupStack::Pop();//profilectx 
    return *profilectx;
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileAgent::ProvideContextL
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CSIPIetfProfileAgent::CleanIdleConnectionContexts()
    {
    CSIPIetfConnectionContext* context = 0;

    for (TInt i=iConnectionCtxArray.Count()-1; i>= 0;)
        {
        iConnectionCtxArray[i]->CleanIdleContexts();
        if (iConnectionCtxArray[i]->IsIdle())
            {
            PROFILE_DEBUG1("CSIPIetfProfileAgent::CleanIdleConnectionContexts,\
                ConnectionContext removed")
            context = iConnectionCtxArray[i];
            iConnectionCtxArray.Remove(i);
            delete context;
            context = NULL;
            }
        i--;
        }
        
    iConnectionCtxArray.Compress();
    }

Sipietfprofilecontext.cpp

//Sipietfprofilecontext.cpp


// INCLUDE FILES
#include "sipietfprofilecontext.h"
#include "sipprflstatebase.h"
#include "sipconcreteprofile.h"
#include "sipietfprofileagent.h"
#include "sipregistrationbinding.h"
#include "sipclienttransaction.h"
#include "siprouteheader.h"
#include "sipgendefs.h"
#include "siprefresh.h"
#include "sipmessagebuilder.h"
#include "sipaddress.h"
#include "siptoheader.h"
#include "siprouteheader.h"
#include "sipmessageelements.h"
#include "sipresponseelements.h"
#include "sipsecurityclientheader.h"
#include "sipconnection.h"
#include "SipProfileLog.h"
#include "sipstrings.h"
#include "sipstrconsts.h"
#include "siperr.h"
#include "sipcodecerr.h"
#include "sipcontactheader.h"
#include <sipprofile.h>
#include <bamdesca.h>
#include <e32math.h>
#include <uri8.h>
#include <uriutils.h>

_LIT8(KNATTraversalRequiredDes, "nat_traversal_required");
_LIT8(KSIPTls, "tls");
_LIT8(KTransportUdpParam, "transport=udp");
_LIT8(KTransportTcpParam, "transport=tcp");

const TUint KMaxRandomLimit = 50;
const TUint KBaseTimeInSec    = 30;
const TUint KWaitTimeCoefficient = 2;
const TUint KRandomDivider        = 100;
const TUint KMaxRetryForOneAddress = 9;

// -----------------------------------------------------------------------------
// CSIPIetfProfileContext::NewLC
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
CSIPIetfProfileContext* CSIPIetfProfileContext::NewLC(
    CSIP& aSIP,
    CSIPIetfConnectionContext& aConnection, 
    MSIPProfileAgentObserver& aObserver,
    CSIPPrflStateBase& aInitState,
    CSIPConcreteProfile& aProfile,
    CDeltaTimer& aDeltaTimer)
    {
    CSIPIetfProfileContext* self = new (ELeave) CSIPIetfProfileContext(aSIP,
        aConnection, aObserver, aInitState, aProfile, aDeltaTimer);
    CleanupStack::PushL(self);
    self->ConstructL();
    return self;
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileContext::NewL
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
CSIPIetfProfileContext* CSIPIetfProfileContext::NewL(
    CSIP& aSIP,
    CSIPIetfConnectionContext& aConnection, 
    MSIPProfileAgentObserver& aObserver,
    CSIPPrflStateBase& aInitState,
    CSIPConcreteProfile& aProfile,
    CDeltaTimer& aDeltaTimer)
    {
    CSIPIetfProfileContext* self = CSIPIetfProfileContext::NewLC(
        aSIP, aConnection, aObserver, aInitState, aProfile, aDeltaTimer);
    CleanupStack::Pop();
    return self;
    }
    
// -----------------------------------------------------------------------------
// CSIPIetfProfileContext::CSIPIetfProfileContext
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
CSIPIetfProfileContext::CSIPIetfProfileContext(
    CSIP& aSIP,
    CSIPIetfConnectionContext& aConnection,
    MSIPProfileAgentObserver& aObserver,
    CSIPPrflStateBase& aInitState,
    CSIPConcreteProfile& aProfile,
    CDeltaTimer& aDeltaTimer)
    : CSIPProfileContextBase(aSIP,
                             *(aConnection.Connection()),
                             aObserver,
                             aInitState,
                             aProfile,
                             aDeltaTimer),
      iConnectionContext(aConnection),
      iRetryTimerUse(EFalse)
    {
    iRandomSeed = 0;
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileContext::ConstructL
// -----------------------------------------------------------------------------
//    
void CSIPIetfProfileContext::ConstructL()
    {
    iStrNATTraversalRequired = 
        SIPStrings::Pool().OpenFStringL(KNATTraversalRequiredDes);
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileContext::~CSIPIetfProfileContext
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
CSIPIetfProfileContext::~CSIPIetfProfileContext()
    {
    iStrNATTraversalRequired.Close();
    }
    
// -----------------------------------------------------------------------------
// CSIPIetfProfileContext::DestroyRegistration()
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CSIPIetfProfileContext::DestroyRegistration()
    {
    PROFILE_DEBUG3("SIPIetfProfileContext::DestroyRegistration", iProfileId)
    delete iRegistration;
    iRegistration = 0;
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileContext::CreateRegistrationL
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CSIPIetfProfileContext::CreateRegistrationL()
    {
    ASSERT(iProfile);
    RStringF transport(SIPStrings::StringF(SipStrConsts::EEmpty));
    CleanupClosePushL(transport);
    CSIPRouteHeader* proxy = 0;
    CUri8* remoteUri = 0;
    CSIPRefresh* refresh = CSIPRefresh::NewLC();
    CSIPToHeader* to = SIPMessageBuilder::CreateToLC(iProfile->AOR());
    to->SetParamL(iStrNATTraversalRequired);
    TUint pops = 2; //initial amount to pop from CleanupStack
    
    const TDesC8& proxyAddr = ProxyAddressL();
    HBufC8* sipsproxy = NULL;
    if(IsAddressSIPSURIL(iProfile->AOR()) && proxyAddr.Length() > 0)
        {
        if (!IsProxyResolvingEnabled())
            {
            __ASSERT_ALWAYS (IsAddressSIPSURIL(proxyAddr), 
                        User::Leave(KErrArgument));
            }
        else
            {
            sipsproxy = SetAddressToSIPSURIL(proxyAddr);
            CleanupStack::PushL(sipsproxy);
            pops++;
            }
        __ASSERT_ALWAYS (!iProfile->IsSecurityNegotiationEnabled(), 
                    User::Leave(KErrArgument));    
        }
        
    if (!sipsproxy)
        {
        sipsproxy = proxyAddr.AllocLC();
        pops++;
        }

    if (sipsproxy->Length()) //there is an outbound proxy defined
        {
        (iProfile->IsSigCompEnabled())?
        proxy = SIPMessageBuilder::CreateRouteLC(*sipsproxy, ETrue):
        proxy = SIPMessageBuilder::CreateRouteLC(*sipsproxy);
        pops++;
        RStringF proxyTransport = TransportProtocol(proxy->SIPAddress().Uri8());    
        if (proxyTransport.DesC().Length() > 0)
            {
            transport = proxyTransport.Copy();
            }        
        }
        
    if (iProfile->Server(KSIPRegistrar).Length()) //there's a registrar defined
        {
        TUriParser8 parser;
        User::LeaveIfError(parser.Parse(iProfile->Server(KSIPRegistrar)));
        remoteUri = CUri8::NewLC(parser);            
        pops++;
        if (!proxy)
            {
            RStringF registrarTransport = TransportProtocol(*remoteUri);        
            if (registrarTransport.DesC().Length() > 0)
                {
                transport = registrarTransport.Copy();
                }
            }
        }        

    TBool sigcomp = iProfile->IsSigCompEnabled();
    
    const TDesC8* user = NULL;
    User::LeaveIfError(
        iProfile->ExtensionParameter(KSIPContactHeaderUser,user));
    
    CSIPContactHeader* contact =
        SIPMessageBuilder::CreateContactLC(*user, KSIPIetfExpiresValue,
                                           iProfile->ContactHeaderParams(),
                                           transport, sigcomp);
    pops++;

    if (IsAddressSIPSURIL(iProfile->AOR()))
        {
        CUri8* contactUriClone = 
            CUri8::NewLC(contact->SIPAddress()->Uri8().Uri());
        contactUriClone->SetComponentL(
            SIPStrings::StringF(SipStrConsts::ESips).DesC(),EUriScheme);
        contactUriClone->SetComponentL(*user,EUriUserinfo);                
        contact->SIPAddress()->SetUri8L(contactUriClone);
        CleanupStack::Pop(contactUriClone);
        }
    
    iRegistration = CSIPRegistrationBinding::NewL(iConnection, to, contact,
                                                  refresh, proxy, remoteUri);
    CleanupStack::Pop(pops);
    delete sipsproxy;
    CleanupStack::PopAndDestroy(1); // transport
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileContext::CreateMsgElementsLC()
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
CSIPMessageElements* CSIPIetfProfileContext::CreateMsgElementsLC()
    {
    ASSERT(iProfile);
    
    CSIPMessageElements* elements = CSIPMessageElements::NewLC();
    
    RPointerArray<CSIPHeaderBase> headers;
    CSIPHeaderBase::PushLC(&headers);
    if (SetTlsToSecurityClientL())
        {
        CSIPSecurityClientHeader* sclient = 
            CSIPSecurityClientHeader::NewLC(KSIPTls);
        headers.AppendL(sclient);
        CleanupStack::Pop(sclient);
        }
        
    if (iProfile->IsSecurityNegotiationEnabled())
        {
        CSIPSecurityClientHeader* sclient = 
            CSIPSecurityClientHeader::NewLC(KSIPdigest);
        headers.AppendL(sclient);
        CleanupStack::Pop(sclient);
        }
        
    TInt sipHeaderCount = iProfile->SIPHeaders().MdcaCount();
    for (TInt i=0; i < sipHeaderCount; i++)
        {
        TPtrC8 headerDes(iProfile->SIPHeaders().MdcaPoint(i));
        CSIPHeaderBase* header = SIPMessageBuilder::CreateHeaderLC(headerDes);
        headers.AppendL(header);
        CleanupStack::Pop(header);
        }   
    
    elements->SetUserHeadersL(headers); // // An empty array is also allowed
    CleanupStack::Pop(1); // headers
        
    return elements;
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileContext::CreateDeRegisterElementsL()
// -----------------------------------------------------------------------------
//    
CSIPMessageElements* CSIPIetfProfileContext::CreateDeRegisterElementsL()
    {
    return NULL;
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileContext::UpdateContactHeaderParamsL
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CSIPIetfProfileContext::UpdateContactHeaderParamsL(
    CSIPConcreteProfile& aNewProfile)
    {
    CSIPContactHeader& contact = Registration()->ContactHeader();
    TPtrC8 paramName;
    TPtrC8 paramValue;

    for (TInt i = Profile()->ContactHeaderParams().MdcaCount()-1;i >= 0; i--)
        {
        TPtrC8 param(Profile()->ContactHeaderParams().MdcaPoint(i));
        SIPMessageBuilder::ParseParamL(param,paramName,paramValue);        
        RStringF name = SIPStrings::Pool().OpenFStringL(paramName);
        CleanupClosePushL(name);
        contact.DeleteParam(name);
        CleanupStack::PopAndDestroy(1); // name
        }

    for (TInt i = 0; &(aNewProfile.ContactHeaderParams()) && 
                     (i < aNewProfile.ContactHeaderParams().MdcaCount()); i++)
        {
        TPtrC8 param(aNewProfile.ContactHeaderParams().MdcaPoint(i));
        TBool hasValue = 
            SIPMessageBuilder::ParseParamL(param,paramName,paramValue);
        RStringF name = SIPStrings::Pool().OpenFStringL(paramName);
        CleanupClosePushL(name);
        if (hasValue)
            {
            RStringF value = SIPStrings::Pool().OpenFStringL(paramValue);
            CleanupClosePushL(value);
            contact.SetParamL(name,value);
            CleanupStack::PopAndDestroy(1); // value
            }
        else
            {
            contact.SetParamL(name);    
            }
        CleanupStack::PopAndDestroy(1); // name    
        }
    
    CSIPMessageElements* elements = CreateMsgElementsForUpdateLC(aNewProfile);
    SetTransaction(Registration()->UpdateL(KSIPIetfExpiresValue, elements));
    CleanupStack::Pop(elements);
    }
    
// -----------------------------------------------------------------------------
// CSIPIetfProfileContext::SetRegisteredAORsL()
// -----------------------------------------------------------------------------
//    
void CSIPIetfProfileContext::SetRegisteredAORsL()
    {
    if (iProfile)
        {
        CDesC8ArrayFlat* array = new(ELeave)CDesC8ArrayFlat(1);
        CleanupStack::PushL(array);    
        array->AppendL(iProfile->AOR());
        iProfile->SetRegisteredAORsL(*array);
        CleanupStack::PopAndDestroy(array);
        if (iRegistration && iRegistration->RegisteredContact())
            {
            HBufC8* contact = 
                iRegistration->RegisteredContact()->ToTextValueLC();
            iProfile->SetExtensionParameterL(KSIPRegisteredContact,*contact);
            CleanupStack::PopAndDestroy(contact);
            }
        }
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileContext::ResolveProxyL
// -----------------------------------------------------------------------------
//    
void CSIPIetfProfileContext::ResolveProxyL()
    {
    iConnectionContext.ResolveL();
    }
       
// -----------------------------------------------------------------------------
// CSIPIetfProfileContext::CancelProxyResolving
// -----------------------------------------------------------------------------
//
void CSIPIetfProfileContext::CancelProxyResolving()
    {
    iConnectionContext.CleanProxyResolving();
    }    

// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------
// CSIPIetfProfileContext::RetryAfterTimer
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//    
TBool CSIPIetfProfileContext::RetryAfterTimer()
    {
    return ( iRetryCounterSum == 0 && iRetryTimerUse );
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileContext::RetryRegister
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//    
TBool CSIPIetfProfileContext::RetryRegister( 
    CSIPClientTransaction* /*aTransaction*/,
    TInt aError )
    {
    PROFILE_DEBUG4("CSIPIetfProfileContext::RetryRegister",
                   aError, iRetryCounterSum)

    TBool retry = EFalse;
        
    if (iProfile &&
        AgentObserver().ProceedRegistration(*iProfile) &&
        (CurrentState() == MSIPProfileContext::ERegistrationInProgress ||
         CurrentState() == MSIPProfileContext::ERegistered) &&
        (aError == KErrSIPOutboundProxyNotResponding || 
         aError == KErrSIPResolvingFailure || 
         aError == KErrTimedOut || 
         aError == KErrSIPTransportFailure && 
         iConnection.State() != CSIPConnection::ESuspended))        
        {
        if ( iRetryCounterSum + 1 < KMaxRetryForOneAddress &&
             iRetryCounter < KMaxRetryForOneAddress )
            {
            retry = ETrue;
            }
        else
            {
            if (iRetryCounterSum < KMaxRetryForOneAddress && 
                iRetryCounter + 1 >= KMaxRetryForOneAddress ||
                iRetryCounter >=  KMaxRetryForOneAddress)
                {
                iRetryCounter = 0;
                retry = RetryPossible(aError);
                }
            else
                {
                retry = ETrue;
                }
            }
        iRetryTimerUse = retry;
        SetRetryPossible(retry);
        }
    else
        {
        iRetryCounter = 0;
        iRetryCounterSum = 0;
        iRetryTimerUse = EFalse;
        }
    if (!retry)
        {
        iRetryCounter = 0;
        iRetryCounterSum = 0;
        }
    return retry;
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileContext::ShouldRetryRegistration
// -----------------------------------------------------------------------------
//    
TBool CSIPIetfProfileContext::ShouldRetryRegistration( TInt aError )
    {
    return (aError == K503ServiceUnavailable || 
            aError == KErrSIPOutboundProxyNotResponding || 
            aError == KErrTimedOut ||
            ((aError == KErrSIPResolvingFailure || 
              aError == KErrSIPTransportFailure) && 
             iConnection.State() != CSIPConnection::ESuspended));
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileContext::InitializeRetryTimerValue
// -----------------------------------------------------------------------------
//    
void CSIPIetfProfileContext::InitializeRetryTimerValue()
    {
    iRetryTimerUse = 0;
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileContext::ConnectionStateChangedImpl
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CSIPIetfProfileContext::ConnectionStateChangedImpl(
    CSIPConnection::TState /*aState*/)
    {
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileContext::DeregisterL
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CSIPIetfProfileContext::DeregisterL()
    {
    PROFILE_DEBUG4("CSIPIetfProfileContext::DeregisterL", iProfileId\
        , iCurrentState->Name())
    iCurrentState->DeregisterL(*this);
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileContext::UpdateL
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CSIPIetfProfileContext::UpdateL(
    CSIPConcreteProfile& aNewProfile)
    {
    PROFILE_DEBUG4("CSIPIetfProfileContext::UpdateL", iProfileId\
        , iCurrentState->Name())
    iCurrentState->UpdateL(*this, aNewProfile);
    }
    
// -----------------------------------------------------------------------------
// CSIPIetfProfileContext::IncomingResponse()
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CSIPIetfProfileContext::IncomingResponse(
    CSIPClientTransaction& aTransaction,
    CSIPRegistrationBinding& aRegistration,
    TBool& aHandled)
    {
    if (iClientTx && iRegistration && 
        aTransaction==*iClientTx && aRegistration==*iRegistration)
        {
        PROFILE_DEBUG3("SIPIetfProfileContext::IncomingResponse", iProfileId)
        aHandled = ETrue;
        const CSIPResponseElements* response = aTransaction.ResponseElements();
        if (response)
            {
            TUint responseCode = response->StatusCode();
            if (responseCode >= K300MultipleChoices)
                {
                PROFILE_DEBUG1("IETFProfileContext: registration failed")
                RetryPossible(responseCode);
                }
            else
                {
                if (responseCode >= K200Ok)
                    {
                    PROFILE_DEBUG1("IETFProfileContext: registration complete")
                    iRetryCounter = 0;
                    iRetryCounterSum = 0;
                    Received2XXRegisterResponse();
                    }
                }
            }
        iCurrentState->ResponseReceived(*this, aTransaction);
        }
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileContext::RandomPercent()
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TUint CSIPIetfProfileContext::RandomPercent()
    {
    const TInt rand = Math::Rand(iRandomSeed);
    TInt result = 0;
    result = KMaxRandomLimit + (rand%KMaxRandomLimit);
    return result;
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileContext::DelayTime()
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TUint CSIPIetfProfileContext::DelayTime()
    {
    PROFILE_DEBUG1("CSIPIetfProfileContext::DelayTime")
    TReal res;
    iRetryCounter++;
    iRetryCounterSum++;
    Math::Pow(res,KWaitTimeCoefficient,iRetryCounter);
    TUint respond = res;
    TUint waitTime = KBaseTimeInSec*respond;
    if (waitTime > 1800)
        {
        waitTime = 1800;
        }
    return ((waitTime*RandomPercent())/KRandomDivider);
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileContext::RetryTimerInUse()
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CSIPIetfProfileContext::RetryTimerInUse()
    {
    return iRetryTimerUse;
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileContext::IsAddressSIPSURIL()
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CSIPIetfProfileContext::IsAddressSIPSURIL(const TDesC8& aValue) const
    {
    __ASSERT_ALWAYS (aValue.Length() > 0, User::Leave(KErrArgument));
    TUriParser8 uriParser;
    User::LeaveIfError(uriParser.Parse(aValue));
    TPtrC8 sips(SIPStrings::StringF(SipStrConsts::ESips).DesC());
    return (uriParser.Extract(EUriScheme).CompareF(sips) == 0);
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileContext::SetAddressToSIPSURIL()
// -----------------------------------------------------------------------------
//
HBufC8* CSIPIetfProfileContext::SetAddressToSIPSURIL(const TDesC8& aValue)
    {
    TUriParser8 uriParser;
    User::LeaveIfError(uriParser.Parse(aValue));
    CUri8* uri = CUri8::NewLC(uriParser);    
    uri->SetComponentL(
        SIPStrings::StringF(SipStrConsts::ESips).DesC(),EUriScheme);
    HBufC8* value = uri->Uri().UriDes().AllocL();
    CleanupStack::PopAndDestroy(uri);
    return value;
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileContext::SetTlsToSecurityClientL()
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CSIPIetfProfileContext::SetTlsToSecurityClientL()
    {
    TBool tlsSet = EFalse;
    if(!IsAddressSIPSURIL(iProfile->AOR()) && 
       iProfile->IsSecurityNegotiationEnabled())
        {
        const TDesC8& proxyAddr = ProxyAddressL();
        if (proxyAddr.Length() > 0)
            {
            if(IsConfiguredOutboundProxySIPURIL(proxyAddr)|| 
               IsDynamicNumericIPAddress(proxyAddr))
                {
                tlsSet = ETrue;
                }
            }
        }
    return tlsSet;
    }
    
// -----------------------------------------------------------------------------
// CSIPIetfProfileContext::IsDynamicNumericIPAddress()
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CSIPIetfProfileContext::IsDynamicNumericIPAddress( const TDesC8& aValue )
    {
    return ( IsProxyResolvingEnabled() && 
         !( UriUtils::HostType( aValue ) == UriUtils::ETextHost ) );
    }    

// -----------------------------------------------------------------------------
// CSIPIetfProfileContext::IsConfiguredOutboundProxySIPURIL()
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CSIPIetfProfileContext::IsConfiguredOutboundProxySIPURIL( const TDesC8& aValue )
    {
    return ( !IsProxyResolvingEnabled() && !IsAddressSIPSURIL(aValue) );
    }    

// -----------------------------------------------------------------------------
// CSIPIetfProfileContext::CreateMsgElementsForUpdateLC
// add SIP headers to REGISTER request
// -----------------------------------------------------------------------------
//
CSIPMessageElements* CSIPIetfProfileContext::CreateMsgElementsForUpdateLC(
    CSIPConcreteProfile& aProfile)
    {
    CSIPMessageElements* elements = CSIPMessageElements::NewLC();
    
    RPointerArray<CSIPHeaderBase> headers;
    CSIPHeaderBase::PushLC(&headers);

    TInt sipHeaderCount = aProfile.SIPHeaders().MdcaCount();
    for (TInt i=0; i < sipHeaderCount; i++)
        {
        TPtrC8 headerDes(aProfile.SIPHeaders().MdcaPoint(i));
        CSIPHeaderBase* header = SIPMessageBuilder::CreateHeaderLC(headerDes);
        headers.AppendL(header);
        CleanupStack::Pop(header);
        }   
        
    elements->SetUserHeadersL(headers); // An empty array is also allowed
    CleanupStack::Pop(1); // headers
        
    return elements;
    }

// -----------------------------------------------------------------------------
// CSIPIetfProfileContext::TransportProtocol
// -----------------------------------------------------------------------------
//
RStringF CSIPIetfProfileContext::TransportProtocol(const CUri8& aUri) const
    {
    RStringF transport(SIPStrings::StringF(SipStrConsts::EEmpty));
    if (aUri.Uri().Extract(EUriPath).FindF(KTransportUdpParam) >= 0)
        {
        transport = SIPStrings::StringF(SipStrConsts::EUdp); 
        }
    if (aUri.Uri().Extract(EUriPath).FindF(KTransportTcpParam) >= 0)
        {
        transport = SIPStrings::StringF(SipStrConsts::ETcp);
        }
    return transport;
    }

Sipietfconnectioncontext.cpp

//Sipietfconnectioncontext.cpp


// INCLUDE FILES

#include    "sipietfconnectioncontext.h"
#include    "sipmessageelements.h"
#include    "sipregistrationbinding.h"
#include    "sipconnection.h"
#include    "sipclienttransaction.h"
#include    "siprefresh.h"
#include    "sipietfprofilecontext.h"
#include    "sipprofileagent.h"
#include    "sipconcreteprofile.h"
#include    "SipProfileLog.h"
#include    "CSIPProxyResolver.h"
#include    "siperr.h"
#include    "sipresponseelements.h"


// ============================ MEMBER FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// CSIPIetfConnectionContext::CSIPIetfConnectionContext
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CSIPIetfConnectionContext::CSIPIetfConnectionContext()
    {
    }

// -----------------------------------------------------------------------------
// CSIPIetfConnectionContext::~CSIPIetfConnectionContext
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
CSIPIetfConnectionContext::~CSIPIetfConnectionContext()
    {
    iContexts.ResetAndDestroy();

    delete iProxyResolver;
    delete iConnection;

    }

// -----------------------------------------------------------------------------
// CSIPIetfConnectionContext::NewLC
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
CSIPIetfConnectionContext* CSIPIetfConnectionContext::NewLC()
    {
    CSIPIetfConnectionContext* self =
        new (ELeave) CSIPIetfConnectionContext();
    CleanupStack::PushL(self);
    self->ConstructL();
    return self;
    }

// -----------------------------------------------------------------------------
// CSIPIetfConnectionContext::NewL
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
CSIPIetfConnectionContext* CSIPIetfConnectionContext::NewL()
    {
    CSIPIetfConnectionContext* self = 
        CSIPIetfConnectionContext::NewLC();
    CleanupStack::Pop();
    return self;
    }

// -----------------------------------------------------------------------------
// CSIPIetfConnectionContext::SetConnection
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CSIPIetfConnectionContext::SetConnection(CSIPConnection* aConnection)
    {
    iConnection = aConnection;
    }

// -----------------------------------------------------------------------------
// CSIPIetfConnectionContext::Connection
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
CSIPConnection* CSIPIetfConnectionContext::Connection()
    {
    return iConnection;
    }

// -----------------------------------------------------------------------------
// CSIPIetfConnectionContext::IsIdle
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CSIPIetfConnectionContext::IsIdle() const
    {
    return (iContexts.Count()==0);
    }

// -----------------------------------------------------------------------------
// CSIPIetfConnectionContext::FindContext
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
CSIPIetfProfileContext* 
    CSIPIetfConnectionContext::FindContext(TUint32 aProfileId)
    {
    CSIPIetfProfileContext* context = 0;
    TBool found = EFalse;
    for (TInt i=0; i<iContexts.Count() && !found; i++)
        {
        if (iContexts[i]->Profile() && iContexts[i]->Profile()->Id() == aProfileId)
            {
            context = iContexts[i];
            found = ETrue;
            }
        }
    return context;
    }

// -----------------------------------------------------------------------------
// CSIPIetfConnectionContext::AddProfileContextL
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void 
CSIPIetfConnectionContext::AddProfileContextL(CSIPIetfProfileContext* aContext)
    {
    __ASSERT_DEBUG(aContext->Connection().IapId()==iConnection->IapId(),
                                                             User::Invariant());
    User::LeaveIfError(iContexts.Append(aContext));
    }

// -----------------------------------------------------------------------------
// CSIPIetfConnectionContext::CleanIdleContexts
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CSIPIetfConnectionContext::CleanIdleContexts()
    {
    PROFILE_DEBUG1("CSIPIetfConnectionContext::CleanIdleContexts")
    CSIPIetfProfileContext* context = 0;
    for (TInt i= iContexts.Count()-1; i >= 0;i--)
        {
        PROFILE_DEBUG3("CSIPIetfConnectionContext::CleanIdleContexts iContexts.Count() > 0 i=",i)
        if (iContexts[i]->CurrentState() == MSIPProfileContext::EInit &&
            iContexts[i]->IsIdle())
            {
            PROFILE_DEBUG1("CSIPIetfConnectionContext::CleanIdleContexts, ProfileContext removed")
            context = iContexts[i];
            iContexts.Remove(i);
            delete context;
            context = NULL;    
            }
        }
    iContexts.Compress();
    }

// -----------------------------------------------------------------------------
// CSIPIetfConnectionContext::SetCredentials
// -----------------------------------------------------------------------------
//
TBool CSIPIetfConnectionContext::SetCredentials(
    const CSIPClientTransaction& aTransaction,
    CSIPHttpDigest& aDigest)
    {
    TBool found = EFalse;
    for (TInt i=0; i < iContexts.Count() && !found; i++)
        {
        found = iContexts[i]->SetCredentials(aTransaction,aDigest);
        }
    return found;   
    }

// -----------------------------------------------------------------------------
// CSIPIetfConnectionContext::SetCredentials
// -----------------------------------------------------------------------------
//
TBool CSIPIetfConnectionContext::SetCredentials(
    const CSIPRefresh& aRefresh,
    CSIPHttpDigest& aDigest)
    {
    TBool found = EFalse;
    for (TInt i=0; i < iContexts.Count() && !found; i++)
        {
        found = iContexts[i]->SetCredentials(aRefresh,aDigest);
        }
    return found;    
    }

// -----------------------------------------------------------------------------
// CSIPIetfConnectionContext::ResolveL
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CSIPIetfConnectionContext::ResolveL()
    {
    CleanProxyResolving();
    ResolveProxyL();
    }

// -----------------------------------------------------------------------------
// CSIPIetfConnectionContext::ResolveProxyL
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CSIPIetfConnectionContext::ResolveProxyL()
    {
    PROFILE_DEBUG1("CSIPIetfConnectionContext::ResolveProxyL")
    if (iProxyResolveRequestId == 0)
        {
        if (iProxyResolver == 0)
            {
            iProxyResolver = CSIPProxyResolver::NewL();
            }

        if (iConnection->State() == CSIPConnection::EActive)
            {
            PROFILE_DEBUG1("CSIPIetfConnectionContext::ResolveProxyL, resolving")
            iProxyResolver->ResolveProxyL(
                iProxyResolveRequestId, iConnection->IapId(), *this);
            }
        }
    PROFILE_DEBUG1("CSIPIetfConnectionContext::ResolveProxyL, exit")
    }

// -----------------------------------------------------------------------------
// CSIPIetfConnectionContext::CleanProxyResolving
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CSIPIetfConnectionContext::CleanProxyResolving()
    {
    PROFILE_DEBUG1("CSIPIetfConnectionContext::CleanProxyResolving")
    if(iProxyResolveRequestId)
        {
        iProxyResolver->Cancel(iProxyResolveRequestId);
        iProxyResolveRequestId = 0;
        }
    }

// -----------------------------------------------------------------------------
// CSIPIetfConnectionContext::ConnectionStateChanged
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CSIPIetfConnectionContext::ConnectionStateChanged (
    CSIPConnection::TState aState)
    {
    PROFILE_DEBUG1("CSIPIetfConnectionContext::ConnectionStateChanged")
    if (aState == CSIPConnection::EActive)
        {
        PROFILE_DEBUG1("ConnectionStateChanged, Active")
        }
    else if (aState == CSIPConnection::EInactive)
        {
        PROFILE_DEBUG1("ConnectionStateChanged, Inactive")
        CleanProxyResolving();
        }
    else
        {
        PROFILE_DEBUG3("ConnectionStateChanged, state: ", aState)
        //makes pclint happy
        }

    CleanIdleContexts();

    for (TInt i=0; i<iContexts.Count(); i++)
        {
        iContexts[i]->ConnectionStateChanged(aState);
        }
    } 

// -----------------------------------------------------------------------------
// CSIPIetfConnectionContext::IncomingResponse
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CSIPIetfConnectionContext::IncomingResponse (
    CSIPClientTransaction& aTransaction,
    CSIPRegistrationBinding& aRegistration)
    {
    PROFILE_DEBUG1("CSIPIetfConnectionContext::IncomingResponse")
    TBool handled = EFalse;

    CleanIdleContexts();

    for (TInt i=0; i<iContexts.Count() && !handled; i++)
        {
        const CSIPResponseElements* response = aTransaction.ResponseElements();
        if (response)
            {
            TBool isErrorResponse = (response->StatusCode() >= 300);
            TInt contextCountBefore = iContexts.Count();
            
            iContexts[i]->IncomingResponse(aTransaction, aRegistration, handled);
            
            TBool contextRemoved = (iContexts.Count() != contextCountBefore);    
            if (handled && !contextRemoved && isErrorResponse)
                {
                iContexts[i]->RetryRegistration();
                }
            }
        }
    }

// -----------------------------------------------------------------------------
// CSIPIetfConnectionContext::ErrorOccured
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CSIPIetfConnectionContext::ErrorOccured (
    TInt aError,
    CSIPClientTransaction& aTransaction,
    CSIPRegistrationBinding& aRegistration)
    {
    PROFILE_DEBUG3("CSIPIetfConnectionContext::ErrorOccured", aError)
    TBool handled = EFalse;

    CleanIdleContexts();

    for (TInt i=0; i<iContexts.Count() && !handled; i++)
        {
        iContexts[i]->ErrorOccured(aError, aTransaction, aRegistration, handled);
        if (handled && (iProxyResolveRequestId == 0))
            {
            if ( iContexts[i]->RetryTimerInUse() )
                {
                iContexts[i]->RetryDeltaTimer( iContexts[i]->DelayTime() );
                }
            else
                {
                iContexts[i]->RetryRegistration();
                }
            }
        }
    }

// -----------------------------------------------------------------------------
// CSIPIetfConnectionContext::ErrorOccured
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CSIPIetfConnectionContext::ErrorOccured (
    TInt aError,
    CSIPRegistrationBinding& aRegistration)
    {
    PROFILE_DEBUG3("CSIPIetfConnectionContext::ErrorOccured", aError)
    TBool handled = EFalse;

    CleanIdleContexts();

    for (TInt i=0; i<iContexts.Count() && !handled; i++)
        {
        if (aError == KErrSIPTerminatedWithResponse)
            {
            const CSIPClientTransaction* transaction = 
            iContexts[i]->Registration()->SIPRefresh()->SIPTransaction();
            if (transaction)
                {
                aError = transaction->ResponseElements()->StatusCode();
                iContexts[i]->CSIPProfileContextBase::ErrorOccured(aError,
                                   const_cast<CSIPClientTransaction&> (*transaction),
                                   aRegistration,
                                   handled);
                }
            else
                {
                iContexts[i]->ErrorOccured(aError, aRegistration, handled);
                }
            }
        else
            {
            iContexts[i]->ErrorOccured(aError, aRegistration, handled);
            }
            
        if (handled && (iProxyResolveRequestId == 0))
            {
            if ( iContexts[i]->RetryTimerInUse() )
                {
                iContexts[i]->RetryDeltaTimer( iContexts[i]->DelayTime() );
                }
            else
                {
                iContexts[i]->RetryRegistration();
                }
            }
        }
    }

// -----------------------------------------------------------------------------
// CSIPIetfConnectionContext::ProxyResolvingRequestComplete
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CSIPIetfConnectionContext::ProxyResolvingRequestComplete (
    TUint /*aRequestId*/, MDesC8Array* aProxies)
    {
    PROFILE_DEBUG1("CSIPIetfConnectionContext::ProxyResolvingRequestComplete")
    iProxyResolveRequestId = 0;

    CleanIdleContexts();

    TInt err = KErrNone;
    for (TInt i=0; i<iContexts.Count(); i++)
        {
        TRAP(err, iContexts[i]->ProxyResolvingRequestCompleteL(*aProxies));
        if (err != KErrNone)
            {
            iContexts[i]->HandleProxyResolvingError(err);    
            }
        }
    delete aProxies;
    }

// -----------------------------------------------------------------------------
// CSIPIetfConnectionContext::ProxyResolvingRequestFailed
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CSIPIetfConnectionContext::ProxyResolvingRequestFailed (
    TUint /*aRequestId*/, TInt aError)
    {
    PROFILE_DEBUG3("CSIPIetfConnectionContext::\
        ProxyResolvingRequestFailed", aError)
    CleanIdleContexts();
    iProxyResolveRequestId = 0;

    for (TInt i=0; i<iContexts.Count(); i++)
        {
        iContexts[i]->ProxyResolvingRequestFailed(aError);
        }
    }

// -----------------------------------------------------------------------------
// CSIPIetfConnectionContext::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CSIPIetfConnectionContext::ConstructL()
    {
    }

// -----------------------------------------------------------------------------
// CSIPIetfConnectionContext::ErrorOccured
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CSIPIetfConnectionContext::ErrorOccured (
    TInt /*aError*/,
    CSIPTransactionBase& /*aTransaction*/)
    {
    }

// -----------------------------------------------------------------------------
// CSIPIetfConnectionContext::IncomingRequest
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CSIPIetfConnectionContext::IncomingRequest (
    CSIPServerTransaction* /*aTransaction*/)
    {
    }

// -----------------------------------------------------------------------------
// CSIPIetfConnectionContext::IncomingRequest
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CSIPIetfConnectionContext::IncomingRequest (
    CSIPServerTransaction* /*aTransaction*/,
    CSIPDialog& /*aDialog*/)
    {
    }

// -----------------------------------------------------------------------------
// CSIPIetfConnectionContext::IncomingResponse
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CSIPIetfConnectionContext::IncomingResponse (
    CSIPClientTransaction& /*aTransaction*/)
    {
    }

// -----------------------------------------------------------------------------
// CSIPIetfConnectionContext::IncomingResponse
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CSIPIetfConnectionContext::IncomingResponse (
    CSIPClientTransaction& /*aTransaction*/,
    CSIPDialogAssocBase& /*aDialogAssoc*/)
    {
    }

// -----------------------------------------------------------------------------
// CSIPIetfConnectionContext::IncomingResponse
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CSIPIetfConnectionContext::IncomingResponse (
    CSIPClientTransaction& /*aTransaction*/,
    CSIPInviteDialogAssoc* /*aDialogAssoc*/)
    {
    }


// -----------------------------------------------------------------------------
// CSIPIetfConnectionContext::ErrorOccured
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CSIPIetfConnectionContext::ErrorOccured (
    TInt /*aError*/,
    CSIPDialogAssocBase& /*aDialogAssoc*/)
    {
    }
// -----------------------------------------------------------------------------
// CSIPIetfConnectionContext::ErrorOccured
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CSIPIetfConnectionContext::ErrorOccured (
    TInt /*aError*/,
    CSIPTransactionBase& /*aTransaction*/,
    CSIPDialogAssocBase& /*aDialogAssoc*/)
    {
    }

// -----------------------------------------------------------------------------
// CSIPIetfConnectionContext::ErrorOccured
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CSIPIetfConnectionContext::ErrorOccured (
    TInt /*aError*/,
    CSIPRefresh& /*aRefresh*/)
    {
    }

// -----------------------------------------------------------------------------
// CSIPIetfConnectionContext::InviteCompleted
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CSIPIetfConnectionContext::InviteCompleted (
    CSIPClientTransaction& /*aTransaction*/)
    {
    }
    
// -----------------------------------------------------------------------------
// CSIPIetfConnectionContext::InviteCanceled
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CSIPIetfConnectionContext::InviteCanceled (CSIPServerTransaction& /*aTransaction*/)
    {
    }

// -----------------------------------------------------------------------------
// CSIPIetfConnectionContext::AddIntoQueue
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TBool CSIPIetfConnectionContext::AddIntoQueue( const TDesC8& aValue )
    {
    PROFILE_DEBUG1("CSIPIetfConnectionContext::AddIntoQue")
    TBool result = EFalse;
    for (TInt i=0; i<iContexts.Count() && !result; i++)
        {
        result = iContexts[i]->AddIntoQueue( aValue );
        }
    return result;
    }

implementationproxy.cpp

//implementationproxy.cpp

#include "sipietfprofileagent.h"
#include <implementationproxy.h>

// Disabled PC-Lint warning for "suspicious typecast" caused by Symbian's
// ECom declarations
/*lint -e611 */


const TImplementationProxy ImplementationTable[] =
    {
    //Implementation UID and pointer to instantiation method
    IMPLEMENTATION_PROXY_ENTRY( 0x101F413A, CSIPIetfProfileAgent::NewL )
    };

EXPORT_C const TImplementationProxy* ImplementationGroupProxy(TInt& aTableCount)
    {
    aTableCount = sizeof(ImplementationTable) / sizeof(TImplementationProxy);

    return ImplementationTable;
    }

101F4139.rss

// 101F4139.rss

#include "registryinfov2.rh"

RESOURCE REGISTRY_INFO theInfo
{
resource_format_version = RESOURCE_FORMAT_VERSION_2;
dll_uid = 0x101F4139;
interfaces = 
    {
    INTERFACE_INFO
        {
        interface_uid = 0x101F4136;
        implementations = 
            {
            IMPLEMENTATION_INFO
                {
                implementation_uid = 0x101F413A;
                version_no = 1;
                display_name = "standard IETF profile agent";
                default_data = "0_IETF";
                }            
            };
        }
    };
}