Mercurial > xib
comparison bot.py @ 22:e2bd4de698e5
Solved an XMPP resource conflict that would have happened when someone on IRC changed its nickname and later its old nickname would be used again. In other words, the bot no longer uses nicknames as XMPP resources.
Signed-off-by: Charly COSTE <changaco@changaco.net>
author | Charly COSTE <changaco@changaco.net> |
---|---|
date | Thu, 20 Aug 2009 17:49:40 +0200 |
parents | 801160b4136f |
children | abdb7a2b6c6d |
comparison
equal
deleted
inserted
replaced
21:801160b4136f | 22:e2bd4de698e5 |
---|---|
37 def __init__(self, jid, password, nickname, error_fd=sys.stderr, debug=False): | 37 def __init__(self, jid, password, nickname, error_fd=sys.stderr, debug=False): |
38 Thread.__init__(self) | 38 Thread.__init__(self) |
39 self.commands = ['!xmpp_participants', '!irc_participants'] | 39 self.commands = ['!xmpp_participants', '!irc_participants'] |
40 self.bare_jid = xmpp.protocol.JID(jid=jid) | 40 self.bare_jid = xmpp.protocol.JID(jid=jid) |
41 self.bare_jid.setResource('') | 41 self.bare_jid.setResource('') |
42 self.jid = xmpp.protocol.JID(jid=jid) | |
43 self.nickname = nickname | 42 self.nickname = nickname |
44 self.jid.setResource(self.nickname) | |
45 self.password = password | 43 self.password = password |
46 self.error_fd = error_fd | 44 self.error_fd = error_fd |
47 self.debug = debug | 45 self.debug = debug |
48 self.bridges = [] | 46 self.bridges = [] |
49 self.xmpp_connections = {} | 47 self.xmpp_connections = {} |
52 self.irc.add_global_handler('all_events', self._irc_event_handler) | 50 self.irc.add_global_handler('all_events', self._irc_event_handler) |
53 self.irc_thread = Thread(target=self.irc.process_forever) | 51 self.irc_thread = Thread(target=self.irc.process_forever) |
54 self.irc_thread.start() | 52 self.irc_thread.start() |
55 # Open connection with XMPP server | 53 # Open connection with XMPP server |
56 try: | 54 try: |
57 self.xmpp_c = self.get_xmpp_connection(self.jid.getResource()) | 55 self.xmpp_c = self.get_xmpp_connection(self.nickname) |
58 except: | 56 except: |
59 self.error('[Error] XMPP Connection failed') | 57 self.error('[Error] XMPP Connection failed') |
60 raise | 58 raise |
61 self.xmpp_thread = Thread(target=self._xmpp_loop) | 59 self.xmpp_thread = Thread(target=self._xmpp_loop) |
62 self.xmpp_thread.start() | 60 self.xmpp_thread.start() |
87 except xml.parsers.expat.ExpatError: | 85 except xml.parsers.expat.ExpatError: |
88 self.error('=> Debug: received invalid stanza', debug=True) | 86 self.error('=> Debug: received invalid stanza', debug=True) |
89 continue | 87 continue |
90 | 88 |
91 | 89 |
92 def _xmpp_presence_handler(self, xmpp_c, presence): | 90 def _xmpp_presence_handler(self, dispatcher, presence): |
93 """[Internal] Manage XMPP presence.""" | 91 """[Internal] Manage XMPP presence.""" |
94 | 92 |
95 if presence.getTo() != self.jid: | 93 xmpp_c = dispatcher._owner |
94 | |
95 if xmpp_c.nickname != self.nickname: | |
96 self.error('=> Debug: Skipping XMPP presence not received on bot connection.', debug=True) | 96 self.error('=> Debug: Skipping XMPP presence not received on bot connection.', debug=True) |
97 return | 97 return |
98 | 98 |
99 self.error('==> Debug: Received XMPP presence.', debug=True) | 99 self.error('==> Debug: Received XMPP presence.', debug=True) |
100 self.error(presence.__str__(fancy=1), debug=True) | 100 self.error(presence.__str__(fancy=1), debug=True) |
141 bridge.removeParticipant('xmpp', resource, presence.getStatus()) | 141 bridge.removeParticipant('xmpp', resource, presence.getStatus()) |
142 | 142 |
143 return | 143 return |
144 | 144 |
145 | 145 |
146 def _xmpp_iq_handler(self, xmpp_c, iq): | 146 def _xmpp_iq_handler(self, dispatcher, iq): |
147 """[Internal] Manage XMPP IQs.""" | 147 """[Internal] Manage XMPP IQs.""" |
148 self.error('=> Debug: Received XMPP iq.', debug=True) | 148 self.error('=> Debug: Received XMPP iq.', debug=True) |
149 self.error(iq.__str__(fancy=1), debug=True) | 149 self.error(iq.__str__(fancy=1), debug=True) |
150 | 150 |
151 | 151 |
152 def _xmpp_message_handler(self, xmpp_c, message): | 152 def _xmpp_message_handler(self, dispatcher, message): |
153 """[Internal] Manage XMPP messages.""" | 153 """[Internal] Manage XMPP messages.""" |
154 | |
155 xmpp_c = dispatcher._owner | |
156 | |
154 if message.getType() == 'chat': | 157 if message.getType() == 'chat': |
155 self.error('==> Debug: Received XMPP chat message.', debug=True) | 158 self.error('==> Debug: Received XMPP chat message.', debug=True) |
156 self.error(message.__str__(fancy=1), debug=True) | 159 self.error(message.__str__(fancy=1), debug=True) |
157 from_bare_jid = unicode(message.getFrom().getNode()+'@'+message.getFrom().getDomain()) | 160 from_bare_jid = unicode(message.getFrom().getNode()+'@'+message.getFrom().getDomain()) |
158 for bridge in self.bridges: | 161 for bridge in self.bridges: |
164 to_ = bridge.getParticipant(message.getTo().getResource()) | 167 to_ = bridge.getParticipant(message.getTo().getResource()) |
165 | 168 |
166 if from_.protocol == 'xmpp': | 169 if from_.protocol == 'xmpp': |
167 from_.sayOnIRCTo(to_.nickname, message.getBody()) | 170 from_.sayOnIRCTo(to_.nickname, message.getBody()) |
168 else: | 171 else: |
169 self.error('==> Debug: received XMPP chat message from a non-XMPP participant, WTF ?', debug=True) | 172 self.error('=> Debug: received XMPP chat message from a non-XMPP participant, WTF ?', debug=True) |
170 | 173 |
171 except NoSuchParticipantException: | 174 except NoSuchParticipantException: |
172 if message.getTo() == self.jid: | 175 if xmpp_c.nickname == self.nickname: |
173 xmpp_c.send(xmpp.protocol.Message(to=message.getFrom(), body=self.respond(message.getBody(), participant=from_), typ='chat')) | 176 xmpp_c.send(xmpp.protocol.Message(to=message.getFrom(), body=self.respond(message.getBody(), participant=from_), typ='chat')) |
174 return | 177 return |
175 self.error('==> Debug: XMPP chat message not relayed, from_bare_jid='+from_bare_jid+' to='+str(message.getTo().getResource())+' from='+message.getFrom().getResource(), debug=True) | 178 self.error('=> Debug: XMPP chat message not relayed', debug=True) |
176 return | 179 return |
177 | 180 |
178 elif message.getType() == 'groupchat': | 181 elif message.getType() == 'groupchat': |
179 # message comes from a room | 182 # message comes from a room |
180 | 183 |
181 for child in message.getChildren(): | 184 for child in message.getChildren(): |
182 if child.getName() == 'delay': | 185 if child.getName() == 'delay': |
183 # MUC delayed message | 186 # MUC delayed message |
184 return | 187 return |
185 | 188 |
186 if message.getTo() != self.jid: | 189 if xmpp_c.nickname != self.nickname: |
187 self.error('=> Debug: Ignoring XMPP MUC message not received on bot connection.', debug=True) | 190 self.error('=> Debug: Ignoring XMPP MUC message not received on bot connection.', debug=True) |
188 return | 191 return |
189 | 192 |
190 | 193 |
191 from_ = xmpp.protocol.JID(message.getFrom()) | 194 from_ = xmpp.protocol.JID(message.getFrom()) |
397 if bridge in bridges: | 400 if bridge in bridges: |
398 bridges.remove(bridge) | 401 bridges.remove(bridge) |
399 return bridges | 402 return bridges |
400 | 403 |
401 | 404 |
402 def get_xmpp_connection(self, resource): | 405 def get_xmpp_connection(self, nickname): |
403 if self.xmpp_connections.has_key(resource): | 406 if self.xmpp_connections.has_key(nickname): |
404 c = self.xmpp_connections[resource] | 407 c = self.xmpp_connections[nickname] |
405 c.used_by += 1 | 408 c.used_by += 1 |
406 self.error('===> Debug: using existing XMPP connection for "'+str(self.bare_jid)+'/'+resource+'", now used by '+str(c.used_by)+' bridges', debug=True) | 409 self.error('===> Debug: using existing XMPP connection for "'+nickname+'", now used by '+str(c.used_by)+' bridges', debug=True) |
407 return c | 410 return c |
408 self.error('===> Debug: opening new XMPP connection for "'+str(self.bare_jid)+'/'+resource+'"', debug=True) | 411 self.error('===> Debug: opening new XMPP connection for "'+nickname+'"', debug=True) |
409 c = xmpp.client.Client(self.jid.getDomain(), debug=[]) | 412 c = xmpp.client.Client(self.bare_jid.getDomain(), debug=[]) |
410 self.xmpp_connections[resource] = c | 413 self.xmpp_connections[nickname] = c |
411 c.used_by = 1 | 414 c.used_by = 1 |
415 c.nickname = nickname | |
412 c.connect() | 416 c.connect() |
413 c.auth(self.jid.getNode(), self.password, resource=resource) | 417 c.auth(self.bare_jid.getNode(), self.password) |
414 c.RegisterHandler('presence', self._xmpp_presence_handler) | 418 c.RegisterHandler('presence', self._xmpp_presence_handler) |
415 c.RegisterHandler('iq', self._xmpp_iq_handler) | 419 c.RegisterHandler('iq', self._xmpp_iq_handler) |
416 c.RegisterHandler('message', self._xmpp_message_handler) | 420 c.RegisterHandler('message', self._xmpp_message_handler) |
417 c.sendInitPresence() | 421 c.sendInitPresence() |
418 return c | 422 return c |
419 | 423 |
420 | 424 |
421 def close_xmpp_connection(self, resource): | 425 def close_xmpp_connection(self, nickname): |
422 self.xmpp_connections[resource].used_by -= 1 | 426 self.xmpp_connections[nickname].used_by -= 1 |
423 if self.xmpp_connections[resource].used_by < 1: | 427 if self.xmpp_connections[nickname].used_by < 1: |
424 self.error('===> Debug: closing XMPP connection for "'+str(self.bare_jid)+'/'+resource+'"', debug=True) | 428 self.error('===> Debug: closing XMPP connection for "'+nickname+'"', debug=True) |
425 del self.xmpp_connections[resource] | 429 del self.xmpp_connections[nickname] |
426 else: | 430 else: |
427 self.error('===> Debug: XMPP connection for "'+str(self.bare_jid)+'/'+resource+'" is now used by '+str(self.xmpp_connections[resource].used_by)+' bridges', debug=True) | 431 self.error('===> Debug: XMPP connection for "'+nickname+'" is now used by '+str(self.xmpp_connections[nickname].used_by)+' bridges', debug=True) |
428 | 432 |
429 | 433 |
430 def removeBridge(self, bridge): | 434 def removeBridge(self, bridge): |
431 self.bridges.remove(bridge) | 435 self.bridges.remove(bridge) |
432 del bridge | 436 del bridge |