Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / XML

A simple XMPP-client based on Workflow Foundation

4.44/5 (8 votes)
27 Dec 2009CPOL3 min read 65.5K   3.8K  
This article describes a simple XMPP client application based on Workflow Foundation.

Image 1

Introduction

The article describes a simple XMPP client application based on the Windows Workflow Foundation, which allows to send and receive messages and also to add and remove contacts from your contact list.

Background

Extensible Messaging and Presence Protocol

The Extensible Messaging and Presence Protocol (XMPP) is an open technology for real time communication, using Extensible Markup Language (XML) as the base format for exchanging information. In essence, XMPP provides a way to send small pieces of XML from one entity to another in close to real time.

The XMPP protocol is taken as the RFC standard, and is described by the following documents:

  • RFC 3920 Extensible Messaging and Presence Protocol: Core
  • RFC 3921 Extensible Messaging and Presence Protocol: Instant Messaging and Presence

Windows Workflow Foundation

Windows Workflow Foundation (WF) is a Microsoft technology for defining, executing, and managing workflows. This technology was first released in November 2006 as a part of .NET Framework 3.0.

WF is a special runtime environment that manages the execution of programs that are composed of resumable program statements. In WF, a resumable program statement is called an Activity. A resumable program is a composition of activities. In WF, such a program is often called a Workflow.

Using the Code

The project consists of two libraries and an XOML-file: JabberClient.dll (root namespace is Jabber.Client), WorkflowActivities.dll (root namespace is Workflow), and Sequence.xml.

Namespace Jabber.Client

The Jabber.Client namespace includes the types for the XMPP client realization with minimal functionality, which are presented in the following list:

  • Jabber.Client.Core.TcpBinder wraps the standard System.Net.Sockets.Socket class.
  • Jabber.Client.Core.ClientState enumerates the possible client states.
  • Jabber.Client.Xml.PacketBuilder contains the methods for building XML-strings for XMPP-server requests (authentication, contact list request, message sending, etc.).
  • Jabber.Client.Xml.PacketParser contains the methods for XMPP-server response parsing.
  • Jabber.Client.Cryptography.DigestMD5Auth implies digest authentication according to RFC2831.
  • Jabber.Client.JabberClient encapsulates all of XMPP-client logic.

Namespace Worflow

The Worflow namespace includes the set of activities and helper classes which help to specify the program algorithm. You can see the list of main activities below.

  • Workflow.Activities.Receiver retrieves the message from a Queue, converts it with the help of the ReceiveMethod method of the ReceiveType class of the AssemblyFile assembly, and calls the OnReceived method of the IWorkflowDataService interface.
  • Workflow.Activities.Sender retrieves the message from a Queue, converts it with the help of the SendMethod method of the SendType class of the AssemblyFile assembly, and calls the Send method of the IWorkflowDataService interface.
  • Workflow.Activities.StateSendAndReceive sends the message and receives the response. For it to work, the activity needs these properties: ReceiveMethod, ReceiveType, AssemblyFile, SendMethod, SendType, and Context. The Context property is used as in-out params.
  • Workflow.Activities.Sequence is a type of CompositeActivity, which sequentially executes its child activities.
  • Workflow.Activities.Switch emulates a switch instruction.

Thus, the simple XMPP client's XOML-file is represented below:

XML
<Sequence x:Name="root"
   xmlns="http://Workflow/Activities"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:wf="http://schemas.microsoft.com/winfx/2006/xaml/workflow">
  <Switch  x:Name="sw1">
    <StateSequence x:Name="Auth" Queue="AuthInputQueue">
      <StateSendAndReceive Name="step1_0" AssemblyFile="JabberClient.dll" 
        SendType="Jabber.Client.Xml.PacketBuilder"  SendMethod="AuthStreamHeader" 
        ReceiveType="Jabber.Client.Xml.PacketParser" ReceiveMethod="AuthStreamHeader1" 
        Context="{wf:ActivityBind Auth, Path=Context}" />
      <StateSendAndReceive Name="step1_1" AssemblyFile="JabberClient.dll" 
            ReceiveType="Jabber.Client.Xml.PacketParser" 
            ReceiveMethod="AuthStreamHeader2" 
            Context="{wf:ActivityBind step1_0, Path=Context}" />
            ........
    </StateSequence>
    <Receiver x:Name="Receive" Queue="ReceiveQueue" 
            AssemblyFile="JabberClient.dll" 
            ReceiveType="Jabber.Client.Xml.PacketParser" 
            ReceiveMethod="ResponseMessage" />
    <Sender x:Name="Send" Queue="SendQueue" 
            AssemblyFile="JabberClient.dll" 
            SendType="Jabber.Client.Xml.PacketBuilder" 
            SendMethod="ChatMessage"/>
    <Sender x:Name="Status" Queue="StatusQueue" 
            AssemblyFile="JabberClient.dll" 
            SendType="Jabber.Client.Xml.PacketBuilder" 
            SendMethod="PresenceShow"/>
    <Sender x:Name="Roster" Queue="RosterQueue" 
            AssemblyFile="JabberClient.dll" 
            SendType="Jabber.Client.Xml.PacketBuilder" 
            SendMethod="Roster"/>
    <Sender x:Name="Subscribe" Queue="RosterQueue" 
            AssemblyFile="JabberClient.dll" 
            SendType="Jabber.Client.Xml.PacketBuilder" 
            SendMethod="Subscribe"/>
    <Sender x:Name="Unsubscribe" Queue="RosterQueue" 
            AssemblyFile="JabberClient.dll"
            SendType="Jabber.Client.Xml.PacketBuilder" 
            SendMethod="Unsubscribe"/>
  </Switch>
</Sequence>

It follows from the XOML-file that the StateSequence activity performs the client authentication on the XMPP-server according to RFC2831. Dynamic binding of the Context property is used in child Activities.

An example of using a simple XMPP-client is shown below:

C#
....
using Jabber.Client;
using Jabber.Client.Core;
....

using (JabberClient jabber =
            new JabberClient("jabber.org", "vba32cc", "1234qwer"))
{
    //subscribe to events
    jabber.Authentificated += new EventHandler(jabber_Authentificated);
    jabber.RosterReceived += new RosterHandler(jabber_RosterReceived);
    jabber.MessageReceived += new MessageHandler(jabber_MessageReceived);

    Console.WriteLine("Authentification...");
    jabber.Auth();
    string s = Console.ReadLine();
    Console.WriteLine("Client state={0}", jabber.State);
    while (!string.IsNullOrEmpty(s))
    {
        if (jabber.State == ClientState.Authentificated)
        {
            Contact contact = new Contact("", "veleslaff@jabber.ru");
            jabber.AddToContacts(contact); //Add to contacts
            jabber.SetStatusForContact(contact, UserStatus.Online);//Set status
            jabber.Send(contact, s); //Send  message
            jabber.Contacts(); //Get roster list
        }
        s = Console.ReadLine();
    }
}
....

Points of Interest

The error handling in the workflow library and the host program's notification need improving. Classes in the Jabber.Client.Xml namespace need refactoring.

History

  • 27th December, 2009: First version of a simple XMPP-client with basic functionality.
  • 28th December, 2009: Updated the sample project.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)