Mercurial > libervia-backend
comparison sat/plugins/plugin_xep_0050.py @ 2624:56f94936df1e
code style reformatting using black
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 27 Jun 2018 20:14:46 +0200 |
parents | 0112c1f7dcf0 |
children | 8dd9db785ac8 |
comparison
equal
deleted
inserted
replaced
2623:49533de4540b | 2624:56f94936df1e |
---|---|
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. | 18 # along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 | 19 |
20 from sat.core.i18n import _, D_ | 20 from sat.core.i18n import _, D_ |
21 from sat.core.constants import Const as C | 21 from sat.core.constants import Const as C |
22 from sat.core.log import getLogger | 22 from sat.core.log import getLogger |
23 | |
23 log = getLogger(__name__) | 24 log = getLogger(__name__) |
24 from twisted.words.protocols.jabber import jid | 25 from twisted.words.protocols.jabber import jid |
25 from twisted.words.protocols import jabber | 26 from twisted.words.protocols import jabber |
26 from twisted.words.xish import domish | 27 from twisted.words.xish import domish |
27 from twisted.internet import defer | 28 from twisted.internet import defer |
39 from wokkel.subprotocols import XMPPHandler | 40 from wokkel.subprotocols import XMPPHandler |
40 | 41 |
41 from collections import namedtuple | 42 from collections import namedtuple |
42 | 43 |
43 try: | 44 try: |
44 from collections import OrderedDict # only available from python 2.7 | 45 from collections import OrderedDict # only available from python 2.7 |
45 except ImportError: | 46 except ImportError: |
46 from ordereddict import OrderedDict | 47 from ordereddict import OrderedDict |
47 | 48 |
48 IQ_SET = '/iq[@type="set"]' | 49 IQ_SET = '/iq[@type="set"]' |
49 NS_COMMANDS = "http://jabber.org/protocol/commands" | 50 NS_COMMANDS = "http://jabber.org/protocol/commands" |
50 ID_CMD_LIST = disco.DiscoIdentity("automation", "command-list") | 51 ID_CMD_LIST = disco.DiscoIdentity("automation", "command-list") |
51 ID_CMD_NODE = disco.DiscoIdentity("automation", "command-node") | 52 ID_CMD_NODE = disco.DiscoIdentity("automation", "command-node") |
52 CMD_REQUEST = IQ_SET + '/command[@xmlns="' + NS_COMMANDS + '"]' | 53 CMD_REQUEST = IQ_SET + '/command[@xmlns="' + NS_COMMANDS + '"]' |
53 | 54 |
54 SHOWS = OrderedDict([('default', _('Online')), | 55 SHOWS = OrderedDict( |
55 ('away', _('Away')), | 56 [ |
56 ('chat', _('Free for chat')), | 57 ("default", _("Online")), |
57 ('dnd', _('Do not disturb')), | 58 ("away", _("Away")), |
58 ('xa', _('Left')), | 59 ("chat", _("Free for chat")), |
59 ('disconnect', _('Disconnect'))]) | 60 ("dnd", _("Do not disturb")), |
61 ("xa", _("Left")), | |
62 ("disconnect", _("Disconnect")), | |
63 ] | |
64 ) | |
60 | 65 |
61 PLUGIN_INFO = { | 66 PLUGIN_INFO = { |
62 C.PI_NAME: "Ad-Hoc Commands", | 67 C.PI_NAME: "Ad-Hoc Commands", |
63 C.PI_IMPORT_NAME: "XEP-0050", | 68 C.PI_IMPORT_NAME: "XEP-0050", |
64 C.PI_TYPE: "XEP", | 69 C.PI_TYPE: "XEP", |
65 C.PI_PROTOCOLS: ["XEP-0050"], | 70 C.PI_PROTOCOLS: ["XEP-0050"], |
66 C.PI_MAIN: "XEP_0050", | 71 C.PI_MAIN: "XEP_0050", |
67 C.PI_HANDLER: "yes", | 72 C.PI_HANDLER: "yes", |
68 C.PI_DESCRIPTION: _("""Implementation of Ad-Hoc Commands""") | 73 C.PI_DESCRIPTION: _("""Implementation of Ad-Hoc Commands"""), |
69 } | 74 } |
70 | 75 |
71 | 76 |
72 class AdHocError(Exception): | 77 class AdHocError(Exception): |
73 | |
74 def __init__(self, error_const): | 78 def __init__(self, error_const): |
75 """ Error to be used from callback | 79 """ Error to be used from callback |
76 @param error_const: one of XEP_0050.ERROR | 80 @param error_const: one of XEP_0050.ERROR |
77 """ | 81 """ |
78 assert error_const in XEP_0050.ERROR | 82 assert error_const in XEP_0050.ERROR |
79 self.callback_error = error_const | 83 self.callback_error = error_const |
80 | 84 |
85 | |
81 class AdHocCommand(XMPPHandler): | 86 class AdHocCommand(XMPPHandler): |
82 implements(iwokkel.IDisco) | 87 implements(iwokkel.IDisco) |
83 | 88 |
84 def __init__(self, parent, callback, label, node, features, timeout, allowed_jids, allowed_groups, allowed_magics, forbidden_jids, forbidden_groups, client): | 89 def __init__( |
90 self, | |
91 parent, | |
92 callback, | |
93 label, | |
94 node, | |
95 features, | |
96 timeout, | |
97 allowed_jids, | |
98 allowed_groups, | |
99 allowed_magics, | |
100 forbidden_jids, | |
101 forbidden_groups, | |
102 client, | |
103 ): | |
85 self.parent = parent | 104 self.parent = parent |
86 self.callback = callback | 105 self.callback = callback |
87 self.label = label | 106 self.label = label |
88 self.node = node | 107 self.node = node |
89 self.features = [disco.DiscoFeature(feature) for feature in features] | 108 self.features = [disco.DiscoFeature(feature) for feature in features] |
90 self.allowed_jids, self.allowed_groups, self.allowed_magics, self.forbidden_jids, self.forbidden_groups = allowed_jids, allowed_groups, allowed_magics, forbidden_jids, forbidden_groups | 109 self.allowed_jids, self.allowed_groups, self.allowed_magics, self.forbidden_jids, self.forbidden_groups = ( |
110 allowed_jids, | |
111 allowed_groups, | |
112 allowed_magics, | |
113 forbidden_jids, | |
114 forbidden_groups, | |
115 ) | |
91 self.client = client | 116 self.client = client |
92 self.sessions = Sessions(timeout=timeout) | 117 self.sessions = Sessions(timeout=timeout) |
93 | 118 |
94 def getName(self, xml_lang=None): | 119 def getName(self, xml_lang=None): |
95 return self.label | 120 return self.label |
96 | 121 |
97 def isAuthorised(self, requestor): | 122 def isAuthorised(self, requestor): |
98 if '@ALL@' in self.allowed_magics: | 123 if "@ALL@" in self.allowed_magics: |
99 return True | 124 return True |
100 forbidden = set(self.forbidden_jids) | 125 forbidden = set(self.forbidden_jids) |
101 for group in self.forbidden_groups: | 126 for group in self.forbidden_groups: |
102 forbidden.update(self.client.roster.getJidsFromGroup(group)) | 127 forbidden.update(self.client.roster.getJidsFromGroup(group)) |
103 if requestor.userhostJID() in forbidden: | 128 if requestor.userhostJID() in forbidden: |
105 allowed = set(self.allowed_jids) | 130 allowed = set(self.allowed_jids) |
106 for group in self.allowed_groups: | 131 for group in self.allowed_groups: |
107 try: | 132 try: |
108 allowed.update(self.client.roster.getJidsFromGroup(group)) | 133 allowed.update(self.client.roster.getJidsFromGroup(group)) |
109 except exceptions.UnknownGroupError: | 134 except exceptions.UnknownGroupError: |
110 log.warning(_(u"The groups [%(group)s] is unknown for profile [%(profile)s])" % {'group':group, 'profile':self.client.profile})) | 135 log.warning( |
136 _( | |
137 u"The groups [%(group)s] is unknown for profile [%(profile)s])" | |
138 % {"group": group, "profile": self.client.profile} | |
139 ) | |
140 ) | |
111 if requestor.userhostJID() in allowed: | 141 if requestor.userhostJID() in allowed: |
112 return True | 142 return True |
113 return False | 143 return False |
114 | 144 |
115 def getDiscoInfo(self, requestor, target, nodeIdentifier=''): | 145 def getDiscoInfo(self, requestor, target, nodeIdentifier=""): |
116 if nodeIdentifier != NS_COMMANDS: # FIXME: we should manage other disco nodes here | 146 if ( |
147 nodeIdentifier != NS_COMMANDS | |
148 ): # FIXME: we should manage other disco nodes here | |
117 return [] | 149 return [] |
118 # identities = [ID_CMD_LIST if self.node == NS_COMMANDS else ID_CMD_NODE] # FIXME | 150 # identities = [ID_CMD_LIST if self.node == NS_COMMANDS else ID_CMD_NODE] # FIXME |
119 return [disco.DiscoFeature(NS_COMMANDS)] + self.features | 151 return [disco.DiscoFeature(NS_COMMANDS)] + self.features |
120 | 152 |
121 def getDiscoItems(self, requestor, target, nodeIdentifier=''): | 153 def getDiscoItems(self, requestor, target, nodeIdentifier=""): |
122 return [] | 154 return [] |
123 | 155 |
124 def _sendAnswer(self, callback_data, session_id, request): | 156 def _sendAnswer(self, callback_data, session_id, request): |
125 """ Send result of the command | 157 """ Send result of the command |
126 @param callback_data: tuple (payload, status, actions, note) with: | 158 @param callback_data: tuple (payload, status, actions, note) with: |
132 @param session_id: current session id | 164 @param session_id: current session id |
133 @param request: original request (domish.Element) | 165 @param request: original request (domish.Element) |
134 @return: deferred | 166 @return: deferred |
135 """ | 167 """ |
136 payload, status, actions, note = callback_data | 168 payload, status, actions, note = callback_data |
137 assert(isinstance(payload, domish.Element) or payload is None) | 169 assert isinstance(payload, domish.Element) or payload is None |
138 assert(status in XEP_0050.STATUS) | 170 assert status in XEP_0050.STATUS |
139 if not actions: | 171 if not actions: |
140 actions = [XEP_0050.ACTION.EXECUTE] | 172 actions = [XEP_0050.ACTION.EXECUTE] |
141 result = domish.Element((None, 'iq')) | 173 result = domish.Element((None, "iq")) |
142 result['type'] = 'result' | 174 result["type"] = "result" |
143 result['id'] = request['id'] | 175 result["id"] = request["id"] |
144 result['to'] = request['from'] | 176 result["to"] = request["from"] |
145 command_elt = result.addElement('command', NS_COMMANDS) | 177 command_elt = result.addElement("command", NS_COMMANDS) |
146 command_elt['sessionid'] = session_id | 178 command_elt["sessionid"] = session_id |
147 command_elt['node'] = self.node | 179 command_elt["node"] = self.node |
148 command_elt['status'] = status | 180 command_elt["status"] = status |
149 | 181 |
150 if status != XEP_0050.STATUS.CANCELED: | 182 if status != XEP_0050.STATUS.CANCELED: |
151 if status != XEP_0050.STATUS.COMPLETED: | 183 if status != XEP_0050.STATUS.COMPLETED: |
152 actions_elt = command_elt.addElement('actions') | 184 actions_elt = command_elt.addElement("actions") |
153 actions_elt['execute'] = actions[0] | 185 actions_elt["execute"] = actions[0] |
154 for action in actions: | 186 for action in actions: |
155 actions_elt.addElement(action) | 187 actions_elt.addElement(action) |
156 | 188 |
157 if note is not None: | 189 if note is not None: |
158 note_type, note_mess = note | 190 note_type, note_mess = note |
159 note_elt = command_elt.addElement('note', content=note_mess) | 191 note_elt = command_elt.addElement("note", content=note_mess) |
160 note_elt['type'] = note_type | 192 note_elt["type"] = note_type |
161 | 193 |
162 if payload is not None: | 194 if payload is not None: |
163 command_elt.addChild(payload) | 195 command_elt.addChild(payload) |
164 | 196 |
165 self.client.send(result) | 197 self.client.send(result) |
179 self.client.send(iq_elt) | 211 self.client.send(iq_elt) |
180 del self.sessions[session_id] | 212 del self.sessions[session_id] |
181 | 213 |
182 def onRequest(self, command_elt, requestor, action, session_id): | 214 def onRequest(self, command_elt, requestor, action, session_id): |
183 if not self.isAuthorised(requestor): | 215 if not self.isAuthorised(requestor): |
184 return self._sendError(XEP_0050.ERROR.FORBIDDEN, session_id, command_elt.parent) | 216 return self._sendError( |
217 XEP_0050.ERROR.FORBIDDEN, session_id, command_elt.parent | |
218 ) | |
185 if session_id: | 219 if session_id: |
186 try: | 220 try: |
187 session_data = self.sessions[session_id] | 221 session_data = self.sessions[session_id] |
188 except KeyError: | 222 except KeyError: |
189 return self._sendError(XEP_0050.ERROR.SESSION_EXPIRED, session_id, command_elt.parent) | 223 return self._sendError( |
190 if session_data['requestor'] != requestor: | 224 XEP_0050.ERROR.SESSION_EXPIRED, session_id, command_elt.parent |
191 return self._sendError(XEP_0050.ERROR.FORBIDDEN, session_id, command_elt.parent) | 225 ) |
226 if session_data["requestor"] != requestor: | |
227 return self._sendError( | |
228 XEP_0050.ERROR.FORBIDDEN, session_id, command_elt.parent | |
229 ) | |
192 else: | 230 else: |
193 session_id, session_data = self.sessions.newSession() | 231 session_id, session_data = self.sessions.newSession() |
194 session_data['requestor'] = requestor | 232 session_data["requestor"] = requestor |
195 if action == XEP_0050.ACTION.CANCEL: | 233 if action == XEP_0050.ACTION.CANCEL: |
196 d = defer.succeed((None, XEP_0050.STATUS.CANCELED, None, None)) | 234 d = defer.succeed((None, XEP_0050.STATUS.CANCELED, None, None)) |
197 else: | 235 else: |
198 d = defer.maybeDeferred(self.callback, command_elt, session_data, action, self.node, self.client.profile) | 236 d = defer.maybeDeferred( |
237 self.callback, | |
238 command_elt, | |
239 session_data, | |
240 action, | |
241 self.node, | |
242 self.client.profile, | |
243 ) | |
199 d.addCallback(self._sendAnswer, session_id, command_elt.parent) | 244 d.addCallback(self._sendAnswer, session_id, command_elt.parent) |
200 d.addErrback(lambda failure, request: self._sendError(failure.value.callback_error, session_id, request), command_elt.parent) | 245 d.addErrback( |
246 lambda failure, request: self._sendError( | |
247 failure.value.callback_error, session_id, request | |
248 ), | |
249 command_elt.parent, | |
250 ) | |
201 | 251 |
202 | 252 |
203 class XEP_0050(object): | 253 class XEP_0050(object): |
204 STATUS = namedtuple('Status', ('EXECUTING', 'COMPLETED', 'CANCELED'))('executing', 'completed', 'canceled') | 254 STATUS = namedtuple("Status", ("EXECUTING", "COMPLETED", "CANCELED"))( |
205 ACTION = namedtuple('Action', ('EXECUTE', 'CANCEL', 'NEXT', 'PREV'))('execute', 'cancel', 'next', 'prev') | 255 "executing", "completed", "canceled" |
206 NOTE = namedtuple('Note', ('INFO','WARN','ERROR'))('info','warn','error') | 256 ) |
207 ERROR = namedtuple('Error', ('MALFORMED_ACTION', 'BAD_ACTION', 'BAD_LOCALE', 'BAD_PAYLOAD', 'BAD_SESSIONID', 'SESSION_EXPIRED', | 257 ACTION = namedtuple("Action", ("EXECUTE", "CANCEL", "NEXT", "PREV"))( |
208 'FORBIDDEN', 'ITEM_NOT_FOUND', 'FEATURE_NOT_IMPLEMENTED', 'INTERNAL'))(('bad-request', 'malformed-action'), | 258 "execute", "cancel", "next", "prev" |
209 ('bad-request', 'bad-action'), ('bad-request', 'bad-locale'), ('bad-request','bad-payload'), | 259 ) |
210 ('bad-request','bad-sessionid'), ('not-allowed','session-expired'), ('forbidden', None), | 260 NOTE = namedtuple("Note", ("INFO", "WARN", "ERROR"))("info", "warn", "error") |
211 ('item-not-found', None), ('feature-not-implemented', None), ('internal-server-error', None)) # XEP-0050 §4.4 Table 5 | 261 ERROR = namedtuple( |
262 "Error", | |
263 ( | |
264 "MALFORMED_ACTION", | |
265 "BAD_ACTION", | |
266 "BAD_LOCALE", | |
267 "BAD_PAYLOAD", | |
268 "BAD_SESSIONID", | |
269 "SESSION_EXPIRED", | |
270 "FORBIDDEN", | |
271 "ITEM_NOT_FOUND", | |
272 "FEATURE_NOT_IMPLEMENTED", | |
273 "INTERNAL", | |
274 ), | |
275 )( | |
276 ("bad-request", "malformed-action"), | |
277 ("bad-request", "bad-action"), | |
278 ("bad-request", "bad-locale"), | |
279 ("bad-request", "bad-payload"), | |
280 ("bad-request", "bad-sessionid"), | |
281 ("not-allowed", "session-expired"), | |
282 ("forbidden", None), | |
283 ("item-not-found", None), | |
284 ("feature-not-implemented", None), | |
285 ("internal-server-error", None), | |
286 ) # XEP-0050 §4.4 Table 5 | |
212 | 287 |
213 def __init__(self, host): | 288 def __init__(self, host): |
214 log.info(_("plugin XEP-0050 initialization")) | 289 log.info(_("plugin XEP-0050 initialization")) |
215 self.host = host | 290 self.host = host |
216 self.requesting = Sessions() | 291 self.requesting = Sessions() |
217 self.answering = {} | 292 self.answering = {} |
218 host.bridge.addMethod("adHocRun", ".plugin", in_sign='sss', out_sign='s', | 293 host.bridge.addMethod( |
219 method=self._run, | 294 "adHocRun", |
220 async=True) | 295 ".plugin", |
221 host.bridge.addMethod("adHocList", ".plugin", in_sign='ss', out_sign='s', | 296 in_sign="sss", |
222 method=self._list, | 297 out_sign="s", |
223 async=True) | 298 method=self._run, |
224 self.__requesting_id = host.registerCallback(self._requestingEntity, with_data=True) | 299 async=True, |
225 host.importMenu((D_("Service"), D_("Commands")), self._commandsMenu, security_limit=2, help_string=D_("Execute ad-hoc commands")) | 300 ) |
301 host.bridge.addMethod( | |
302 "adHocList", | |
303 ".plugin", | |
304 in_sign="ss", | |
305 out_sign="s", | |
306 method=self._list, | |
307 async=True, | |
308 ) | |
309 self.__requesting_id = host.registerCallback( | |
310 self._requestingEntity, with_data=True | |
311 ) | |
312 host.importMenu( | |
313 (D_("Service"), D_("Commands")), | |
314 self._commandsMenu, | |
315 security_limit=2, | |
316 help_string=D_("Execute ad-hoc commands"), | |
317 ) | |
226 | 318 |
227 def getHandler(self, client): | 319 def getHandler(self, client): |
228 return XEP_0050_handler(self) | 320 return XEP_0050_handler(self) |
229 | 321 |
230 def profileConnected(self, client): | 322 def profileConnected(self, client): |
231 self.addAdHocCommand(self._statusCallback, _("Status"), profile_key=client.profile) | 323 self.addAdHocCommand( |
324 self._statusCallback, _("Status"), profile_key=client.profile | |
325 ) | |
232 | 326 |
233 def profileDisconnected(self, client): | 327 def profileDisconnected(self, client): |
234 try: | 328 try: |
235 del self.answering[client.profile] | 329 del self.answering[client.profile] |
236 except KeyError: | 330 except KeyError: |
240 """ Convert discovery items to XMLUI dialog """ | 334 """ Convert discovery items to XMLUI dialog """ |
241 # TODO: manage items on different jids | 335 # TODO: manage items on different jids |
242 form_ui = xml_tools.XMLUI("form", submit_id=self.__requesting_id) | 336 form_ui = xml_tools.XMLUI("form", submit_id=self.__requesting_id) |
243 | 337 |
244 if not no_instructions: | 338 if not no_instructions: |
245 form_ui.addText(_("Please select a command"), 'instructions') | 339 form_ui.addText(_("Please select a command"), "instructions") |
246 | 340 |
247 options = [(item.nodeIdentifier, item.name) for item in items] | 341 options = [(item.nodeIdentifier, item.name) for item in items] |
248 form_ui.addList("node", options) | 342 form_ui.addList("node", options) |
249 return form_ui | 343 return form_ui |
250 | 344 |
252 """Return the constant corresponding to <note/> type attribute value | 346 """Return the constant corresponding to <note/> type attribute value |
253 | 347 |
254 @param type_: note type (see XEP-0050 §4.3) | 348 @param type_: note type (see XEP-0050 §4.3) |
255 @return: a C.XMLUI_DATA_LVL_* constant | 349 @return: a C.XMLUI_DATA_LVL_* constant |
256 """ | 350 """ |
257 if type_ == 'error': | 351 if type_ == "error": |
258 return C.XMLUI_DATA_LVL_ERROR | 352 return C.XMLUI_DATA_LVL_ERROR |
259 elif type_ == 'warn': | 353 elif type_ == "warn": |
260 return C.XMLUI_DATA_LVL_WARNING | 354 return C.XMLUI_DATA_LVL_WARNING |
261 else: | 355 else: |
262 if type_ != 'info': | 356 if type_ != "info": |
263 log.warning(_(u"Invalid note type [%s], using info") % type_) | 357 log.warning(_(u"Invalid note type [%s], using info") % type_) |
264 return C.XMLUI_DATA_LVL_INFO | 358 return C.XMLUI_DATA_LVL_INFO |
265 | 359 |
266 def _mergeNotes(self, notes): | 360 def _mergeNotes(self, notes): |
267 """Merge notes with level prefix (e.g. "ERROR: the message") | 361 """Merge notes with level prefix (e.g. "ERROR: the message") |
268 | 362 |
269 @param notes (list): list of tuple (level, message) | 363 @param notes (list): list of tuple (level, message) |
270 @return: list of messages | 364 @return: list of messages |
271 """ | 365 """ |
272 lvl_map = {C.XMLUI_DATA_LVL_INFO: '', | 366 lvl_map = { |
273 C.XMLUI_DATA_LVL_WARNING: "%s: " % _("WARNING"), | 367 C.XMLUI_DATA_LVL_INFO: "", |
274 C.XMLUI_DATA_LVL_ERROR: "%s: " % _("ERROR") | 368 C.XMLUI_DATA_LVL_WARNING: "%s: " % _("WARNING"), |
275 } | 369 C.XMLUI_DATA_LVL_ERROR: "%s: " % _("ERROR"), |
370 } | |
276 return [u"%s%s" % (lvl_map[lvl], msg) for lvl, msg in notes] | 371 return [u"%s%s" % (lvl_map[lvl], msg) for lvl, msg in notes] |
277 | 372 |
278 def _commandsAnswer2XMLUI(self, iq_elt, session_id, session_data): | 373 def _commandsAnswer2XMLUI(self, iq_elt, session_id, session_data): |
279 """ | 374 """ |
280 Convert command answer to an ui for frontend | 375 Convert command answer to an ui for frontend |
282 @param session_id: id of the session used with the frontend | 377 @param session_id: id of the session used with the frontend |
283 @param profile_key: %(doc_profile_key)s | 378 @param profile_key: %(doc_profile_key)s |
284 | 379 |
285 """ | 380 """ |
286 command_elt = iq_elt.elements(NS_COMMANDS, "command").next() | 381 command_elt = iq_elt.elements(NS_COMMANDS, "command").next() |
287 status = command_elt.getAttribute('status', XEP_0050.STATUS.EXECUTING) | 382 status = command_elt.getAttribute("status", XEP_0050.STATUS.EXECUTING) |
288 if status in [XEP_0050.STATUS.COMPLETED, XEP_0050.STATUS.CANCELED]: | 383 if status in [XEP_0050.STATUS.COMPLETED, XEP_0050.STATUS.CANCELED]: |
289 # the command session is finished, we purge our session | 384 # the command session is finished, we purge our session |
290 del self.requesting[session_id] | 385 del self.requesting[session_id] |
291 if status == XEP_0050.STATUS.COMPLETED: | 386 if status == XEP_0050.STATUS.COMPLETED: |
292 session_id = None | 387 session_id = None |
293 else: | 388 else: |
294 return None | 389 return None |
295 remote_session_id = command_elt.getAttribute('sessionid') | 390 remote_session_id = command_elt.getAttribute("sessionid") |
296 if remote_session_id: | 391 if remote_session_id: |
297 session_data['remote_id'] = remote_session_id | 392 session_data["remote_id"] = remote_session_id |
298 notes = [] | 393 notes = [] |
299 for note_elt in command_elt.elements(NS_COMMANDS, 'note'): | 394 for note_elt in command_elt.elements(NS_COMMANDS, "note"): |
300 notes.append((self._getDataLvl(note_elt.getAttribute('type', 'info')), | 395 notes.append( |
301 unicode(note_elt))) | 396 ( |
302 for data_elt in command_elt.elements(data_form.NS_X_DATA, 'x'): | 397 self._getDataLvl(note_elt.getAttribute("type", "info")), |
303 if data_elt['type'] in ('form', 'result'): | 398 unicode(note_elt), |
399 ) | |
400 ) | |
401 for data_elt in command_elt.elements(data_form.NS_X_DATA, "x"): | |
402 if data_elt["type"] in ("form", "result"): | |
304 break | 403 break |
305 else: | 404 else: |
306 # no matching data element found | 405 # no matching data element found |
307 if status != XEP_0050.STATUS.COMPLETED: | 406 if status != XEP_0050.STATUS.COMPLETED: |
308 log.warning(_("No known payload found in ad-hoc command result, aborting")) | 407 log.warning( |
408 _("No known payload found in ad-hoc command result, aborting") | |
409 ) | |
309 del self.requesting[session_id] | 410 del self.requesting[session_id] |
310 return xml_tools.XMLUI(C.XMLUI_DIALOG, | 411 return xml_tools.XMLUI( |
311 dialog_opt = {C.XMLUI_DATA_TYPE: C.XMLUI_DIALOG_NOTE, | 412 C.XMLUI_DIALOG, |
312 C.XMLUI_DATA_MESS: _("No payload found"), | 413 dialog_opt={ |
313 C.XMLUI_DATA_LVL: C.XMLUI_DATA_LVL_ERROR, | 414 C.XMLUI_DATA_TYPE: C.XMLUI_DIALOG_NOTE, |
314 } | 415 C.XMLUI_DATA_MESS: _("No payload found"), |
315 ) | 416 C.XMLUI_DATA_LVL: C.XMLUI_DATA_LVL_ERROR, |
417 }, | |
418 ) | |
316 if not notes: | 419 if not notes: |
317 # the status is completed, and we have no note to show | 420 # the status is completed, and we have no note to show |
318 return None | 421 return None |
319 | 422 |
320 # if we have only one note, we show a dialog with the level of the note | 423 # if we have only one note, we show a dialog with the level of the note |
321 # if we have more, we show a dialog with "info" level, and all notes merged | 424 # if we have more, we show a dialog with "info" level, and all notes merged |
322 dlg_level = notes[0][0] if len(notes) == 1 else C.XMLUI_DATA_LVL_INFO | 425 dlg_level = notes[0][0] if len(notes) == 1 else C.XMLUI_DATA_LVL_INFO |
323 return xml_tools.XMLUI( | 426 return xml_tools.XMLUI( |
324 C.XMLUI_DIALOG, | 427 C.XMLUI_DIALOG, |
325 dialog_opt = {C.XMLUI_DATA_TYPE: C.XMLUI_DIALOG_NOTE, | 428 dialog_opt={ |
326 C.XMLUI_DATA_MESS: u'\n'.join(self._mergeNotes(notes)), | 429 C.XMLUI_DATA_TYPE: C.XMLUI_DIALOG_NOTE, |
327 C.XMLUI_DATA_LVL: dlg_level, | 430 C.XMLUI_DATA_MESS: u"\n".join(self._mergeNotes(notes)), |
328 }, | 431 C.XMLUI_DATA_LVL: dlg_level, |
329 session_id = session_id | 432 }, |
330 ) | 433 session_id=session_id, |
434 ) | |
331 | 435 |
332 if session_id is None: | 436 if session_id is None: |
333 return xml_tools.dataFormEltResult2XMLUI(data_elt) | 437 return xml_tools.dataFormEltResult2XMLUI(data_elt) |
334 form = data_form.Form.fromElement(data_elt) | 438 form = data_form.Form.fromElement(data_elt) |
335 # we add any present note to the instructions | 439 # we add any present note to the instructions |
336 form.instructions.extend(self._mergeNotes(notes)) | 440 form.instructions.extend(self._mergeNotes(notes)) |
337 return xml_tools.dataForm2XMLUI(form, self.__requesting_id, session_id=session_id) | 441 return xml_tools.dataForm2XMLUI(form, self.__requesting_id, session_id=session_id) |
338 | 442 |
339 def _requestingEntity(self, data, profile): | 443 def _requestingEntity(self, data, profile): |
340 def serialise(ret_data): | 444 def serialise(ret_data): |
341 if 'xmlui' in ret_data: | 445 if "xmlui" in ret_data: |
342 ret_data['xmlui'] = ret_data['xmlui'].toXml() | 446 ret_data["xmlui"] = ret_data["xmlui"].toXml() |
343 return ret_data | 447 return ret_data |
344 | 448 |
345 d = self.requestingEntity(data, profile) | 449 d = self.requestingEntity(data, profile) |
346 d.addCallback(serialise) | 450 d.addCallback(serialise) |
347 return d | 451 return d |
352 @param data: data returned by previous XMLUI (first one must come from self._commandsMenu) | 456 @param data: data returned by previous XMLUI (first one must come from self._commandsMenu) |
353 @param profile: %(doc_profile)s | 457 @param profile: %(doc_profile)s |
354 @return: callback dict result (with "xmlui" corresponding to the answering dialog, or empty if it's finished without error) | 458 @return: callback dict result (with "xmlui" corresponding to the answering dialog, or empty if it's finished without error) |
355 | 459 |
356 """ | 460 """ |
357 if C.bool(data.get('cancelled', C.BOOL_FALSE)): | 461 if C.bool(data.get("cancelled", C.BOOL_FALSE)): |
358 return defer.succeed({}) | 462 return defer.succeed({}) |
359 client = self.host.getClient(profile) | 463 client = self.host.getClient(profile) |
360 # TODO: cancel, prev and next are not managed | 464 # TODO: cancel, prev and next are not managed |
361 # TODO: managed answerer errors | 465 # TODO: managed answerer errors |
362 # TODO: manage nodes with a non data form payload | 466 # TODO: manage nodes with a non data form payload |
363 if "session_id" not in data: | 467 if "session_id" not in data: |
364 # we just had the jid, we now request it for the available commands | 468 # we just had the jid, we now request it for the available commands |
365 session_id, session_data = self.requesting.newSession(profile=client.profile) | 469 session_id, session_data = self.requesting.newSession(profile=client.profile) |
366 entity = jid.JID(data[xml_tools.SAT_FORM_PREFIX+'jid']) | 470 entity = jid.JID(data[xml_tools.SAT_FORM_PREFIX + "jid"]) |
367 session_data['jid'] = entity | 471 session_data["jid"] = entity |
368 d = self.list(client, entity) | 472 d = self.list(client, entity) |
369 | 473 |
370 def sendItems(xmlui): | 474 def sendItems(xmlui): |
371 xmlui.session_id = session_id # we need to keep track of the session | 475 xmlui.session_id = session_id # we need to keep track of the session |
372 return {'xmlui': xmlui} | 476 return {"xmlui": xmlui} |
373 | 477 |
374 d.addCallback(sendItems) | 478 d.addCallback(sendItems) |
375 else: | 479 else: |
376 # we have started a several forms sessions | 480 # we have started a several forms sessions |
377 try: | 481 try: |
378 session_data = self.requesting.profileGet(data["session_id"], client.profile) | 482 session_data = self.requesting.profileGet( |
483 data["session_id"], client.profile | |
484 ) | |
379 except KeyError: | 485 except KeyError: |
380 log.warning ("session id doesn't exist, session has probably expired") | 486 log.warning("session id doesn't exist, session has probably expired") |
381 # TODO: send error dialog | 487 # TODO: send error dialog |
382 return defer.succeed({}) | 488 return defer.succeed({}) |
383 session_id = data["session_id"] | 489 session_id = data["session_id"] |
384 entity = session_data['jid'] | 490 entity = session_data["jid"] |
385 try: | 491 try: |
386 session_data['node'] | 492 session_data["node"] |
387 # node has already been received | 493 # node has already been received |
388 except KeyError: | 494 except KeyError: |
389 # it's the first time we know the node, we save it in session data | 495 # it's the first time we know the node, we save it in session data |
390 session_data['node'] = data[xml_tools.SAT_FORM_PREFIX+'node'] | 496 session_data["node"] = data[xml_tools.SAT_FORM_PREFIX + "node"] |
391 | 497 |
392 # we request execute node's command | 498 # we request execute node's command |
393 iq_elt = compat.IQ(client.xmlstream, 'set') | 499 iq_elt = compat.IQ(client.xmlstream, "set") |
394 iq_elt['to'] = entity.full() | 500 iq_elt["to"] = entity.full() |
395 command_elt = iq_elt.addElement("command", NS_COMMANDS) | 501 command_elt = iq_elt.addElement("command", NS_COMMANDS) |
396 command_elt['node'] = session_data['node'] | 502 command_elt["node"] = session_data["node"] |
397 command_elt['action'] = XEP_0050.ACTION.EXECUTE | 503 command_elt["action"] = XEP_0050.ACTION.EXECUTE |
398 try: | 504 try: |
399 # remote_id is the XEP_0050 sessionid used by answering command | 505 # remote_id is the XEP_0050 sessionid used by answering command |
400 # while session_id is our own session id used with the frontend | 506 # while session_id is our own session id used with the frontend |
401 command_elt['sessionid'] = session_data['remote_id'] | 507 command_elt["sessionid"] = session_data["remote_id"] |
402 except KeyError: | 508 except KeyError: |
403 pass | 509 pass |
404 | 510 |
405 command_elt.addChild(xml_tools.XMLUIResultToElt(data)) # We add the XMLUI result to the command payload | 511 command_elt.addChild( |
512 xml_tools.XMLUIResultToElt(data) | |
513 ) # We add the XMLUI result to the command payload | |
406 d = iq_elt.send() | 514 d = iq_elt.send() |
407 d.addCallback(self._commandsAnswer2XMLUI, session_id, session_data) | 515 d.addCallback(self._commandsAnswer2XMLUI, session_id, session_data) |
408 d.addCallback(lambda xmlui: {'xmlui': xmlui} if xmlui is not None else {}) | 516 d.addCallback(lambda xmlui: {"xmlui": xmlui} if xmlui is not None else {}) |
409 | 517 |
410 return d | 518 return d |
411 | 519 |
412 def _commandsMenu(self, menu_data, profile): | 520 def _commandsMenu(self, menu_data, profile): |
413 """ First XMLUI activated by menu: ask for target jid | 521 """ First XMLUI activated by menu: ask for target jid |
414 @param profile: %(doc_profile)s | 522 @param profile: %(doc_profile)s |
415 | 523 |
416 """ | 524 """ |
417 form_ui = xml_tools.XMLUI("form", submit_id=self.__requesting_id) | 525 form_ui = xml_tools.XMLUI("form", submit_id=self.__requesting_id) |
418 form_ui.addText(_("Please enter target jid"), 'instructions') | 526 form_ui.addText(_("Please enter target jid"), "instructions") |
419 form_ui.changeContainer("pairs") | 527 form_ui.changeContainer("pairs") |
420 form_ui.addLabel("jid") | 528 form_ui.addLabel("jid") |
421 form_ui.addString("jid", value=self.host.getClient(profile).jid.host) | 529 form_ui.addString("jid", value=self.host.getClient(profile).jid.host) |
422 return {'xmlui': form_ui.toXml()} | 530 return {"xmlui": form_ui.toXml()} |
423 | 531 |
424 def _statusCallback(self, command_elt, session_data, action, node, profile): | 532 def _statusCallback(self, command_elt, session_data, action, node, profile): |
425 """ Ad-hoc command used to change the "show" part of status """ | 533 """ Ad-hoc command used to change the "show" part of status """ |
426 actions = session_data.setdefault('actions',[]) | 534 actions = session_data.setdefault("actions", []) |
427 actions.append(action) | 535 actions.append(action) |
428 | 536 |
429 if len(actions) == 1: | 537 if len(actions) == 1: |
430 # it's our first request, we ask the desired new status | 538 # it's our first request, we ask the desired new status |
431 status = XEP_0050.STATUS.EXECUTING | 539 status = XEP_0050.STATUS.EXECUTING |
432 form = data_form.Form('form', title=_('status selection')) | 540 form = data_form.Form("form", title=_("status selection")) |
433 show_options = [data_form.Option(name, label) for name, label in SHOWS.items()] | 541 show_options = [ |
434 field = data_form.Field('list-single', 'show', options=show_options, required=True) | 542 data_form.Option(name, label) for name, label in SHOWS.items() |
543 ] | |
544 field = data_form.Field( | |
545 "list-single", "show", options=show_options, required=True | |
546 ) | |
435 form.addField(field) | 547 form.addField(field) |
436 | 548 |
437 payload = form.toElement() | 549 payload = form.toElement() |
438 note = None | 550 note = None |
439 | 551 |
440 elif len(actions) == 2: | 552 elif len(actions) == 2: |
441 # we should have the answer here | 553 # we should have the answer here |
442 try: | 554 try: |
443 x_elt = command_elt.elements(data_form.NS_X_DATA,'x').next() | 555 x_elt = command_elt.elements(data_form.NS_X_DATA, "x").next() |
444 answer_form = data_form.Form.fromElement(x_elt) | 556 answer_form = data_form.Form.fromElement(x_elt) |
445 show = answer_form['show'] | 557 show = answer_form["show"] |
446 except (KeyError, StopIteration): | 558 except (KeyError, StopIteration): |
447 raise AdHocError(XEP_0050.ERROR.BAD_PAYLOAD) | 559 raise AdHocError(XEP_0050.ERROR.BAD_PAYLOAD) |
448 if show not in SHOWS: | 560 if show not in SHOWS: |
449 raise AdHocError(XEP_0050.ERROR.BAD_PAYLOAD) | 561 raise AdHocError(XEP_0050.ERROR.BAD_PAYLOAD) |
450 if show == "disconnect": | 562 if show == "disconnect": |
451 self.host.disconnect(profile) | 563 self.host.disconnect(profile) |
452 else: | 564 else: |
453 self.host.setPresence(show=show, profile_key=profile) | 565 self.host.setPresence(show=show, profile_key=profile) |
454 | 566 |
455 # job done, we can end the session | 567 # job done, we can end the session |
456 form = data_form.Form('form', title=_(u'Updated')) | 568 form = data_form.Form("form", title=_(u"Updated")) |
457 form.addField(data_form.Field('fixed', u'Status updated')) | 569 form.addField(data_form.Field("fixed", u"Status updated")) |
458 status = XEP_0050.STATUS.COMPLETED | 570 status = XEP_0050.STATUS.COMPLETED |
459 payload = None | 571 payload = None |
460 note = (self.NOTE.INFO, _(u"Status updated")) | 572 note = (self.NOTE.INFO, _(u"Status updated")) |
461 else: | 573 else: |
462 raise AdHocError(XEP_0050.ERROR.INTERNAL) | 574 raise AdHocError(XEP_0050.ERROR.INTERNAL) |
463 | 575 |
464 return (payload, status, None, note) | 576 return (payload, status, None, note) |
465 | 577 |
466 def _run(self, service_jid_s='', node='', profile_key=C.PROF_KEY_NONE): | 578 def _run(self, service_jid_s="", node="", profile_key=C.PROF_KEY_NONE): |
467 client = self.host.getClient(profile_key) | 579 client = self.host.getClient(profile_key) |
468 service_jid = jid.JID(service_jid_s) if service_jid_s else None | 580 service_jid = jid.JID(service_jid_s) if service_jid_s else None |
469 d = self.run(client, service_jid, node or None) | 581 d = self.run(client, service_jid, node or None) |
470 d.addCallback(lambda xmlui: xmlui.toXml()) | 582 d.addCallback(lambda xmlui: xmlui.toXml()) |
471 return d | 583 return d |
481 @return(unicode): command page XMLUI | 593 @return(unicode): command page XMLUI |
482 """ | 594 """ |
483 if service_jid is None: | 595 if service_jid is None: |
484 service_jid = jid.JID(client.jid.host) | 596 service_jid = jid.JID(client.jid.host) |
485 session_id, session_data = self.requesting.newSession(profile=client.profile) | 597 session_id, session_data = self.requesting.newSession(profile=client.profile) |
486 session_data['jid'] = service_jid | 598 session_data["jid"] = service_jid |
487 if node is None: | 599 if node is None: |
488 xmlui = yield self.list(client, service_jid) | 600 xmlui = yield self.list(client, service_jid) |
489 else: | 601 else: |
490 session_data['node'] = node | 602 session_data["node"] = node |
491 cb_data = yield self.requestingEntity({'session_id': session_id}, client.profile) | 603 cb_data = yield self.requestingEntity( |
492 xmlui = cb_data['xmlui'] | 604 {"session_id": session_id}, client.profile |
605 ) | |
606 xmlui = cb_data["xmlui"] | |
493 | 607 |
494 xmlui.session_id = session_id | 608 xmlui.session_id = session_id |
495 defer.returnValue(xmlui) | 609 defer.returnValue(xmlui) |
496 | 610 |
497 def _list(self, to_jid_s, profile_key): | 611 def _list(self, to_jid_s, profile_key): |
510 """ | 624 """ |
511 d = self.host.getDiscoItems(client, to_jid, NS_COMMANDS) | 625 d = self.host.getDiscoItems(client, to_jid, NS_COMMANDS) |
512 d.addCallback(self._items2XMLUI, no_instructions) | 626 d.addCallback(self._items2XMLUI, no_instructions) |
513 return d | 627 return d |
514 | 628 |
515 def addAdHocCommand(self, callback, label, node=None, features=None, timeout=600, allowed_jids=None, allowed_groups=None, | 629 def addAdHocCommand( |
516 allowed_magics=None, forbidden_jids=None, forbidden_groups=None, profile_key=C.PROF_KEY_NONE): | 630 self, |
631 callback, | |
632 label, | |
633 node=None, | |
634 features=None, | |
635 timeout=600, | |
636 allowed_jids=None, | |
637 allowed_groups=None, | |
638 allowed_magics=None, | |
639 forbidden_jids=None, | |
640 forbidden_groups=None, | |
641 profile_key=C.PROF_KEY_NONE, | |
642 ): | |
517 """Add an ad-hoc command for the current profile | 643 """Add an ad-hoc command for the current profile |
518 | 644 |
519 @param callback: method associated with this ad-hoc command which return the payload data (see AdHocCommand._sendAnswer), can return a deferred | 645 @param callback: method associated with this ad-hoc command which return the payload data (see AdHocCommand._sendAnswer), can return a deferred |
520 @param label: label associated with this command on the main menu | 646 @param label: label associated with this command on the main menu |
521 @param node: disco item node associated with this command. None to use autogenerated node | 647 @param node: disco item node associated with this command. None to use autogenerated node |
532 @return: node of the added command, useful to remove the command later | 658 @return: node of the added command, useful to remove the command later |
533 """ | 659 """ |
534 # FIXME: "@ALL@" for profile_key seems useless and dangerous | 660 # FIXME: "@ALL@" for profile_key seems useless and dangerous |
535 | 661 |
536 if node is None: | 662 if node is None: |
537 node = "%s_%s" % ('COMMANDS', uuid4()) | 663 node = "%s_%s" % ("COMMANDS", uuid4()) |
538 | 664 |
539 if features is None: | 665 if features is None: |
540 features = [data_form.NS_X_DATA] | 666 features = [data_form.NS_X_DATA] |
541 | 667 |
542 if allowed_jids is None: | 668 if allowed_jids is None: |
543 allowed_jids = [] | 669 allowed_jids = [] |
544 if allowed_groups is None: | 670 if allowed_groups is None: |
545 allowed_groups = [] | 671 allowed_groups = [] |
546 if allowed_magics is None: | 672 if allowed_magics is None: |
547 allowed_magics = ['@PROFILE_BAREJID@'] | 673 allowed_magics = ["@PROFILE_BAREJID@"] |
548 if forbidden_jids is None: | 674 if forbidden_jids is None: |
549 forbidden_jids = [] | 675 forbidden_jids = [] |
550 if forbidden_groups is None: | 676 if forbidden_groups is None: |
551 forbidden_groups = [] | 677 forbidden_groups = [] |
552 | 678 |
553 for client in self.host.getClients(profile_key): | 679 for client in self.host.getClients(profile_key): |
554 #TODO: manage newly created/removed profiles | 680 # TODO: manage newly created/removed profiles |
555 _allowed_jids = (allowed_jids + [client.jid.userhostJID()]) if '@PROFILE_BAREJID@' in allowed_magics else allowed_jids | 681 _allowed_jids = ( |
556 ad_hoc_command = AdHocCommand(self, callback, label, node, features, timeout, _allowed_jids, | 682 (allowed_jids + [client.jid.userhostJID()]) |
557 allowed_groups, allowed_magics, forbidden_jids, forbidden_groups, client) | 683 if "@PROFILE_BAREJID@" in allowed_magics |
684 else allowed_jids | |
685 ) | |
686 ad_hoc_command = AdHocCommand( | |
687 self, | |
688 callback, | |
689 label, | |
690 node, | |
691 features, | |
692 timeout, | |
693 _allowed_jids, | |
694 allowed_groups, | |
695 allowed_magics, | |
696 forbidden_jids, | |
697 forbidden_groups, | |
698 client, | |
699 ) | |
558 ad_hoc_command.setHandlerParent(client) | 700 ad_hoc_command.setHandlerParent(client) |
559 profile_commands = self.answering.setdefault(client.profile, {}) | 701 profile_commands = self.answering.setdefault(client.profile, {}) |
560 profile_commands[node] = ad_hoc_command | 702 profile_commands[node] = ad_hoc_command |
561 | 703 |
562 def onCmdRequest(self, request, profile): | 704 def onCmdRequest(self, request, profile): |
563 request.handled = True | 705 request.handled = True |
564 requestor = jid.JID(request['from']) | 706 requestor = jid.JID(request["from"]) |
565 command_elt = request.elements(NS_COMMANDS, 'command').next() | 707 command_elt = request.elements(NS_COMMANDS, "command").next() |
566 action = command_elt.getAttribute('action', self.ACTION.EXECUTE) | 708 action = command_elt.getAttribute("action", self.ACTION.EXECUTE) |
567 node = command_elt.getAttribute('node') | 709 node = command_elt.getAttribute("node") |
568 if not node: | 710 if not node: |
569 raise exceptions.DataError | 711 raise exceptions.DataError |
570 sessionid = command_elt.getAttribute('sessionid') | 712 sessionid = command_elt.getAttribute("sessionid") |
571 try: | 713 try: |
572 command = self.answering[profile][node] | 714 command = self.answering[profile][node] |
573 except KeyError: | 715 except KeyError: |
574 raise exceptions.DataError | 716 raise exceptions.DataError |
575 command.onRequest(command_elt, requestor, action, sessionid) | 717 command.onRequest(command_elt, requestor, action, sessionid) |
580 | 722 |
581 def __init__(self, plugin_parent): | 723 def __init__(self, plugin_parent): |
582 self.plugin_parent = plugin_parent | 724 self.plugin_parent = plugin_parent |
583 | 725 |
584 def connectionInitialized(self): | 726 def connectionInitialized(self): |
585 self.xmlstream.addObserver(CMD_REQUEST, self.plugin_parent.onCmdRequest, profile=self.parent.profile) | 727 self.xmlstream.addObserver( |
586 | 728 CMD_REQUEST, self.plugin_parent.onCmdRequest, profile=self.parent.profile |
587 def getDiscoInfo(self, requestor, target, nodeIdentifier=''): | 729 ) |
730 | |
731 def getDiscoInfo(self, requestor, target, nodeIdentifier=""): | |
588 identities = [] | 732 identities = [] |
589 if nodeIdentifier == NS_COMMANDS and self.plugin_parent.answering.get(self.parent.profile): # we only add the identity if we have registred commands | 733 if nodeIdentifier == NS_COMMANDS and self.plugin_parent.answering.get( |
734 self.parent.profile | |
735 ): # we only add the identity if we have registred commands | |
590 identities.append(ID_CMD_LIST) | 736 identities.append(ID_CMD_LIST) |
591 return [disco.DiscoFeature(NS_COMMANDS)] + identities | 737 return [disco.DiscoFeature(NS_COMMANDS)] + identities |
592 | 738 |
593 def getDiscoItems(self, requestor, target, nodeIdentifier=''): | 739 def getDiscoItems(self, requestor, target, nodeIdentifier=""): |
594 ret = [] | 740 ret = [] |
595 if nodeIdentifier == NS_COMMANDS: | 741 if nodeIdentifier == NS_COMMANDS: |
596 for command in self.plugin_parent.answering.get(self.parent.profile,{}).values(): | 742 for command in self.plugin_parent.answering.get( |
743 self.parent.profile, {} | |
744 ).values(): | |
597 if command.isAuthorised(requestor): | 745 if command.isAuthorised(requestor): |
598 ret.append(disco.DiscoItem(self.parent.jid, command.node, command.getName())) #TODO: manage name language | 746 ret.append( |
747 disco.DiscoItem(self.parent.jid, command.node, command.getName()) | |
748 ) # TODO: manage name language | |
599 return ret | 749 return ret |