intertwingly

It’s just data

Personal Jabber Server


The following started out as an exploration of erlang, but the side trip has proven interesting enough to merit its own entry.  Accordingly, here are notes regarding the installation of a personal (or “workgroup”, if you prefer) Jabber server on a home LAN.  Beware, specific user and host names are filled in, as well as a dummy password; adjust as required.

To start:

sudo apt-get install ejabberd
sudo chown rubys:rubys .erlang.cookie

The first command installs the server.  The second command is quite optional, but may be helpful later if you experiment with erlang.  The plus side of installing this way is that the installation is standard and will be kept up to date with the distribution.  The downside is that the initial install wizard that comes with ejabberd isn’t run, so three small configuration steps are required.

First, sudo vi /etc/ejabberd/ejabberd.cfg.

Now uncomment out one of the administrators, and set it to your preferred user id:

%{acl, admin, {user, "aleksey"}}.
{acl, admin, {user, "rubys"}}.

Next, the default setup will insert what this machine knows itself by into the configuration, but what you actually want is what other machines on this LAN know this machine as, so make the following change:

{hosts, ["localhost"]}.
{hosts, ["rubix"]}.

Now, write and exit that configuration file, restart the server, and add your user:

sudo /etc/init.d/ejabberd restart
sudo ejabberdctl register rubys rubix password

You can now perform administration functions from any machine on your LAN thus:

http://rubix:5280/admin/
user: rubys@rubix
password: password

Configuring GAIM/Pidgin

Adding the account couldn’t be easier.  Accounts, Add/Edit, Add:

Protocol:Jabber
Screen name:rubys
Server:rubix
Resource:Laptop
Password:password

At this point, you can receive messages or add buddies.

Command line client

sendxmpp is a command line client (written in Perl).  Install it, and configure your default user, server, and password information:

apt-get install sendxmpp
vi ~/.sendxmpprc
rubys@rubix password
:x
chmod 0600 .sendxmpprc

You can now send messages to yourself via:

echo -n hi | sendxmpp -r echocmd rubys@rubix

Ruby library

While Jabber (the protocol) allows Jabber IDs to be used by multiple resources (/Laptop and /echocmd are examples above), I couldn’t get this to work with the “simple” Ruby and Python libraries.  No problem: since this is your server, creating new IDs are a piece of cake:

sudo ejabberdctl register george rubix password

Note: the first time you receive a message from any new Jabber ID, you will need to confirm it in your GAIM window.

Now install xmpp4r-simple:

sudo apt-get install libxmpp4r-ruby1.8 libopenssl-ruby
sudo gem install xmpp4r-simple

You can now send yourself a message from irb:

require 'rubygems'
require 'xmpp4r-simple'
jabber = Jabber::Simple.new('george@rubix','password')
jabber.deliver('rubys@rubix','hello world')
jabber.disconnect

Note: if this is a program, a sleep 1 before the disconnect is handy, otherwise the message may be lost.

Python client

Install python-xmpp:

sudo apt-get install python-xmpp python-dns

Here’s it in action:

import xmpp
jid=xmpp.protocol.JID('george@rubix')
cl=xmpp.Client(jid.getDomain(),debug=[])
cl.connect()
cl.auth(jid.getNode(),'password')
cl.send(xmpp.protocol.Message('rubys@rubix','hi there'))
cl.disconnect()

Uses

At the moment, I’m primarily using this for “best effort delivery” of notification of events for various background processes I have running.  If I’m not online, ejabberd will apparently queue up the messages.  Being able to send these messages from the command line, Python, or Ruby makes integration easy.  Of course, there are plenty of other libraries spanning most of the popular languages.  And anything available to these languages, are accessible via ssh or CGI or any other means you may have set up to tunnel into your LAN from the outside.

For example, Planet Intertwingly reflects my predilection for Atom 1.0 feeds.  At first, I periodically spot checked feeds.  Then I produced a template which produces a report every time the page is generated.  Now I’ve completely automated the check so that I’m notified if any of the feeds is ever replaced by a feed of another flavor by the following small script:

require 'rexml/document'
require 'rubygems'
require 'xmpp4r-simple'

VALIDATE = '/home/rubys/public_html/planet/validate.html'

jabber = nil

doc = REXML::Document.new(open(VALIDATE))
REXML::XPath.match(doc,'//tr[td[3] != "atom10"]').each do |tr|
  jabber = Jabber::Simple.new('planet@rubix','password') unless jabber
  message = "#{tr.elements['td[3]'].text}: #{tr.elements['td[2]/a'].text}"
  jabber.deliver 'rubys@rubix', message
end

sleep 2; jabber.disconnect if jabber

Another use that I haven’t explored yet: jabber-bots.