XMPP Jabber Photo Module

I was looking around for a XMPP vCard Photo Module in May of 2007, and could not find one, so I wrote my own. It uses the xmpppy python module for communicating with the jabber server. Once the connection is made with the server, call register_handler(session). It will then download avatars of people on the roster list. To get the filename of a person’s avatar, call get_photo(photo_hash).

import base64
import os
import sha
import xmpp

PHOTO_DIR = "./photos/"

PHOTO_TYPES = {
    'image/png': '.png',
    'image/jpeg': '.jpg',
    'image/gif': '.gif',
    'image/bmp': '.bmp',
    }

def append_directory(filename):
    return os.path.join(PHOTO_DIR, filename)

def register_handler(session):
    session.RegisterHandler('presence', photo_update_handler)

def photo_update_handler(session, stanza):
    JID = stanza['from'].getStripped()
    vupdate = stanza.getTag('x', namespace='vcard-temp:x:update')
    if not vupdate:
        return
    photo = vupdate.getTag('photo')
    if not photo:
        return
    photo = photo.getData()
    if not photo:
        return
    #request the photo only if we don't have it already
    if not get_photo(photo):
        request_vcard(session, JID)

def get_photo(photo_hash):
    for ext in PHOTO_TYPES.values():
        filepath = append_directory(photo_hash + ext)
        if os.path.exists(filepath):
            return filepath

def request_vcard(session, JID):
    n = xmpp.Node('vCard', attrs={'xmlns': xmpp.NS_VCARD})
    iq = xmpp.Protocol('iq', JID, 'get', payload=[n])
    return session.SendAndCallForResponse(iq, recieve_vcard)

def recieve_vcard(session, stanza):
    photo = stanza.getTag('vCard').getTag('PHOTO')
    if not photo:
        return
    photo_type = photo.getTag('TYPE').getData()
    photo_bin = photo.getTag('BINVAL').getData()
    photo_bin = base64.b64decode(photo_bin)
    ext = PHOTO_TYPES[photo_type]
    photo_hash = sha.new()
    photo_hash.update(photo_bin)
    photo_hash = photo_hash.hexdigest()
    filename = append_directory(photo_hash + ext)
    file(filename, 'wb').write(photo_bin)

UPDATE 7/20/09
Here is roughly how I would solve the use case in the comment. I realize that my code doesn’t solve that case very nicely. If it made this more object oriented I could solve that problem. Until then, here is some rough code that I think does what it needs to. Save the above code as photo.py and be sure to create a “photos” directory

import xmpp
import photo

jid_photo_map = {}

def receive_presence(session, stanza):
    jid = stanza['from'].getStripped()
    vupdate = stanza.getTag('x', namespace='vcard-temp:x:update')
    if not vupdate:
        return
    photo = vupdate.getTag('photo')
    if not photo:
        return
    photo = photo.getData()
    if not photo:
        return
    jid_photo_map[jid] = photo

def login(username, password):
    jabber = xmpp.Client('gmail.com')
    jabber.connect(server=('talk.google.com', 5223))
    jabber.auth(username, password, 'test_client')
    jabber.sendInitPresence()
    jabber.RegisterHandler('presence', receive_presence)
    photo.register_handler(jabber)
    return jabber

def display_filenames(j):
    roster = j.getRoster()
    for jid in roster.getItems():
        if jid in jid_photo_map:
            photo_filename = photo.get_photo(jid_photo_map[jid])
        else:
            photo_filename = ""
        print jid, photo_filename

if __name__ == '__main__':
    j = login('username', 'password')
    for x in range(30):
        j.Process(1) # process for 1 second
    display_filenames(j)
Advertisements