Writing a command line XMPP bot (echobot) using Jaxl 2.0

In this blog post, we will write a sample XMPP bot (echobot) using Jaxl 2.0. In turn we will introduce ourselves to some of the basic functionality we can do using Jaxl e.g. fetching roster list, subscribing and unsubscribing to a user presence, etc. We will also focus on how to use XMPP extensions (XEP’s) inside our echobot code. Specifically, we will make use of XEP-0085 (chat state notification), XEP-0203 (delayed delivery) and XEP-0092 (software version) in our sample echobot application.

Echobot source code:
This sample echobot application comes packaged with Jaxl 2.0. If you have already read Installation, Usage guide and Running example apps, you might have even run this sample application.

Alternately, browse and download the sample source code from github echobot app files

Coding with Jaxl 2.0:
Every XMPP application developed using Jaxl 2.0, MUST have a jaxl.ini environment setup file inside your project directory. For example, packaged echobot sample application contains jaxl.ini which setup necessary Jaxl environment for our echobot application.

If you are developing an application from scratch, copy sample packaged jaxl.ini into your project folder:

cp /usr/share/php/jaxl/env/jaxl.ini /my/app/directory/jaxl.ini

and update JAXL_BASE_PATH and JAXL_APP_BASE_PATH with Jaxl installation path and your application directory path respectively.

Before we go on to write our echobot application code logic, lets see how an XMPP application code written using Jaxl 2.0 will generally look like:

<?php

        // Initialize Jaxl Library (#1)
        $jaxl = new JAXL();

        // Include required XEP's (#2)
        jaxl_require(array(
                'JAXL0085', // Chat State Notification
                'JAXL0092', // Software Version
                'JAXL0203'  // Delayed Delivery
        ), $jaxl);

        // Sample Echobot class (#3)
        class echobot {
                function startStream() {}
                function doAuth($mechanism) {}
                function postAuth() {}
                function getMessage($payloads) {}
                function getPresence($payloads) {}
        }
        $echobot = new echobot();

        // Add callbacks on various xmpp events (#4)
        JAXLPlugin::add('jaxl_post_connect', array($echobot, 'startStream'));
        JAXLPlugin::add('jaxl_get_auth_mech', array($echobot, 'doAuth'));
        JAXLPlugin::add('jaxl_post_auth', array($echobot, 'postAuth'));
        JAXLPlugin::add('jaxl_get_message', array($echobot, 'getMessage'));
        JAXLPlugin::add('jaxl_get_presence', array($echobot, 'getPresence'));

?>

Lets break down the above applications code structure (note the #1, #2, #3, #4 markers in the above code)

  • #1 – Create a new Jaxl instance inside your application. By doing so Jaxl core functionality and other utilities are made available inside your application code. You can also pass parameters while initializing Jaxl instance
    $jaxl = new JAXL(array(
            'user'    =>    'username',
            'pass'    =>    'password',
            'host'    =>    'talk.google.com',
            'domain' =>    'gmail.com',
            'port'    =>    5222
    ));

    Passed parameters will overwrite the values specified inside jaxl.ini file

  • #2 – Include required XMPP extensions (XEP’s) inside your application code. jaxl_require is a special method which makes sure that no Jaxl core class loads twice inside a running Jaxl instance.

    To include an implemented XEP inside your application code simply use:

    jaxl_require('JAXL0203', $jaxl);

    where 0203 is the XEP number for Delayed Delivery extension, which will help our echobot know if an incoming message is an offline message. If you wish to include more than one XEP inside your application code, simply pass the list of XEP’s as an array:

    jaxl_require(array(
    	'JAXL0085',
    	'JAXL0092',
    	'JAXL0203'
    ), $jaxl);

    where 0085 is xep number for Chat state notification extension and 0092 is the xep number for Software Version extension.

    Since version 2.1.0, jaxl_require MANDOTORY accepts Jaxl instance which require core classes, in this case $jaxl. It helps Jaxl core to keep a track of required core classes for every Jaxl instances in a multiple-instance application.

  • #3 – Now that we have Jaxl core and required XEP’s in our application environment, it’s time to write our application code logic. Application code MUST have methods which are called back by the Jaxl core when specific xmpp events occur during your application run time. Optionally, Jaxl core can pass parameters to these methods during callbacks.
  • #4 – In the final step, we will register callbacks for necessary xmpp events using JAXLPlugin class add() method inside our application logic. Syntax:
    JAXLPlugin::add($hook, $callback);

    In this example, we want to receive callbacks in our application code for following available hooks and events:

    1. jaxl_post_connect: After Jaxl has opened stream socket to the jabber server
    2. jaxl_get_auth_mech: When Jaxl have information about supported auth mechanisms by the jabber server
    3. jaxl_post_auth: After Jaxl finish authenticating the bot with the jabber server
    4. jaxl_get_message: When a new message stanza is received by Jaxl
    5. jaxl_get_presence: When a new presence stanza is received by Jaxl

Writing application logic:
Till now we have the registered callbacks for various xmpp events, it’s time to catch these callbacks inside our echobot class and implement the required functionality of our application. Below is an explanation for some of the important pieces inside echobot class:

  • startStream() method is called when jaxl_post_connect event occurs. For our application we will simply send XMPP start stream by calling $jaxl->startStream()
  • doAuth($mechanism) method is called when jaxl_get_auth_mech event occurs in Jaxl core. Jaxl core passes list of supported auth mechanism by the jabber server. Proceed with a preferred auth type by calling $jaxl->auth() method
  • postAuth() is called after Jaxl library has finished authenticating our application bot with the jabber server
  • getMessage($payloads) gets all new messages as they are received by Jaxl core
  • getPresence($payloads) gets all new presence as they are received by Jaxl core

Running Echobot:
Enter your application directory (/usr/share/php/jaxl/echobot). It MUST contain jaxl.ini, open and edit connecting echobot username, password and jabber host. Then from command line run echobot as follows:

root@ubuntu:/usr/share/pear/jaxl/app/echobot# jaxl echobot.php
== 5617 == [[2010-08-03 10:37:21]] Socket opened to the jabber host jaxl.im:5222 ...
== 5617 == [[2010-08-03 10:37:22]] Performing Auth type: DIGEST-MD5
== 5617 == [[2010-08-03 10:37:28]] Auth completed...