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')