3 # if you brick and have 0 -> kick from chan
4 # brick quantity must be queried, not automatically given
5 # if A bricks B, A--, B++
6 # cant give them nicely
7 # new person gets 5 bricks
13 class Bricker(object):
16 'welcome', 'disconnect', 'nicknameinuse', 'kick', 'privmsg', 'privnotice',
17 'bannedfromchan', 'erroneusnickname', 'join', 'namreply', 'nick', 'quit',
21 OVERBRICKED_MESSAGE = 'Overbricked, haha!'
22 BRICKED_MESSAGE = '*** %s was bricked.'
23 PLEASE_REGISTER_MESSAGE = 'You need to register. Use register <password>.'
24 BAD_PASSWORD_MESSAGE = 'Bad password.'
25 REGISTERED_MESSAGE = 'Registered successfully.'
26 SHARED_CHANNEL_MESSAGE = 'Both you and your target must be in the channel.'
27 COUNT_MESSAGE = 'You have %d bricks remaining.'
29 'Available commands are:\n'
30 ' register <password> - register yourself, or create a new password\n'
31 ' brick <nick> <channel> - brick someone in a channel\n'
32 ' (we must all be in the channel)\n'
33 ' count - tells you how many bricks you have left\n'
34 ' help - show this text\n')
36 def __init__(self, confignetwork, irc):
37 """A brickbot instance, which exists for an irc network..
40 confignetwork: A ConfigNetwork object.
41 irc: An irclib.IRC instance.
44 self.config = confignetwork
45 self._server_index = 0
48 self.state = State(self.config.statefile)
54 def _on_event(self, connection, event):
55 print 'event %s' % event.eventtype()
57 def _brick(self, connection, nick, target, channel):
58 if channel in self._channels:
59 fromuser = self.state.user(nick)
60 touser = self.state.user(target)
61 if not fromuser.registered:
62 connection.notice(nick, self.PLEASE_REGISTER_MESSAGE)
63 elif channel not in fromuser.visible or channel not in touser.visible:
64 connection.notice(nick, self.SHARED_CHANNEL_MESSAGE)
65 elif fromuser.bricks < 1:
66 # uh oh ! overbricked !
67 connection.kick(channel, nick, self.OVERBRICKED_MESSAGE)
69 connection.privmsg(channel, self.BRICKED_MESSAGE % target)
74 def _register(self, connection, nick, password):
75 user = self.state.user(nick)
76 if not password or (user.password and password != user.password):
77 connection.notice(nick, self.BAD_PASSWORD_MESSAGE)
80 user.password = password
82 user.registered = True
83 user.lasthost = user.onhost
85 connection.notice(nick, self.REGISTERED_MESSAGE)
87 def _count(self, connection, nick):
88 user = self.state.user(nick)
89 if not user.registered:
90 connection.notice(nick, self.PLEASE_REGISTER_MESSAGE)
92 connection.notice(nick, self.COUNT_MESSAGE % user.bricks)
94 def _help(self, connection, nick):
95 for line in self.HELP_MESSAGE.split('\n'):
96 connection.notice(nick, line)
100 server = self.config.servers[self._server_index]
101 self._nick = self.config.nickname
102 print 'Connecting to %s:%s' % (server.host, server.port)
103 conn = self.irc.server().connect(server.host, server.port, self._nick)
104 for s in self.LISTEN_EVENTS:
105 conn.add_global_handler(s, getattr(self, '_on_%s' % s), -10)
106 conn.add_global_handler('all_events', self._on_event, -30)
107 except irclib.ServerConnectionError:
108 self._server_index = (self._server_index + 1) % len(self.config.servers)
109 net.connection.execute_delayed(net.reconnect_delay,
112 def _rejoin(self, connection, channel):
114 for c in self.config.channels:
115 if channel == c.name:
116 password = c.password
118 print 'rejoining %s with password %s' % (channel, password)
119 connection.join(channel, password)
121 def _on_welcome(self, connection, event):
122 print 'welcome %s' % event
123 for s in self.config.autocommands:
124 connection.send_raw(s)
125 if self.config.nickservpw:
126 connection.privmsg('nickserv', 'identify %s %s' % (
127 self.config.nickservpw, self.config.nickname))
128 for c in self.config.channels:
129 connection.join(c.name, c.password)
131 def _on_disconnect(self, connection, event):
132 print 'disconnect %s' % event
133 connection.execute_delayed(self.config.reconnect_delay,
136 def _on_erroneusnickname(self, connection, event):
137 print 'unable to use nickname'
139 def _on_nicknameinuse(self, connection, event):
140 print 'nicknameinuse %s' % event.target()
141 if not self.config.nickservpw:
143 print 'using nickname %s' % self._nick
144 connection.nick(self._nick)
146 def _on_kick(self, connection, event):
147 nick = event.arguments()[0]
148 channel = event.target()
149 print 'kick %s from %s' % (nick, channel)
150 if nick == self._nick:
151 self._channels[channel] = False
152 connection.execute_delayed(self.config.rejoin_delay, self._rejoin,
153 (connection, event.target()))
155 self._rm_nick(connection, channel, nick)
157 def _on_bannedfromchan(self, connection, event):
158 print 'bannedfromchan %s' % event.arguments()[0]
159 connection.execute_delayed(self.config.rejoin_delay, self._rejoin,
160 (connection, event.arguments()[0]))
162 def _on_privmsg(self, connection, event):
163 print 'privmsg %s' % event.target()
164 print ' %s' % event.source()
165 print ' %s' % event.arguments()
166 data = event.arguments()[0].split(' ')
167 nick = irclib.nm_to_n(event.source())
170 if cmd == 'brick' and len(args) == 2:
173 self._brick(connection, nick, target, channel)
174 if cmd == 'register' and len(args) == 1:
176 self._register(connection, nick, password)
178 self._count(connection, nick)
180 self._help(connection, nick)
182 def _on_privnotice(self, connection, event):
183 print 'privnotice %s' % event.target()
184 print ' %s' % event.source()
185 print ' %s' % event.arguments()
186 data = event.arguments()[0].split(' ')
190 def _add_nick(self, connection, channel, nick, host=None):
191 print 'adding nick %s (%s)' % (nick, host)
192 user = self.state.user(nick)
193 user.visible[channel] = True
196 if host == user.lasthost:
197 user.registered = True
198 print 'registered %s by host %s' % (nick, host)
199 user.ignore_userhost_reply = True
201 connection.userhost([nick]) # get their userhost
202 user.ignore_userhost_reply = False
205 def _rm_nick(self, connection, channel, nick):
206 print 'removing nick %s' % nick
207 user = self.state.user(nick)
208 del user.visible[channel]
210 user.registered = False
213 def _on_join(self, connection, event):
214 nick, host = event.source().split('!', 1)
215 channel = event.target()
216 print 'join %s (%s) on %s' % (nick, host, channel)
217 if nick == self._nick:
218 self._channels[channel] = True
220 self._add_nick(connection, channel, nick, host=host)
222 def _on_namreply(self, connection, event):
223 nicks = event.arguments()[2].split(' ')
224 channel = event.arguments()[1]
225 print 'namreply found nicks %s' % nicks
226 nicks = [n.strip('@+ ') for n in nicks]
228 if nick != self._nick:
229 self._add_nick(connection, channel, nick)
231 def _on_nick(self, connection, event):
232 tonick = event.target()
233 fromnick = irclib.nm_to_n(event.source())
234 host = irclib.nm_to_uh(event.source())
235 print 'nick %s -> %s' % fromnick, tonick
236 if tonick != self._nick:
237 for c in self._channels:
238 user = self.state.user(fromnick)
239 if c in user.visible:
240 self._rm_nick(connection, c, fromnick)
241 self._add_nick(connection, c, tonick, host=host)
243 def _on_userhost(self, connection, event):
244 if not event.arguments()[0]: return
245 nick, host = event.arguments()[0].split('=', 1)
246 nick = nick.strip('* ')
247 host = host.strip('+- ')
248 print 'userhost for %s is %s' % (nick, host)
249 user = self.state.user(nick)
250 if not user.ignore_userhost_reply:
251 for c in user.visible:
252 self._add_nick(connection, c, nick, host=host)
254 def _on_quit(self, connection, event):
255 nick = irclib.nm_to_n(event.source())
256 channel = event.target()
257 print 'quit %s' % nick
258 if nick == self._nick:
259 self._channels[channel] = False
261 user = self.state.user(nick)
262 for c in user.visible:
263 self._rm_nick(connection, c, nick)
265 def _on_part(self, connection, event):
266 nick = irclib.nm_to_n(event.source())
267 channel = event.target()
268 print 'part %s from %s' % (nick, channel)
269 if nick == self._nick:
270 self._channels[channel] = False
272 self._rm_nick(connection, channel, nick)
277 def __init__(self, filename):
278 # a dictionary of User objects keyed by their nicknames
280 self._filename = filename
283 if not self._filename:
284 print 'WARNING: not using a state file'
287 f = open(self._filename, 'r+')
289 print 'IOError: %s' % e
290 print 'WARNING: not using a state file'
295 data = line.strip().split(' ', 1)
296 if data[0] == 'nick' and len(data) > 1:
298 if curnick and data[0] == 'lasthost' and len(data) > 1:
299 self.user(curnick).lasthost = data[1]
300 if curnick and data[0] == 'bricks' and len(data) > 1:
301 self.user(curnick).bricks = int(data[1])
302 if curnick and data[0] == 'password' and len(data) > 1:
303 self.user(curnick).password = data[1]
307 if not self._filename: return
309 f = open(self._filename, 'w')
311 print 'IOError: %s' % e
312 print 'WARNING: failed to write state file'
314 for u in self._users.values():
315 f.write('nick %s\n' % u.nick)
316 if u.lasthost: f.write('lasthost %s\n' % u.lasthost)
317 if u.password: f.write('password %s\n' % u.password)
318 f.write('bricks %s\n' % u.bricks)
321 def user(self, nick):
322 nick = irclib.irc_lower(nick)
323 if nick not in self._users:
324 user = State.User(self, nick)
325 self._users[nick] = user
328 user = self._users[nick]
333 def __init__(self, state, nick):
338 self.registered = False
340 self.ignore_userhost_reply = True
347 for n in config.Config.networks:
350 irc.process_forever()
352 if __name__ == '__main__':