Couldn't find a script to update my Jabber/XMPP vCard photo (a/k/a avatar), so I wrote one. It requires xmpppy (a/k/a python-xmpp). It should work with gTalk, but I have not tested it.
Credit to pastebin for some code snippets.
Hope this saves someone some time and effort.
#!/usr/bin/python
'''vcard.py - Update your XMPP vcard photo with the image you provide
Usage: vcard.py image_file jid password
'''
from xmpp import JID, Client, Iq, Presence, NS_VERSION, NS_VCARD
import sys
import os
import time
from base64 import encode, decode
from hashlib import sha1
try:
file=os.path.expanduser(sys.argv[1])
jid=sys.argv[2]
password=sys.argv[3]
resource='vcard'
except:
print >>sys.stderr, __doc__
sys.exit(2)
NS_VCARD_UPDATE = 'vcard-temp:x:update'
NS_NICK = 'http://jabber.org/protocol/nick'
def hash_img(img):
return sha1(img).hexdigest()
def base64_img(img):
return img.encode('base64')
def get_img(file):
try:
os.stat(file)[6]
fh = open(file, 'rb')
img = fh.read()
return img
except Exception, e:
print >>sys.stderr, e
sys.exit(2)
def get_mime_type(file):
try:
ext = file[-4:]
if ext == '.png':
mime_type = 'image/png'
elif ext == '.gif':
mime_type = 'image/gif'
elif ext == '.jpg' or ext == '.jpeg':
mime_type = 'image/jpeg'
else:
raise ValueError, "Wrong mime-type detected. Check file suffix."
except ValueError, e:
print >>sys.stderr, e
sys.exit(2)
return mime_type
def send_vcard(conn, base64_img, mime_type, nick):
iq_vcard = Iq(typ='set')
vcard = iq_vcard.addChild(name='vCard', namespace=NS_VCARD)
vcard.addChild(name='NICKNAME', payload=[nick])
photo = vcard.addChild(name='PHOTO')
photo.setTagData(tag='TYPE', val=mime_type)
photo.setTagData(tag='BINVAL', val=base64_img)
conn.send(iq_vcard)
def send_presence(conn, status, hash1, nick):
presence = Presence(status = status, show = 'xa', priority = '-1')
presence.setTag(name='x',namespace=NS_VCARD_UPDATE).setTag(name='photo',namespace=NS_VCARD_UPDATE).setData(hash1)
presence.setTag(name='nick',namespace=NS_NICK).setData(nick)
conn.send(presence)
if __name__ == '__main__':
img = get_img(file)
j=JID(jid)
cl=Client(j.getDomain(),debug=[])
conn=cl.connect()
if not conn:
raise Exception, 'failed to start connection'
auth=cl.auth(j.getNode(),password,resource,sasl=1)
if not auth:
raise Exception, 'could not authenticate'
send_vcard(cl, base64_img(img), get_mime_type(file), j.getNode())
send_presence(cl, 'Updated vCard Image', hash_img(img), j.getNode())
time.sleep(1)
cl.disconnect()
Hi there,
I was just testing out your code, but for some reason it doesn’t work for me.
I understand that you pass the variables through the command prompt but it doesn’t recognize my file and I tried hard coding the file extension and user name, etc into the code and it says ‘permission denied’. Any ideas why that would be? I am a newbie to XMPP and just discovered the VCARD, I wanted to use the avatar.
Should I be naming the image file vcard? Because I have tried that too.
Any help is appreciated,
Thanks,
Needz
Two possibilities come to mind: (1) the python script is not executable — remember to run “chmod 755 vcard.py” (2) you (or more specifically, the script) don’t have permission to read the image file — try making the image file world readable with chmod 644.
Thanks for replying, but I am not using Linux. I run “python vcard.py …………” and then the variables and that is when I get the error. I am actually using windows vista. Could it be something to do with this line:
“file=os.path.expanduser(sys.argv[1])”
Perhaps I am passing something wrongly here?
What do you think?
Oh. Vista. Can’t help you there — I don’t have Python installed on a Vista machine. I would imagine that the User Account Controls could be a possible culprit. Or the line you mentioned. Have you tried hard-coding the filename in lieu of sys.argv[1]?
Cool. I wrote a similar one that downloads other people’s instead of updating your own. Nice to know you can go the other direction too.
http://collincode.wordpress.com/2009/01/31/xmpp-jabber-photo-module-2/
Yes, I have hard-coded it, and have had to make a few changes. That problem does not occur anymore.
I have been debugging and for some reason it will only accept a png file, strange, but now the problem is the following:
“””
Traceback (most recent call last):
File “C:\Users\Nida\Documents\CMPT 275\vcard.py”, line 86, in
send_presence(cl, ‘Updated vCard Image’, hash_img(img), j.getNode())
File “C:\Users\Nida\Documents\CMPT 275\vcard.py”, line 71, in send_presence
conn.send(presence)
File “C:\Python26\lib\site-packages\xmpppy-0.5.0rc1-py2.6.egg\xmpp\dispatcher.py”, line 367, in send
self._owner_send(stanza)
File “C:\Python26\lib\site-packages\xmpppy-0.5.0rc1-py2.6.egg\xmpp\transports.py”, line 195, in send
self._owner.disconnected()
File “C:\Python26\lib\site-packages\xmpppy-0.5.0rc1-py2.6.egg\xmpp\client.py”, line 129, in disconnected
for i in self.disconnect_handlers: i()
File “C:\Python26\lib\site-packages\xmpppy-0.5.0rc1-py2.6.egg\xmpp\client.py”, line 137, in DisconnectHandler
raise IOError(‘Disconnected from server.’)
IOError: Disconnected from server.
“””
I guess it now has a problem with conn.send(presence), I have to do some more debugging before I can fully understand why this is happening.
Any ideas?
I have realized that by simply switching the order of these two statements:
” send_vcard(cl, base64_img(img), get_mime_type(file), j.getNode())
send_presence(cl, ‘Updated vCard Image’, hash_img(img), j.getNode())
”
The code will run smoothly and update the vcard photo on jabber accounts.
However it does not work for gmail accounts. For gmail, the log in process is a little different, and when I do that, it doesn’t work anymore. Does gmail support Vcards?
I did notice a typo on the get_mime_type function, but as for gmail, like I said, I don’t know if it works. Sounds like maybe not. Google Talk certainly supports vcard avatars, but maybe you can’t set it from outside the GMail or Google Talk service.