presencefwsimpleadpt/src/simpleplugindata.cpp
branchRCL_3
changeset 35 fbd2e7cec7ef
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/presencefwsimpleadpt/src/simpleplugindata.cpp	Wed Sep 01 12:23:14 2010 +0100
@@ -0,0 +1,776 @@
+/*
+* Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:    SIMPLE Protocol implementation for Presence Framework
+*
+*/
+
+
+
+
+
+// *** system include files go here:
+#include <e32std.h>
+#include <s32strm.h>
+#include <utf.h>
+
+#include <presenceobjectfactory.h>
+#include <presenceinfo.h>
+#include <personpresenceinfo.h>
+#include <presenceinfofieldcollection.h>
+#include <presenceinfofield.h>
+#include <presenceinfofieldvaluetext.h>
+#include <presenceinfofieldvalueenum.h>
+#include <presenceinfofieldvaluebinary.h>
+#include <presenceinfofieldvalueenum.h>
+#include <presenceerrors.hrh>
+
+#include <ximpobjectfactory.h>
+#include <ximpidentity.h>
+#include <ximpdatasubscriptionstate.h>
+#include <ximpprotocolconnectionhost.h>
+#include <ximpstatus.h>
+
+#include <msimpledocument.h>
+#include <msimpleelement.h>
+#include <msimplepresencelist.h>
+#include <msimplemeta.h>
+#include <msimplecontent.h>
+#include <simpleutils.h>
+#include <simplefactory.h>
+
+#include "simpleplugindata.h"
+#include "simpleplugincommon.h"
+#include "simpleplugindebugutils.h"
+
+
+// ----------------------------------------------------------
+// CSimplePluginData::CSimplePluginData
+// ----------------------------------------------------------
+//
+CSimplePluginData::CSimplePluginData( )
+    {
+    }
+
+// ---------------------------------------------------------------------------
+// CSimplePluginData::~CSimplePluginData
+// ---------------------------------------------------------------------------
+//
+CSimplePluginData::~CSimplePluginData()
+    {
+
+    }
+
+// ---------------------------------------------------------------------------
+// CSimplePluginData::NewL
+// ---------------------------------------------------------------------------
+//
+CSimplePluginData* CSimplePluginData::NewL( )
+    {
+    CSimplePluginData* self = CSimplePluginData::NewLC( );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+// CSimplePluginData::NewLC
+// ---------------------------------------------------------------------------
+//
+CSimplePluginData* CSimplePluginData::NewLC( )
+    {
+    CSimplePluginData* self = new( ELeave ) CSimplePluginData;
+    CleanupStack::PushL( self );
+    self->ConstructL(  );
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+// CSimplePluginData::ConstructL
+// ---------------------------------------------------------------------------
+//
+void CSimplePluginData::ConstructL( )
+    {
+    }
+
+// ---------------------------------------------------------------------------
+// CSimplePluginData::NotifyToPrInfoL
+// ---------------------------------------------------------------------------
+//
+void CSimplePluginData::NotifyToPrInfoL(
+        MPresenceObjectFactory& aPresenceFactory,
+        MSimpleDocument& aDocument,
+        MPresenceInfo& aPrInfo )
+    {
+    MPersonPresenceInfo* persInfo = aPresenceFactory.NewPersonPresenceInfoLC();
+    MPresenceInfoFieldCollection& coll = persInfo->Fields();
+
+    // Search own person info. Notice: Extend supported attributes later
+
+    RPointerArray<MSimpleElement> elems;
+    CleanupClosePushL( elems );
+    TInt err = aDocument.SimpleElementsL( elems );
+
+    if ( !err )
+        {
+        TInt myLatestPosition = SearchLatestTimestampL( elems );
+
+        if ( myLatestPosition != KErrNotFound )
+            {
+            MSimpleElement* elem = elems[myLatestPosition];
+
+            using namespace NSimplePlugin::NSimpleOma;
+
+            // person element found
+            RPointerArray<MSimpleElement> elems2;
+            CleanupClosePushL( elems2 );
+            elem->SimpleElementsL( elems2 );
+            TInt count2 = elems2.Count();
+
+            for ( TInt j = 0; j < count2; j++ )
+                {
+                MSimpleElement* elem2 = elems2[j];
+                if ( !elem2->LocalName().CompareF( KSimpleOverridingwillingness8 ))
+                    {
+                    UserOverridingWillingnessToPrFwL( aPresenceFactory, elem2, coll );
+                    }
+                else if ( !elem2->LocalName().CompareF( KSimpleStatusicon8 ))
+                    {
+                    UserStatusIconToPrFwL( aPresenceFactory, elem2, coll, aDocument );
+                    }
+                else if ( !elem2->LocalName().CompareF( KSimpleNote8 ))
+                    {
+                    UserNoteToPrFwL( aPresenceFactory, elem2, coll );
+                    }
+                }
+
+            CleanupStack::PopAndDestroy( &elems2 );
+            }
+        }
+
+    CleanupStack::PopAndDestroy( &elems );
+
+    aPrInfo.SetPersonPresenceL( persInfo );
+    CleanupStack::Pop();   // >> persInfo
+    }
+
+// ---------------------------------------------------------------------------
+// CSimplePluginData::UserOverridingWillingnessToPrFwL
+// ---------------------------------------------------------------------------
+//
+void CSimplePluginData::UserOverridingWillingnessToPrFwL(
+        MPresenceObjectFactory& aPresenceFactory,
+        MSimpleElement* aElement,
+        MPresenceInfoFieldCollection& aCollection )
+    {
+
+#ifdef _DEBUG
+    PluginLogger::Log(_L("PluginData: UserOverridingWillingnessToPrFwL") );
+#endif
+    using namespace NSimplePlugin::NSimpleOma;
+
+    RPointerArray<MSimpleElement> elems;
+    CleanupClosePushL( elems );
+    User::LeaveIfError( aElement->SimpleElementsL( elems ));
+    MSimpleElement* elem3 = elems[0]; // notice: we assume that there is no other sub-elements
+    if ( !elem3->LocalName().CompareF( KSimpleBasic8 ))
+        {
+        // write the data into text field.
+        HBufC* nodeContent = elem3->ContentUnicodeL();
+        CleanupStack::PushL( nodeContent );
+        if ( nodeContent )
+            {
+            // Save availability
+            using namespace NPresenceInfo::NFieldType;
+            MPresenceInfoField* field = aPresenceFactory.NewInfoFieldLC();
+            field->SetFieldTypeL( KAvailability );
+            MPresenceInfoFieldValueText* text = aPresenceFactory.NewTextInfoFieldLC();
+            text->SetTextValueL( nodeContent->Des() );
+            field->SetFieldValue( text );
+            CleanupStack::Pop();            // >> text
+            aCollection.AddOrReplaceFieldL( field );
+            CleanupStack::Pop();            // >> field
+            }
+        CleanupStack::PopAndDestroy( nodeContent );
+        }
+    CleanupStack::PopAndDestroy( &elems );  // close the array, do not delete the content
+    }
+
+// ---------------------------------------------------------------------------
+// CSimplePluginData::UserStatusIconToPrFwL
+// ---------------------------------------------------------------------------
+//
+void CSimplePluginData::UserStatusIconToPrFwL(
+        MPresenceObjectFactory& aPresenceFactory,
+        MSimpleElement* aElement,
+        MPresenceInfoFieldCollection& aCollection,
+        MSimpleDocument& aDocument )
+    {
+#ifdef _DEBUG
+    PluginLogger::Log(_L("PluginData: UserStatusIconToPrFwL") );
+#endif
+    using namespace NSimpleDocument;
+
+    using namespace NPresenceInfo::NFieldType;
+
+    HBufC* nodeContent = aElement->ContentUnicodeL();
+    CleanupStack::PushL( nodeContent );
+    if ( nodeContent )
+        {
+        RPointerArray<MSimpleContent> contents;
+        CleanupClosePushL( contents );
+
+        // Search the corresponding direct content
+        aDocument.GetDirectContentsL( contents );
+
+        TInt contCount = contents.Count();
+        for ( TInt i = 0; i<contCount; i++ )
+            {
+            TPtrC8 id = (contents[i])->ContentID();
+            // nodecontent = "cid:simple.avatar.com"
+            // content-id: simple.avatar.com
+            HBufC8* cid8 = NULL;
+            cid8 = CnvUtfConverter::ConvertFromUnicodeToUtf8L( nodeContent->Des() );
+            CleanupStack::PushL( cid8 ); // << cid8
+
+            TInt contentLen = cid8->Des().Length() - 4;  // "cid:"
+            TInt headLen = id.Length();
+            TPtrC8 pUnquoted( KNullDesC8 );
+            if ( id.Locate('"') == 0 )
+                {
+                // remove "..." characters
+                pUnquoted.Set( id.Mid( 1, headLen-2 ));
+                }
+            else
+                {
+                pUnquoted.Set( id );
+                }
+            TInt foundPos = cid8->Des().Find( pUnquoted );
+            if ( contentLen == headLen && foundPos >= 0 )
+                {
+                MPresenceInfoField* field = aPresenceFactory.NewInfoFieldLC();
+                field->SetFieldTypeL( KAvatar );
+                MPresenceInfoFieldValueBinary* val = aPresenceFactory.NewBinaryInfoFieldLC();
+                val->SetMimeTypeL( (contents[i])->ContentType() );
+                // Body is not BASE64 encoded internally
+                val->SetBinaryValueL( (contents[i])->Body() );
+                field->SetFieldValue( val );
+                CleanupStack::Pop();                // >> val
+                aCollection.AddOrReplaceFieldL( field );
+                CleanupStack::Pop();                // >> field
+                }
+            CleanupStack::PopAndDestroy( cid8 ); // >> cid8
+            }
+        CleanupStack::PopAndDestroy( &contents );
+        }
+    CleanupStack::PopAndDestroy( nodeContent );
+    }
+
+// ---------------------------------------------------------------------------
+// CSimplePluginData::UserNoteToPrFwL
+// ---------------------------------------------------------------------------
+//
+void CSimplePluginData::UserNoteToPrFwL(
+        MPresenceObjectFactory& aPresenceFactory,
+        MSimpleElement* aElement,
+        MPresenceInfoFieldCollection& aCollection )
+    {
+#ifdef _DEBUG
+    PluginLogger::Log(_L("PluginData: UserNoteToPrFwL") );
+#endif
+    // using namespace NSimplePlugin::NSimpleOma;
+    HBufC* nodeContent = aElement->ContentUnicodeL();
+    CleanupStack::PushL( nodeContent );
+    if ( nodeContent )
+        {
+        // Save note, convert from unicode
+        // notice: consider xml::lang-attribute
+        // note <-> KStatusMessage
+        using namespace NPresenceInfo::NFieldType;
+        MPresenceInfoField* field = aPresenceFactory.NewInfoFieldLC();
+        field->SetFieldTypeL( KStatusMessage );
+        MPresenceInfoFieldValueText* text = aPresenceFactory.NewTextInfoFieldLC();
+        text->SetTextValueL( nodeContent->Des() );
+        field->SetFieldValue( text );
+        CleanupStack::Pop();            // >> text
+        aCollection.AddOrReplaceFieldL( field );
+        CleanupStack::Pop();            // >> field
+        }
+    CleanupStack::PopAndDestroy( nodeContent );
+    }
+
+// ---------------------------------------------------------------------------
+// CSimplePluginData::NotifyListToPrInfoL
+// ---------------------------------------------------------------------------
+//
+void CSimplePluginData::NotifyListToPrInfoL(
+    MXIMPObjectFactory& aFactory,
+    MPresenceObjectFactory& aPresenceFactory,
+    MSimplePresenceList& aList,
+    RPointerArray<MPresenceInfo>& aEntities,
+    RPointerArray<MXIMPIdentity>& aActives,
+    RPointerArray<MXIMPIdentity>& aTerminated,
+    TBool& aFullList )
+    {
+    // Split array into individual prInfos
+
+#ifdef _DEBUG
+    PluginLogger::Log(_L("PluginData: NotifyListToPrInfoL") );
+#endif
+
+    RPointerArray<MSimpleDocument> docs;
+    CleanupClosePushL( docs );
+    // get documents, ownership is not transferred.
+    aList.GetDocuments( docs );
+
+    CollectAllPresentitiesL( aEntities, aActives, docs, aFactory, aPresenceFactory );
+
+    using namespace NSimplePlugin::NSimpleOma;
+
+    MSimpleMeta* meta = aList.MetaData();
+
+#ifdef _DEBUG
+    // TODO: remove
+    if ( meta == NULL )
+    PluginLogger::Log(_L("PluginData: META Is NULL !!! *****"));
+#endif
+
+
+
+    // ownership in not transferred
+    if ( meta && !meta->LocalName().CompareF( KSimpleList8 ))
+        {
+        // list element found, find out if fullstate
+        const TDesC8* fullStateVal = meta->AttrValue( KSimpleFullState8 );
+        if ( fullStateVal && !fullStateVal->CompareF( KSimpleTrue8 ))
+            {
+            aFullList = ETrue;
+            }
+        else
+            {
+            aFullList = EFalse;
+            }
+
+#ifdef _DEBUG
+        PluginLogger::Log(_L("PluginData: fullState === %d"), aFullList );
+#endif
+
+        // Search "terminated" presentities
+        RPointerArray<MSimpleElement> elems2;
+        CleanupClosePushL( elems2 );
+        meta->SimpleElementsL( elems2);
+        CollectTerminatedPresentitiesL( aTerminated, elems2, aFactory );
+        CleanupStack::PopAndDestroy( &elems2 );
+        }
+
+    CleanupStack::PopAndDestroy( &docs );
+    }
+
+        /*
+        example:
+   Content-Transfer-Encoding: binary
+   Content-ID: <nXYxAE@pres.vancouver.example.com>
+   Content-Type: application/rlmi+xml;charset="UTF-8"
+
+   <?xml version="1.0" encoding="UTF-8"?>
+   <list xmlns="urn:ietf:params:xml:ns:rlmi"
+         uri="sip:adam-friends@pres.vancouver.example.com"
+         version="1" fullState="true">
+     <name xml:lang="en">Buddy List at COM</name>
+     <name xml:lang="de">Liste der Freunde an COM</name>
+     <resource uri="sip:bob@vancouver.example.com"">        <------- note
+       <name>Bob Smith</name>
+       <instance id="juwigmtboe" state="active"
+                 cid="bUZBsM@pres.vancouver.example.com"/>
+     </resource>
+     <resource uri="sip:dave@vancouver.example.com">
+       <name>Dave Jones</name>
+       <instance id="hqzsuxtfyq" state="active"
+                 cid="ZvSvkz@pres.vancouver.example.com"/>
+     </resource>
+     <resource uri="sip:ed@dallas.example.net">
+       <name>Ed at NET</name>
+     </resource>
+     <resource uri="sip:adam-friends@stockholm.example.org">
+       <name xml:lang="en">My Friends at ORG</name>
+       <name xml:lang="de">Meine Freunde an ORG</name>
+     </resource>
+   </list>
+        */
+
+// ---------------------------------------------------------------------------
+// CSimplePluginData::AddPrPersToSimpleDocumentL
+// ---------------------------------------------------------------------------
+//
+void CSimplePluginData::AddPrPersToSimpleDocumentL(
+    const MPersonPresenceInfo* aInfo,
+    MSimpleDocument& aDocument,
+    const TDesC8& aSipId )
+    {
+    using namespace NSimpleDocument;
+
+    TPtrC8 p8( KSimpleAvatarCIDURI8 );
+    TInt bufSize = p8.Length();
+
+    HBufC16* CIDcontent = HBufC16::NewLC( bufSize );   // << CID
+    CIDcontent->Des().Copy( KSimpleAvatarCIDURI8 );
+
+    // notice: we do not generate random id but a static one.
+
+    using namespace NSimplePlugin::NSimpleOma;
+
+    aDocument.SetEntityURIL( aSipId );
+
+    MSimpleElement* persElem = aDocument.AddSimpleElementL(
+        KSimpleNsPDM, KSimplePerson8 );
+    CleanupClosePushL( *persElem );             // << persElem
+
+    using namespace NPresenceInfo::NFieldType;
+
+    const MPresenceInfoFieldCollection& coll = aInfo->Fields();
+
+    TInt myCount = coll.FieldCount();
+    for ( TInt i = 0; i < myCount; i++ )
+        {
+        const MPresenceInfoField& field =  coll.FieldAt( i );
+        const TDesC8& fieldType = field.FieldType();
+        const MXIMPBase& storage = field.FieldValue();
+
+        // Notice: tuple id saving for partial data in future.
+
+        /*
+        Mapping:
+        Avatar -> Person/status-icon
+        status-msg -> Person/note
+        Availability -> Person/overriding-willingness
+        */
+
+        if ( !fieldType.CompareF( KAvatar ) )
+            {
+            const MPresenceInfoFieldValueBinary* bin =
+                  TXIMPGetInterface< const MPresenceInfoFieldValueBinary >::From( storage,
+                  MXIMPBase::EReturnNullIfUnknown );
+            if ( bin )
+                {
+                MSimpleElement* elem = persElem->AddSimpleElementL(
+                        KSimpleNsRPID,
+                        KSimpleStatusicon8 );
+                CleanupClosePushL( *elem );             // << elem
+                elem->SetContentUnicodeL( CIDcontent->Des());
+                // Create the MIME multipart content
+                MSimpleContent* content = TSimpleFactory::NewContentL(
+                    KSimpleAvatarContent8, bin->MimeType() );
+                CleanupClosePushL( *content );          // << content
+                content->CopyBodyL( bin->BinaryValue( ) );
+                aDocument.AddDirectContentL( *content, EFalse );
+                CleanupStack::PopAndDestroy( content );         // >> content
+                CleanupStack::PopAndDestroy( elem );  // >> elem
+                }
+            }
+        else if ( !fieldType.CompareF( KStatusMessage ) )
+            {
+            const MPresenceInfoFieldValueText* text =
+                  TXIMPGetInterface< const MPresenceInfoFieldValueText >::From( storage,
+                  MXIMPBase::EReturnNullIfUnknown );
+            if ( text )
+                {
+                MSimpleElement* elem = persElem->AddSimpleElementL(
+                    KSimpleNsPDM,
+                    KSimpleNote8 );
+                CleanupClosePushL( *elem );             // << elem
+                elem->SetContentUnicodeL( text->TextValue() );
+                CleanupStack::PopAndDestroy( elem );  // >> elem
+                }
+            }
+        else if ( !fieldType.CompareF( KAvailability ))
+            {
+            const MPresenceInfoFieldValueText* text =
+                  TXIMPGetInterface< const MPresenceInfoFieldValueText >::From( storage,
+                  MXIMPBase::EReturnNullIfUnknown );
+            if ( text )
+                {
+                AddPrPersAvailabilityToDocL( text, persElem );
+                }         
+            }
+        else
+            {
+            // Notice: currently all the fields in the namespace are supported,
+            // but this ensures that if namespace is extended later, it is
+            // handled right way in the adaptation
+            User::Leave( KPresenceErrPresenceInfoFieldTypeNotSupported );
+            }
+        }
+    CleanupStack::PopAndDestroy( persElem );
+    CleanupStack::PopAndDestroy( CIDcontent );
+    }
+
+
+// ---------------------------------------------------------------------------
+// CSimplePluginData::CollectAllPresentitiesL
+// ---------------------------------------------------------------------------
+//
+void CSimplePluginData::CollectAllPresentitiesL(
+    RPointerArray<MPresenceInfo>& aEntities,
+    RPointerArray<MXIMPIdentity>& aActives,
+    RPointerArray<MSimpleDocument>& aDocs,
+    MXIMPObjectFactory& aFactory,
+    MPresenceObjectFactory& aPresenceFactory )
+    {
+    TInt count = aDocs.Count();
+
+    // active presentities
+    for ( TInt i = 0; i < count; i++ )
+        {
+        MPresenceInfo* info = aPresenceFactory.NewPresenceInfoLC();   // << info
+        aEntities.AppendL( info );
+        // aEntities may contain entries even this method leaves
+        CleanupStack::Pop();                                      // >> info
+
+        NotifyToPrInfoL( aPresenceFactory, *aDocs[i], *info );
+
+        // Add SIP identity to active users list
+        MXIMPIdentity* active = aFactory.NewIdentityLC();  // << active
+        aActives.AppendL( active );
+        CleanupStack::Pop();                            // >> active
+
+        // Convert SIP entity URI from UTF to Unicode.
+        const TDesC8* pUri8 = (aDocs[i])->EntityURI();
+        HBufC16* uri16 = NULL;
+        uri16 = CnvUtfConverter::ConvertToUnicodeFromUtf8L( *pUri8 );
+        CleanupStack::PushL( uri16 );  // << uri16
+        active->SetIdentityL( uri16->Des() );
+
+#ifdef _DEBUG
+    // ---------------------------------------------------------
+    TBuf<200> buffer2;
+    buffer2.Copy(uri16->Des());
+    const MPersonPresenceInfo* pers_debug = info->PersonPresence();
+    const MPresenceInfoFieldCollection& coll_debug = pers_debug->Fields();
+    TInt count_debug = coll_debug.FieldCount();
+    PluginLogger::Log(_L("PluginData: nbr of fields received =%d"), count_debug );
+    PluginLogger::Log(_L("PluginData: User added to actives: %S"), &buffer2 );
+    // ---------------------------------------------------------
+#endif
+        CleanupStack::PopAndDestroy( uri16 );  // >> uri16
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CSimplePluginData::CollectTerminatedPresentitiesL
+// ---------------------------------------------------------------------------
+//
+void CSimplePluginData::CollectTerminatedPresentitiesL(
+    RPointerArray<MXIMPIdentity>& aTerminated,
+    RPointerArray<MSimpleElement>& aElems,
+    MXIMPObjectFactory& aFactory )
+    {
+#ifdef _DEBUG
+    PluginLogger::Log(_L("PluginData: CollectTerminatedPresentitiesL"));
+#endif
+    using namespace NSimplePlugin::NSimpleOma;
+
+    TInt count2 = aElems.Count();
+    for ( TInt i = 0; i < count2; i++ )
+        {
+        MSimpleElement* elem2 = aElems[i];
+        if ( !elem2->LocalName().CompareF( KSimpleResource8 ))
+            {
+            // resource element
+            RPointerArray<MSimpleElement> elems3;
+            CleanupClosePushL( elems3 );
+            elem2->SimpleElementsL( elems3 );
+            TInt count3 = elems3.Count();
+            const TDesC8* uri8 = elem2->AttrValue( KSimpleUri8 );
+            if ( !uri8 )
+                {
+                continue;
+                }
+            for ( TInt j=0; j < count3; j++ )
+                {
+                MSimpleElement* elem3 = elems3[j];
+                SearchTerminatedInstanceL( aTerminated, elem3, uri8, aFactory  );
+                }
+            CleanupStack::PopAndDestroy( &elems3 );
+            } // resource element
+        }// for (i); list element subelement
+
+#ifdef _DEBUG
+    PluginLogger::Log(_L("PluginData: CollectTerminatedPresentitiesL ends"));
+#endif
+    }
+
+
+// ---------------------------------------------------------------------------
+// CSimplePluginData::SearchLatestTimestampL
+// ---------------------------------------------------------------------------
+//
+TInt CSimplePluginData::SearchLatestTimestampL(
+    RPointerArray<MSimpleElement>& aElems  )
+    {
+    TInt ret = KErrNotFound;
+
+    const TInt KMaxTimestamp = 40;
+    TBuf<KMaxTimestamp> myTimestamp;
+
+    // Timestamp to save the latest one person data
+    myTimestamp = KNullDesC;
+
+    // They want to get empty notifications too.
+    TInt count = aElems.Count();
+
+    using namespace NSimplePlugin::NSimpleOma;
+
+    MSimpleElement* elem = NULL;
+    TPtrC8 p8;
+
+    for ( TInt i = 0; i < count; i++ )
+        {
+        elem = aElems[i];
+        p8.Set( elem->LocalName());
+        if (!( p8.CompareF( KSimplePerson8 )))
+            {
+
+            if ( ret == KErrNotFound )
+                {
+                // Save since the time stamp is optional, this is first <person> .
+                // the whole <person> may also be missing.
+                ret = i;
+                }
+
+            // person element found
+            RPointerArray<MSimpleElement> elems2;
+            CleanupClosePushL( elems2 );
+            elem->SimpleElementsL( elems2 );
+            TInt count2 = elems2.Count();
+
+            // Search optional timestamp element first, the latest one
+            for ( TInt j = 0; j < count2; j++ )
+                {
+                //
+                MSimpleElement* elem2 = elems2[j];
+                // Search optional timestamp element
+                if ( !elem2->LocalName().CompareF( KSimpleTimestamp8 ))
+                    {
+                    HBufC* nodeContent = elem2->ContentUnicodeL();
+                    // Notice: Timestamp comparision assumes now
+                    // that all the timestamps have a similar format.
+                    if ( myTimestamp.Compare( nodeContent->Des() ) < 0 )
+                        {
+                        // Save latest timestamp
+                        myTimestamp.Copy( nodeContent->Des() );
+                        ret = i;
+                        }
+                    delete nodeContent;
+                    }
+                }
+            CleanupStack::PopAndDestroy( &elems2 );
+            }
+        }  // for
+
+    return ret;
+    }
+
+// ---------------------------------------------------------------------------
+// CSimplePluginData::AddPrPersAvailabilityToDocL
+// ---------------------------------------------------------------------------
+//
+void CSimplePluginData::AddPrPersAvailabilityToDocL(
+    const MPresenceInfoFieldValueText* aText, MSimpleElement* aPersElem )
+    {
+    using namespace NSimplePlugin::NSimpleOma;
+
+    MSimpleElement* elem = aPersElem->AddSimpleElementL(
+            KSimpleNsOP,
+            KSimpleOverridingwillingness8 );
+    CleanupClosePushL( *elem );             // << elem
+    MSimpleElement* elem2 = elem->AddSimpleElementL(
+            KSimpleNsOP,
+            KSimpleBasic8 );
+    CleanupClosePushL( *elem2 );             // << elem2
+    if ( !aText->TextValue().CompareF( KSimpleOpen ) )
+        {
+        elem2->SetContentUnicodeL( KSimpleOpen );
+        }
+    else 
+        {
+        elem2->SetContentUnicodeL( KSimpleClosed );
+        }
+    CleanupStack::PopAndDestroy( elem2 ); // >> elem2
+    CleanupStack::PopAndDestroy( elem );  // >> elem
+    }
+
+// ---------------------------------------------------------------------------
+// CSimplePluginData::SearchTerminatedInstanceL
+// ---------------------------------------------------------------------------
+//
+void CSimplePluginData::SearchTerminatedInstanceL(
+    RPointerArray<MXIMPIdentity>& aTerminated,
+    MSimpleElement* aElem,
+    const TDesC8* uri8,
+    MXIMPObjectFactory& aFactory )
+    {
+#ifdef _DEBUG
+    PluginLogger::Log(_L("PluginData: SearchTerminatedInstanceL"));
+#endif
+
+    using namespace NSimplePlugin::NSimpleOma;
+    if ( !aElem->LocalName().CompareF( KSimpleInstance8 ))
+        {
+        // instance element
+        const TDesC8* stateVal = aElem->AttrValue( KSimpleState8 );
+        if ( stateVal && !stateVal->CompareF( KSimpleTerminated8 ))
+            {
+            // Add presentity into terminated list
+            MXIMPIdentity* terminated = aFactory.NewIdentityLC();  // +terminated
+            aTerminated.AppendL( terminated );
+            CleanupStack::Pop();                   // -terminated
+
+            // Convert SIP entity URI from UTF to Unicode.
+            HBufC16* uri16 = NULL;
+            uri16 = CnvUtfConverter::ConvertToUnicodeFromUtf8L( *uri8 );
+            CleanupStack::PushL( uri16 );  // +uri16
+            terminated->SetIdentityL( uri16->Des() );
+
+#ifdef _DEBUG
+            // Debug buffer size
+            const TInt KMyBufSize = 200;
+            // ---------------------------------------------------------
+            TBuf<KMyBufSize> buffer3;
+            buffer3.Copy(uri16->Des());
+            PluginLogger::Log(_L("PluginData:   SearchTerminatedInstanceL TERMINATED INSTANCE FOUND ***"));
+            PluginLogger::Log(_L("PluginData:   User added to terminated: %S"), &buffer3 );
+            // ---------------------------------------------------------
+#endif
+            CleanupStack::PopAndDestroy( uri16 );   // -uri16
+            }
+        else
+            {
+            // -------------------------------------------------------------
+#ifdef _DEBUG
+            if ( stateVal != NULL )
+                {
+                // Debug buffer size
+                const TInt KMyBufSize = 100;
+                HBufC16* uri16 = NULL;
+                uri16 = CnvUtfConverter::ConvertToUnicodeFromUtf8L( *stateVal );
+                CleanupStack::PushL( uri16 );  // +uri16
+                TBuf<KMyBufSize> buffer4;
+                buffer4.Copy(uri16->Des());
+                PluginLogger::Log(_L("    STATEVAL: %S"), &buffer4 );
+                CleanupStack::PopAndDestroy( uri16 );   // -uri16
+                }
+#endif
+            // -------------------------------------------------------------
+            }
+        }
+    }
+