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)
Tags: avatar, gchat, google, gtalk, jabber, photo, picture, python, talk, vCard, xmpp, xmpppy
July 19, 2009 at 11:18 pm |
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
July 20, 2009 at 6:48 pm |
I updated the post with some example code. Let me know if that helps.
July 21, 2009 at 3:02 pm |
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?
July 21, 2009 at 6:28 pm |
Right. I knew there was a change that I made recently. This happens when someone has a vCard, but no photo. I updated the code to handle this case.
July 21, 2009 at 3:11 pm |
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!
July 21, 2009 at 10:58 pm |
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?
July 22, 2009 at 6:06 am |
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.
July 25, 2009 at 12:06 am |
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!
July 27, 2009 at 7:40 pm |
I’ve actually never done this before, so I don’t know if it is possible or not.
July 13, 2010 at 9:16 pm |
thanks for ur skrip
January 20, 2012 at 7:03 am |
Nice job :)
Thx!