comparison bot.py @ 17:32a35f7eff70

Rewrote/modified many things, multiple bridges should now work and are preferred over multiple bots. Signed-off-by: Charly COSTE <changaco@changaco.net>
author Charly COSTE <changaco@changaco.net>
date Thu, 20 Aug 2009 01:00:54 +0200
parents 1a1f2a0d35c7
children 3cdf7bb580da
comparison
equal deleted inserted replaced
16:0c4a7452d66c 17:32a35f7eff70
34 class bot(Thread): 34 class bot(Thread):
35 35
36 def __init__(self, jid, password, nickname, error_fd=sys.stderr, debug=False): 36 def __init__(self, jid, password, nickname, error_fd=sys.stderr, debug=False):
37 Thread.__init__(self) 37 Thread.__init__(self)
38 self.commands = ['!xmpp_participants'] 38 self.commands = ['!xmpp_participants']
39 self.bare_jid = xmpp.protocol.JID(jid=jid)
40 self.bare_jid.setResource('')
39 self.jid = xmpp.protocol.JID(jid=jid) 41 self.jid = xmpp.protocol.JID(jid=jid)
40 self.nickname = nickname 42 self.nickname = nickname
43 self.jid.setResource(self.nickname)
41 self.password = password 44 self.password = password
42 self.error_fd = error_fd 45 self.error_fd = error_fd
43 self.debug = debug 46 self.debug = debug
44 self.bridges = [] 47 self.bridges = []
48 self.xmpp_connections = {}
45 self.irc = irclib.IRC() 49 self.irc = irclib.IRC()
50 self.irc.bot = self
46 self.irc.add_global_handler('all_events', self._irc_event_handler) 51 self.irc.add_global_handler('all_events', self._irc_event_handler)
47 self.irc_thread = Thread(target=self.irc.process_forever) 52 self.irc_thread = Thread(target=self.irc.process_forever)
48 self.irc_thread.start() 53 self.irc_thread.start()
49 # Open connection with XMPP server 54 # Open connection with XMPP server
50 try: 55 try:
51 self.xmpp_c = xmpp.client.Client(self.jid.getDomain(), debug=[]) 56 self.xmpp_c = self.get_xmpp_connection(self.jid.getResource())
52 self.xmpp_c.connect()
53 if self.jid.getResource() == '':
54 self.jid.setResource('xib-bot')
55 self.xmpp_c.auth(self.jid.getNode(), password, resource=self.jid.getResource())
56 self.xmpp_c.RegisterHandler('presence', self._xmpp_presence_handler)
57 self.xmpp_c.RegisterHandler('iq', self._xmpp_iq_handler)
58 self.xmpp_c.RegisterHandler('message', self._xmpp_message_handler)
59 self.xmpp_c.sendInitPresence()
60 except: 57 except:
61 self.error('Error: XMPP Connection failed') 58 self.error('Error: XMPP Connection failed')
62 raise 59 raise
63 self.xmpp_thread = Thread(target=self._xmpp_loop) 60 self.xmpp_thread = Thread(target=self._xmpp_loop)
64 self.xmpp_thread.start() 61 self.xmpp_thread.start()
65 62
66 63
67 def error(self, s, debug=False): 64 def error(self, s, debug=False):
65 """Output an error message."""
68 if not debug or debug and self.debug: 66 if not debug or debug and self.debug:
69 try: 67 try:
70 self.error_fd.write(auto_encode(s)+"\n") 68 self.error_fd.write(auto_encode(s)+"\n")
71 except EncodingException: 69 except EncodingException:
72 self.error_fd.write('Error message cannot be transcoded.\n') 70 self.error_fd.write('Error message cannot be transcoded.\n')
73 71
74 72
75 def _xmpp_loop(self): 73 def _xmpp_loop(self):
74 """[Internal] XMPP infinite loop."""
76 while True: 75 while True:
77 self.xmpp_c.Process(5) 76 self.xmpp_c.Process(5)
77 try:
78 for c in self.xmpp_connections.itervalues():
79 if hasattr(c, 'Process'):
80 c.Process(5)
81 else:
82 sleep(1)
83 except RuntimeError:
84 pass
78 85
79 86
80 def _xmpp_presence_handler(self, xmpp_c, presence): 87 def _xmpp_presence_handler(self, xmpp_c, presence):
81 """[Internal] Manage XMPP presence.""" 88 """[Internal] Manage XMPP presence."""
89
90 if presence.getTo() != self.jid:
91 self.error('=> Debug: Skipping XMPP presence not received on bot connection.', debug=True)
92 return
93
82 self.error('==> Debug: Received XMPP presence.', debug=True) 94 self.error('==> Debug: Received XMPP presence.', debug=True)
83 self.error(presence.__str__(fancy=1), debug=True) 95 self.error(presence.__str__(fancy=1), debug=True)
84 96
85 if presence.getTo() != self.jid:
86 #self.error('=> Debug: Skipping XMPP presence not received on bot connection.', debug=True)
87 return
88 from_ = xmpp.protocol.JID(presence.getFrom()) 97 from_ = xmpp.protocol.JID(presence.getFrom())
89 bare_jid = unicode(from_.getNode()+'@'+from_.getDomain()) 98 bare_jid = unicode(from_.getNode()+'@'+from_.getDomain())
90 for bridge in self.bridges: 99 for bridge in self.bridges:
91 if bare_jid == bridge.xmpp_room.room_jid: 100 if bare_jid == bridge.xmpp_room.room_jid:
92 # presence comes from a muc 101 # presence comes from a muc
93 resource = unicode(from_.getResource()) 102 resource = unicode(from_.getResource())
103
94 if resource == '': 104 if resource == '':
95 # presence comes from the muc itself 105 # presence comes from the muc itself
96 # TODO: handle room deletion and muc server reboot 106 # TODO: handle room deletion and muc server reboot
97 pass 107 pass
108
98 else: 109 else:
99 # presence comes from a participant of the muc 110 # presence comes from a participant of the muc
100 try: 111 try:
101 p = bridge.getParticipant(resource) 112 p = bridge.getParticipant(resource)
102 if p.protocol in ['xmpp', 'both']: 113
103 if presence.getType() == 'unavailable':
104 x = presence.getTag('x', namespace='http://jabber.org/protocol/muc#user')
105 if x and x.getTag('status', attrs={'code': '303'}):
106 # participant changed its nickname
107 item = x.getTag('item')
108 if not item:
109 self.error('Debug: bad stanza, no item element', debug=True)
110 return
111 new_nick = item.getAttr('nick')
112 if not new_nick:
113 self.error('Debug: bad stanza, new nick is not given', debug=True)
114 return
115 p.changeNickname(new_nick, 'irc')
116 return
117 # participant left
118 bridge.removeParticipant('xmpp', resource, presence.getStatus())
119 except NoSuchParticipantException: 114 except NoSuchParticipantException:
120 if presence.getType() != 'unavailable': 115 if presence.getType() != 'unavailable' and resource != bridge.bot.nickname:
121 try: 116 bridge.addParticipant('xmpp', resource)
122 bridge.addParticipant('xmpp', resource) 117 return
123 except Exception: 118
124 pass 119
120 if p.protocol == 'xmpp' and presence.getType() == 'unavailable':
121 x = presence.getTag('x', namespace='http://jabber.org/protocol/muc#user')
122 if x and x.getTag('status', attrs={'code': '303'}):
123 # participant changed its nickname
124 item = x.getTag('item')
125 if not item:
126 self.error('Debug: bad stanza, no item element', debug=True)
127 return
128 new_nick = item.getAttr('nick')
129 if not new_nick:
130 self.error('Debug: bad stanza, new nick is not given', debug=True)
131 return
132 p.changeNickname(new_nick, 'irc')
133
134 else:
135 # participant left
136 bridge.removeParticipant('xmpp', resource, presence.getStatus())
137
125 return 138 return
126 139
127 140
128 def _xmpp_iq_handler(self, xmpp_c, iq): 141 def _xmpp_iq_handler(self, xmpp_c, iq):
129 """[Internal] Manage XMPP IQs.""" 142 """[Internal] Manage XMPP IQs."""
132 145
133 146
134 def _xmpp_message_handler(self, xmpp_c, message): 147 def _xmpp_message_handler(self, xmpp_c, message):
135 """[Internal] Manage XMPP messages.""" 148 """[Internal] Manage XMPP messages."""
136 if message.getType() == 'chat': 149 if message.getType() == 'chat':
137 self.error('==> Debug: Received XMPP message.', debug=True) 150 self.error('==> Debug: Received XMPP chat message.', debug=True)
138 self.error(message.__str__(fancy=1), debug=True) 151 self.error(message.__str__(fancy=1), debug=True)
139 from_bare_jid = unicode(message.getFrom().getNode()+'@'+message.getFrom().getDomain()) 152 from_bare_jid = unicode(message.getFrom().getNode()+'@'+message.getFrom().getDomain())
140 for bridge in self.bridges: 153 for bridge in self.bridges:
141 if from_bare_jid == bridge.xmpp_room.room_jid: 154 if from_bare_jid == bridge.xmpp_room.room_jid:
142 # message comes from a room participant 155 # message comes from a room participant
156
143 try: 157 try:
144 from_ = bridge.getParticipant(message.getFrom().getResource()) 158 from_ = bridge.getParticipant(message.getFrom().getResource())
145 to_ = bridge.getParticipant(message.getTo().getResource()) 159 to_ = bridge.getParticipant(message.getTo().getResource())
160
161 if from_.protocol == 'xmpp':
162 from_.sayOnIRCTo(to_.nickname, message.getBody())
163 else:
164 self.error('==> Debug: received XMPP chat message from a non-XMPP participant, WTF ?', debug=True)
165
146 except NoSuchParticipantException: 166 except NoSuchParticipantException:
147 if message.getTo() == self.jid: 167 if message.getTo() == self.jid:
148 xmpp_c.send(xmpp.protocol.Message(to=message.getFrom(), body=self.respond(message.getBody(), from_), typ='chat')) 168 xmpp_c.send(xmpp.protocol.Message(to=message.getFrom(), body=self.respond(message.getBody(), from_), typ='chat'))
149 return 169 return
150 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) 170 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)
151 return 171 return
152 if from_.protocol in ['xmpp', 'both']:
153 from_.sayOnIRCTo(to_.nickname, message.getBody())
154 else:
155 self.error('==> Debug: received XMPP chat message from a non-XMPP participant, WTF ?', debug=True)
156 172
157 elif message.getType() == 'groupchat': 173 elif message.getType() == 'groupchat':
158 # message comes from a room 174 # message comes from a room
159 if message.getTo() != self.jid: 175
160 self.error('=> Debug: Skipping XMPP MUC message not received on bot connection.', debug=True)
161 return
162 for child in message.getChildren(): 176 for child in message.getChildren():
163 if child.getName() == 'delay': 177 if child.getName() == 'delay':
164 self.error('=> Debug: Skipping XMPP MUC delayed message.', debug=True) 178 # MUC delayed message
165 return 179 return
166 self.error('==> Debug: Received XMPP message.', debug=True) 180
167 self.error(message.__str__(fancy=1), debug=True) 181 if message.getTo() != self.jid:
182 self.error('=> Debug: Ignoring XMPP MUC message not received on bot connection.', debug=True)
183 return
184
185
168 from_ = xmpp.protocol.JID(message.getFrom()) 186 from_ = xmpp.protocol.JID(message.getFrom())
169 room_jid = unicode(from_.getNode()+'@'+from_.getDomain()) 187 room_jid = unicode(from_.getNode()+'@'+from_.getDomain())
170 for bridge in self.bridges: 188 for bridge in self.bridges:
171 if room_jid == bridge.xmpp_room.room_jid: 189 if room_jid == bridge.xmpp_room.room_jid:
172 resource = unicode(from_.getResource()) 190 resource = unicode(from_.getResource())
173 if resource == '': 191 if resource == '':
174 # message comes from the room itself 192 # message comes from the room itself
175 pass 193 self.error('=> Debug: Ignoring XMPP groupchat message sent by the room.', debug=True)
194 return
176 else: 195 else:
177 # message comes from a participant of the room 196 # message comes from a participant of the room
197 self.error('==> Debug: Received XMPP groupchat message.', debug=True)
198 self.error(message.__str__(fancy=1), debug=True)
199
178 try: 200 try:
179 participant_ = bridge.getParticipant(resource) 201 participant_ = bridge.getParticipant(resource)
180 except NoSuchParticipantException: 202 except NoSuchParticipantException:
203 if resource != self.nickname:
204 self.error('=> Debug: NoSuchParticipantException "'+resource+'", WTF ?', debug=True)
181 return 205 return
206
182 if participant_.protocol == 'xmpp': 207 if participant_.protocol == 'xmpp':
183 participant_.sayOnIRC(message.getBody()) 208 participant_.sayOnIRC(message.getBody())
184 elif participant_.protocol == 'both': 209
185 bridge.irc_connection.privmsg(bridge.irc_room, '<'+participant_.nickname+'> '+message.getBody())
186 else: 210 else:
187 self.error('==> Debug: Received XMPP message.', debug=True) 211 self.error('==> Debug: Received XMPP message of unknown type "'+message.getType()+'".', debug=True)
188 self.error(message.__str__(fancy=1), debug=True) 212 self.error(message.__str__(fancy=1), debug=True)
189 213
190 214
191 def _irc_event_handler(self, connection, event): 215 def _irc_event_handler(self, connection, event):
192 """[internal] Manage IRC events""" 216 """[Internal] Manage IRC events"""
193 if not connection.bridge in self.bridges: 217
194 # Not for us, ignore 218 # Answer ping
195 return
196 if 'all' in event.eventtype():
197 return
198 if 'motd' in event.eventtype():
199 self.error('=> Debug: ignoring event containing "motd" in the eventtype ('+event.eventtype()+')', debug=True)
200 return
201 if event.eventtype() in ['pong', 'privnotice']:
202 self.error('=> Debug: ignoring '+event.eventtype(), debug=True)
203 return
204 if event.eventtype() == 'pubmsg' and connection.get_nickname() != connection.bridge.irc_connection.get_nickname():
205 self.error('=> Debug: ignoring IRC pubmsg not received on bridge connection', debug=True)
206 return
207 if event.eventtype() == 'ping': 219 if event.eventtype() == 'ping':
208 connection.pong(connection.get_server_name()) 220 connection.pong(connection.get_server_name())
209 return 221 return
222
223
224 # Events we always want to ignore
225 if 'all' in event.eventtype() or 'motd' in event.eventtype():
226 return
227 if event.eventtype() in ['pong', 'privnotice', 'ctcp', 'nochanmodes']:
228 self.error('=> Debug: ignoring '+event.eventtype(), debug=True)
229 return
230
231
232 nickname = None
233 if '!' in event.source():
234 nickname = event.source().split('!')[0]
235
236
237 # Events that we want to ignore only in some cases
210 if event.eventtype() in ['umode', 'welcome', 'yourhost', 'created', 'myinfo', 'featurelist', 'luserclient', 'luserop', 'luserchannels', 'luserme', 'n_local', 'n_global', 'endofnames', 'luserunknown', 'luserconns']: 238 if event.eventtype() in ['umode', 'welcome', 'yourhost', 'created', 'myinfo', 'featurelist', 'luserclient', 'luserop', 'luserchannels', 'luserme', 'n_local', 'n_global', 'endofnames', 'luserunknown', 'luserconns']:
211 if connection.really_connected == False: 239 if connection.really_connected == False:
212 connection.really_connected = True 240 if event.target() == connection.nickname:
213 self.error('===> Debug: now really connected', debug=True) 241 connection.really_connected = True
214 if connection.nick_callback: 242 connection._call_nick_callbacks(None)
215 connection.nick_callback(None) 243 elif len(connection.nick_callbacks) > 0:
216 else: 244 self.error('===> Debug: event target ('+event.target()+') and connection nickname ('+connection.nickname+') don\'t match')
217 self.error('=> Debug: no nick callback for "'+str(event.target())+'"', debug=True) 245 connection._call_nick_callbacks('nicknametoolong', arguments=[len(event.target())])
218 self.error('connection.nick_callback='+str(connection.nick_callback), debug=True)
219 self.error('=> Debug: ignoring '+event.eventtype(), debug=True) 246 self.error('=> Debug: ignoring '+event.eventtype(), debug=True)
220 return 247 return
221 self.error('==> Debug: Received IRC event.', debug=True) 248
222 self.error('server='+connection.get_server_name(), debug=True) 249
223 self.error('eventtype='+event.eventtype(), debug=True) 250 # A string representation of the event
224 self.error('source='+str(event.source()), debug=True) 251 event_str = '==> Debug: Received IRC event.\nconnection='+str(connection)+'\neventtype='+event.eventtype()+'\nsource='+str(event.source())+'\ntarget='+str(event.target())+'\narguments='+str(event.arguments())
225 self.error('target='+str(event.target()), debug=True) 252
226 self.error('arguments='+str(event.arguments()), debug=True) 253
254 if event.eventtype() in ['pubmsg', 'privmsg', 'quit', 'part', 'nick']:
255 if nickname == None:
256 return
257
258 # TODO: lock self.bridges for thread safety
259 for bridge in self.bridges:
260 try:
261 from_ = bridge.getParticipant(nickname)
262
263 except NoSuchParticipantException:
264 self.error('===> Debug: NoSuchParticipantException "'+nickname+'" in bridge "'+str(bridge)+'"', debug=True)
265 continue
266
267
268 # Private message
269 if event.eventtype() == 'privmsg':
270 if event.target() == None:
271 return
272
273 try:
274 to_ = bridge.getParticipant(event.target().split('!')[0])
275 self.error(event_str, debug=True)
276 from_.sayOnXMPPTo(to_.nickname, event.arguments()[0])
277 return
278
279 except NoSuchParticipantException:
280 if event.target().split('!')[0] == self.nickname:
281 # Message is for the bot
282 self.error(event_str, debug=True)
283 connection.privmsg(from_.nickname, self.respond(event.arguments()[0], from_))
284 return
285 else:
286 continue
287
288
289 # From here we skip if the event was not received on bot connection
290 if connection.get_nickname() != self.nickname:
291 self.error('=> Debug: ignoring IRC '+event.eventtype()+' not received on bridge connection', debug=True)
292 continue
293
294 self.error(event_str, debug=True)
295
296
297 # Leaving events
298 if event.eventtype() == 'quit' or event.eventtype() == 'part' and event.target() == bridge.irc_room:
299 if from_.protocol == 'irc':
300 bridge.removeParticipant('irc', from_.nickname, event.arguments()[0])
301 continue
302
303
304 # Nickname change
305 if event.eventtype() == 'nick' and from_.protocol == 'irc':
306 from_.changeNickname(event.target(), 'xmpp')
307 continue
308
309
310 # Chan message
311 if event.eventtype() == 'pubmsg':
312 if bridge.irc_room == event.target() and bridge.irc_server == connection.server:
313 if from_.protocol != 'xmpp':
314 from_.sayOnXMPP(event.arguments()[0])
315 return
316 else:
317 continue
318
319 return
320
321
322 if event.eventtype() in ['namreply', 'join']:
323 if connection.get_nickname() != self.nickname:
324 self.error('=> Debug: ignoring IRC '+event.eventtype()+' not received on bridge connection', debug=True)
325 return
326
327 if event.eventtype() == 'namreply':
328 # TODO: lock self.bridges for thread safety
329 for bridge in self.getBridges(irc_room=event.arguments()[1], irc_server=connection.server):
330 for nickname in re.split('(?:^[@\+]?|(?: [@\+]?)*)', event.arguments()[2].strip()):
331 if nickname == '' or nickname == self.nickname:
332 continue
333 bridge.addParticipant('irc', nickname)
334 return
335 elif event.eventtype() == 'join':
336 bridges = self.getBridges(irc_room=event.target(), irc_server=connection.server)
337 if len(bridges) == 0:
338 self.error('===> Debug: no bridge found for "'+event.target()+' at '+connection.server+'"', debug=True)
339 return
340 for bridge in bridges:
341 bridge.addParticipant('irc', nickname)
342 return
343
344
345 # From here the event is shown
346 self.error(event_str, debug=True)
347
227 if event.eventtype() == 'disconnect': 348 if event.eventtype() == 'disconnect':
228 if connection.get_nickname() == connection.bridge.irc_connection.get_nickname(): 349 # TODO: lock self.bridges for thread safety
229 # Lost bridge IRC connection, we must reconnect if we want the bridge to work 350 for bridge in self.bridges:
230 self.recreate_bridge(connection.bridge) 351 try:
231 return 352 bridge.getParticipant(connection.get_nickname())
232 if connection.bridge.mode == 'normal' and connection.closing == False: 353 if bridge.mode == 'normal':
233 connection.bridge.switchToLimitedMode() 354 bridge.switchFromNormalToLimitedMode()
234 if connection.closing == True: 355 except NoSuchParticipantException:
235 connection.close() 356 pass
236 return 357 return
237 elif event.eventtype() == 'nicknameinuse': 358 elif event.eventtype() == 'nicknameinuse':
238 if connection.nick_callback: 359 connection._call_nick_callbacks('nicknameinuse')
239 connection.nick_callback('nicknameinuse')
240 else:
241 self.error('=> Debug: no nick callback for "'+str(event.target())+'"', debug=True)
242 return 360 return
243 elif event.eventtype() == 'erroneusnickname': 361 elif event.eventtype() == 'erroneusnickname':
244 if connection.nick_callback: 362 connection._call_nick_callbacks('erroneusnickname')
245 connection.nick_callback('erroneusnickname') 363 return
246 else: 364
247 self.error('=> Debug: no nick callback for "'+str(event.target())+'"', debug=True) 365
248 return 366 # Unhandled events
249 elif event.eventtype() == 'namreply': 367 self.error('=> Debug: event not handled', debug=True)
250 for nickname in re.split('(?:^[@\+]?|(?: [@\+]?)*)', event.arguments()[2].strip()): 368
251 if nickname == '': 369
252 continue 370 def new_bridge(self, xmpp_room, irc_room, irc_server, mode, say_participants_list, irc_port=6667):
253 try:
254 connection.bridge.addParticipant('irc', nickname)
255 except:
256 pass
257 return
258 elif event.eventtype() == 'join':
259 nickname = event.source().split('!')[0]
260 if nickname == self.nickname:
261 pass
262 else:
263 try:
264 connection.bridge.getParticipant(nickname)
265 except NoSuchParticipantException:
266 connection.bridge.addParticipant('irc', nickname)
267 return
268 try:
269 if event.source() == None or not '!' in event.source():
270 return
271 from_ = connection.bridge.getParticipant(event.source().split('!')[0])
272 if event.eventtype() == 'quit' or event.eventtype() == 'part' and event.target() == connection.bridge.irc_room:
273 if from_.protocol in ['irc', 'both']:
274 connection.bridge.removeParticipant('irc', from_.nickname, event.arguments()[0])
275 return
276 if event.eventtype() == 'nick' and from_.protocol in ['irc', 'both']:
277 from_.changeNickname(event.target(), 'xmpp')
278 except NoSuchParticipantException:
279 self.error('===> Debug: NoSuchParticipantException "'+event.source().split('!')[0]+'"', debug=True)
280 return
281 if event.eventtype() == 'pubmsg':
282 if from_.protocol == 'irc' or from_.protocol == 'both':
283 from_.sayOnXMPP(event.arguments()[0])
284 elif event.eventtype() == 'privmsg':
285 if event.target() == None:
286 return
287 try:
288 to_ = connection.bridge.getParticipant(event.target().split('!')[0])
289 except NoSuchParticipantException:
290 if event.target().split('!')[0] == self.nickname:
291 connection.privmsg(from_.nickname, self.respond(event.arguments()[0], from_))
292 return
293 if to_.protocol == 'xmpp':
294 from_.sayOnXMPPTo(to_.nickname, event.arguments()[0])
295
296
297 def new_bridge(self, xmpp_room, irc_room, irc_server, irc_port=6667):
298 """Create a bridge between xmpp_room and irc_room at irc_server.""" 371 """Create a bridge between xmpp_room and irc_room at irc_server."""
299 b = bridge(self, xmpp_room, irc_room, irc_server, irc_port=irc_port) 372 b = bridge(self, xmpp_room, irc_room, irc_server, mode, say_participants_list, irc_port=irc_port)
300 self.bridges.append(b) 373 self.bridges.append(b)
301 return b 374 return b
302 375
303 376
304 def recreate_bridge(self, bridge): 377 def getBridges(self, irc_room=None, irc_server=None, xmpp_room_jid=None):
305 """Disconnect and reconnect.""" 378 bridges = [b for b in self.bridges]
306 self.new_bridge(bridge.xmpp_room.room_jid, bridge.irc_room, bridge.irc_server) 379 if irc_room != None:
380 for bridge in bridges:
381 if bridge.irc_room != irc_room:
382 if bridge in bridges:
383 bridges.remove(bridge)
384 if irc_server != None:
385 for bridge in bridges:
386 if bridge.irc_server != irc_server:
387 if bridge in bridges:
388 bridges.remove(bridge)
389 if xmpp_room_jid != None:
390 for bridge in bridges:
391 if bridge.xmpp_room.room_jid != xmpp_room_jid:
392 if bridge in bridges:
393 bridges.remove(bridge)
394 return bridges
395
396
397 def get_xmpp_connection(self, resource):
398 if self.xmpp_connections.has_key(resource):
399 c = self.xmpp_connections[resource]
400 c.used_by += 1
401 self.error('===> Debug: using existing XMPP connection for "'+str(self.bare_jid)+'/'+resource+'", now used by '+str(c.used_by)+' bridges', debug=True)
402 return c
403 self.error('===> Debug: opening new XMPP connection for "'+str(self.bare_jid)+'/'+resource+'"', debug=True)
404 c = xmpp.client.Client(self.jid.getDomain(), debug=[])
405 self.xmpp_connections[resource] = c
406 c.used_by = 1
407 c.connect()
408 c.auth(self.jid.getNode(), self.password, resource=resource)
409 c.RegisterHandler('presence', self._xmpp_presence_handler)
410 c.RegisterHandler('iq', self._xmpp_iq_handler)
411 c.RegisterHandler('message', self._xmpp_message_handler)
412 c.sendInitPresence()
413 return c
414
415
416 def close_xmpp_connection(self, resource):
417 self.xmpp_connections[resource].used_by -= 1
418 if self.xmpp_connections[resource].used_by < 1:
419 self.error('===> Debug: closing XMPP connection for "'+str(self.bare_jid)+'/'+resource+'"', debug=True)
420 del self.xmpp_connections[resource]
421 else:
422 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)
423
424
425 def removeBridge(self, bridge):
307 self.bridges.remove(bridge) 426 self.bridges.remove(bridge)
308 del bridge 427 del bridge
309 428
310 429
311 def respond(self, message, participant): 430 def respond(self, message, participant):
312 if message.strip() == '!xmpp_participants': 431 if message.strip() == '!xmpp_participants':
313 xmpp_participants_nicknames = participant.bridge.get_xmpp_participants_nicknames_list() 432 xmpp_participants_nicknames = participant.bridge.get_participants_nicknames_list(protocols=['xmpp'])
314 return 'participants on '+participant.bridge.xmpp_room.room_jid+': '+' '.join(xmpp_participants_nicknames) 433 return 'participants on '+participant.bridge.xmpp_room.room_jid+': '+' '.join(xmpp_participants_nicknames)
315 else: 434 else:
316 return 'commands: '+' '.join(self.commands) 435 return 'commands: '+' '.join(self.commands)
317 436
437
318 def __del__(self): 438 def __del__(self):
319 for bridge in bridges: 439 for bridge in self.bridges:
320 del bridge 440 self.removeBridge(bridge)