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)
About these ads

Tags: , , , , , , , , , , ,

11 Responses to “XMPP Jabber Photo Module”

  1. Needz Says:

    Hey there,
    Is there an easy way to use this code to update a buddy list of avatars for each buddy?
    I am a newbie to XMPP.py and am just wondering how I could understand exactly what your code does and how to use it.
    Thanks,
    Needz

  2. Needz Says:

    Thanks for the update, what your doing makes a lot more sense now. The only thing is when I try to run the code, after creating the appropriate directory, I get the following error:

    Traceback (most recent call last):
    File “C:\Users\Nida\Desktop\usePhotos.py”, line 40, in
    j.Process(1) # process for 1 second
    File “C:\Python26\lib\site-packages\xmpppy-0.5.0rc1-py2.6.egg\xmpp\dispatcher.py”, line 122, in Process
    self.Stream.Parse(data)
    File “C:\Python26\lib\site-packages\xmpppy-0.5.0rc1-py2.6.egg\xmpp\simplexml.py”, line 424, in endtag
    self.dispatch(self._mini_dom)
    File “C:\Python26\lib\site-packages\xmpppy-0.5.0rc1-py2.6.egg\xmpp\dispatcher.py”, line 293, in dispatch
    try: cb(session,stanza,**args)
    File “C:\Users\Nida\Desktop\photo.py”, line 57, in recieve_vcard
    photo = stanza.getTag(‘vCard’).getTag(‘PHOTO’)
    AttributeError: ‘NoneType’ object has no attribute ‘getTag’

    I am not sure which ‘getTag’ it is referencing! Do you think it has something do to with there being no vcard for a certain contact?

  3. Needz Says:

    Actually, when I use a jabber account to log in instead of a gmail account, it works just fine! Success. I guess there is something fishy with gmail!

    Thank-you so much for the code, it was very helpful!

  4. Needz Says:

    Thank you for that, it now works great for gmail and regular jabber accounts!

    Do you know if gmail supports Vcard updates?
    What I mean to say is, if I have code that updates a persons Vcard with a photo, will it work for gmail too? Because so far I am having issues with it. It works fine for jabber but not gmail. So I thought I’d ask if you’ve ever given it a go?

  5. Collin Anderson Says:

    I would take a look at http://yabfog.com/blog/2009/06/03/xmpp-vcard-python-script which seems to do the opposite of mine: changing your photo. It could probably change the rest of the vCard too.

  6. Needz Says:

    Thanks,
    I have managed to get that working, I do something similar to the website you suggested.
    I am wondering if you have used your code to get your own avatar?
    I am trying something like the following:
    “”"
    class MyAvatar:
    def __init__(self, presence, client, jid):
    self.jid_photo_map = {}
    self.presence = presence
    self.client = client
    self.jid = xmpp.protocol.JID(jid).getStripped()

    def retrievePhoto(self, session, stanza):
    vphoto = self.presence.getTag(‘x’, namespace = ‘vcard-temp:x:update’)
    if not vphoto:
    return
    photo = vphoto.getTag(‘photo’)
    if not photo:
    return
    photo = photo.getData()
    if not photo:
    return
    self.jid_photo_map[self.jid] = photo

    def loggedIn(self):
    self.client.RegisterHandler(‘presence’, self.retrievePhoto)
    photo.register_handler(self.client)
    return self.client

    def display(self, client):
    photo_filename = photo.get_photo(self.jid_photo_map[self.jid])
    print self.jid, photo_filename

    def getMyPhoto(self):
    j = self.loggedIn()
    for x in range(30):
    j.Process(1)
    self.display(j)
    “”"
    I can’t quite get it right. I tired to copy the same way you get other’s avatars, but this seems quite wrong!

  7. heru priadi Says:

    thanks for ur skrip

  8. Kitek Says:

    Nice job :)
    Thx!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s


Follow

Get every new post delivered to your Inbox.

%d bloggers like this: