Sample Contact Presence Handling Class

This content is no longer actively maintained. It is provided as is, for anyone who may still be using these technologies, with no warranties or claims of accuracy with regard to the most recent product version or service release.

In Unified Communications Client API, a contact is represented as an IUccContact object, which can be considered as a strongly typed category instance. To process enhanced presence category data as it is received on a client in a subscription-related event, a Unified Communications Client API application must use both the IUccCategoryInstance and IUccContact interfaces. The former is used in publishing or subscribing to a contact, namely, a contacts category instance. The latter is used to get or set the contact-specific properties, such as the name and URI of the contact as well as the groups to which the contact belongs. The application can obtain the IUccContact interface by calling QueryInterface on an IUccCategoryInstance object.

The following C# class handles presence events received on a client when a remote subscribed user publishes new or updated presence information. In this example, the sample class raises a public event to the calling application code (ContactPropertyUpdated) as subscription events are handled. The single argument of this delegate is a reference to the class object itself. The class exposes several contact-related properties useful for building and maintaining a contact list in a client application.

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using Microsoft.Office.Interop.UccApi;


namespace ContactsSample
{

    public delegate void ContactPropertyUpdatedEventHandler(Contact c);
    
    /// <summary>
    /// Contact class represents a contact and manages subscription to various attributes
    /// of the contact i.e. display name and availability state. It fires events when any
    /// of these properties are updated.
    /// </summary>
    public class Contact : 
        _IUccSubscriptionEvents, 
        _IUccPresentityEvents,
        _IUccCategoryContextEvents,
        _IUccCategoryInstanceEvents
    {
        public IUccContact uccContact;
        private IUccSubscriptionManager subscriptionManager;
        private IUccSubscription subscription;
        private IUccPresentity presentity;

        private string displayName;
        private string availability;

        //event to raise when display name ot availability for this contact are updated
        public event ContactPropertyUpdatedEventHandler ContactPropertyUpdated;

        #region _IUccSubscriptionEvents Members

        void _IUccSubscriptionEvents.OnQuery(
               IUccSubscription pSubscription, 
               IUccSubscriptionEvent pEventInfo)
        {
            
        }

        void _IUccSubscriptionEvents.OnSubscribe(
               IUccSubscription pSubscription, 
               IUccSubscriptionEvent pEventInfo)
        {
            
        }

        void _IUccSubscriptionEvents.OnUnsubscribe(
               IUccSubscription pSubscription, 
               IUccSubscriptionEvent pEventInfo)
        {
        }

        #endregion

        #region _IUccPresentityEvents Members

        void _IUccPresentityEvents.OnCategoryContextAdded(
               IUccPresentity pPresentity, 
               IUccCategoryContextEvent pCategoryCtxt)
        {
            IUccCategoryContext cx = pCategoryCtxt.CategoryContext;
            //Advise for "contactCard" and "state" ctaegroy context events to get notified when
            //corresponding instances are published
            if (cx.Name == "contactCard" || cx.Name == "state") 
            {
                UCC_Advise<_IUccCategoryContextEvents>( cx, this);
            }
        }

        void _IUccPresentityEvents.OnCategoryContextRemoved(
               IUccPresentity pPresentity, 
               IUccCategoryContext pCategoryCtxt)
        {
            //UnAdvise here
        }
        #endregion

        #region _IUccCategoryContextEvents

        void _IUccCategoryContextEvents.OnCategoryInstanceAdded(
               IUccCategoryContext pCategoryCtxt, 
               IUccCategoryInstanceEvent pCategory)
        {
            IUccCategoryInstance ci = pCategory.CategoryInstance;
            try
            {
                // Advise for category instance events to get notification when this 
                // instance is modified and process the current category instance

                if (pCategoryCtxt.Name == "contactCard")
                {
                   UCC_Advise<_IUccCategoryInstanceEvents>( ci, this);
                   this.processContactCardInstance(ci);
                }

                if (pCategoryCtxt.Name == "state")
                {
                    UCC_Advise<_IUccCategoryInstanceEvents>( ci, this);
                    this.processStateInstance(ci);
                }
            }
            catch (COMException ex)
            {
                
            }
        }

        void _IUccCategoryContextEvents.OnCategoryInstanceRemoved(
               IUccCategoryContext pCategoryCtxt, 
               IUccCategoryInstanceEvent pCategory)
        {
            //Unadvise here
        }

#endregion

        #region _IUccCategoryInstanceEvents Members

        void _IUccCategoryInstanceEvents.OnCategoryInstanceValueModified(
               IUccCategoryInstance pEventSource, 
               object pEventData)
        {
            try
            {
                //process the updated "contactCard" category instance 
                if (pEventSource.CategoryContext.Name == "contactCard")
                {
                    this.processContactCardInstance(pEventSource);
                }

                //process the updated "state" category instance 
                else if (pEventSource.CategoryContext.Name == "state")
                {
                    this.processStateInstance(pEventSource);
                }

            }
            catch (COMException ex)
            {
                
                //this.ShowError(ex.ToString());
            }
        }
        #endregion

        /// <summary>
        /// Constructor to create and initialize the Contact object
        /// </summary>
        /// <param name="c">IUccContact object that this Contact object represents</param>
        /// <param name="subMan">IUccSubscriptionManager representing the endpoint which is
        /// subscribing to this contact</param>
        /// <param name="sub">IUccSubscription shared by all contacts to subscribe</param>
        public Contact(IUccContact c, IUccSubscriptionManager subMan, IUccSubscription sub)
        {
            this.uccContact = c;
            this.subscriptionManager = subMan;
            this.subscription = sub;

            //initialize the name to Uri and availability to "Unknown"
            this.displayName = c.Uri;
            this.availability = "Unknown";
        }

        /// <summary>
        /// Subscribes for contact card (contains display name) and presence state (contains 
        /// availability) for this contact
        /// </summary>
        public void subscribe()
        {
            try
            {
                //Advise for subscription events to get results of subscribe
                UCC_Advise<_IUccSubscriptionEvents>(this.subscription, this);

                presentity = subscriptionManager.CreatePresentity(this.uccContact.Uri, null);
                UCC_Advise<_IUccPresentityEvents>(this.presentity, this);

                //add presentity and category names to the subscription
                this.subscription.AddPresentity(presentity);
                this.subscription.AddCategoryName("contactCard");
                this.subscription.AddCategoryName("state");

                //subscribe
                this.subscription.Subscribe(0);
            }
            catch (COMException ex)
            {

            }
        }

        /// <summary>
        /// Unsubscribe
        /// </summary>
        public void unsubscribe()
        {
            this.subscription.Unsubscribe(0);
        }

        /// <summary>
        /// Computes and returns the string representation of this contact which is display
        /// name followed by availability in parentheses
        /// </summary>
        /// <returns>String representation of this contact </returns>
        public override string ToString()
        {
            return (this.displayName + " (" + this.availability + ")"); 
        }

        /// <summary>
        /// Processes an instance of "contactCard" category to obtain the display name
        /// </summary>
        private void processContactCardInstance(IUccCategoryInstance category)
        {
            // Need to cast the category into IUccPresenceContactCardInstance to obtain
            // contact card properties
            IUccPresenceContactCardInstance card = category as IUccPresenceContactCardInstance;
            this.displayName = card.Identity.DisplayName;

            // Raise a property update event so any observers observing this contact can
            // update their own state
            ContactPropertyUpdated(this);
        }

        /// <summary>
        /// Processes an instance of "state" category to obtain availability
        /// </summary>
        private void processStateInstance(IUccCategoryInstance category)
        {
            // Need to cast the category into IUccPresenceStateInstance to obtain
            // state properties
            IUccPresenceStateInstance state = category as IUccPresenceStateInstance;
            this.availability = availabilityIntToString(state.Availability);

            // Raise a property update event so any observers observing this contact can
            // update their own state
            ContactPropertyUpdated(this);
        }
        /// <summary>
        /// Converts availability from a string to an integer.
        /// </summary>
        /// <param name="avail">String representation of availability</param>
        /// <returns>Integer representation of availability</returns>
        private int AvailabilityStringToInt(string avail)
        {
            StringComparer strComparer = StringComparer.Create(
               System.Globalization.CultureInfo.CurrentCulture, true);

            if (strComparer.Compare(avail, "Available") == 0)
                return 3500;

            else if (strComparer.Compare(avail, "Busy") == 0)
                return 6500;

            else if (strComparer.Compare(avail, "Do Not Disturb") == 0)
                return 9500;

            else if (strComparer.Compare(avail, "Away") == 0)
                return 15500;

            else if (strComparer.Compare(avail, "Appear Offline") == 0)
                return 18500;

            else
                return 0;
        }
        /// <summary>
        /// Converts the availability value from integer to one of a predefined set of
        /// strings
        /// </summary>
        /// <param name="avail">Integer representation of availability</param>
        /// <returns>String representation of availability</returns>
        privte string availabilityIntToString(int avail)
        {
            if (avail < 3000)
                return "Unknown";
            else if (avail < 4500)
                return "Available";
            else if (avail < 6000)
                return "Idle";
            else if (avail < 7500)
                return "Busy";
            else if (avail < 9000)
                return "Idle - Busy";
            else if (avail < 12000)
                return "Do Not Disturb";
            else if (avail < 18000)
                return "Away";
            else
                return "Offline";
        }

    }
}

See Also

Concepts

Create Contact List Subscription
Add a Contact to the Contact List
Remove a Contact from the Contact List
Granting Permissions to View Published Presence States
Presence Availability State
Sample Contact Presence Handling Class
Category and Category Instances
Publication and Subscription Objects