XMPP vCard Python Script

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()

8 thoughts on “XMPP vCard Python Script

  1. 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

  2. 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.

  3. 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?

  4. 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]?

  5. 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?

  6. 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?

  7. 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.

Comments are closed.