---
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](http://home.gna.org/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?](http://xmpp4r-simple.rubyforge.org/)". 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.get_roster()
roster.wait_for_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.add_presence_callback do |roster_item, old_presence, new_presence|
  puts "Somebody changed his/her state to " + new_presence.status.to_s
  # new_presence 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.add_presence_callback, 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.add_presence_callback 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.
