Subscribing to Message Waiting Indicator or Using Exchange Web Services to Determine if a User has Voice Mail

Summary:   This article discusses how to determine when new voice mails appear in a unified communications application. You learn how to receive and examine the Message Waiting Indicator (MWI) instance that is provisioned by a Microsoft Exchange Server 2010 SP1 server that is integrated with Microsoft Lync Server 2010. If Lync Server 2010 is integrated with Microsoft Exchange Server 2007 SP1, this article also explains how to query Exchange Server 2007 SP1 for voice mails by using Microsoft Exchange Web Services (EWS).

Applies to:    Microsoft Lync 2010 | Microsoft Lync Server 2010 | Microsoft Exchange Server 2010 SP1 | Microsoft Exchange Server 2010 SP1 Web Services SDK | Microsoft Exchange Server 2007 SP1

Published:   March 2011 | Provided by:   Kurt De Ding, Microsoft | About the Author

Contents

  • Introduction

  • Receive mwi Category Instances in Self-Subscription

  • Use Exchange Web Services to Query Voice Mails in Exchange Server 2007 SP1

  • Conclusion

  • Additional Resources

Introduction

In a Microsoft Lync Server 2010 deployment that includes Microsoft Exchange Server 2010 SP1, a unified communications application can be configured to determine whether a local user has new voice mails in their Exchange Server 2010 SP1 email account.

When a call to the user is forwarded to the user’s email account, Exchange Server 2010 SP1 starts the Message Waiting Indicator (MWI) for the user and sends a SIP NOTIFY message to Lync Server 2010. After the SIP NOTIFY message is received, Lync Server 2010 adds the MWI message to the user’s roaming data profile by publishing a private mwi category instance to the user’s Self container. The Self container has a ContainerId value of 1.

The published mwi category instance contains the MWI messageWaiting attribute that appears in the next code example together with the number of pending voice mails that include read (readVoiceMailCount) and unread (unreadVoiceMailCount) voice mails. The following example of the mwi category instance shows that 10 voice mails appear in the user’s email account and two have not been opened.

<Category name="mwi" instance="0" publishTime="2009-09-25T05:40:44.113" container="1" version="1" expireType="static">
    <mwi xmlns="https://schemas.microsoft.com/2006/09/sip/mwi" messageWaiting="true"
       unreadVoiceMailCount="2" readVoiceMailCount="8"/>
</Category>

mwi is a private category that is only published by Lync Server 2010. A unified communications application can receive publications or updates of the mwi category instance in a self-subscription that is used to synchronize a local user’s roaming data across various endpoints. To receive the mwi category instances, the user account must be configured to use MWI on Exchange Server 2010 SP1. The user’s telephone line must be UC enabled to support Microsoft Exchange Unified Messaging 2010.

When Lync Server 2010 is deployed with Microsoft Exchange Server 2007 SP1 instead of Exchange Server 2010 SP1, the user does not receive mwi category instances in the self-subscription. In this case, the application can use Microsoft Exchange Web Services (EWS) to query Exchange Server 2007 SP1 to determine whether a voice mail appears in the user’s Microsoft Outlook Inbox and confirm the number of read or unread voice mails.

The next section discusses how to use Microsoft Unified Communications Managed API (UCMA) 3.0 Core SDK to receive and parse the mwi category instance that originates in Exchange Server 2010 SP1. How to use Microsoft Exchange Web Services (EWS) to query Exchange Server 2007 SP1 to extract voice mails from the user’s Outlook Inbox is discussed later in this article.

Receive mwi Category Instances in Self-Subscription

The process that is used to receive mwi category instances includes the following tasks.

  • Ensure that Exchange Server 2010 SP1 is configured to use MWI.

  • Sign in to Lync Server 2010.

  • Subscribe to self-presence.

  • Handle PresenceNotificationReceived events from the self-subscription and then parse the mwi category instance.

To receive mwi category instances in self-subscription

  1. Ensure that all user accounts are configured to use Message Waiting Indicator (MWI). An Exchange Server 2010 SP1 administrator uses the Exchange Unified Messaging (UM) Mailbox Policy or UM IP Gateway Policy to configure user accounts. For more information, see Understanding Message Waiting Indicator.

  2. Start Microsoft Visual Studio 2010 development system, and then create a Microsoft Windows Forms or Console project with C#.

  3. In the Visual Studio project, add a reference to the Microsoft.Rtc.Collaboration.dll assembly. Ensure that UCMA 3.0 Core SDK is installed on the development computer.

  4. Ensure that the following using directive is added to the code file.

    using System.Xml;
    using Microsoft.Rtc.Collaboration;
    using Microsoft.Rtc.Collaboration.Presence;
    

    The System.Xml namespace is used to parse the received mwi category instance XML data.

  5. Use the code example appearing in Signing In to Lync Server to add sign-in logic to the code file.

  6. Add the following C# routine to the code file. The routine starts the self-subscription (SubscribeToSelfPresence) after registering an event handler (SelfPresenceReceivedEventHandler) to receive locally-available category instances that include mwi. The mwi instance is called after the user signs in to the endpoint.

            void StartSelfSubscription(LocalEndpoint endpoint)
            {
                if (endpoint == null || endpoint.State != LocalEndpointState.Established)
                    return;
    
                _localPresence = endpoint.LocalOwnerPresence;
                _localPresence.PresenceNotificationReceived +=
                    new EventHandler<LocalPresentityNotificationEventArgs>(
                        SelfPresenceReceivedEventHandler);
                _localPresence.EndSubscribe(_localPresence.BeginSubscribe(null, null));
            }
    

    The previous code example invokes the asynchronous call to subscribe to self-presence synchronously. You should avoid this kind of shortcut in any production code.

  7. Add the following implementation of the SelfPresenceReceivedEventHandler event handler for the PresenceNotificationReceived event.

    private void SelfPresenceReceivedEventHandler(object sender, LocalPresentityNotificationEventArgs e)
    {
    
        #region Find MWI Category
        foreach (var cat in e.AllCategories)
        {
            if (category.Name == "mwi")
            {
                 XmlDocument xmldoc = new XmlDocument();
                 xmldoc.LoadXml(cat.Category.GetCategoryDataXml());
                 XmlNode node = xmldoc.SelectSingleNode("./mwi");
    
                 string mwi = null;
                 int readCount = 0;
                 int unreadCount = 0;
                 XmlAttribute attr = node.Attributes["messageWaiting"];
                 if (attr != null)
                    mwi = attr.Value;
    
                 attr = node.Attributes["unreadVoiceMailCount"];
                 if (attr != null)
                    int.TryParse(attr.Value, out unreadCount);
    
                 attr = node.Attributes["readVoiceMailCount"];
                 if (attr != null)
                     int.TryParse(attr.Value, out readCount);
    
                 Console.WriteLine("mwi = {0}; readCount= {1}; unreadCount = {2}", mwi, readCount, unreadCount);
            } 
        }
        #endregion
    }
    

    In the previous code example, an XmlDocument instance is used to load the raw XML string that is located before the messageWaiting, unreadVoiceMailCount, and readVoiceMailCount attributes of the selected mwi category instance. There are other programming techniques that you can use to complete this task. For example, you can use the System.XmlSerialization namespace to deserialize the raw XML data into a .NET Framework object, and then inspect the appropriate properties on the deserialized object. For more information, see Programming Enhanced Presence Schemas Part 1: Create .NET Framework Assembly from Schemas.

The next section discusses how to use Microsoft Exchange Web Services to query Exchange Server 2007 SP1 and then extract voice mails from the user’s Exchange email account.

Use Exchange Web Services to Query Voice Mails in Exchange Server 2007 SP1

The following tasks show the process that is used to call Exchange Web Services (EWS) and then directly query voice mails in an Exchange Server 2007 SP1 email account.

  • Ensure Exchange Server 2010 SP1 Web Services SDK is installed on the development computer.

  • Instantiate EWS by creating an ExchangeService instance.

  • Specify the credentials for the user account.

  • Connect to Exchange Server 2007 SP1

  • Query voice mails in the Voice Mail folder.

  • Enumerate the query results to determine the number of read and unread voice mails.

To use EWS to query voice mails

  1. Install Exchange Server 2010 SP1 Web Services SDK. The default installation folder is %ProgramFiles%\Microsoft\Exchange\Web Services\1.0.

  2. In Visual Studio 2010, create a new Console application project that is named EwsConsole. Use all default settings.

  3. In the project, add a reference to the EWS Microsoft.Exchange.WebServices.DLL assembly that is installed in step 1.

  4. In the default Program.cs file for the application project, append the following C# using directive to the existing using directive block.

    using Microsoft.Exchange.WebServices.Data;
    

    The Microsoft.Exchange.WebServices.Data namespace is used to query Exchange Server 2007 SP1 and verify the number of voice mails.

  5. Add the C# code fragment to initialize EWS in the Main method of the Program class. The following code example shows how Program.cs appears in the project.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    using Microsoft.Exchange.WebServices.Data;
    
    namespace EwsConsole
    {
        class Program
        {
            static void Main(string[] args)
            {
                ExchangeService exService = new ExchangeService(ExchangeVersion.Exchange2007_SP1);
                exService.UseDefaultCredentials = true;
                exService.AutodiscoverUrl("user@contoso.com");
    
                FindVoiceMails(exService);
            }
        }
    }
    

    The FindVoiceMails routine implements the logic that is used to query and enumerate voice mails in the user’s Outlook Inbox, which is discussed in the next step.

  6. Add the following C# code listing to the Program class file.

            static void FindVoiceMails(ExchangeService service)
            {
                if (service == null)
                    return;
    
                int pageSize = 50;
                ItemView itemView = new ItemView(pageSize);
                WellKnownFolderName voiceMailFolder = WellKnownFolderName.VoiceMail;
                int count = 0;
                int unread = 0;
    
                FindItemsResults<Item> findResults;
                do
                {
                    findResults = service.FindItems(voiceMailFolder, itemView);
                    count += findResults.TotalCount;
    
                    foreach (Item item in findResults.Items)
                    {
                        EmailMessage msg = item as EmailMessage;
                        msg.Load(new PropertySet(BasePropertySet.FirstClassProperties));
    
                        string subject = msg.Subject;
                        string sender = msg.From.Name;
                        bool isNew = msg.IsNew;
                        bool isRead = msg.IsRead;
                        if (!isRead)
                        {
                            unread++;
                        }
                    }
    
                    itemView.Offset += pageSize;
                } while (findResults.MoreAvailable);
                Console.WriteLine("total voice mails = " + count);
                Console.WriteLine("unread voice mails = " + unread);
    
            }
    

    In the previous code example, the query returns a maximum of 50 messages at the same time until all of the voice mails in the user’s Outlook Inbox are returned.

Although the example appearing in this article describes a one-off query, EWS push notification features can also be used to automatically receive new or updated voice mails. For more information, see Push Notification Sample Application.

Conclusion

In this article, Message Waiting Indicator (MWI) category instances are used to determine when new voice mail messages appear in a unified communications application that is integrated with Exchange Server 2010 SP1. This article discussed how to complete the following tasks.

  1. Sign in to Lync Server 2010.

  2. Subscribe to self-presence.

  3. Handle PresenceNotificationReceived events that are raised in the self-subscription session.

  4. Parse the received mwi category instance.

This article also discussed how to use Exchange Web Services (EWS) to query for voice mails in Exchange Server 2007 SP1 and complete the following tasks.

  1. Create an ExchangeService instance against Exchange Server 2007 SP1.

  2. Specify the security credential that is used to access the specified Exchange Server 2007 SP1 email account.

  3. Connect to Exchange Server 2007 SP1.

  4. Query voice mails from the user’s Outlook Inbox.

  5. Enumerate the results to verify the number of read and new voice mails.

Additional Resources

For more information, see the following resources:

About the Author

Kurt De Ding is a Senior Programming Writer in the Microsoft Office Content Publishing (UA) group.