layout: post title: "XMPP4R: Get client's complete roster the right way" date: 2013-03-25 00:28 comments: true categories: [ruby, jabber] cover: /images/cover/avatar.png keywords: ruby, jabber, xmpp, xmpp4r, roster, client, xmpp4r-simple

description: Fetch roster from jabber server

Connect to Jabber. With XMPP4R, a library for Ruby, it is possible, but not as easy as you could think.

One could ask "Why don't you use xmpp4r-simple?". My answer: "I'm not a pussy!".

There are many little bastards you should know before fetching client's roster with contacts' vcard (nickname, full name, avatar, ...), status (online, away, ...) or status message. This is how I do this task. It works flawlessly.

This is simplified code I use in my chat application. Reading comments might be helpful.

{% codeblock lang:ruby %}

Enable to see requests and responses between your machine and your jabber

server (easy to read XML). Recommended.

Jabber::debug = true

first, sign in to your jabber account with your Jabber ID and password

client = Jabber::Client.new("someuser@somejabberserver.tld") client.connect() client.auth("my password")

now we are authenticated, let's fetch roster with all information we want

initialize roster

roster = Jabber::Roster::Helper.new(client)

request roster from jabber server, wait for response

roster.getroster() roster.waitfor_roster()

now we know your friends' Jabber Ids

roster.items.each do |jid, contact| puts "In roster I have: " + jid end

we don't know their status and status message, let's do it

First, add presence callback. If anyone in roster change his/her state

(e.g. come online), you will know it.

roster.addpresencecallback do |rosteritem, oldpresence, newpresence| puts "Somebody changed his/her state to " + newpresence.status.tos # newpresence also offers status message and other stuff end

To start receiving presence messages from your jabber server, you have to

send your presence first. It's really important to send your presence

AFTER roster.addpresencecallback, because the callback will not catch

every presence message which your jabber server sent to you.

client.send(Jabber::Presence.new.set_type(:available))

Now you know who is online in your roster. If somebody from your

roster won't be caught in roster.addpresencecallback block, then

it just means he/she is offline.

get vcard

roster.items.each do |jid, contact| # According to documentation, fetching vcard can take longer time. # Use threads if you think it is a good idea. Thread.new do vcard = Jabber::Vcard::Helper.get(client, jid) nickname = vcard && vcard["FN"] || '' #get avatar or other information here end end {% endcodeblock %}

What I've learned from using XMPP4R library in my project -- callbacks are good thing and use them.