Beispiel #1
0
	def __init__(self, channels=[], nickname="", server="", port=6667, module_list=[]):
		"""MooBot initializer - gets values from config files and uses those
		unless passed values directly"""
		# Get values from config files and replace any of the empty ones above
		configs = self.get_configs()
		config_nick = configs['nick']
		config_server = configs['server']
		config_port = configs['port']
		config_channels = configs['channels']
		config_module_list = configs['module_list']
		config_others = configs['others']
		# If we are passed any values directly, use those, but if they are empty
		# we will fall back to the values we got from the config file
		if channels == []: channels = config_channels
		if nickname == "": nickname = config_nick
		if server == "": server = config_server
		if port == 6667: port = config_port
		if module_list == []: module_list = config_module_list
		# Now that we have our values, initialize it all
		SingleServerIRCBot.__init__(self, [(server, port)], nickname, nickname)
		self.channels = IRCDict()
		for channel in channels:
			self.channels[channel] = Channel()
		self.handlers = []
		self.configs = config_others
		self.module_list = module_list
Beispiel #2
0
 def _on_disconnect(self, c, e):
     """[Internal]"""
     self.channels = IRCDict()
     if self.runCond:
         self.connection.execute_delayed(self.reconnection_interval,
                                         self._connected_checker)
     if hasattr(self, "disconnect_event"):
         self.disconnect_event.set()
Beispiel #3
0
    def __init__(self,
                 channels=[],
                 nickname="",
                 password="",
                 realname="",
                 server="",
                 port=6667,
                 module_list=[],
                 encoding=""):
        """MooBot initializer - gets values from config files and uses those
		unless passed values directly"""
        Debug("possible config files: " + ", ".join(self.config_files))

        # Get values from config files and replace any of the empty ones above
        configs = self.get_configs()
        config_nick = configs['nick']
        config_username = configs['username']
        config_realname = configs['realname']
        config_server = configs['server']
        config_port = configs['port']
        config_encoding = configs['encoding']
        config_password = configs['password']
        config_channels = configs['channels']
        config_module_list = configs['module_list']
        config_others = configs['others']
        # If we are passed any values directly, use those, but if they are empty
        # we will fall back to the values we got from the config file
        #		for var in \
        #			['channels', 'nickname', 'username', 'server',
        #			'port', 'module_list', 'others']:
        #				if kwargs.has_key(var):
        #		if kwargs.has_key('channels'): channels = kwargs['channels']
        #		else: channels = config_channels
        if channels == []: channels = config_channels
        if nickname == "": nickname = config_nick
        if realname == "": realname = config_realname
        if server == "": server = config_server
        if port == 6667: port = config_port
        if password == "": password = config_password
        if module_list == []: module_list = config_module_list
        if encoding == "": encoding = config_encoding
        # Now that we have our values, initialize it all
        SingleServerIRCBot.__init__(
            self, [(server, port, password, encoding.upper())], nickname,
            realname)
        self.serve_nick = config_nick
        self.serve_password = config_password
        self.serve_channels = [
            channel for channel in channels if channel.strip()
        ]
        self.channels = IRCDict()
        self.handlers = {}
        self.configs = config_others
        self.module_list = module_list
Beispiel #4
0
    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')
Beispiel #5
0
    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')
Beispiel #6
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
Beispiel #7
0
 def _on_disconnect(self, c, e):
     """[Internal]"""
     self.channels = IRCDict()
     self.connection.execute_delayed(self.reconInterval,
                                     self._connected_checker)
Beispiel #8
0
class MooBot(SingleServerIRCBot):
	class MooBotException(Exception): pass
	class HandlerExists(MooBotException): pass
	config_files = ['moobot.conf', '/etc/moobot.conf']

	def __init__(self, channels=[], nickname="", server="", port=6667, module_list=[]):
		"""MooBot initializer - gets values from config files and uses those
		unless passed values directly"""
		# Get values from config files and replace any of the empty ones above
		configs = self.get_configs()
		config_nick = configs['nick']
		config_server = configs['server']
		config_port = configs['port']
		config_channels = configs['channels']
		config_module_list = configs['module_list']
		config_others = configs['others']
		# If we are passed any values directly, use those, but if they are empty
		# we will fall back to the values we got from the config file
		if channels == []: channels = config_channels
		if nickname == "": nickname = config_nick
		if server == "": server = config_server
		if port == 6667: port = config_port
		if module_list == []: module_list = config_module_list
		# Now that we have our values, initialize it all
		SingleServerIRCBot.__init__(self, [(server, port)], nickname, nickname)
		self.channels = IRCDict()
		for channel in channels:
			self.channels[channel] = Channel()
		self.handlers = []
		self.configs = config_others
		self.module_list = module_list

	def on_join(self, c, e):
		"""Whenever a client joins a channel the bot is in, this is
		executed"""
		pass

	def on_welcome(self, c, e):
		"""Whenever this bot joins a server, this is executed"""
		for channel in self.channels.keys():
			print "Joining", channel
			c.join(channel)

	def on_privmsg(self, c, e):
		"""Whenever someone sends a /msg to our bot, this is executed"""
		msg = e.arguments()[0]	# the string of what was said
		# build the args dict for the handlers
		args={}
		args["text"] = self.connection.get_nickname() + ": " + msg
		args["type"] = e.eventtype()
		args["source"] = e.source()
		args["channel"] = e.target()
		msg = string.strip(msg)
		from irclib import nm_to_n
		# print what was said to the stdout with a bit of colour.
		print YELLOW + "<" + nm_to_n(args["source"]) + NORMAL + "/" + \
			BLUE + args["channel"] + ">" + NORMAL + \
			RED + "(" + args["type"] + ")" + NORMAL, args["text"]
		temp = threading.Thread(target=self.process_privmsg, args=(msg, args), name="privmsg subthread")
		temp.setDaemon(1)
		temp.start()
	
	def process_privmsg(self, msg, args):
		"""Process private messages (/msg's) to the bot"""
		eventlist = self.get_local_handler(msg, args)
		if eventlist != []:
			for event in eventlist:
				self.do_event(event)

	def on_pubmsg(self, c, e):
		"""Whenever someone speaks in a channel where our bot resides, this is
		executed"""
		import string
		msg = e.arguments()[0]
		args = {}
		args["text"] = msg
		args["type"] = e.eventtype()
		args["source"] = e.source()
		args["channel"] = e.target()
		# Then check with all the global handlers, see if any match
		from irclib import nm_to_n
		# print what was said to the stdout with a bit of colour.
		print YELLOW + "<" + nm_to_n(args["source"]) + NORMAL + "/" +\
			BLUE + args["channel"] + ">" + NORMAL +\
			RED + "(" + args["type"] + ")" + NORMAL, args["text"]
		temp = threading.Thread(target=self.process_pubmsg, \
			args=(msg, args), name="pubmsg subthread")
		temp.setDaemon(1)
		temp.start()
	
	def process_pubmsg(self, msg, args):
		"""Process messages into the channel"""
		from re import compile
		import string
		eventlist = self.get_global_handler(msg, args)
		if eventlist != []:
			for event in eventlist:
				self.do_event(event)
			if eventlist[-1].eventtype() != "continue":
				return
		# If we are referred to with our shorthand name, make it look
		# like we were referred to normally.
		shortname = "^\s*" + self.configs["shorthand"]
		shortregex = compile(shortname)
		replace_str = self.connection.get_nickname() + ": "
		if shortregex.search(msg):
			msg = string.replace(msg, self.configs["shorthand"], replace_str, 1)
			args["text"] = msg
		# Now, check and see if we are being spoken too
		ourname = "^" + self.connection.get_nickname()
		regex = compile(ourname)
		if regex.search(msg):
			msg = string.strip(msg[string.find(msg, " "):])
			eventlist = self.get_local_handler(msg, args)
			if eventlist != []:
				for event in eventlist:
					self.do_event(event)

	def get_global_handler(self, msg, args):
		"""Used when an event is raised that needs a global handler"""
		return self.get_handler(Handler.GLOBAL, msg, args)

	def get_local_handler(self, msg, args):
		"""Used when an event is raised that needs a local handler"""
		return self.get_handler(Handler.LOCAL, msg, args)

	def get_handler(self, type, msg, args):
		"""Used when an event is raised that needs an event handler"""
		# Check through the handlers for a key that matches
		# the message contents.
		from irclib import nm_to_n
		from irclib import Event
		import weakref
		nickname = self.connection.get_nickname()
		if type == Handler.GLOBAL and args["text"][:len(nickname)] != nickname:
			# For now we are going to rewrite the message with the
			# name on the front so that modules don't care if they are
			# local or global.
			args["text"] = self.connection.get_nickname() + ": " +\
				args["text"]
		# Iterate over the list of registered handlers, looking for a handler
		# that matches in type and regex.  When it is found, call it and get a
		# resulting event or list of events which we return
		eventlist = [Event("continue", "", "", [""])]
		for handler in self.handlers:
			if eventlist[-1].eventtype() != "continue":
				break

			if handler.type == type:
				if handler.regex.search(msg):
					instance = handler.instance
					# result can either be an Event or a list of Events, 
					# in either case, we just add on all the Events to
					# eventlist
					result = instance.handler(text=args["text"], 
						type=args["type"], source=args["source"], 
						channel=args["channel"], ref=weakref.ref(self))
					if isinstance(result, Event):
						eventlist.append(result)
					else:
						eventlist += result

		if len(eventlist) >1:
			return eventlist

		# This should never come up unless you take out the "dunno" handlers
		# that generally hand every case that no other handler takes care of
		if type == Handler.LOCAL:
			print "Could not get event handler."
			print "msg:", args["text"]
			print "type:", args["type"]
			print "source:", args["source"]
			print "channel:", args["channel"]

		return []

	def list_handlers(self):
		"""Display the handlers currently registered with the bot"""
		strings =[] 
		for handler in self.handlers:
			if handler.function.__doc__ is not None:
				string = handler.pattern() + ": " + handler.func_name() + \
					"() - " + handler.function.__doc__ + " ("
				if handler.type == Handler.GLOBAL: string += "global)"
				else: string += "local)"
			else:
				string = handler.pattern() + ": " + handler.func_name() + "() ("
				if handler.type == Handler.GLOBAL: string += "global)"
				else: string += "local)"
			strings.append(string)
		return strings

	def do_event(self, event):
		"""Does an appropriate action based on event"""
		if event.eventtype() == "privmsg":
			for line in string.split(event.arguments()[0], "\n"):
				# print the output to the STDOUT, with a bit of colour
				print RED + ">" + \
					PURPLE + self.connection.get_nickname() + \
					RED + "/" + \
					GREEN + event.target() + \
					RED + "<" + \
					NORMAL, line
				self.connection.privmsg(event.target(), line)
		elif event.eventtype() == "action":
			print RED + " * " + \
				PURPLE + self.connection.get_nickname() + \
				RED + "/" + \
				GREEN + event.target() + \
				NORMAL, event.arguments()
			self.connection.action(event.target(), event.arguments()[0])
		elif event.eventtype() == "internal":
			#print "internal", event.arguments()[0], event.target
			if event.arguments()[0] == "join":
				print "Joining", event.target()
				self.connection.join(event.target())
			elif event.arguments()[0] == "part":
				print "Parting", event.target()
				self.connection.part(event.target())
			elif event.arguments()[0] == "load":
				self.load_module(event);
			elif event.arguments()[0] == "unload":
				self.unload_module(event);
			elif event.arguments()[0] == "nick":
				print "Changing nick to ", event.target()
				self.connection.nick(event.target())
			elif event.arguments()[0] == "kick":
				print "Kicking", event.target(), "from", event.arguments()[1]
				self.connection.kick(event.arguments()[1], event.target())
			elif event.arguments()[0] == "send_raw":
				print "Sending raw command: " + event.arguments()[0]
				self.connection.send_raw(event.arguments()[1])
			elif event.arguments()[0] == "modules":
				from irclib import Event
#				if event.arguments()[1] == "":
#					strings = self.list_handlers()
#					reply = ""
#					for msg in strings:
#						reply += msg + " ;; "
#					self.do_event(Event("privmsg", "", event.target(), [reply]))
#				else:
				for module in event.arguments()[1].split(" "):
					match = 0
					for handler in self.handlers:
						if handler.className == module:
							match = 1
							if handler.className is not None:
								msg = `handler.pattern()` + ": " + \
									`handler.func_name()` + "() - " + \
									`handler.instance.__doc__` + " ("
								if handler.type == Handler.GLOBAL:
									msg += "global)"
								else:
									msg += "local)"
							else:
								msg = handler.pattern() + ": " + \
									handler.func_name() + "() ("
								if handler.type == Handler.GLOBAL:
									msg += "global)"
								else:
									msg += "local)"
					if match == 0:
						msg = "no handler found with function " + module + "()"
					self.do_event(Event("privmsg", "", event.target(), [msg]))
		elif event.eventtype() == "continue":
			return
		else:
			print "This event type", event.eventtype(), "has no suitable event"

	def get_configs(self, filelist=[]):
		"""Gets configuration options from a list of files"""
		from ConfigParser import ConfigParser, NoSectionError, NoOptionError
		config = ConfigParser()
		filelist += MooBot.config_files
		config.read(filelist)
		# Initialize the things we will return just in case they aren't in
		# any of the files that we parse through.  Then get their values
		# and stick the rest in "others"
		nick=""; server=""; port=6667; channels=[]; others={}
		try:
			nick = config.get('connection', 'nick')
			server = config.get('connection', 'server')
			port = int(config.get('connection', 'port'))
			channels = config.get('connection', 'channels').split(" ")
			module_list = config.get('modules', 'modulefiles').split(" ")
		except ValueError:
			print "ERROR: Non-numeric port in config files."
		except NoSectionError:
			print "ERROR: [connection] section missing from config files."
		except NoOptionError:
			print "ERROR: missing vital option"
		for section in config.sections():
			if section != "connection":
				# These will all be returned, don't need to be in others
				for option in config.options(section):
					others[option] = config.get(section, option)
		return {'nick': nick, 'server': server, 'port': port,
			'channels': channels, 'module_list': module_list,
			'others': others}
	
	def load_module(self, event):
		""" this loads a module, at run-time.  event is an Event whose arguments()
		attribute contains a list of modules to write (starting with the second
		element """
		import imp
		for newmod in event.arguments()[1:]:
			# why this?  --djd
			fp = ""
			pathname = ""
			description = ""

			# we need to do this to make sure the module is there, and to
			# get some information needed by imp.load_module
			try:
				fp, pathname, description = imp.find_module(newmod)
			except:
				print "Module \"%s\" not found " % (newmod)
				if fp:
					fp.close()
				continue

			# as a side note, imp.load_module doesn't add the module to
			# the modules table, it only returns a reference to that 
			# module.
			try:
				importedModule = imp.load_module(newmod, fp, pathname, description)
				# each module contains a list called handler_list, which
				# contains the names of classes to be loaded as bot modules
				for handlerName in importedModule.handler_list:
					newHandler = Handler(importedModule, handlerName)
					self.handlers.append(newHandler)
					print "Added handler: " , handlerName, "for \"" \
						+ newHandler.regex.pattern+"\"", \
						"priority ", newHandler.instance.priority
				if importedModule.__name__ not in self.module_list:
					self.module_list.append(importedModule.__name__)
			finally:
				# sort the list (for priorities)
				self.handlers.sort()
				# Since we may exit via an exception, close fp explicitly.
				if fp:
					fp.close()

	def unload_module(self, event):
		""" remove any handlers from self.handlers that are from any of the
		modules passed in event.arguments()[1:]"""
		module_list = event.arguments()[1:]
		for index in range(len(self.handlers)-1, -1, -1):
			if self.handlers[index].module.__name__ in module_list:
				self.handlers.pop(index)
		# sort the list (for priorities)
		for module in module_list:
			if module in self.module_list:
				self.module_list.remove(module)
		self.handlers.sort()
Beispiel #9
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
Beispiel #10
0
 def _on_disconnect(self, c, e):
     """[Internal]"""
     self.channels = IRCDict()
     self.connection.execute_delayed(self.reconInterval,
                                     self._connected_checker)