Microsoft Lync has a rich set of .NET APIs which make it easy to extend the platform and integrate it with other applications. This blog helps explain how to use them.

Response Groups and call forwarding

Posted: December 16th, 2013 | Author: | Filed under: MSPL | 6 Comments »

Every so often I get a question about Response Groups – can you use the APIs to make it do this or that thing differently? Unfortunately, the answer to these questions is usually no; Response Group Services is not very customizable. But there is one feature of Response Groups that can be changed relatively easily using the development platform. By default, calls from Response Groups ignore call forwarding or simultaneous ring settings. If you receive a call from Response Groups, it will not ring your cell phone or any other phone number you have set up the Lync client to forward to. With a simple Lync Server SDK application, you can change this and allow Response Group calls to go to call forwarding numbers.

Keep in mind that the default behavior of ignoring call forwarding is mostly by design: often you don’t want Response Group calls to go to your cell phone, for a couple of reasons. First, depending on the type of calls that are going through Response Groups, you may not want to be interrupted by these calls on your cell phone. Second, if a Response Group call gets picked up by your cell phone voice mail, for instance, Response Group Services will consider that call answered, and it may not go to another person who is actually available to take it.

If, bearing those things in mind, you still want to enable call forwarding for Response Groups calls, it’s relatively simple to do with the Lync Server SDK. For the purposes of this post, I’m going to assume some experience with the Lync Server SDK; you can find more posts about it here.

The first step is to create a manifest file (.am file) that captures INVITE requests, using a requestFilter element like this:

<lc:requestFilter methodNames="INVITE" strictRoute="false"
    registrarGenerated="true" domainSupported="true" />

Because this script will dispatch messages to managed code, you should make sure you do NOT have a <lc:scriptOnly /> element.

Finally, you should proxy requests by default using an element like this:

<lc:proxyByDefault action="true" />

In the script itself, you can do something like this:

if (sipRequest)
{
    userAgentHeaders = GetHeaderValues("User-Agent");

    foreach (userAgentHeader in userAgentHeaders)
    {
        if (ContainsString(userAgentHeader, "Response_Group_Service", true))
        {
            Dispatch("HandleRgsInvite");
        }
    }
}

This will cause INVITE messages from Response Group Services  to go to your managed code component.

Next, you’ll need to create the managed code piece. You’ll first need an application that loads your .am file, creates an instance of the ServerAgent class, and passes in the manifest file and your custom handler class. You can find details on how to do this in my post on the SIP Application API.

The core of the managed SIP application you need will be the custom handler class. The purpose of this class in this case is very simple: it needs to remove any Ms-Target-Class SIP headers that are present in the INVITE message. This header is the one that disables call forwarding and simultaneous ring. An example of the necessary code is below:

public class ResponseGroupInviteHandler
{
	public void HandleRgsInvite(object sender,
		RequestReceivedEventArgs e)
	{
		// Enable simple proxy mode and disable forking.
		e.Request.SimpleProxy = true;
		e.ServerTransaction.EnableForking = false;

		// Get a collection of all headers on the request.
		HeaderCollection headers = e.Request.AllHeaders;

		// Find and remove an Ms-Sensitivity header if present.
		Header sensitivity = headers.FindFirst("Ms-Sensitivity");
		if (sensitivity != null)
		{
			headers.Remove(sensitivity);
		}

		// Find and remove an Ms-Target-Class header if present.
		Header targetClass = headers.FindFirst("Ms-Target-Class");
		if (targetClass != null)
		{
			headers.Remove(targetClass);
		}

		// Add a custom header.
		Header newHeader = new Header("RgsCallForwardingSample",
			Dns.GetHostEntry("localhost").HostName);
		headers.Add(newHeader);

		// Send the request along.
		e.ServerTransaction.CreateBranch().SendRequest(
			e.Request);
	}
}

Next, you’ll need to deploy the application and install it using the New-CsServerApplication command; again, you can refer to the earlier post for the instructions.

Once the application is deployed and is removing the Ms-Target-Class header, calls from your Response Groups will go to call forwarding numbers like normal calls. As another side effect, you’ll get missed call notifications if you miss a Response Group call.

Please note that this approach to getting call forwarding and simultaneous ring working with Response Group Services is in no way officially supported, and if you use it in production you are doing so at your own risk.


6 Comments on “Response Groups and call forwarding”

  1. 1 Martin Zeleny said at 8:24 am on December 17th, 2013:

    What a great sample. I was looking for that since friday 13.12.2013 and you made me happy. May be you should mention which namespaces you are using. I am not so experienced, so it take time find them. (like System.Net)
    I have a question. Why in .am you are using “<lc:requestFilter" and not "<r:requestFilter" like in other samples.

    Thank you Michael

  2. 2 Michael said at 2:14 pm on February 16th, 2014:

    Hi Martin,

    Glad it was helpful.

    To answer your question, it doesn’t really matter whether the XML namespace is lc or r as long as it’s consistent throughout the manifest file. I think some of the older samples had lc and so I got in the habit of using that.

    Michael

  3. 3 Han said at 6:18 am on March 18th, 2014:

    Hi,

    The Response Groups and call forwarding looks very usefull for a project I am working on.
    One customer really needs this.
    However I am a experience .NET programmer but new with Lync.
    Is it possible to have this sample as source?
    I only want to enable this for one workflow, how can we only catch this one (sip adress) and leave eveything else like it is.
    Thanks for your help

  4. 4 Michael said at 11:56 am on March 20th, 2014:

    Hi Han,

    I will see if I can post some sample code.

    Michael

  5. 5 Han said at 9:26 am on March 26th, 2014:

    Hi Michael. Thank you

  6. 6 Dennis Højgaard said at 9:15 am on April 15th, 2014:

    Is this possible to enable for a single workflow and not the others? That would be awsome


Leave a Reply

  • Note: Comment moderation is in use because of excessive spam. Your comment may not appear immediately.

  •