Mercurial > xib
comparison bridge.py @ 0:4c842d23d4ce
Initial commit, version 0.1
Signed-off-by: Charly COSTE <changaco@changaco.net>
author | Charly COSTE <changaco@changaco.net> |
---|---|
date | Sun, 16 Aug 2009 01:47:03 +0200 |
parents | |
children | 3f651f4fdb4f |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4c842d23d4ce |
---|---|
1 #!/usr/bin/env python | |
2 # -*- coding: utf-8 -*- | |
3 | |
4 # This program is free software: you can redistribute it and/or modify | |
5 # it under the terms of the GNU General Public License as published by | |
6 # the Free Software Foundation, either version 3 of the License, or | |
7 # (at your option) any later version. | |
8 # | |
9 # This program is distributed in the hope that it will be useful, | |
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 # GNU General Public License for more details. | |
13 # | |
14 # You should have received a copy of the GNU General Public License | |
15 # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
16 | |
17 | |
18 import muc | |
19 xmpp = muc.xmpp | |
20 del muc | |
21 from participant import * | |
22 from encoding import * | |
23 | |
24 | |
25 class NoSuchParticipantException(Exception): pass | |
26 | |
27 | |
28 class bridge: | |
29 def __init__(self, owner_bot, xmpp_room_jid, irc_room, irc_server, irc_port=6667, mode='normal'): | |
30 self.bot = owner_bot | |
31 self.irc_server = irc_server | |
32 self.irc_port = irc_port | |
33 self.irc_room = irc_room | |
34 self.participants = [] | |
35 self.mode = mode | |
36 | |
37 # Join IRC room | |
38 self.irc_connection = self.bot.irc.server() | |
39 self.irc_connection.nick_callback = self._irc_nick_callback | |
40 self.irc_connection.bridge = self | |
41 try: | |
42 self.irc_connection.connect(irc_server, irc_port, self.bot.nickname) | |
43 except: | |
44 self.bot.error('Error: joining IRC room failed') | |
45 raise | |
46 | |
47 # Join XMPP room | |
48 try: | |
49 self.xmpp_room = xmpp.muc(xmpp_room_jid) | |
50 self.xmpp_room.join(self.bot.xmpp_c, self.bot.nickname) | |
51 except: | |
52 self.bot.error('Error: joining XMPP room failed') | |
53 raise | |
54 | |
55 | |
56 def _irc_nick_callback(self, error): | |
57 if error == None: | |
58 self.irc_connection.join(self.irc_room) | |
59 self.irc_connection.nick_callback = None | |
60 self.bot.error('===> Debug: successfully connected on IRC side of bridge "'+str(self)+'"', debug=True) | |
61 elif self.protocol != 'both': | |
62 if error == 'nicknameinuse': | |
63 self.bot.error('Error: "'+self.bot.nickname+'" is already used in the IRC chan of bridge "'+str(self)+'"') | |
64 raise Exception('Error: "'+self.bot.nickname+'" is already used in the IRC chan of bridge "'+str(self)+'"') | |
65 elif error == 'erroneusnickname': | |
66 self.bot.error('Error: "'+self.bot.nickname+'" got "erroneusnickname" on bridge "'+str(self)+'"') | |
67 raise Exception('Error: "'+self.bot.nickname+'" got "erroneusnickname" on bridge "'+str(self)+'"') | |
68 | |
69 | |
70 def addParticipant(self, protocol, nickname): | |
71 """Add a participant to the bridge.""" | |
72 if (protocol == 'irc' and nickname == self.irc_connection.get_nickname()) or (protocol == 'xmpp' and nickname == self.xmpp_room.nickname): | |
73 raise Exception('cannot add self') | |
74 try: | |
75 p = self.getParticipant(nickname) | |
76 if p.protocol != protocol: | |
77 if protocol == 'irc': | |
78 p.createDuplicateOnXMPP() | |
79 elif protocol == 'xmpp': | |
80 p.createDuplicateOnIRC() | |
81 else: | |
82 raise Exception('Internal Error: bad protocol') | |
83 return | |
84 except NoSuchParticipantException: | |
85 pass | |
86 self.bot.error('===> Debug: adding participant "'+nickname+'" from "'+protocol+'" to bridge "'+str(self)+'"', debug=True) | |
87 p = participant(self, protocol, nickname) | |
88 self.participants.append(p) | |
89 return p | |
90 | |
91 | |
92 def getParticipant(self, nickname): | |
93 """Returns a participant object if there is a participant using nickname in the bridge. Raises a NoSuchParticipantException otherwise.""" | |
94 for participant_ in self.participants: | |
95 if participant_.nickname == nickname: | |
96 return participant_ | |
97 raise NoSuchParticipantException('there is no participant using the nickname "'+nickname+'" in this bridge') | |
98 | |
99 | |
100 def removeParticipant(self, protocol, nickname, leave_message): | |
101 """Remove the participant using nickname from the bridge. Raises a NoSuchParticipantException if nickname is not used in the bridge.""" | |
102 p = self.getParticipant(nickname) | |
103 if p.protocol == 'both': | |
104 self.bot.error('===> Debug: "'+nickname+'" was on both sides of bridge "'+str(self)+'" but left '+protocol, debug=True) | |
105 if protocol == 'xmpp': | |
106 p.createDuplicateOnIRC() | |
107 elif protocol == 'irc': | |
108 p.createDuplicateOnXMPP() | |
109 else: | |
110 raise Exception('Internal Error: bad protocol') | |
111 else: | |
112 self.bot.error('===> Debug: removing participant "'+nickname+'" from bridge "'+str(self)+'"', debug=True) | |
113 self.participants.remove(p) | |
114 p.leave(leave_message) | |
115 i = 0 | |
116 for p in self.participants: | |
117 if p.protocol == 'irc': | |
118 i += 1 | |
119 if protocol == 'xmpp' and self.irc_connections_limit >= i: | |
120 self.switchToNormalMode() | |
121 del p | |
122 | |
123 | |
124 def say(self, message): | |
125 self.xmpp_room.say(message) | |
126 self.irc_connection.privmsg(self.irc_room, auto_encode(message)) | |
127 | |
128 | |
129 def switchToNormalMode(self): | |
130 if self.mode == 'normal': | |
131 return | |
132 prev_mode = self.mode | |
133 self.mode = 'normal' | |
134 for p in self.participants: | |
135 if p.protocol == 'xmpp': | |
136 p.createDuplicateOnIRC() | |
137 elif p.protocol == 'irc' and prev_mode == 'minimal': | |
138 p.createDuplicateOnXMPP() | |
139 self.bot.error('===> Bridge is switching to normal mode.') | |
140 self.say('[Notice] Bridge is switching to normal mode.') | |
141 | |
142 | |
143 def switchToLimitedMode(self): | |
144 if self.mode == 'limited': | |
145 return | |
146 self.mode = 'limited' | |
147 i = 0 | |
148 for p in self.participants: | |
149 if p.protocol == 'xmpp': | |
150 i += 1 | |
151 if p.irc_connection: | |
152 p.irc_connection.disconnect('Bridge is switching to limited mode') | |
153 p.irc_connection.close() | |
154 p.irc_connection = None | |
155 self.irc_connections_limit = i | |
156 self.bot.error('===> Bridge is switching to limited mode.') | |
157 self.say('[Warning] Bridge is switching to limited mode, it means that it will be transparent for XMPP users but not for IRC users, this is due to the IRC servers\' per-IP-address connections\' limit number.') | |
158 | |
159 | |
160 def __str__(self): | |
161 return self.irc_room+'@'+self.irc_server+' <-> '+self.xmpp_room.room_jid | |
162 | |
163 | |
164 def __del__(self): | |
165 # Delete participants objects | |
166 for p in self.participants: | |
167 p.leave('Removing bridge') | |
168 del p | |
169 # Leave IRC room | |
170 self.irc_connection.quit('Removing bridge') | |
171 # Close IRC connection | |
172 self.irc_connection.close() | |
173 del self.irc_connection | |
174 # Leave XMPP room | |
175 self.xmpp_room.leave('Removing bridge') |