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 []