17757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch# Copyright (C) 1999--2002 Joel Rosdahl 27757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch# 37757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch# This library is free software; you can redistribute it and/or 47757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch# modify it under the terms of the GNU Lesser General Public 57757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch# License as published by the Free Software Foundation; either 67757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch# version 2.1 of the License, or (at your option) any later version. 77757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch# 87757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch# This library is distributed in the hope that it will be useful, 97757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch# but WITHOUT ANY WARRANTY; without even the implied warranty of 107757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 117757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch# Lesser General Public License for more details. 127757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch# 137757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch# You should have received a copy of the GNU Lesser General Public 147757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch# License along with this library; if not, write to the Free Software 157757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 167757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch# 177757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch# Joel Rosdahl <joel@rosdahl.net> 187757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch# 197757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch# $Id: ircbot.py,v 1.23 2008/09/11 07:38:30 keltus Exp $ 207757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 217757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch"""ircbot -- Simple IRC bot library. 227757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 237757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen MurdochThis module contains a single-server IRC bot class that can be used to 247757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochwrite simpler bots. 257757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch""" 267757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 277757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochimport sys 287757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochfrom UserDict import UserDict 297757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 307757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochfrom irclib import SimpleIRCClient 317757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochfrom irclib import nm_to_n, irc_lower, all_events 327757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochfrom irclib import parse_channel_modes, is_channel 337757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochfrom irclib import ServerConnectionError 347757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 357757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochclass SingleServerIRCBot(SimpleIRCClient): 367757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """A single-server IRC bot class. 377757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 387757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch The bot tries to reconnect if it is disconnected. 397757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 407757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch The bot keeps track of the channels it has joined, the other 417757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch clients that are present in the channels and which of those that 427757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch have operator or voice modes. The "database" is kept in the 437757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.channels attribute, which is an IRCDict of Channels. 447757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """ 457757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def __init__(self, server_list, nickname, realname, reconnection_interval=60): 467757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """Constructor for SingleServerIRCBot objects. 477757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 487757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch Arguments: 497757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 507757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch server_list -- A list of tuples (server, port) that 517757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch defines which servers the bot should try to 527757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch connect to. 537757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 547757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch nickname -- The bot's nickname. 557757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 567757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch realname -- The bot's realname. 577757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 587757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch reconnection_interval -- How long the bot should wait 597757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch before trying to reconnect. 607757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 617757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch dcc_connections -- A list of initiated/accepted DCC 627757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch connections. 637757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """ 647757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 657757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch SimpleIRCClient.__init__(self) 667757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.channels = IRCDict() 677757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.server_list = server_list 687757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch if not reconnection_interval or reconnection_interval < 0: 697757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch reconnection_interval = 2**31 707757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.reconnection_interval = reconnection_interval 717757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 727757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self._nickname = nickname 737757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self._realname = realname 747757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch for i in ["disconnect", "join", "kick", "mode", 757757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch "namreply", "nick", "part", "quit"]: 767757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.connection.add_global_handler(i, 777757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch getattr(self, "_on_" + i), 787757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch -10) 797757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def _connected_checker(self): 807757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """[Internal]""" 817757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch if not self.connection.is_connected(): 827757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.connection.execute_delayed(self.reconnection_interval, 837757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self._connected_checker) 847757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.jump_server() 857757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 867757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def _connect(self): 877757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """[Internal]""" 887757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch password = None 897757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch if len(self.server_list[0]) > 2: 907757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch password = self.server_list[0][2] 917757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch try: 927757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.connect(self.server_list[0][0], 937757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.server_list[0][1], 947757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self._nickname, 957757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch password, 967757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch ircname=self._realname) 977757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch except ServerConnectionError: 987757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch pass 997757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 1007757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def _on_disconnect(self, c, e): 1017757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """[Internal]""" 1027757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.channels = IRCDict() 1037757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.connection.execute_delayed(self.reconnection_interval, 1047757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self._connected_checker) 1057757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 1067757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def _on_join(self, c, e): 1077757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """[Internal]""" 1087757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch ch = e.target() 1097757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch nick = nm_to_n(e.source()) 1107757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch if nick == c.get_nickname(): 1117757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.channels[ch] = Channel() 1127757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.channels[ch].add_user(nick) 1137757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 1147757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def _on_kick(self, c, e): 1157757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """[Internal]""" 1167757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch nick = e.arguments()[0] 1177757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch channel = e.target() 1187757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 1197757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch if nick == c.get_nickname(): 1207757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch del self.channels[channel] 1217757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch else: 1227757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.channels[channel].remove_user(nick) 1237757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 1247757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def _on_mode(self, c, e): 1257757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """[Internal]""" 1267757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch modes = parse_channel_modes(" ".join(e.arguments())) 1277757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch t = e.target() 1287757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch if is_channel(t): 1297757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch ch = self.channels[t] 1307757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch for mode in modes: 1317757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch if mode[0] == "+": 1327757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch f = ch.set_mode 1337757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch else: 1347757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch f = ch.clear_mode 1357757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch f(mode[1], mode[2]) 1367757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch else: 1377757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch # Mode on self... XXX 1387757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch pass 1397757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 1407757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def _on_namreply(self, c, e): 1417757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """[Internal]""" 1427757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 1437757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch # e.arguments()[0] == "@" for secret channels, 1447757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch # "*" for private channels, 1457757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch # "=" for others (public channels) 1467757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch # e.arguments()[1] == channel 1477757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch # e.arguments()[2] == nick list 1487757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 1497757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch ch = e.arguments()[1] 1507757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch for nick in e.arguments()[2].split(): 1517757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch if nick[0] == "@": 1527757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch nick = nick[1:] 1537757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.channels[ch].set_mode("o", nick) 1547757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch elif nick[0] == "+": 1557757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch nick = nick[1:] 1567757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.channels[ch].set_mode("v", nick) 1577757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.channels[ch].add_user(nick) 1587757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 1597757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def _on_nick(self, c, e): 1607757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """[Internal]""" 1617757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch before = nm_to_n(e.source()) 1627757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch after = e.target() 1637757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch for ch in self.channels.values(): 1647757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch if ch.has_user(before): 1657757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch ch.change_nick(before, after) 1667757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 1677757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def _on_part(self, c, e): 1687757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """[Internal]""" 1697757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch nick = nm_to_n(e.source()) 1707757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch channel = e.target() 1717757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 1727757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch if nick == c.get_nickname(): 1737757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch del self.channels[channel] 1747757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch else: 1757757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.channels[channel].remove_user(nick) 1767757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 1777757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def _on_quit(self, c, e): 1787757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """[Internal]""" 1797757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch nick = nm_to_n(e.source()) 1807757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch for ch in self.channels.values(): 1817757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch if ch.has_user(nick): 1827757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch ch.remove_user(nick) 1837757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 1847757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def die(self, msg="Bye, cruel world!"): 1857757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """Let the bot die. 1867757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 1877757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch Arguments: 1887757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 1897757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch msg -- Quit message. 1907757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """ 1917757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 1927757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.connection.disconnect(msg) 1937757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch sys.exit(0) 1947757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 1957757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def disconnect(self, msg="I'll be back!"): 1967757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """Disconnect the bot. 1977757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 1987757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch The bot will try to reconnect after a while. 1997757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 2007757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch Arguments: 2017757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 2027757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch msg -- Quit message. 2037757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """ 2047757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.connection.disconnect(msg) 2057757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 2067757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def get_version(self): 2077757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """Returns the bot version. 2087757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 2097757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch Used when answering a CTCP VERSION request. 2107757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """ 2117757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch return "ircbot.py by Joel Rosdahl <joel@rosdahl.net>" 2127757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 2137757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def jump_server(self, msg="Changing servers"): 2147757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """Connect to a new server, possibly disconnecting from the current. 2157757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 2167757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch The bot will skip to next server in the server_list each time 2177757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch jump_server is called. 2187757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """ 2197757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch if self.connection.is_connected(): 2207757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.connection.disconnect(msg) 2217757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 2227757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.server_list.append(self.server_list.pop(0)) 2237757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self._connect() 2247757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 2257757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def on_ctcp(self, c, e): 2267757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """Default handler for ctcp events. 2277757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 2287757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch Replies to VERSION and PING requests and relays DCC requests 2297757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch to the on_dccchat method. 2307757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """ 2317757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch if e.arguments()[0] == "VERSION": 2327757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch c.ctcp_reply(nm_to_n(e.source()), 2337757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch "VERSION " + self.get_version()) 2347757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch elif e.arguments()[0] == "PING": 2357757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch if len(e.arguments()) > 1: 2367757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch c.ctcp_reply(nm_to_n(e.source()), 2377757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch "PING " + e.arguments()[1]) 2387757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch elif e.arguments()[0] == "DCC" and e.arguments()[1].split(" ", 1)[0] == "CHAT": 2397757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.on_dccchat(c, e) 2407757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 2417757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def on_dccchat(self, c, e): 2427757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch pass 2437757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 2447757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def start(self): 2457757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """Start the bot.""" 2467757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self._connect() 2477757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch SimpleIRCClient.start(self) 2487757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 2497757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 2507757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochclass IRCDict: 2517757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """A dictionary suitable for storing IRC-related things. 2527757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 2537757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch Dictionary keys a and b are considered equal if and only if 2547757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch irc_lower(a) == irc_lower(b) 2557757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 2567757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch Otherwise, it should behave exactly as a normal dictionary. 2577757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """ 2587757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 2597757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def __init__(self, dict=None): 2607757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.data = {} 2617757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.canon_keys = {} # Canonical keys 2627757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch if dict is not None: 2637757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.update(dict) 2647757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def __repr__(self): 2657757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch return repr(self.data) 2667757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def __cmp__(self, dict): 2677757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch if isinstance(dict, IRCDict): 2687757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch return cmp(self.data, dict.data) 2697757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch else: 2707757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch return cmp(self.data, dict) 2717757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def __len__(self): 2727757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch return len(self.data) 2737757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def __getitem__(self, key): 2747757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch return self.data[self.canon_keys[irc_lower(key)]] 2757757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def __setitem__(self, key, item): 2767757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch if key in self: 2777757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch del self[key] 2787757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.data[key] = item 2797757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.canon_keys[irc_lower(key)] = key 2807757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def __delitem__(self, key): 2817757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch ck = irc_lower(key) 2827757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch del self.data[self.canon_keys[ck]] 2837757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch del self.canon_keys[ck] 2847757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def __iter__(self): 2857757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch return iter(self.data) 2867757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def __contains__(self, key): 2877757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch return self.has_key(key) 2887757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def clear(self): 2897757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.data.clear() 2907757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.canon_keys.clear() 2917757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def copy(self): 2927757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch if self.__class__ is UserDict: 2937757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch return UserDict(self.data) 2947757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch import copy 2957757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch return copy.copy(self) 2967757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def keys(self): 2977757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch return self.data.keys() 2987757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def items(self): 2997757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch return self.data.items() 3007757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def values(self): 3017757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch return self.data.values() 3027757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def has_key(self, key): 3037757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch return irc_lower(key) in self.canon_keys 3047757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def update(self, dict): 3057757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch for k, v in dict.items(): 3067757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.data[k] = v 3077757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def get(self, key, failobj=None): 3087757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch return self.data.get(key, failobj) 3097757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 3107757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 3117757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochclass Channel: 3127757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """A class for keeping information about an IRC channel. 3137757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 3147757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch This class can be improved a lot. 3157757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """ 3167757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 3177757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def __init__(self): 3187757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.userdict = IRCDict() 3197757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.operdict = IRCDict() 3207757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.voiceddict = IRCDict() 3217757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.modes = {} 3227757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 3237757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def users(self): 3247757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """Returns an unsorted list of the channel's users.""" 3257757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch return self.userdict.keys() 3267757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 3277757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def opers(self): 3287757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """Returns an unsorted list of the channel's operators.""" 3297757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch return self.operdict.keys() 3307757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 3317757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def voiced(self): 3327757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """Returns an unsorted list of the persons that have voice 3337757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch mode set in the channel.""" 3347757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch return self.voiceddict.keys() 3357757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 3367757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def has_user(self, nick): 3377757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """Check whether the channel has a user.""" 3387757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch return nick in self.userdict 3397757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 3407757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def is_oper(self, nick): 3417757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """Check whether a user has operator status in the channel.""" 3427757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch return nick in self.operdict 3437757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 3447757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def is_voiced(self, nick): 3457757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """Check whether a user has voice mode set in the channel.""" 3467757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch return nick in self.voiceddict 3477757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 3487757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def add_user(self, nick): 3497757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.userdict[nick] = 1 3507757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 3517757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def remove_user(self, nick): 3527757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch for d in self.userdict, self.operdict, self.voiceddict: 3537757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch if nick in d: 3547757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch del d[nick] 3557757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 3567757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def change_nick(self, before, after): 3577757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.userdict[after] = 1 3587757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch del self.userdict[before] 3597757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch if before in self.operdict: 3607757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.operdict[after] = 1 3617757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch del self.operdict[before] 3627757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch if before in self.voiceddict: 3637757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.voiceddict[after] = 1 3647757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch del self.voiceddict[before] 3657757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 3667757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def set_mode(self, mode, value=None): 3677757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """Set mode on the channel. 3687757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 3697757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch Arguments: 3707757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 3717757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch mode -- The mode (a single-character string). 3727757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 3737757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch value -- Value 3747757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """ 3757757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch if mode == "o": 3767757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.operdict[value] = 1 3777757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch elif mode == "v": 3787757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.voiceddict[value] = 1 3797757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch else: 3807757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch self.modes[mode] = value 3817757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 3827757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def clear_mode(self, mode, value=None): 3837757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """Clear mode on the channel. 3847757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 3857757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch Arguments: 3867757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 3877757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch mode -- The mode (a single-character string). 3887757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 3897757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch value -- Value 3907757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch """ 3917757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch try: 3927757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch if mode == "o": 3937757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch del self.operdict[value] 3947757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch elif mode == "v": 3957757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch del self.voiceddict[value] 3967757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch else: 3977757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch del self.modes[mode] 3987757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch except KeyError: 3997757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch pass 4007757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 4017757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def has_mode(self, mode): 4027757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch return mode in self.modes 4037757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 4047757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def is_moderated(self): 4057757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch return self.has_mode("m") 4067757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 4077757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def is_secret(self): 4087757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch return self.has_mode("s") 4097757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 4107757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def is_protected(self): 4117757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch return self.has_mode("p") 4127757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 4137757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def has_topic_lock(self): 4147757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch return self.has_mode("t") 4157757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 4167757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def is_invite_only(self): 4177757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch return self.has_mode("i") 4187757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 4197757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def has_allow_external_messages(self): 4207757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch return self.has_mode("n") 4217757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 4227757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def has_limit(self): 4237757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch return self.has_mode("l") 4247757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 4257757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def limit(self): 4267757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch if self.has_limit(): 4277757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch return self.modes[l] 4287757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch else: 4297757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch return None 4307757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 4317757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def has_key(self): 4327757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch return self.has_mode("k") 4337757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 4347757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch def key(self): 4357757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch if self.has_key(): 4367757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch return self.modes["k"] 4377757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch else: 4387757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch return None 439