Mercurial > libervia-backend
comparison sat/plugins/plugin_xep_0249.py @ 3002:6acaa8244220
plugin 0249: fixed invitation handling + some improvments:
- properly retrieve payload by namespace
- now use a trigger instead of observer, so the message workflow is stopped if an invitation is found
- namespace is registered
fix 241
author | Goffi <goffi@goffi.org> |
---|---|
date | Sun, 14 Jul 2019 11:23:25 +0200 |
parents | 003b8b4b56a7 |
children | ab2696e34d29 |
comparison
equal
deleted
inserted
replaced
3001:ce52ac2fe213 | 3002:6acaa8244220 |
---|---|
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 | 39 |
40 MESSAGE = "/message" | 40 MESSAGE = "/message" |
41 NS_DIRECT_MUC_INVITATION = "jabber:x:conference" | 41 NS_X_CONFERENCE = "jabber:x:conference" |
42 DIRECT_MUC_INVITATION_REQUEST = MESSAGE + '/x[@xmlns="' + NS_DIRECT_MUC_INVITATION + '"]' | |
43 AUTOJOIN_KEY = "Misc" | 42 AUTOJOIN_KEY = "Misc" |
44 AUTOJOIN_NAME = "Auto-join MUC on invitation" | 43 AUTOJOIN_NAME = "Auto-join MUC on invitation" |
45 AUTOJOIN_VALUES = ["ask", "always", "never"] | 44 AUTOJOIN_VALUES = ["ask", "always", "never"] |
46 | 45 |
47 PLUGIN_INFO = { | 46 PLUGIN_INFO = { |
92 ) | 91 ) |
93 try: | 92 try: |
94 self.host.plugins[C.TEXT_CMDS].registerTextCommands(self) | 93 self.host.plugins[C.TEXT_CMDS].registerTextCommands(self) |
95 except KeyError: | 94 except KeyError: |
96 log.info(_("Text commands not available")) | 95 log.info(_("Text commands not available")) |
96 host.registerNamespace('x-conference', NS_X_CONFERENCE) | |
97 host.trigger.add("MessageReceived", self._MessageReceivedTrigger) | |
97 | 98 |
98 def getHandler(self, client): | 99 def getHandler(self, client): |
99 return XEP_0249_handler(self) | 100 return XEP_0249_handler() |
100 | 101 |
101 def _invite(self, guest_jid_s, room_jid_s, options, profile_key): | 102 def _invite(self, guest_jid_s, room_jid_s, options, profile_key): |
102 """Invite an user to a room | 103 """Invite an user to a room |
103 | 104 |
104 @param guest_jid_s: jid of the user to invite | 105 @param guest_jid_s: jid of the user to invite |
117 @param room(jid.JID): jid of the room where the user is invited | 118 @param room(jid.JID): jid of the room where the user is invited |
118 @param options(dict): attribute with extra info (reason, password) as in #XEP-0249 | 119 @param options(dict): attribute with extra info (reason, password) as in #XEP-0249 |
119 """ | 120 """ |
120 message = domish.Element((None, "message")) | 121 message = domish.Element((None, "message")) |
121 message["to"] = guest.full() | 122 message["to"] = guest.full() |
122 x_elt = message.addElement((NS_DIRECT_MUC_INVITATION, "x")) | 123 x_elt = message.addElement((NS_X_CONFERENCE, "x")) |
123 x_elt["jid"] = room.userhost() | 124 x_elt["jid"] = room.userhost() |
124 for key, value in options.iteritems(): | 125 for key, value in options.iteritems(): |
125 if key not in ("password", "reason", "thread"): | 126 if key not in ("password", "reason", "thread"): |
126 log.warning(u"Ignoring invalid invite option: {}".format(key)) | 127 log.warning(u"Ignoring invalid invite option: {}".format(key)) |
127 continue | 128 continue |
140 % {"room": room_jid.userhost(), "profile": client.profile} | 141 % {"room": room_jid.userhost(), "profile": client.profile} |
141 ) | 142 ) |
142 d = self.host.plugins["XEP-0045"].join(client, room_jid, client.jid.user, {}) | 143 d = self.host.plugins["XEP-0045"].join(client, room_jid, client.jid.user, {}) |
143 return d | 144 return d |
144 | 145 |
145 def onInvitation(self, message, profile): | 146 def _MessageReceivedTrigger(self, client, message_elt, post_treat): |
146 """ | 147 """Check if a direct invitation is in the message, and handle it""" |
147 called when an invitation is received | 148 x_elt = next(message_elt.elements(NS_X_CONFERENCE, 'x'), None) |
148 @param message: message element | 149 if x_elt is None: |
149 @profile: %(doc_profile)s | 150 return True |
150 """ | 151 |
151 client = self.host.getClient(profile) | 152 try: |
152 try: | 153 room_jid_s = x_elt[u"jid"] |
153 room_jid_s = message.firstChildElement()["jid"] | 154 except KeyError: |
154 log.info( | 155 log.warning(_(u"invalid invitation received: {xml}").format( |
155 _(u"Invitation received for room %(room)s [%(profile)s]") | 156 xml=message_elt.toXml())) |
156 % {"room": room_jid_s, "profile": profile} | 157 return False |
157 ) | 158 log.info( |
158 except: | 159 _(u"Invitation received for room %(room)s [%(profile)s]") |
159 log.error(_("Error while parsing invitation")) | 160 % {"room": room_jid_s, "profile": client.profile} |
160 return | 161 ) |
161 from_jid_s = message["from"] | 162 from_jid_s = message_elt["from"] |
162 room_jid = jid.JID(room_jid_s) | 163 room_jid = jid.JID(room_jid_s) |
163 try: | 164 try: |
164 self.host.plugins["XEP-0045"].checkRoomJoined(client, room_jid) | 165 self.host.plugins["XEP-0045"].checkRoomJoined(client, room_jid) |
165 except exceptions.NotFound: | 166 except exceptions.NotFound: |
166 pass | 167 pass |
169 _(u"Invitation silently discarded because user is already in the room.") | 170 _(u"Invitation silently discarded because user is already in the room.") |
170 ) | 171 ) |
171 return | 172 return |
172 | 173 |
173 autojoin = self.host.memory.getParamA( | 174 autojoin = self.host.memory.getParamA( |
174 AUTOJOIN_NAME, AUTOJOIN_KEY, profile_key=profile | 175 AUTOJOIN_NAME, AUTOJOIN_KEY, profile_key=client.profile |
175 ) | 176 ) |
176 | 177 |
177 if autojoin == "always": | 178 if autojoin == "always": |
178 self._accept(room_jid, profile) | 179 self._accept(room_jid, client.profile) |
179 elif autojoin == "never": | 180 elif autojoin == "never": |
180 msg = D_( | 181 msg = D_( |
181 "An invitation from %(user)s to join the room %(room)s has been declined according to your personal settings." | 182 u"An invitation from %(user)s to join the room %(room)s has been " |
183 u"declined according to your personal settings." | |
182 ) % {"user": from_jid_s, "room": room_jid_s} | 184 ) % {"user": from_jid_s, "room": room_jid_s} |
183 title = D_("MUC invitation") | 185 title = D_("MUC invitation") |
184 xml_tools.quickNote(self.host, client, msg, title, C.XMLUI_DATA_LVL_INFO) | 186 xml_tools.quickNote(self.host, client, msg, title, C.XMLUI_DATA_LVL_INFO) |
185 else: # leave the default value here | 187 else: # leave the default value here |
186 confirm_msg = D_( | 188 confirm_msg = D_( |
187 "You have been invited by %(user)s to join the room %(room)s. Do you accept?" | 189 u"You have been invited by %(user)s to join the room %(room)s. " |
190 u"Do you accept?" | |
188 ) % {"user": from_jid_s, "room": room_jid_s} | 191 ) % {"user": from_jid_s, "room": room_jid_s} |
189 confirm_title = D_("MUC invitation") | 192 confirm_title = D_("MUC invitation") |
190 d = xml_tools.deferConfirm( | 193 d = xml_tools.deferConfirm( |
191 self.host, confirm_msg, confirm_title, profile=profile | 194 self.host, confirm_msg, confirm_title, profile=client.profile |
192 ) | 195 ) |
193 | 196 |
194 def accept_cb(accepted): | 197 def accept_cb(accepted): |
195 if accepted: | 198 if accepted: |
196 self._accept(room_jid, profile) | 199 self._accept(room_jid, client.profile) |
197 | 200 |
198 d.addCallback(accept_cb) | 201 d.addCallback(accept_cb) |
202 return False | |
199 | 203 |
200 def cmd_invite(self, client, mess_data): | 204 def cmd_invite(self, client, mess_data): |
201 """invite someone in the room | 205 """invite someone in the room |
202 | 206 |
203 @command (group): JID | 207 @command (group): JID |
207 my_host = client.jid.host | 211 my_host = client.jid.host |
208 try: | 212 try: |
209 contact_jid = jid.JID(contact_jid_s) | 213 contact_jid = jid.JID(contact_jid_s) |
210 except (RuntimeError, jid.InvalidFormat, AttributeError): | 214 except (RuntimeError, jid.InvalidFormat, AttributeError): |
211 feedback = _( | 215 feedback = _( |
212 u"You must provide a valid JID to invite, like in '/invite contact@{host}'" | 216 u"You must provide a valid JID to invite, like in '/invite " |
217 u"contact@{host}'" | |
213 ).format(host=my_host) | 218 ).format(host=my_host) |
214 self.host.plugins[C.TEXT_CMDS].feedBack(client, feedback, mess_data) | 219 self.host.plugins[C.TEXT_CMDS].feedBack(client, feedback, mess_data) |
215 return False | 220 return False |
216 if not contact_jid.user: | 221 if not contact_jid.user: |
217 contact_jid.user, contact_jid.host = contact_jid.host, my_host | 222 contact_jid.user, contact_jid.host = contact_jid.host, my_host |
220 | 225 |
221 | 226 |
222 class XEP_0249_handler(XMPPHandler): | 227 class XEP_0249_handler(XMPPHandler): |
223 implements(iwokkel.IDisco) | 228 implements(iwokkel.IDisco) |
224 | 229 |
225 def __init__(self, plugin_parent): | |
226 self.plugin_parent = plugin_parent | |
227 self.host = plugin_parent.host | |
228 | |
229 def connectionInitialized(self): | |
230 self.xmlstream.addObserver( | |
231 DIRECT_MUC_INVITATION_REQUEST, | |
232 self.plugin_parent.onInvitation, | |
233 profile=self.parent.profile, | |
234 ) | |
235 | |
236 def getDiscoInfo(self, requestor, target, nodeIdentifier=""): | 230 def getDiscoInfo(self, requestor, target, nodeIdentifier=""): |
237 return [disco.DiscoFeature(NS_DIRECT_MUC_INVITATION)] | 231 return [disco.DiscoFeature(NS_X_CONFERENCE)] |
238 | 232 |
239 def getDiscoItems(self, requestor, target, nodeIdentifier=""): | 233 def getDiscoItems(self, requestor, target, nodeIdentifier=""): |
240 return [] | 234 return [] |