comparison libervia/backend/plugins/plugin_xep_0092.py @ 4071:4b842c1fb686

refactoring: renamed `sat` package to `libervia.backend`
author Goffi <goffi@goffi.org>
date Fri, 02 Jun 2023 11:49:51 +0200
parents sat/plugins/plugin_xep_0092.py@e75827204fe0
children
comparison
equal deleted inserted replaced
4070:d10748475025 4071:4b842c1fb686
1 #!/usr/bin/env python3
2
3
4 # SàT plugin for Software Version (XEP-0092)
5 # Copyright (C) 2009-2021 Jérôme Poisson (goffi@goffi.org)
6
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Affero General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
11
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU Affero General Public License for more details.
16
17 # You should have received a copy of the GNU Affero General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20 from typing import Tuple
21
22 from twisted.internet import defer, reactor
23 from twisted.words.protocols.jabber import jid
24 from wokkel import compat
25
26 from libervia.backend.core import exceptions
27 from libervia.backend.core.constants import Const as C
28 from libervia.backend.core.core_types import SatXMPPEntity
29 from libervia.backend.core.i18n import _
30 from libervia.backend.core.log import getLogger
31
32 log = getLogger(__name__)
33
34 NS_VERSION = "jabber:iq:version"
35 TIMEOUT = 10
36
37 PLUGIN_INFO = {
38 C.PI_NAME: "Software Version Plugin",
39 C.PI_IMPORT_NAME: "XEP-0092",
40 C.PI_TYPE: "XEP",
41 C.PI_PROTOCOLS: ["XEP-0092"],
42 C.PI_DEPENDENCIES: [],
43 C.PI_RECOMMENDATIONS: [C.TEXT_CMDS],
44 C.PI_MAIN: "XEP_0092",
45 C.PI_HANDLER: "no", # version is already handler in core.xmpp module
46 C.PI_DESCRIPTION: _("""Implementation of Software Version"""),
47 }
48
49
50 class XEP_0092(object):
51 def __init__(self, host):
52 log.info(_("Plugin XEP_0092 initialization"))
53 self.host = host
54 host.bridge.add_method(
55 "software_version_get",
56 ".plugin",
57 in_sign="ss",
58 out_sign="(sss)",
59 method=self._get_version,
60 async_=True,
61 )
62 try:
63 self.host.plugins[C.TEXT_CMDS].add_who_is_cb(self._whois, 50)
64 except KeyError:
65 log.info(_("Text commands not available"))
66
67 def _get_version(self, entity_jid_s, profile_key):
68 def prepare_for_bridge(data):
69 name, version, os = data
70 return (name or "", version or "", os or "")
71
72 client = self.host.get_client(profile_key)
73 d = self.version_get(client, jid.JID(entity_jid_s))
74 d.addCallback(prepare_for_bridge)
75 return d
76
77 def version_get(
78 self,
79 client: SatXMPPEntity,
80 jid_: jid.JID,
81 ) -> Tuple[str, str, str]:
82 """Ask version of the client that jid_ is running
83
84 @param jid_: jid from who we want to know client's version
85 @return: a defered which fire a tuple with the following data (None if not available):
86 - name: Natural language name of the software
87 - version: specific version of the software
88 - os: operating system of the queried entity
89 """
90
91 def do_version_get(__):
92 iq_elt = compat.IQ(client.xmlstream, "get")
93 iq_elt["to"] = jid_.full()
94 iq_elt.addElement("query", NS_VERSION)
95 d = iq_elt.send()
96 d.addCallback(self._got_version)
97 return d
98
99 d = self.host.check_feature(client, NS_VERSION, jid_)
100 d.addCallback(do_version_get)
101 reactor.callLater(
102 TIMEOUT, d.cancel
103 ) # XXX: timeout needed because some clients don't answer the IQ
104 return d
105
106 def _got_version(self, iq_elt):
107 try:
108 query_elt = next(iq_elt.elements(NS_VERSION, "query"))
109 except StopIteration:
110 raise exceptions.DataError
111 ret = []
112 for name in ("name", "version", "os"):
113 try:
114 data_elt = next(query_elt.elements(NS_VERSION, name))
115 ret.append(str(data_elt))
116 except StopIteration:
117 ret.append(None)
118
119 return tuple(ret)
120
121 def _whois(self, client, whois_msg, mess_data, target_jid):
122 """Add software/OS information to whois"""
123
124 def version_cb(version_data):
125 name, version, os = version_data
126 if name:
127 whois_msg.append(_("Client name: %s") % name)
128 if version:
129 whois_msg.append(_("Client version: %s") % version)
130 if os:
131 whois_msg.append(_("Operating system: %s") % os)
132
133 def version_eb(failure):
134 failure.trap(exceptions.FeatureNotFound, defer.CancelledError)
135 if failure.check(failure, exceptions.FeatureNotFound):
136 whois_msg.append(_("Software version not available"))
137 else:
138 whois_msg.append(_("Client software version request timeout"))
139
140 d = self.version_get(client, target_jid)
141 d.addCallbacks(version_cb, version_eb)
142 return d