Mercurial > libervia-backend
comparison src/plugins/plugin_xep_0085.py @ 1252:5ff9f9af9d1f
plugin XEP-0085: use the full JID + fixes bad entity data "type" value
author | souliane <souliane@mailoo.org> |
---|---|
date | Mon, 20 Oct 2014 12:57:55 +0200 |
parents | 301b342c697a |
children | c13a46207410 |
comparison
equal
deleted
inserted
replaced
1251:51a85e8f599a | 1252:5ff9f9af9d1f |
---|---|
125 self.host.memory.updateEntityData(entity_jid, ENTITY_KEY, value, profile) | 125 self.host.memory.updateEntityData(entity_jid, ENTITY_KEY, value, profile) |
126 if not value or value == C.PROF_KEY_NONE: | 126 if not value or value == C.PROF_KEY_NONE: |
127 # disable chat state for this or these contact(s) | 127 # disable chat state for this or these contact(s) |
128 self.host.bridge.chatStateReceived(unicode(entity_jid), "", profile) | 128 self.host.bridge.chatStateReceived(unicode(entity_jid), "", profile) |
129 | 129 |
130 def paramUpdateTrigger(self, name, value, category, type, profile): | 130 def paramUpdateTrigger(self, name, value, category, type_, profile): |
131 """ | 131 """ |
132 Reset all the existing chat state entity data associated with this profile after a parameter modification. | 132 Reset all the existing chat state entity data associated with this profile after a parameter modification. |
133 @param name: parameter name | 133 @param name: parameter name |
134 @param value: "true" to activate the notifications, or any other value to delete it | 134 @param value: "true" to activate the notifications, or any other value to delete it |
135 @param category: parameter category | 135 @param category: parameter category |
136 @param type_: parameter type | |
136 """ | 137 """ |
137 if (category, name) == (PARAM_KEY, PARAM_NAME): | 138 if (category, name) == (PARAM_KEY, PARAM_NAME): |
138 self.updateEntityData("@ALL@", True if value == "true" else C.PROF_KEY_NONE, profile) | 139 self.updateEntityData("@ALL@", True if value == "true" else C.PROF_KEY_NONE, profile) |
139 return False | 140 return False |
140 return True | 141 return True |
146 """ | 147 """ |
147 if not self.host.memory.getParamA(PARAM_NAME, PARAM_KEY, profile_key=profile): | 148 if not self.host.memory.getParamA(PARAM_NAME, PARAM_KEY, profile_key=profile): |
148 return True | 149 return True |
149 | 150 |
150 from_jid = JID(message.getAttribute("from")) | 151 from_jid = JID(message.getAttribute("from")) |
151 try: | 152 if self.__isMUC(from_jid, profile): |
152 domish.generateElementsNamed(message.elements(), name="body").next() | 153 from_jid = from_jid.userhostJID() |
154 else: # update entity data for one2one chat | |
155 assert(from_jid.resource) | |
153 try: | 156 try: |
154 domish.generateElementsNamed(message.elements(), name="active").next() | 157 domish.generateElementsNamed(message.elements(), name="body").next() |
155 # contact enabled Chat State Notifications | 158 try: |
156 self.updateEntityData(from_jid, True, profile) | 159 domish.generateElementsNamed(message.elements(), name="active").next() |
160 # contact enabled Chat State Notifications | |
161 self.updateEntityData(from_jid, True, profile) | |
162 except StopIteration: | |
163 if message.getAttribute('type') == 'chat': | |
164 # contact didn't enable Chat State Notifications | |
165 self.updateEntityData(from_jid, False, profile) | |
166 return True | |
157 except StopIteration: | 167 except StopIteration: |
158 if message.getAttribute('type') == 'chat': | 168 pass |
159 # contact didn't enable Chat State Notifications | |
160 self.updateEntityData(from_jid, False, profile) | |
161 return True | |
162 except StopIteration: | |
163 pass | |
164 | 169 |
165 # send our next "composing" states to any MUC and to the contacts who enabled the feature | 170 # send our next "composing" states to any MUC and to the contacts who enabled the feature |
166 self.__chatStateInit(from_jid, message.getAttribute("type"), profile) | 171 self.__chatStateInit(from_jid, message.getAttribute("type"), profile) |
167 | 172 |
168 state_list = [child.name for child in message.elements() if | 173 state_list = [child.name for child in message.elements() if |
189 try: | 194 try: |
190 # message with a body always mean active state | 195 # message with a body always mean active state |
191 domish.generateElementsNamed(message.elements(), name="body").next() | 196 domish.generateElementsNamed(message.elements(), name="body").next() |
192 message.addElement('active', NS_CHAT_STATES) | 197 message.addElement('active', NS_CHAT_STATES) |
193 # launch the chat state machine (init the timer) | 198 # launch the chat state machine (init the timer) |
199 if self.__isMUC(to_jid, profile): | |
200 to_jid = to_jid.userhostJID() | |
194 self.__chatStateActive(to_jid, mess_data["type"], profile) | 201 self.__chatStateActive(to_jid, mess_data["type"], profile) |
195 except StopIteration: | 202 except StopIteration: |
196 if "chat_state" in mess_data["extra"]: | 203 if "chat_state" in mess_data["extra"]: |
197 state = mess_data["extra"].pop("chat_state") | 204 state = mess_data["extra"].pop("chat_state") |
198 assert(state in CHAT_STATES) | 205 assert(state in CHAT_STATES) |
200 return mess_data | 207 return mess_data |
201 | 208 |
202 post_xml_treatments.addCallback(treatment) | 209 post_xml_treatments.addCallback(treatment) |
203 return True | 210 return True |
204 | 211 |
212 def __isMUC(self, to_jid, profile): | |
213 """Tell if that JID is a MUC or not | |
214 | |
215 @param to_jid (JID): full or bare JID to check | |
216 @param profile (str): %(doc_profile)s | |
217 @return: bool | |
218 """ | |
219 try: | |
220 type_ = self.host.memory.getEntityDatum(to_jid.userhostJID(), 'type', profile) | |
221 if type_ == 'chatroom': | |
222 return True | |
223 except (exceptions.UnknownEntityError, KeyError): | |
224 pass | |
225 return False | |
226 | |
205 def __checkActivation(self, to_jid, forceEntityData, profile): | 227 def __checkActivation(self, to_jid, forceEntityData, profile): |
206 """ | 228 """ |
207 @param to_joid: the contact's JID | 229 @param to_jid: the contact's full JID (or bare if you know it's a MUC) |
208 @param forceEntityData: if set to True, a non-existing | 230 @param forceEntityData: if set to True, a non-existing |
209 entity data will be considered to be True (and initialized) | 231 entity data will be considered to be True (and initialized) |
210 @param: current profile | 232 @param: current profile |
211 @return: True if the notifications should be sent to this JID. | 233 @return: True if the notifications should be sent to this JID. |
212 """ | 234 """ |
213 # check if the parameter is active | 235 # check if the parameter is active |
214 if not self.host.memory.getParamA(PARAM_NAME, PARAM_KEY, profile_key=profile): | 236 if not self.host.memory.getParamA(PARAM_NAME, PARAM_KEY, profile_key=profile): |
215 return False | 237 return False |
216 # check if notifications should be sent to this contact | 238 # check if notifications should be sent to this contact |
239 if self.__isMUC(to_jid, profile): | |
240 return True | |
241 assert(to_jid.resource or not self.host.memory.isContactConnected(to_jid, profile)) | |
217 try: | 242 try: |
218 type_ = self.host.memory.getEntityData(to_jid, ['type'], profile)['type'] | 243 return self.host.memory.getEntityDatum(to_jid, ENTITY_KEY, profile) |
219 if type_ == 'groupchat': # always send to groupchat | |
220 return True | |
221 except (exceptions.UnknownEntityError, KeyError): | |
222 pass # private chat | |
223 try: | |
224 return self.host.memory.getEntityData(to_jid, [ENTITY_KEY], profile)[ENTITY_KEY] | |
225 except (exceptions.UnknownEntityError, KeyError): | 244 except (exceptions.UnknownEntityError, KeyError): |
226 if forceEntityData: | 245 if forceEntityData: |
227 # enable it for the first time | 246 # enable it for the first time |
228 self.updateEntityData(to_jid, True, profile) | 247 self.updateEntityData(to_jid, True, profile) |
229 return True | 248 return True |
231 return False | 250 return False |
232 | 251 |
233 def __chatStateInit(self, to_jid, mess_type, profile): | 252 def __chatStateInit(self, to_jid, mess_type, profile): |
234 """ | 253 """ |
235 Data initialization for the chat state machine. | 254 Data initialization for the chat state machine. |
236 """ | 255 |
237 # TODO: use also the resource in map key (not for groupchat) | 256 @param to_jid (JID): full JID for one2one, bare JID for MUC |
238 to_jid = to_jid.userhostJID() | 257 @param mess_type (str): "one2one" or "groupchat" |
258 @param profile (str): %(doc_profile)s | |
259 """ | |
239 if mess_type is None: | 260 if mess_type is None: |
240 return | 261 return |
241 if not hasattr(self, "map"): | 262 if not hasattr(self, "map"): |
242 self.map = {} | 263 self.map = {} |
243 profile_map = self.map.setdefault(profile, {}) | 264 profile_map = self.map.setdefault(profile, {}) |
244 if not to_jid in profile_map: | 265 if to_jid not in profile_map: |
245 machine = ChatStateMachine(self.host, to_jid, | 266 machine = ChatStateMachine(self.host, to_jid, |
246 mess_type, profile) | 267 mess_type, profile) |
247 self.map[profile][to_jid] = machine | 268 self.map[profile][to_jid] = machine |
248 | 269 |
249 def __chatStateActive(self, to_jid, mess_type, profile_key): | 270 def __chatStateActive(self, to_jid, mess_type, profile_key): |
250 """ | 271 """ |
251 Launch the chat state machine on "active" state. | 272 Launch the chat state machine on "active" state. |
252 """ | 273 |
253 # TODO: use also the JID resource in the map key (not for groupchat) | 274 @param to_jid (JID): full JID for one2one, bare JID for MUC |
254 to_jid = to_jid.userhostJID() | 275 @param mess_type (str): "one2one" or "groupchat" |
276 @param profile (str): %(doc_profile)s | |
277 """ | |
255 profile = self.host.memory.getProfileName(profile_key) | 278 profile = self.host.memory.getProfileName(profile_key) |
256 if profile is None: | 279 if profile is None: |
257 raise exceptions.ProfileUnknownError | 280 raise exceptions.ProfileUnknownError |
258 return | |
259 self.__chatStateInit(to_jid, mess_type, profile) | 281 self.__chatStateInit(to_jid, mess_type, profile) |
260 self.map[profile][to_jid]._onEvent("active") | 282 self.map[profile][to_jid]._onEvent("active") |
261 | 283 |
262 def chatStateComposing(self, to_jid_s, profile_key): | 284 def chatStateComposing(self, to_jid_s, profile_key): |
263 """ | 285 """Move to the "composing" state when required. |
264 Move to the "composing" state. Since this method is called | 286 |
265 from the front-end, it needs to check the values of the | 287 Since this method is called from the front-end, it needs to check the |
266 parameter "Send chat state notifications" and the entity | 288 values of the parameter "Send chat state notifications" and the entity |
267 data associated to the target JID. | 289 data associated to the target JID. |
268 TODO: try to optimize this method which is called often | 290 |
269 """ | 291 @param to_jid_s (str): contact full JID as a string |
270 # TODO: use also the JID resource in the map key (not for groupchat) | 292 @param profile_key (str): %(doc_profile_key)s |
271 to_jid = JID(to_jid_s).userhostJID() | 293 """ |
294 # TODO: try to optimize this method which is called often | |
272 profile = self.host.memory.getProfileName(profile_key) | 295 profile = self.host.memory.getProfileName(profile_key) |
273 if profile is None: | 296 if profile is None: |
274 raise exceptions.ProfileUnknownError | 297 raise exceptions.ProfileUnknownError |
275 return | 298 to_jid = JID(to_jid_s) |
299 if self.__isMUC(to_jid, profile): | |
300 to_jid = to_jid.userhostJID() | |
301 elif not to_jid.resource: | |
302 to_jid.resource = self.host.memory.getLastResource(to_jid, profile) | |
276 if not self.__checkActivation(to_jid, forceEntityData=False, profile=profile): | 303 if not self.__checkActivation(to_jid, forceEntityData=False, profile=profile): |
277 return | 304 return |
278 try: | 305 try: |
279 self.map[profile][to_jid]._onEvent("composing") | 306 self.map[profile][to_jid]._onEvent("composing") |
280 except (KeyError, AttributeError): | 307 except (KeyError, AttributeError): |
316 # send a new message without body | 343 # send a new message without body |
317 self.host.sendMessage(self.to_jid, '', '', self.mess_type, | 344 self.host.sendMessage(self.to_jid, '', '', self.mess_type, |
318 extra={"chat_state": state}, | 345 extra={"chat_state": state}, |
319 profile_key=self.profile) | 346 profile_key=self.profile) |
320 self.state = state | 347 self.state = state |
321 if not self.timer is None: | 348 if self.timer is not None: |
322 self.timer.cancel() | 349 self.timer.cancel() |
323 | 350 |
324 if not state in TRANSITIONS: | 351 if state not in TRANSITIONS: |
325 return | 352 return |
326 if not "next_state" in TRANSITIONS[state]: | 353 if "next_state" not in TRANSITIONS[state]: |
327 return | 354 return |
328 if not "delay" in TRANSITIONS[state]: | 355 if "delay" not in TRANSITIONS[state]: |
329 return | 356 return |
330 next_state = TRANSITIONS[state]["next_state"] | 357 next_state = TRANSITIONS[state]["next_state"] |
331 delay = TRANSITIONS[state]["delay"] | 358 delay = TRANSITIONS[state]["delay"] |
332 if next_state == "" or delay < 0: | 359 if next_state == "" or delay < 0: |
333 return | 360 return |