DZone Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

Snippets has posted 5883 posts at DZone. View Full User Profile

Setting An Avatar/Buddy Icon With Ruby's XMPP4R API

  • submit to reddit
        I have been making service bots using Ruby, XMPP4R, and Jabber for some time now. I recently had someone ask if I could add a buddy icon to one of them. I had a hard time finding info on the net about doing this with XMPP4R.

After some trial and error and RFC reading, I got it to work. Here is a skeleton code listing of what I did to get it to work. This is also detailed at:

require 'rubygems'
require 'xmpp4r'
# allows me to use the vcard stuff
require 'xmpp4r/vcard'
# for encoding the buddy icon
require 'base64'

class JabberBot
  # user : Jabber ID
  # pass : Password
  def initialize(user, pass)
    # no debugging for now
    Jabber::debug = false
    # connect Jabber client to the Server
    @client =
    # send initial presence to let the server know you are ready for messages

    # set vcard info
    # this is in a thread because it waits on a server response
    # the XMPP4R docs suggest placing this code inside a thread
    avatar_sha1 = nil # this gets used later on do
      vcard =
      vcard["FN"] = "My Bot" # full name
      vcard["NICKNAME"] = "mybot" # nickname
      # buddy icon stuff
      vcard["PHOTO/TYPE"] = "image/png"
      # open buddy icon/avatar image file
      image_file ="buddy.png", "r")
      # Base64 encode the file contents
      image_b64 = Base64.b64encode(
      # process sha1 hash of photo contents
      # this is used by the presence setting
      image_file.rewind # must rewind the file to the beginning
      avatar_sha1 = Digest::SHA1.hexdigest(
      vcard["PHOTO/BINVAL"] = image_b64 # set the BINVAL to the Base64 encoded contents of our image
        # create a vcard helper and immediately set the vcard info
        vcard_helper =
        # very simple error "logging" if you can call it that
        puts "#{} vcard operation timed out." 
    # just a 'keepalive' thread to keep the jabber server in touch
    # sends a presence entity every 30 seconds do
      while true do
        # saying "I'm alive!" to the Jabber server
        pres = Jabber::Presence::new
        # according to the RFC the server expects a SHA1 hash of the avatar to be 
        # sent with subsequent presence messages
        # it wants it in the following format:
        # <presence from='username@jabber.server/ResourceName'>
        #    <x xmlns='vcard-temp:x:update'>
        #        <photo>sha1-hash-of-image</photo>
        #    </x>
        # </presence>       
        # append buddy icon/avatar info
        if not avatar_sha1.nil?
            # send the sha1 hash of the avatar to the server
            # as per the RFC
            x = REXML::Element::new("x")
            photo = REXML::Element::new("photo")
            # this is the avatar hash as computed in the vcard thread above
            avatar_hash =
            # add text to photo
            # add photo to x
            # add x to presence
        # send presence entity
        sleep 30
    end # end 'keepalive'
  end # initialize

# the most barebones basic way to run this code
bot ='username@jabber.server', 'password')

while true do