Extending Unified Communications Services of UCMA Bots to PIC Clients: Intercepting Presence Requests (Part 2 of 5)

Summary:   Learn how to extend Microsoft Lync Server 2010 supported unified communications services that are provided by a trusted Microsoft Unified Communications Managed API (UCMA) bot application to Public Internet Cloud (PIC) clients. Without the extension, the unified communications services are restricted to a limited number of Microsoft Lync 2010 clients in a single enterprise network domain. This number is derived from the CategorySubscriptions property of the presence policy that is set by a Lync Server 2010 administrator. Here, PIC clients can include Windows Live Messenger, Skype, and Yahoo! Messenger.

Programmatically, you learn how to enable a Lync Server 2010 application by using the Microsoft Lync Server 2010 SIP Application API and UCMA. Lync Server 2010 SIP Application API is used to intercept a presence subscription from a PIC client and UCMA is used to send the requesting PIC client the online status of an active bot.

Applies to:   Microsoft Unified Communications Managed API (UCMA) 3.0 Core SDK | Microsoft Lync Server 2010 SDK

Published:   May 2012 | Provided by:   Kurt De Ding and Ajay Soni, Microsoft | About the Author

Contents

  • Intercepting Presence SUBSCRIBE Requests by PIC Clients

  • Additional Resources

Download code  Download code

This is the second in a series of five articles about how to extend the services of a Microsoft Unified Communications Managed API (UCMA) bot application to Public Internet Cloud (PIC) clients by enabling an unlimited number of PIC clients that can subscribe to the presence of the UCMA bot.

Intercepting Presence SUBSCRIBE Requests by PIC Clients

To receive presence state of a presentity, including a bot, a client sends a SIP request of the SUBSCRIBE method to Microsoft Lync Server 2010. Before processing a SIP message, Lync Server 2010 can reroute it to registered applications for preprocessing or custom handling, as long as the message type matches what is declared in the application manifests. Lync Server 2010 calls the loaded MSPL script and uses the MSPL built-in variables, such as sipRequest, sipResponse and sipMessage to pass along the intercepted message.

To handle the presence subscription by a PIC client, SUBSCRIBE requests must be declared in the application manifest by using the <requestFilter> element of the following format:

<requestFilter methodNames="SUBSCRIBE"/>

In addition, the application must also ensure that only the presence SUBSCRIBE requests from PIC clients are handled. This is done by parsing the intercepted SIP message in the MSPL script. In this section, you learn how to parse an intercepted SUBSCRIBE message to determine whether it is from a PIC client.

In a Lync Server 2010 deployment, a client can submit SIP SUBSCRIBE requests to receive various kinds of data, ranging from self-published contact lists and roaming data to server-provisioned configuration and policies, and to presence data published by remote users or presentities. In a SIP message, the kind of SUBSCRIBE request can be determined by the value of the Event header, as is summarized in the following table.

SUBSCRIBE request type

Event header value

Remote presence

presence

Contact list

application/vnd-microsoft-roaming-contacts+xml

Roaming data

vnd-microsoft-roaming-self

In-band provisioning

vnd-microsoft-provisioning-v2

In addition, the message content (or message body) of the different kinds of SUBSCRIBE requests have different formats. For the presence SUBSCRIBE request, the message body contains a <batchSub> element that includes, under the <adhocList> element, a list of presentities to whose presence the sender wishes to subscribe. It also contains, in the <categoryList> element, a list of categories specifying the kinds of presence data to be received. Each presence data type is described by the name attribute of a <category> element. Each presentity is described by a <resource> element. Its uri attribute specifies the SIP URI of the presentity. If the <adhocList> contains a single <resource> element, the request is known as a single SUBSCRIBE. If there are multiple <resource> elements in the list, the request is a batched SUBSCRIBE. Lync Server 2010 requires that batched SUBSCRIBE be used for the requests when the subscriber and targeted publishers are in the same enterprise pool and that single SUBSCRIBE requests be made when the subscriber and publisher are not in the same enterprise pool. The latter implies that a single SUBSCRIBE request is made by either a Microsoft Lync 2010 client on a different enterprise pool or a PIC client, which is definitely on a different pool. Also, the To and From Uri values are different in a single SUBSCRIBE request and they are identical in a batched SUBSCRIBE request.

As an example, consider a SUBSCRIBE request that is used for a local user (sip:sender@contoso.com) to receive the state, contactCard, calendarData, notes, and services types for the presence data that is published by two remote users (sip:johndoe@contoso.com, sip:janedoe.contoso.com) and one trusted server application (sip:lobapp@contoso.com):

SUBSCRIBE sip:sender@contoso.com SIP/2.0
Via: SIP/2.0/TLS 10.121.132.136:64403
Max-Forwards: 70
From: <sip:sender@contoso.com>;tag=ab252fa3a7;epid=16ce6a1da0
To: <sip:sender@contoso.com>
Call-ID: eeb7080c638f4a7387d3184f7fd7eaf2
CSeq: 1 SUBSCRIBE
Contact: <sip:sender@contoso.com;opaque=user:epid:2OMA-5poxVOPb7Z4ozfhpAAA;gruu>
User-Agent: UCCAPI/4.0.7736.0 OC/4.0.7736.0 (Microsoft Lync 2010)
Event: presence
Accept: application/msrtc-event-categories+xml, application/xpidf+xml, text/xml+msrtc.pidf, application/pidf+xml, application/rlmi+xml, multipart/related
Supported: com.microsoft.autoextend
Supported: ms-benotify
Proxy-Require: ms-benotify
Supported: ms-piggyback-first-notify
Require: adhoclist, categoryList
Supported: eventlist
Proxy-Authorization: TLS-DSK qop="auth", realm="SIP Communications Service", opaque="6A10A67D", targetname="000DCO2O40FE13.corp.contoso.com", crand="fecfe177", cnum="12", response="c1211726ef689c5362c5f2423cf6c5a4839b1dd6"
Content-Type: application/msrtc-adrl-categorylist+xml
Content-Length: 1223

<batchSub xmlns="https://schemas.microsoft.com/2006/01/sip/batch-subscribe" uri="sip:sender@contoso.com" name="">
  <action name="subscribe" id="169563800">
    <adhocList>
      <resource uri="sip:johndoe@contoso.com"/>
      <resource uri="sip:janedoe@contoso.com"/>
      <resource uri="sip:lobapp@contoso.com"/>
    </adhocList>
    <categoryList xmlns="https://schemas.microsoft.com/2006/09/sip/categorylist">
      <category name="state"/>
      <category name="contactCard"/>
      <category name="note"/>
      <category name="services"/>
      <category name="calendarData"/>
    </categoryList>
  </action>
</batchSub>

This request cannot be from a PIC client because it is a batched SUBSCRIBE. There are more than one <resource> elements under <adhocList> and the To and From SIP URI values are the same. However, if this is a single SUBSCRIBE, with a single <resource> element and different To and From SIP URI values, the request is not from a PIC client because it is still consistent with a request submitted from a nm-oc-14-2nd client on a different enterprise pool. A more definitive criterion is to check for the presence of the ms-edge-proxy-message-trust header on a SUBSCRIBE request. If the header is present and contains the ms-source-network parameter with a value of publiccloud, then the SUBSCRIBE request is from a PIC client. This logic appearing in the next example is used in the MSPL script in our Lync Server 2010 application.

    if(sipRequest)
    {
        // Check that the message is from a PIC user
        
        isPICUser = false;
        foreach (header in GetHeaderValues("ms-edge-proxy-message-trust"))
        {
            msSourceNetworkType = GetParameterValue(header, "ms-source-network");            
            if (msSourceNetworkType == null)
            {
                // skip - it's not a PIC message
                return;
            }

            if (EqualString(msSourceNetworkType, "publiccloud", true))
            {
                // This is a subscribe from a PIC user
                isPICUser = true;
            }
            // Not expecting more than one ms-edge-proxy-message-trust header
            // in a SIP message.
            break; 
        }

        if (isPICUser)
        {
            foreach (eventHeader in GetHeaderValues("Event"))
            {
                if (ContainsString(eventHeader, "presence", true))
                {            
                    Dispatch("OnSubscribe");
                    break;
                }
            }
        }
    }
return;

In the previous code listing, the top-level if statement, if (sipRequest) ( …) , ensures that only a SIP Request is handled in this script, by testing if the built-in sipRequest variable is set (where the value is not NULL). If the sipRequest is set, the enclosed script block is executed. First, it verifies if the SIP request is from a PIC client by examining whether the message contains the ms-edge-proxy-message-trust header. If so, additional tests are performed to see whether the header has the msSourceNetworkType parameter set to the value of publiccloud. Here, GetHeaderValues is a MSPL built-in function that returns a collection of strings as the header value of the specified header name. GetParameterValues is another MSPL built-in function that returns the parameter value of a specified parameter in the given header. Secondly, it checks for the Event header with the value of “presence”. Only when the both conditions are met, does the application proceed to process the message by calling the MSPL built-in Dispatch function to invoke the OnSubscribe event handler implemented by the managed Lync Server Application component, which is discussed in Extending Unified Communications Services of UCMA Bots to PIC Clients: Handling SUBSCRIBE Requests (Part 3 of 5).

If the sipRequest object is not set or if any of the ensuing conditions are not satisfied before Dispatch is called, the enclosed script block is skipped and the server application stops processing the message. The message remains unhandled. According to the application manifest, where action attribute is set to “true” in the <proxyByDefault > element, the original SUBSCRIBE request is then rerouted back to the server for additional processing, including additional filtering by other Lync Server 2010 applications. If proxy by default is not set to true, the script must call the MSPL built-in ProxyRequest(sipRequest) function to start rerouting explicitly.

In practice, using an MSPL to filter, reroute, and log a message is useful when the message handling requires no more than basic string manipulations. One example involves searching and removing scenarios where the lastActive attribute of an aggregateState category instance in a message body of a NOTIFY or BENOTIFY message and a 200 OK response to a SUBSCRIBE request is used. The logic can be implemented by using the MSPL built-in functions of IndexOfString, SubString and Concatenate, in addition to the ProxyRequest and ProxyResponse functions to reroute the processed message back to the server. Such handling prevents Lync 2010 clients from displaying the information about how long a user has been in the presence state of Away or Offline. It can be a convenient solution to enforce a custom privacy policy for any users in an enterprise. In this case, using a script is sufficient and the Dispatch function will not be called. A script-only Lync Server 2010 application manifest must contain an empty <scriptOnly/> element.

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. Ajay Soni is a Senior Program Manager with Engineering, Community & Online (ECO) of Microsoft Services.