xmpp: import xmppy-0.5.0rc1
[uccdoor.git] / xmpp / features.py
1 ##   features.py 
2 ##
3 ##   Copyright (C) 2003-2004 Alexey "Snake" Nezhdanov
4 ##
5 ##   This program is free software; you can redistribute it and/or modify
6 ##   it under the terms of the GNU General Public License as published by
7 ##   the Free Software Foundation; either version 2, or (at your option)
8 ##   any later version.
9 ##
10 ##   This program is distributed in the hope that it will be useful,
11 ##   but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ##   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 ##   GNU General Public License for more details.
14
15 # $Id: features.py,v 1.25 2009/04/07 07:11:48 snakeru Exp $
16
17 """
18 This module contains variable stuff that is not worth splitting into separate modules.
19 Here is:
20     DISCO client and agents-to-DISCO and browse-to-DISCO emulators.
21     IBR and password manager.
22     jabber:iq:privacy methods
23 All these methods takes 'disp' first argument that should be already connected
24 (and in most cases already authorised) dispatcher instance.
25 """
26
27 from protocol import *
28
29 REGISTER_DATA_RECEIVED='REGISTER DATA RECEIVED'
30
31 ### DISCO ### http://jabber.org/protocol/disco ### JEP-0030 ####################
32 ### Browse ### jabber:iq:browse ### JEP-0030 ###################################
33 ### Agents ### jabber:iq:agents ### JEP-0030 ###################################
34 def _discover(disp,ns,jid,node=None,fb2b=0,fb2a=1):
35     """ Try to obtain info from the remote object.
36         If remote object doesn't support disco fall back to browse (if fb2b is true)
37         and if it doesnt support browse (or fb2b is not true) fall back to agents protocol
38         (if gb2a is true). Returns obtained info. Used internally. """
39     iq=Iq(to=jid,typ='get',queryNS=ns)
40     if node: iq.setQuerynode(node)
41     rep=disp.SendAndWaitForResponse(iq)
42     if fb2b and not isResultNode(rep): rep=disp.SendAndWaitForResponse(Iq(to=jid,typ='get',queryNS=NS_BROWSE))   # Fallback to browse
43     if fb2a and not isResultNode(rep): rep=disp.SendAndWaitForResponse(Iq(to=jid,typ='get',queryNS=NS_AGENTS))   # Fallback to agents
44     if isResultNode(rep): return [n for n in rep.getQueryPayload() if isinstance(n, Node)]
45     return []
46
47 def discoverItems(disp,jid,node=None):
48     """ Query remote object about any items that it contains. Return items list. """
49     """ According to JEP-0030:
50         query MAY have node attribute
51         item: MUST HAVE jid attribute and MAY HAVE name, node, action attributes.
52         action attribute of item can be either of remove or update value."""
53     ret=[]
54     for i in _discover(disp,NS_DISCO_ITEMS,jid,node):
55         if i.getName()=='agent' and i.getTag('name'): i.setAttr('name',i.getTagData('name'))
56         ret.append(i.attrs)
57     return ret
58
59 def discoverInfo(disp,jid,node=None):
60     """ Query remote object about info that it publishes. Returns identities and features lists."""
61     """ According to JEP-0030:
62         query MAY have node attribute
63         identity: MUST HAVE category and name attributes and MAY HAVE type attribute.
64         feature: MUST HAVE var attribute"""
65     identities , features = [] , []
66     for i in _discover(disp,NS_DISCO_INFO,jid,node):
67         if i.getName()=='identity': identities.append(i.attrs)
68         elif i.getName()=='feature': features.append(i.getAttr('var'))
69         elif i.getName()=='agent':
70             if i.getTag('name'): i.setAttr('name',i.getTagData('name'))
71             if i.getTag('description'): i.setAttr('name',i.getTagData('description'))
72             identities.append(i.attrs)
73             if i.getTag('groupchat'): features.append(NS_GROUPCHAT)
74             if i.getTag('register'): features.append(NS_REGISTER)
75             if i.getTag('search'): features.append(NS_SEARCH)
76     return identities , features
77
78 ### Registration ### jabber:iq:register ### JEP-0077 ###########################
79 def getRegInfo(disp,host,info={},sync=True):
80     """ Gets registration form from remote host.
81         You can pre-fill the info dictionary.
82         F.e. if you are requesting info on registering user joey than specify 
83         info as {'username':'joey'}. See JEP-0077 for details.
84         'disp' must be connected dispatcher instance."""
85     iq=Iq('get',NS_REGISTER,to=host)
86     for i in info.keys(): iq.setTagData(i,info[i])
87     if sync:
88         resp=disp.SendAndWaitForResponse(iq)
89         _ReceivedRegInfo(disp.Dispatcher,resp, host)
90         return resp
91     else: disp.SendAndCallForResponse(iq,_ReceivedRegInfo, {'agent': host})
92
93 def _ReceivedRegInfo(con, resp, agent):
94     iq=Iq('get',NS_REGISTER,to=agent)
95     if not isResultNode(resp): return
96     df=resp.getTag('query',namespace=NS_REGISTER).getTag('x',namespace=NS_DATA)
97     if df:
98         con.Event(NS_REGISTER,REGISTER_DATA_RECEIVED,(agent, DataForm(node=df)))
99         return
100     df=DataForm(typ='form')
101     for i in resp.getQueryPayload():
102         if type(i)<>type(iq): pass
103         elif i.getName()=='instructions': df.addInstructions(i.getData())
104         else: df.setField(i.getName()).setValue(i.getData())
105     con.Event(NS_REGISTER,REGISTER_DATA_RECEIVED,(agent, df))
106
107 def register(disp,host,info):
108     """ Perform registration on remote server with provided info.
109         disp must be connected dispatcher instance.
110         Returns true or false depending on registration result.
111         If registration fails you can get additional info from the dispatcher's owner
112         attributes lastErrNode, lastErr and lastErrCode.
113     """
114     iq=Iq('set',NS_REGISTER,to=host)
115     if type(info)<>type({}): info=info.asDict()
116     for i in info.keys(): iq.setTag('query').setTagData(i,info[i])
117     resp=disp.SendAndWaitForResponse(iq)
118     if isResultNode(resp): return 1
119
120 def unregister(disp,host):
121     """ Unregisters with host (permanently removes account).
122         disp must be connected and authorized dispatcher instance.
123         Returns true on success."""
124     resp=disp.SendAndWaitForResponse(Iq('set',NS_REGISTER,to=host,payload=[Node('remove')]))
125     if isResultNode(resp): return 1
126
127 def changePasswordTo(disp,newpassword,host=None):
128     """ Changes password on specified or current (if not specified) server.
129         disp must be connected and authorized dispatcher instance.
130         Returns true on success."""
131     if not host: host=disp._owner.Server
132     resp=disp.SendAndWaitForResponse(Iq('set',NS_REGISTER,to=host,payload=[Node('username',payload=[disp._owner.Server]),Node('password',payload=[newpassword])]))
133     if isResultNode(resp): return 1
134
135 ### Privacy ### jabber:iq:privacy ### draft-ietf-xmpp-im-19 ####################
136 #type=[jid|group|subscription]
137 #action=[allow|deny]
138
139 def getPrivacyLists(disp):
140     """ Requests privacy lists from connected server.
141         Returns dictionary of existing lists on success."""
142     try:
143         dict={'lists':[]}
144         resp=disp.SendAndWaitForResponse(Iq('get',NS_PRIVACY))
145         if not isResultNode(resp): return
146         for list in resp.getQueryPayload():
147             if list.getName()=='list': dict['lists'].append(list.getAttr('name'))
148             else: dict[list.getName()]=list.getAttr('name')
149         return dict
150     except: pass
151
152 def getPrivacyList(disp,listname):
153     """ Requests specific privacy list listname. Returns list of XML nodes (rules)
154         taken from the server responce."""
155     try:
156         resp=disp.SendAndWaitForResponse(Iq('get',NS_PRIVACY,payload=[Node('list',{'name':listname})]))
157         if isResultNode(resp): return resp.getQueryPayload()[0]
158     except: pass
159
160 def setActivePrivacyList(disp,listname=None,typ='active'):
161     """ Switches privacy list 'listname' to specified type.
162         By default the type is 'active'. Returns true on success."""
163     if listname: attrs={'name':listname}
164     else: attrs={}
165     resp=disp.SendAndWaitForResponse(Iq('set',NS_PRIVACY,payload=[Node(typ,attrs)]))
166     if isResultNode(resp): return 1
167
168 def setDefaultPrivacyList(disp,listname=None):
169     """ Sets the default privacy list as 'listname'. Returns true on success."""
170     return setActivePrivacyList(disp,listname,'default')
171
172 def setPrivacyList(disp,list):
173     """ Set the ruleset. 'list' should be the simpleXML node formatted
174         according to RFC 3921 (XMPP-IM) (I.e. Node('list',{'name':listname},payload=[...]) )
175         Returns true on success."""
176     resp=disp.SendAndWaitForResponse(Iq('set',NS_PRIVACY,payload=[list]))
177     if isResultNode(resp): return 1
178
179 def delPrivacyList(disp,listname):
180     """ Deletes privacy list 'listname'. Returns true on success."""
181     resp=disp.SendAndWaitForResponse(Iq('set',NS_PRIVACY,payload=[Node('list',{'name':listname})]))
182     if isResultNode(resp): return 1

UCC git Repository :: git.ucc.asn.au