Pages Menu
TwitterRssFacebook

Posted by on May 26, 2015 in Skype for Business® (Lync®)

Learn Skype Web SDK Day 19 : Receiving a New Conversation

Learn Skype Web SDK Day 19 : Receiving a New Conversation

This is one post in a series of more than 30, devoted to helping you get up to speed quickly with the new Skype Web SDK. Each lesson comes with source code (in GitHub) and a working demo page so you can see what it does. Check out the full list of posts on the Skype Web SDK page.


View Demo
Depending on the Skype for Web API application you’re building, you may need to deal with new incoming messages. Once you’ve signed in as a Skype for Business user your presence will show as Available to everyone else, and they may decide to IM you. It’s not obvious from the Skype for Business desktop client that a user has signed in over the web so people may just think that you have the full capabilities of the Skype for Business client.

Of course, you can just ignore possibility entirely, in which case anyone sending an IM will receive a timeout message. However a nicer user experience, even if you don’t intend on handling incoming messages is to code for it, and reject them – this will give a better experience to the person sending the message, rather than letting it just time out.

When a new conversation request is received by the Skype for Web API, it is added to the list of conversations managed by the conversationsManager. By monitoring new conversations being added here you can then take actions when they appear.

You can register an event listener for new conversations being added with the event listener:

var client = new Skype.Web.Model.Application;
 //perform sign in
   client.conversationsManager.conversations.added(function (newConversation) {
//do something with newConversation
});

Obviously there is only one conversationsManager and if you’re starting your own conversations as well then conversations will be being added and removed from this fairly regularly. There are two important things you should check for to know whether this is a incoming conversation you need to act on. You should check that you are able to accept the conversation, and that the conversation is in the right state to be accepted.

Checking to see whether you are able to accept the conversation is in fact checking the specific modality you are interested in, to see if it is supported. IM should always be support, but it’s good practice to make sure. You do this by checking the value of:

newConversation.chatService.accept.enabled()

Secondly, you should evaluate the state of the conversation. A conversation moves through various states during its lifetime and checking the current state will make sure you don’t try and accept or reject a conversation that isn’t ready for it. If the conversation state is Notified then it means that the conversation is waiting for an invitation decision to be made: i.e. it’s ready to be accepted or declined:

newConversation.chatService.state() == 'Notified'

Putting the two together gives you:

var client;
 //code to instantiate client and perform sign in
   client.conversationsManager.conversations.added(function (newConversation) {
    if (newConversation.chatService.accept.enabled() && newConversation.chatService.state() == 'Notified')
      {
       //accept or reject invite
      }
});

Actually accepting or rejecting the conversation invitation is easy:

newConversation.chatService.accept();

or

newConversation.chatService.reject();

Of course, in a real-life scenario you might want to display a notification about the new conversation to the user, and let them make the decision to accept or reject. With the event listener shown above the newConversation object has full information about who is calling (checking the participants() object for a list of participants so you can easily pull out the caller’s name and photo. You might also look at JavaScript libraries such as toast.js to provide a familiar toast popup.

The code sample below with respond to an incoming IM conversation, allowing it to be accepted or declined:

 <div class="form-horizontal">
    <div class="form-group">
      <label for="username" class="col-sm-2 control-label">Username</label>
      <div class="col-sm-10">
        <input type="email" class="form-control" id="username" placeholder="Email">
      </div>
    </div>
    <div class="form-group">
      <label for="password" class="col-sm-2 control-label">Password</label>
      <div class="col-sm-10">
        <input type="password" class="form-control" id="password" placeholder="Password">
      </div>
    </div>

    <div class="form-group">
      <div class="col-sm-offset-2 col-sm-10">
        <button class="btn btn-default" id="btnLogIn">Log in</button>
      </div>
    </div>

    <div class="form-group">
      <div class="col-sm-offset-2 col-sm-10">
        <button class="btn btn-default" id="btnLogOut">Log out</button>
      </div>
    </div>
  </div>

  <div>
    <span id="loginStatus"></span>
  </div>

  <hr/>

 <div id="divIncomingNotification" style="display: none;" >

<span id="lblNewConversationMsg"></span>
  <div class="form-horizontal">
    <div class="form-group">
      <div class="col-sm-offset-2 col-sm-10">
        <button class="btn btn-default" id="btnAccept" >Accept</button>
      </div>
    </div>

    <div class="form-group">
      <div class="col-sm-offset-2 col-sm-10">
        <button class="btn btn-default" id="btnDecline" >Decline</button>
      </div>
    </div>
  </div>

 </div> <!-- IncomingNotification -->

<div id="divActiveConversationControls" style="display: none;">

  <div class="form-horizontal">   
   
     <div class="form-group">
      <div class="col-sm-offset-2 col-sm-10">
        <button class="btn btn-default" id="btnStopConversation">Stop</button>
      </div>
    </div>
  </div>

    Conversation State: <span id="lblConversationState"></span>
    <ul id='conversationText'></ul>

<hr/>

  <div class="form-horizontal">
    <div class="form-group">
      <label for="message" class="col-sm-2 control-label">Send Message:</label>
      <div class="col-sm-10">
        <input type="email" class="form-control" id="message" placeholder="Message to send">
      </div>
    </div>  

    <div class="form-group">
      <div class="col-sm-offset-2 col-sm-10">
        <button class="btn btn-default" id="btnSendIM">Send IM</button>
      </div>
    </div>
  </div>

</div> <!-- ActiveConversationControls -->
  
  
  
  <div id="footer"></div>
  
  <!-- This is not needed for the samples to run, but adds standard headers and footers to the samples, to display title, instructions, about etc.
       If you're taking this code and using it yourself, you can remove this.-->
   <script type="text/javascript" src="../../assets/layoutcodesample-min.js"></script>
  
  <script type="text/javascript">

  <!-- These variables are only needed for laying out the code sample, they are not part of the sample code. -->
  var pageTitle = 'Receiving a Conversation';
  var blogPostLocation = "http://thoughtstuff.co.uk";
  var githubLocation = "http://github.com";
 


 var client;
  $(function () {
    'use strict';

	Skype.initialize({
            apiKey: 'SWX-BUILD-SDK',
        }, function (api) {
            client = new api.application();           
			
		// whenever client.state changes, display its value
		client.signInManager.state.changed(function (state) {
		$('#loginStatus').text("Login State: " + state);
		});
	
        }, function (err) {
            alert('Error loading Skype Web SDK: ' + err);
        }); 

    $('#btnLogIn').click(function () {

        // start signing in
        client.signInManager.signIn({
          username: $('#username').val(),
          password: $('#password').val()
        }).then(function () {
            //log in worked!
            alert('Logged in!');
            ListenForNewConversations();
            
          }, function (error) {
            //Something went wrong.
            alert(error);
          });
      });

    $('#btnLogOut').click(function () {
        // start signing out
        client.signInManager.signOut()
        .then(function () {
               //log out worked!
               alert('Logged out!');               
             }, function (error) {
                //Something went wrong.
                alert(error);
              });
      });


    $('#btnStopConversation').click(function () {
      StopConversation();
    });

        $('#btnSendIM').click(function () {
      conversation.chatService.sendMessage($('#message').val());
    });

        $('#btnAccept').click(function () {
          AcceptConversation();
        });

        $('#btnDecline').click(function () {
          RejectConversation();
        })

  function ListenForNewConversations() {
    client.conversationsManager.conversations.added(function (newConversation) {
      if (newConversation.chatService.accept.enabled() &amp;&amp; newConversation.chatService.state() == 'Notified')
      {
        conversation = newConversation;
        $('#lblNewConversationMsg').text('Incoming Conversation from ' + conversation.participants()[0].name());
        $('#divIncomingNotification').show();
      }
    });
  }

  function AcceptConversation() {
    
//register for the conversation state changing to connected.
  conversation.chatService.state.changed(function(newState){
  $('#lblConversationState').text(newState);
    if (newState == 'Disconnected') {
     $('#divActiveConversationControls').hide();
  }
  });

 
//register for new messages added to the historyService object
  conversation.historyService.activityItems.added(function (newMsg){
    if (newMsg.type() == 'TextMessage')
    {
         var direction;
         if (newMsg.direction() == 'Incoming') 
            direction = "<--";          
         else
         {
            direction = "-->";          
          }

         $("#conversationText").append('<li><b>' + direction + '</b>&amp;nbsp; ' + newMsg.sender.displayName() + ' : ' + newMsg.text() + '</li>');  
    }
  });

   //finally, accept the conversation 
    conversation.chatService.accept();


    //update the UI
    $('#divIncomingNotification').hide();
    $('#divActiveConversationControls').show();
  }

  function RejectConversation() {
    conversation.chatService.reject();
    $('#divIncomingNotification').hide();
  }


function StopConversation() {
if (conversation != null)
  //conversation.chatService.stop();  
//client.conversationsManager.conversations.remove(conversation)
conversation.leave();
}


});

</script>

Demo Online

You can try this code out against your own Skype for Business environment by going to the demo page. From here you can also download the code from GitHub if you want to host it locally, or take it and use it in your next project.

Disclaimer: This is sample code, intended to inform and educate. It is not production-ready and is lacking key components such as error handling. You use it entirely at your own risk. You should fully understand the effects, limitations and risks of the code before executing, and understand the implications of any set-up steps. By using these code examples you are using the Skype Web SDK, so you should read the Skype Software License Terms to which you are agreeing.

Good to Know

Written by Tom Morgan

Tom is a Microsoft Teams Platform developer and Microsoft MVP who has been blogging for over a decade. Find out more.
Buy the book: Building and Developing Apps & Bots for Microsoft Teams. Now available to purchase online with free updates.

Post a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.