예제 #1
0
 def __init__(self):
     self.userdict = IRCDict()
     self.operdict = IRCDict()
     self.voiceddict = IRCDict()
     self.ownerdict = IRCDict()
     self.halfopdict = IRCDict()
     self.modes = {}
예제 #2
0
    def __init__(
            self, server_list, nickname, realname,
            reconnection_interval=missing,
            recon=ExponentialBackoff(), **connect_params):
        super(SingleServerIRCBot, self).__init__()
        self.__connect_params = connect_params
        self.channels = IRCDict()
        self.server_list = [
            ServerSpec(*server)
            if isinstance(server, (tuple, list))
            else server
            for server in server_list
        ]
        assert all(
            isinstance(server, ServerSpec)
            for server in self.server_list
        )
        self.recon = recon
        # for compatibility
        if reconnection_interval is not missing:
            warnings.warn(
                "reconnection_interval is deprecated; "
                "pass a ReconnectStrategy object instead")
            self.recon = ExponentialBackoff(min_interval=reconnection_interval)

        self._nickname = nickname
        self._realname = realname
        for i in ["disconnect", "join", "kick", "mode",
                  "namreply", "nick", "part", "quit"]:
            self.connection.add_global_handler(
                i, getattr(self, "_on_" + i),
                -20)
예제 #3
0
 def __init__(self, logchannel=None, **kwargs):
   """Uses PanHandler automatically."""
   IRCClient.__init__(self, PanHandler, **kwargs)
   print "Successfully created", self
   self.channels = IRCDict()
   self.db = MongoClient(document_class=SON).mzpn
   self.logchan = logchannel
예제 #4
0
파일: ircclient.py 프로젝트: yerejm/ttt
    def __init__(self, channel, nickname, server, port=6667, **connect_params):
        super(IRCClient, self).__init__()
        if server is None:
            raise Exception("IRC Server not provided")
        if nickname is None or " " in nickname:
            raise Exception("Invalid nickname: must be one word")
        if channel is None or " " in channel or "#" not in channel:
            raise Exception("Invalid channel: must be a word starting with #")
        self.__connect_params = connect_params
        self.channels = IRCDict()
        self.channel = channel
        self.server = ServerSpec(server, port)
        self._nickname = nickname
        self.clientname = socket.gethostname().split(".")[0]
        if 0 <= self.min_reconnect_wait:
            raise Exception("Minimum reconnect wait must be positive number")
        if self.min_reconnect_wait <= self.max_reconnect_wait:
            raise Exception(
                "Maximum reconnect wait must be larger than minimum")
        self._check_scheduled = False

        # Global handlers to handle channel/nick associations
        # Mostly when a nick is already in use
        for i in [
                "disconnect",
                "join",
                "kick",
                "mode",
                "namreply",
                "nick",
                "part",
                "quit",
        ]:
            self.connection.add_global_handler(i, getattr(self, "_on_" + i),
                                               -20)
예제 #5
0
 def __init__(self, namreply=None):
   Channel.__init__(self)
   self.admindict = IRCDict()
   self.logdict = IRCDict()
   if namreply:
     for nick in namreply.split(' '):
       if nick[0] == '~': self.ownerdict[nick[1:]] = 1
       elif nick[0] == '&': self.admindict[nick[1:]] = 1
       elif nick[0] == '@': self.operdict[nick[1:]] = 1
       elif nick[0] =='%': self.halfopdict[nick[1:]] = 1
       elif nick[0] == '+': self.voicedict[nick[1:]] = 1
       else: 
         self.userdict[nick] = 1
         self.logdict[nick] = tempfile.NamedTemporaryFile(bufsize=5120)
         continue
       self.userdict[nick[1:]] = 1
       self.logdict[nick[1:]] = tempfile.NamedTemporaryFile(bufsize=5120)
예제 #6
0
    def __init__(self,
                 server_list,
                 nickname,
                 realname,
                 reconnection_interval=60,
                 **connect_params):
        """Constructor for SingleServerIRCBot objects.

        Arguments:

            server_list -- A list of ServerSpec objects or tuples of
                           parameters suitable for constructing ServerSpec
                           objects. Defines the list of servers the bot will
                           use (in order).

            nickname -- The bot's nickname.

            realname -- The bot's realname.

            reconnection_interval -- How long the bot should wait
                                     before trying to reconnect.

            dcc_connections -- A list of initiated/accepted DCC
            connections.

            **connect_params -- parameters to pass through to the connect
                                method.
        """

        super(SingleServerIRCBot, self).__init__()
        self.__connect_params = connect_params
        self.channels = IRCDict()
        self.server_list = [
            ServerSpec(*server) if isinstance(server,
                                              (tuple, list)) else server
            for server in server_list
        ]
        assert all(
            isinstance(server, ServerSpec) for server in self.server_list)
        if not reconnection_interval or reconnection_interval < 0:
            reconnection_interval = 2**31
        self.reconnection_interval = reconnection_interval

        self._nickname = nickname
        self._realname = realname
        for i in [
                "disconnect", "join", "kick", "mode", "namreply", "nick",
                "part", "quit"
        ]:
            self.connection.add_global_handler(i, getattr(self, "_on_" + i),
                                               -20)
예제 #7
0
    def __init__(self,
                 server_list,
                 channel_list,
                 nickname,
                 reconnection_interval=5,
                 **connect_params):
        """Constructor for IRCChatBot objects.

        Arguments:

            server_list -- A list of ServerSpec objects or tuples of
                           parameters suitable for constructing ServerSpec
                           objects. Defines the list of servers the bot will
                           use (in order).

            channel_list -- A list of channel names to join

            nickname -- The bot's nickname.

            reconnection_interval -- How long the bot should wait
                                     before trying to reconnect.

            **connect_params -- parameters to pass through to the connect
                                method.
        """

        super(IRCChatBot, self).__init__()
        self.connection.set_rate_limit(0.5)

        self.nickname = nickname
        self.__connect_params = connect_params

        self.channels = IRCDict()
        self.channel_list = channel_list

        self.server_list = [
            ServerSpec(*server) if isinstance(server,
                                              (tuple, list)) else server
            for server in server_list
        ]
        assert all(
            isinstance(server, ServerSpec) for server in self.server_list)

        if not reconnection_interval or reconnection_interval < 0:
            reconnection_interval = 2**31
        self.reconnection_interval = reconnection_interval
예제 #8
0
 def __init__(self):
     self._users = IRCDict()
     self.mode_users = collections.defaultdict(IRCDict)
     self.modes = {}
예제 #9
0
 def _on_disconnect(self, c, e):
     self.channels = IRCDict()
     self.recon.run(self)
예제 #10
0
파일: irc.py 프로젝트: danhetrick/qbit
    def __init__(self,
                 gui,
                 server,
                 port,
                 nickname,
                 password=None,
                 username=None,
                 ircname=None,
                 ssl=False):
        QThread.__init__(self)
        self.gui = gui
        self.server = server
        self.port = port
        self.nickname = nickname
        self.password = password
        self.username = username
        self.ircname = ircname
        self.ssl = ssl

        self.irc = None

        self.channels = IRCDict()

        self.cusers = defaultdict(list)

        self.blink_pubmsg = signal("pubmsg")
        self.blink_privmsg = signal("privmsg")
        self.blink_chanjoin = signal("join")
        self.blink_chanpart = signal("part")
        self.blink_registered = signal("registered")
        self.blink_gotnames = signal("names")
        self.blink_gotmotd = signal("motd")
        self.blink_nameend = signal("endnames")
        self.blink_mynick = signal("mynick")
        self.blink_gotmode = signal("mode")
        self.blink_gotumode = signal("umode")
        self.blink_gotnick = signal("newnick")
        self.blink_gotquit = signal("quit")
        self.blink_gotact = signal("action")
        self.blink_joinerror = signal("joinerror")
        self.blink_chanerror = signal("chanerror")
        self.blink_miscerror = signal("miscerror")
        self.blink_notice = signal("notice")
        self.blink_nicklength = signal("nicklen")
        self.blink_network = signal("network")
        self.blink_disconnected = signal("disconnected")
        self.blink_currenttopic = signal("currenttopic")
        self.blink_topicsetter = signal("topicsetter")
        self.blink_topic = signal("topic")

        self.blink_pubmsg.connect(self.pubchat)
        self.blink_privmsg.connect(self.privchat)
        self.blink_chanjoin.connect(self.join_channel)
        self.blink_chanpart.connect(self.part_channel)
        self.blink_registered.connect(self.welcome)
        self.blink_gotnames.connect(self.channel_users)
        self.blink_gotmotd.connect(self.motd)
        self.blink_nameend.connect(self.endnames)
        self.blink_mynick.connect(self.my_nick)
        self.blink_gotmode.connect(self.got_mode)
        self.blink_gotumode.connect(self.got_umode)
        self.blink_gotnick.connect(self.got_nick)
        self.blink_gotquit.connect(self.got_quit)
        self.blink_gotact.connect(self.got_action)
        self.blink_joinerror.connect(self.join_error)
        self.blink_chanerror.connect(self.chan_error)
        self.blink_miscerror.connect(self.misc_error)
        self.blink_notice.connect(self.got_notice)
        self.blink_nicklength.connect(self.got_nicklength)
        self.blink_network.connect(self.got_network)
        self.blink_disconnected.connect(self.got_disco)
        self.blink_currenttopic.connect(self.got_ctopic)
        self.blink_topicsetter.connect(self.got_stopic)
        self.blink_topic.connect(self.got_topic)
예제 #11
0
 def on_disconnect(self, c, e):
     self.channels = IRCDict()
     self.reactor.scheduler.execute_after(self.reconnection_interval,
                                          self._connected_checker)
예제 #12
0
class DixieBot(irc.bot.SingleServerIRCBot):

    # Class-level variables which form attributes.  These all refer to aspects
    # of the bot.
    joined_channels = IRCDict()
    canonical_name = ""
    nick = ""
    owner = ""

    # Connection information.
    server = ""
    port = 0

    # The bot's owner's authentication password.
    password = ""

    # Is the bot's owner authenticated or not?
    authenticated = ""

    # Whether or not the connection is SSL/TLS encrypted or not.
    usessl = ""

    # Response engine's hostname and port.
    engine = ""

    # Bot's API key to interface with the response engine.
    api_key = ""

    # One instance of wordfilter.Wordfilter() to rule them all...
    wordfilter = None

    # Whether or not to use the conversation engine to respond?
    respond = None

    # Whether or not the bot's owner can speak through the bot by using
    # private messages.  By default, the bot doesn't let you do that.
    ghost = None

    # Methods on the connection object to investigate:
    # connect() - Connect to a server?
    # connected() -
    # disconnect() -
    # get_nickname() -
    # get_server_name() -
    # info() -
    # ircname() -
    # is_connected() - See if the connection is still up?
    # part() - Leave channel?
    # privmsg() - Send privmsg?
    # quit() - Terminate IRC connection?
    # reconnect() - Reconnect to server?
    # send_raw() -
    # stats() -
    # time() -

    def __init__(self, channels, nickname, server, port, owner, usessl,
                 password, engine_host, engine_port, api_key, respond):

        # Initialize the class' attributes.
        for i in channels:
            self.joined_channels[i] = 1
        self.canonical_name = nick
        self.nick = nick
        self.owner = owner
        self.server = server
        self.port = port
        self.password = password
        self.authenticated = False
        self.usessl = usessl
        self.engine = 'http://' + engine_host + ':' + engine_port
        self.api_key = api_key
        self.wordfilter = Wordfilter()
        self.respond = respond
        self.ghost = False

        # Connection factory object handle.
        factory = ""

        # If SSL/TLS support is requested, pass the ssl.wrap_socket() method
        # as a keyword argument.
        if self.usessl:
            logger.debug("Constructing SSL/TLS server connector.")
            factory = irc.connection.Factory(wrapper=ssl.wrap_socket)
        else:
            logger.debug("Constructing plaintext server connector.")
            factory = irc.connection.Factory()

        # Initialize an instance of this class by running the parent class'
        # default initializer method.
        #
        # [(server, port)] can be a list of one or more (server, port) tuples
        # because it can connect to more than one at once.
        # The other two arguments are the bot's nickname and realname.
        logger.debug("Instantiating SingleServerIRCBot superclass.")
        irc.bot.SingleServerIRCBot.__init__(self, [(self.server, self.port)],
                                            self.nick,
                                            self.nick,
                                            connect_factory=factory)
        logger.debug("Channels configured for this bot:")
        logger.debug("  " + str(self.joined_channels))

    # This method fires if the configured nickname is already in use.  If that
    # happens, change the bot's nick slightly.
    # Note that the name of this method is specifically what the irc module
    # looks for.
    def on_nicknameinuse(self, connection, event):
        logger.info("Bot nickname " + self.nick +
                    " is already taken.  Falling back to bot nickname " +
                    self.nick + "_.")
        connection.privmsg(
            self.owner, self.nick +
            " seems to be taken already.  Falling back to nickname " +
            self.nick + "_.")
        connection.nick(connection.get_nickname() + "_")

    # This method fires when the server accepts the bot's connection.  It walks
    # through the IRCDict of channels and tries to join each one.
    def on_welcome(self, connection, event):
        logger.debug("Entered DixieBot.on_welcome().")
        for channel in self.joined_channels:
            logger.debug("Trying to join channel " + channel + ".")
            connection.join(channel)
            logger.info("Joined channel " + channel + ".")
            connection.privmsg(self.owner, "Joined " + channel + ".")

            # Just to be silly, roll 1d10.  On a 1, say hello to the channel.
            roll = random.randint(1, 10)
            if roll == 1:
                pause = random.randint(1, 10)
                time.sleep(pause)
                logger.debug("Bot has randomly decided to announce itself.")
                connection.privmsg(
                    channel, "Hey, bro!  I'm " + self.nick +
                    ", the best cowboy who ever punched deck!")
        logger.debug("Exiting DixieBot.on_welcome().")

    # This method fires if the bot gets kicked from a channel.  The smart
    # thing to do is sleep for a random period of time (between one and three
    # minutes) before trying to join again.
    def on_kick(self, connection, event):
        delay = random.randint(60, 180)
        logger.debug("Got kicked from " + event.target + ".  Sleeping for " +
                     str(delay) + " seconds.")
        connection.privmsg(
            self.owner, "Got kicked from " + event.target +
            ".  Sleeping for " + str(delay) + " seconds.")
        time.sleep(delay)
        logger.debug("Rejoining channel " + event.target + ".")
        connection.privmsg(self.owner,
                           "Rejoining channel " + event.target + ".")
        connection.join(event.target)
        logger.info("Successfully re-joined channel " + event.target + ".")
        connection.privmsg(
            self.owner, "Successfully re-joined channel " + event.target + ".")
        return

    # This method fires if the bot gets kickbanned.
    def on_bannedfromchan(self, connection, event):
        logger.warn("Uh-oh - I got kickbanned from " + event.target +
                    ".  I know when I'm not wanted.")
        self.privmsg(
            self.owner, "Uh-oh - I got kickbanned from " + event.target +
            ".  I know when I'm not wanted.")
        self.joined_channels.remove(event.target)
        return

    # This method fires when the server disconnects the bot for some reason.
    # Ideally, the bot should try to connect again after a random number of
    # seconds.
    def on_disconnect(self, connection, event):
        delay = random.randint(60, 180)
        logger.warn("Connection dropped from server " + self.server +
                    ".  Sleeping for " + str(delay) + " seconds.")
        time.sleep(delay)
        logger.warn("Reconnecting to server " + self.server + " on port " +
                    str(self.port) + ".")
        try:
            irc.bot.SingleServerIRCBot.connect(self,
                                               [(self.server, self.port)],
                                               self.nick, self.nick)
            logger.info("Successfully reconnected to server " + self.server +
                        ".")
        except:
            logger.warn("Unable to reconnect to " + self.server +
                        ".  Something's really wrong.")

    # This method fires when the bot receives a private message.  For the
    # moment, if it's the bot's owner always learn from the text because this
    # is an ideal way to get more interesting stuff into the bot's brain.
    # It'll make a good place to look for and respond to specific commands,
    # too.
    def on_privmsg(self, connection, line):

        # IRC nick that sent a line to the bot in private chat.
        sending_nick = line.source.split("!~")[0]

        # Line of text sent from the channel or private message.
        irc_text = line.arguments[0]

        # String that holds what may or may not be a channel name.
        possible_channel_name = None

        # String that may or may not hold a respond to a channel in ghost mode.
        irc_response = None

        # Handle to an HTTP request object.
        http_connection = ""

        # JSON document containing responses from the conversation engine.
        json_response = {}

        # See if the owner is authenticating to the bot.
        if "!auth " in irc_text:
            self._authenticate(connection, sending_nick, irc_text)
            return

        # Handle messages from the bot's owner (if authenticated).
        if sending_nick == self.owner:
            if not self.authenticated:
                connection.privmsg(sending_nick, "You're not authenticated.")
                return

            # If the owner asks for online help, provide it.
            if irc_text == "!help" or irc_text == "!commands":
                self._help(connection, sending_nick)
                return

            # See if the owner is asking the bot to self-terminate.
            if irc_text == "!quit":
                logger.info("The bot's owner has told it to shut down.")
                connection.privmsg(sending_nick,
                                   "I get the hint.  Shuttin' down.")
                sys.exit(0)

            # See if the owner is asking for the bot's current configuration.
            if irc_text == "!config":
                self._current_config(connection, sending_nick)
                return

            # See if the owner is asking the bot to ping the conversation
            # engine's server.
            if irc_text == "!ping":
                self._ping(connection, sending_nick)
                return

            # See if the owner is asking the bot to change its nick.
            if "!nick" in irc_text:
                self._nick(connection, irc_text, sending_nick)
                return

            # See if the owner is asking the bot to join a channel.
            if "!join " in irc_text:
                self._join(connection, irc_text, sending_nick)
                return

            # See if the owner is flipping the self.respond flag.
            if "!respond" in irc_text:
                self._respond(connection, irc_text, sending_nick)
                return

            # See if the owner is asking for help on ghost mode.
            if "!ghosthelp" in irc_text:
                self._ghost_help(connection, sending_nick)
                return

            # See if the owner is flipping the self.ghost flag.
            if "!ghost" in irc_text:
                self._ghost_mode(connection, sending_nick)
                return

            # If the bot's in ghost mode, determine whether or not the bot's
            # owner has sent text destined for a channel the bot's sitting in.
            # If this is the case, send the channel the text sent by the
            # bot's owner.
            possible_channel_name = irc_text.split()[0]
            logger.debug("Value of possible_channel_name: " +
                         possible_channel_name)
            if self.ghost:
                if "#" in possible_channel_name:

                    # Test to see if the bot is in the channel in question.
                    in_channel = False
                    for channel in self.joined_channels:
                        if channel == possible_channel_name:
                            in_channel = True
                            break
                    if not in_channel:
                        logger.debug("Not in channel " +
                                     possible_channel_name + ".")
                        connection.privmsg(
                            sending_nick, "I'm not in channel " +
                            possible_channel_name + ".")
                        return
                    logger.debug("In channel " + possible_channel_name + ".")

                    # Send the text to the channel.
                    irc_response = " ".join(irc_text.split()[1:])
                    logger.debug("Value of irc_response: " + irc_response)
                    connection.privmsg(possible_channel_name, irc_response)

            # Always learn from private messages from the bot's owner.  Do not
            # respond to them if the bot's in ghost mode.  Determine whether
            # or not a #channelname is at the head of the text and if so
            # elide it by setting the line of text from the IRC channel to
            # the IRC response which already has the #channelname removed.
            if "#" in possible_channel_name:
                irc_text = " ".join(irc_text.split()[1:])
                logger.debug(
                    "Got a possible channel name.  Set value of irc_text to: "
                    + str(irc_text))

            # Train the bot on text sent by the bot's owner.
            json_response = json.loads(self._teach_brain(irc_text))
            if json_response['id'] != 200:
                logger.warn(
                    "DixieBot.on_privmsg(): Conversation engine returned error code "
                    + str(json_response['id']) + ".")

            # Don't get responses when in ghost mode.
            if self.ghost:
                return

            # Get a response for text sent by the bot's owner.
            json_response = json.loads(self._get_response(irc_text))
            if json_response['id'] != 200:
                logger.warn(
                    "DixieBot.on_privmsg(): Conversation engine returned error code "
                    + str(json_response['id']) + ".")
                return

            # Send the response text back to the bot's owner.
            connection.privmsg(sending_nick, json_response['response'])
            return
        else:
            logger.debug(
                "Somebody messaged me.  The content of the message was: " +
                irc_text)

    # Helper method for authenticating the bot's owner.
    def _authenticate(self, connection, nick, text):
        logger.warn("IRC user " + nick +
                    " is attempting to authenticate to the bot.")
        if self.password in text:
            connection.privmsg(nick,
                               "Authentication confirmed.  Welcome back.")
            self.owner = nick
            self.authenticated = True
            return
        else:
            connection.privmsg(nick, "Incorrect.")
            return

    # Helper method that implements online help.
    def _help(self, connection, nick):
        connection.privmsg(nick, "Here are the commands I support:")
        connection.privmsg(
            nick, "!help and !commands - You're reading them right now.")
        connection.privmsg(nick, "!quit - Shut me down.")
        connection.privmsg(
            nick, "!auth - Authenticate your current IRC nick as my admin.")
        connection.privmsg(nick, "!config - Send my current configuration.")
        connection.privmsg(
            nick,
            "!ping - Ping the conversation engine to make sure I can contact it."
        )
        connection.privmsg(nick,
                           "!nick <new nick> - Try to change my IRC nick.")
        connection.privmsg(nick, "!join <channel> - Join a channel.")
        connection.privmsg(
            nick, "!respond - Toggle respond/don't respond to users flag.")
        connection.privmsg(nick,
                           "!ghosthelp - Get online help for ghost mode.")
        connection.privmsg(
            nick,
            "!ghost - Whether or not the bot's registered owner can remotely interact with a channel the bot's a member of using the bot as a client."
        )
        return

    # Helper method that tells the bot's owner what the bot's current runtime
    # configuration is.
    def _current_config(self, connection, nick):
        connection.privmsg(nick, "Here's my current runtime configuration.")
        connection.privmsg(nick, "Channels I'm connected to: ")
        for channel in self.joined_channels:
            connection.privmsg(nick, "  " + channel)
        connection.privmsg(nick, "Current nick: " + self.nick)
        connection.privmsg(
            nick,
            "Canonical name (for interacting with the conversation engine): " +
            self.canonical_name)
        connection.privmsg(
            nick,
            "Server and port: " + self.server + " " + str(self.port) + "/tcp")
        if self.usessl:
            connection.privmsg(nick,
                               "My connection to the server is encrypted.")
        else:
            connection.privmsg(nick,
                               "My connection to the server isn't encrypted.")
        if self.respond:
            connection.privmsg(nick, "I respond to people talking to me.")
        else:
            connection.privmsg(nick,
                               "I don't respond to people talking to me.")
        if self.ghost:
            connection.privmsg(nick,
                               "I am monitoring IRC channels in ghost mode.")
        else:
            connection.privmsg(nick, "I am not in ghost mode.")
        return

    # Helper method that pings the bot's conversation engine.  I realize that
    # doing this is probably a little weird, but seeing as how I'm splitting
    # everything else out into helper methods to make adding functionality
    # later on easier I may as well.
    def _ping(self, connection, nick):
        connection.privmsg(nick, "Pinging the conversation engine...")
        http_connection = requests.get(self.engine + "/ping")
        if http_connection.text == "pong":
            connection.privmsg(nick, "I can hit the conversation engine.")
        else:
            connection.privmsg(
                nick,
                "I don't seem to be able to reach the conversation engine.")
        return

    # Helper method that will allow the bot to change its nick.
    def _nick(self, connection, text, nick):
        connection.privmsg(nick, "Trying to change my IRC nick...")
        self.nick = text.split()[1].strip()
        connection.nick(self.nick)
        logger.debug("New IRC nick: " + self.nick)
        connection.privmsg(nick, "Done.")
        return

    # Helper method that will allow the bot to join a channel.
    def _join(self, connection, text, nick):
        new_channel = text.split()[1].strip()
        connection.privmsg(nick, "Trying to join channel " + new_channel + ".")
        logger.debug("Trying to join channel " + new_channel + ".")
        connection.join(new_channel)
        self.joined_channels[new_channel] = 1
        connection.privmsg(nick, "Joined " + new_channel + ".")
        return

    # Helper method that flips the bot's mode from "respond when spoken to" to
    # don't respond when spoken to.
    def _respond(self, connection, text, nick):
        if self.respond == True:
            self.respond = False
            logger.info("Turn off the bot's auto-response mode.")
            connection.privmsg(nick,
                               "I won't respond to people talking to me.")
            return
        if self.respond == False:
            self.respond = True
            logger.info("Turn on the bot's auto-response mode.")
            connection.privmsg(nick, "Now responding to people talking to me.")
            return

    # Send the user online help for ghost mode.
    def _ghost_help(self, connection, nick):
        connection.privmsg(
            nick,
            "Ghost mode lets you interact with any channel I'm sitting in remotely so you don't have to join it."
        )
        connection.privmsg(
            nick,
            "This is ideal if you want to maintain a certain degree of stealth."
        )
        connection.privmsg(
            nick,
            "I can join the channel from one server and interact with everyone like a bot, and you can connect from another server without joining any channels, !auth to me, and communicate through me."
        )
        connection.privmsg(
            nick,
            "If I get rumbled, I get bounced and your disposable server can be banned, and all you have to do is get a copy of my conversation engine to preserve me.  You should be okay."
        )
        connection.privmsg(
            nick,
            "Please note that if you have me join a number of busy channels you may not be able to keep up with all the traffic, so choose the channels I join wisely.  Keep the number small for best results."
        )
        connection.privmsg(
            nick,
            "Put the name of the channel you want me to send text to at the front of a private message, like this:"
        )
        connection.privmsg(nick, "/msg botname")
        connection.privmsg(nick, "#somechannel Hello, world.")
        connection.privmsg(
            nick,
            "I will send activity in the channel back to you via the same privmsg as long as you're authenticated."
        )
        return

    # Flips the ghost mode flag.
    def _ghost_mode(self, connection, nick):
        if self.ghost == False:
            self.ghost = True
            logger.info("Ghost mode now activated.")
            connection.privmsg(nick, "Ghost mode activated.")
            connection.privmsg(
                nick,
                "You can now interact with the following channels through me: "
            )
            for channel in self.joined_channels:
                connection.privmsg(nick, "  " + channel)
            return
        if self.ghost == True:
            self.ghost = False
            logger.info("Ghost mode now deactivated.")
            connection.privmsg(nick, "Ghost mode deactivated.")
            return

    # This method fires every time a public message is posted to an IRC
    # channel.  Technically, 'line' should be 'event' but I'm just now getting
    # this module figured out...
    def on_pubmsg(self, connection, line):
        # JSON document from the conversation engine.
        json_response = {}

        # IRC nick that sent a line to the channel.
        sending_nick = line.source.split("!~")[0]
        logger.debug("Sending nick: " + sending_nick)

        # Line of text sent from the channel.
        irc_text = line.arguments[0]

        # If the line is from the bot's owner, learn from it and then decide
        # whether to respond or not.  Just in case somebody grabs the nick of
        # the bot's owner, don't respond if they're not authenticated (because
        # that could go real bad, real fast...)
        if sending_nick == self.owner and self.authenticated:

            # If the bot's owner addressed it directly, always respond.  Just
            # make sure to remove the bot's nick from the text to minimize
            # spurious entries in the bot's brain.
            asked_directly = irc_text.split(':')[0].strip()
            if asked_directly == self.nick:
                logger.debug(
                    "The bot's owner addressed the construct directly.  This is a special case."
                )

                # Extract the dialogue from the text in the IRC channel.
                dialogue_text = irc_text.split(':')[1].strip()

                # Send a request to train the conversation engine on the text.
                logger.debug("Training engine on text: " + dialogue_text)
                json_response = json.loads(self._teach_brain(dialogue_text))
                if json_response['id'] != int(200):
                    logger.warn(
                        "DixieBot.on_pubmsg(): Conversation engine returned error code "
                        + str(json_response['id']) + ".")
                    return

                # If the bot is in ghost mode, do not respond.
                if self.ghost:
                    return

                # Get a response to the text from the channel.
                json_response = json.loads(self._get_response(irc_text))
                if json_response['id'] != int(200):
                    logger.warn(
                        "DixieBot.on_pubmsg(): Conversation engine returned error code "
                        + str(json_response['id']) + ".")
                    return

                # Send the reply to the channel.
                connection.privmsg(line.target, json_response['response'])
                return

            # Otherwise, just learn from the bot's owner.
            json_response = json.loads(self._teach_brain(irc_text))
            if json_response['id'] != int(200):
                logger.warn(
                    "DixieBot.on_pubmsg(): Conversation engine returned error code "
                    + str(json_response['id']) + ".")
                return

            # Check the respond/don't respond flag.  If it's set to False,
            # don't say anything.
            if not self.respond:
                return

            # If the respond/don't respond flag it set to True, decide if the
            # bot is going to respond or not.  To be polite to people, only
            # respond 5% of the time.  10% was too much.
            roll = random.randint(1, 100)
            if roll <= 5:
                json_response = json.loads(self._get_response(irc_text))
                if json_response['id'] != int(200):
                    logger.warn(
                        "DixieBot.on_pubmsg(): Conversation engine returned error code "
                        + str(json_response['id']) + ".")
                    return

                # connection.privmsg() can be used to send text to either a
                # channel or a user.
                # Send the response.
                connection.privmsg(line.target, json_response['response'])
            return

        # If the line is not from the bot's owner, and the bot is in ghost
        # mode, relay the line to the bot's owner via privmsg.
        if self.ghost and self.authenticated:
            logger.debug("Relaying a line of text from " + line.target +
                         " to the bot's owner.")
            connection.privmsg(self.owner, line.target + ":: " + irc_text)

        # If the line is not from the bot's owner, decide randomly if the bot
        # should learn from it, or learn from and respond to it.  Respect the
        # respond/don't respond flag.
        roll = random.randint(1, 10)
        if roll == 1:
            logger.debug("Learning from the last line seen in the channel.")
            if self.wordfilter.blacklisted(irc_text):
                logger.warn("Wordfilter: Nope nope nope...")
                return
            json_response = json.loads(self._teach_brain(irc_text))
            if json_response['id'] != int(200):
                logger.warn(
                    "DixieBot.on_pubmsg(): Conversation engine returned error code "
                    + str(json_response['id']) + ".")
            return

        if roll == 2:
            logger.debug(
                "Learning from the last line seen in the channel.  I might respond to it."
            )
            if self.wordfilter.blacklisted(irc_text):
                logger.warn("Wordfilter: Nope nope nope...")
                return
            json_response = json.loads(self._teach_brain(irc_text))
            if json_response['id'] != int(200):
                logger.warn(
                    "DixieBot.on_pubmsg(): Conversation engine returned error code "
                    + str(json_response['id']) + ".")
                return

            # Check the respond/don't respond flag.  If it's set to False,
            # don't say anything.
            if not self.respond:
                return

            # Get and send a response.
            json_response = json.loads(self._get_response(irc_text))
            if json_response['id'] != int(200):
                logger.warn(
                    "DixieBot.on_pubmsg(): Conversation engine returned error code "
                    + str(json_response['id']) + ".")
                return
            connection.privmsg(line.target, json_response['response'])
            return

    # This method should fire when a client in the current channel emits a QUIT
    # event relayed by the server.  It detects the bot's owner disconnecting
    # and deauthenticates them.
    def on_quit(self, connection, event):
        sending_nick = event.source.split("!~")[0]
        if event.type == "quit" and sending_nick == self.owner and self.authenticated:
            logger.info("The bot's owner has disconnected.  Deauthenticating.")
            self.authenticated = False
            connection.privmsg(line.target, "Seeya, boss.")
            return

    # Sends text to train the conversation engine on.
    def _teach_brain(self, text):

        # Custom headers required by the conversation engine.
        headers = {"Content-Type": "application/json"}

        # HTTP request object handle.
        http_request = ""

        # JSON documents sent to and received from the conversation engine.
        json_request = {}
        json_request['botname'] = self.canonical_name
        json_request['apikey'] = self.api_key
        json_request['stimulus'] = text
        json_response = {}

        # Make an HTTP request to the conversation engine.
        http_request = requests.put(self.engine + "/learn",
                                    headers=headers,
                                    data=json.dumps(json_request))
        json_response = json.loads(http_request.content)
        return json_response

    # Gets a response from the conversation engine.  Return a response.
    def _get_response(self, text):

        # Custom headers required by the conversation engine.
        headers = {"Content-Type": "application/json"}

        # HTTP request object handle.
        http_request = ""

        # Response to send to the channel or user.
        response = ""

        # JSON documents sent to and received from the conversation engine.
        json_request = {}
        json_request['botname'] = self.canonical_name
        json_request['apikey'] = self.api_key
        json_request['stimulus'] = text
        json_response = {}

        # Contact the conversation engine to get a response.
        http_request = requests.get(self.engine + "/response",
                                    headers=headers,
                                    data=json.dumps(json_request))
        json_response = json.loads(http_request.content)
        return json_response
예제 #13
0
 def _on_disconnect(self, c, e):
     self.channels = IRCDict()
     self.connection.execute_delayed(self.reconnection_interval,
                                     self._connected_checker)