Ejemplo n.º 1
0
class IRCClientDispatcher(object):
    def __init__(self):
        self.ircobj = IRC()
        self.clients = {}
        self.ircobj.add_global_handler('all_events', self._dispatcher, -10)

    def bind(self, connection, client):
        self.clients[connection] = client

    def _dispatcher(self, connection, event):
        try:
            client = self.clients[connection]
        except KeyError, e:
            raise UnboundClientException(connection)

        if event.eventtype() != 'all_raw_messages':
            print '[%s] %s %s->%s %s' % (connection.get_nickname(), event.eventtype(), event.source(), event.target(), event.arguments())
        handler = getattr(client, 'on_' + event.eventtype(), client.do_nothing)
        handler(connection, event)
Ejemplo n.º 2
0
class IRCClientDispatcher(object):
    def __init__(self):
        self.ircobj = IRC()
        self.clients = {}
        self.ircobj.add_global_handler('all_events', self._dispatcher, -10)

    def bind(self, connection, client):
        self.clients[connection] = client

    def _dispatcher(self, connection, event):
        try:
            client = self.clients[connection]
        except KeyError, e:
            raise UnboundClientException(connection)

        if event.eventtype() != 'all_raw_messages':
            print '[%s] %s %s->%s %s' % (connection.get_nickname(),
                                         event.eventtype(), event.source(),
                                         event.target(), event.arguments())
        handler = getattr(client, 'on_' + event.eventtype(), client.do_nothing)
        handler(connection, event)
Ejemplo n.º 3
0
class CNBIRCCon(CNBCon):
    """
    IRC Connector class
    """

    # Constants
    IRC_REPLY_SLEEP = 0.5
    IRC_PORT = 6667
    IRC_CHAT = 'privmsg'

    _nickname = None
    """ 
    @ivar: Nick name of the bot
    @type: String
    """

    _realname = None
    """ 
    @ivar: Real Name of the bot
    @type: String
    """

    _password = None
    """ 
    @ivar: Bot password for identifying
    @type: String
    """

    server_list = []
    """ 
    @ivar: List of servers to connect
    @type: List
    """

    channels = {}
    """ 
    @ivar: List of joined channels
    @type: hashtable
    """

    channelsToJoin = []
    """ 
    @ivar: List of channels to join when the connector start
    @type: List
    """

    autoReconnect = False
    """ 
    @ivar: Determine if the bot will auto-reconnect if it disconnect/fail
    @type: bool
    """

    reconInterval = 60
    """ 
    @ivar: Reconnection interval (in sec)
    @type: int
    """

    connection = None
    """ 
    @ivar: Connection Object provided by irclib
    @type: Object
    """

    ircobj = None
    """ 
    @ivar: IRC Object provided by irclib
    @type: Object
    """

    def __init__(self, botConfig):
        CNBCon.__init__(self, botConfig)
        config = CNBConfig.getInstance()

        username = botConfig.get('bot', 'username')
        nickname = username
        realname = username
        channels = botConfig.get('bot', 'channels')
        password = botConfig.get('bot', 'password')
        server = botConfig.get('bot', 'server')
        autostart = botConfig.get('bot', 'auto-start')
        autoreconnect = botConfig.get('bot', 'auto-reconnect')
        reconInterval = 60

        self.ircobj = IRC()
        self.connection = self.ircobj.server()
        self.dcc_connections = []
        self.ircobj.add_global_handler("all_events", self._dispatcher, -10)
        #self.ircobj.add_global_handler("dcc_disconnect", self._dcc_disconnect, -10)

        self.autoReconnect = autoreconnect
        self.server_list.append([server, self.IRC_PORT])
        self.channelsToJoin = channels

        self.channels = IRCDict()
        if not reconInterval or reconInterval < 0:
            reconInterval = 2**31
        self.reconInterval = reconInterval

        self._nickname = nickname
        self._realname = realname
        self._password = password

        if autostart == '1':
            self.log.info('Auto-start = 1')
            self.startBot()

        if autoreconnect == '1':
            self.log.info('Auto-reconnect = 1')

    def __del__(self):
        pass

    def _shutdown(self):
        self.log.info('Going down')

    def _getMsgFromEvent(self, e, et = 'Msg'):
        """
        Generate a message object from an event
        @param e: Event
        @type e: Event
        @param et: 
        @type et: String
        """
        oMsg = CNBMessage()
        oMsg.protocol = 'irc'
        oMsg.conId = self._botConfig.get('bot', 'id')
        oMsg.type = str(e.eventtype())
        oMsg.isPrivate = (oMsg.type == 'privmsg' or oMsg.type == 'privnotice' or oMsg.type == 'invite')
        oMsg.source = str(e.source())
        oMsg.target = str(e.target())
        oMsg.text = str(e.arguments()[0]).strip()
        oMsg.domain = self._botConfig.get('bot', 'server')
        oMsg.initCmd()

        if oMsg.isPrivate:
            oMsg.username = str(e.source()).split('!')[0]
            oMsg.replyTo = str(e.source()).split('!')[0]
            if oMsg.type == 'invite':
                oMsg.room = oMsg.text
        else:
            #oMsg.username = str(e.target())
            oMsg.username = str(e.source()).split('!')[0]
            oMsg.replyTo = str(e.target())
            oMsg.room = str(e.target())

        # Logging
        for i in dir(oMsg):
            if i not in ['__init__', '__del__', '__module__', '__doc__']:
                self.log.debug(et + ": oMsg." + str(i) + " = " + str(getattr(oMsg,i)))
        
        return oMsg

    def _dispatcher(self, c, e):
        """[Internal]"""
        m = "_on_" + e.eventtype()
        if hasattr(self, m):
            getattr(self, m)(c, e)

    def _dcc_connect(self, address, port, dcctype="chat"):
        """
        Connect to a DCC peer.
        @param address: IP address of the peer.
        @param port: Port to connect to.
        @return: a DCCConnection instance.
        """
        dcc = self.ircobj.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.ircobj.dcc(dcctype)
        self.dcc_connections.append(dcc)
        dcc.listen()
        return dcc

    def _dcc_disconnect(self, c, e):
        """[Internal]"""
        self.dcc_connections.remove(c)
    
    def _connected_checker(self):
        """[Internal]"""
        if not self.connection.is_connected():
            self.log.info('Not connected, reconnecting')
            self.connection.execute_delayed(self.reconInterval,
                                            self._connected_checker)
            if self.autoReconnect:
                self._connect()

    def _connect(self):
        """[Internal]"""
        password = None
        if len(self.server_list[0]) > 2:
            password = self.server_list[0][2]
        try:
            self.log.info('Connecting to ' + self.server_list[0][0] + ':' + str(self.server_list[0][1]) + ' as ' + self._nickname + ' (ircname:' + self._realname + ')')
            self.connect(self.server_list[0][0],
                         self.server_list[0][1],
                         self._nickname,
                         password,
                         ircname=self._realname)
        except ServerConnectionError:
            self.log.info('Could not connect')

    def _disconnect(self, msg="I'll be back!"):
        """
        Disconnect the bot.
        The bot will try to reconnect after a while.
        @param msg: Quit message.
        @type msg: String
        """
        self.connection.disconnect(msg)

    def _on_ping(self, c, e):
        """[Internal]"""
        #self.log.debug('Received a ping, sending a pong')
        self.connection.pong(e.target())

    def _on_pubmsg(self, c, e):
        """[Internal]"""
        oMatrix = CNBMatrix.getInstance()
        oMsg = self._getMsgFromEvent(e, 'Pub Msg')
        if self._botConfig.get('bot', 'username') != oMsg.replyTo:
            replies = oMatrix.processIrcMod(oMsg)
            if replies != None:
                for r in replies:
                    c.privmsg(oMsg.replyTo, r)
                    sleep(self.IRC_REPLY_SLEEP)

    def _on_privmsg(self, c, e):
        """[Internal]"""
        oMatrix = CNBMatrix.getInstance()
        oMsg = self._getMsgFromEvent(e, 'Priv Msg')
        if self._botConfig.get('bot', 'username') != oMsg.replyTo:
            replies = oMatrix.processIrcMod(oMsg)
            if replies != None:
                for r in replies:
                    c.privmsg(oMsg.replyTo, r)
                    sleep(self.IRC_REPLY_SLEEP)
    
    def _on_pubnotice(self, c, e):
        """
        Pub Notice event handler
        Note: the bot do not answer to pub notice
        """
        oMsg = self._getMsgFromEvent(e, 'Pub Notice')

    def _on_privnotice(self, c, e):
        """[Internal]"""
        oMsg = self._getMsgFromEvent(e, 'Priv Notice')
        if oMsg.replyTo == 'NickServ' and 'You are now identified for' in oMsg.text:
            self.setState('identified')

    def _on_invite(self, c, e):
        """[Internal]"""
        oMatrix = CNBMatrix.getInstance()
        oMsg = self._getMsgFromEvent(e, 'Invite')
        if self._botConfig.get('bot', 'username') != oMsg.replyTo:
            replies = oMatrix.processIrcMod(oMsg)
            if replies != None:
                for r in replies:
                    c.privmsg(oMsg.replyTo, r)
                    sleep(self.IRC_REPLY_SLEEP)

    def _on_disconnect(self, c, e):
        """[Internal]"""
        self.channels = IRCDict()
        self.connection.execute_delayed(self.reconInterval,
                                        self._connected_checker)

    def _on_all_raw_messages(self, c, e):
        """[Internal]"""
        self.log.debug('Raw Message: ' + str(e.arguments()))

    def _on_error(self, c, e):
        """[Internal]"""
        self.log.info('Error: ' + str(c) + str(e))
        self.log.exception(str(c))
        self.log.exception(str(e))

    def _on_join(self, c, e):
        """[Internal]"""
        ch = e.target()
        nick = nm_to_n(e.source())
        self.log.info(nick + ' is joining channel ' + ch)
        if nick == c.get_nickname():
            self.channels[ch] = Channel()
        self.channels[ch].add_user(nick)

    def _on_kick(self, c, e):
        """[Internal]"""
        nick = e.arguments()[0]
        ch = e.target()

        self.log.info(nick + ' was kicked from ' + ch)
        if nick == c.get_nickname():
            del self.channels[ch]
        else:
            self.channels[ch].remove_user(nick)

    def _on_mode(self, c, e):
        """[Internal]"""
        modes = parse_channel_modes(" ".join(e.arguments()))
        t = e.target()
        self.log.info(t + ' set mode to ' + t)
        if 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):
        """
        [Internal]
        e.arguments()[0] == "@" for secret channels,
                             "*" for private channels,
                             "=" for others (public channels)
        e.arguments()[1] == channel
        e.arguments()[2] == nick list
        """

        ch = e.arguments()[1]
        for nick in e.arguments()[2].split():
            if nick[0] == "@":
                nick = nick[1:]
                self.channels[ch].set_mode("o", nick)
            elif nick[0] == "+":
                nick = nick[1:]
                self.channels[ch].set_mode("v", nick)
            self.channels[ch].add_user(nick)

    def _on_nick(self, c, e):
        """[Internal]"""
        before = nm_to_n(e.source())
        after = e.target()
        self.log.info(before + ' set nick to ' + after)
        for ch in self.channels.values():
            if ch.has_user(before):
                ch.change_nick(before, after)

    def _on_part(self, c, e):
        """[Internal]"""
        nick = nm_to_n(e.source())
        channel = e.target()
        self.log.info(nick + ' left the chan ' + channel)
        if nick == c.get_nickname():
            del self.channels[channel]
        else:
            self.channels[channel].remove_user(nick)

    def _on_quit(self, c, e):
        """[Internal]"""
        nick = nm_to_n(e.source())
        self.log.info(nick + ' has quit')
        for ch in self.channels.values():
            if ch.has_user(nick):
                ch.remove_user(nick)

    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.
        """
        if e.arguments()[0] == "VERSION":
            c.ctcp_reply(nm_to_n(e.source()),
                         "VERSION " + self.get_version())
        elif e.arguments()[0] == "PING":
            if len(e.arguments()) > 1:
                c.ctcp_reply(nm_to_n(e.source()),
                             "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):
        """[Internal]"""
        pass

    def run(self):
        """
        IRC connector main thread - Listen to commands, parse messages and responses to users.
        """
        while self.isRunning():
            if self.getState() == 'dying':
                break

            if self.getState() in ['connected', 'identifying', 'joiningChannels']:
                try:
                    self.ircobj.process_once(1)
                except KeyboardInterrupt:
                    self.log.info('bot stopped by user request. shutting down.')
                    break
                except Exception, e:
                    self.log.exception(e)

            if self.getState() == 'joiningChannels':
                for ch in self.channelsToJoin:
                    if ':' in ch:
                        ch,pwd = ch.split(':',1)
                        self.joinChan(ch,pwd)
                    else:
                        self.joinChan(ch)
                self.setState('connected')

            if self.getState() == 'identified':
                self.log.info('Identified, joining channels...')
                self.setState('joiningChannels')
                #sleep(2)
                self.ircobj.process_once(0.5)

            if self.getState() == 'identifying':
                if self._password:
                    self.log.info('Identifying with password')
                    self.identify(self._password)
                    #sleep(2)
                    self.ircobj.process_once(0.5)
                self.setState('identified')

            if self.getState() == 'connecting':
                self._connect()
                if self.connection.is_connected():
                    self.log.info('bot connected, identifying...')
                    self.setState('identifying')
                    sleep(5)
                    self.ircobj.process_once(0.5)
                else:
                    self.log.warn('could not connect to server - aborting.')
                    self.setState('disconnected')

            if self.getState() == 'disconnected':
                #self.log.info('bot disconnected')
                if self.autoReconnect:
                    self.setState('connecting')
                    self.ircobj.process_once(0.5)

            if self.getState() == 'disconnecting':
                self.log.info('bot disconnecting')
                self._disconnect()
                self.setState('disconnected')

            if self.getState() == 'notstarted':
                pass

           # self.log.info('Current state: ' + self.getState())
            sleep(1)

        self._shutdown()
        return 0
Ejemplo n.º 4
0
class CNBIRCCon(CNBCon):
    """
    IRC Connector class
    """

    # Constants
    IRC_REPLY_SLEEP = 0.5
    IRC_PORT = 6667
    IRC_CHAT = 'privmsg'

    _nickname = None
    """ 
    @ivar: Nick name of the bot
    @type: String
    """

    _realname = None
    """ 
    @ivar: Real Name of the bot
    @type: String
    """

    _password = None
    """ 
    @ivar: Bot password for identifying
    @type: String
    """

    server_list = []
    """ 
    @ivar: List of servers to connect
    @type: List
    """

    channels = {}
    """ 
    @ivar: List of joined channels
    @type: hashtable
    """

    channelsToJoin = []
    """ 
    @ivar: List of channels to join when the connector start
    @type: List
    """

    autoReconnect = False
    """ 
    @ivar: Determine if the bot will auto-reconnect if it disconnect/fail
    @type: bool
    """

    reconInterval = 60
    """ 
    @ivar: Reconnection interval (in sec)
    @type: int
    """

    connection = None
    """ 
    @ivar: Connection Object provided by irclib
    @type: Object
    """

    ircobj = None
    """ 
    @ivar: IRC Object provided by irclib
    @type: Object
    """
    def __init__(self, botConfig):
        CNBCon.__init__(self, botConfig)
        config = CNBConfig.getInstance()

        username = botConfig.get('bot', 'username')
        nickname = username
        realname = username
        channels = botConfig.get('bot', 'channels')
        password = botConfig.get('bot', 'password')
        server = botConfig.get('bot', 'server')
        autostart = botConfig.get('bot', 'auto-start')
        autoreconnect = botConfig.get('bot', 'auto-reconnect')
        reconInterval = 60

        self.ircobj = IRC()
        self.connection = self.ircobj.server()
        self.dcc_connections = []
        self.ircobj.add_global_handler("all_events", self._dispatcher, -10)
        #self.ircobj.add_global_handler("dcc_disconnect", self._dcc_disconnect, -10)

        self.autoReconnect = autoreconnect
        self.server_list.append([server, self.IRC_PORT])
        self.channelsToJoin = channels

        self.channels = IRCDict()
        if not reconInterval or reconInterval < 0:
            reconInterval = 2**31
        self.reconInterval = reconInterval

        self._nickname = nickname
        self._realname = realname
        self._password = password

        if autostart == '1':
            self.log.info('Auto-start = 1')
            self.startBot()

        if autoreconnect == '1':
            self.log.info('Auto-reconnect = 1')

    def __del__(self):
        pass

    def _shutdown(self):
        self.log.info('Going down')

    def _getMsgFromEvent(self, e, et='Msg'):
        """
        Generate a message object from an event
        @param e: Event
        @type e: Event
        @param et: 
        @type et: String
        """
        oMsg = CNBMessage()
        oMsg.protocol = 'irc'
        oMsg.conId = self._botConfig.get('bot', 'id')
        oMsg.type = str(e.eventtype())
        oMsg.isPrivate = (oMsg.type == 'privmsg' or oMsg.type == 'privnotice'
                          or oMsg.type == 'invite')
        oMsg.source = str(e.source())
        oMsg.target = str(e.target())
        oMsg.text = str(e.arguments()[0]).strip()
        oMsg.domain = self._botConfig.get('bot', 'server')
        oMsg.initCmd()

        if oMsg.isPrivate:
            oMsg.username = str(e.source()).split('!')[0]
            oMsg.replyTo = str(e.source()).split('!')[0]
            if oMsg.type == 'invite':
                oMsg.room = oMsg.text
        else:
            #oMsg.username = str(e.target())
            oMsg.username = str(e.source()).split('!')[0]
            oMsg.replyTo = str(e.target())
            oMsg.room = str(e.target())

        # Logging
        for i in dir(oMsg):
            if i not in ['__init__', '__del__', '__module__', '__doc__']:
                self.log.debug(et + ": oMsg." + str(i) + " = " +
                               str(getattr(oMsg, i)))

        return oMsg

    def _dispatcher(self, c, e):
        """[Internal]"""
        m = "_on_" + e.eventtype()
        if hasattr(self, m):
            getattr(self, m)(c, e)

    def _dcc_connect(self, address, port, dcctype="chat"):
        """
        Connect to a DCC peer.
        @param address: IP address of the peer.
        @param port: Port to connect to.
        @return: a DCCConnection instance.
        """
        dcc = self.ircobj.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.ircobj.dcc(dcctype)
        self.dcc_connections.append(dcc)
        dcc.listen()
        return dcc

    def _dcc_disconnect(self, c, e):
        """[Internal]"""
        self.dcc_connections.remove(c)

    def _connected_checker(self):
        """[Internal]"""
        if not self.connection.is_connected():
            self.log.info('Not connected, reconnecting')
            self.connection.execute_delayed(self.reconInterval,
                                            self._connected_checker)
            if self.autoReconnect:
                self._connect()

    def _connect(self):
        """[Internal]"""
        password = None
        if len(self.server_list[0]) > 2:
            password = self.server_list[0][2]
        try:
            self.log.info('Connecting to ' + self.server_list[0][0] + ':' +
                          str(self.server_list[0][1]) + ' as ' +
                          self._nickname + ' (ircname:' + self._realname + ')')
            self.connect(self.server_list[0][0],
                         self.server_list[0][1],
                         self._nickname,
                         password,
                         ircname=self._realname)
        except ServerConnectionError:
            self.log.info('Could not connect')

    def _disconnect(self, msg="I'll be back!"):
        """
        Disconnect the bot.
        The bot will try to reconnect after a while.
        @param msg: Quit message.
        @type msg: String
        """
        self.connection.disconnect(msg)

    def _on_ping(self, c, e):
        """[Internal]"""
        #self.log.debug('Received a ping, sending a pong')
        self.connection.pong(e.target())

    def _on_pubmsg(self, c, e):
        """[Internal]"""
        oMatrix = CNBMatrix.getInstance()
        oMsg = self._getMsgFromEvent(e, 'Pub Msg')
        if self._botConfig.get('bot', 'username') != oMsg.replyTo:
            replies = oMatrix.processIrcMod(oMsg)
            if replies != None:
                for r in replies:
                    c.privmsg(oMsg.replyTo, r)
                    sleep(self.IRC_REPLY_SLEEP)

    def _on_privmsg(self, c, e):
        """[Internal]"""
        oMatrix = CNBMatrix.getInstance()
        oMsg = self._getMsgFromEvent(e, 'Priv Msg')
        if self._botConfig.get('bot', 'username') != oMsg.replyTo:
            replies = oMatrix.processIrcMod(oMsg)
            if replies != None:
                for r in replies:
                    c.privmsg(oMsg.replyTo, r)
                    sleep(self.IRC_REPLY_SLEEP)

    def _on_pubnotice(self, c, e):
        """
        Pub Notice event handler
        Note: the bot do not answer to pub notice
        """
        oMsg = self._getMsgFromEvent(e, 'Pub Notice')

    def _on_privnotice(self, c, e):
        """[Internal]"""
        oMsg = self._getMsgFromEvent(e, 'Priv Notice')
        if oMsg.replyTo == 'NickServ' and 'You are now identified for' in oMsg.text:
            self.setState('identified')

    def _on_invite(self, c, e):
        """[Internal]"""
        oMatrix = CNBMatrix.getInstance()
        oMsg = self._getMsgFromEvent(e, 'Invite')
        if self._botConfig.get('bot', 'username') != oMsg.replyTo:
            replies = oMatrix.processIrcMod(oMsg)
            if replies != None:
                for r in replies:
                    c.privmsg(oMsg.replyTo, r)
                    sleep(self.IRC_REPLY_SLEEP)

    def _on_disconnect(self, c, e):
        """[Internal]"""
        self.channels = IRCDict()
        self.connection.execute_delayed(self.reconInterval,
                                        self._connected_checker)

    def _on_all_raw_messages(self, c, e):
        """[Internal]"""
        self.log.debug('Raw Message: ' + str(e.arguments()))

    def _on_error(self, c, e):
        """[Internal]"""
        self.log.info('Error: ' + str(c) + str(e))
        self.log.exception(str(c))
        self.log.exception(str(e))

    def _on_join(self, c, e):
        """[Internal]"""
        ch = e.target()
        nick = nm_to_n(e.source())
        self.log.info(nick + ' is joining channel ' + ch)
        if nick == c.get_nickname():
            self.channels[ch] = Channel()
        self.channels[ch].add_user(nick)

    def _on_kick(self, c, e):
        """[Internal]"""
        nick = e.arguments()[0]
        ch = e.target()

        self.log.info(nick + ' was kicked from ' + ch)
        if nick == c.get_nickname():
            del self.channels[ch]
        else:
            self.channels[ch].remove_user(nick)

    def _on_mode(self, c, e):
        """[Internal]"""
        modes = parse_channel_modes(" ".join(e.arguments()))
        t = e.target()
        self.log.info(t + ' set mode to ' + t)
        if 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):
        """
        [Internal]
        e.arguments()[0] == "@" for secret channels,
                             "*" for private channels,
                             "=" for others (public channels)
        e.arguments()[1] == channel
        e.arguments()[2] == nick list
        """

        ch = e.arguments()[1]
        for nick in e.arguments()[2].split():
            if nick[0] == "@":
                nick = nick[1:]
                self.channels[ch].set_mode("o", nick)
            elif nick[0] == "+":
                nick = nick[1:]
                self.channels[ch].set_mode("v", nick)
            self.channels[ch].add_user(nick)

    def _on_nick(self, c, e):
        """[Internal]"""
        before = nm_to_n(e.source())
        after = e.target()
        self.log.info(before + ' set nick to ' + after)
        for ch in self.channels.values():
            if ch.has_user(before):
                ch.change_nick(before, after)

    def _on_part(self, c, e):
        """[Internal]"""
        nick = nm_to_n(e.source())
        channel = e.target()
        self.log.info(nick + ' left the chan ' + channel)
        if nick == c.get_nickname():
            del self.channels[channel]
        else:
            self.channels[channel].remove_user(nick)

    def _on_quit(self, c, e):
        """[Internal]"""
        nick = nm_to_n(e.source())
        self.log.info(nick + ' has quit')
        for ch in self.channels.values():
            if ch.has_user(nick):
                ch.remove_user(nick)

    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.
        """
        if e.arguments()[0] == "VERSION":
            c.ctcp_reply(nm_to_n(e.source()), "VERSION " + self.get_version())
        elif e.arguments()[0] == "PING":
            if len(e.arguments()) > 1:
                c.ctcp_reply(nm_to_n(e.source()), "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):
        """[Internal]"""
        pass

    def run(self):
        """
        IRC connector main thread - Listen to commands, parse messages and responses to users.
        """
        while self.isRunning():
            if self.getState() == 'dying':
                break

            if self.getState() in [
                    'connected', 'identifying', 'joiningChannels'
            ]:
                try:
                    self.ircobj.process_once(1)
                except KeyboardInterrupt:
                    self.log.info(
                        'bot stopped by user request. shutting down.')
                    break
                except Exception, e:
                    self.log.exception(e)

            if self.getState() == 'joiningChannels':
                for ch in self.channelsToJoin:
                    if ':' in ch:
                        ch, pwd = ch.split(':', 1)
                        self.joinChan(ch, pwd)
                    else:
                        self.joinChan(ch)
                self.setState('connected')

            if self.getState() == 'identified':
                self.log.info('Identified, joining channels...')
                self.setState('joiningChannels')
                #sleep(2)
                self.ircobj.process_once(0.5)

            if self.getState() == 'identifying':
                if self._password:
                    self.log.info('Identifying with password')
                    self.identify(self._password)
                    #sleep(2)
                    self.ircobj.process_once(0.5)
                self.setState('identified')

            if self.getState() == 'connecting':
                self._connect()
                if self.connection.is_connected():
                    self.log.info('bot connected, identifying...')
                    self.setState('identifying')
                    sleep(5)
                    self.ircobj.process_once(0.5)
                else:
                    self.log.warn('could not connect to server - aborting.')
                    self.setState('disconnected')

            if self.getState() == 'disconnected':
                #self.log.info('bot disconnected')
                if self.autoReconnect:
                    self.setState('connecting')
                    self.ircobj.process_once(0.5)

            if self.getState() == 'disconnecting':
                self.log.info('bot disconnecting')
                self._disconnect()
                self.setState('disconnected')

            if self.getState() == 'notstarted':
                pass

        # self.log.info('Current state: ' + self.getState())
            sleep(1)

        self._shutdown()
        return 0