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
Setting An Avatar/Buddy Icon With Ruby's XMPP4R API
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: http://nocompile.blogspot.com/2008/06/setting-avatar-with-rubys-xmpp4r-api.html
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 = Jabber::Client.new(Jabber::JID.new(user))
@client.connect
@client.auth(pass)
# send initial presence to let the server know you are ready for messages
@client.send(Jabber::Presence::new)
# 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
Thread.new do
vcard = Jabber::Vcard::IqVcard.new
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 = File.new("buddy.png", "r")
# Base64 encode the file contents
image_b64 = Base64.b64encode(image_file.read())
# 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(image_file.read())
vcard["PHOTO/BINVAL"] = image_b64 # set the BINVAL to the Base64 encoded contents of our image
begin
# create a vcard helper and immediately set the vcard info
vcard_helper = Jabber::Vcard::Helper.new(@client).set(vcard)
rescue
# very simple error "logging" if you can call it that
puts "#{Time.now} vcard operation timed out."
end
end
# just a 'keepalive' thread to keep the jabber server in touch
# sends a presence entity every 30 seconds
Thread.new 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 http://www.xmpp.org/extensions/xep-0153.html
x = REXML::Element::new("x")
x.add_namespace('vcard-temp:x:update')
photo = REXML::Element::new("photo")
# this is the avatar hash as computed in the vcard thread above
avatar_hash = REXML::Text.new(avatar_sha1)
# add text to photo
photo.add(avatar_hash)
# add photo to x
x.add(photo)
# add x to presence
pres.add_element(x)
end
# send presence entity
@client.send(pres)
sleep 30
end # end 'keepalive'
end # initialize
end
# the most barebones basic way to run this code
bot = JabberBot.new('username@jabber.server', 'password')
while true do
end





