Structure of a client-side xmpp4moz application

Whether you are developing a scriptlet, an extension, or a full-blown XUL application, the XMPP-related code you are going to write will probably have the same basic structure:

  1. Making xmpp4moz available to your code
  2. Sending out XMPP stanzas
  3. Listening to XMPP events
  4. Selecting and reacting to XMPP events
  5. (Optional) Connecting/disconnecting accounts
  6. (Optional) Synchronizing with existing state

Making xmpp4moz available to your code

First, you have to grab the XMPP object. This will be available by default to scriptlets. For extensions and XUL applications, write the following in your XUL main file or overlay:

<script type="application/x-javascript" src="chrome://xmpp4moz/content/xmpp.js"/>

Sending out XMPP stanzas

To send a message stanza to contact@server.org using the account foo@bar.org/SamePlace:

XMPP.send('foo@bar.org/SamePlace',
          <message to="contact@server.org"><body>hello!</body></message>);

Listening to XMPP events

To listen to XMPP events, you need a channel. You'll usually create this in the onload handler of the application or extension, and release it in the onunload handler:

Example:

var channel;

function init() {
    // initialization...

    channel = XMPP.createChannel();

    // more initialization...
}

function finish() {
    // finalization...

    channel.release();
}

Selecting and reacting to XMPP events

Once you're listening to XMPP traffic, you'll want to pick a subset of it and react on certain patterns.

For example, to display every incoming message with an alert(), you can register the following listener:

function init() {
    channel = XMPP.createChannel();

    channel.on({
        event     : 'message',
        direction : 'in',
        }, function(message) {
            alert(message.stanza.body);
        });
}

To do something whenever the user sets an "away" status (and thus sends a <presence><show>away</show></presence> stanza), you can use something like this:

channel.on({
    event     : 'presence',
    direction : 'out',
    stanza    : function(s) {
        return s.show == 'away';
    }},
    function(presence) {
        onUserAway(presence);
    });
}

The above highlights a very important practice: most of the time, you don't want to react on a user interface event (such the user selecting an "away" option from a menu), but rather on the resulting XMPP event.

The reason is that there could be many ways for the user to trigger an "away" action in the UI (a menu, a button, a command line), and you cannot keep track of them all; but they all result in sending out a <presence/> stanza, so that is what you want to watch out for.

(Optional) Connecting/disconnecting accounts

Connection and disconnection is usually requested by the user through the global button in the toolbar or the Jabber menu, so you won't have to care about this. However, if you need to take control (e.g. your application is not running as a browser extension), connecting and disconnecting configured accounts is done with:

    XMPP.up(account);
    // ...
    XMPP.down(account);

To do something after a session has been brought up, provide a function as a second parameter to up():

    XMPP.up(account,
            function() {
                alert('connected!');
            });

account can be a string containing the full JID of the configured account:

    var account = 'foo@bar.org/SamePlace';
    XMPP.up(account);

It can also be an empty object, in which case the user will be prompted to select an account, and the jid property of the object will be set to the selected account afterwards:

    var account = {};
    XMPP.up(account,
            function() {
                alert('connected with ' + account.jid + '!');
            });

(Optional) Synchronizing with existing state

Since XMPP sessions are independent of applications, it may easily happen that an application is loaded when one or more session are already connected.

Applications will then have to "peek into the past" if, for example, they want to display the latest known status of user or contacts. This is done using the cache.

For example, to retrieve online contacts as soon as your application is started (note that online contacts are those who sent a <presence/> stanza with no "type" attribute):

function init() {
    // initialization ...

    var contactPresences = XMPP.cache.fetch({
        event     : 'presence',
        direction : 'in',
        stanza    : function(s) {
            return s.@type == undefined;
        }
    });

    var onlineContacts = '';
    for each(var presence in contactPresences) {
        onlineContacts += presence.stanza.@from + '\n';
    }
    alert('contacts now online:\n' + onlineContacts);
}