wvuing/wvuipresence/src/CAPresenceUtils.cpp
changeset 0 094583676ce7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wvuing/wvuipresence/src/CAPresenceUtils.cpp	Thu Dec 17 08:41:52 2009 +0200
@@ -0,0 +1,992 @@
+/*
+* Copyright (c) 2002-2005 Nokia Corporation and/or its subsidiary(-ies). 
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  Utility class for presence functions
+*
+*/
+
+
+
+// INCLUDE FILES
+#include "CAPresenceDefinitions.h"
+#include "CAPresenceUtils.h"
+#include "ChatDebugPrint.h"
+#include "CCAStorageManagerFactory.h"
+#include "MCAStoredContact.h"
+#include "MCAStoredContacts.h"
+#include "MCAWatcherObserver.h"
+#include "CCAPresenceError.h"
+#include "CCAPresenceErrors.h"
+#include "ImpsCSPAllErrors.h"
+#include "CAPresenceConst.h"
+#include "MCAContactList.h"
+#include "TDecodeAttrParams.h"
+#include "SServerPrefers.h"
+#include "MCAPresenceUpdater.h"
+#include "impsbuilddefinitions.h"
+
+#include "WVUIPresenceVariationNG.hrh"
+#include <WVUIPresenceVariationNG.rsg>
+
+#include <PEngWVPresenceAttributes2.h>
+#include <MPEngPresenceAttrModel2.h>
+#include <MPEngContactList2.h>
+#include <MPEngTransactionStatus2.h>
+#include <PEngWVPresenceErrors2.h>
+#include <ImpsErrors.h>
+#include <PEngPresenceEngineErrors2.h>
+#include <MPEngContactItem.h>
+#include <MPEngContactListProperties.h>
+#include <barsread.h> // RResourceReader
+#include <eikenv.h>
+
+// "test character identity and accents, ignore case"
+const TInt KCollationLevel = 1;
+#ifndef IMPS_FETCH_CONTACT_BACKGROUND
+const TInt KMaxIdAtTheTime = 2;
+#else
+const TInt KMaxIdAtTheTime = 20;
+#endif //IMPS_FETCH_CONTACT_BACKGROUND
+
+_LIT( KPanicAttribute, "WVUIPresenceVariation attribute" );
+
+// -----------------------------------------------------------------------------
+// CAPresenceUtils::DecodeOnlineState
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+MCAPresence::TPresenceStatus CAPresenceUtils::DecodeOnlineState(
+    const RPointerArray<CCAState>& aStates,
+    const RPointerArray<MPEngPresenceAttrModel2>& aAttributes )
+    {
+    MCAPresence::TPresenceStatus status( MCAPresence::EUnknown );
+
+    TInt stateCount( aStates.Count() );
+    TBool stateFound( EFalse );
+    for ( TInt stateIndex( 0 ); stateIndex < stateCount && !stateFound; ++stateIndex )
+        {
+        CCAState* state = aStates[stateIndex];
+        TInt stateAttrCount( state->iAttributes.Count() );
+        if ( stateAttrCount == 0 )
+            {
+            // no attributes => default state
+            status = MCAPresence::TPresenceStatus( state->iStateId );
+            }
+        else
+            {
+            // we have a match if:
+            // all attributes defined in state can be found from current
+            // set of attributes with same values as in state.
+
+            stateFound = ETrue;
+            for ( TInt stateAttrIndex( 0 ); stateAttrIndex < stateAttrCount  &&
+                  stateFound; ++stateAttrIndex )
+                {
+                TCAAttribute& stateAttr = state->iAttributes[stateAttrIndex];
+
+                const MPEngPresenceAttrModel2* attr =
+                    FindAttr( stateAttr.iAttribute, aAttributes );
+                if ( attr )
+                    {
+                    // attribute found
+                    if ( attr->DataInt( stateAttr.iField, stateAttr.iGroup )
+                         != stateAttr.iData ||
+                         attr->Qualifier()
+                         != stateAttr.iQualifier )
+                        {
+                        // but different value or qualifier => doesn't match
+                        stateFound = EFalse;
+                        }
+                    }
+                else
+                    {
+                    // not found at all => doesn't match
+                    stateFound = EFalse;
+                    }
+                }
+
+            if ( stateFound )
+                {
+                status = MCAPresence::TPresenceStatus( state->iStateId );
+                }
+            }
+        }
+
+    CHAT_DP_TXT( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" );
+    return status;
+    }
+
+// -----------------------------------------------------------------------------
+// CAPresenceUtils::PopulateAttributes
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CAPresenceUtils::PopulateAttributesL( const MPEngPresenceAttrModel2& aModel,
+                                           RPointerArray<MPEngPresenceAttrModel2>& aArray,
+                                           TStorageManagerGlobals::TClientType& aClientType,
+                                           TPtrC& aAlias,
+                                           TPtrC& aStatusText )
+    {
+    switch ( aModel.Type() )
+        {
+        case KUidPrAttrClientInfo:
+            {
+            aClientType = TStorageManagerGlobals::EUnknownClient;
+            if ( aModel.Qualifier() )
+                {
+                switch ( aModel.DataInt( EPEngCliInfDeviceType ) )
+                    {
+                    case EPEngCliDevTypeMobilePhone:
+                        {
+                        aClientType = TStorageManagerGlobals::EMobile;
+                        break;
+                        }
+                    case EPEngCliDevTypeComputer:
+                        {
+                        aClientType = TStorageManagerGlobals::EPC;
+                        break;
+                        }
+                    default:
+                        {
+                        // nothing to do here
+                        }
+                    }
+                }
+            break;
+            }
+        case KUidPrAttrAlias:
+            {
+            if ( aAlias.Ptr() )
+                {
+                // have valid descriptor to where this points,
+                // otherwise it's unused by the IM Open Conversation
+                // routines
+                aAlias.Set( aModel.DataDesC16( EPEngAlias ) );
+                }
+            break;
+            }
+        case KUidPrAttrStatusText:
+            {
+            if ( ! aStatusText.Ptr() )
+                {
+                // have valid descriptor to where this points,
+                // otherwise it's unused by the IM Open Conversation
+                // routines
+                aStatusText.Set( aModel.DataDesC16( EPEngStatusText ) );
+                }
+            break;
+            }
+        default:
+            {
+            aArray.AppendL( &aModel );
+            break;
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CAPresenceUtils::GenerateFriendsArrayLC
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+CPtrCArray* CAPresenceUtils::GenerateFriendsArrayLC(
+    MCAStoredContacts* aContactStorage )
+    {
+    TInt granularity( aContactStorage->ContactCount() );
+    if ( granularity == 0 )
+        {
+        granularity = 1;
+        }
+
+    CPtrCArray* contactsArray =
+        new ( ELeave ) CPtrCArray( granularity );
+    CleanupStack::PushL( contactsArray );
+
+    TInt listCount( aContactStorage->ListCount() );
+    TKeyArrayFix cmpKey( 0, ECmpCollated );
+    for ( TInt a( 0 ); a < listCount; ++a )
+        {
+        MCAContactList& contactList = aContactStorage->ListAt( a );
+        TInt contactCount( contactList.Count() );
+        for ( TInt b( 0 ); b < contactCount; ++b )
+            {
+            TPtrC userId( contactList[ b ].UserId() );
+            TInt pos( KErrNotFound );
+            if ( userId.Length() > 0 )
+                {
+                // user id exists
+                if ( contactsArray->FindIsq( userId, cmpKey, pos ) != 0 )
+                    {
+                    // user id not found already from the list, so let's add it
+                    contactsArray->InsertIsqL( userId, cmpKey );
+                    }
+                }
+            }
+        }
+    return contactsArray;
+    }
+
+// -----------------------------------------------------------------------------
+// CAPresenceUtils::PushModelArrayL
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CAPresenceUtils::PushModelArrayL(
+    RPointerArray<MPEngPresenceAttrModel2>& aArray, TBool aOwnsItems )
+    {
+    if ( aOwnsItems )
+        {
+        CleanupStack::PushL( TCleanupItem( DestroyCloseModelArray, &aArray ) );
+        }
+    else
+        {
+        CleanupStack::PushL( TCleanupItem( CloseModelArray, &aArray ) );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CAPresenceUtils::DecodeAttrModelsL
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TBool CAPresenceUtils::DecodeAttrModelsL( struct TDecodeAttrParams& aParams )
+    {
+    CHAT_DP_TXT( "CAPresenceUtils::DecodeAttrModelsL  Enter" );
+    // unpack the structure for easier access
+    RPointerArray<CCAState>* states = aParams.iPresenceStates;
+    RPointerArray< MPEngPresenceAttrModel2 >& array = aParams.iArray;
+    MCAStoredContacts* contactStorage = aParams.iContactStorage;
+    MCAWatcherObserver* watcherObserver = aParams.iWatcherObserver;
+    CDesCArray* stateOnline = aParams.iStateOnline;
+    CDesCArray* stateOffline = aParams.iStateOffline;
+    CDesCArray* stateUnknown = aParams.iStateUnknown;
+    TInt& entryIndex = aParams.iEntryIndex;
+
+    TBool done( EFalse ); // flag for loop termination
+    TBool updateUserData( EFalse );
+
+    MPEngPresenceAttrModel2* model = NULL;
+    RPointerArray<MPEngPresenceAttrModel2> attributes;
+    CAPresenceUtils::PushModelArrayL( attributes, EFalse );
+
+    // alias support preparations
+    TPtrC aliasPtr( NULL, 0 );
+    HBufC* dummy = NULL;
+
+    if ( aParams.iServerPrefers.iAliasUsed )
+        {
+        // have alias support
+        // alias ptr must point to non-NULL
+        dummy = HBufC::NewL( 1 );
+        CleanupStack::PushL( dummy );
+        aliasPtr.Set( dummy->Des() );
+        }
+    else
+        {
+        // no alias support
+        aliasPtr.Set( NULL, 0 );
+        }
+    TPtrC statusText( NULL, 0 );
+
+    TStorageManagerGlobals::TPresenceStatus newPresenceStatus =
+        TStorageManagerGlobals::EUnknown;
+    TStorageManagerGlobals::TPresenceStatus oldPresenceStatus =
+        TStorageManagerGlobals::EUnknown;
+    TStorageManagerGlobals::TClientType clientType =
+        TStorageManagerGlobals::EUnknownClient;
+
+    TInt attrCount( array.Count() );
+    const TDesC* lastID = NULL;
+
+    CHAT_DP( D_CHAT_LIT( "DecodeAttrModelsL for %d models" ), attrCount );
+
+    // Loop through all attributes received
+    TInt idCount( 0 );
+    do
+        {
+        updateUserData = EFalse;
+
+        if ( entryIndex < attrCount )
+            {
+            model = array[entryIndex];
+
+            // Create initial userID or
+            // Check if all attributes concerning this user has been processed
+            if ( !lastID )
+                {
+                lastID = &model->PresenceID();
+                }
+            else if ( model->PresenceID() != *lastID )
+                {
+                ++idCount;
+                updateUserData = ETrue;
+                }
+            }
+        else
+            {
+            if ( attrCount > 0 )
+                {
+                updateUserData = ETrue;
+                }
+            done = ETrue;
+            }
+
+        // If all attributes concerning certain user have been collected,
+        // then we can update local presence information concerning that user
+        if ( updateUserData )
+            {
+            newPresenceStatus = MapPresenceStateId(
+                                    DecodeOnlineState( *states, attributes ) );
+
+            CAPresenceUtils::FillArraysL( *lastID, newPresenceStatus,
+                                          stateOnline, stateOffline,
+                                          stateUnknown );
+            if ( contactStorage )
+                {
+                MCAStoredContact* updatedContact = contactStorage->UpdatePresenceL(
+                                                       *lastID, newPresenceStatus,
+                                                       clientType, aliasPtr,
+                                                       statusText,
+                                                       oldPresenceStatus );
+
+                if ( updatedContact )
+                    {
+                    if ( updatedContact->IsWatched()
+                         && watcherObserver
+                         && ( newPresenceStatus != TStorageManagerGlobals::EUnknown )
+                         && !( newPresenceStatus == TStorageManagerGlobals::EOffline
+                               && oldPresenceStatus == TStorageManagerGlobals::EUnknown )
+                       )
+                        {
+                        watcherObserver->HandleWatcherEvent( updatedContact );
+                        }
+                    }
+                }
+
+            // reset attributes
+            attributes.Reset();
+            clientType = TStorageManagerGlobals::EUnknownClient;
+
+            if ( aParams.iServerPrefers.iAliasUsed )
+                {
+                // have alias support
+                // alias ptr must point to non-NULL
+                aliasPtr.Set( dummy->Des() );
+                }
+            statusText.Set( NULL, 0 );
+
+            }
+
+        if ( !done && idCount < KMaxIdAtTheTime )
+            {
+            lastID = &model->PresenceID();
+            CAPresenceUtils::PopulateAttributesL( *model,
+                                                  attributes,
+                                                  clientType,
+                                                  aliasPtr,
+                                                  statusText );
+            }
+
+        ++entryIndex;
+        } while ( !done && idCount < KMaxIdAtTheTime );
+
+
+    --entryIndex;
+
+    if ( aParams.iServerPrefers.iAliasUsed )
+        {
+        CleanupStack::PopAndDestroy( dummy );
+        }
+
+    CleanupStack::PopAndDestroy(); // attributes.Close()
+    CHAT_DP( D_CHAT_LIT( "CAPresenceUtils::DecodeAttrModelsL  Done-:%d" ), done );
+    return !done;
+    }
+
+// -----------------------------------------------------------------------------
+// CAPresenceUtils::HandleListErrorsL
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CAPresenceUtils::HandleListErrorsL( TInt aError )
+    {
+    CHAT_DP( D_CHAT_LIT( "CCAPEngListManager::HandleListErrorsL checking \
+	                      error %d" ), aError );
+
+    if ( aError != KErrNone && aError != KErrNotFound
+         && aError != KErrAlreadyExists )
+        {
+        CHAT_DP_TXT( "Error can not be ignored, leaving..." );
+        User::Leave( aError );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CAPresenceUtils::CompareAttrModelArray
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TInt CAPresenceUtils::CompareAttrModelArray(
+    const MPEngPresenceAttrModel2& aFirst,
+    const MPEngPresenceAttrModel2& aSecond )
+    {
+    return aFirst.PresenceID().CompareC( aSecond.PresenceID(), KCollationLevel,
+                                         NULL );
+    }
+
+// -----------------------------------------------------------------------------
+// CAPresenceUtils::CloseModelArray
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CAPresenceUtils::CloseModelArray( TAny* aObject )
+    {
+    reinterpret_cast<RPointerArray<MPEngPresenceAttrModel2>*>( aObject )->
+    Close();
+    }
+
+// -----------------------------------------------------------------------------
+// CAPresenceUtils::DestroyCloseModelArray
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CAPresenceUtils::DestroyCloseModelArray( TAny* aObject )
+    {
+    reinterpret_cast<RPointerArray<MPEngPresenceAttrModel2>*>( aObject )->
+    ResetAndDestroy();
+    }
+
+// -----------------------------------------------------------------------------
+// CAPresenceUtils::FillArraysL
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CAPresenceUtils::FillArraysL(
+    const TDesC& aUserId,
+    TStorageManagerGlobals::TPresenceStatus aOnlineStatus,
+    CDesCArray *aStateOnline,
+    CDesCArray *aStateOffline,
+    CDesCArray *aStateUnknown )
+    {
+    if ( aUserId == KNullDesC )
+        {
+        // if userID == KNullDesC then this is probably our own presence notify
+        // no need to do anything here
+        return;
+        }
+
+    switch ( aOnlineStatus )
+        {
+        case TStorageManagerGlobals::EOnline:
+        case TStorageManagerGlobals::EAway:
+        case TStorageManagerGlobals::EBusy: // flow through
+            {
+            if ( aStateOnline )
+                {
+                aStateOnline->AppendL( aUserId );
+                }
+            break;
+            }
+        case TStorageManagerGlobals::EOffline:
+            {
+            if ( aStateOffline )
+                {
+                aStateOffline->AppendL( aUserId );
+                }
+            break;
+            }
+        case TStorageManagerGlobals::EUnknown:
+            {
+            if ( aStateUnknown )
+                {
+                aStateUnknown->AppendL( aUserId );
+                }
+            break;
+            }
+        default:
+            {
+            // Unknown state, ignore
+            break;
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CAPresenceUtils::HandleTransactionStatusL
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CAPresenceUtils::HandleTransactionStatusL( MPEngTransactionStatus2&
+                                                aStatus, CCAPresenceErrors& aErrorContainer )
+    {
+    CHAT_DP_TXT( "CAPresenceUtils::HandleTransactionStatusL" );
+
+    // Reset the container
+    aErrorContainer.Reset();
+    aErrorContainer.SetError( CAPresenceUtils::MapErrorPECtoCSP(
+                                  aStatus.Status() ) );
+
+    // If partially successful, then fill the local information
+    if ( aErrorContainer.Error() == ECSPPartiallySuccessful )
+        {
+        CHAT_DP_TXT( "CAPresenceUtils::HandleTransactionStatusL, received \
+                      ECSPPartiallySuccessful" );
+        const MPEngDetailedResultEntry2* detailed = NULL;
+        TPtrC data;
+
+        TInt count( aStatus.DetailedResultCount() );
+        for ( TInt i( 0 ); i < count; ++i )
+            {
+            detailed = &aStatus.DetailedResult( i );
+            detailed->GetDetailedDesc( data, EPEngDTPresenceID );
+            CCAPresenceError* error =
+                CCAPresenceError::NewLC( CAPresenceUtils::MapErrorPECtoCSP(
+                                             detailed->Error() ), data );
+            CHAT_DP( D_CHAT_LIT( "Detailed result (%d): %d: %S" ), i,
+                     error->ErrorCode(), &data );
+
+            // Ownership is passed to error container
+            aErrorContainer.AddDetailedErrorL( error );
+            CleanupStack::Pop( error );
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CAPresenceUtils::MapErrorPECtoCSP
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TInt CAPresenceUtils::MapErrorPECtoCSP( TInt aError )
+    {
+    TInt error( aError );
+
+    // Map everything between KPEngErrorWVServerResponseBase and KPEngErrorBase
+    // to Imps_ERROR_BASE
+    if ( aError < KPEngErrorWVServerResponseBase &&
+         aError > KPEngErrorBase )
+        {
+        error = aError - KPEngErrorWVServerResponseBase + Imps_ERROR_BASE;
+        }
+
+    return error;
+    }
+
+// -----------------------------------------------------------------------------
+// CAPresenceUtils::AppendContactsL
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TBool CAPresenceUtils::AppendContactsL( MPEngContactList2* aContactList,
+                                        CDesCArray* aWVIds,
+                                        CDesCArray* aNicknames,
+                                        MCAStoredContacts* aContactStorage,
+                                        TInt& aEntryIndex,
+                                        MCAContactList& aCaContactList,
+                                        MCAPresenceUpdater& aPresenceUpdater )
+    {
+    // Fill arrays
+    TInt idCount( 0 );
+    TInt count( aContactList->Count() );
+    if ( aEntryIndex >= count )
+        {
+        // list has been changed, possibly we ran out of memory
+        aEntryIndex = count - 1;
+        }
+
+    if ( aWVIds && aNicknames )
+        {
+        while ( ( idCount < KMaxIdAtTheTime ) && ( aEntryIndex >= 0 ) )
+            {
+            MPEngContactItem& contact = aContactList->ContactItem( aEntryIndex );
+            TPtrC id = contact.Id();
+            TPtrC nick( contact.NickName() );
+            // append to lists
+            aWVIds->AppendL( id );
+            aNicknames->AppendL( nick );
+            ++idCount;
+            --aEntryIndex;
+            }
+        }
+    else
+        {
+        RPointerArray<MPEngPresenceAttrModel2> attrModels;
+        CAPresenceUtils::PushModelArrayL( attrModels, ETrue );
+        RPointerArray<MPEngPresenceAttrModel2> onlineStateModels;
+        CAPresenceUtils::PushModelArrayL( onlineStateModels, EFalse );
+
+        TPtrC aliasPtr( NULL, 0 );
+        TPtrC statusText( NULL, 0 );
+        TStorageManagerGlobals::TClientType clientType =
+            TStorageManagerGlobals::EUnknownClient;
+        const RPointerArray<CCAState>& presenceStates = aPresenceUpdater.PresenceStates();
+        TStorageManagerGlobals::TPresenceStatus presenceStatus =
+            TStorageManagerGlobals::EUnknown;
+
+        while ( ( idCount < KMaxIdAtTheTime ) && ( aEntryIndex >= 0 ) )
+            {
+            MPEngContactItem& contact = aContactList->ContactItem( aEntryIndex );
+            TPtrC uderId = contact.Id();
+            TPtrC nick( contact.NickName() );
+
+            // fetch attribute for this contact and add it all at once
+            aPresenceUpdater.ExtractAttributeModelsForUserL( uderId, attrModels );
+            // populate attributes
+            TInt attrCount( attrModels.Count() );
+            for ( TInt x( 0 ) ; x < attrCount ; ++x )
+                {
+                CAPresenceUtils::PopulateAttributesL( *attrModels[x],
+                                                      onlineStateModels,
+                                                      clientType,
+                                                      aliasPtr,
+                                                      statusText );
+                }
+
+            presenceStatus = MapPresenceStateId(
+                                 DecodeOnlineState( presenceStates, onlineStateModels ) );
+
+
+            // update directly to storage
+            aContactStorage->CreateContactL( aCaContactList,
+                                             nick,
+                                             uderId,
+                                             presenceStatus,
+                                             clientType,
+                                             aliasPtr,
+                                             statusText );
+
+            // reset attributes
+            onlineStateModels.Reset();
+            attrModels.ResetAndDestroy();
+
+            clientType = TStorageManagerGlobals::EUnknownClient;
+            statusText.Set( NULL, 0 );
+            aliasPtr.Set( KNullDesC );
+
+            ++idCount;
+            --aEntryIndex;
+            }
+        CleanupStack::PopAndDestroy( 2 ); // attrModels, onlineStateModels
+        }
+
+    // if aEntryIndex is -1, then we are done
+    return ( aEntryIndex != -1 );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CAPresenceUtils::ReadAttributeL
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TCAAttribute CAPresenceUtils::ReadAttributeL( TResourceReader& aReader )
+    {
+    TInt attribute( aReader.ReadInt16() );
+    TInt qualifier( aReader.ReadInt16() );
+    TInt value( aReader.ReadInt16() );
+
+    TCAAttribute attr;
+    attr.iQualifier = ( qualifier == EIMQualifierTrue );
+    attr.iData = KErrNotFound;
+    attr.iField = KErrNotFound;
+    attr.iGroup = KPEngDefaultAttrValueGroup;
+
+    switch ( attribute )
+        {
+        case EIMOnlineAttr:
+            {
+            attr.iAttribute = KUidPrAttrOnlineStatus;
+            attr.iField = EPEngOnlineStatus;
+            switch ( value )
+                {
+                case EIMOnlineNoChange:
+                    {
+                    // by default, value isn't used
+                    break;
+                    }
+                case EIMOnlineTrue:
+                    {
+                    attr.iData = EPEngOnlineStatusOnline;
+                    break;
+                    }
+                case EIMOnlineFalse:
+                    {
+                    attr.iData = EPEngOnlineStatusOffline;
+                    break;
+                    }
+                default:
+                    {
+                    User::Panic( KPanicAttribute, KErrArgument );
+                    }
+                }
+            break;
+            }
+        case EIMUserAvailabilityAttr:
+            {
+            attr.iAttribute = KUidPrAttrUserAvailability;
+            attr.iField = EPEngUsrAvailability;
+            switch ( value )
+                {
+                case EIMUserAvailabilityNoChange:
+                    {
+                    // by default, value isn't used
+                    break;
+                    }
+                case EIMUserAvailabilityNotAvailable:
+                    {
+                    attr.iData = EPEngUsrAvailabilityOffline;
+                    break;
+                    }
+                case EIMUserAvailabilityDiscreet:
+                    {
+                    attr.iData = EPEngUsrAvailabilityDiscreet;
+                    break;
+                    }
+                case EIMUserAvailabilityAvailable:
+                    {
+                    attr.iData = EPEngUsrAvailabilityOnline;
+                    break;
+                    }
+                default:
+                    {
+                    User::Panic( KPanicAttribute, KErrArgument );
+                    }
+                }
+            break;
+            }
+        case EIMCommCapAttr:
+            {
+            attr.iAttribute = KUidPrAttrCommCap;
+            attr.iField = EPEngCommCapStatus;
+            attr.iGroup = EPEngCommCapIMClient;
+            switch ( value )
+                {
+                case EIMCommCapNoChange:
+                    {
+                    // by default, value isn't used
+                    break;
+                    }
+                case EIMCommCapClosed:
+                    {
+                    attr.iData = EPEngCommCapStatusClosed;
+                    break;
+                    }
+                case EIMCommCapOpen:
+                    {
+                    attr.iData = EPEngCommCapStatusOpen;
+                    break;
+                    }
+                default:
+                    {
+                    User::Panic( KPanicAttribute, KErrArgument );
+                    }
+                }
+            break;
+            }
+        case EIMStatusTextAttr:
+            {
+            attr.iAttribute = KUidPrAttrStatusText;
+            switch ( value )
+                {
+                case EIMStatusTextNoChange:
+                    {
+                    // by default, value isn't used
+                    break;
+                    }
+                default:
+                    {
+                    User::Panic( KPanicAttribute, KErrArgument );
+                    }
+                }
+            break;
+            }
+        default:
+            {
+            User::Panic( KPanicAttribute, KErrArgument );
+            }
+        }
+    return attr;
+    }
+
+// -----------------------------------------------------------------------------
+// CAPresenceUtils::MapStateId
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TInt CAPresenceUtils::MapStateId( TInt aResourceStateId )
+    {
+    MCAPresence::TPresenceStatus ret( MCAPresence::EUnknown );
+    switch ( aResourceStateId )
+        {
+        case EIMStateAvailable:
+            {
+            ret = MCAPresence::EOnline;
+            break;
+            }
+        case EIMStateAway:
+            {
+            ret = MCAPresence::EAway;
+            break;
+            }
+        case EIMStateBusy:
+            {
+            ret = MCAPresence::EBusy;
+            break;
+            }
+        case EIMStateInvisible: // flowthrough at the moment
+        case EIMStateOffline:
+            {
+            ret = MCAPresence::EOffline;
+            break;
+            }
+        default:
+            {
+            User::Panic( KPanicAttribute, KErrArgument );
+            }
+        }
+    return ret;
+    }
+
+// -----------------------------------------------------------------------------
+// CAPresenceUtils::MapPresenceStateId
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TStorageManagerGlobals::TPresenceStatus CAPresenceUtils::MapPresenceStateId(
+    MCAPresence::TPresenceStatus aPresenceStateId )
+    {
+    TStorageManagerGlobals::TPresenceStatus ret( TStorageManagerGlobals::EUnknown );
+    switch ( aPresenceStateId )
+        {
+        case MCAPresence::EOnline:
+            {
+            ret = TStorageManagerGlobals::EOnline;
+            break;
+            }
+        case MCAPresence::EOffline:
+            {
+            ret = TStorageManagerGlobals::EOffline;
+            break;
+            }
+        case MCAPresence::EAway:
+            {
+            ret = TStorageManagerGlobals::EAway;
+            break;
+            }
+        case MCAPresence::EBusy:
+            {
+            ret = TStorageManagerGlobals::EBusy;
+            break;
+            }
+        default:
+            {
+            // nothing to do
+            }
+        }
+    return ret;
+    }
+
+// -----------------------------------------------------------------------------
+// CAPresenceUtils::ReadStatesFromResourceL
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CAPresenceUtils::ReadStatesFromResourceL( TInt aResourceId,
+                                               RPointerArray<CCAState>& aStates )
+    {
+    TResourceReader reader;
+    CCoeEnv::Static()->CreateResourceReaderLC( reader, aResourceId );
+
+    // reset array
+    aStates.ResetAndDestroy();
+
+    // read states
+    TInt stateCount( reader.ReadInt16() );
+    for ( TInt stateIndex( 0 ); stateIndex < stateCount; ++stateIndex )
+        {
+        // read state id and create state for it
+        TInt stateId( MapStateId( reader.ReadInt16() ) );
+
+        CCAState* state = new( ELeave )CCAState( stateId );
+        CleanupStack::PushL( state );
+
+        // and attributes
+        TInt attributeCount( reader.ReadInt16() );
+        for ( TInt i( 0 ); i < attributeCount; ++i )
+            {
+            state->iAttributes.AppendL( ReadAttributeL( reader ) );
+            }
+
+        // finished
+        aStates.AppendL( state );
+        CleanupStack::Pop( state );
+        }
+
+    CleanupStack::PopAndDestroy(); // reader
+    }
+
+// -----------------------------------------------------------------------------
+// CAPresenceUtils::FindState
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+CCAState* CAPresenceUtils::FindStateL( TInt aState, const RPointerArray<CCAState>& aStates )
+    {
+    CCAState* tmp = new( ELeave )CCAState( aState );
+    CleanupStack::PushL( tmp );
+
+    CCAState* ret = NULL;
+    TIdentityRelation< CCAState > equals( CAPresenceUtils::EqualStates );
+
+    TInt index( aStates.Find( tmp, equals ) );
+    if ( index != KErrNotFound )
+        {
+        ret = aStates[index];
+        }
+
+    CleanupStack::PopAndDestroy( tmp );
+    return ret;
+    }
+
+// -----------------------------------------------------------------------------
+// CAPresenceUtils::FindAttrL
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+const MPEngPresenceAttrModel2* CAPresenceUtils::FindAttr( TInt aType,
+                                                          const RPointerArray<MPEngPresenceAttrModel2>& aArray )
+    {
+    TInt count( aArray.Count() );
+    for ( TInt i( 0 ); i < count; ++i )
+        {
+        const MPEngPresenceAttrModel2* attr = aArray[i];
+        if ( attr->Type() == aType )
+            {
+            return attr;
+            }
+        }
+    return NULL;
+    }
+
+// -----------------------------------------------------------------------------
+// CAPresenceUtils::EqualStates
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TBool CAPresenceUtils::EqualStates( const CCAState& aState1, const CCAState& aState2 )
+    {
+    return ( aState1.iStateId == aState2.iStateId );
+    }
+
+
+//  End of File