Philipp Hörist pushed to branch master at gajim / python-nbxmpp
Commits:
-
cf7f0625
by Philipp Hörist at 2019-04-06T21:25:37Z
-
11dffacf
by Philipp Hörist at 2019-04-06T21:26:47Z
5 changed files:
- nbxmpp/const.py
- nbxmpp/dispatcher.py
- + nbxmpp/modules/adhoc.py
- + nbxmpp/modules/discovery.py
- nbxmpp/structs.py
Changes:
| ... | ... | @@ -296,6 +296,26 @@ class AnonymityMode(Enum): |
| 296 | 296 |
NONE = 'none'
|
| 297 | 297 |
|
| 298 | 298 |
|
| 299 |
+class AdHocStatus(Enum):
|
|
| 300 |
+ EXECUTING = 'executing'
|
|
| 301 |
+ COMPLETED = 'completed'
|
|
| 302 |
+ CANCELED = 'canceled'
|
|
| 303 |
+ |
|
| 304 |
+ |
|
| 305 |
+class AdHocAction(Enum):
|
|
| 306 |
+ EXECUTE = 'execute'
|
|
| 307 |
+ CANCEL = 'cancel'
|
|
| 308 |
+ PREV = 'prev'
|
|
| 309 |
+ NEXT = 'next'
|
|
| 310 |
+ COMPLETE = 'complete'
|
|
| 311 |
+ |
|
| 312 |
+ |
|
| 313 |
+class AdHocNoteType(Enum):
|
|
| 314 |
+ INFO = 'info'
|
|
| 315 |
+ WARN = 'warn'
|
|
| 316 |
+ ERROR = 'error'
|
|
| 317 |
+ |
|
| 318 |
+ |
|
| 299 | 319 |
MOODS = [
|
| 300 | 320 |
'afraid',
|
| 301 | 321 |
'amazed',
|
| ... | ... | @@ -67,6 +67,7 @@ from nbxmpp.modules.omemo import OMEMO |
| 67 | 67 |
from nbxmpp.modules.annotations import Annotations
|
| 68 | 68 |
from nbxmpp.modules.muclumbus import Muclumbus
|
| 69 | 69 |
from nbxmpp.modules.software_version import SoftwareVersion
|
| 70 |
+from nbxmpp.modules.adhoc import AdHoc
|
|
| 70 | 71 |
from nbxmpp.modules.misc import unwrap_carbon
|
| 71 | 72 |
from nbxmpp.modules.misc import unwrap_mam
|
| 72 | 73 |
from nbxmpp.util import get_properties_struct
|
| ... | ... | @@ -202,6 +203,7 @@ class XMPPDispatcher(PlugIn): |
| 202 | 203 |
self._modules['Annotations'] = Annotations(self._owner)
|
| 203 | 204 |
self._modules['Muclumbus'] = Muclumbus(self._owner)
|
| 204 | 205 |
self._modules['SoftwareVersion'] = SoftwareVersion(self._owner)
|
| 206 |
+ self._modules['AdHoc'] = AdHoc(self._owner)
|
|
| 205 | 207 |
|
| 206 | 208 |
for instance in self._modules.values():
|
| 207 | 209 |
for handler in instance.handlers:
|
| 1 |
+# Copyright (C) 2019 Philipp Hörist <philipp AT hoerist.com>
|
|
| 2 |
+#
|
|
| 3 |
+# This file is part of nbxmpp.
|
|
| 4 |
+#
|
|
| 5 |
+# This program is free software; you can redistribute it and/or
|
|
| 6 |
+# modify it under the terms of the GNU General Public License
|
|
| 7 |
+# as published by the Free Software Foundation; either version 3
|
|
| 8 |
+# of the License, or (at your option) 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 |
+# You should have received a copy of the GNU General Public License
|
|
| 16 |
+# along with this program; If not, see <http://www.gnu.org/licenses/>.
|
|
| 17 |
+ |
|
| 18 |
+import logging
|
|
| 19 |
+ |
|
| 20 |
+from nbxmpp.protocol import NS_COMMANDS
|
|
| 21 |
+from nbxmpp.protocol import NS_DISCO_ITEMS
|
|
| 22 |
+from nbxmpp.protocol import NS_DATA
|
|
| 23 |
+from nbxmpp.protocol import Iq
|
|
| 24 |
+from nbxmpp.protocol import isResultNode
|
|
| 25 |
+from nbxmpp.protocol import Node
|
|
| 26 |
+from nbxmpp.util import call_on_response
|
|
| 27 |
+from nbxmpp.util import callback
|
|
| 28 |
+from nbxmpp.util import raise_error
|
|
| 29 |
+from nbxmpp.structs import AdHocCommand
|
|
| 30 |
+from nbxmpp.structs import AdHocCommandNote
|
|
| 31 |
+from nbxmpp.const import AdHocStatus
|
|
| 32 |
+from nbxmpp.const import AdHocAction
|
|
| 33 |
+from nbxmpp.const import AdHocNoteType
|
|
| 34 |
+from nbxmpp.modules.discovery import get_disco_request
|
|
| 35 |
+ |
|
| 36 |
+ |
|
| 37 |
+log = logging.getLogger('nbxmpp.m.adhoc')
|
|
| 38 |
+ |
|
| 39 |
+ |
|
| 40 |
+class AdHoc:
|
|
| 41 |
+ def __init__(self, client):
|
|
| 42 |
+ self._client = client
|
|
| 43 |
+ self.handlers = []
|
|
| 44 |
+ |
|
| 45 |
+ @call_on_response('_command_list_received')
|
|
| 46 |
+ def request_command_list(self, jid=None):
|
|
| 47 |
+ if jid is None:
|
|
| 48 |
+ jid = self._client.get_bound_jid().getBare()
|
|
| 49 |
+ return get_disco_request(NS_DISCO_ITEMS, jid, node=NS_COMMANDS)
|
|
| 50 |
+ |
|
| 51 |
+ @callback
|
|
| 52 |
+ def _command_list_received(self, stanza):
|
|
| 53 |
+ if not isResultNode(stanza):
|
|
| 54 |
+ return raise_error(log.info, stanza)
|
|
| 55 |
+ |
|
| 56 |
+ payload = stanza.getQueryPayload()
|
|
| 57 |
+ if not payload:
|
|
| 58 |
+ return raise_error(log.warning, stanza, 'stanza-malformed')
|
|
| 59 |
+ |
|
| 60 |
+ command_list = []
|
|
| 61 |
+ for item in payload:
|
|
| 62 |
+ if item.getName() != 'item':
|
|
| 63 |
+ continue
|
|
| 64 |
+ try:
|
|
| 65 |
+ command_list.append(AdHocCommand(**item.getAttrs()))
|
|
| 66 |
+ except Exception as error:
|
|
| 67 |
+ log.warning(error)
|
|
| 68 |
+ return raise_error(log.warning, stanza, 'stanza-malformed')
|
|
| 69 |
+ |
|
| 70 |
+ return command_list
|
|
| 71 |
+ |
|
| 72 |
+ @call_on_response('_command_result_received')
|
|
| 73 |
+ def execute_command(self, command, action=None, dataform=None):
|
|
| 74 |
+ if action is None:
|
|
| 75 |
+ action = AdHocAction.EXECUTE
|
|
| 76 |
+ attrs = {'node': command.node,
|
|
| 77 |
+ 'xmlns': NS_COMMANDS,
|
|
| 78 |
+ 'action': action.value}
|
|
| 79 |
+ if command.sessionid is not None:
|
|
| 80 |
+ attrs['sessionid'] = command.sessionid
|
|
| 81 |
+ |
|
| 82 |
+ command_node = Node('command', attrs=attrs)
|
|
| 83 |
+ if dataform is not None:
|
|
| 84 |
+ command_node.addChild(node=dataform)
|
|
| 85 |
+ iq = Iq('set', to=command.jid)
|
|
| 86 |
+ iq.addChild(node=command_node)
|
|
| 87 |
+ return iq
|
|
| 88 |
+ |
|
| 89 |
+ @callback
|
|
| 90 |
+ def _command_result_received(self, stanza):
|
|
| 91 |
+ if not isResultNode(stanza):
|
|
| 92 |
+ return raise_error(log.info, stanza)
|
|
| 93 |
+ |
|
| 94 |
+ command = stanza.getTag('command', namespace=NS_COMMANDS)
|
|
| 95 |
+ if command is None:
|
|
| 96 |
+ return raise_error(log.warning, stanza, 'stanza-malformed')
|
|
| 97 |
+ |
|
| 98 |
+ attrs = command.getAttrs()
|
|
| 99 |
+ notes = []
|
|
| 100 |
+ actions = []
|
|
| 101 |
+ try:
|
|
| 102 |
+ for note in command.getTags('note'):
|
|
| 103 |
+ type_ = note.getAttr('type')
|
|
| 104 |
+ if type_ is not None:
|
|
| 105 |
+ type_ = AdHocNoteType(note.getAttr('type'))
|
|
| 106 |
+ notes.append(AdHocCommandNote(text=note.getData(),
|
|
| 107 |
+ type=type_))
|
|
| 108 |
+ |
|
| 109 |
+ actions_ = command.getTag('actions')
|
|
| 110 |
+ if actions_ is not None:
|
|
| 111 |
+ for action in actions_.getChildren():
|
|
| 112 |
+ actions.append(AdHocAction(action.getName()))
|
|
| 113 |
+ |
|
| 114 |
+ return AdHocCommand(
|
|
| 115 |
+ jid=str(stanza.getFrom()),
|
|
| 116 |
+ name=None,
|
|
| 117 |
+ node=attrs['node'],
|
|
| 118 |
+ sessionid=attrs.get('sessionid'),
|
|
| 119 |
+ status=AdHocStatus(attrs['status']),
|
|
| 120 |
+ data=command.getTag('x', namespace=NS_DATA),
|
|
| 121 |
+ actions=actions,
|
|
| 122 |
+ notes=notes)
|
|
| 123 |
+ except Exception as error:
|
|
| 124 |
+ log.warning(error)
|
|
| 125 |
+ return raise_error(log.warning, stanza, 'stanza-malformed')
|
| 1 |
+# Copyright (C) 2019 Philipp Hörist <philipp AT hoerist.com>
|
|
| 2 |
+#
|
|
| 3 |
+# This file is part of nbxmpp.
|
|
| 4 |
+#
|
|
| 5 |
+# This program is free software; you can redistribute it and/or
|
|
| 6 |
+# modify it under the terms of the GNU General Public License
|
|
| 7 |
+# as published by the Free Software Foundation; either version 3
|
|
| 8 |
+# of the License, or (at your option) 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 |
+# You should have received a copy of the GNU General Public License
|
|
| 16 |
+# along with this program; If not, see <http://www.gnu.org/licenses/>.
|
|
| 17 |
+ |
|
| 18 |
+import logging
|
|
| 19 |
+ |
|
| 20 |
+from nbxmpp.protocol import Iq
|
|
| 21 |
+ |
|
| 22 |
+ |
|
| 23 |
+log = logging.getLogger('nbxmpp.m.discovery')
|
|
| 24 |
+ |
|
| 25 |
+ |
|
| 26 |
+def get_disco_request(namespace, jid, node=None):
|
|
| 27 |
+ iq = Iq('get', to=jid, queryNS=namespace)
|
|
| 28 |
+ if node is not None:
|
|
| 29 |
+ iq.getQuery().setAttr('node', node)
|
|
| 30 |
+ return iq
|
| ... | ... | @@ -29,6 +29,7 @@ from nbxmpp.const import StatusCode |
| 29 | 29 |
from nbxmpp.const import PresenceType
|
| 30 | 30 |
from nbxmpp.const import Error
|
| 31 | 31 |
from nbxmpp.const import LOCATION_DATA
|
| 32 |
+from nbxmpp.const import AdHocStatus
|
|
| 32 | 33 |
|
| 33 | 34 |
StanzaHandler = namedtuple('StanzaHandler',
|
| 34 | 35 |
'name callback typ ns xmlns system priority')
|
| ... | ... | @@ -106,6 +107,25 @@ MuclumbusItem = namedtuple('MuclumbusItem', 'jid name nusers description languag |
| 106 | 107 |
|
| 107 | 108 |
SoftwareVersionResult = namedtuple('SoftwareVersionResult', 'name version os')
|
| 108 | 109 |
|
| 110 |
+AdHocCommandNote = namedtuple('AdHocCommandNote', 'text type')
|
|
| 111 |
+ |
|
| 112 |
+class AdHocCommand(namedtuple('AdHocCommand', 'jid node name sessionid status data actions notes')):
|
|
| 113 |
+ |
|
| 114 |
+ __slots__ = []
|
|
| 115 |
+ |
|
| 116 |
+ def __new__(cls, jid, node, name, sessionid=None, status=None,
|
|
| 117 |
+ data=None, actions=None, notes=None):
|
|
| 118 |
+ return super(AdHocCommand, cls).__new__(cls, jid, node, name, sessionid,
|
|
| 119 |
+ status, data, actions, notes)
|
|
| 120 |
+ |
|
| 121 |
+ @property
|
|
| 122 |
+ def is_completed(self):
|
|
| 123 |
+ return self.status == AdHocStatus.COMPLETED
|
|
| 124 |
+ |
|
| 125 |
+ @property
|
|
| 126 |
+ def is_canceled(self):
|
|
| 127 |
+ return self.status == AdHocStatus.CANCEL
|
|
| 128 |
+ |
|
| 109 | 129 |
|
| 110 | 130 |
class OMEMOBundle(namedtuple('OMEMOBundle', 'spk spk_signature ik otpks')):
|
| 111 | 131 |
def pick_prekey(self):
|