comparison src/plugins/plugin_xep_0085.py @ 908:2ef523f0b5c3

plugin XEP-0085: bug fixes, especially for groupchat messages
author souliane <souliane@mailoo.org>
date Tue, 18 Mar 2014 13:52:12 +0100
parents 967b94ef821e
children 1a759096ccbd
comparison
equal deleted inserted replaced
907:cd02f5ef30df 908:2ef523f0b5c3
135 if (category, name) == (PARAM_KEY, PARAM_NAME): 135 if (category, name) == (PARAM_KEY, PARAM_NAME):
136 self.updateEntityData("@ALL@", True if value == "true" else "@NONE@", profile) 136 self.updateEntityData("@ALL@", True if value == "true" else "@NONE@", profile)
137 return False 137 return False
138 return True 138 return True
139 139
140
141 def messageReceivedTrigger(self, message, post_treat, profile): 140 def messageReceivedTrigger(self, message, post_treat, profile):
142 """ 141 """
143 Update the entity cache when we receive a message with body. 142 Update the entity cache when we receive a message with body.
144 Check for a check state in the incoming message and broadcast signal. 143 Check for a chat state in the message and signal frontends.
145 """ 144 """
146 if not self.host.memory.getParamA(PARAM_NAME, PARAM_KEY, profile_key=profile): 145 if not self.host.memory.getParamA(PARAM_NAME, PARAM_KEY, profile_key=profile):
147 return True 146 return True
148 147
148 from_jid = JID(message.getAttribute("from"))
149 try: 149 try:
150 domish.generateElementsNamed(message.elements(), name="body").next() 150 domish.generateElementsNamed(message.elements(), name="body").next()
151 from_jid = JID(message.getAttribute("from"))
152 try: 151 try:
153 domish.generateElementsNamed(message.elements(), name="active").next() 152 domish.generateElementsNamed(message.elements(), name="active").next()
154 # contact enabled Chat State Notifications 153 # contact enabled Chat State Notifications
155 self.updateEntityData(from_jid, True, profile) 154 self.updateEntityData(from_jid, True, profile)
156 # init to send following "composing" state
157 self.__chatStateInit(from_jid, message.getAttribute("type"), profile)
158 except StopIteration: 155 except StopIteration:
159 # contact didn't enable Chat State Notifications 156 if message.getAttribute('type') == 'chat':
160 self.updateEntityData(from_jid, False, profile) 157 # contact didn't enable Chat State Notifications
161 return True 158 self.updateEntityData(from_jid, False, profile)
159 return True
162 except StopIteration: 160 except StopIteration:
163 pass 161 pass
162
163 # send our next "composing" states to any MUC and to the contacts who enabled the feature
164 self.__chatStateInit(from_jid, message.getAttribute("type"), profile)
164 165
165 state_list = [child.name for child in message.elements() if 166 state_list = [child.name for child in message.elements() if
166 message.getAttribute("type") in MESSAGE_TYPES 167 message.getAttribute("type") in MESSAGE_TYPES
167 and child.name in CHAT_STATES 168 and child.name in CHAT_STATES
168 and child.defaultUri == NS_CHAT_STATES] 169 and child.defaultUri == NS_CHAT_STATES]
169 for state in state_list: 170 for state in state_list:
170 # there must be only one state according to the XEP 171 # there must be only one state according to the XEP
171 self.host.bridge.chatStateReceived(message.getAttribute("from"), state, profile) 172 if state != 'gone' or message.getAttribute('type') != 'groupchat':
173 self.host.bridge.chatStateReceived(message.getAttribute("from"), state, profile)
172 break 174 break
173 return True 175 return True
174 176
175 def sendMessageTrigger(self, mess_data, treatments, profile): 177 def sendMessageTrigger(self, mess_data, treatments, profile):
176 """ 178 """
209 # check if the parameter is active 211 # check if the parameter is active
210 if not self.host.memory.getParamA(PARAM_NAME, PARAM_KEY, profile_key=profile): 212 if not self.host.memory.getParamA(PARAM_NAME, PARAM_KEY, profile_key=profile):
211 return False 213 return False
212 # check if notifications should be sent to this contact 214 # check if notifications should be sent to this contact
213 try: 215 try:
216 type_ = self.host.memory.getEntityData(to_jid, ['type'], profile)['type']
217 if type_ == 'groupchat': # always send to groupchat
218 return True
219 except (exceptions.UnknownEntityError, KeyError):
220 pass # private chat
221 try:
214 return self.host.memory.getEntityData(to_jid, [ENTITY_KEY], profile)[ENTITY_KEY] 222 return self.host.memory.getEntityData(to_jid, [ENTITY_KEY], profile)[ENTITY_KEY]
215 except (exceptions.UnknownEntityError, KeyError): 223 except (exceptions.UnknownEntityError, KeyError):
216 if forceEntityData: 224 if forceEntityData:
217 # enable it for the first time 225 # enable it for the first time
218 self.updateEntityData(to_jid, True, profile) 226 self.updateEntityData(to_jid, True, profile)
222 230
223 def __chatStateInit(self, to_jid, mess_type, profile): 231 def __chatStateInit(self, to_jid, mess_type, profile):
224 """ 232 """
225 Data initialization for the chat state machine. 233 Data initialization for the chat state machine.
226 """ 234 """
227 # TODO: use also the resource in map key 235 # TODO: use also the resource in map key (not for groupchat)
228 to_jid = to_jid.userhostJID() 236 to_jid = to_jid.userhostJID()
229 if mess_type is None: 237 if mess_type is None:
230 return 238 return
231 if not hasattr(self, "map"): 239 if not hasattr(self, "map"):
232 self.map = {} 240 self.map = {}
238 246
239 def __chatStateActive(self, to_jid, mess_type, profile_key): 247 def __chatStateActive(self, to_jid, mess_type, profile_key):
240 """ 248 """
241 Launch the chat state machine on "active" state. 249 Launch the chat state machine on "active" state.
242 """ 250 """
243 # TODO: use also the JID resource in the map key 251 # TODO: use also the JID resource in the map key (not for groupchat)
244 to_jid = to_jid.userhostJID() 252 to_jid = to_jid.userhostJID()
245 profile = self.host.memory.getProfileName(profile_key) 253 profile = self.host.memory.getProfileName(profile_key)
246 if profile is None: 254 if profile is None:
247 raise exceptions.ProfileUnknownError 255 raise exceptions.ProfileUnknownError
248 return 256 return
255 from the front-end, it needs to check the values of the 263 from the front-end, it needs to check the values of the
256 parameter "Send chat state notifications" and the entity 264 parameter "Send chat state notifications" and the entity
257 data associated to the target JID. 265 data associated to the target JID.
258 TODO: try to optimize this method which is called often 266 TODO: try to optimize this method which is called often
259 """ 267 """
260 # TODO: use also the JID resource in the map key 268 # TODO: use also the JID resource in the map key (not for groupchat)
261 to_jid = JID(to_jid_s).userhostJID() 269 to_jid = JID(to_jid_s).userhostJID()
262 profile = self.host.memory.getProfileName(profile_key) 270 profile = self.host.memory.getProfileName(profile_key)
263 if profile is None: 271 if profile is None:
264 raise exceptions.ProfileUnknownError 272 raise exceptions.ProfileUnknownError
265 return 273 return
266 if not self.__checkActivation(to_jid, forceEntityData=False, profile=profile): 274 if not self.__checkActivation(to_jid, forceEntityData=False, profile=profile):
267 return 275 return
268 try: 276 try:
269 self.map[profile][to_jid]._onEvent("composing") 277 self.map[profile][to_jid]._onEvent("composing")
270 except AttributeError: 278 except (KeyError, AttributeError):
271 # no message has been sent/received since the notifications 279 # no message has been sent/received since the notifications
272 # have been enabled, it's better to wait for a first one 280 # have been enabled, it's better to wait for a first one
273 pass 281 pass
274 282
275 283
300 Move to the specified state, eventually send the 308 Move to the specified state, eventually send the
301 notification to the contact (the "active" state is 309 notification to the contact (the "active" state is
302 automatically sent with each message) and set the timer. 310 automatically sent with each message) and set the timer.
303 """ 311 """
304 if state != self.state and state != "active": 312 if state != self.state and state != "active":
305 # send a new message without body 313 if state != 'gone' or self.mess_type != 'groupchat':
306 self.host.sendMessage(self.to_jid, 314 # send a new message without body
307 '', 315 self.host.sendMessage(self.to_jid, '', '', self.mess_type,
308 '', 316 extra={"chat_state": state},
309 self.mess_type, 317 profile_key=self.profile)
310 extra={"chat_state": state},
311 profile_key=self.profile)
312 self.state = state 318 self.state = state
313 if not self.timer is None: 319 if not self.timer is None:
314 self.timer.cancel() 320 self.timer.cancel()
315 321
316 if not state in TRANSITIONS: 322 if not state in TRANSITIONS: