Commit c85273d5 authored by Yann Leboulanger's avatar Yann Leboulanger

switch from jabberpy to xmpppy

parent 581b387b
This diff is collapsed.
This diff is collapsed.
# $Id: __init__.py,v 1.9 2005/03/07 09:34:51 snakeru Exp $
"""
All features of xmpppy library contained within separate modules.
At present there are modules:
simplexml - XML handling routines
protocol - jabber-objects (I.e. JID and different stanzas and sub-stanzas) handling routines.
debug - Jacob Lundquist's debugging module. Very handy if you like colored debug.
auth - Non-SASL and SASL stuff. You will need it to auth as a client or transport.
transports - low level connection handling. TCP and TLS currently. HTTP support planned.
roster - simple roster for use in clients.
dispatcher - decision-making logic. Handles all hooks. The first who takes control over fresh stanzas.
features - different stuff that didn't worths separating into modules
browser - DISCO server framework. Allows to build dynamic disco tree.
filetransfer - Currently contains only IBB stuff. Can be used for bot-to-bot transfers.
Most of the classes that is defined in all these modules is an ancestors of
class PlugIn so they share a single set of methods allowing you to compile
a featured XMPP client. For every instance of PlugIn class the 'owner' is the class
in what the plug was plugged. While plugging in such instance usually sets some
methods of owner to it's own ones for easy access. All session specific info stored
either in instance of PlugIn or in owner's instance. This is considered unhandy
and there are plans to port 'Session' class from xmppd.py project for storing all
session-related info. Though if you are not accessing instances variables directly
and use only methods for access all values you should not have any problems.
"""
import simplexml,protocol,debug,auth,transports,roster,dispatcher,features,browser,filetransfer
from client import *
from protocol import *
This diff is collapsed.
## browser.py
##
## Copyright (C) 2004 Alexey "Snake" Nezhdanov
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2, or (at your option)
## any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
# $Id: browser.py,v 1.8 2004/12/24 19:56:35 snakeru Exp $
"""Browser module provides DISCO server framework for your application.
This functionality can be used for very different purposes - from publishing
software version and supported features to building of "jabber site" that users
can navigate with their disco browsers and interact with active content.
Such functionality is achieved via registering "DISCO handlers" that are
automatically called when user requests some node of your disco tree.
"""
from dispatcher import *
from client import PlugIn
class Browser(PlugIn):
""" Standart xmpppy class that is ancestor of PlugIn and can be attached
to your application.
All processing will be performed in the handlers registered in the browser
instance. You can register any number of handlers ensuring that for each
node/jid combination only one (or none) handler registered.
You can register static information or the fully-blown function that will
calculate the answer dynamically.
Example of static info (see JEP-0030, examples 13-14):
# cl - your xmpppy connection instance.
b=xmpp.browser.Browser()
b.PlugIn(cl)
items=[]
item={}
item['jid']='catalog.shakespeare.lit'
item['node']='books'
item['name']='Books by and about Shakespeare'
items.append(item)
item={}
item['jid']='catalog.shakespeare.lit'
item['node']='clothing'
item['name']='Wear your literary taste with pride'
items.append(item)
item={}
item['jid']='catalog.shakespeare.lit'
item['node']='music'
item['name']='Music from the time of Shakespeare'
items.append(item)
info={'ids':[], 'features':[]}
b.setDiscoHandler({'items':items,'info':info})
items should be a list of item elements.
every item element can have any of these four keys: 'jid', 'node', 'name', 'action'
info should be a dicionary and must have keys 'ids' and 'features'.
Both of them should be lists:
ids is a list of dictionaries and features is a list of text strings.
Example (see JEP-0030, examples 1-2)
# cl - your xmpppy connection instance.
b=xmpp.browser.Browser()
b.PlugIn(cl)
items=[]
ids=[]
ids.append({'category':'conference','type':'text','name':'Play-Specific Chatrooms'})
ids.append({'category':'directory','type':'chatroom','name':'Play-Specific Chatrooms'})
features=[NS_DISCO_INFO,NS_DISCO_ITEMS,NS_MUC,NS_REGISTER,NS_SEARCH,NS_TIME,NS_VERSION]
info={'ids':ids,'features':features}
# info['xdata']=xmpp.protocol.DataForm() # JEP-0128
b.setDiscoHandler({'items':[],'info':info})
"""
def __init__(self):
"""Initialises internal variables. Used internally."""
PlugIn.__init__(self)
DBG_LINE='browser'
self._exported_methods=[]
self._handlers={'':{}}
def plugin(self, owner):
""" Registers it's own iq handlers in your application dispatcher instance.
Used internally."""
owner.RegisterHandler('iq',self._DiscoveryHandler,ns=NS_DISCO_INFO)
owner.RegisterHandler('iq',self._DiscoveryHandler,ns=NS_DISCO_ITEMS)
def plugout(self):
""" Unregisters browser's iq handlers from your application dispatcher instance.
Used internally."""
self._owner.UnregisterHandler('iq',self._DiscoveryHandler,ns=NS_DISCO_INFO)
self._owner.UnregisterHandler('iq',self._DiscoveryHandler,ns=NS_DISCO_ITEMS)
def _traversePath(self,node,jid,set=0):
""" Returns dictionary and key or None,None
None - root node (w/o "node" attribute)
/a/b/c - node
/a/b/ - branch
Set returns '' or None as the key
get returns '' or None as the key or None as the dict.
Used internally."""
if self._handlers.has_key(jid): cur=self._handlers[jid]
elif set:
self._handlers[jid]={}
cur=self._handlers[jid]
else: cur=self._handlers['']
if node is None: node=[None]
else: node=node.replace('/',' /').split('/')
for i in node:
if i<>'' and cur.has_key(i): cur=cur[i]
elif set and i<>'': cur[i]={dict:cur,str:i}; cur=cur[i]
elif set or cur.has_key(''): return cur,''
else: return None,None
if cur.has_key(1) or set: return cur,1
raise "Corrupted data"
def setDiscoHandler(self,handler,node='',jid=''):
""" This is the main method that you will use in this class.
It is used to register supplied DISCO handler (or dictionary with static info)
as handler of some disco tree branch.
If you do not specify the node this handler will be used for all queried nodes.
If you do not specify the jid this handler will be used for all queried JIDs.
Usage:
cl.Browser.setDiscoHandler(someDict,node,jid)
or
cl.Browser.setDiscoHandler(someDISCOHandler,node,jid)
where
someDict={
'items':[
{'jid':'jid1','action':'action1','node':'node1','name':'name1'},
{'jid':'jid2','action':'action2','node':'node2','name':'name2'},
{'jid':'jid3','node':'node3','name':'name3'},
{'jid':'jid4','node':'node4'}
]
'info' :{
'ids':[
{'category':'category1','type':'type1','name':'name1'},
{'category':'category2','type':'type2','name':'name2'},
{'category':'category3','type':'type3','name':'name3'},
],
'features':['feature1','feature2','feature3','feature4'],
'xdata':DataForm
}
}
and/or
def someDISCOHandler(session,request,TYR):
# if TYR=='items': # returns items list of the same format as shown above
# elif TYR=='info': # returns info dictionary of the same format as shown above
# else: # this case is impossible for now.
"""
node,key=self._traversePath(node,jid,1)
node[key]=handler
def getDiscoHandler(self,node='',jid=''):
""" Returns the previously registered DISCO handler
that is resonsible for this node/jid combination.
Used internally."""
node,key=self._traversePath(node,jid)
if node: return node[key]
def delDiscoHandler(self,node='',jid=''):
""" Unregisters DISCO handler that is resonsible for this
node/jid combination. When handler is unregistered the branch
is handled in the same way that it's parent branch from this moment.
"""
node,key=self._traversePath(node,jid)
if node:
handler=node[key]
del node[dict][node[str]]
return handler
def _DiscoveryHandler(self,conn,request):
""" Servers DISCO iq request from the remote client.
Automatically determines the best handler to use and calls it
to handle the request. Used internally.
"""
handler=self.getDiscoHandler(request.getQuerynode(),request.getTo())
if not handler: return conn.send(Error(request,ERR_ITEM_NOT_FOUND))
rep=request.buildReply('result')
q=rep.getTag('query')
if request.getQueryNS()==NS_DISCO_ITEMS:
# handler must return list: [{jid,action,node,name}]
if type(handler)==dict: lst=handler['items']
else: lst=handler(conn,request,'items')
for item in lst: q.addChild('item',item)
elif request.getQueryNS()==NS_DISCO_INFO:
if type(handler)==dict: dt=handler['info']
else: dt=handler(conn,request,'info')
# handler must return dictionary:
# {'ids':[{},{},{},{}], 'features':[fe,at,ur,es], 'xdata':DataForm}
for id in dt['ids']: q.addChild('identity',id)
for feature in dt['features']: q.addChild('feature',{'var':feature})
if dt.has_key('xdata'): q.addChild(node=dt['xdata'])
conn.send(rep)
raise NodeProcessed
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
## features.py
##
## Copyright (C) 2003-2004 Alexey "Snake" Nezhdanov
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2, or (at your option)
## any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
# $Id: features.py,v 1.19 2004/12/25 20:06:59 snakeru Exp $
"""
This module contains variable stuff that is not worth splitting into separate modules.
Here is:
DISCO client and agents-to-DISCO and browse-to-DISCO emulators.
IBR and password manager.
jabber:iq:privacy methods
All these methods takes 'disp' first argument that should be already connected
(and in most cases already authorised) dispatcher instance.
"""
from protocol import *
### DISCO ### http://jabber.org/protocol/disco ### JEP-0030 ####################
### Browse ### jabber:iq:browse ### JEP-0030 ###################################
### Agents ### jabber:iq:agents ### JEP-0030 ###################################
def _discover(disp,ns,jid,node=None,fb2b=0,fb2a=1):
""" Try to obtain info from the remote object.
If remote object doesn't support disco fall back to browse (if fb2b is true)
and if it doesnt support browse (or fb2b is not true) fall back to agents protocol
(if gb2a is true). Returns obtained info. Used internally. """
iq=Iq(to=jid,typ='get',queryNS=ns)
if node: iq.setAttr('node',node)
rep=disp.SendAndWaitForResponse(iq)
if fb2b and not isResultNode(rep): rep=disp.SendAndWaitForResponse(Iq(to=jid,typ='get',queryNS=NS_BROWSE)) # Fallback to browse
if fb2a and not isResultNode(rep): rep=disp.SendAndWaitForResponse(Iq(to=jid,typ='get',queryNS=NS_AGENTS)) # Fallback to agents
if isResultNode(rep): return rep.getQueryPayload()
return []
def discoverItems(disp,jid,node=None):
""" Query remote object about any items that it contains. Return items list. """
""" According to JEP-0030:
query MAY have node attribute
item: MUST HAVE jid attribute and MAY HAVE name, node, action attributes.
action attribute of item can be either of remove or update value."""
ret=[]
for i in _discover(disp,NS_DISCO_ITEMS,jid,node):
if i.getName()=='agent' and i.getTag('name'): i.setAttr('name',i.getTagData('name'))
ret.append(i.attrs)
return ret
def discoverInfo(disp,jid,node=None):
""" Query remote object about info that it publishes. Returns identities and features lists."""
""" According to JEP-0030:
query MAY have node attribute
identity: MUST HAVE category and name attributes and MAY HAVE type attribute.
feature: MUST HAVE var attribute"""
identities , features = [] , []
for i in _discover(disp,NS_DISCO_INFO,jid,node):
if i.getName()=='identity': identities.append(i.attrs)
elif i.getName()=='feature': features.append(i.getAttr('var'))
elif i.getName()=='agent':
if i.getTag('name'): i.setAttr('name',i.getTagData('name'))
if i.getTag('description'): i.setAttr('name',i.getTagData('description'))
identities.append(i.attrs)
if i.getTag('groupchat'): features.append(NS_GROUPCHAT)
if i.getTag('register'): features.append(NS_REGISTER)
if i.getTag('search'): features.append(NS_SEARCH)
return identities , features
### Registration ### jabber:iq:register ### JEP-0077 ###########################
def getRegInfo(disp,host,info={}):
""" Gets registration form from remote host.
You can pre-fill the info dictionary.
F.e. if you are requesting info on registering user joey than specify
info as {'username':'joey'}. See JEP-0077 for details.
'disp' must be connected dispatcher instance."""
iq=Iq('get',NS_REGISTER,to=host)
for i in info.keys(): iq.setTagData(i,info[i])
resp=disp.SendAndWaitForResponse(iq)
if not isResultNode(resp): return
df=resp.getTag('query',namespace=NS_REGISTER).getTag('x',namespace=NS_DATA)
if df: return DataForm(node=df)
df=DataForm(typ='form')
for i in resp.getQueryPayload():
if i.getName()=='instructions': df.addInstructions(i.getData())
else: df.setField(i.getName()).setValue(i.getData())
return df
def register(disp,host,info):
""" Perform registration on remote server with provided info.
disp must be connected dispatcher instance.
Returns true or false depending on registration result.
If registration fails you can get additional info from the dispatcher's owner
attributes lastErrNode, lastErr and lastErrCode.
"""
iq=Iq('set',NS_REGISTER,to=host)
if type(info)<>type({}): info=info.asDict()
for i in info.keys(): iq.setTag('query').setTagData(i,info[i])
resp=disp.SendAndWaitForResponse(iq)
if isResultNode(resp): return 1
def unregister(disp,host):
""" Unregisters with host (permanently removes account).
disp must be connected and authorized dispatcher instance.
Returns true on success."""
resp=disp.SendAndWaitForResponse(Iq('set',NS_REGISTER,to=host,payload=[Node('remove')]))
if isResultNode(resp): return 1
def changePasswordTo(disp,newpassword,host=None):
""" Changes password on specified or current (if not specified) server.
disp must be connected and authorized dispatcher instance.
Returns true on success."""
if not host: host=disp._owner.Server
resp=disp.SendAndWaitForResponse(Iq('set',NS_REGISTER,to=host,payload=[Node('username',payload=[disp._owner.Server]),Node('password',payload=[newpassword])]))
if isResultNode(resp): return 1
### Privacy ### jabber:iq:privacy ### draft-ietf-xmpp-im-19 ####################
#type=[jid|group|subscription]
#action=[allow|deny]
def getPrivacyLists(disp):
""" Requests privacy lists from connected server.
Returns dictionary of existing lists on success."""
try:
dict={'lists':[]}
resp=disp.SendAndWaitForResponse(Iq('get',NS_PRIVACY))
if not isResultNode(resp): return
for list in resp.getQueryPayload():
if list.getName()=='list': dict['lists'].append(list.getAttr('name'))
else: dict[list.getName()]=list.getAttr('name')
return dict
except: pass
def getPrivacyList(disp,listname):
""" Requests specific privacy list listname. Returns list of XML nodes (rules)
taken from the server responce."""
try:
resp=disp.SendAndWaitForResponse(Iq('get',NS_PRIVACY,payload=[Node('list',{'name':listname})]))
if isResultNode(resp): return resp.getQueryPayload()[0]
except: pass
def setActivePrivacyList(disp,listname=None,typ='active'):
""" Switches privacy list 'listname' to specified type.
By default the type is 'active'. Returns true on success."""
if listname: attrs={'name':listname}
else: attrs={}
resp=disp.SendAndWaitForResponse(Iq('set',NS_PRIVACY,payload=[Node(typ,attrs)]))
if isResultNode(resp): return 1
def setDefaultPrivacyList(disp,listname=None):
""" Sets the default privacy list as 'listname'. Returns true on success."""
return setActivePrivacyList(disp,listname,'default')
def setPrivacyList(disp,list):
""" Set the ruleset. 'list' should be the simpleXML node formatted
according to RFC 3921 (XMPP-IM) (I.e. Node('list',{'name':listname},payload=[...]) )
Returns true on success."""
resp=disp.SendAndWaitForResponse(Iq('set',NS_PRIVACY,payload=[payload]))
if isResultNode(resp): return 1
def delPrivacyList(disp,listname):
""" Deletes privacy list 'listname'. Returns true on success."""
resp=disp.SendAndWaitForResponse(Iq('set',NS_PRIVACY,payload=[Node('list',{'name':listname})]))
if isResultNode(resp): return 1
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -1334,7 +1334,7 @@ class Service_registration_window:
'offline', 'from', '', '', 0, '')
self.plugin.roster.contacts[self.account][self.service] = [user1]
self.plugin.roster.add_user_to_roster(self.service, self.account)
gajim.connections[self.account].register_agent(self.service)
gajim.connections[self.account].register_agent(self.service, self.infos)
self.window.destroy()
def __init__(self, service, infos, plugin, account):
......@@ -1767,7 +1767,7 @@ class Service_discovery_window:
jid = model.get_value(iter, 1)
node = model.get_value(iter, 2)
if self.agent_infos[jid + node].has_key('features'):
if common.jabber.NS_REGISTER in self.agent_infos[jid + node] \
if common.xmpp.NS_REGISTER in self.agent_infos[jid + node] \
['features']:
self.register_button.set_sensitive(True)
if self.agent_infos[jid + node].has_key('identities'):
......
......@@ -136,10 +136,8 @@ class Interface:
gobject.timeout_add(10000, self.play_timeout, pid)
def handle_event_roster(self, account, data):
#('ROSTER', account, (state, array))
statuss = ['offline', 'online', 'away', 'xa', 'dnd', 'invisible']
self.roster.on_status_changed(account, statuss[data[0]])
self.roster.mklists(data[1], account)
#('ROSTER', account, array)
self.roster.mklists(data, account)
self.roster.draw_roster()
def handle_event_warning(self, unused, msg):
......
......@@ -368,13 +368,14 @@ class Roster_window:
else:
name = jid.split('@')[0]
#get show
show = array[jid]['show']
if not show:
show = 'offline'
# show = array[jid]['show']
# if not show:
show = 'offline'
status = ''
user1 = User(ji, name, array[jid]['groups'],
show, array[jid]['status'],
array[jid]['sub'], array[jid]['ask'],
show, status,
array[jid]['subscription'], array[jid]['ask'],
resource, 0, '')
# when we draw the roster, we can't have twice the same
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment