One more portion of doc-string and formatting refactoring
This commit is contained in:
parent
6d0f28c47d
commit
f084a1f78b
|
@ -476,7 +476,7 @@ class Protocol(Node):
|
||||||
self.setTo(self['to'])
|
self.setTo(self['to'])
|
||||||
if self['from']:
|
if self['from']:
|
||||||
self.setFrom(self['from'])
|
self.setFrom(self['from'])
|
||||||
if node and type(self )== type(node) and self.__class__ == node.__class__ and self.attrs.has_key('id'):
|
if node and type(self) == type(node) and self.__class__ == node.__class__ and self.attrs.has_key('id'):
|
||||||
del self.attrs['id']
|
del self.attrs['id']
|
||||||
self.timestamp = None
|
self.timestamp = None
|
||||||
for d in self.getTags('delay', namespace=NS_DELAY2):
|
for d in self.getTags('delay', namespace=NS_DELAY2):
|
||||||
|
|
|
@ -14,27 +14,30 @@
|
||||||
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
## GNU General Public License for more details.
|
## GNU General Public License for more details.
|
||||||
'''
|
|
||||||
Module containing classes for proxy connecting. So far its HTTP CONNECT
|
"""
|
||||||
and SOCKS5 proxy.
|
Module containing classes for proxy connecting. So far its HTTP CONNECT and
|
||||||
|
SOCKS5 proxy
|
||||||
|
|
||||||
Authentication to NTLM (Microsoft implementation) proxies can be next.
|
Authentication to NTLM (Microsoft implementation) proxies can be next.
|
||||||
'''
|
"""
|
||||||
|
|
||||||
import struct, socket, base64
|
import struct, socket, base64
|
||||||
import logging
|
import logging
|
||||||
log = logging.getLogger('gajim.c.x.proxy_connectors')
|
log = logging.getLogger('gajim.c.x.proxy_connectors')
|
||||||
|
|
||||||
class ProxyConnector:
|
class ProxyConnector:
|
||||||
'''
|
"""
|
||||||
Interface for proxy-connecting object - when tunnneling XMPP over proxies,
|
Interface for proxy-connecting object - when tunnneling XMPP over proxies,
|
||||||
some connecting process usually has to be done before opening stream.
|
some connecting process usually has to be done before opening stream. Proxy
|
||||||
Proxy connectors are used right after TCP connection is estabilished.
|
connectors are used right after TCP connection is estabilished
|
||||||
'''
|
"""
|
||||||
|
|
||||||
def __init__(self, send_method, onreceive, old_on_receive, on_success,
|
def __init__(self, send_method, onreceive, old_on_receive, on_success,
|
||||||
on_failure, xmpp_server, proxy_creds=(None,None)):
|
on_failure, xmpp_server, proxy_creds=(None,None)):
|
||||||
'''
|
"""
|
||||||
Creates proxy connector, starts connecting immediately and gives control
|
Creates proxy connector, starts connecting immediately and gives control
|
||||||
back to transport afterwards.
|
back to transport afterwards
|
||||||
|
|
||||||
:param send_method: transport send method
|
:param send_method: transport send method
|
||||||
:param onreceive: method to set on_receive callbacks
|
:param onreceive: method to set on_receive callbacks
|
||||||
|
@ -44,7 +47,7 @@ class ProxyConnector:
|
||||||
:param on_failure: called when errors occured while connecting
|
:param on_failure: called when errors occured while connecting
|
||||||
:param xmpp_server: tuple of (hostname, port)
|
:param xmpp_server: tuple of (hostname, port)
|
||||||
:param proxy_creds: tuple of (proxy_user, proxy_credentials)
|
:param proxy_creds: tuple of (proxy_user, proxy_credentials)
|
||||||
'''
|
"""
|
||||||
self.send = send_method
|
self.send = send_method
|
||||||
self.onreceive = onreceive
|
self.onreceive = onreceive
|
||||||
self.old_on_receive = old_on_receive
|
self.old_on_receive = old_on_receive
|
||||||
|
@ -58,12 +61,12 @@ class ProxyConnector:
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_instance(cls, *args, **kwargs):
|
def get_instance(cls, *args, **kwargs):
|
||||||
'''
|
"""
|
||||||
Factory Method for object creation.
|
Factory Method for object creation
|
||||||
|
|
||||||
Use this instead of directly initializing the class in order to make
|
Use this instead of directly initializing the class in order to make unit
|
||||||
unit testing much easier.
|
testing much easier.
|
||||||
'''
|
"""
|
||||||
return cls(*args, **kwargs)
|
return cls(*args, **kwargs)
|
||||||
|
|
||||||
def start_connecting(self):
|
def start_connecting(self):
|
||||||
|
@ -75,11 +78,11 @@ class ProxyConnector:
|
||||||
|
|
||||||
class HTTPCONNECTConnector(ProxyConnector):
|
class HTTPCONNECTConnector(ProxyConnector):
|
||||||
def start_connecting(self):
|
def start_connecting(self):
|
||||||
'''
|
"""
|
||||||
Connects to proxy, supplies login and password to it
|
Connect to a proxy, supply login and password to it (if were specified
|
||||||
(if were specified while creating instance). Instructs proxy to make
|
while creating instance). Instruct proxy to make connection to the target
|
||||||
connection to the target server.
|
server.
|
||||||
'''
|
"""
|
||||||
log.info('Proxy server contacted, performing authentification')
|
log.info('Proxy server contacted, performing authentification')
|
||||||
connector = ['CONNECT %s:%s HTTP/1.1' % self.xmpp_server,
|
connector = ['CONNECT %s:%s HTTP/1.1' % self.xmpp_server,
|
||||||
'Proxy-Connection: Keep-Alive',
|
'Proxy-Connection: Keep-Alive',
|
||||||
|
@ -115,10 +118,11 @@ class HTTPCONNECTConnector(ProxyConnector):
|
||||||
|
|
||||||
|
|
||||||
class SOCKS5Connector(ProxyConnector):
|
class SOCKS5Connector(ProxyConnector):
|
||||||
'''
|
"""
|
||||||
SOCKS5 proxy connection class. Allows to use SOCKS5 proxies with
|
SOCKS5 proxy connection class. Allows to use SOCKS5 proxies with
|
||||||
(optionally) simple authentication (only USERNAME/PASSWORD auth).
|
(optionally) simple authentication (only USERNAME/PASSWORD auth)
|
||||||
'''
|
"""
|
||||||
|
|
||||||
def start_connecting(self):
|
def start_connecting(self):
|
||||||
log.info('Proxy server contacted, performing authentification')
|
log.info('Proxy server contacted, performing authentification')
|
||||||
if self.proxy_user and self.proxy_pass:
|
if self.proxy_user and self.proxy_pass:
|
||||||
|
|
|
@ -16,10 +16,11 @@
|
||||||
|
|
||||||
# $Id: roster.py,v 1.17 2005/05/02 08:38:49 snakeru Exp $
|
# $Id: roster.py,v 1.17 2005/05/02 08:38:49 snakeru Exp $
|
||||||
|
|
||||||
'''
|
|
||||||
|
"""
|
||||||
Simple roster implementation. Can be used though for different tasks like
|
Simple roster implementation. Can be used though for different tasks like
|
||||||
mass-renaming of contacts.
|
mass-renaming of contacts.
|
||||||
'''
|
"""
|
||||||
|
|
||||||
from protocol import JID, Iq, Presence, Node, NodeProcessed, NS_MUC_USER, NS_ROSTER
|
from protocol import JID, Iq, Presence, Node, NodeProcessed, NS_MUC_USER, NS_ROSTER
|
||||||
from plugin import PlugIn
|
from plugin import PlugIn
|
||||||
|
@ -29,15 +30,18 @@ log = logging.getLogger('gajim.c.x.roster_nb')
|
||||||
|
|
||||||
|
|
||||||
class NonBlockingRoster(PlugIn):
|
class NonBlockingRoster(PlugIn):
|
||||||
''' Defines a plenty of methods that will allow you to manage roster.
|
"""
|
||||||
Also automatically track presences from remote JIDs taking into
|
Defines a plenty of methods that will allow you to manage roster. Also
|
||||||
account that every JID can have multiple resources connected. Does not
|
automatically track presences from remote JIDs taking into account that
|
||||||
currently support 'error' presences.
|
every JID can have multiple resources connected. Does not currently support
|
||||||
You can also use mapping interface for access to the internal representation of
|
'error' presences. You can also use mapping interface for access to the
|
||||||
contacts in roster.
|
internal representation of contacts in roster
|
||||||
'''
|
"""
|
||||||
|
|
||||||
def __init__(self, version=''):
|
def __init__(self, version=''):
|
||||||
''' Init internal variables. '''
|
"""
|
||||||
|
Init internal variables
|
||||||
|
"""
|
||||||
PlugIn.__init__(self)
|
PlugIn.__init__(self)
|
||||||
self.version = version
|
self.version = version
|
||||||
self._data = {}
|
self._data = {}
|
||||||
|
@ -45,11 +49,15 @@ class NonBlockingRoster(PlugIn):
|
||||||
self._exported_methods=[self.getRoster]
|
self._exported_methods=[self.getRoster]
|
||||||
self.received_from_server = False
|
self.received_from_server = False
|
||||||
|
|
||||||
def Request(self,force=0):
|
def Request(self, force=0):
|
||||||
''' Request roster from server if it were not yet requested
|
"""
|
||||||
(or if the 'force' argument is set). '''
|
Request roster from server if it were not yet requested (or if the
|
||||||
if self.set is None: self.set=0
|
'force' argument is set)
|
||||||
elif not force: return
|
"""
|
||||||
|
if self.set is None:
|
||||||
|
self.set = 0
|
||||||
|
elif not force:
|
||||||
|
return
|
||||||
|
|
||||||
iq = Iq('get',NS_ROSTER)
|
iq = Iq('get',NS_ROSTER)
|
||||||
iq.setTagAttr('query', 'ver', self.version)
|
iq.setTagAttr('query', 'ver', self.version)
|
||||||
|
@ -59,9 +67,11 @@ class NonBlockingRoster(PlugIn):
|
||||||
log.info('Roster requested from server')
|
log.info('Roster requested from server')
|
||||||
return id_
|
return id_
|
||||||
|
|
||||||
def RosterIqHandler(self,dis,stanza):
|
def RosterIqHandler(self, dis, stanza):
|
||||||
''' Subscription tracker. Used internally for setting items state in
|
"""
|
||||||
internal roster representation. '''
|
Subscription tracker. Used internally for setting items state in internal
|
||||||
|
roster representation
|
||||||
|
"""
|
||||||
sender = stanza.getAttr('from')
|
sender = stanza.getAttr('from')
|
||||||
if not sender is None and not sender.bareMatch(
|
if not sender is None and not sender.bareMatch(
|
||||||
self._owner.User + '@' + self._owner.Server):
|
self._owner.User + '@' + self._owner.Server):
|
||||||
|
@ -91,9 +101,11 @@ class NonBlockingRoster(PlugIn):
|
||||||
# Looks like we have a workaround
|
# Looks like we have a workaround
|
||||||
# raise NodeProcessed # a MUST. Otherwise you'll get back an <iq type='error'/>
|
# raise NodeProcessed # a MUST. Otherwise you'll get back an <iq type='error'/>
|
||||||
|
|
||||||
def PresenceHandler(self,dis,pres):
|
def PresenceHandler(self, dis, pres):
|
||||||
''' Presence tracker. Used internally for setting items' resources state in
|
"""
|
||||||
internal roster representation. '''
|
Presence tracker. Used internally for setting items' resources state in
|
||||||
|
internal roster representation
|
||||||
|
"""
|
||||||
if pres.getTag('x', namespace=NS_MUC_USER):
|
if pres.getTag('x', namespace=NS_MUC_USER):
|
||||||
return
|
return
|
||||||
jid=pres.getFrom()
|
jid=pres.getFrom()
|
||||||
|
@ -118,112 +130,204 @@ class NonBlockingRoster(PlugIn):
|
||||||
elif typ=='unavailable' and item['resources'].has_key(jid.getResource()): del item['resources'][jid.getResource()]
|
elif typ=='unavailable' and item['resources'].has_key(jid.getResource()): del item['resources'][jid.getResource()]
|
||||||
# Need to handle type='error' also
|
# Need to handle type='error' also
|
||||||
|
|
||||||
def _getItemData(self,jid,dataname):
|
def _getItemData(self, jid, dataname):
|
||||||
''' Return specific jid's representation in internal format. Used internally. '''
|
"""
|
||||||
jid=jid[:(jid+'/').find('/')]
|
Return specific jid's representation in internal format. Used internally
|
||||||
|
"""
|
||||||
|
jid = jid[:(jid+'/').find('/')]
|
||||||
return self._data[jid][dataname]
|
return self._data[jid][dataname]
|
||||||
def _getResourceData(self,jid,dataname):
|
|
||||||
''' Return specific jid's resource representation in internal format. Used internally. '''
|
|
||||||
if jid.find('/')+1:
|
|
||||||
jid,resource=jid.split('/',1)
|
|
||||||
if self._data[jid]['resources'].has_key(resource): return self._data[jid]['resources'][resource][dataname]
|
|
||||||
elif self._data[jid]['resources'].keys():
|
|
||||||
lastpri=-129
|
|
||||||
for r in self._data[jid]['resources'].keys():
|
|
||||||
if int(self._data[jid]['resources'][r]['priority'])>lastpri: resource,lastpri=r,int(self._data[jid]['resources'][r]['priority'])
|
|
||||||
return self._data[jid]['resources'][resource][dataname]
|
|
||||||
def delItem(self,jid):
|
|
||||||
''' Delete contact 'jid' from roster.'''
|
|
||||||
self._owner.send(Iq('set',NS_ROSTER,payload=[Node('item',{'jid':jid,'subscription':'remove'})]))
|
|
||||||
def getAsk(self,jid):
|
|
||||||
''' Returns 'ask' value of contact 'jid'.'''
|
|
||||||
return self._getItemData(jid,'ask')
|
|
||||||
def getGroups(self,jid):
|
|
||||||
''' Returns groups list that contact 'jid' belongs to.'''
|
|
||||||
return self._getItemData(jid,'groups')
|
|
||||||
def getName(self,jid):
|
|
||||||
''' Returns name of contact 'jid'.'''
|
|
||||||
return self._getItemData(jid,'name')
|
|
||||||
def getPriority(self,jid):
|
|
||||||
''' Returns priority of contact 'jid'. 'jid' should be a full (not bare) JID.'''
|
|
||||||
return self._getResourceData(jid,'priority')
|
|
||||||
def getRawRoster(self):
|
|
||||||
''' Returns roster representation in internal format. '''
|
|
||||||
return self._data
|
|
||||||
def getRawItem(self,jid):
|
|
||||||
''' Returns roster item 'jid' representation in internal format. '''
|
|
||||||
return self._data[jid[:(jid+'/').find('/')]]
|
|
||||||
def getShow(self, jid):
|
|
||||||
''' Returns 'show' value of contact 'jid'. 'jid' should be a full (not bare) JID.'''
|
|
||||||
return self._getResourceData(jid,'show')
|
|
||||||
def getStatus(self, jid):
|
|
||||||
''' Returns 'status' value of contact 'jid'. 'jid' should be a full (not bare) JID.'''
|
|
||||||
return self._getResourceData(jid,'status')
|
|
||||||
def getSubscription(self,jid):
|
|
||||||
''' Returns 'subscription' value of contact 'jid'.'''
|
|
||||||
return self._getItemData(jid,'subscription')
|
|
||||||
def getResources(self,jid):
|
|
||||||
''' Returns list of connected resources of contact 'jid'.'''
|
|
||||||
return self._data[jid[:(jid+'/').find('/')]]['resources'].keys()
|
|
||||||
def setItem(self,jid,name=None,groups=[]):
|
|
||||||
''' Renames contact 'jid' and sets the groups list that it now belongs to.'''
|
|
||||||
iq=Iq('set',NS_ROSTER)
|
|
||||||
query=iq.getTag('query')
|
|
||||||
attrs={'jid':jid}
|
|
||||||
if name: attrs['name']=name
|
|
||||||
item=query.setTag('item',attrs)
|
|
||||||
for group in groups: item.addChild(node=Node('group',payload=[group]))
|
|
||||||
self._owner.send(iq)
|
|
||||||
def setItemMulti(self,items):
|
|
||||||
''' Renames multiple contacts and sets their group lists.'''
|
|
||||||
iq=Iq('set',NS_ROSTER)
|
|
||||||
query=iq.getTag('query')
|
|
||||||
for i in items:
|
|
||||||
attrs={'jid':i['jid']}
|
|
||||||
if i['name']: attrs['name']=i['name']
|
|
||||||
item=query.setTag('item',attrs)
|
|
||||||
for group in i['groups']: item.addChild(node=Node('group',payload=[group]))
|
|
||||||
self._owner.send(iq)
|
|
||||||
def getItems(self):
|
|
||||||
''' Return list of all [bare] JIDs that the roster is currently tracks.'''
|
|
||||||
return self._data.keys()
|
|
||||||
def keys(self):
|
|
||||||
''' Same as getItems. Provided for the sake of dictionary interface.'''
|
|
||||||
return self._data.keys()
|
|
||||||
def __getitem__(self,item):
|
|
||||||
''' Get the contact in the internal format. Raises KeyError if JID 'item' is not in roster.'''
|
|
||||||
return self._data[item]
|
|
||||||
def getItem(self,item):
|
|
||||||
''' Get the contact in the internal format (or None if JID 'item' is not in roster).'''
|
|
||||||
if self._data.has_key(item): return self._data[item]
|
|
||||||
def Subscribe(self,jid):
|
|
||||||
''' Send subscription request to JID 'jid'.'''
|
|
||||||
self._owner.send(Presence(jid,'subscribe'))
|
|
||||||
def Unsubscribe(self,jid):
|
|
||||||
''' Ask for removing our subscription for JID 'jid'.'''
|
|
||||||
self._owner.send(Presence(jid,'unsubscribe'))
|
|
||||||
def Authorize(self,jid):
|
|
||||||
''' Authorise JID 'jid'. Works only if these JID requested auth previously. '''
|
|
||||||
self._owner.send(Presence(jid,'subscribed'))
|
|
||||||
def Unauthorize(self,jid):
|
|
||||||
''' Unauthorise JID 'jid'. Use for declining authorisation request
|
|
||||||
or for removing existing authorization. '''
|
|
||||||
self._owner.send(Presence(jid,'unsubscribed'))
|
|
||||||
def getRaw(self):
|
|
||||||
'''Returns the internal data representation of the roster.'''
|
|
||||||
return self._data
|
|
||||||
def setRaw(self, data):
|
|
||||||
'''Returns the internal data representation of the roster.'''
|
|
||||||
self._data = data
|
|
||||||
self._data[self._owner.User+'@'+self._owner.Server]={'resources':{},'name':None,'ask':None,'subscription':None,'groups':None,}
|
|
||||||
self.set=1
|
|
||||||
# copypasted methods for roster.py from constructor to here
|
|
||||||
|
|
||||||
|
def _getResourceData(self, jid, dataname):
|
||||||
|
"""
|
||||||
|
Return specific jid's resource representation in internal format. Used
|
||||||
|
internally
|
||||||
|
"""
|
||||||
|
if jid.find('/') + 1:
|
||||||
|
jid, resource = jid.split('/', 1)
|
||||||
|
if self._data[jid]['resources'].has_key(resource):
|
||||||
|
return self._data[jid]['resources'][resource][dataname]
|
||||||
|
elif self._data[jid]['resources'].keys():
|
||||||
|
lastpri = -129
|
||||||
|
for r in self._data[jid]['resources'].keys():
|
||||||
|
if int(self._data[jid]['resources'][r]['priority']) > lastpri:
|
||||||
|
resource,lastpri=r,int(self._data[jid]['resources'][r]['priority'])
|
||||||
|
return self._data[jid]['resources'][resource][dataname]
|
||||||
|
|
||||||
|
def delItem(self, jid):
|
||||||
|
"""
|
||||||
|
Delete contact 'jid' from roster
|
||||||
|
"""
|
||||||
|
self._owner.send(Iq('set', NS_ROSTER, payload=[Node('item', {'jid': jid, 'subscription': 'remove'})]))
|
||||||
|
|
||||||
|
def getAsk(self, jid):
|
||||||
|
"""
|
||||||
|
Return 'ask' value of contact 'jid'
|
||||||
|
"""
|
||||||
|
return self._getItemData(jid, 'ask')
|
||||||
|
|
||||||
|
def getGroups(self, jid):
|
||||||
|
"""
|
||||||
|
Return groups list that contact 'jid' belongs to
|
||||||
|
"""
|
||||||
|
return self._getItemData(jid, 'groups')
|
||||||
|
|
||||||
|
def getName(self, jid):
|
||||||
|
"""
|
||||||
|
Return name of contact 'jid'
|
||||||
|
"""
|
||||||
|
return self._getItemData(jid, 'name')
|
||||||
|
|
||||||
|
def getPriority(self, jid):
|
||||||
|
"""
|
||||||
|
Return priority of contact 'jid'. 'jid' should be a full (not bare) JID
|
||||||
|
"""
|
||||||
|
return self._getResourceData(jid, 'priority')
|
||||||
|
|
||||||
|
def getRawRoster(self):
|
||||||
|
"""
|
||||||
|
Return roster representation in internal format
|
||||||
|
"""
|
||||||
|
return self._data
|
||||||
|
|
||||||
|
def getRawItem(self, jid):
|
||||||
|
"""
|
||||||
|
Return roster item 'jid' representation in internal format
|
||||||
|
"""
|
||||||
|
return self._data[jid[:(jid+'/').find('/')]]
|
||||||
|
|
||||||
|
def getShow(self, jid):
|
||||||
|
"""
|
||||||
|
Return 'show' value of contact 'jid'. 'jid' should be a full (not bare)
|
||||||
|
JID
|
||||||
|
"""
|
||||||
|
return self._getResourceData(jid, 'show')
|
||||||
|
|
||||||
|
def getStatus(self, jid):
|
||||||
|
"""
|
||||||
|
Return 'status' value of contact 'jid'. 'jid' should be a full (not bare)
|
||||||
|
JID
|
||||||
|
"""
|
||||||
|
return self._getResourceData(jid, 'status')
|
||||||
|
|
||||||
|
def getSubscription(self, jid):
|
||||||
|
"""
|
||||||
|
Return 'subscription' value of contact 'jid'
|
||||||
|
"""
|
||||||
|
return self._getItemData(jid, 'subscription')
|
||||||
|
|
||||||
|
def getResources(self, jid):
|
||||||
|
"""
|
||||||
|
Return list of connected resources of contact 'jid'
|
||||||
|
"""
|
||||||
|
return self._data[jid[:(jid+'/').find('/')]]['resources'].keys()
|
||||||
|
|
||||||
|
def setItem(self, jid, name=None, groups=[]):
|
||||||
|
"""
|
||||||
|
Rename contact 'jid' and sets the groups list that it now belongs to
|
||||||
|
"""
|
||||||
|
iq = Iq('set',NS_ROSTER)
|
||||||
|
query = iq.getTag('query')
|
||||||
|
attrs = {'jid': jid}
|
||||||
|
if name:
|
||||||
|
attrs['name'] = name
|
||||||
|
item = query.setTag('item' ,attrs)
|
||||||
|
for group in groups:
|
||||||
|
item.addChild(node=Node('group', payload=[group]))
|
||||||
|
self._owner.send(iq)
|
||||||
|
|
||||||
|
def setItemMulti(self, items):
|
||||||
|
"""
|
||||||
|
Rename multiple contacts and sets their group lists
|
||||||
|
"""
|
||||||
|
iq = Iq('set', NS_ROSTER)
|
||||||
|
query = iq.getTag('query')
|
||||||
|
for i in items:
|
||||||
|
attrs = {'jid': i['jid']}
|
||||||
|
if i['name']:
|
||||||
|
attrs['name'] = i['name']
|
||||||
|
item = query.setTag('item', attrs)
|
||||||
|
for group in i['groups']:
|
||||||
|
item.addChild(node=Node('group', payload=[group]))
|
||||||
|
self._owner.send(iq)
|
||||||
|
|
||||||
|
def getItems(self):
|
||||||
|
"""
|
||||||
|
Return list of all [bare] JIDs that the roster is currently tracks
|
||||||
|
"""
|
||||||
|
return self._data.keys()
|
||||||
|
|
||||||
|
def keys(self):
|
||||||
|
"""
|
||||||
|
Same as getItems. Provided for the sake of dictionary interface
|
||||||
|
"""
|
||||||
|
return self._data.keys()
|
||||||
|
|
||||||
|
def __getitem__(self, item):
|
||||||
|
"""
|
||||||
|
Get the contact in the internal format. Raises KeyError if JID 'item' is
|
||||||
|
not in roster
|
||||||
|
"""
|
||||||
|
return self._data[item]
|
||||||
|
|
||||||
|
def getItem(self,item):
|
||||||
|
"""
|
||||||
|
Get the contact in the internal format (or None if JID 'item' is not in
|
||||||
|
roster)
|
||||||
|
"""
|
||||||
|
if self._data.has_key(item):
|
||||||
|
return self._data[item]
|
||||||
|
|
||||||
|
def Subscribe(self, jid):
|
||||||
|
"""
|
||||||
|
Send subscription request to JID 'jid'
|
||||||
|
"""
|
||||||
|
self._owner.send(Presence(jid, 'subscribe'))
|
||||||
|
|
||||||
|
def Unsubscribe(self,jid):
|
||||||
|
"""
|
||||||
|
Ask for removing our subscription for JID 'jid'
|
||||||
|
"""
|
||||||
|
self._owner.send(Presence(jid, 'unsubscribe'))
|
||||||
|
|
||||||
|
def Authorize(self, jid):
|
||||||
|
"""
|
||||||
|
Authorize JID 'jid'. Works only if these JID requested auth previously
|
||||||
|
"""
|
||||||
|
self._owner.send(Presence(jid, 'subscribed'))
|
||||||
|
|
||||||
|
def Unauthorize(self, jid):
|
||||||
|
"""
|
||||||
|
Unauthorise JID 'jid'. Use for declining authorisation request or for
|
||||||
|
removing existing authorization
|
||||||
|
"""
|
||||||
|
self._owner.send(Presence(jid, 'unsubscribed'))
|
||||||
|
|
||||||
|
def getRaw(self):
|
||||||
|
"""
|
||||||
|
Return the internal data representation of the roster
|
||||||
|
"""
|
||||||
|
return self._data
|
||||||
|
|
||||||
|
def setRaw(self, data):
|
||||||
|
"""
|
||||||
|
Return the internal data representation of the roster
|
||||||
|
"""
|
||||||
|
self._data = data
|
||||||
|
self._data[self._owner.User + '@' + self._owner.Server] = {
|
||||||
|
'resources': {},
|
||||||
|
'name': None,
|
||||||
|
'ask': None,
|
||||||
|
'subscription': None,
|
||||||
|
'groups': None
|
||||||
|
}
|
||||||
|
self.set = 1
|
||||||
|
|
||||||
def plugin(self, owner, request=1):
|
def plugin(self, owner, request=1):
|
||||||
''' Register presence and subscription trackers in the owner's dispatcher.
|
"""
|
||||||
Also request roster from server if the 'request' argument is set.
|
Register presence and subscription trackers in the owner's dispatcher.
|
||||||
Used internally.'''
|
Also request roster from server if the 'request' argument is set. Used
|
||||||
|
internally
|
||||||
|
"""
|
||||||
self._owner.RegisterHandler('iq', self.RosterIqHandler, 'result', NS_ROSTER, makefirst = 1)
|
self._owner.RegisterHandler('iq', self.RosterIqHandler, 'result', NS_ROSTER, makefirst = 1)
|
||||||
self._owner.RegisterHandler('iq', self.RosterIqHandler, 'set', NS_ROSTER)
|
self._owner.RegisterHandler('iq', self.RosterIqHandler, 'set', NS_ROSTER)
|
||||||
self._owner.RegisterHandler('presence', self.PresenceHandler)
|
self._owner.RegisterHandler('presence', self.PresenceHandler)
|
||||||
|
@ -242,7 +346,9 @@ class NonBlockingRoster(PlugIn):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def getRoster(self, on_ready=None, force=False):
|
def getRoster(self, on_ready=None, force=False):
|
||||||
''' Requests roster from server if neccessary and returns self. '''
|
"""
|
||||||
|
Request roster from server if neccessary and returns self
|
||||||
|
"""
|
||||||
return_self = True
|
return_self = True
|
||||||
if not self.set:
|
if not self.set:
|
||||||
self.on_ready = on_ready
|
self.on_ready = on_ready
|
||||||
|
|
|
@ -14,64 +14,96 @@
|
||||||
|
|
||||||
# $Id: simplexml.py,v 1.27 2005/04/30 07:20:27 snakeru Exp $
|
# $Id: simplexml.py,v 1.27 2005/04/30 07:20:27 snakeru Exp $
|
||||||
|
|
||||||
'''Simplexml module provides xmpppy library with all needed tools to handle XML nodes and XML streams.
|
"""
|
||||||
I'm personally using it in many other separate projects. It is designed to be as standalone as possible.'''
|
Simplexml module provides xmpppy library with all needed tools to handle XML
|
||||||
|
nodes and XML streams. I'm personally using it in many other separate
|
||||||
|
projects. It is designed to be as standalone as possible
|
||||||
|
"""
|
||||||
|
|
||||||
import xml.parsers.expat
|
import xml.parsers.expat
|
||||||
import logging
|
import logging
|
||||||
log = logging.getLogger('gajim.c.x.simplexml')
|
log = logging.getLogger('gajim.c.x.simplexml')
|
||||||
|
|
||||||
def XMLescape(txt):
|
def XMLescape(txt):
|
||||||
'''Returns provided string with symbols & < > " replaced by their respective XML entities.'''
|
"""
|
||||||
|
Return provided string with symbols & < > " replaced by their respective XML
|
||||||
|
entities
|
||||||
|
"""
|
||||||
# replace also FORM FEED and ESC, because they are not valid XML chars
|
# replace also FORM FEED and ESC, because they are not valid XML chars
|
||||||
return txt.replace("&", "&").replace("<", "<").replace(">", ">").replace('"', """).replace(u'\x0C', "").replace(u'\x1B', "")
|
return txt.replace("&", "&").replace("<", "<").replace(">", ">").replace('"', """).replace(u'\x0C', "").replace(u'\x1B', "")
|
||||||
|
|
||||||
ENCODING='utf-8'
|
ENCODING='utf-8'
|
||||||
|
|
||||||
def ustr(what):
|
def ustr(what):
|
||||||
'''Converts object "what" to unicode string using it's own __str__ method if accessible or unicode method otherwise.'''
|
"""
|
||||||
if isinstance(what, unicode): return what
|
Converts object "what" to unicode string using it's own __str__ method if
|
||||||
try: r=what.__str__()
|
accessible or unicode method otherwise
|
||||||
except AttributeError: r=str(what)
|
"""
|
||||||
if not isinstance(r, unicode): return unicode(r,ENCODING)
|
if isinstance(what, unicode):
|
||||||
|
return what
|
||||||
|
try:
|
||||||
|
r = what.__str__()
|
||||||
|
except AttributeError:
|
||||||
|
r = str(what)
|
||||||
|
if not isinstance(r, unicode):
|
||||||
|
return unicode(r, ENCODING)
|
||||||
return r
|
return r
|
||||||
|
|
||||||
class Node(object):
|
class Node(object):
|
||||||
''' Node class describes syntax of separate XML Node. It have a constructor that permits node creation
|
"""
|
||||||
from set of "namespace name", attributes and payload of text strings and other nodes.
|
Node class describes syntax of separate XML Node. It have a constructor that
|
||||||
It does not natively support building node from text string and uses NodeBuilder class for that purpose.
|
permits node creation from set of "namespace name", attributes and payload
|
||||||
After creation node can be mangled in many ways so it can be completely changed.
|
of text strings and other nodes. It does not natively support building node
|
||||||
Also node can be serialised into string in one of two modes: default (where the textual representation
|
from text string and uses NodeBuilder class for that purpose. After
|
||||||
of node describes it exactly) and "fancy" - with whitespace added to make indentation and thus make
|
creation node can be mangled in many ways so it can be completely changed.
|
||||||
result more readable by human.
|
Also node can be serialised into string in one of two modes: default (where
|
||||||
|
the textual representation of node describes it exactly) and "fancy" - with
|
||||||
|
whitespace added to make indentation and thus make result more readable by
|
||||||
|
human.
|
||||||
|
|
||||||
Node class have attribute FORCE_NODE_RECREATION that is defaults to False thus enabling fast node
|
Node class have attribute FORCE_NODE_RECREATION that is defaults to False
|
||||||
replication from the some other node. The drawback of the fast way is that new node shares some
|
thus enabling fast node replication from the some other node. The drawback
|
||||||
info with the "original" node that is changing the one node may influence the other. Though it is
|
of the fast way is that new node shares some info with the "original" node
|
||||||
rarely needed (in xmpppy it is never needed at all since I'm usually never using original node after
|
that is changing the one node may influence the other. Though it is rarely
|
||||||
replication (and using replication only to move upwards on the classes tree).
|
needed (in xmpppy it is never needed at all since I'm usually never using
|
||||||
'''
|
original node after replication (and using replication only to move upwards
|
||||||
FORCE_NODE_RECREATION=0
|
on the classes tree).
|
||||||
def __init__(self, tag=None, attrs={}, payload=[], parent=None, nsp=None, node_built=False, node=None):
|
"""
|
||||||
''' Takes "tag" argument as the name of node (prepended by namespace, if needed and separated from it
|
|
||||||
by a space), attrs dictionary as the set of arguments, payload list as the set of textual strings
|
FORCE_NODE_RECREATION = 0
|
||||||
and child nodes that this node carries within itself and "parent" argument that is another node
|
|
||||||
that this one will be the child of. Also the __init__ can be provided with "node" argument that is
|
def __init__(self, tag=None, attrs={}, payload=[], parent=None, nsp=None,
|
||||||
either a text string containing exactly one node or another Node instance to begin with. If both
|
node_built=False, node=None):
|
||||||
"node" and other arguments is provided then the node initially created as replica of "node"
|
"""
|
||||||
provided and then modified to be compliant with other arguments.'''
|
Takes "tag" argument as the name of node (prepended by namespace, if
|
||||||
|
needed and separated from it by a space), attrs dictionary as the set of
|
||||||
|
arguments, payload list as the set of textual strings and child nodes
|
||||||
|
that this node carries within itself and "parent" argument that is
|
||||||
|
another node that this one will be the child of. Also the __init__ can be
|
||||||
|
provided with "node" argument that is either a text string containing
|
||||||
|
exactly one node or another Node instance to begin with. If both "node"
|
||||||
|
and other arguments is provided then the node initially created as
|
||||||
|
replica of "node" provided and then modified to be compliant with other
|
||||||
|
arguments.
|
||||||
|
"""
|
||||||
if node:
|
if node:
|
||||||
if self.FORCE_NODE_RECREATION and isinstance(node, Node):
|
if self.FORCE_NODE_RECREATION and isinstance(node, Node):
|
||||||
node=str(node)
|
node = str(node)
|
||||||
if not isinstance(node, Node):
|
if not isinstance(node, Node):
|
||||||
node=NodeBuilder(node,self)
|
node = NodeBuilder(node,self)
|
||||||
node_built = True
|
node_built = True
|
||||||
else:
|
else:
|
||||||
self.name,self.namespace,self.attrs,self.data,self.kids,self.parent,self.nsd = node.name,node.namespace,{},[],[],node.parent,{}
|
self.name, self.namespace, self.attrs, self.data, self.kids, self.parent, self.nsd = node.name, node.namespace, {}, [], [], node.parent, {}
|
||||||
for key in node.attrs.keys(): self.attrs[key]=node.attrs[key]
|
for key in node.attrs.keys():
|
||||||
for data in node.data: self.data.append(data)
|
self.attrs[key] = node.attrs[key]
|
||||||
for kid in node.kids: self.kids.append(kid)
|
for data in node.data:
|
||||||
for k,v in node.nsd.items(): self.nsd[k] = v
|
self.data.append(data)
|
||||||
else: self.name,self.namespace,self.attrs,self.data,self.kids,self.parent,self.nsd = 'tag','',{},[],[],None,{}
|
for kid in node.kids:
|
||||||
|
self.kids.append(kid)
|
||||||
|
for k,v in node.nsd.items():
|
||||||
|
self.nsd[k] = v
|
||||||
|
else:
|
||||||
|
self.name, self.namespace, self.attrs, self.data, self.kids, self.parent, self.nsd = 'tag', '', {}, [], [], None, {}
|
||||||
if parent:
|
if parent:
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
self.nsp_cache = {}
|
self.nsp_cache = {}
|
||||||
|
@ -94,10 +126,12 @@ class Node(object):
|
||||||
self.name = tag
|
self.name = tag
|
||||||
if isinstance(payload, basestring): payload=[payload]
|
if isinstance(payload, basestring): payload=[payload]
|
||||||
for i in payload:
|
for i in payload:
|
||||||
if isinstance(i, Node): self.addChild(node=i)
|
if isinstance(i, Node):
|
||||||
else: self.data.append(ustr(i))
|
self.addChild(node=i)
|
||||||
|
else:
|
||||||
|
self.data.append(ustr(i))
|
||||||
|
|
||||||
def lookup_nsp(self,pfx=''):
|
def lookup_nsp(self, pfx=''):
|
||||||
ns = self.nsd.get(pfx,None)
|
ns = self.nsd.get(pfx,None)
|
||||||
if ns is None:
|
if ns is None:
|
||||||
ns = self.nsp_cache.get(pfx,None)
|
ns = self.nsp_cache.get(pfx,None)
|
||||||
|
@ -109,9 +143,11 @@ class Node(object):
|
||||||
return 'http://www.gajim.org/xmlns/undeclared'
|
return 'http://www.gajim.org/xmlns/undeclared'
|
||||||
return ns
|
return ns
|
||||||
|
|
||||||
def __str__(self,fancy=0):
|
def __str__(self, fancy=0):
|
||||||
''' Method used to dump node into textual representation.
|
"""
|
||||||
if "fancy" argument is set to True produces indented output for readability.'''
|
Method used to dump node into textual representation. If "fancy" argument
|
||||||
|
is set to True produces indented output for readability
|
||||||
|
"""
|
||||||
s = (fancy-1) * 2 * ' ' + "<" + self.name
|
s = (fancy-1) * 2 * ' ' + "<" + self.name
|
||||||
if self.namespace:
|
if self.namespace:
|
||||||
if not self.parent or self.parent.namespace!=self.namespace:
|
if not self.parent or self.parent.namespace!=self.namespace:
|
||||||
|
@ -142,9 +178,12 @@ class Node(object):
|
||||||
s = s + "</" + self.name + ">"
|
s = s + "</" + self.name + ">"
|
||||||
if fancy: s = s + "\n"
|
if fancy: s = s + "\n"
|
||||||
return s
|
return s
|
||||||
|
|
||||||
def addChild(self, name=None, attrs={}, payload=[], namespace=None, node=None):
|
def addChild(self, name=None, attrs={}, payload=[], namespace=None, node=None):
|
||||||
''' If "node" argument is provided, adds it as child node. Else creates new node from
|
"""
|
||||||
the other arguments' values and adds it as well.'''
|
If "node" argument is provided, adds it as child node. Else creates new
|
||||||
|
node from the other arguments' values and adds it as well
|
||||||
|
"""
|
||||||
if 'xmlns' in attrs:
|
if 'xmlns' in attrs:
|
||||||
raise AttributeError("Use namespace=x instead of attrs={'xmlns':x}")
|
raise AttributeError("Use namespace=x instead of attrs={'xmlns':x}")
|
||||||
if node:
|
if node:
|
||||||
|
@ -155,190 +194,332 @@ class Node(object):
|
||||||
newnode.setNamespace(namespace)
|
newnode.setNamespace(namespace)
|
||||||
self.kids.append(newnode)
|
self.kids.append(newnode)
|
||||||
return newnode
|
return newnode
|
||||||
|
|
||||||
def addData(self, data):
|
def addData(self, data):
|
||||||
''' Adds some CDATA to node. '''
|
"""
|
||||||
|
Add some CDATA to node
|
||||||
|
"""
|
||||||
self.data.append(ustr(data))
|
self.data.append(ustr(data))
|
||||||
|
|
||||||
def clearData(self):
|
def clearData(self):
|
||||||
''' Removes all CDATA from the node. '''
|
"""
|
||||||
self.data=[]
|
Remove all CDATA from the node
|
||||||
|
"""
|
||||||
|
self.data = []
|
||||||
|
|
||||||
def delAttr(self, key):
|
def delAttr(self, key):
|
||||||
''' Deletes an attribute "key" '''
|
"""
|
||||||
|
Delete an attribute "key"
|
||||||
|
"""
|
||||||
del self.attrs[key]
|
del self.attrs[key]
|
||||||
|
|
||||||
def delChild(self, node, attrs={}):
|
def delChild(self, node, attrs={}):
|
||||||
''' Deletes the "node" from the node's childs list, if "node" is an instance.
|
"""
|
||||||
Else deletes the first node that have specified name and (optionally) attributes. '''
|
Delete the "node" from the node's childs list, if "node" is an instance.
|
||||||
if not isinstance(node, Node): node=self.getTag(node,attrs)
|
Else delete the first node that have specified name and (optionally)
|
||||||
|
attributes
|
||||||
|
"""
|
||||||
|
if not isinstance(node, Node):
|
||||||
|
node = self.getTag(node,attrs)
|
||||||
self.kids.remove(node)
|
self.kids.remove(node)
|
||||||
return node
|
return node
|
||||||
|
|
||||||
def getAttrs(self):
|
def getAttrs(self):
|
||||||
''' Returns all node's attributes as dictionary. '''
|
"""
|
||||||
|
Return all node's attributes as dictionary
|
||||||
|
"""
|
||||||
return self.attrs
|
return self.attrs
|
||||||
|
|
||||||
def getAttr(self, key):
|
def getAttr(self, key):
|
||||||
''' Returns value of specified attribute. '''
|
"""
|
||||||
|
Return value of specified attribute
|
||||||
|
"""
|
||||||
return self.attrs.get(key)
|
return self.attrs.get(key)
|
||||||
|
|
||||||
def getChildren(self):
|
def getChildren(self):
|
||||||
''' Returns all node's child nodes as list. '''
|
"""
|
||||||
|
Return all node's child nodes as list
|
||||||
|
"""
|
||||||
return self.kids
|
return self.kids
|
||||||
|
|
||||||
def getData(self):
|
def getData(self):
|
||||||
''' Returns all node CDATA as string (concatenated). '''
|
"""
|
||||||
|
Return all node CDATA as string (concatenated)
|
||||||
|
"""
|
||||||
return ''.join(self.data)
|
return ''.join(self.data)
|
||||||
|
|
||||||
def getName(self):
|
def getName(self):
|
||||||
''' Returns the name of node '''
|
"""
|
||||||
|
Return the name of node
|
||||||
|
"""
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
def getNamespace(self):
|
def getNamespace(self):
|
||||||
''' Returns the namespace of node '''
|
"""
|
||||||
|
Return the namespace of node
|
||||||
|
"""
|
||||||
return self.namespace
|
return self.namespace
|
||||||
|
|
||||||
def getParent(self):
|
def getParent(self):
|
||||||
''' Returns the parent of node (if present). '''
|
"""
|
||||||
|
Returns the parent of node (if present)
|
||||||
|
"""
|
||||||
return self.parent
|
return self.parent
|
||||||
|
|
||||||
def getPayload(self):
|
def getPayload(self):
|
||||||
''' Return the payload of node i.e. list of child nodes and CDATA entries.
|
"""
|
||||||
F.e. for "<node>text1<nodea/><nodeb/> text2</node>" will be returned list:
|
Return the payload of node i.e. list of child nodes and CDATA entries.
|
||||||
['text1', <nodea instance>, <nodeb instance>, ' text2']. '''
|
F.e. for "<node>text1<nodea/><nodeb/> text2</node>" will be returned
|
||||||
ret=[]
|
list: ['text1', <nodea instance>, <nodeb instance>, ' text2']
|
||||||
|
"""
|
||||||
|
ret = []
|
||||||
for i in range(len(self.kids)+len(self.data)+1):
|
for i in range(len(self.kids)+len(self.data)+1):
|
||||||
try:
|
try:
|
||||||
if self.data[i]: ret.append(self.data[i])
|
if self.data[i]:
|
||||||
except IndexError: pass
|
ret.append(self.data[i])
|
||||||
try: ret.append(self.kids[i])
|
except IndexError:
|
||||||
except IndexError: pass
|
pass
|
||||||
|
try:
|
||||||
|
ret.append(self.kids[i])
|
||||||
|
except IndexError:
|
||||||
|
pass
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def getTag(self, name, attrs={}, namespace=None):
|
def getTag(self, name, attrs={}, namespace=None):
|
||||||
''' Filters all child nodes using specified arguments as filter.
|
"""
|
||||||
Returns the first found or None if not found. '''
|
Filter all child nodes using specified arguments as filter. Return the
|
||||||
|
first found or None if not found
|
||||||
|
"""
|
||||||
return self.getTags(name, attrs, namespace, one=1)
|
return self.getTags(name, attrs, namespace, one=1)
|
||||||
def getTagAttr(self,tag,attr):
|
|
||||||
''' Returns attribute value of the child with specified name (or None if no such attribute).'''
|
def getTagAttr(self, tag, attr):
|
||||||
|
"""
|
||||||
|
Return attribute value of the child with specified name (or None if no
|
||||||
|
such attribute)
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
return self.getTag(tag).attrs[attr]
|
return self.getTag(tag).attrs[attr]
|
||||||
except:
|
except:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def getTagData(self,tag):
|
def getTagData(self,tag):
|
||||||
''' Returns cocatenated CDATA of the child with specified name.'''
|
"""
|
||||||
|
Return cocatenated CDATA of the child with specified name
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
return self.getTag(tag).getData()
|
return self.getTag(tag).getData()
|
||||||
except Exception:
|
except Exception:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def getTags(self, name, attrs={}, namespace=None, one=0):
|
def getTags(self, name, attrs={}, namespace=None, one=0):
|
||||||
''' Filters all child nodes using specified arguments as filter.
|
"""
|
||||||
Returns the list of nodes found. '''
|
Filter all child nodes using specified arguments as filter. Returns the
|
||||||
nodes=[]
|
list of nodes found
|
||||||
|
"""
|
||||||
|
nodes = []
|
||||||
for node in self.kids:
|
for node in self.kids:
|
||||||
if namespace and namespace!=node.getNamespace(): continue
|
if namespace and namespace != node.getNamespace():
|
||||||
|
continue
|
||||||
if node.getName() == name:
|
if node.getName() == name:
|
||||||
for key in attrs.keys():
|
for key in attrs.keys():
|
||||||
if key not in node.attrs or node.attrs[key]!=attrs[key]: break
|
if key not in node.attrs or node.attrs[key]!=attrs[key]:
|
||||||
else: nodes.append(node)
|
break
|
||||||
if one and nodes: return nodes[0]
|
else:
|
||||||
if not one: return nodes
|
nodes.append(node)
|
||||||
|
if one and nodes:
|
||||||
|
return nodes[0]
|
||||||
|
if not one:
|
||||||
|
return nodes
|
||||||
|
|
||||||
def iterTags(self, name, attrs={}, namespace=None):
|
def iterTags(self, name, attrs={}, namespace=None):
|
||||||
''' Iterate over all children using specified arguments as filter. '''
|
"""
|
||||||
|
Iterate over all children using specified arguments as filter
|
||||||
|
"""
|
||||||
for node in self.kids:
|
for node in self.kids:
|
||||||
if namespace is not None and namespace!=node.getNamespace(): continue
|
if namespace is not None and namespace != node.getNamespace():
|
||||||
|
continue
|
||||||
if node.getName() == name:
|
if node.getName() == name:
|
||||||
for key in attrs.keys():
|
for key in attrs.keys():
|
||||||
if key not in node.attrs or \
|
if key not in node.attrs or \
|
||||||
node.attrs[key]!=attrs[key]: break
|
node.attrs[key]!=attrs[key]:
|
||||||
|
break
|
||||||
else:
|
else:
|
||||||
yield node
|
yield node
|
||||||
|
|
||||||
def setAttr(self, key, val):
|
def setAttr(self, key, val):
|
||||||
''' Sets attribute "key" with the value "val". '''
|
"""
|
||||||
self.attrs[key]=val
|
Set attribute "key" with the value "val"
|
||||||
|
"""
|
||||||
|
self.attrs[key] = val
|
||||||
|
|
||||||
def setData(self, data):
|
def setData(self, data):
|
||||||
''' Sets node's CDATA to provided string. Resets all previous CDATA!'''
|
"""
|
||||||
self.data=[ustr(data)]
|
Set node's CDATA to provided string. Resets all previous CDATA!
|
||||||
def setName(self,val):
|
"""
|
||||||
''' Changes the node name. '''
|
self.data = [ustr(data)]
|
||||||
|
|
||||||
|
def setName(self, val):
|
||||||
|
"""
|
||||||
|
Change the node name
|
||||||
|
"""
|
||||||
self.name = val
|
self.name = val
|
||||||
|
|
||||||
def setNamespace(self, namespace):
|
def setNamespace(self, namespace):
|
||||||
''' Changes the node namespace. '''
|
"""
|
||||||
self.namespace=namespace
|
Changes the node namespace
|
||||||
|
"""
|
||||||
|
self.namespace = namespace
|
||||||
|
|
||||||
def setParent(self, node):
|
def setParent(self, node):
|
||||||
''' Sets node's parent to "node". WARNING: do not checks if the parent already present
|
"""
|
||||||
and not removes the node from the list of childs of previous parent. '''
|
Set node's parent to "node". WARNING: do not checks if the parent already
|
||||||
|
present and not removes the node from the list of childs of previous
|
||||||
|
parent
|
||||||
|
"""
|
||||||
self.parent = node
|
self.parent = node
|
||||||
def setPayload(self,payload,add=0):
|
|
||||||
''' Sets node payload according to the list specified. WARNING: completely replaces all node's
|
def setPayload(self, payload, add=0):
|
||||||
previous content. If you wish just to add child or CDATA - use addData or addChild methods. '''
|
"""
|
||||||
if isinstance(payload, basestring): payload=[payload]
|
Set node payload according to the list specified. WARNING: completely
|
||||||
if add: self.kids+=payload
|
replaces all node's previous content. If you wish just to add child or
|
||||||
else: self.kids=payload
|
CDATA - use addData or addChild methods
|
||||||
|
"""
|
||||||
|
if isinstance(payload, basestring):
|
||||||
|
payload = [payload]
|
||||||
|
if add:
|
||||||
|
self.kids += payload
|
||||||
|
else:
|
||||||
|
self.kids = payload
|
||||||
|
|
||||||
def setTag(self, name, attrs={}, namespace=None):
|
def setTag(self, name, attrs={}, namespace=None):
|
||||||
''' Same as getTag but if the node with specified namespace/attributes not found, creates such
|
"""
|
||||||
node and returns it. '''
|
Same as getTag but if the node with specified namespace/attributes not
|
||||||
node=self.getTags(name, attrs, namespace=namespace, one=1)
|
found, creates such node and returns it
|
||||||
if node: return node
|
"""
|
||||||
else: return self.addChild(name, attrs, namespace=namespace)
|
node = self.getTags(name, attrs, namespace=namespace, one=1)
|
||||||
def setTagAttr(self,tag,attr,val):
|
if node:
|
||||||
''' Creates new node (if not already present) with name "tag"
|
return node
|
||||||
and sets it's attribute "attr" to value "val". '''
|
else:
|
||||||
|
return self.addChild(name, attrs, namespace=namespace)
|
||||||
|
|
||||||
|
def setTagAttr(self, tag, attr, val):
|
||||||
|
"""
|
||||||
|
Create new node (if not already present) with name "tag" and set it's
|
||||||
|
attribute "attr" to value "val"
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
self.getTag(tag).attrs[attr]=val
|
self.getTag(tag).attrs[attr] = val
|
||||||
except Exception:
|
except Exception:
|
||||||
self.addChild(tag,attrs={attr:val})
|
self.addChild(tag, attrs={attr: val})
|
||||||
def setTagData(self,tag,val,attrs={}):
|
|
||||||
''' Creates new node (if not already present) with name "tag" and (optionally) attributes "attrs"
|
def setTagData(self, tag, val, attrs={}):
|
||||||
and sets it's CDATA to string "val". '''
|
"""
|
||||||
|
Creates new node (if not already present) with name "tag" and
|
||||||
|
(optionally) attributes "attrs" and sets it's CDATA to string "val"
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
self.getTag(tag,attrs).setData(ustr(val))
|
self.getTag(tag,attrs).setData(ustr(val))
|
||||||
except Exception:
|
except Exception:
|
||||||
self.addChild(tag,attrs,payload=[ustr(val)])
|
self.addChild(tag,attrs,payload = [ustr(val)])
|
||||||
def has_attr(self,key):
|
|
||||||
''' Checks if node have attribute "key".'''
|
def has_attr(self, key):
|
||||||
|
"""
|
||||||
|
Check if node have attribute "key"
|
||||||
|
"""
|
||||||
return key in self.attrs
|
return key in self.attrs
|
||||||
def __getitem__(self,item):
|
|
||||||
''' Returns node's attribute "item" value. '''
|
def __getitem__(self, item):
|
||||||
|
"""
|
||||||
|
Return node's attribute "item" value
|
||||||
|
"""
|
||||||
return self.getAttr(item)
|
return self.getAttr(item)
|
||||||
def __setitem__(self,item,val):
|
|
||||||
''' Sets node's attribute "item" value. '''
|
def __setitem__(self, item, val):
|
||||||
return self.setAttr(item,val)
|
"""
|
||||||
def __delitem__(self,item):
|
Set node's attribute "item" value
|
||||||
''' Deletes node's attribute "item". '''
|
"""
|
||||||
|
return self.setAttr(item, val)
|
||||||
|
|
||||||
|
def __delitem__(self, item):
|
||||||
|
"""
|
||||||
|
Delete node's attribute "item"
|
||||||
|
"""
|
||||||
return self.delAttr(item)
|
return self.delAttr(item)
|
||||||
def __contains__(self,item):
|
|
||||||
""" Checks if node has attribute "item" """
|
def __contains__(self, item):
|
||||||
|
"""
|
||||||
|
Check if node has attribute "item"
|
||||||
|
"""
|
||||||
return self.has_attr(item)
|
return self.has_attr(item)
|
||||||
def __getattr__(self,attr):
|
|
||||||
''' Reduce memory usage caused by T/NT classes - use memory only when needed. '''
|
def __getattr__(self, attr):
|
||||||
if attr=='T':
|
"""
|
||||||
self.T=T(self)
|
Reduce memory usage caused by T/NT classes - use memory only when needed
|
||||||
|
"""
|
||||||
|
if attr == 'T':
|
||||||
|
self.T = T(self)
|
||||||
return self.T
|
return self.T
|
||||||
if attr=='NT':
|
if attr == 'NT':
|
||||||
self.NT=NT(self)
|
self.NT = NT(self)
|
||||||
return self.NT
|
return self.NT
|
||||||
raise AttributeError
|
raise AttributeError
|
||||||
|
|
||||||
class T:
|
class T:
|
||||||
''' Auxiliary class used to quick access to node's child nodes. '''
|
"""
|
||||||
def __init__(self,node): self.__dict__['node']=node
|
Auxiliary class used to quick access to node's child nodes
|
||||||
def __getattr__(self,attr): return self.node.setTag(attr)
|
"""
|
||||||
def __setattr__(self,attr,val):
|
|
||||||
if isinstance(val,Node): Node.__init__(self.node.setTag(attr),node=val)
|
def __init__(self, node):
|
||||||
else: return self.node.setTagData(attr,val)
|
self.__dict__['node'] = node
|
||||||
def __delattr__(self,attr): return self.node.delChild(attr)
|
|
||||||
|
def __getattr__(self, attr):
|
||||||
|
return self.node.setTag(attr)
|
||||||
|
|
||||||
|
def __setattr__(self, attr, val):
|
||||||
|
if isinstance(val,Node):
|
||||||
|
Node.__init__(self.node.setTag(attr), node=val)
|
||||||
|
else:
|
||||||
|
return self.node.setTagData(attr, val)
|
||||||
|
|
||||||
|
def __delattr__(self, attr):
|
||||||
|
return self.node.delChild(attr)
|
||||||
|
|
||||||
class NT(T):
|
class NT(T):
|
||||||
''' Auxiliary class used to quick create node's child nodes. '''
|
"""
|
||||||
def __getattr__(self,attr): return self.node.addChild(attr)
|
Auxiliary class used to quick create node's child nodes
|
||||||
def __setattr__(self,attr,val):
|
"""
|
||||||
if isinstance(val,Node): self.node.addChild(attr,node=val)
|
|
||||||
else: return self.node.addChild(attr,payload=[val])
|
def __getattr__(self, attr):
|
||||||
|
return self.node.addChild(attr)
|
||||||
|
|
||||||
|
def __setattr__(self, attr, val):
|
||||||
|
if isinstance(val,Node):
|
||||||
|
self.node.addChild(attr,node=val)
|
||||||
|
else:
|
||||||
|
return self.node.addChild(attr, payload=[val])
|
||||||
|
|
||||||
class NodeBuilder:
|
class NodeBuilder:
|
||||||
''' Builds a Node class minidom from data parsed to it. This class used for two purposes:
|
"""
|
||||||
1. Creation an XML Node from a textual representation. F.e. reading a config file. See an XML2Node method.
|
Builds a Node class minidom from data parsed to it. This class used for two
|
||||||
2. Handling an incoming XML stream. This is done by mangling
|
purposes:
|
||||||
the __dispatch_depth parameter and redefining the dispatch method.
|
1. Creation an XML Node from a textual representation. F.e. reading a
|
||||||
You do not need to use this class directly if you do not designing your own XML handler.'''
|
config file. See an XML2Node method.
|
||||||
def __init__(self,data=None,initial_node=None):
|
2. Handling an incoming XML stream. This is done by mangling the
|
||||||
''' Takes two optional parameters: "data" and "initial_node".
|
__dispatch_depth parameter and redefining the dispatch method.
|
||||||
By default class initialised with empty Node class instance.
|
|
||||||
Though, if "initial_node" is provided it used as "starting point".
|
You do not need to use this class directly if you do not designing your own
|
||||||
You can think about it as of "node upgrade".
|
XML handler
|
||||||
"data" (if provided) feeded to parser immidiatedly after instance init.
|
"""
|
||||||
'''
|
|
||||||
|
def __init__(self, data=None, initial_node=None):
|
||||||
|
"""
|
||||||
|
Take two optional parameters: "data" and "initial_node"
|
||||||
|
|
||||||
|
By default class initialised with empty Node class instance. Though, if
|
||||||
|
"initial_node" is provided it used as "starting point". You can think
|
||||||
|
about it as of "node upgrade". "data" (if provided) feeded to parser
|
||||||
|
immidiatedly after instance init.
|
||||||
|
"""
|
||||||
log.debug("Preparing to handle incoming XML stream.")
|
log.debug("Preparing to handle incoming XML stream.")
|
||||||
self._parser = xml.parsers.expat.ParserCreate()
|
self._parser = xml.parsers.expat.ParserCreate()
|
||||||
self._parser.StartElementHandler = self.starttag
|
self._parser.StartElementHandler = self.starttag
|
||||||
|
@ -369,7 +550,9 @@ class NodeBuilder:
|
||||||
self.data_buffer = None
|
self.data_buffer = None
|
||||||
|
|
||||||
def destroy(self):
|
def destroy(self):
|
||||||
''' Method used to allow class instance to be garbage-collected. '''
|
"""
|
||||||
|
Method used to allow class instance to be garbage-collected
|
||||||
|
"""
|
||||||
self.check_data_buffer()
|
self.check_data_buffer()
|
||||||
self._parser.StartElementHandler = None
|
self._parser.StartElementHandler = None
|
||||||
self._parser.EndElementHandler = None
|
self._parser.EndElementHandler = None
|
||||||
|
@ -377,7 +560,9 @@ class NodeBuilder:
|
||||||
self._parser.StartNamespaceDeclHandler = None
|
self._parser.StartNamespaceDeclHandler = None
|
||||||
|
|
||||||
def starttag(self, tag, attrs):
|
def starttag(self, tag, attrs):
|
||||||
'''XML Parser callback. Used internally'''
|
"""
|
||||||
|
XML Parser callback. Used internally
|
||||||
|
"""
|
||||||
self.check_data_buffer()
|
self.check_data_buffer()
|
||||||
self._inc_depth()
|
self._inc_depth()
|
||||||
log.info("STARTTAG.. DEPTH -> %i , tag -> %s, attrs -> %s" % (self.__depth, tag, `attrs`))
|
log.info("STARTTAG.. DEPTH -> %i , tag -> %s, attrs -> %s" % (self.__depth, tag, `attrs`))
|
||||||
|
@ -410,8 +595,11 @@ class NodeBuilder:
|
||||||
if not self.last_is_data and self._ptr.parent:
|
if not self.last_is_data and self._ptr.parent:
|
||||||
self._ptr.parent.data.append('')
|
self._ptr.parent.data.append('')
|
||||||
self.last_is_data = 0
|
self.last_is_data = 0
|
||||||
|
|
||||||
def endtag(self, tag ):
|
def endtag(self, tag ):
|
||||||
'''XML Parser callback. Used internally'''
|
"""
|
||||||
|
XML Parser callback. Used internally
|
||||||
|
"""
|
||||||
log.info("DEPTH -> %i , tag -> %s" % (self.__depth, tag))
|
log.info("DEPTH -> %i , tag -> %s" % (self.__depth, tag))
|
||||||
self.check_data_buffer()
|
self.check_data_buffer()
|
||||||
if self.__depth == self._dispatch_depth:
|
if self.__depth == self._dispatch_depth:
|
||||||
|
@ -439,25 +627,42 @@ class NodeBuilder:
|
||||||
self.last_is_data = 1
|
self.last_is_data = 1
|
||||||
|
|
||||||
def handle_namespace_start(self, prefix, uri):
|
def handle_namespace_start(self, prefix, uri):
|
||||||
'''XML Parser callback. Used internally'''
|
"""
|
||||||
|
XML Parser callback. Used internally
|
||||||
|
"""
|
||||||
self.check_data_buffer()
|
self.check_data_buffer()
|
||||||
|
|
||||||
def getDom(self):
|
def getDom(self):
|
||||||
''' Returns just built Node. '''
|
"""
|
||||||
|
Return just built Node
|
||||||
|
"""
|
||||||
self.check_data_buffer()
|
self.check_data_buffer()
|
||||||
return self._mini_dom
|
return self._mini_dom
|
||||||
def dispatch(self,stanza):
|
|
||||||
''' Gets called when the NodeBuilder reaches some level of depth on it's way up with the built
|
def dispatch(self, stanza):
|
||||||
node as argument. Can be redefined to convert incoming XML stanzas to program events. '''
|
"""
|
||||||
def stream_header_received(self,ns,tag,attrs):
|
Get called when the NodeBuilder reaches some level of depth on it's way
|
||||||
''' Method called when stream just opened. '''
|
up with the built node as argument. Can be redefined to convert incoming
|
||||||
|
XML stanzas to program events
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def stream_header_received(self, ns, tag, attrs):
|
||||||
|
"""
|
||||||
|
Method called when stream just opened
|
||||||
|
"""
|
||||||
self.check_data_buffer()
|
self.check_data_buffer()
|
||||||
|
|
||||||
def stream_footer_received(self):
|
def stream_footer_received(self):
|
||||||
''' Method called when stream just closed. '''
|
"""
|
||||||
|
Method called when stream just closed
|
||||||
|
"""
|
||||||
self.check_data_buffer()
|
self.check_data_buffer()
|
||||||
|
|
||||||
def has_received_endtag(self, level=0):
|
def has_received_endtag(self, level=0):
|
||||||
''' Return True if at least one end tag was seen (at level) '''
|
"""
|
||||||
|
Return True if at least one end tag was seen (at level)
|
||||||
|
"""
|
||||||
return self.__depth <= level and self.__max_depth > level
|
return self.__depth <= level and self.__max_depth > level
|
||||||
|
|
||||||
def _inc_depth(self):
|
def _inc_depth(self):
|
||||||
|
@ -470,14 +675,20 @@ class NodeBuilder:
|
||||||
self.__depth -= 1
|
self.__depth -= 1
|
||||||
|
|
||||||
def XML2Node(xml):
|
def XML2Node(xml):
|
||||||
''' Converts supplied textual string into XML node. Handy f.e. for reading configuration file.
|
"""
|
||||||
Raises xml.parser.expat.parsererror if provided string is not well-formed XML. '''
|
Convert supplied textual string into XML node. Handy f.e. for reading
|
||||||
|
configuration file. Raises xml.parser.expat.parsererror if provided string
|
||||||
|
is not well-formed XML
|
||||||
|
"""
|
||||||
return NodeBuilder(xml).getDom()
|
return NodeBuilder(xml).getDom()
|
||||||
|
|
||||||
def BadXML2Node(xml):
|
def BadXML2Node(xml):
|
||||||
''' Converts supplied textual string into XML node. Survives if xml data is cutted half way round.
|
"""
|
||||||
I.e. "<html>some text <br>some more text". Will raise xml.parser.expat.parsererror on misplaced
|
Convert supplied textual string into XML node. Survives if xml data is
|
||||||
tags though. F.e. "<b>some text <br>some more text</b>" will not work.'''
|
cutted half way round. I.e. "<html>some text <br>some more text". Will raise
|
||||||
|
xml.parser.expat.parsererror on misplaced tags though. F.e. "<b>some text
|
||||||
|
<br>some more text</b>" will not work
|
||||||
|
"""
|
||||||
return NodeBuilder(xml).getDom()
|
return NodeBuilder(xml).getDom()
|
||||||
|
|
||||||
# vim: se ts=3:
|
# vim: se ts=3:
|
||||||
|
|
Loading…
Reference in New Issue