verse logo

Introduction

<Verse> is a <Jabber>/<XMPP> library for <Lua>. It is based on the C version of the <strophe> library.

One handy feature of verse is that only the core protocol is implemented by default. Extensions to the protocol (either <XEPs>, or custom-made protocols) can be 'described', and then used by any verse application. It is the developer's intention to include support for as many <XEPs> as possible with verse, any number of which can be optionally loaded by the application when initialising the library.

For more information, or to give comments, feedback, bug reports and kind words, contact: me (at) matthewwild.co.uk

Initialising the library

First things first,

			require 'verse'

That was easy :)

Making a connection

Verse makes extensive use of handlers to provide notification of events. Every application will have at least one handler... the connection handler. This function gets called when the application gets connected (or disconnected) to/from the server.

			-- An example connection handler
			function conn_handler(e)
				print("Connected!");
			end
		

As you can see, this is a straightforward Lua function. The single parameter 'e' (you can call it whatever you like) is a table containing various information about the connection. More on this later.

Once you have your connection handler, you need a connection. Getting this is easy, just call:

			conn = verse.connect("juliet@capulet.lit/balcony", "iheartromeo", conn_handler);
		

As you can see this takes the JID (with or without a resource), a password, and the connection handler.A fourth, optional, parameter allows you to specify a server to connect directly to. For example "talk.google.com" for gmail users. This will not be necessary when strophe gains support for SRV records.

One last thing after calling connect()... we need to tell verse to start listening to the connection:

			verse.run();
		

You now have all you need to make a connection. Run the script, and you should see the text "Connected!" come from your connection handler. Nice work :)

Sending presence

Presence is a large part of XMPP. Presence is what tells others on the network when you are online, and in what state (online, away from computer, do not disturb, "Gone to lunch!", etc.).

The first thing to do after signing in is to publish your initial presence. This couldn't be easier. In the connection handler, put a line:

			verse.presence():send(e.conn);
		

Told ya' it was easy! Lets take a look at what this actually does though.

Data in XMPP is relayed in snippets of XML, known as 'stanzas'. There are 3 main types of stanza; presence, message, and iq. Each one has a from, a to, and an id attribute, also often a type. The one you just sent looked like this:

			<presence/>
			
		

Yep, that's it. You see no to attribute, so this went just to your server (which will then broadcast to your contacts on your behalf). We also set our status to available, which is the default status. An example of a presence stanza with additional information:

			<presence>
				<show>away</show>
			</presence>
			
		

This will show other people on your contact list that you are away. That's great, but how do we incorporate this into our original code? Simple:

			verse.presence()
				:tag("show") -- Adds a child tag of the <presence> called <show>,
					:text("away") -- Adds some text to the <show> tag
				:send(e.conn);
		

Ok, we've covered the basics, and you probably want to get on and do your own stuff, so let me just finish off with introducing you to the tools to craft your own stanzas from scratch.

Stanza constructors

Verse provides a multitude of ways to create and manipulate stanzas. It has constructors for the three stanza types, plus some generic ones for adding custom elements to stanzas.

verse.presence()

table/attributes:Attributes of the stanza

Creates and returns a presence stanza, with the specified (if any) attributes.

verse.message()

table/attributes:Attributes of the stanza

Creates and returns a message stanza, with the specified (if any) attributes.

verse.iq()

table/attributes:Attributes of the stanza

Creates and returns an iq stanza.

Additional stanza constructors and helpers

These stanza methods allow you to insert new child elements and easily create custom stanzas. See below for the "Building stanzas" section for more information.

:query()

string/xmlns:XMLNS of the the IQ |payload|.

Inserts into the stanza a <query> element tagged with the specified namespace.

:tag()

string/name:Name of the tag
string/attributes:A table specifying attributes for the tag.

Inserts into the stanza a new element with the specified name and attributes.

:text()

string/text:A text string

Inserts into the stanza a text node.

:up()

A helper function to step up the tree when building a stanza. See the "Building stanzas" section for more info and examples.

Building stanzas

Given the tools described above, it should be possible to craft any XML stanza you need. Some examples are given below.

Example 1: A software version request

			<iq 
			    type='get' 
			    to='juliet@capulet.com/balcony' id='version_1'>
				<query xmlns='jabber:iq:version'/>
			</iq>
		
		

In Lua code using verse, this would be:

			verse.iq{ to = "juliet@capulet.com/balcony", type = "get" }
				:query("jabber:iq:version")
		

Example 2: On the phone presence

			<presence to="romeo@montague.lit" type="available">
				<show>away</show>
				<status>on the phone</status>
			</presence>
		
		

would be generated with...

			verse.presence{ to = "romeo@matague.lit", type = "available" }
				:tag("show"):text("away"):up()
				:tag("status"):text("on the phone")
		

Here you see an example of the up() method, which is required to step back up the tree, for when you want to add adjacent tags. For example, without it, <status> would have ended up a child of <show>

Using protocol extensions

It's all very well being able to easily build XML from the ground up, but that can get tedious for common tasks after a while. This is why verse supports add-on modules, for protocol extensions.

As an example, a module could implement code for XEP-0045 Multi-User Chat. It would then supply new functions for performing common MUC operations (joining, leaving, kicking, banning).

In addition to making it easier to *send* stanzas, extension modules are also able to define 'events'. The module may supply a list of rules, and when an incoming stanza matches that rule, the associated event will be 'fired'. It is possible to associate handler functions with events, so your code can catch and react to these events.

An example below shows full code to publish and retrieve XEP-0118 User Tune announcements:

			require 'verse'
			require 'verse.XEP0118'
			function conn_handler(e)
				verse.XEP0118.publish{ artist = "Big Bird and Friends", title = "Sesame Street Theme" }:send(e.conn);
				verse.XEP0118.request_last{ to = "friend@example.com" }:send(e.conn); -- Request friend's current music
			end
			
			function tune_handler(e, tune)
				print(tune.from.." is listening to '"..(tune.title or "some music").."' by '"..(tune.artist or "someone").."'");
			end
			
			-- Associate our tune_handler function with XEP0118's "response" event...
			verse.hook_event("XEP0118", "response", tune_handler);
			
			-- Finally, connect and run...
			conn = verse.connect("me@example.com", "youllneverguess", conn_handler);
			verse.run();