#!/usr/bin/python
# -*- coding: utf-8 -*-
# According to http://search.eb.com/shakespeare/article-9000043
# Lucio from Measure for Measure is a scandalmonger
import sys
import xmpp
import os
import os.path
import ConfigParser
import optparse
import StringIO
import lxml.etree
from xml.dom.ext import PrettyPrint
debug = False
NS_XEP136="http://www.xmpp.org/extensions/xep-0136.html#ns"
NS_RSM = "http://jabber.org/protocol/rsm"
class FoundMessage(Exception):
pass
class MsgType:
msg = 0
iq = 1
presence = 2
class WatchStream(xmpp.Client):
def __init__(self,jidStr=None,password="",initDebug=[]):
if not(jidStr and password):
configFN = os.path.abspath(os.path.expanduser("~/.xsendrc"))
self.jid,self.passwd = self.__getAuthenticators(configFN)
else:
self.jid=xmpp.protocol.JID(jidStr)
self.passwd=password
if initDebug:
debugList = ['always', 'nodebuilder']
else:
debugList = []
# FIXME: why are the following two properties not generated
# automagically by xmpp.Client?
self.Namespace=xmpp.NS_CLIENT
self.DBG=xmpp.client.DBG_CLIENT
xmpp.Client.__init__(self,self.jid.getDomain(),debug=debugList)
if self.connect() == "":
raise RuntimeError, "Cannot connect."
if self.auth(self.jid.getNode(),self.passwd,
self.jid.getResource()) == None:
raise RuntimeError, "Authentication failed."
self.__typeOfMsg = None
self.__msgid = ""
self.__retMessage = None
self.RegisterHandler('message', self.__messageCB)
self.RegisterHandler('iq', self.__iqCB)
self.sendInitPresence(requestRoster=0)
def __getAuthenticators(self,filename):
conf = {"jid":None,"password":None}
try:
configFile=file(filename,"r")
except:
print >>sys.stderr,"Cannot open configuration file %s." % filename
raise
for line in configFile:
key,value = line.strip().lower().split("=")
conf[key]=value
if not(conf["jid"] and conf["password"]):
raise RuntimeError,"Authentication tokens not available."
return conf["jid"],conf["password"]
def __messageCB(self,conn,msg):
if (str(msg.getID()) == self.__msgid) and self.__typeOfMsg == MsgType.msg:
if debug:
print "Sender: " + str(msg.getFrom())
print "Content: " + str(msg.getBody())
self.__retMessage = msg
raise FoundMessage
def __iqCB(self,conn,msg):
if (str(msg.getID()) == self.__msgid) and self.__typeOfMsg == MsgType.iq:
if debug:
print "Sender: " + str(msg.getFrom())
print "Type: " + str(msg.getType())
print "QueryNS: " + str(msg.getQueryNS())
print "Payload: " + \
str(",".join([str(x) for x in msg.getQueryPayload()]))
self.__retMessage = msg
raise FoundMessage
def __stepOn(self):
try:
self.Process(1)
except (KeyboardInterrupt,FoundMessage):
return False
return True
def getResponse(self,idNo,msgType=MsgType.iq):
self.__msgid = idNo
self.__typeOfMsg = msgType
while self.__stepOn():
pass
return self.__retMessage
class IqSource(xmpp.Iq):
def __init__(self,jid=None,maxKarma=30):
xmpp.Iq.__init__(self,typ="get")
self.maxResp=maxKarma
self.sJid = jid
exNode = self.ExecNode()
self.addChild(node=exNode)
def SetNode(self):
setNode = xmpp.Node("set")
setNode.setNamespace(NS_RSM)
setNode.addChild(name="max",payload=str(self.maxResp))
return setNode
def ExecNode(self,name="dummy"):
node = xmpp.Node(name)
node.setNamespace(NS_XEP136)
node.addChild(node=self.SetNode())
if self.sJid:
node.setAttr("with",self.sJid)
def getData(self,cl):
idReturned = cl.send(self)
return cl.getResponse(idReturned)
# from http://infix.se/2007/02/06/gentlemen-indent-your-xml
def __xmlIndent(self,elem,level=0):
i = "\n" + level*" "
if len(elem):
if not elem.text or not elem.text.strip():
elem.text = i + " "
for e in elem:
xmlIndent(e, level+1)
if not e.tail or not e.tail.strip():
e.tail = i + " "
if not e.tail or not e.tail.strip():
e.tail = i
else:
if level and (not elem.tail or not elem.tail.strip()):
elem.tail = i
def __prettyPrint(self):
doc_file = StringIO.StringIO(xmpp.ustr(self))
out_file = StringIO.StringIO()
doc = lxml.etree.parse(doc_file)
self.__xmlIndent(doc.getroot())
doc.write(out_file,"utf-8")
return unicode(out_file.getvalue())
def __own_str__(self):
# if the following doesn't work, use:
# self.prettyPrint()
return xmpp.Iq.__str__(fancy=1)
class Collections(IqSource):
def __init__(self,jid=None,start=None,end=None):
IqSource.__init__(self,jid,30)
def ExecNode(self):
node=IqSource.ExecNode(self,"list")
class Chats(IqSource):
def __init__(self,jid=None,start=None,end=None):
self.startTime = start
self.endTime = end
IqSource.__init__(self,jid,30)
def ExecNode(self):
node=IqSource.ExecNode("retrieve")
if self.startTime:
node.setAttr("start",self.startTime)
if self.endTime:
node.setAttr("end",self.endTime)
def main():
searchJid = None
cmdlineparser = optparse.OptionParser()
(options,args) = cmdlineparser.parse_args()
if (len(args) > 0):
searchJid = args[0]
cl = WatchStream("jid@domain/resource",
"passwd",debug)
# disco request
idReturned = cl.send(xmpp.Iq("get",xmpp.NS_DISCO_INFO))
response = cl.getResponse(idReturned,MsgType.iq)
# get collections
#
# question:
#
#
#
# 30
#
#
#
#
# response:
#
#
#
#
# 63367484175
# 63367484175
# 1
#
#
#
coll = Collections(searchJid)
coll.getData(cl)
print "%s\n%s" % ("=" * 80,str(coll))
# parse response
startTimes = {}
listTag = response.getTag("list")
print >>sys.stderr,listTag
xchats = response.getTag("list").getTags("chat")
for xchat in xchats:
prettyPrint(xchat)
who = xchat.getAttr("with")
start = xchat.getAttr("start")
if not(startTimes.hasKey(who)):
startTimes[who]=[]
startTimes[who].append(start)
print >>sys.stderr,startTimes
# FIXME: testing measure
print >>sys.stderr,"This is the end for now."
startTimes = {}
# get content of a collection
#
# question:
#
#
#
# 100
#
#
#
#
# long reply:
#
#
#
# are you there?
#
#
# yes, I am
#
# ... a lot of stuff deleted
#
# 0
# 7
# 7
#
#
#
for currJid in startTimes.keys():
print "%s\nCurrent JID: %s\n%s" % ("=" * 80,
currJid, "-" * 80)
for startT in startTimes[currJid]:
chatList = Collections(searchJid)
chatList.getData(cl)
print "%s\n%s" % ("-" * 80,str(chatList))
cl.disconnect()
if __name__ == '__main__':
main()