__init__.py
                        
                             · 7.6 KiB · Python
                        
                    
                    
                      
                        Raw
                      
                      
                        
                          
                        
                    
                    
                
                
            from irc.bot import ServerSpec
import irc
import sys
import json
try:
    with open('smbotconfig.json') as f:
        conf = json.load(f)
except:
    print "Error in config or no config found, returning to defaults. Please edit smbotconfig.json (http://jsonlint.com/) and restart the bot"
    with open('smbotconfig.json', 'w') as f:
        f.write(json.dumps(dict(channel="#blha303",
                            nickname="SingleMessageTest",
                            server="irc.esper.net") ) )
    sys.exit(1)
class SingleMessageClient(object):
    reactor_class = irc.client.Reactor
    def __init__(self):
        self.reactor = self.reactor_class()
        self.connection = self.reactor.server()
        self.dcc_connections = []
        self.reactor.add_global_handler("all_events", self._dispatcher, -10)
        self.reactor.add_global_handler("dcc_disconnect",
            self._dcc_disconnect, -10)
    def _dispatcher(self, connection, event):
        """
        Dispatch events to on_<event.type> method, if present.
        """
        do_nothing = lambda c, e: None
        method = getattr(self, "on_" + event.type, do_nothing)
        method(connection, event)
    def _dcc_disconnect(self, c, e):
        self.dcc_connections.remove(c)
    def connect(self, *args, **kwargs):
        """Connect using the underlying connection"""
        self.connection.connect(*args, **kwargs)
    def dcc_connect(self, address, port, dcctype="chat"):
        """Connect to a DCC peer.
        Arguments:
            address -- IP address of the peer.
            port -- Port to connect to.
        Returns a DCCConnection instance.
        """
        dcc = self.reactor.dcc(dcctype)
        self.dcc_connections.append(dcc)
        dcc.connect(address, port)
        return dcc
    def dcc_listen(self, dcctype="chat"):
        """Listen for connections from a DCC peer.
        Returns a DCCConnection instance.
        """
        dcc = self.reactor.dcc(dcctype)
        self.dcc_connections.append(dcc)
        dcc.listen()
        return dcc
    def start(self):
        """Start the IRC client."""
        while 1:
            if not self.connection.is_connected():
                break
            self.reactor.process_once(0.2)
class SingleMessageBot(SingleMessageClient):
    def __init__(self, msg, channel=conf.get('channel'),
                            nickname=conf.get('nickname'),
                            realname=conf.get('realname', conf.get('nickname', None)),
                            server=conf.get('server'),
                            port=conf.get('port', 6667),
                            password=conf.get('password', None),
                            **connect_params):
        super(SingleMessageBot, self).__init__()
        self.__connect_params = connect_params
        self.channel = channel
        self.server = ServerSpec(server, port, password)
        self.msg = msg
        self._nickname = nickname
        self._realname = realname
        for i in ["join", "kick", "mode",
                  "namreply", "nick", "part", "quit"]:
            self.connection.add_global_handler(i, getattr(self, "_on_" + i),
                -20)
    def _connect(self):
        """
        Establish a connection to the server at the front of the server_list.
        """
        try:
            self.connect(self.server.host, self.server.port, self._nickname,
                self.server.password, ircname=self._realname,
                **self.__connect_params)
        except irc.client.ServerConnectionError:
            pass
    def _on_join(self, c, e):
        ch = e.target
        nick = e.source.nick
        if nick == c.get_nickname():
            self.channels[ch] = Channel()
        self.channels[ch].add_user(nick)
    def _on_kick(self, c, e):
        nick = e.arguments[0]
        channel = e.target
        if nick == c.get_nickname():
            del self.channels[channel]
        else:
            self.channels[channel].remove_user(nick)
    def _on_mode(self, c, e):
        modes = irc.modes.parse_channel_modes(" ".join(e.arguments))
        t = e.target
        if irc.client.is_channel(t):
            ch = self.channels[t]
            for mode in modes:
                if mode[0] == "+":
                    f = ch.set_mode
                else:
                    f = ch.clear_mode
                f(mode[1], mode[2])
        else:
            # Mode on self... XXX
            pass
    def _on_namreply(self, c, e):
        """
        e.arguments[0] == "@" for secret channels,
                          "*" for private channels,
                          "=" for others (public channels)
        e.arguments[1] == channel
        e.arguments[2] == nick list
        """
        ch_type, channel, nick_list = e.arguments
        if channel == '*':
            # User is not in any visible channel
            # http://tools.ietf.org/html/rfc2812#section-3.2.5
            return
        for nick in nick_list.split():
            nick_modes = []
            if nick[0] in self.connection.features.prefix:
                nick_modes.append(self.connection.features.prefix[nick[0]])
                nick = nick[1:]
            for mode in nick_modes:
                self.channels[channel].set_mode(mode, nick)
            self.channels[channel].add_user(nick)
    def _on_nick(self, c, e):
        before = e.source.nick
        after = e.target
        for ch in self.channels.values():
            if ch.has_user(before):
                ch.change_nick(before, after)
    def _on_part(self, c, e):
        nick = e.source.nick
        channel = e.target
        if nick == c.get_nickname():
            del self.channels[channel]
        else:
            self.channels[channel].remove_user(nick)
    def _on_quit(self, c, e):
        nick = e.source.nick
        for ch in self.channels.values():
            if ch.has_user(nick):
                ch.remove_user(nick)
    def die(self, msg="Bye, cruel world!"):
        self.connection.disconnect(msg)
    def get_version(self):
        """Returns the bot version.
        Used when answering a CTCP VERSION request.
        """
        return "Python irc.bot ({version})".format(
            version=irc.client.VERSION_STRING)
    def jump_server(self, msg="Changing servers"):
        """Connect to a new server, possibly disconnecting from the current.
        The bot will skip to next server in the server_list each time
        jump_server is called.
        """
        if self.connection.is_connected():
            self.connection.disconnect(msg)
        self.server_list.append(self.server_list.pop(0))
        self._connect()
    def on_ctcp(self, c, e):
        """Default handler for ctcp events.
        Replies to VERSION and PING requests and relays DCC requests
        to the on_dccchat method.
        """
        nick = e.source.nick
        if e.arguments[0] == "VERSION":
            c.ctcp_reply(nick, "VERSION " + self.get_version())
        elif e.arguments[0] == "PING":
            if len(e.arguments) > 1:
                c.ctcp_reply(nick, "PING " + e.arguments[1])
        elif e.arguments[0] == "DCC" and e.arguments[1].split(" ", 1)[0] == "CHAT":
            self.on_dccchat(c, e)
    def on_dccchat(self, c, e):
        pass
    def start(self):
        """Start the bot."""
        self._connect()
        super(SingleMessageBot, self).start()
    def on_welcome(self, c, e):
        c.join(self.channel)
        c.privmsg(self.channel, self.msg)
        c.close()
def main(msg):
    b = SingleMessageBot(msg)
    b.start()
    return 0
if __name__ == "__main__":
    sys.exit(main(" ".join(sys.argv[1:]) if len(sys.argv) > 1 else "This is a test of SingleMessageBot!"))
                | 1 | from irc.bot import ServerSpec | 
| 2 | import irc | 
| 3 | import sys | 
| 4 | import json | 
| 5 | |
| 6 | try: | 
| 7 | with open('smbotconfig.json') as f: | 
| 8 | conf = json.load(f) | 
| 9 | except: | 
| 10 | print "Error in config or no config found, returning to defaults. Please edit smbotconfig.json (http://jsonlint.com/) and restart the bot" | 
| 11 | with open('smbotconfig.json', 'w') as f: | 
| 12 | f.write(json.dumps(dict(channel="#blha303", | 
| 13 | nickname="SingleMessageTest", | 
| 14 | server="irc.esper.net") ) ) | 
| 15 | sys.exit(1) | 
| 16 | |
| 17 | class SingleMessageClient(object): | 
| 18 | reactor_class = irc.client.Reactor | 
| 19 | |
| 20 | def __init__(self): | 
| 21 | self.reactor = self.reactor_class() | 
| 22 | self.connection = self.reactor.server() | 
| 23 | self.dcc_connections = [] | 
| 24 | self.reactor.add_global_handler("all_events", self._dispatcher, -10) | 
| 25 | self.reactor.add_global_handler("dcc_disconnect", | 
| 26 | self._dcc_disconnect, -10) | 
| 27 | |
| 28 | def _dispatcher(self, connection, event): | 
| 29 | """ | 
| 30 | Dispatch events to on_<event.type> method, if present. | 
| 31 | """ | 
| 32 | do_nothing = lambda c, e: None | 
| 33 | method = getattr(self, "on_" + event.type, do_nothing) | 
| 34 | method(connection, event) | 
| 35 | |
| 36 | def _dcc_disconnect(self, c, e): | 
| 37 | self.dcc_connections.remove(c) | 
| 38 | |
| 39 | def connect(self, *args, **kwargs): | 
| 40 | """Connect using the underlying connection""" | 
| 41 | self.connection.connect(*args, **kwargs) | 
| 42 | |
| 43 | def dcc_connect(self, address, port, dcctype="chat"): | 
| 44 | """Connect to a DCC peer. | 
| 45 | |
| 46 | Arguments: | 
| 47 | |
| 48 | address -- IP address of the peer. | 
| 49 | |
| 50 | port -- Port to connect to. | 
| 51 | |
| 52 | Returns a DCCConnection instance. | 
| 53 | """ | 
| 54 | dcc = self.reactor.dcc(dcctype) | 
| 55 | self.dcc_connections.append(dcc) | 
| 56 | dcc.connect(address, port) | 
| 57 | return dcc | 
| 58 | |
| 59 | def dcc_listen(self, dcctype="chat"): | 
| 60 | """Listen for connections from a DCC peer. | 
| 61 | |
| 62 | Returns a DCCConnection instance. | 
| 63 | """ | 
| 64 | dcc = self.reactor.dcc(dcctype) | 
| 65 | self.dcc_connections.append(dcc) | 
| 66 | dcc.listen() | 
| 67 | return dcc | 
| 68 | |
| 69 | def start(self): | 
| 70 | """Start the IRC client.""" | 
| 71 | while 1: | 
| 72 | if not self.connection.is_connected(): | 
| 73 | break | 
| 74 | self.reactor.process_once(0.2) | 
| 75 | |
| 76 | class SingleMessageBot(SingleMessageClient): | 
| 77 | def __init__(self, msg, channel=conf.get('channel'), | 
| 78 | nickname=conf.get('nickname'), | 
| 79 | realname=conf.get('realname', conf.get('nickname', None)), | 
| 80 | server=conf.get('server'), | 
| 81 | port=conf.get('port', 6667), | 
| 82 | password=conf.get('password', None), | 
| 83 | **connect_params): | 
| 84 | super(SingleMessageBot, self).__init__() | 
| 85 | self.__connect_params = connect_params | 
| 86 | self.channel = channel | 
| 87 | self.server = ServerSpec(server, port, password) | 
| 88 | self.msg = msg | 
| 89 | self._nickname = nickname | 
| 90 | self._realname = realname | 
| 91 | for i in ["join", "kick", "mode", | 
| 92 | "namreply", "nick", "part", "quit"]: | 
| 93 | self.connection.add_global_handler(i, getattr(self, "_on_" + i), | 
| 94 | -20) | 
| 95 | |
| 96 | def _connect(self): | 
| 97 | """ | 
| 98 | Establish a connection to the server at the front of the server_list. | 
| 99 | """ | 
| 100 | try: | 
| 101 | self.connect(self.server.host, self.server.port, self._nickname, | 
| 102 | self.server.password, ircname=self._realname, | 
| 103 | **self.__connect_params) | 
| 104 | except irc.client.ServerConnectionError: | 
| 105 | pass | 
| 106 | |
| 107 | def _on_join(self, c, e): | 
| 108 | ch = e.target | 
| 109 | nick = e.source.nick | 
| 110 | if nick == c.get_nickname(): | 
| 111 | self.channels[ch] = Channel() | 
| 112 | self.channels[ch].add_user(nick) | 
| 113 | |
| 114 | def _on_kick(self, c, e): | 
| 115 | nick = e.arguments[0] | 
| 116 | channel = e.target | 
| 117 | |
| 118 | if nick == c.get_nickname(): | 
| 119 | del self.channels[channel] | 
| 120 | else: | 
| 121 | self.channels[channel].remove_user(nick) | 
| 122 | |
| 123 | def _on_mode(self, c, e): | 
| 124 | modes = irc.modes.parse_channel_modes(" ".join(e.arguments)) | 
| 125 | t = e.target | 
| 126 | if irc.client.is_channel(t): | 
| 127 | ch = self.channels[t] | 
| 128 | for mode in modes: | 
| 129 | if mode[0] == "+": | 
| 130 | f = ch.set_mode | 
| 131 | else: | 
| 132 | f = ch.clear_mode | 
| 133 | f(mode[1], mode[2]) | 
| 134 | else: | 
| 135 | # Mode on self... XXX | 
| 136 | pass | 
| 137 | |
| 138 | def _on_namreply(self, c, e): | 
| 139 | """ | 
| 140 | e.arguments[0] == "@" for secret channels, | 
| 141 | "*" for private channels, | 
| 142 | "=" for others (public channels) | 
| 143 | e.arguments[1] == channel | 
| 144 | e.arguments[2] == nick list | 
| 145 | """ | 
| 146 | |
| 147 | ch_type, channel, nick_list = e.arguments | 
| 148 | |
| 149 | if channel == '*': | 
| 150 | # User is not in any visible channel | 
| 151 | # http://tools.ietf.org/html/rfc2812#section-3.2.5 | 
| 152 | return | 
| 153 | |
| 154 | for nick in nick_list.split(): | 
| 155 | nick_modes = [] | 
| 156 | |
| 157 | if nick[0] in self.connection.features.prefix: | 
| 158 | nick_modes.append(self.connection.features.prefix[nick[0]]) | 
| 159 | nick = nick[1:] | 
| 160 | |
| 161 | for mode in nick_modes: | 
| 162 | self.channels[channel].set_mode(mode, nick) | 
| 163 | |
| 164 | self.channels[channel].add_user(nick) | 
| 165 | |
| 166 | def _on_nick(self, c, e): | 
| 167 | before = e.source.nick | 
| 168 | after = e.target | 
| 169 | for ch in self.channels.values(): | 
| 170 | if ch.has_user(before): | 
| 171 | ch.change_nick(before, after) | 
| 172 | |
| 173 | def _on_part(self, c, e): | 
| 174 | nick = e.source.nick | 
| 175 | channel = e.target | 
| 176 | |
| 177 | if nick == c.get_nickname(): | 
| 178 | del self.channels[channel] | 
| 179 | else: | 
| 180 | self.channels[channel].remove_user(nick) | 
| 181 | |
| 182 | def _on_quit(self, c, e): | 
| 183 | nick = e.source.nick | 
| 184 | for ch in self.channels.values(): | 
| 185 | if ch.has_user(nick): | 
| 186 | ch.remove_user(nick) | 
| 187 | |
| 188 | def die(self, msg="Bye, cruel world!"): | 
| 189 | self.connection.disconnect(msg) | 
| 190 | |
| 191 | def get_version(self): | 
| 192 | """Returns the bot version. | 
| 193 | |
| 194 | Used when answering a CTCP VERSION request. | 
| 195 | """ | 
| 196 | return "Python irc.bot ({version})".format( | 
| 197 | version=irc.client.VERSION_STRING) | 
| 198 | |
| 199 | def jump_server(self, msg="Changing servers"): | 
| 200 | """Connect to a new server, possibly disconnecting from the current. | 
| 201 | |
| 202 | The bot will skip to next server in the server_list each time | 
| 203 | jump_server is called. | 
| 204 | """ | 
| 205 | if self.connection.is_connected(): | 
| 206 | self.connection.disconnect(msg) | 
| 207 | |
| 208 | self.server_list.append(self.server_list.pop(0)) | 
| 209 | self._connect() | 
| 210 | |
| 211 | def on_ctcp(self, c, e): | 
| 212 | """Default handler for ctcp events. | 
| 213 | |
| 214 | Replies to VERSION and PING requests and relays DCC requests | 
| 215 | to the on_dccchat method. | 
| 216 | """ | 
| 217 | nick = e.source.nick | 
| 218 | if e.arguments[0] == "VERSION": | 
| 219 | c.ctcp_reply(nick, "VERSION " + self.get_version()) | 
| 220 | elif e.arguments[0] == "PING": | 
| 221 | if len(e.arguments) > 1: | 
| 222 | c.ctcp_reply(nick, "PING " + e.arguments[1]) | 
| 223 | elif e.arguments[0] == "DCC" and e.arguments[1].split(" ", 1)[0] == "CHAT": | 
| 224 | self.on_dccchat(c, e) | 
| 225 | |
| 226 | def on_dccchat(self, c, e): | 
| 227 | pass | 
| 228 | |
| 229 | def start(self): | 
| 230 | """Start the bot.""" | 
| 231 | self._connect() | 
| 232 | super(SingleMessageBot, self).start() | 
| 233 | |
| 234 | def on_welcome(self, c, e): | 
| 235 | c.join(self.channel) | 
| 236 | c.privmsg(self.channel, self.msg) | 
| 237 | c.close() | 
| 238 | |
| 239 | def main(msg): | 
| 240 | b = SingleMessageBot(msg) | 
| 241 | b.start() | 
| 242 | return 0 | 
| 243 | |
| 244 | if __name__ == "__main__": | 
| 245 | sys.exit(main(" ".join(sys.argv[1:]) if len(sys.argv) > 1 else "This is a test of SingleMessageBot!")) |