Mercurial > libervia-backend
comparison sat/plugins/plugin_xep_0055.py @ 3028:ab2696e34d29
Python 3 port:
/!\ this is a huge commit
/!\ starting from this commit, SàT is needs Python 3.6+
/!\ SàT maybe be instable or some feature may not work anymore, this will improve with time
This patch port backend, bridge and frontends to Python 3.
Roughly this has been done this way:
- 2to3 tools has been applied (with python 3.7)
- all references to python2 have been replaced with python3 (notably shebangs)
- fixed files not handled by 2to3 (notably the shell script)
- several manual fixes
- fixed issues reported by Python 3 that where not handled in Python 2
- replaced "async" with "async_" when needed (it's a reserved word from Python 3.7)
- replaced zope's "implements" with @implementer decorator
- temporary hack to handle data pickled in database, as str or bytes may be returned,
to be checked later
- fixed hash comparison for password
- removed some code which is not needed anymore with Python 3
- deactivated some code which needs to be checked (notably certificate validation)
- tested with jp, fixed reported issues until some basic commands worked
- ported Primitivus (after porting dependencies like urwid satext)
- more manual fixes
author | Goffi <goffi@goffi.org> |
---|---|
date | Tue, 13 Aug 2019 19:08:41 +0200 |
parents | 003b8b4b56a7 |
children | 9d0df638c8b4 |
comparison
equal
deleted
inserted
replaced
3027:ff5bcb12ae60 | 3028:ab2696e34d29 |
---|---|
1 #!/usr/bin/env python2 | 1 #!/usr/bin/env python3 |
2 # -*- coding: utf-8 -*- | 2 # -*- coding: utf-8 -*- |
3 | 3 |
4 # SAT plugin for Jabber Search (xep-0055) | 4 # SAT plugin for Jabber Search (xep-0055) |
5 # Copyright (C) 2009-2019 Jérôme Poisson (goffi@goffi.org) | 5 # Copyright (C) 2009-2019 Jérôme Poisson (goffi@goffi.org) |
6 | 6 |
34 | 34 |
35 try: | 35 try: |
36 from twisted.words.protocols.xmlstream import XMPPHandler | 36 from twisted.words.protocols.xmlstream import XMPPHandler |
37 except ImportError: | 37 except ImportError: |
38 from wokkel.subprotocols import XMPPHandler | 38 from wokkel.subprotocols import XMPPHandler |
39 from zope.interface import implements | 39 from zope.interface import implementer |
40 | 40 |
41 | 41 |
42 NS_SEARCH = "jabber:iq:search" | 42 NS_SEARCH = "jabber:iq:search" |
43 | 43 |
44 PLUGIN_INFO = { | 44 PLUGIN_INFO = { |
82 "searchGetFieldsUI", | 82 "searchGetFieldsUI", |
83 ".plugin", | 83 ".plugin", |
84 in_sign="ss", | 84 in_sign="ss", |
85 out_sign="s", | 85 out_sign="s", |
86 method=self._getFieldsUI, | 86 method=self._getFieldsUI, |
87 async=True, | 87 async_=True, |
88 ) | 88 ) |
89 host.bridge.addMethod( | 89 host.bridge.addMethod( |
90 "searchRequest", | 90 "searchRequest", |
91 ".plugin", | 91 ".plugin", |
92 in_sign="sa{ss}s", | 92 in_sign="sa{ss}s", |
93 out_sign="s", | 93 out_sign="s", |
94 method=self._searchRequest, | 94 method=self._searchRequest, |
95 async=True, | 95 async_=True, |
96 ) | 96 ) |
97 | 97 |
98 self.__search_menu_id = host.registerCallback(self._getMainUI, with_data=True) | 98 self.__search_menu_id = host.registerCallback(self._getMainUI, with_data=True) |
99 host.importMenu( | 99 host.importMenu( |
100 (D_("Contacts"), D_("Search directory")), | 100 (D_("Contacts"), D_("Search directory")), |
191 main_ui.addButton(self.__search_menu_id, _("Search"), (FIELD_SINGLE,)) | 191 main_ui.addButton(self.__search_menu_id, _("Search"), (FIELD_SINGLE,)) |
192 main_ui.addDivider("blank") | 192 main_ui.addDivider("blank") |
193 main_ui.addDivider("blank") # a blank line again after the button | 193 main_ui.addDivider("blank") # a blank line again after the button |
194 | 194 |
195 simple_data = { | 195 simple_data = { |
196 key: value for key, value in data.iteritems() if key in (FIELD_SINGLE,) | 196 key: value for key, value in data.items() if key in (FIELD_SINGLE,) |
197 } | 197 } |
198 if simple_data: | 198 if simple_data: |
199 log.debug("Simple search with %s on %s" % (simple_data, service_jid)) | 199 log.debug("Simple search with %s on %s" % (simple_data, service_jid)) |
200 sub_cont.parent.setSelected(True) | 200 sub_cont.parent.setSelected(True) |
201 main_ui.changeContainer(sub_cont.append(xml_tools.VerticalContainer(main_ui))) | 201 main_ui.changeContainer(sub_cont.append(xml_tools.VerticalContainer(main_ui))) |
232 # refresh button has been pushed, select the tab | 232 # refresh button has been pushed, select the tab |
233 sub_cont.parent.setSelected(True) | 233 sub_cont.parent.setSelected(True) |
234 # get the selected service | 234 # get the selected service |
235 service_jid_s = data.get("service_jid_extra", "") | 235 service_jid_s = data.get("service_jid_extra", "") |
236 if not service_jid_s: | 236 if not service_jid_s: |
237 service_jid_s = data.get("service_jid", unicode(services[0])) | 237 service_jid_s = data.get("service_jid", str(services[0])) |
238 log.debug("Refreshing search fields for %s" % service_jid_s) | 238 log.debug("Refreshing search fields for %s" % service_jid_s) |
239 else: | 239 else: |
240 service_jid_s = data.get(FIELD_CURRENT_SERVICE, unicode(services[0])) | 240 service_jid_s = data.get(FIELD_CURRENT_SERVICE, str(services[0])) |
241 services_s = [unicode(service) for service in services] | 241 services_s = [str(service) for service in services] |
242 if service_jid_s not in services_s: | 242 if service_jid_s not in services_s: |
243 services_s.append(service_jid_s) | 243 services_s.append(service_jid_s) |
244 | 244 |
245 main_ui.changeContainer(sub_cont.append(xml_tools.PairsContainer(main_ui))) | 245 main_ui.changeContainer(sub_cont.append(xml_tools.PairsContainer(main_ui))) |
246 main_ui.addLabel(_("Search on")) | 246 main_ui.addLabel(_("Search on")) |
284 | 284 |
285 @return: a __ Deferred | 285 @return: a __ Deferred |
286 """ | 286 """ |
287 field_list = data_form.Form.fromElement(form_elt).fieldList | 287 field_list = data_form.Form.fromElement(form_elt).fieldList |
288 adv_fields = [field.var for field in field_list if field.var] | 288 adv_fields = [field.var for field in field_list if field.var] |
289 adv_data = {key: value for key, value in data.iteritems() if key in adv_fields} | 289 adv_data = {key: value for key, value in data.items() if key in adv_fields} |
290 | 290 |
291 xml_tools.dataForm2Widgets(main_ui, data_form.Form.fromElement(form_elt)) | 291 xml_tools.dataForm2Widgets(main_ui, data_form.Form.fromElement(form_elt)) |
292 | 292 |
293 # refill the submitted values | 293 # refill the submitted values |
294 # FIXME: wokkel's data_form.Form.fromElement doesn't parse the values, so we do it directly in XMLUI for now | 294 # FIXME: wokkel's data_form.Form.fromElement doesn't parse the values, so we do it directly in XMLUI for now |
330 if [child for child in elt.children if child.name == "item"]: | 330 if [child for child in elt.children if child.name == "item"]: |
331 headers, xmlui_data = xml_tools.dataFormEltResult2XMLUIData(elt) | 331 headers, xmlui_data = xml_tools.dataFormEltResult2XMLUIData(elt) |
332 if "jid" in headers: # use XMLUI JidsListWidget to display the results | 332 if "jid" in headers: # use XMLUI JidsListWidget to display the results |
333 values = {} | 333 values = {} |
334 for i in range(len(xmlui_data)): | 334 for i in range(len(xmlui_data)): |
335 header = headers.keys()[i % len(headers)] | 335 header = list(headers.keys())[i % len(headers)] |
336 widget_type, widget_args, widget_kwargs = xmlui_data[i] | 336 widget_type, widget_args, widget_kwargs = xmlui_data[i] |
337 value = widget_args[0] | 337 value = widget_args[0] |
338 values.setdefault(header, []).append( | 338 values.setdefault(header, []).append( |
339 jid.JID(value) if header == "jid" else value | 339 jid.JID(value) if header == "jid" else value |
340 ) | 340 ) |
341 main_ui.addJidsList(jids=values["jid"], name=D_(u"Search results")) | 341 main_ui.addJidsList(jids=values["jid"], name=D_("Search results")) |
342 # TODO: also display the values other than JID | 342 # TODO: also display the values other than JID |
343 else: | 343 else: |
344 xml_tools.XMLUIData2AdvancedList(main_ui, headers, xmlui_data) | 344 xml_tools.XMLUIData2AdvancedList(main_ui, headers, xmlui_data) |
345 else: | 345 else: |
346 main_ui.addText(D_("The search gave no result")) | 346 main_ui.addText(D_("The search gave no result")) |
379 | 379 |
380 @param answer (domish.Element): search query element | 380 @param answer (domish.Element): search query element |
381 @return: domish.Element | 381 @return: domish.Element |
382 """ | 382 """ |
383 try: | 383 try: |
384 query_elts = answer.elements("jabber:iq:search", "query").next() | 384 query_elts = next(answer.elements("jabber:iq:search", "query")) |
385 except StopIteration: | 385 except StopIteration: |
386 log.info(_("No query element found")) | 386 log.info(_("No query element found")) |
387 raise DataError # FIXME: StanzaError is probably more appropriate, check the RFC | 387 raise DataError # FIXME: StanzaError is probably more appropriate, check the RFC |
388 try: | 388 try: |
389 form_elt = query_elts.elements(data_form.NS_X_DATA, "x").next() | 389 form_elt = next(query_elts.elements(data_form.NS_X_DATA, "x")) |
390 except StopIteration: | 390 except StopIteration: |
391 log.info(_("No data form found")) | 391 log.info(_("No data form found")) |
392 raise NotImplementedError( | 392 raise NotImplementedError( |
393 "Only search through data form is implemented so far" | 393 "Only search through data form is implemented so far" |
394 ) | 394 ) |
398 """Errback to self.getFieldsUI. | 398 """Errback to self.getFieldsUI. |
399 | 399 |
400 @param failure (defer.failure.Failure): twisted failure | 400 @param failure (defer.failure.Failure): twisted failure |
401 @raise: the unchanged defer.failure.Failure | 401 @raise: the unchanged defer.failure.Failure |
402 """ | 402 """ |
403 log.info(_("Fields request failure: %s") % unicode(failure.getErrorMessage())) | 403 log.info(_("Fields request failure: %s") % str(failure.getErrorMessage())) |
404 raise failure | 404 raise failure |
405 | 405 |
406 ## Do the search ## | 406 ## Do the search ## |
407 | 407 |
408 def _searchRequest(self, to_jid_s, search_data, profile_key): | 408 def _searchRequest(self, to_jid_s, search_data, profile_key): |
486 | 486 |
487 @param answer (domish.Element): search query element | 487 @param answer (domish.Element): search query element |
488 @return: domish.Element | 488 @return: domish.Element |
489 """ | 489 """ |
490 try: | 490 try: |
491 query_elts = answer.elements("jabber:iq:search", "query").next() | 491 query_elts = next(answer.elements("jabber:iq:search", "query")) |
492 except StopIteration: | 492 except StopIteration: |
493 log.info(_("No query element found")) | 493 log.info(_("No query element found")) |
494 raise DataError # FIXME: StanzaError is probably more appropriate, check the RFC | 494 raise DataError # FIXME: StanzaError is probably more appropriate, check the RFC |
495 try: | 495 try: |
496 form_elt = query_elts.elements(data_form.NS_X_DATA, "x").next() | 496 form_elt = next(query_elts.elements(data_form.NS_X_DATA, "x")) |
497 except StopIteration: | 497 except StopIteration: |
498 log.info(_("No data form found")) | 498 log.info(_("No data form found")) |
499 raise NotImplementedError( | 499 raise NotImplementedError( |
500 "Only search through data form is implemented so far" | 500 "Only search through data form is implemented so far" |
501 ) | 501 ) |
505 """Errback to self.searchRequest. | 505 """Errback to self.searchRequest. |
506 | 506 |
507 @param failure (defer.failure.Failure): twisted failure | 507 @param failure (defer.failure.Failure): twisted failure |
508 @raise: the unchanged defer.failure.Failure | 508 @raise: the unchanged defer.failure.Failure |
509 """ | 509 """ |
510 log.info(_("Search request failure: %s") % unicode(failure.getErrorMessage())) | 510 log.info(_("Search request failure: %s") % str(failure.getErrorMessage())) |
511 raise failure | 511 raise failure |
512 | 512 |
513 | 513 |
514 @implementer(iwokkel.IDisco) | |
514 class XEP_0055_handler(XMPPHandler): | 515 class XEP_0055_handler(XMPPHandler): |
515 implements(iwokkel.IDisco) | |
516 | 516 |
517 def __init__(self, plugin_parent, profile): | 517 def __init__(self, plugin_parent, profile): |
518 self.plugin_parent = plugin_parent | 518 self.plugin_parent = plugin_parent |
519 self.host = plugin_parent.host | 519 self.host = plugin_parent.host |
520 self.profile = profile | 520 self.profile = profile |