Beispiel #1
0
class PesterIRC(QtCore.QThread):
    def __init__(self, config, window):
        QtCore.QThread.__init__(self)
        self.mainwindow = window
        self.config = config
        self.registeredIRC = False
        self.stopIRC = None
        self.NickServ = services.NickServ()
        self.ChanServ = services.ChanServ()
    def IRCConnect(self):
        server = self.config.server()
        port = self.config.port()
        self.cli = IRCClient(PesterHandler, host=server, port=int(port), nick=self.mainwindow.profile().handle, real_name='pcc31', blocking=True, timeout=120)
        self.cli.command_handler.parent = self
        self.cli.command_handler.mainwindow = self.mainwindow
        self.cli.connect()
        self.conn = self.cli.conn()
    def run(self):
        try:
            self.IRCConnect()
        except socket.error as se:
            self.stopIRC = se
            return
        while 1:
            res = True
            try:
                logging.debug("updateIRC()")
                res = self.updateIRC()
            except socket.timeout as se:
                logging.debug("timeout in thread %s" % (self))
                self.cli.close()
                self.stopIRC = se
                return
            except socket.error as se:
                if self.registeredIRC:
                    self.stopIRC = None
                else:
                    self.stopIRC = se
                logging.debug("socket error, exiting thread")
                return
            else:
                if not res:
                    logging.debug("false Yield: %s, returning" % res)
                    return

    def setConnected(self):
        self.registeredIRC = True
        self.connected.emit()
    def setConnectionBroken(self):
        logging.debug("setconnection broken")
        self.reconnectIRC()
        #self.brokenConnection = True
    @QtCore.pyqtSlot()
    def updateIRC(self):
        try:
            res = next(self.conn)
        except socket.timeout as se:
            if self.registeredIRC:
                return True
            else:
                raise se
        except socket.error as se:
            raise se
        except StopIteration:
            self.conn = self.cli.conn()
            return True
        else:
            return res
    @QtCore.pyqtSlot()
    def reconnectIRC(self):
        logging.debug("reconnectIRC() from thread %s" % (self))
        self.cli.close()

    @QtCore.pyqtSlot(PesterProfile)
    def getMood(self, *chums):
        self.cli.command_handler.getMood(*chums)
    @QtCore.pyqtSlot(PesterList)
    def getMoods(self, chums):
        self.cli.command_handler.getMood(*chums)
    @QtCore.pyqtSlot(QString, QString)
    def sendNotice(self, text, handle):
        h = str(handle)
        t = str(text)
        try:
            helpers.notice(self.cli, h, t)
        except socket.error:
            self.setConnectionBroken()
    @QtCore.pyqtSlot(QString, QString)
    def sendMessage(self, text, handle):
        h = str(handle)
        textl = [str(text)]
        def splittext(l):
            if len(l[0]) > 450:
                space = l[0].rfind(" ", 0,430)
                if space == -1:
                    space = 450
                elif l[0][space+1:space+5] == "</c>":
                    space = space+4
                a = l[0][0:space+1]
                b = l[0][space+1:]
                if a.count("<c") > a.count("</c>"):
                    # oh god ctags will break!! D=
                    hanging = []
                    usedends = []
                    c = a.rfind("<c")
                    while c != -1:
                        d = a.find("</c>", c)
                        while d in usedends:
                            d = a.find("</c>", d+1)
                        if d != -1: usedends.append(d)
                        else:
                            f = a.find(">", c)+1
                            hanging.append(a[c:f])
                        c = a.rfind("<c",0,c)

                    # end all ctags in first part
                    for i in range(a.count("<c")-a.count("</c>")):
                        a = a + "</c>"
                    #start them up again in the second part
                    for c in hanging:
                        b = c + b
                if len(b) > 0:
                    return [a] + splittext([b])
                else:
                    return [a]
            else:
                return l
        textl = splittext(textl)
        try:
            for t in textl:
                helpers.msg(self.cli, h, t)
        except socket.error:
            self.setConnectionBroken()
    @QtCore.pyqtSlot(QString, bool)
    def startConvo(self, handle, initiated):
        h = str(handle)
        try:
            helpers.msg(self.cli, h, "COLOR >%s" % (self.mainwindow.profile().colorcmd()))
            if initiated:
                helpers.msg(self.cli, h, "PESTERCHUM:BEGIN")
        except socket.error:
            self.setConnectionBroken()
    @QtCore.pyqtSlot(QString)
    def endConvo(self, handle):
        h = str(handle)
        try:
            helpers.msg(self.cli, h, "PESTERCHUM:CEASE")
        except socket.error:
            self.setConnectionBroken()
    @QtCore.pyqtSlot()
    def updateProfile(self):
        me = self.mainwindow.profile()
        handle = me.handle
        try:
            helpers.nick(self.cli, handle)
        except socket.error:
            self.setConnectionBroken()
        self.mainwindow.closeConversations(True)
        self.mainwindow.doAutoIdentify()
        self.mainwindow.autoJoinDone = False
        self.mainwindow.doAutoJoins()
        self.updateMood()
    @QtCore.pyqtSlot()
    def updateMood(self):
        me = self.mainwindow.profile()
        try:
            helpers.msg(self.cli, "#pesterchum", "MOOD >%d" % (me.mood.value()))
        except socket.error:
            self.setConnectionBroken()
    @QtCore.pyqtSlot()
    def updateColor(self):
        #logging.debug("irc updateColor (outgoing)")
        me = self.mainwindow.profile()
        for h in list(self.mainwindow.convos.keys()):
            try:
                helpers.msg(self.cli, h, "COLOR >%s" % (self.mainwindow.profile().colorcmd()))
            except socket.error:
                self.setConnectionBroken()
    @QtCore.pyqtSlot(QString)
    def blockedChum(self, handle):
        h = str(handle)
        try:
            helpers.msg(self.cli, h, "PESTERCHUM:BLOCK")
        except socket.error:
            self.setConnectionBroken()
    @QtCore.pyqtSlot(QString)
    def unblockedChum(self, handle):
        h = str(handle)
        try:
            helpers.msg(self.cli, h, "PESTERCHUM:UNBLOCK")
        except socket.error:
            self.setConnectionBroken()
    @QtCore.pyqtSlot(QString)
    def requestNames(self, channel):
        c = str(channel)
        try:
            helpers.names(self.cli, c)
        except socket.error:
            self.setConnectionBroken()
    @QtCore.pyqtSlot()
    def requestChannelList(self):
        try:
            helpers.channel_list(self.cli)
        except socket.error:
            self.setConnectionBroken()
    @QtCore.pyqtSlot(QString)
    def joinChannel(self, channel):
        c = str(channel)
        try:
            helpers.join(self.cli, c)
            helpers.mode(self.cli, c, "", None)
        except socket.error:
            self.setConnectionBroken()
    @QtCore.pyqtSlot(QString)
    def leftChannel(self, channel):
        c = str(channel)
        try:
            helpers.part(self.cli, c)
            self.cli.command_handler.joined = False
        except socket.error:
            self.setConnectionBroken()
    @QtCore.pyqtSlot(QString, QString)
    def kickUser(self, handle, channel):
        l = handle.split(":")
        c = str(channel)
        h = str(l[0])
        if len(l) > 1:
            reason = str(l[1])
            if len(l) > 2:
              for x in l[2:]:
                reason += str(":") + str(x)
        else:
            reason = ""
        try:
            helpers.kick(self.cli, h, c, reason)
        except socket.error:
            self.setConnectionBroken()
    @QtCore.pyqtSlot(QString, QString, QString)
    def setChannelMode(self, channel, mode, command):
        c = str(channel)
        m = str(mode)
        cmd = str(command)
        if cmd == "":
            cmd = None
        try:
            helpers.mode(self.cli, c, m, cmd)
        except socket.error:
            self.setConnectionBroken()
    @QtCore.pyqtSlot(QString)
    def channelNames(self, channel):
        c = str(channel)
        try:
            helpers.names(self.cli, c)
        except socket.error:
            self.setConnectionBroken()
    @QtCore.pyqtSlot(QString, QString)
    def inviteChum(self, handle, channel):
        h = str(handle)
        c = str(channel)
        try:
            helpers.invite(self.cli, h, c)
        except socket.error:
            self.setConnectionBroken()

    @QtCore.pyqtSlot()
    def pingServer(self):
        try:
            self.cli.send("PING %s" % int(time()))
        except socket.error:
            self.setConnectionBroken()

    @QtCore.pyqtSlot(bool)
    def setAway(self, away=True):
        try:
            if away:
                self.cli.send("AWAY Idle")
            else:
                self.cli.send("AWAY")
        except socket.error:
            self.setConnectionBroken()

    @QtCore.pyqtSlot(QString, QString)
    def killSomeQuirks(self, channel, handle):
        c = str(channel)
        h = str(handle)
        try:
            helpers.ctcp(self.cli, c, "NOQUIRKS", h)
        except socket.error:
            self.setConnectionBroken()
            
    def quit_dc(self):
        helpers.quit(self.cli, _pcVersion + " <3")

    #def getMask(self):
        # This needs to be updated when our hostname is changed.
        # Nevermind this entire thing, actually.

    moodUpdated = QtCore.pyqtSignal('QString', Mood)
    colorUpdated = QtCore.pyqtSignal('QString', QtGui.QColor)
    messageReceived = QtCore.pyqtSignal('QString', 'QString')
    memoReceived = QtCore.pyqtSignal('QString', 'QString', 'QString')
    noticeReceived = QtCore.pyqtSignal('QString', 'QString')
    inviteReceived = QtCore.pyqtSignal('QString', 'QString')
    timeCommand = QtCore.pyqtSignal('QString', 'QString', 'QString')
    namesReceived = QtCore.pyqtSignal('QString', PesterList)
    channelListReceived = QtCore.pyqtSignal(PesterList)
    nickCollision = QtCore.pyqtSignal('QString', 'QString')
    myHandleChanged = QtCore.pyqtSignal('QString')
    chanInviteOnly = QtCore.pyqtSignal('QString')
    modesUpdated = QtCore.pyqtSignal('QString', 'QString')
    connected = QtCore.pyqtSignal()
    userPresentUpdate = QtCore.pyqtSignal('QString', 'QString',
                                   'QString')
    cannotSendToChan = QtCore.pyqtSignal('QString', 'QString')
    tooManyPeeps = QtCore.pyqtSignal()
    quirkDisable = QtCore.pyqtSignal('QString', 'QString', 'QString')
Beispiel #2
0
class IRC:
    def __init__(self):
        self.running = False
        self.stopping = False
        self.nick_number = 0
        self.channels = {}
        self.my_nick = ""
        self.client = None
        # FIXME: should not be hardcoded here
        self.default_channel = LOBBY_CHANNEL
        self.active_channel_name = self.default_channel
        self.connection = None

    def message(self, message, color=None):
        self.channel(self.active_channel_name).message(message, color)

    def warning(self, message):
        self.message(message, IRCColor.WARNING)

    def info(self, message):
        self.message(message, IRCColor.INFO)

    @staticmethod
    def is_channel(name):
        return len(name) > 0 and name[0] in "&#+!"

    def channel(self, name):
        # FIXME: name should be checked case independently
        if not name:
            name = self.default_channel

        from .channel import Channel
        try:
            return self.channels[name]
        except KeyError:
            print("new channel", repr(name))
            self.channels[name] = Channel(self, name)
            print("channels are now", repr(self.channels))
            # self.set_active_channel(name)
            IRCBroadcaster.broadcast("channel_list", {"added": name})
            return self.channels[name]

    def active_channel(self):
        return self.channel(self.active_channel_name)

    def set_active_channel_name(self, name):
        self.active_channel_name = name
        IRCBroadcaster.broadcast("active_channel", {"channel": name})

    def connect(self):
        self.start()

    def start(self):
        self.stopping = False
        if self.running:
            print("IRC.start - already running")
            return
        threading.Thread(target=self.irc_thread, name="IRCThread").start()
        self.running = True

    def stop(self):
        if not self.running:
            return
        self.stopping = True
        helpers.quit(self.client, "Exited")
        # self.client.quit()

    def irc_thread(self):
        try:
            self.irc_main()
        except Exception as e:
            import traceback
            traceback.print_exc()
            # Bind exception to local variable, so the inline function below
            # can access it.
            exception = e

            def func():
                self.warning(repr(exception))

            call_after(func)
        self.running = False

    @staticmethod
    def nick(spec):
        nick = spec.split("!")[0]
        nick = nick.strip("@+")
        return nick

    def me(self, spec):
        nick = spec.split("!")[0]
        return nick == self.my_nick

    @staticmethod
    def get_irc_server_host():
        return LauncherSettings.get_irc_server()

    def irc_main(self):
        def func():
            self.message("connecting to {0}...".format(
                self.get_irc_server_host()))

        call_after(func)

        self.client = IRCClient(CommandHandler,
                                host=self.get_irc_server_host(),
                                port=6667,
                                nick=self.generate_nick(True),
                                blocking=True,
                                connect_cb=self.connect_callback)
        self.client.handler = self
        self.connection = self.client.connect()

        while not self.stopping:
            next(self.connection)
        print("irc_main done")
        self.running = False

    def connect_callback(self, client):
        def func():
            self.message("connected to {0}".format(self.get_irc_server_host()))

        call_after(func)

    def post_message(self, command, args):
        # command = command.decode("UTF-8", errors="replace")
        if self.stopping:
            print("ignoring message", command, "because we're stopping")
            return
        # print("post_message", command, args)
        # self.on_message(command, args)
        # print(command, args)

        args = list(args)

        # for i, arg in enumerate(args):
        #     if arg is not None:
        #         args[i] = arg.decode("UTF-8", errors="replace")

        def func():
            # if IRC.broadcast(command, args):
            #     return
            if self.irc_server_message(command, args):
                return
            name = "irc_" + command
            try:
                method = getattr(self, name)
            except AttributeError:
                self.info(" ".join([command] + args))
                pass
            else:
                method(*args)

        call_after(func)

    def privmsg(self, destination, message):
        helpers.msg(self.client, destination, message)

    def notice(self, destination, message):
        self.client.send("notice {0} :{1}".format(destination, message))

    def generate_nick(self, reset=False):
        if reset:
            self.nick_number = 0
        self.nick_number += 1
        if self.nick_number == 1:
            nick = LauncherSettings.get_irc_nick()
        else:
            nick = LauncherSettings.get_irc_nick() + str(self.nick_number)
        self.my_nick = nick
        return nick

    def append_text(self, message):
        self.message(message)

    def handle_command(self, message):
        if message.startswith("/"):
            return self.handle_command_string(message)
        else:
            if not self.active_channel_name:
                self.warning("no active channel")
            else:
                self.channel(self.active_channel_name).privmsg(message)

    def handle_command_string(self, message):
        message = message[1:]
        parts = message.split(" ")
        command = parts[0].lower()
        args = parts[1:]
        name = "command_" + command
        try:
            method = getattr(self, name)
        except AttributeError:
            self.warning(command + ": unknown command")
            return False
        else:
            method(args)
            return True

    def command_raw(self, args):
        if len(args) >= 1:
            self.client.send(" ".join(args))
        else:
            self.warning("usage: /raw <raw irc message>")

    # noinspection SpellCheckingInspection
    def command_whois(self, args):
        if len(args) >= 1:
            self.client.send("whois {0}".format(" ".join(args)))
        else:
            self.warning("usage: /whois <nick>")

    def command_away(self, args):
        if len(args) == 0:
            self.client.send("away")
        else:
            self.client.send("away {0}".format(" ".join(args)))

    def command_back(self, args):
        if len(args) == 0:
            self.client.send("away")
        else:
            self.warning("usage: /back")

    def command_msg(self, args):
        if len(args) >= 2:
            channel = args[0]
            message = " ".join(args[1:])
            # self.channel(channel).privmsg(message)
            # self.channel(channel).message("<{0}> {1}".format(self.my_nick,
            #        message), IRCColor.MY_MESSAGE)
            self.client.send("privmsg {0} :{1}".format(channel, message))
        else:
            self.warning("usage: /msg <nick|channel> <message>")

    def command_notice(self, args):
        if len(args) >= 2:
            channel = args[0]
            message = " ".join(args[1:])
            # self.channel(channel).notice(message)
            self.client.send("notice {0} :{1}".format(channel, message))
        else:
            self.warning("usage: /notice <nick|channel> <message>")

    # noinspection SpellCheckingInspection
    def command_oper(self, args):
        if len(args) == 2:
            self.client.send("oper {0} {1}".format(args[0], args[1]))
        else:
            self.warning("usage: /oper <user> <password>")

    def command_slap(self, args):
        if len(args) == 1:
            message = "slaps {0} around a bit with a large trout".format(
                args[0])
            self.channel(self.active_channel_name).action(message)
        else:
            self.warning("usage: /slap <nick>")

    def command_me(self, args):
        if len(args) > 0:
            message = " ".join(args)
            self.channel(self.active_channel_name).action(message)
        else:
            self.warning("usage: /me <message>")

    def command_mode(self, args):
        if len(args) >= 2:
            self.client.send("mode {0}".format(" ".join(args)))
        else:
            self.warning("usage: /mode <channel|nick> <parameters...>")

    def command_kick(self, args):
        if not self.is_channel(self.active_channel_name):
            self.warning("cannot kick - not in a channel")
            return
        if len(args) >= 1:
            self.kick(self.active_channel_name, args[0], " ".join(args[1:]))
        else:
            self.warning("usage: /kick <nick> [<message>]")

    def kick(self, channel, nick, message="kicked"):
        self.client.send("KICK", channel, nick, ":{0}".format(message))

    def command_join(self, args):
        if len(args) == 1:
            self.join(args[0])
        else:
            self.warning("join: invalid arguments")

    def join(self, channel):
        helpers.join(self.client, channel)

    def command_leave(self, args):
        return self.command_part(args)

    def command_part(self, args):
        if len(args) == 1:
            self.part(args[0])
        else:
            self.warning("part: invalid arguments")

    def part(self, channel):
        helpers.part(self.client, channel)

    # noinspection SpellCheckingInspection
    def irc_server_message(self, command, args):
        commands = [
            "yourhost", "created", "luserclient", "luserchannels", "luserme",
            "n_local", "n_global", "luserconns", "motdstart", "motd", "nomotd",
            "endofmotd"
        ]
        if command in commands:
            self.message(args[2])
            return 1
        return 0

    # noinspection SpellCheckingInspection
    def irc_featurelist(self, server, nick, *features):
        self.message(" ".join(features))

    def irc_welcome(self, server, nick, message):
        self.message(message)

        password = LauncherSettings.get_irc_nickserv_pass()
        if password:
            self.privmsg("nickserv", "identify {0}".format(password))

        self.join(LOBBY_CHANNEL)

        # convenience for development...
        for arg in sys.argv:
            if arg.startswith("--netplay-game="):
                self.join("&" + arg[15:])
                break

    @classmethod
    def filter_nick(cls, full):
        nick = full.split("!")[0]
        return nick

    def irc_privmsg(self, sender, destination, message):
        nick = self.filter_nick(sender)
        if self.is_channel(destination):
            channel = destination
        else:
            channel = self.filter_nick(sender)
        self.channel(channel).on_privmsg(nick, message)
        IRCBroadcaster.broadcast("privmsg", {
            "channel": channel,
            "message": message,
            "nick": nick
        })

    def irc_notice(self, sender, destination, message):
        if sender:
            nick = self.filter_nick(sender)
        else:
            nick = "(server)"
        if self.is_channel(destination):
            channel = destination
        else:
            channel = self.active_channel_name
        self.channel(channel).on_notice(nick, message)
        IRCBroadcaster.broadcast("notice", {
            "channel": channel,
            "message": message,
            "nick": nick
        })

    def irc_kick(self, kicker, channel, who, why):
        self.channel(channel).on_kick(self.filter_nick(kicker), who, why)

    def irc_part(self, who, channel, *_):
        self.channel(channel).on_part(self.filter_nick(who))

    def irc_join(self, who, channel):
        self.channel(channel).on_join(self.filter_nick(who))

    # noinspection SpellCheckingInspection
    def irc_endofnames(self, sender, recipient, channel, message):
        pass

    # noinspection SpellCheckingInspection
    def irc_namreply(self, server, who, equals, channel, nicks):
        self.channel(channel).on_namreply(nicks.split(" "))

    # noinspection SpellCheckingInspection
    def irc_currenttopic(self, sender, recipient, channel, topic):
        self.channel(channel).on_currenttopic(topic)

    # noinspection SpellCheckingInspection
    def irc_topicinfo(self, sender, recipient, channel, who, when):
        pass

    # noinspection SpellCheckingInspection
    def irc_cannotsendtochan(self, server, who, channel, message):
        self.channel(channel).warning("cannot send to channel: " + message)

    def irc_topic(self, who, channel, topic):
        self.channel(channel).on_topic(who, topic)

    def irc_mode(self, who, destination, *args):
        if self.is_channel(destination):
            self.channel(destination).on_mode(self.filter_nick(who), args)
        else:
            self.message("{0} set mode {1} {2}".format(who, destination,
                                                       " ".join(args)))

    def irc_quit(self, who, reason):
        for name in self.channels:
            self.channel(name).on_quit(self.filter_nick(who), reason)
Beispiel #3
0
class IRC:
    def __init__(self):
        self.running = False
        self.stopping = False
        self.nick_number = 0
        self.channels = {}
        self.my_nick = ""
        self.client = None
        # FIXME: should not be hardcoded here
        self.default_channel = LOBBY_CHANNEL
        self.active_channel_name = self.default_channel
        self.connection = None

    def message(self, message, color=None):
        self.channel(self.active_channel_name).message(message, color)

    def warning(self, message):
        self.message(message, IRCColor.WARNING)

    def info(self, message):
        self.message(message, IRCColor.INFO)

    @staticmethod
    def is_channel(name):
        return len(name) > 0 and name[0] in "&#+!"

    def channel(self, name):
        # FIXME: name should be checked case independently
        if not name:
            name = self.default_channel

        from .channel import Channel
        try:
            return self.channels[name]
        except KeyError:
            print("new channel", repr(name))
            self.channels[name] = Channel(self, name)
            print("channels are now", repr(self.channels))
            # self.set_active_channel(name)
            IRCBroadcaster.broadcast("channel_list", {"added": name})
            return self.channels[name]

    def active_channel(self):
        return self.channel(self.active_channel_name)

    def set_active_channel_name(self, name):
        self.active_channel_name = name
        IRCBroadcaster.broadcast("active_channel", {"channel": name})

    def connect(self):
        self.start()

    def start(self):
        self.stopping = False
        if self.running:
            print("IRC.start - already running")
            return
        threading.Thread(target=self.irc_thread,
                         name="IRCThread").start()
        self.running = True

    def stop(self):
        if not self.running:
            return
        self.stopping = True
        helpers.quit(self.client, "Exited")
        # self.client.quit()

    def irc_thread(self):
        try:
            self.irc_main()
        except Exception as e:
            def func():
                self.warning(repr(e))

            call_after(func)
            import traceback
            traceback.print_exc()
        self.running = False

    @staticmethod
    def nick(spec):
        nick = spec.split("!")[0]
        nick = nick.strip("@+")
        return nick

    def me(self, spec):
        nick = spec.split("!")[0]
        return nick == self.my_nick

    @staticmethod
    def get_irc_server_host():
        return LauncherSettings.get_irc_server()

    def irc_main(self):
        def func():
            self.message("connecting to {0}...".format(
                    self.get_irc_server_host()))

        call_after(func)

        self.client = IRCClient(
                CommandHandler,
                host=self.get_irc_server_host(),
                port=6667,
                nick=self.generate_nick(True),
                blocking=True,
                connect_cb=self.connect_callback)
        self.client.handler = self
        self.connection = self.client.connect()

        while not self.stopping:
            next(self.connection)
        print("irc_main done")
        self.running = False

    def connect_callback(self, client):
        def func():
            self.message("connected to {0}".format(self.get_irc_server_host()))

        call_after(func)

    def post_message(self, command, args):
        # command = command.decode("UTF-8", errors="replace")
        if self.stopping:
            print("ignoring message", command, "because we're stopping")
            return
        # print("post_message", command, args)
        # self.on_message(command, args)
        # print(command, args)

        args = list(args)

        # for i, arg in enumerate(args):
        #     if arg is not None:
        #         args[i] = arg.decode("UTF-8", errors="replace")

        def func():
            # if IRC.broadcast(command, args):
            #     return
            if self.irc_server_message(command, args):
                return
            name = "irc_" + command
            try:
                method = getattr(self, name)
            except AttributeError:
                self.info(" ".join([command] + args))
                pass
            else:
                method(*args)

        call_after(func)

    def privmsg(self, destination, message):
        helpers.msg(self.client, destination, message)

    def notice(self, destination, message):
        self.client.send("notice {0} :{1}".format(destination, message))

    def generate_nick(self, reset=False):
        if reset:
            self.nick_number = 0
        self.nick_number += 1
        if self.nick_number == 1:
            nick = LauncherSettings.get_irc_nick()
        else:
            nick = LauncherSettings.get_irc_nick() + str(self.nick_number)
        self.my_nick = nick
        return nick

    def append_text(self, message):
        self.message(message)

    def handle_command(self, message):
        if message.startswith("/"):
            return self.handle_command_string(message)
        else:
            if not self.active_channel_name:
                self.warning("no active channel")
            else:
                self.channel(self.active_channel_name).privmsg(message)

    def handle_command_string(self, message):
        message = message[1:]
        parts = message.split(" ")
        command = parts[0].lower()
        args = parts[1:]
        name = "command_" + command
        try:
            method = getattr(self, name)
        except AttributeError:
            self.warning(command + ": unknown command")
            return False
        else:
            method(args)
            return True

    def command_raw(self, args):
        if len(args) >= 1:
            self.client.send(" ".join(args))
        else:
            self.warning("usage: /raw <raw irc message>")

    # noinspection SpellCheckingInspection
    def command_whois(self, args):
        if len(args) >= 1:
            self.client.send("whois {0}".format(" ".join(args)))
        else:
            self.warning("usage: /whois <nick>")

    def command_away(self, args):
        if len(args) == 0:
            self.client.send("away")
        else:
            self.client.send("away {0}".format(" ".join(args)))

    def command_back(self, args):
        if len(args) == 0:
            self.client.send("away")
        else:
            self.warning("usage: /back")

    def command_msg(self, args):
        if len(args) >= 2:
            channel = args[0]
            message = " ".join(args[1:])
            # self.channel(channel).privmsg(message)
            # self.channel(channel).message("<{0}> {1}".format(self.my_nick,
            #        message), IRCColor.MY_MESSAGE)
            self.client.send("privmsg {0} :{1}".format(channel, message))
        else:
            self.warning("usage: /msg <nick|channel> <message>")

    def command_notice(self, args):
        if len(args) >= 2:
            channel = args[0]
            message = " ".join(args[1:])
            # self.channel(channel).notice(message)
            self.client.send("notice {0} :{1}".format(channel, message))
        else:
            self.warning("usage: /notice <nick|channel> <message>")

    # noinspection SpellCheckingInspection
    def command_oper(self, args):
        if len(args) == 2:
            self.client.send("oper {0} {1}".format(args[0], args[1]))
        else:
            self.warning("usage: /oper <user> <password>")

    def command_slap(self, args):
        if len(args) == 1:
            message = "slaps {0} around a bit with a large trout".format(
                    args[0])
            self.channel(self.active_channel_name).action(message)
        else:
            self.warning("usage: /slap <nick>")

    def command_me(self, args):
        if len(args) > 0:
            message = " ".join(args)
            self.channel(self.active_channel_name).action(message)
        else:
            self.warning("usage: /me <message>")

    def command_mode(self, args):
        if len(args) >= 2:
            self.client.send("mode {0}".format(" ".join(args)))
        else:
            self.warning("usage: /mode <channel|nick> <parameters...>")

    def command_kick(self, args):
        if not self.is_channel(self.active_channel_name):
            self.warning("cannot kick - not in a channel")
            return
        if len(args) >= 1:
            self.kick(self.active_channel_name, args[0], " ".join(args[1:]))
        else:
            self.warning("usage: /kick <nick> [<message>]")

    def kick(self, channel, nick, message="kicked"):
        self.client.send("KICK", channel, nick, ":{0}".format(message))

    def command_join(self, args):
        if len(args) == 1:
            self.join(args[0])
        else:
            self.warning("join: invalid arguments")

    def join(self, channel):
        helpers.join(self.client, channel)

    def command_leave(self, args):
        return self.command_part(args)

    def command_part(self, args):
        if len(args) == 1:
            self.part(args[0])
        else:
            self.warning("part: invalid arguments")

    def part(self, channel):
        helpers.part(self.client, channel)

    # noinspection SpellCheckingInspection
    def irc_server_message(self, command, args):
        commands = [
            "yourhost", "created", "luserclient", "luserchannels",
            "luserme", "n_local", "n_global", "luserconns", "motdstart",
            "motd", "nomotd", "endofmotd"
        ]
        if command in commands:
            self.message(args[2])
            return 1
        return 0

    # noinspection SpellCheckingInspection
    def irc_featurelist(self, server, nick, *features):
        self.message(" ".join(features))

    def irc_welcome(self, server, nick, message):
        self.message(message)

        password = LauncherSettings.get_irc_nickserv_pass()
        if password:
            self.privmsg("nickserv", "identify {0}".format(password))

        self.join(LOBBY_CHANNEL)

        # convenience for development...
        for arg in sys.argv:
            if arg.startswith("--netplay-game="):
                self.join("&" + arg[15:])
                break

    @classmethod
    def filter_nick(cls, full):
        nick = full.split("!")[0]
        return nick

    def irc_privmsg(self, sender, destination, message):
        nick = self.filter_nick(sender)
        if self.is_channel(destination):
            channel = destination
        else:
            channel = self.filter_nick(sender)
        self.channel(channel).on_privmsg(nick, message)
        IRCBroadcaster.broadcast("privmsg", {
            "channel": channel, "message": message, "nick": nick})

    def irc_notice(self, sender, destination, message):
        if sender:
            nick = self.filter_nick(sender)
        else:
            nick = "(server)"
        if self.is_channel(destination):
            channel = destination
        else:
            channel = self.active_channel_name
        self.channel(channel).on_notice(nick, message)
        IRCBroadcaster.broadcast("notice", {
            "channel": channel, "message": message, "nick": nick})

    def irc_kick(self, kicker, channel, who, why):
        self.channel(channel).on_kick(self.filter_nick(kicker), who, why)

    def irc_part(self, who, channel, *_):
        self.channel(channel).on_part(self.filter_nick(who))

    def irc_join(self, who, channel):
        self.channel(channel).on_join(self.filter_nick(who))

    # noinspection SpellCheckingInspection
    def irc_endofnames(self, sender, recipient, channel, message):
        pass

    # noinspection SpellCheckingInspection
    def irc_namreply(self, server, who, equals, channel, nicks):
        self.channel(channel).on_namreply(nicks.split(" "))

    # noinspection SpellCheckingInspection
    def irc_currenttopic(self, sender, recipient, channel, topic):
        self.channel(channel).on_currenttopic(topic)

    # noinspection SpellCheckingInspection
    def irc_topicinfo(self, sender, recipient, channel, who, when):
        pass

    # noinspection SpellCheckingInspection
    def irc_cannotsendtochan(self, server, who, channel, message):
        self.channel(channel).warning("cannot send to channel: " + message)

    def irc_topic(self, who, channel, topic):
        self.channel(channel).on_topic(who, topic)

    def irc_mode(self, who, destination, *args):
        if self.is_channel(destination):
            self.channel(destination).on_mode(self.filter_nick(who), args)
        else:
            self.message("{0} set mode {1} {2}".format(
                    who, destination, " ".join(args)))

    def irc_quit(self, who, reason):
        for name in self.channels:
            self.channel(name).on_quit(self.filter_nick(who), reason)
Beispiel #4
0
class PesterIRC(QtCore.QThread):
    def __init__(self, config, window):
        QtCore.QThread.__init__(self)
        self.mainwindow = window
        self.config = config
        self.registeredIRC = False
        self.stopIRC = None
        self.NickServ = services.NickServ()
        self.ChanServ = services.ChanServ()
    def IRCConnect(self):
        server = self.config.server()
        port = self.config.port()
        self.cli = IRCClient(PesterHandler, host=server, port=int(port), nick=self.mainwindow.profile().handle, real_name='pcc31', blocking=True, timeout=120)
        self.cli.command_handler.parent = self
        self.cli.command_handler.mainwindow = self.mainwindow
        self.cli.connect()
        self.conn = self.cli.conn()
    def run(self):
        try:
            self.IRCConnect()
        except socket.error as se:
            self.stopIRC = se
            return
        while 1:
            res = True
            try:
                logging.debug("updateIRC()")
                res = self.updateIRC()
            except socket.timeout as se:
                logging.debug("timeout in thread %s" % (self))
                self.cli.close()
                self.stopIRC = se
                return
            except socket.error as se:
                if self.registeredIRC:
                    self.stopIRC = None
                else:
                    self.stopIRC = se
                logging.debug("socket error, exiting thread")
                return
            else:
                if not res:
                    logging.debug("false Yield: %s, returning" % res)
                    return

    def setConnected(self):
        self.registeredIRC = True
        self.connected.emit()
    def setConnectionBroken(self):
        logging.debug("setconnection broken")
        self.reconnectIRC()
        #self.brokenConnection = True
    @QtCore.pyqtSlot()
    def updateIRC(self):
        try:
            res = next(self.conn)
        except socket.timeout as se:
            if self.registeredIRC:
                return True
            else:
                raise se
        except socket.error as se:
            raise se
        except StopIteration:
            self.conn = self.cli.conn()
            return True
        else:
            return res
    @QtCore.pyqtSlot()
    def reconnectIRC(self):
        logging.debug("reconnectIRC() from thread %s" % (self))
        self.cli.close()

    @QtCore.pyqtSlot(PesterProfile)
    def getMood(self, *chums):
        self.cli.command_handler.getMood(*chums)
    @QtCore.pyqtSlot(PesterList)
    def getMoods(self, chums):
        self.cli.command_handler.getMood(*chums)
    @QtCore.pyqtSlot('QString', 'QString')
    def sendNotice(self, text, handle):
        h = str(handle)
        t = str(text)
        try:
            helpers.notice(self.cli, h, t)
        except socket.error:
            self.setConnectionBroken()
    @QtCore.pyqtSlot('QString', 'QString')
    def sendMessage(self, text, handle):
        h = str(handle)
        textl = [str(text)]
        def splittext(l):
            if len(l[0]) > 450:
                space = l[0].rfind(" ", 0,430)
                if space == -1:
                    space = 450
                elif l[0][space+1:space+5] == "</c>":
                    space = space+4
                a = l[0][0:space+1]
                b = l[0][space+1:]
                if a.count("<c") > a.count("</c>"):
                    # oh god ctags will break!! D=
                    hanging = []
                    usedends = []
                    c = a.rfind("<c")
                    while c != -1:
                        d = a.find("</c>", c)
                        while d in usedends:
                            d = a.find("</c>", d+1)
                        if d != -1: usedends.append(d)
                        else:
                            f = a.find(">", c)+1
                            hanging.append(a[c:f])
                        c = a.rfind("<c",0,c)

                    # end all ctags in first part
                    for i in range(a.count("<c")-a.count("</c>")):
                        a = a + "</c>"
                    #start them up again in the second part
                    for c in hanging:
                        b = c + b
                if len(b) > 0:
                    return [a] + splittext([b])
                else:
                    return [a]
            else:
                return l
        textl = splittext(textl)
        try:
            for t in textl:
                helpers.msg(self.cli, h, t)
        except socket.error:
            self.setConnectionBroken()
    @QtCore.pyqtSlot('QString', bool)
    def startConvo(self, handle, initiated):
        h = str(handle)
        try:
            if initiated:
                helpers.msg(self.cli, h, "PESTERCHUM:BEGIN")
            helpers.msg(self.cli, h, "COLOR >%s" % (self.mainwindow.profile().colorcmd()))
        except socket.error:
            self.setConnectionBroken()
    @QtCore.pyqtSlot('QString')
    def endConvo(self, handle):
        h = str(handle)
        try:
            helpers.msg(self.cli, h, "PESTERCHUM:CEASE")
        except socket.error:
            self.setConnectionBroken()
    @QtCore.pyqtSlot()
    def updateProfile(self):
        me = self.mainwindow.profile()
        handle = me.handle
        try:
            helpers.nick(self.cli, handle)
        except socket.error:
            self.setConnectionBroken()
        self.mainwindow.closeConversations(True)
        self.mainwindow.doAutoIdentify()
        self.mainwindow.autoJoinDone = False
        self.mainwindow.doAutoJoins()
        self.updateMood()
    @QtCore.pyqtSlot()
    def updateMood(self):
        me = self.mainwindow.profile()
        try:
            helpers.msg(self.cli, "#pesterchum", "MOOD >%d" % (me.mood.value()))
        except socket.error:
            self.setConnectionBroken()
    @QtCore.pyqtSlot()
    def updateColor(self):
        me = self.mainwindow.profile()
        for h in self.mainwindow.convos.keys():
            try:
                helpers.msg(self.cli, h, "COLOR >%s" % (self.mainwindow.profile().colorcmd()))
            except socket.error:
                self.setConnectionBroken()
    @QtCore.pyqtSlot('QString')
    def blockedChum(self, handle):
        h = str(handle)
        try:
            helpers.msg(self.cli, h, "PESTERCHUM:BLOCK")
        except socket.error:
            self.setConnectionBroken()
    @QtCore.pyqtSlot('QString')
    def unblockedChum(self, handle):
        h = str(handle)
        try:
            helpers.msg(self.cli, h, "PESTERCHUM:UNBLOCK")
        except socket.error:
            self.setConnectionBroken()
    @QtCore.pyqtSlot('QString')
    def requestNames(self, channel):
        c = str(channel)
        try:
            helpers.names(self.cli, c)
        except socket.error:
            self.setConnectionBroken()
    @QtCore.pyqtSlot()
    def requestChannelList(self):
        try:
            helpers.channel_list(self.cli)
        except socket.error:
            self.setConnectionBroken()
    @QtCore.pyqtSlot('QString')
    def joinChannel(self, channel):
        c = str(channel)
        try:
            helpers.join(self.cli, c)
            helpers.mode(self.cli, c, "", None)
        except socket.error:
            self.setConnectionBroken()
    @QtCore.pyqtSlot('QString')
    def leftChannel(self, channel):
        c = str(channel)
        try:
            helpers.part(self.cli, c)
            self.cli.command_handler.joined = False
        except socket.error:
            self.setConnectionBroken()
    @QtCore.pyqtSlot('QString', 'QString')
    def kickUser(self, handle, channel):
        l = handle.split(":")
        c = str(channel)
        h = str(l[0])
        if len(l) > 1:
            reason = str(l[1])
            if len(l) > 2:
              for x in l[2:]:
                reason += str(":") + str(x)
        else:
            reason = ""
        try:
            helpers.kick(self.cli, h, c, reason)
        except socket.error:
            self.setConnectionBroken()
    @QtCore.pyqtSlot('QString', 'QString', 'QString')
    def setChannelMode(self, channel, mode, command):
        c = str(channel)
        m = str(mode)
        cmd = str(command)
        if cmd == "":
            cmd = None
        try:
            helpers.mode(self.cli, c, m, cmd)
        except socket.error:
            self.setConnectionBroken()
    @QtCore.pyqtSlot('QString')
    def channelNames(self, channel):
        c = str(channel)
        try:
            helpers.names(self.cli, c)
        except socket.error:
            self.setConnectionBroken()
    @QtCore.pyqtSlot('QString', 'QString')
    def inviteChum(self, handle, channel):
        h = str(handle)
        c = str(channel)
        try:
            helpers.invite(self.cli, h, c)
        except socket.error:
            self.setConnectionBroken()

    @QtCore.pyqtSlot()
    def pingServer(self):
        try:
            self.cli.send("PING %s" % int(time()))
        except socket.error:
            self.setConnectionBroken()

    @QtCore.pyqtSlot(bool)
    def setAway(self, away=True):
        try:
            if away:
                self.cli.send("AWAY Idle")
            else:
                self.cli.send("AWAY")
        except socket.error:
            self.setConnectionBroken()

    @QtCore.pyqtSlot('QString', 'QString')
    def killSomeQuirks(self, channel, handle):
        c = str(channel)
        h = str(handle)
        try:
            helpers.ctcp(self.cli, c, "NOQUIRKS", h)
        except socket.error:
            self.setConnectionBroken()

    moodUpdated = QtCore.pyqtSignal('QString', Mood)
    colorUpdated = QtCore.pyqtSignal('QString', QtGui.QColor)
    messageReceived = QtCore.pyqtSignal('QString', 'QString')
    memoReceived = QtCore.pyqtSignal('QString', 'QString', 'QString')
    noticeReceived = QtCore.pyqtSignal('QString', 'QString')
    inviteReceived = QtCore.pyqtSignal('QString', 'QString')
    timeCommand = QtCore.pyqtSignal('QString', 'QString', 'QString')
    namesReceived = QtCore.pyqtSignal('QString', PesterList)
    channelListReceived = QtCore.pyqtSignal(PesterList)
    nickCollision = QtCore.pyqtSignal('QString', 'QString')
    myHandleChanged = QtCore.pyqtSignal('QString')
    chanInviteOnly = QtCore.pyqtSignal('QString')
    modesUpdated = QtCore.pyqtSignal('QString', 'QString')
    connected = QtCore.pyqtSignal()
    userPresentUpdate = QtCore.pyqtSignal('QString', 'QString',
                                   'QString')
    cannotSendToChan = QtCore.pyqtSignal('QString', 'QString')
    tooManyPeeps = QtCore.pyqtSignal()
    quirkDisable = QtCore.pyqtSignal('QString', 'QString', 'QString')