comparison sat/plugins/plugin_xep_0050.py @ 4037:524856bd7b19

massive refactoring to switch from camelCase to snake_case: historically, Libervia (SàT before) was using camelCase as allowed by PEP8 when using a pre-PEP8 code, to use the same coding style as in Twisted. However, snake_case is more readable and it's better to follow PEP8 best practices, so it has been decided to move on full snake_case. Because Libervia has a huge codebase, this ended with a ugly mix of camelCase and snake_case. To fix that, this patch does a big refactoring by renaming every function and method (including bridge) that are not coming from Twisted or Wokkel, to use fully snake_case. This is a massive change, and may result in some bugs.
author Goffi <goffi@goffi.org>
date Sat, 08 Apr 2023 13:54:42 +0200
parents 6c93a18b6250
children
comparison
equal deleted inserted replaced
4036:c4464d7ae97b 4037:524856bd7b19
100 return self.parent 100 return self.parent
101 101
102 def getName(self, xml_lang=None): 102 def getName(self, xml_lang=None):
103 return self.label 103 return self.label
104 104
105 def isAuthorised(self, requestor): 105 def is_authorised(self, requestor):
106 if "@ALL@" in self.allowed_magics: 106 if "@ALL@" in self.allowed_magics:
107 return True 107 return True
108 forbidden = set(self.forbidden_jids) 108 forbidden = set(self.forbidden_jids)
109 for group in self.forbidden_groups: 109 for group in self.forbidden_groups:
110 forbidden.update(self.client.roster.getJidsFromGroup(group)) 110 forbidden.update(self.client.roster.get_jids_from_group(group))
111 if requestor.userhostJID() in forbidden: 111 if requestor.userhostJID() in forbidden:
112 return False 112 return False
113 allowed = set(self.allowed_jids) 113 allowed = set(self.allowed_jids)
114 for group in self.allowed_groups: 114 for group in self.allowed_groups:
115 try: 115 try:
116 allowed.update(self.client.roster.getJidsFromGroup(group)) 116 allowed.update(self.client.roster.get_jids_from_group(group))
117 except exceptions.UnknownGroupError: 117 except exceptions.UnknownGroupError:
118 log.warning(_("The groups [{group}] is unknown for profile [{profile}])") 118 log.warning(_("The groups [{group}] is unknown for profile [{profile}])")
119 .format(group=group, profile=self.client.profile)) 119 .format(group=group, profile=self.client.profile))
120 if requestor.userhostJID() in allowed: 120 if requestor.userhostJID() in allowed:
121 return True 121 return True
192 error_elt = next(iq_elt.elements(None, "error")) 192 error_elt = next(iq_elt.elements(None, "error"))
193 error_elt.addElement(cmd_condition, NS_COMMANDS) 193 error_elt.addElement(cmd_condition, NS_COMMANDS)
194 self.client.send(iq_elt) 194 self.client.send(iq_elt)
195 del self.sessions[session_id] 195 del self.sessions[session_id]
196 196
197 def _requestEb(self, failure_, request, session_id): 197 def _request_eb(self, failure_, request, session_id):
198 if failure_.check(AdHocError): 198 if failure_.check(AdHocError):
199 error_constant = failure_.value.callback_error 199 error_constant = failure_.value.callback_error
200 else: 200 else:
201 log.error(f"unexpected error while handling request: {failure_}") 201 log.error(f"unexpected error while handling request: {failure_}")
202 error_constant = XEP_0050.ERROR.INTERNAL 202 error_constant = XEP_0050.ERROR.INTERNAL
203 203
204 self._sendError(error_constant, session_id, request) 204 self._sendError(error_constant, session_id, request)
205 205
206 def onRequest(self, command_elt, requestor, action, session_id): 206 def on_request(self, command_elt, requestor, action, session_id):
207 if not self.isAuthorised(requestor): 207 if not self.is_authorised(requestor):
208 return self._sendError( 208 return self._sendError(
209 XEP_0050.ERROR.FORBIDDEN, session_id, command_elt.parent 209 XEP_0050.ERROR.FORBIDDEN, session_id, command_elt.parent
210 ) 210 )
211 if session_id: 211 if session_id:
212 try: 212 try:
218 if session_data["requestor"] != requestor: 218 if session_data["requestor"] != requestor:
219 return self._sendError( 219 return self._sendError(
220 XEP_0050.ERROR.FORBIDDEN, session_id, command_elt.parent 220 XEP_0050.ERROR.FORBIDDEN, session_id, command_elt.parent
221 ) 221 )
222 else: 222 else:
223 session_id, session_data = self.sessions.newSession() 223 session_id, session_data = self.sessions.new_session()
224 session_data["requestor"] = requestor 224 session_data["requestor"] = requestor
225 if action == XEP_0050.ACTION.CANCEL: 225 if action == XEP_0050.ACTION.CANCEL:
226 d = defer.succeed((None, XEP_0050.STATUS.CANCELED, None, None)) 226 d = defer.succeed((None, XEP_0050.STATUS.CANCELED, None, None))
227 else: 227 else:
228 d = utils.asDeferred( 228 d = utils.as_deferred(
229 self.callback, 229 self.callback,
230 self.client, 230 self.client,
231 command_elt, 231 command_elt,
232 session_data, 232 session_data,
233 action, 233 action,
234 self.node, 234 self.node,
235 ) 235 )
236 d.addCallback(self._sendAnswer, session_id, command_elt.parent) 236 d.addCallback(self._sendAnswer, session_id, command_elt.parent)
237 d.addErrback(self._requestEb, command_elt.parent, session_id) 237 d.addErrback(self._request_eb, command_elt.parent, session_id)
238 238
239 239
240 class XEP_0050(object): 240 class XEP_0050(object):
241 STATUS = namedtuple("Status", ("EXECUTING", "COMPLETED", "CANCELED"))( 241 STATUS = namedtuple("Status", ("EXECUTING", "COMPLETED", "CANCELED"))(
242 "executing", "completed", "canceled" 242 "executing", "completed", "canceled"
274 274
275 def __init__(self, host): 275 def __init__(self, host):
276 log.info(_("plugin XEP-0050 initialization")) 276 log.info(_("plugin XEP-0050 initialization"))
277 self.host = host 277 self.host = host
278 self.requesting = Sessions() 278 self.requesting = Sessions()
279 host.bridge.addMethod( 279 host.bridge.add_method(
280 "adHocRun", 280 "ad_hoc_run",
281 ".plugin", 281 ".plugin",
282 in_sign="sss", 282 in_sign="sss",
283 out_sign="s", 283 out_sign="s",
284 method=self._run, 284 method=self._run,
285 async_=True, 285 async_=True,
286 ) 286 )
287 host.bridge.addMethod( 287 host.bridge.add_method(
288 "adHocList", 288 "ad_hoc_list",
289 ".plugin", 289 ".plugin",
290 in_sign="ss", 290 in_sign="ss",
291 out_sign="s", 291 out_sign="s",
292 method=self._listUI, 292 method=self._list_ui,
293 async_=True, 293 async_=True,
294 ) 294 )
295 host.bridge.addMethod( 295 host.bridge.add_method(
296 "adHocSequence", 296 "ad_hoc_sequence",
297 ".plugin", 297 ".plugin",
298 in_sign="ssss", 298 in_sign="ssss",
299 out_sign="s", 299 out_sign="s",
300 method=self._sequence, 300 method=self._sequence,
301 async_=True, 301 async_=True,
302 ) 302 )
303 self.__requesting_id = host.registerCallback( 303 self.__requesting_id = host.register_callback(
304 self._requestingEntity, with_data=True 304 self._requesting_entity, with_data=True
305 ) 305 )
306 host.importMenu( 306 host.import_menu(
307 (D_("Service"), D_("Commands")), 307 (D_("Service"), D_("Commands")),
308 self._commandsMenu, 308 self._commands_menu,
309 security_limit=2, 309 security_limit=2,
310 help_string=D_("Execute ad-hoc commands"), 310 help_string=D_("Execute ad-hoc commands"),
311 ) 311 )
312 host.registerNamespace('commands', NS_COMMANDS) 312 host.register_namespace('commands', NS_COMMANDS)
313 313
314 def getHandler(self, client): 314 def get_handler(self, client):
315 return XEP_0050_handler(self) 315 return XEP_0050_handler(self)
316 316
317 def profileConnected(self, client): 317 def profile_connected(self, client):
318 # map from node to AdHocCommand instance 318 # map from node to AdHocCommand instance
319 client._XEP_0050_commands = {} 319 client._XEP_0050_commands = {}
320 if not client.is_component: 320 if not client.is_component:
321 self.addAdHocCommand(client, self._statusCallback, _("Status")) 321 self.add_ad_hoc_command(client, self._status_callback, _("Status"))
322 322
323 def do(self, client, entity, node, action=ACTION.EXECUTE, session_id=None, 323 def do(self, client, entity, node, action=ACTION.EXECUTE, session_id=None,
324 form_values=None, timeout=30): 324 form_values=None, timeout=30):
325 """Do an Ad-Hoc Command 325 """Do an Ad-Hoc Command
326 326
347 form.makeFields(form_values) 347 form.makeFields(form_values)
348 command_elt.addChild(form.toElement()) 348 command_elt.addChild(form.toElement())
349 d = iq_elt.send() 349 d = iq_elt.send()
350 return d 350 return d
351 351
352 def getCommandElt(self, iq_elt): 352 def get_command_elt(self, iq_elt):
353 try: 353 try:
354 return next(iq_elt.elements(NS_COMMANDS, "command")) 354 return next(iq_elt.elements(NS_COMMANDS, "command"))
355 except StopIteration: 355 except StopIteration:
356 raise exceptions.NotFound(_("Missing command element")) 356 raise exceptions.NotFound(_("Missing command element"))
357 357
358 def adHocError(self, error_type): 358 def ad_hoc_error(self, error_type):
359 """Shortcut to raise an AdHocError 359 """Shortcut to raise an AdHocError
360 360
361 @param error_type(unicode): one of XEP_0050.ERROR 361 @param error_type(unicode): one of XEP_0050.ERROR
362 """ 362 """
363 raise AdHocError(error_type) 363 raise AdHocError(error_type)
364 364
365 def _items2XMLUI(self, items, no_instructions): 365 def _items_2_xmlui(self, items, no_instructions):
366 """Convert discovery items to XMLUI dialog """ 366 """Convert discovery items to XMLUI dialog """
367 # TODO: manage items on different jids 367 # TODO: manage items on different jids
368 form_ui = xml_tools.XMLUI("form", submit_id=self.__requesting_id) 368 form_ui = xml_tools.XMLUI("form", submit_id=self.__requesting_id)
369 369
370 if not no_instructions: 370 if not no_instructions:
372 372
373 options = [(item.nodeIdentifier, item.name) for item in items] 373 options = [(item.nodeIdentifier, item.name) for item in items]
374 form_ui.addList("node", options) 374 form_ui.addList("node", options)
375 return form_ui 375 return form_ui
376 376
377 def _getDataLvl(self, type_): 377 def _get_data_lvl(self, type_):
378 """Return the constant corresponding to <note/> type attribute value 378 """Return the constant corresponding to <note/> type attribute value
379 379
380 @param type_: note type (see XEP-0050 §4.3) 380 @param type_: note type (see XEP-0050 §4.3)
381 @return: a C.XMLUI_DATA_LVL_* constant 381 @return: a C.XMLUI_DATA_LVL_* constant
382 """ 382 """
387 else: 387 else:
388 if type_ != "info": 388 if type_ != "info":
389 log.warning(_("Invalid note type [%s], using info") % type_) 389 log.warning(_("Invalid note type [%s], using info") % type_)
390 return C.XMLUI_DATA_LVL_INFO 390 return C.XMLUI_DATA_LVL_INFO
391 391
392 def _mergeNotes(self, notes): 392 def _merge_notes(self, notes):
393 """Merge notes with level prefix (e.g. "ERROR: the message") 393 """Merge notes with level prefix (e.g. "ERROR: the message")
394 394
395 @param notes (list): list of tuple (level, message) 395 @param notes (list): list of tuple (level, message)
396 @return: list of messages 396 @return: list of messages
397 """ 397 """
400 C.XMLUI_DATA_LVL_WARNING: "%s: " % _("WARNING"), 400 C.XMLUI_DATA_LVL_WARNING: "%s: " % _("WARNING"),
401 C.XMLUI_DATA_LVL_ERROR: "%s: " % _("ERROR"), 401 C.XMLUI_DATA_LVL_ERROR: "%s: " % _("ERROR"),
402 } 402 }
403 return ["%s%s" % (lvl_map[lvl], msg) for lvl, msg in notes] 403 return ["%s%s" % (lvl_map[lvl], msg) for lvl, msg in notes]
404 404
405 def parseCommandAnswer(self, iq_elt): 405 def parse_command_answer(self, iq_elt):
406 command_elt = self.getCommandElt(iq_elt) 406 command_elt = self.get_command_elt(iq_elt)
407 data = {} 407 data = {}
408 data["status"] = command_elt.getAttribute("status", XEP_0050.STATUS.EXECUTING) 408 data["status"] = command_elt.getAttribute("status", XEP_0050.STATUS.EXECUTING)
409 data["session_id"] = command_elt.getAttribute("sessionid") 409 data["session_id"] = command_elt.getAttribute("sessionid")
410 data["notes"] = notes = [] 410 data["notes"] = notes = []
411 for note_elt in command_elt.elements(NS_COMMANDS, "note"): 411 for note_elt in command_elt.elements(NS_COMMANDS, "note"):
412 notes.append( 412 notes.append(
413 ( 413 (
414 self._getDataLvl(note_elt.getAttribute("type", "info")), 414 self._get_data_lvl(note_elt.getAttribute("type", "info")),
415 str(note_elt), 415 str(note_elt),
416 ) 416 )
417 ) 417 )
418 418
419 return command_elt, data 419 return command_elt, data
420 420
421 421
422 def _commandsAnswer2XMLUI(self, iq_elt, session_id, session_data): 422 def _commands_answer_2_xmlui(self, iq_elt, session_id, session_data):
423 """Convert command answer to an ui for frontend 423 """Convert command answer to an ui for frontend
424 424
425 @param iq_elt: command result 425 @param iq_elt: command result
426 @param session_id: id of the session used with the frontend 426 @param session_id: id of the session used with the frontend
427 @param profile_key: %(doc_profile_key)s 427 @param profile_key: %(doc_profile_key)s
428 """ 428 """
429 command_elt, answer_data = self.parseCommandAnswer(iq_elt) 429 command_elt, answer_data = self.parse_command_answer(iq_elt)
430 status = answer_data["status"] 430 status = answer_data["status"]
431 if status in [XEP_0050.STATUS.COMPLETED, XEP_0050.STATUS.CANCELED]: 431 if status in [XEP_0050.STATUS.COMPLETED, XEP_0050.STATUS.CANCELED]:
432 # the command session is finished, we purge our session 432 # the command session is finished, we purge our session
433 del self.requesting[session_id] 433 del self.requesting[session_id]
434 if status == XEP_0050.STATUS.COMPLETED: 434 if status == XEP_0050.STATUS.COMPLETED:
466 dlg_level = notes[0][0] if len(notes) == 1 else C.XMLUI_DATA_LVL_INFO 466 dlg_level = notes[0][0] if len(notes) == 1 else C.XMLUI_DATA_LVL_INFO
467 return xml_tools.XMLUI( 467 return xml_tools.XMLUI(
468 C.XMLUI_DIALOG, 468 C.XMLUI_DIALOG,
469 dialog_opt={ 469 dialog_opt={
470 C.XMLUI_DATA_TYPE: C.XMLUI_DIALOG_NOTE, 470 C.XMLUI_DATA_TYPE: C.XMLUI_DIALOG_NOTE,
471 C.XMLUI_DATA_MESS: "\n".join(self._mergeNotes(notes)), 471 C.XMLUI_DATA_MESS: "\n".join(self._merge_notes(notes)),
472 C.XMLUI_DATA_LVL: dlg_level, 472 C.XMLUI_DATA_LVL: dlg_level,
473 }, 473 },
474 session_id=session_id, 474 session_id=session_id,
475 ) 475 )
476 476
477 if session_id is None: 477 if session_id is None:
478 xmlui = xml_tools.dataFormEltResult2XMLUI(data_elt) 478 xmlui = xml_tools.data_form_elt_result_2_xmlui(data_elt)
479 if notes: 479 if notes:
480 for level, note in notes: 480 for level, note in notes:
481 if level != "info": 481 if level != "info":
482 note = f"[{level}] {note}" 482 note = f"[{level}] {note}"
483 xmlui.addWidget("text", note) 483 xmlui.add_widget("text", note)
484 return xmlui 484 return xmlui
485 485
486 form = data_form.Form.fromElement(data_elt) 486 form = data_form.Form.fromElement(data_elt)
487 # we add any present note to the instructions 487 # we add any present note to the instructions
488 form.instructions.extend(self._mergeNotes(notes)) 488 form.instructions.extend(self._merge_notes(notes))
489 return xml_tools.dataForm2XMLUI(form, self.__requesting_id, session_id=session_id) 489 return xml_tools.data_form_2_xmlui(form, self.__requesting_id, session_id=session_id)
490 490
491 def _requestingEntity(self, data, profile): 491 def _requesting_entity(self, data, profile):
492 def serialise(ret_data): 492 def serialise(ret_data):
493 if "xmlui" in ret_data: 493 if "xmlui" in ret_data:
494 ret_data["xmlui"] = ret_data["xmlui"].toXml() 494 ret_data["xmlui"] = ret_data["xmlui"].toXml()
495 return ret_data 495 return ret_data
496 496
497 d = self.requestingEntity(data, profile) 497 d = self.requesting_entity(data, profile)
498 d.addCallback(serialise) 498 d.addCallback(serialise)
499 return d 499 return d
500 500
501 def requestingEntity(self, data, profile): 501 def requesting_entity(self, data, profile):
502 """Request and entity and create XMLUI accordingly. 502 """Request and entity and create XMLUI accordingly.
503 503
504 @param data: data returned by previous XMLUI (first one must come from 504 @param data: data returned by previous XMLUI (first one must come from
505 self._commandsMenu) 505 self._commands_menu)
506 @param profile: %(doc_profile)s 506 @param profile: %(doc_profile)s
507 @return: callback dict result (with "xmlui" corresponding to the answering 507 @return: callback dict result (with "xmlui" corresponding to the answering
508 dialog, or empty if it's finished without error) 508 dialog, or empty if it's finished without error)
509 """ 509 """
510 if C.bool(data.get("cancelled", C.BOOL_FALSE)): 510 if C.bool(data.get("cancelled", C.BOOL_FALSE)):
511 return defer.succeed({}) 511 return defer.succeed({})
512 data_form_values = xml_tools.XMLUIResult2DataFormResult(data) 512 data_form_values = xml_tools.xmlui_result_2_data_form_result(data)
513 client = self.host.getClient(profile) 513 client = self.host.get_client(profile)
514 # TODO: cancel, prev and next are not managed 514 # TODO: cancel, prev and next are not managed
515 # TODO: managed answerer errors 515 # TODO: managed answerer errors
516 # TODO: manage nodes with a non data form payload 516 # TODO: manage nodes with a non data form payload
517 if "session_id" not in data: 517 if "session_id" not in data:
518 # we just had the jid, we now request it for the available commands 518 # we just had the jid, we now request it for the available commands
519 session_id, session_data = self.requesting.newSession(profile=client.profile) 519 session_id, session_data = self.requesting.new_session(profile=client.profile)
520 entity = jid.JID(data[xml_tools.SAT_FORM_PREFIX + "jid"]) 520 entity = jid.JID(data[xml_tools.SAT_FORM_PREFIX + "jid"])
521 session_data["jid"] = entity 521 session_data["jid"] = entity
522 d = self.listUI(client, entity) 522 d = self.list_ui(client, entity)
523 523
524 def sendItems(xmlui): 524 def send_items(xmlui):
525 xmlui.session_id = session_id # we need to keep track of the session 525 xmlui.session_id = session_id # we need to keep track of the session
526 return {"xmlui": xmlui} 526 return {"xmlui": xmlui}
527 527
528 d.addCallback(sendItems) 528 d.addCallback(send_items)
529 else: 529 else:
530 # we have started a several forms sessions 530 # we have started a several forms sessions
531 try: 531 try:
532 session_data = self.requesting.profileGet( 532 session_data = self.requesting.profile_get(
533 data["session_id"], client.profile 533 data["session_id"], client.profile
534 ) 534 )
535 except KeyError: 535 except KeyError:
536 log.warning("session id doesn't exist, session has probably expired") 536 log.warning("session id doesn't exist, session has probably expired")
537 # TODO: send error dialog 537 # TODO: send error dialog
550 remote_id = session_data.get("remote_id") 550 remote_id = session_data.get("remote_id")
551 551
552 # we request execute node's command 552 # we request execute node's command
553 d = self.do(client, entity, session_data["node"], action=XEP_0050.ACTION.EXECUTE, 553 d = self.do(client, entity, session_data["node"], action=XEP_0050.ACTION.EXECUTE,
554 session_id=remote_id, form_values=data_form_values) 554 session_id=remote_id, form_values=data_form_values)
555 d.addCallback(self._commandsAnswer2XMLUI, session_id, session_data) 555 d.addCallback(self._commands_answer_2_xmlui, session_id, session_data)
556 d.addCallback(lambda xmlui: {"xmlui": xmlui} if xmlui is not None else {}) 556 d.addCallback(lambda xmlui: {"xmlui": xmlui} if xmlui is not None else {})
557 557
558 return d 558 return d
559 559
560 def _commandsMenu(self, menu_data, profile): 560 def _commands_menu(self, menu_data, profile):
561 """First XMLUI activated by menu: ask for target jid 561 """First XMLUI activated by menu: ask for target jid
562 562
563 @param profile: %(doc_profile)s 563 @param profile: %(doc_profile)s
564 """ 564 """
565 form_ui = xml_tools.XMLUI("form", submit_id=self.__requesting_id) 565 form_ui = xml_tools.XMLUI("form", submit_id=self.__requesting_id)
566 form_ui.addText(_("Please enter target jid"), "instructions") 566 form_ui.addText(_("Please enter target jid"), "instructions")
567 form_ui.changeContainer("pairs") 567 form_ui.change_container("pairs")
568 form_ui.addLabel("jid") 568 form_ui.addLabel("jid")
569 form_ui.addString("jid", value=self.host.getClient(profile).jid.host) 569 form_ui.addString("jid", value=self.host.get_client(profile).jid.host)
570 return {"xmlui": form_ui.toXml()} 570 return {"xmlui": form_ui.toXml()}
571 571
572 def _statusCallback(self, client, command_elt, session_data, action, node): 572 def _status_callback(self, client, command_elt, session_data, action, node):
573 """Ad-hoc command used to change the "show" part of status""" 573 """Ad-hoc command used to change the "show" part of status"""
574 actions = session_data.setdefault("actions", []) 574 actions = session_data.setdefault("actions", [])
575 actions.append(action) 575 actions.append(action)
576 576
577 if len(actions) == 1: 577 if len(actions) == 1:
594 try: 594 try:
595 x_elt = next(command_elt.elements(data_form.NS_X_DATA, "x")) 595 x_elt = next(command_elt.elements(data_form.NS_X_DATA, "x"))
596 answer_form = data_form.Form.fromElement(x_elt) 596 answer_form = data_form.Form.fromElement(x_elt)
597 show = answer_form["show"] 597 show = answer_form["show"]
598 except (KeyError, StopIteration): 598 except (KeyError, StopIteration):
599 self.adHocError(XEP_0050.ERROR.BAD_PAYLOAD) 599 self.ad_hoc_error(XEP_0050.ERROR.BAD_PAYLOAD)
600 if show not in SHOWS: 600 if show not in SHOWS:
601 self.adHocError(XEP_0050.ERROR.BAD_PAYLOAD) 601 self.ad_hoc_error(XEP_0050.ERROR.BAD_PAYLOAD)
602 if show == "disconnect": 602 if show == "disconnect":
603 self.host.disconnect(client.profile) 603 self.host.disconnect(client.profile)
604 else: 604 else:
605 self.host.setPresence(show=show, profile_key=client.profile) 605 self.host.presence_set(show=show, profile_key=client.profile)
606 606
607 # job done, we can end the session 607 # job done, we can end the session
608 status = XEP_0050.STATUS.COMPLETED 608 status = XEP_0050.STATUS.COMPLETED
609 payload = None 609 payload = None
610 note = (self.NOTE.INFO, _("Status updated")) 610 note = (self.NOTE.INFO, _("Status updated"))
611 else: 611 else:
612 self.adHocError(XEP_0050.ERROR.INTERNAL) 612 self.ad_hoc_error(XEP_0050.ERROR.INTERNAL)
613 613
614 return (payload, status, None, note) 614 return (payload, status, None, note)
615 615
616 def _run(self, service_jid_s="", node="", profile_key=C.PROF_KEY_NONE): 616 def _run(self, service_jid_s="", node="", profile_key=C.PROF_KEY_NONE):
617 client = self.host.getClient(profile_key) 617 client = self.host.get_client(profile_key)
618 service_jid = jid.JID(service_jid_s) if service_jid_s else None 618 service_jid = jid.JID(service_jid_s) if service_jid_s else None
619 d = defer.ensureDeferred(self.run(client, service_jid, node or None)) 619 d = defer.ensureDeferred(self.run(client, service_jid, node or None))
620 d.addCallback(lambda xmlui: xmlui.toXml()) 620 d.addCallback(lambda xmlui: xmlui.toXml())
621 return d 621 return d
622 622
629 None to get initial list 629 None to get initial list
630 @return(unicode): command page XMLUI 630 @return(unicode): command page XMLUI
631 """ 631 """
632 if service_jid is None: 632 if service_jid is None:
633 service_jid = jid.JID(client.jid.host) 633 service_jid = jid.JID(client.jid.host)
634 session_id, session_data = self.requesting.newSession(profile=client.profile) 634 session_id, session_data = self.requesting.new_session(profile=client.profile)
635 session_data["jid"] = service_jid 635 session_data["jid"] = service_jid
636 if node is None: 636 if node is None:
637 xmlui = await self.listUI(client, service_jid) 637 xmlui = await self.list_ui(client, service_jid)
638 else: 638 else:
639 session_data["node"] = node 639 session_data["node"] = node
640 cb_data = await self.requestingEntity( 640 cb_data = await self.requesting_entity(
641 {"session_id": session_id}, client.profile 641 {"session_id": session_id}, client.profile
642 ) 642 )
643 xmlui = cb_data["xmlui"] 643 xmlui = cb_data["xmlui"]
644 644
645 xmlui.session_id = session_id 645 xmlui.session_id = session_id
653 @return D(disco.DiscoItems): found commands 653 @return D(disco.DiscoItems): found commands
654 """ 654 """
655 d = self.host.getDiscoItems(client, to_jid, NS_COMMANDS) 655 d = self.host.getDiscoItems(client, to_jid, NS_COMMANDS)
656 return d 656 return d
657 657
658 def _listUI(self, to_jid_s, profile_key): 658 def _list_ui(self, to_jid_s, profile_key):
659 client = self.host.getClient(profile_key) 659 client = self.host.get_client(profile_key)
660 to_jid = jid.JID(to_jid_s) if to_jid_s else None 660 to_jid = jid.JID(to_jid_s) if to_jid_s else None
661 d = self.listUI(client, to_jid, no_instructions=True) 661 d = self.list_ui(client, to_jid, no_instructions=True)
662 d.addCallback(lambda xmlui: xmlui.toXml()) 662 d.addCallback(lambda xmlui: xmlui.toXml())
663 return d 663 return d
664 664
665 def listUI(self, client, to_jid, no_instructions=False): 665 def list_ui(self, client, to_jid, no_instructions=False):
666 """Request available commands and generate XMLUI 666 """Request available commands and generate XMLUI
667 667
668 @param to_jid(jid.JID, None): the entity answering the commands 668 @param to_jid(jid.JID, None): the entity answering the commands
669 None to use profile's server 669 None to use profile's server
670 @param no_instructions(bool): if True, don't add instructions widget 670 @param no_instructions(bool): if True, don't add instructions widget
671 @return D(xml_tools.XMLUI): UI with the commands 671 @return D(xml_tools.XMLUI): UI with the commands
672 """ 672 """
673 d = self.list(client, to_jid) 673 d = self.list(client, to_jid)
674 d.addCallback(self._items2XMLUI, no_instructions) 674 d.addCallback(self._items_2_xmlui, no_instructions)
675 return d 675 return d
676 676
677 def _sequence(self, sequence, node, service_jid_s="", profile_key=C.PROF_KEY_NONE): 677 def _sequence(self, sequence, node, service_jid_s="", profile_key=C.PROF_KEY_NONE):
678 sequence = data_format.deserialise(sequence, type_check=list) 678 sequence = data_format.deserialise(sequence, type_check=list)
679 client = self.host.getClient(profile_key) 679 client = self.host.get_client(profile_key)
680 service_jid = jid.JID(service_jid_s) if service_jid_s else None 680 service_jid = jid.JID(service_jid_s) if service_jid_s else None
681 d = defer.ensureDeferred(self.sequence(client, sequence, node, service_jid)) 681 d = defer.ensureDeferred(self.sequence(client, sequence, node, service_jid))
682 d.addCallback(lambda data: data_format.serialise(data)) 682 d.addCallback(lambda data: data_format.serialise(data))
683 return d 683 return d
684 684
709 service_jid, 709 service_jid,
710 node, 710 node,
711 session_id=session_id, 711 session_id=session_id,
712 form_values=data_to_send, 712 form_values=data_to_send,
713 ) 713 )
714 __, answer_data = self.parseCommandAnswer(iq_result_elt) 714 __, answer_data = self.parse_command_answer(iq_result_elt)
715 session_id = answer_data.pop("session_id") 715 session_id = answer_data.pop("session_id")
716 716
717 return answer_data 717 return answer_data
718 718
719 def addAdHocCommand(self, client, callback, label, node=None, features=None, 719 def add_ad_hoc_command(self, client, callback, label, node=None, features=None,
720 timeout=600, allowed_jids=None, allowed_groups=None, 720 timeout=600, allowed_jids=None, allowed_groups=None,
721 allowed_magics=None, forbidden_jids=None, forbidden_groups=None, 721 allowed_magics=None, forbidden_jids=None, forbidden_groups=None,
722 ): 722 ):
723 """Add an ad-hoc command for the current profile 723 """Add an ad-hoc command for the current profile
724 724
780 ) 780 )
781 ad_hoc_command.setHandlerParent(client) 781 ad_hoc_command.setHandlerParent(client)
782 commands = client._XEP_0050_commands 782 commands = client._XEP_0050_commands
783 commands[node] = ad_hoc_command 783 commands[node] = ad_hoc_command
784 784
785 def onCmdRequest(self, request, client): 785 def on_cmd_request(self, request, client):
786 request.handled = True 786 request.handled = True
787 requestor = jid.JID(request["from"]) 787 requestor = jid.JID(request["from"])
788 command_elt = next(request.elements(NS_COMMANDS, "command")) 788 command_elt = next(request.elements(NS_COMMANDS, "command"))
789 action = command_elt.getAttribute("action", self.ACTION.EXECUTE) 789 action = command_elt.getAttribute("action", self.ACTION.EXECUTE)
790 node = command_elt.getAttribute("node") 790 node = command_elt.getAttribute("node")
796 try: 796 try:
797 command = commands[node] 797 command = commands[node]
798 except KeyError: 798 except KeyError:
799 client.sendError(request, "item-not-found") 799 client.sendError(request, "item-not-found")
800 return 800 return
801 command.onRequest(command_elt, requestor, action, sessionid) 801 command.on_request(command_elt, requestor, action, sessionid)
802 802
803 803
804 @implementer(iwokkel.IDisco) 804 @implementer(iwokkel.IDisco)
805 class XEP_0050_handler(XMPPHandler): 805 class XEP_0050_handler(XMPPHandler):
806 806
811 def client(self): 811 def client(self):
812 return self.parent 812 return self.parent
813 813
814 def connectionInitialized(self): 814 def connectionInitialized(self):
815 self.xmlstream.addObserver( 815 self.xmlstream.addObserver(
816 CMD_REQUEST, self.plugin_parent.onCmdRequest, client=self.parent 816 CMD_REQUEST, self.plugin_parent.on_cmd_request, client=self.parent
817 ) 817 )
818 818
819 def getDiscoInfo(self, requestor, target, nodeIdentifier=""): 819 def getDiscoInfo(self, requestor, target, nodeIdentifier=""):
820 identities = [] 820 identities = []
821 if nodeIdentifier == NS_COMMANDS and self.client._XEP_0050_commands: 821 if nodeIdentifier == NS_COMMANDS and self.client._XEP_0050_commands:
826 def getDiscoItems(self, requestor, target, nodeIdentifier=""): 826 def getDiscoItems(self, requestor, target, nodeIdentifier=""):
827 ret = [] 827 ret = []
828 if nodeIdentifier == NS_COMMANDS: 828 if nodeIdentifier == NS_COMMANDS:
829 commands = self.client._XEP_0050_commands 829 commands = self.client._XEP_0050_commands
830 for command in list(commands.values()): 830 for command in list(commands.values()):
831 if command.isAuthorised(requestor): 831 if command.is_authorised(requestor):
832 ret.append( 832 ret.append(
833 disco.DiscoItem(self.parent.jid, command.node, command.getName()) 833 disco.DiscoItem(self.parent.jid, command.node, command.getName())
834 ) # TODO: manage name language 834 ) # TODO: manage name language
835 return ret 835 return ret