Learn how to configure presence by using the Lync Server 2013 API. Presence helps a caller decide how to communicate with a colleague.

If the colleague's presence is available, the caller can start the call immediately. If the colleague is away or offline, the caller can send the colleague an email. By default, Microsoft Lync 2013 displays how long a user has been away or offline along with the corresponding presence status. However, in a certain locality, this is deemed as a violation of the local privacy requirement and the time period must be removed from the presence display in Lync 2013. This process can be accomplished by using a Microsoft Lync Server 2013 SIP Application API application that filters and removes the SIP messages that contain the presence data and removes time information. This process is similar to the message payloads that are used to How to: Enforce content integrity and, again, can be carried out in a Microsoft SIP Processing Language (MSPL) script or in a managed code message handler. In this topic, an MSPL script is used.

Published presence data is delivered to a client by the Microsoft Lync Server 2013 instance as SIP NOTIFY or BENOTIFY request. The message payload contains a collection of presence category instances. One of them is a state category of the AggregateStatetype. This state category instance contains the lastActiveattribute, when the contained presence status is Away (the availability number between 15000 and 17999) and Offline (the availability number is 18000 or higher). The lastActiveattribute value records the time when the user was last active. An instance of this category appears in the next example.

XML  Copy codeCopy code
<categories
xmlns="http://schemas.microsoft.com/2006/09/sip/categories"
uri="sip:sam@contoso.com">
  <category
xmlns="http://schemas.microsoft.com/2006/09/sip/categories"
name="state" instance="0" publishTime="2012-07-12T13:58:54.237">
	<state xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

		xmlns="http://schemas.microsoft.com/2006/09/sip/state" 
		xsi:type="aggregateState"
lastActive="2012-07-12T13:58:54">
	 <availability>18000</availability>
	</state>
  </category>
</categories>

Lync uses the lastActiveattribute value to compute the duration when a presentity has been in the Away or Offline state and displays the time duration to the user. The enforcement of the custom privacy requirements discussed earlier disables the display of this information.

One way to disable the display of the time duration involves removing the lastActiveattribute from the AggregateStatecategory instances before the subscriber receives it. As shown in the following script-only SIP application manifest example, the processing corresponds to searching for the pattern of lastActive="T"and removing any occurrences from such presence category instances.

  Copy codeCopy code
<?xml version="1.0"?>
<r:applicationManifest
   r:appUri="http://www.contoso.com/RemoveLastActiveAttribute"
   xmlns:r="http://schemas.microsoft.com/lcs/2006/05">
   <r:allowRegistrationBeforeUserServices/>
   <r:serverFilter roles="ALL"/>

   <!-- handle NOTIFY, BENOTIFY, and SUBSCRIBE requests -->
   <r:requestFilter methodNames="NOTIFY,BENOTIFY,SUBSCRIBE"
				 strictRoute="true"
				 registrarGenerated="true"
				 domainSupported="true"/>

   <!-- handle 2XX response. -->
   <r:responseFilter reasonCodes="2XX"/>

   <!-- Script-only application. -->
   <r:scriptOnly/>

   <r:splScript><![CDATA[
	 Log("Event", true, "Entering RemoveLastActiveAttribute.am with
content: \r\n", sipMessage.Content);
	 Log("Debugr", true, "Entering RemoveLastActiveAttribute.am
with content: \r\n", sipMessage.Content);
	 skipScan = true;
	 foreach(s in GetHeaderValues(StandardHeader.Event)) {
	 skipScan = !EqualString(s, "presence", true) &&
!EqualString(s, "vnd-microsoft-roaming-self", true);
	 break;
	 }
	 
	 if (!skipScan && ContainsString(sipMessage.Content,
"lastActive", true)) {
	 newContent = "";
	 foreach (element in Split(sipMessage.Content, "<")) {
		 if (element!= "") {
		 if(!ContainsString(element, "lastActive", true)) {
			 newContent = Concatenate(newContent,
Concatenate("<", element));
		 }
		 else {
			 index = IndexOfString(element, "lastActive=\"");
			 index1 = index + 12 + IndexOfString(SubString(element,
index+12), "\"");
			 before = SubString(element, 0, index);
			 after = SubString(element, index1+1,
LengthString(element)-index1-1);
			 newElement = Concatenate(before, after);
			 newContent = Concatenate(newContent,
Concatenate("<", newElement)); 	 
		 }
		 }
	 }
	 sipMessage.Content = newContent;
	 }
	 Log("Event", true, "Exiting RemoveLastActiveAttribute.am with
new content:\r\n", sipMessage.Content);
	 Log("Debugr", true, "Exiting RemoveLastActiveAttribute.am with
new content:\r\n", sipMessage.Content);
	 if (sipRequest) {
	 ProxyRequest("");
	 }
	 else if (sipResponse) {
	 ProxyResponse();
	 }
   ]]></r:splScript>
</r:applicationManifest>

This SIP application selects and processes only the NOTIFY, BENOTIFY requests, and the 2XX responses. The selection is specified by the <requestFilter>and <responseFilter>elements, respectively of the application manifest. The search and remove operation is carried out in the embedded MSPL script. However, not all the NOTIFY or BENOTIFY messages need to be processed. It is necessary to process only the NOTIFY or BENOTIFY messages whose EVENT header has the value of "presence"or "vnd-microsoft-roaming-self". The first type of the NOTIFY or BENOTIFY messages contains the presence state data of a remote presentity. And the second type is for the self-presence. The first foreachloop is used to ensure that only the NOTIFY or BENOTIFY message types are processed. Otherwise, the messages are routed back to the server.

The processing proceeds as follows:

  1. If the message content does not contain any " lastActive" attribute, skip the processing and route the message back to the server.

  2. Split the message content into a collection of substring, separated by "<", and enumerate substrings to locate all the " lastActive" occurrences. This is similar to enumerating the XML element tags to identify the lastActiveattributes.

  3. If a substring does not contain the lastActiveattribute, prepend "<" to the substring and append the result to the newContentvariable. If the substring contains the lastActiveattribute, remove the attribute (including the value) from the substring and prepend "<" to the processed substring, and then append the result to the newContentvariable.

  4. Update the message content with the newContentvalue.

  5. Route the updated message back to the server that will eventually deliver the message to the requesting client.

Note Note

The foreach …construct must be applied against a collection generated by a built-in MSPL function, such as a Split(string, string) function. The string separator used in Splitmust be a single character. This means that the "lastActive"phrase cannot be used. Although it is possible to use another single character in Splitto generate the collection, the use of "<" is a simple approach in the context of MSPL. Although MSPL is limited in terms of processing messages, its use invokes less overhead in the processing of messages. The managed code message handler, on the other hand, supports more advanced processing capabilities, but its invocation will more likely incur more overhead.

The foreachloop shown above can be replaced with a whileloop. For more information, see the RemoveLastActiveAttributesample in the Code Gallery on MSDN.

See also