Mercurial > xib
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) |