konieczny_jabtran.py
script
Download, Add a comment, Back to main page
#!/usr/bin/python
"""
Jabberd 1.4 to Jabber 2.0 user-database translator
(c) 2003 Jacek Konieczny <jajcus@bnet.pl>
This script reads jabber-1.4.x user files and tries to put user information
from them to jabberd2 database. The script was written for PostgreSQL database,
but probably will work with MySQL too (after changing module name below).
Usage:
./jabtran.py <jid> <user.xml-file>
or:
./jabtran.py <domain> <spool-directory>
Run this only on empty database!
Good luck!
"""
import sys
import glob
import os
import libxml2
import time
import string
# Change 'pgdb' below to DB-API compatible module for your database
# pgdb is OK for PostgreSQL
import pgdb as db
# Change this to your jabberd2 database settings
DBSTRING="localhost:jabberd2:jabberd2:secret"
def ignore_ns(cur,doc,jid,el):
pass
def convert_password(cur,doc,jid,el):
passwd=el.getContent()
cur.execute("UPDATE authreg SET password=%(passwd)s WHERE username=%(username)s",
{'username':jid.split('@')[0],'passwd':passwd})
def convert_zerok(cur,doc,jid,el):
token=None
sequence=None
hash=None
it=el.children
while it:
if it.name=="token":
token=it.getContent()
elif it.name=="sequence":
sequence=it.getContent()
elif it.name=="hash":
hash=it.getContent()
it=it.next
if None in (token,sequence,hash):
print "Incomplete zerok info:",el.serialize
return
cur.execute("UPDATE authreg SET token=%(token)s,sequence=%(sequence)s,hash=%(hash)s"
" WHERE username=%(username)s",
{'token':token,'sequence':sequence,'hash':hash, 'username':jid.split('@')[0]})
def convert_last(cur,doc,jid,el):
last=el.prop("last")
cur.execute("INSERT INTO logout (\"collection-owner\",\"object-sequence\",time)"
" VALUES (%(jid)s,nextval('object-sequence'),%(last)s)",
{'jid':jid,'last':last})
def convert_roster(cur,doc,jid,el):
item=el.children
while item:
if item.name!="item":
print "Unknown roster element:",item.serialize()
continue
if not item.hasProp("jid"):
print "Roster item without jid:",item.serialize()
continue
ijid=item.prop("jid")
if item.hasProp("name"):
name=item.prop("name")
else:
name=None
if item.hasProp("subscription"):
s=item.prop("subscription")
if s=="both":
fr,to='t','t'
elif s=="from":
fr,to='t','n'
elif s=="to":
to,fr='t','n'
else:
fr,to='n','n'
if item.hasProp("ask"):
ask=item.prop("ask")
if ask=="subscribe":
ask=1
elif ask=="unsubscribe":
ask=2
else:
ask=0
else:
ask=None
groups=[]
child=item.children
while child:
if child.name!="group":
print "Unknown roster item subelement:",child.serialize()
continue
if child.getContent():
groups.append(child.getContent())
child=child.next
cur.execute("INSERT INTO \"roster-items\""
" (\"collection-owner\",\"object-sequence\",jid,name,\"to\",\"from\",ask)"
" VALUES (%(jid)s,nextval('object-sequence'),"
"%(ijid)s,%(name)s,%(to)s,%(fr)s,%(ask)s)",
{'jid':jid,'ijid':ijid,'name':name,'to':to,'fr':fr,'ask':ask})
for group in groups:
cur.execute("INSERT INTO \"roster-groups\""
"(\"collection-owner\",\"object-sequence\",jid,\"group\")"
" VALUES (%(jid)s,nextval('object-sequence'),%(ijid)s,%(group)s)",
{'jid':jid,'ijid':ijid,'group':group})
item=item.next
def convert_offline(cur,doc,jid,el):
item=el.children
while item:
cur.execute("INSERT INTO queue (\"collection-owner\",\"object-sequence\",xml)"
" VALUES (%(jid)s,nextval('object-sequence'),%(xml)s)",
{'jid':jid,'xml':item.serialize})
item=item.next
vcard_fields=[
("v:FN","fn"),
("v:NICKNAME","nickname"),
("v:URL","url"),
("v:TEL/NUMBER","tel"),
("v:EMAIL","email"),
("v:TITLE","title"),
("v:ROLE","role"),
("v:BDAY","bday"),
("v:DESC","desc"),
("v:N/GIVEN","n-given"),
("v:N/FAMILY","n-family"),
("v:ADR/STREET","adr-street"),
("v:ADR/EXTADD","adr-extadd"),
("v:ADR/LOCALITY","adr-locality"),
("v:ADR/REGION","adr-region"),
("v:ADR/PCODE","adr-pcode"),
("v:ADR/COUNTRY","adr-country"),
("v:ORG/ORGNAME","org-orgname"),
("v:ORG/ORGUNIT","org-orgunit"),
]
def convert_vcard(cur,doc,jid,el):
xp=doc.xpathNewContext()
xp.xpathRegisterNs("v","vcard-temp")
xp.setContextNode(el)
fields=[]
values=[]
for xpath,field in vcard_fields:
f=xp.xpathEval(xpath)
if not f:
continue
v=f[0].getContent()
if not v:
continue
fields.append('"%s"' % (field,))
v=v.replace("'","''")
values.append("'%s'" % (v,))
if not fields:
return
fields=string.join(fields,",")
values=string.join(values,",")
cur.execute("INSERT INTO vcard (\"collection-owner\",\"object-sequence\",%s)"
" VALUES (%%(jid)s,nextval('object-sequence'),%s)" % (fields,values),
{'jid':jid})
namespace_handlers={
("jabber:iq:auth","jabber:iq:auth"):convert_password,
("jabber:iq:auth:0k","jabber:iq:auth:0k"):convert_zerok,
("jabber:iq:roster","jabber:iq:roster"):convert_roster,
("jabber:iq:last","jabber:iq:last"):convert_last,
("jabber:x:offline","jabber:x:offline"):convert_offline,
("vcard-temp","vcard-temp"):convert_vcard,
("jabber:xdb:nslist","jabber:xdb:nslist"):ignore_ns,
("jabber:iq:register","jabber:iq:register"):ignore_ns,
("jabber:iq:filter","jabber:iq:filter"):ignore_ns,
("jabber:iq:browse","jabber:iq:browse"):ignore_ns,
}
def convert_user(dbconn,jid,filename,realm):
print "Converting: %s (JID: %s)" % (filename,jid)
doc=libxml2.parseFile(filename)
cur=dbconn.cursor()
cur.execute("INSERT INTO authreg(username,realm) VALUES(%(username)s,%(realm)s)",
{'username':jid.split('@')[0],'realm':realm})
cur.execute("INSERT INTO active(\"collection-owner\",\"object-sequence\",time)"
" VALUES(%(jid)s,nextval('object-sequence'),%(time)s)",
{'jid':jid,'time':time.time()})
private_namespaces=[]
xp=doc.xpathNewContext()
xp.xpathRegisterNs("nsl","jabber:xdb:nslist")
nslist=xp.xpathEval("//nsl:*[@xdbns='jabber:xdb:nslist']/nsl:ns")
if nslist:
for ns in nslist:
if not ns.hasProp("type") or ns.prop("type")!="private":
print "Warning: non-private xdb namespace '%s' made private" % (ns.getContent())
private_namespaces.append(ns.getContent())
el=doc.getRootElement().children
while el:
try:
ns=el.ns()
except libxml2.treeError:
ns=None
if ns:
ns=ns.getContent()
xdbns=el.prop("xdbns")
handler=namespace_handlers.get((xdbns,ns))
if handler:
handler(cur,doc,jid,el)
elif not xdbns:
print "Element without xdbns:",el.serialize()
elif xdbns in private_namespaces:
cur.execute("INSERT INTO private"
"(\"collection-owner\",\"object-sequence\",ns,xml)"
" VALUES ( %(jid)s,nextval('object-sequence'),"
" %(xdbns)s,%(xml)s)",
{'jid':jid,'xdbns':xdbns,'xml':el.serialize()})
else:
print "Element in unknown xdb namespace:",el.serialize()
el=el.next
xp.xpathFreeContext()
doc.freeDoc()
dbconn.commit()
print
if len(sys.argv)<3:
print "Usage:"
print " jubgrade.py <jid> <file>"
print "or:"
print " jubgrade.py <domain> <directory>"
sys.exit(1)
dbconn=db.connect(DBSTRING)
jid=sys.argv[1]
if "@" in jid:
filename=sys.argv[2]
convert_user(dbconn,jid,file,jid.split("@")[1])
else:
dirname=sys.argv[2]
domain=jid
files=glob.glob("%s/*.xml" % (dirname,))
for f in files:
username=os.path.splitext(os.path.basename(f))[0]
jid="%s@%s" % (username.lower(),domain)
convert_user(dbconn,jid,f,domain)