Introduction
I wanted to step a little bit deeper into instant messaging development by using the Jabber protocol. The first place where I looked for an introduction was The Code Project, but I couldn't find any article dealing with Jabber client development. So I thought it's my part to write an article on how to create a small Jabber client, after I got familiar with this stuff.
In this article, I want to introduce Jabber development by a small example application that allows you to chat with one of your Roster contacts. The example is written as a Console Application, but it should be no problem to transfer the code into a small Windows Application.
Jabber/XMPP
Jabber is an open protocol for instant messaging (like Skype). The advantage of Jabber is that as an XML based protocol, it is platform independent and clients can be developed under several operating systems. It also provides the possibility to connect to other instant messaging services like ICQ. Jabber is based on the protocol XMPP (a Jabber derivative) which was standardized in 2004.
A simplified Jabber network looks like this:
The most important Jabber terms used in this article are:
JID: Jabber ID, looks like an Email address (e.g. Test@TestServer.com) where TestServer.com is the Jabber server (you can find a list of public Jabber servers here).
In the network above, we would have the following JID's:
Client1@Server1
Client2@Server1
Client3@Server2
Roster: List of contacts (friends, family). The Roster can be organized like a tree (as the Jabber protocol is XML based) with folders and the JIDs.
A basic example for a TCP based XMPP stream can look like this:
C: ='1.0'
<stream:stream
to='example.com'
xmlns='jabber:client'
xmlns:stream='http://etherx.jabber.org/streams'
version='1.0'>
S: ='1.0'
<stream:stream
from='example.com'
id='someid'
xmlns='jabber:client'
xmlns:stream='http://etherx.jabber.org/streams'
version='1.0'>
... encryption, authentication, and resource binding ...
C: <message from='juliet@example.com'
to='romeo@example.net'
xml:lang='en'>
C: <body>Art thou not Romeo, and a Montague?</body>
C: </message>
S: <message from='romeo@example.net'
to='juliet@example.com'
xml:lang='en'>
S: <body>Neither, fair saint, if either thee dislike.</body>
S: </message>
C: </stream:stream>
S: </stream:stream>
Where C
is the Client and S
is the Server. This example is taken from here.
As an open and standardized protocol, there are plenty of libraries for different programming languages and operating systems available. As I was looking for a C# library, I found the agsXMPP
library dealing with the most important tasks like Jabber Client or even Jabber Server development. The agsXMPP
is provided under two licenses, the GPL for open source project, and a commercial license for closed source projects.
To get started with the agsXMPP
library, you can download the SDK here.
For more detailed information about Jabber/XMPP, you should have a look here and here and here.
Jabber Client
This example application is just a demonstration of how to create a Jabber Client; it does not store any connection data or provide creation of a new account. So if you would like to use the code to develop a real world client, you will have to add some more functionality to the code.
So now we are prepared to develop our own Jabber Client. For this example, I have chosen a Console Application, because it makes the code more readable. As the agsXMPP
library provides a lot of events to handle several functionalities that do not make a Console Application the first choice, I think a Windows Forms Application would make it all a little bit confusing on the first view.
So what are the goals of this example application?
- Create a connection to a Jabber server and authenticate the Jabber user
- Send the users presence over to the server
- Handle the presence of the contacts in our Roster (receive all available contacts)
- Last but not least, the chatting functionality (sending and receiving chat messages)
So let's start.
References
To use the agsXMPP
in your own project, you have to add a reference to agsXMPP.dll in your project. For this example, you should also add the following using
directives to the header:
using agsXMPP;
using agsXMPP.protocol.client;
using agsXMPP.Collections;
using agsXMPP.protocol.iq.roster;
using System.Threading;
Connection and Authentication
To connect to a Jabber server, we need a JID (Jabber ID) and the corresponding password. At first, we have to create a new JID
object with the user's JID as a string parameter. After that, we can create a new XmppClientConnection
object with the JID server property of the JID
object as a constructor parameter. The code looks like this:
Console.WriteLine("Login");
Console.WriteLine();
Console.WriteLine("JID: ");
string JID_Sender = Console.ReadLine();
Console.WriteLine("Password: ");
string Password = Console.ReadLine();
Jid jidSender = new Jid(JID_Sender);
XmppClientConnection xmpp = new XmppClientConnection(jidSender.Server);
Now we have to open the connection and wait until we are connected and authenticated. In the agsXMPP
library, the XmppClientConnection.Open()
method is executed asynchronously, so we have to register the OnLogin
Eventhandler and wait until the OnLogin
event is raised. This is a beautiful solution for a Win App, but it makes a Console App not so beautiful. The code should look like this:
xmpp.Open(jidSender.User, Password);
xmpp.OnLogin += new ObjectHandler(xmpp_OnLogin);
I solved the wait for OnLogin
to be raised by a simple do
loop, I know there are more pretty solutions, but it just does what it should do:
Console.Write("Wait for Login ");
_wait = true;
do
{
Console.Write(".");
i++;
if (i == 10)
_wait = false;
Thread.Sleep(500);
} while (_wait);
So now we have to take a look at the xmpp_OnLogin
method:
static void xmpp_OnLogin(object sender)
{
_wait = false;
Console.WriteLine("Logged In");
}
We are just waiting until the OnLogin
event is raised (which means we are logged in and authenticated) and then exit the loop to continue our program. Now we can get some information about the Connection and Authentication state of our XmppClientConnection
object:
Console.WriteLine("xmpp Connection State {0}", xmpp.XmppConnectionState);
Console.WriteLine("xmpp Authenticated? {0}", xmpp.Authenticated);
Sending the Presence
To show our Roster members we are online, we have to send our presence to the server. This little task works like this:
Presence p = new Presence(ShowType.chat, "Online");
p.Type = PresenceType.available;
xmpp.Send(p);
Now they can see in their Roster that we are online and available for chat (this task is necessary to receive the presence of our Roster members).
Receiving the Presence of our Roster Members
To receive the presence of our Roster members we have to register the OnPresence
Eventhandler:
xmpp.OnPresence += new PresenceHandler(xmpp_OnPresence);
Now we have to wait until the event is raised (it is raised now, and if the presence of a Roster member is changed). Attention: we can only see the Roster members where presence type is available.
static void xmpp_OnPresence(object sender, Presence pres)
{
Console.WriteLine("Available Contacts: ");
Console.WriteLine(<a href="mailto:%7B0%7D@%7B1%7D%20%20%7B2%7D">{0}@{1} {2}</a>,
pres.From.User,pres.From.Server,pres.Type);
Console.WriteLine();
}
Sending and Receiving Messages
Now we can start with the most interesting part: Chatting! How does chatting work basically? We send messages to an available chat partner (we need his JID), and we handle received messages in a MessageCallBack
method. To prepare for incoming messages, we have to execute the following statement:
xmpp.MesagageGrabber.Add(new Jid(JID_Receiver),
new BareJidComparer(), new MessageCB(MessageCallBack), null);
Now the MessageCallBack
method is executed if a new message arrives:
static void MessageCallBack
(object sender, agsXMPP.protocol.client.Message msg, object data)
{
if (msg.Body != null)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("{0}>> {1}", msg.From.User, msg.Body);
Console.ForegroundColor = ConsoleColor.Green;
}
}
Sending messages is quite an easy task:
xmpp.Send(new Message(new Jid(JID_Receiver), MessageType.chat, outMessage));
where the JID_Receiver
is the JID
object of our chat buddy. This code should be packed into a loop, to send more than one message (in the download example I have put it into a do
loop, with the string q!
as the exit criteria). When you are finished, you just need to close the XmppClientConnection
object:
xmpp.Close();
Chat
That is all there is to creating a little Jabber Chat Client which looks like this:
The corresponding screenshots of my chat partner using PSI:
Summary
There are plenty more features of Jabber/XMPP provided in the agsXMPP
library, like creating your own Jabber server or creating your own packages. I think for an entry into Jabber development under C#, it is best to start with client development. The agsXMPP
SDK provides a few very detailed examples like a Windows based mini client and a server component. If you would like to dive deeper into this technology, I suggest you study these examples before you dive into the libraries' source code.