Displaying the presence information for the local user or their contacts is a common scenario when adding Unified Communications features to your client applications.   For example, after Office Communicator is installed, Outlook 2007 displays the presence of contacts on the To: and the From: line so the user can make intelligent communication decisions (“should I reply in email or are there enough people online that a concall would be better?”) directly in Outlook 2007.

Luckily, it’s easy to integrate presence information into your client applications.  This video shows a great example:

Let’s break down the code in the above video.  When displaying presence information, you need to get the initial value to display and then update your client UI when changes to presence elements occur.  In the code below, Messenger.GetContact() is used to get an instance of IMessengerContactAdvanced for displaying the initial presence information and the Messenger.OnMyStatusChange and Messenger.OnContactStatusChange events are used to get updated presence information:

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Text;
   5:   
   6:  using CommunicatorAPI;
   7:  using System.Runtime.InteropServices;
   8:   
   9:  namespace ContactPresence
  10:  {
  11:      class Program
  12:      {
  13:          private static Messenger _messenger;
  14:   
  15:          static void Main(string[] args)
  16:          {
  17:              _messenger = new Messenger();
  18:   
  19:              _messenger.OnContactStatusChange += 
  20:                  new DMessengerEvents_OnContactStatusChangeEventHandler(
  21:                      _messenger_OnContactStatusChange);
  22:              _messenger.OnMyStatusChange += 
  23:                  new DMessengerEvents_OnMyStatusChangeEventHandler(
  24:                      _messenger_OnMyStatusChange);
  25:   
  26:              IMessengerContactAdvanced localUser = 
  27:                  (IMessengerContactAdvanced)_messenger.GetContact(
  28:                  _messenger.MySigninName, _messenger.MyServiceId);
  29:   
  30:              if (localUser != null)
  31:              {
  32:                  DisplayContactPresence(localUser);
  33:              }   
  34:   
  35:              Console.WriteLine("\nPress Enter key to exit the application.\n");
  36:              Console.ReadLine();
  37:   
  38:              _messenger.OnContactStatusChange -= 
  39:                  new DMessengerEvents_OnContactStatusChangeEventHandler(
  40:                      _messenger_OnContactStatusChange);
  41:              _messenger.OnMyStatusChange -= 
  42:                  new DMessengerEvents_OnMyStatusChangeEventHandler(
  43:                      _messenger_OnMyStatusChange);
  44:   
  45:              System.Runtime.InteropServices.Marshal.ReleaseComObject(_messenger);
  46:              _messenger = null;
  47:              System.Runtime.InteropServices.Marshal.ReleaseComObject(localUser);
  48:              localUser = null;
  49:          }

In order to display presence information, I’ve created a function called DisplayContactPresence.  This function uses IMessengerContactAdvanced.PresenceProperties to access the presence for a contact (their status, availability, presence note, etc.).  For example, the following code writes all the presence information for a contact out to the console:

   1:          static void DisplayContactPresence(IMessengerContactAdvanced contact)
   2:          {
   3:              object[] presenceProps = (object[])contact.PresenceProperties;
   4:   
   5:              if (contact.IsSelf)
   6:              {
   7:                  Console.WriteLine("Local User Presence Info for {0}:", 
   8:                      contact.FriendlyName);
   9:              }
  10:              else
  11:              {
  12:                  Console.WriteLine("Contact Presence Info for {0}:", 
  13:                      contact.FriendlyName);
  14:              }
  15:   
  16:              // Status or Machine State.
  17:              Console.WriteLine("\tStatus: {0}", 
  18:                  (MISTATUS)presenceProps[(int)PRESENCE_PROPERTY.PRESENCE_PROP_MSTATE]);
  19:              Console.WriteLine("\tStatus String: {0}", 
  20:                  GetStatusString((MISTATUS) presenceProps[(int)PRESENCE_PROPERTY.PRESENCE_PROP_MSTATE]));
  21:              // Status string if status is set to custom.
  22:              Console.WriteLine("\tCustom Status String: {0}", 
  23:                  presenceProps[(int)PRESENCE_PROPERTY.PRESENCE_PROP_CUSTOM_STATUS_STRING]);
  24:   
  25:              // Presence or User state.
  26:              Console.WriteLine("\tAvailability: {0}", 
  27:                  presenceProps[(int)PRESENCE_PROPERTY.PRESENCE_PROP_AVAILABILITY]);
  28:              Console.WriteLine("\tAvailability String: {0}", 
  29:                  GetAvailabilityString((int) presenceProps[(int)PRESENCE_PROPERTY.PRESENCE_PROP_AVAILABILITY]));
  30:   
  31:              // Presence note.
  32:              Console.WriteLine("\tPresence Note: \n'{0}'", 
  33:                  presenceProps[(int)PRESENCE_PROPERTY.PRESENCE_PROP_PRESENCE_NOTE]);
  34:              // Blocked status.  
  35:              Console.WriteLine("\tIs Blocked: {0}", 
  36:                  presenceProps[(int)PRESENCE_PROPERTY.PRESENCE_PROP_IS_BLOCKED]);
  37:              // OOF message for contact, if specified.
  38:              Console.WriteLine("\tIs OOF: {0}", 
  39:                  presenceProps[(int)PRESENCE_PROPERTY.PRESENCE_PROP_IS_OOF]);
  40:              // Tooltip.
  41:              Console.WriteLine("\tTool Tip: \n'{0}'\n", 
  42:                  presenceProps[(int)PRESENCE_PROPERTY.PRESENCE_PROP_TOOL_TIP]);
  43:          }
  44:   
  45:          static string GetAvailabilityString(int availability)
  46:          {
  47:              switch (availability)
  48:              {
  49:                  case 3000:
  50:                      return "Available";
  51:                  case 4500:
  52:                      return "Inactive";
  53:                  case 6000:
  54:                      return "Busy";
  55:                  case 7500:
  56:                      return "Busy-Idle";
  57:                  case 9000:
  58:                      return "Do not disturb";
  59:                  case 12000:
  60:                      return "Be right back";
  61:                  case 15000:
  62:                      return "Away";
  63:                  case 18000:
  64:                      return "Offline";
  65:                  default:
  66:                      return "";
  67:              }
  68:          }
  69:   
  70:          static string GetStatusString(MISTATUS mStatus)
  71:          {
  72:              switch (mStatus)
  73:              {
  74:                  case MISTATUS.MISTATUS_ALLOW_URGENT_INTERRUPTIONS:
  75:                      return "Urgent interuptions only";
  76:                  case MISTATUS.MISTATUS_AWAY:
  77:                      return "Away";
  78:                  case MISTATUS.MISTATUS_BE_RIGHT_BACK:
  79:                      return "Be right back";
  80:                  case MISTATUS.MISTATUS_BUSY:
  81:                      return "Busy";
  82:                  case MISTATUS.MISTATUS_DO_NOT_DISTURB:
  83:                      return "Do no disturb";
  84:                  case MISTATUS.MISTATUS_IDLE:
  85:                      return "Idle";
  86:                  case MISTATUS.MISTATUS_INVISIBLE:
  87:                      return "Invisible";
  88:                  case MISTATUS.MISTATUS_IN_A_CONFERENCE:
  89:                      return "In a conference";
  90:                  case MISTATUS.MISTATUS_IN_A_MEETING:
  91:                      return "In a meeting";
  92:                  case MISTATUS.MISTATUS_LOCAL_CONNECTING_TO_SERVER:
  93:                      return "Connecting to server";
  94:                  case MISTATUS.MISTATUS_LOCAL_DISCONNECTING_FROM_SERVER:
  95:                      return "Disconnecting from server";
  96:                  case MISTATUS.MISTATUS_LOCAL_FINDING_SERVER:
  97:                      return "Finding server";
  98:                  case MISTATUS.MISTATUS_LOCAL_SYNCHRONIZING_WITH_SERVER:
  99:                      return "Synchronizing with server";
 100:                  case MISTATUS.MISTATUS_MAY_BE_AVAILABLE:
 101:                      return "Inactive";
 102:                  case MISTATUS.MISTATUS_OFFLINE:
 103:                      return "Offline";
 104:                  case MISTATUS.MISTATUS_ONLINE:
 105:                      return "Online";
 106:                  case MISTATUS.MISTATUS_ON_THE_PHONE:
 107:                      return "In a call";
 108:                  case MISTATUS.MISTATUS_OUT_OF_OFFICE:
 109:                      return "Out of office";
 110:                  case MISTATUS.MISTATUS_OUT_TO_LUNCH:
 111:                      return "Out to lunch";
 112:                  case MISTATUS.MISTATUS_UNKNOWN:
 113:                      return "Unknown";
 114:                  default:
 115:                      return string.Empty;
 116:              }
 117:          }

When the presence of the local user or any of their contacts changes, the Messenger.OnMyStatusChange and Messenger.OnContactStatusChange events fire, respectively:

   1:          static void _messenger_OnMyStatusChange(int hr, MISTATUS mMyStatus)
   2:          {
   3:              // Your code to work with presence goes here...
   4:              Console.WriteLine("\n***OnMyStatusChange***");
   5:   
   6:              DisplayContactPresence((IMessengerContactAdvanced) 
   7:                  _messenger.GetContact(_messenger.MySigninName, _messenger.MyServiceId));
   8:          }
   9:   
  10:          static void _messenger_OnContactStatusChange(object pMContact, MISTATUS mStatus)
  11:          {
  12:              // Your code to work with presence goes here...
  13:              Console.WriteLine("\n***OnContactStatusChange***");
  14:   
  15:              DisplayContactPresence((IMessengerContactAdvanced) pMContact);
  16:          }

One thing to note, both events have a MISTATUS value passed to provide the current status of the contact.  Using IMessengerContactAdvanced.PresenceProperties is preferred to using this value since it provides access to all the presence information for a contact, not just status.

If you’d like to try this code out for yourself, you’ll need to download the Office Communicator 2007 SDK and setup a UC development environment.

You can download the WPF Presence Controls for Office Communicator 2007 example used in the first demo to see how this code is used in a solution.

More details, tips and tricks on UC development can be found in the Programming for Unified Communications book.

Thanks,

Chris