Esempio n. 1
0
    def _out(self, server, target, target_str, is_channel, obj, type, tags):
        if type == OutType.OUT:
            color = utils.consts.GREEN
        else:
            color = utils.consts.RED

        line_str = obj.pop()
        if obj.prefix:
            line_str = "[%s] %s" % (utils.irc.color(obj.prefix,
                                                    color), line_str)
        method = self._command_method(server, target, is_channel)

        if not method in ["PRIVMSG", "NOTICE"]:
            raise ValueError("Unknown command-method '%s'" % method)

        line = IRCLine.ParsedLine(method, [target_str, line_str], tags=tags)
        valid, trunc = line.truncate(server.hostmask(), margin=STR_MORE_LEN)

        if trunc:
            if not trunc[0] in WORD_BOUNDARIES:
                for boundary in WORD_BOUNDARIES:
                    left, *right = valid.rsplit(boundary, 1)
                    if right:
                        valid = left
                        trunc = right[0] + trunc
            obj.insert("%s %s" % (STR_CONTINUED, trunc))
            valid = valid + STR_MORE
        line = IRCLine.parse_line(valid)
        server.send(line)
Esempio n. 2
0
 def _execute(self, server, commands, **kwargs):
     for command in commands:
         line = command.format(**kwargs)
         if IRCLine.is_human(line):
             line = IRCLine.parse_human(line)
         else:
             line = IRCLine.parse_line(line)
         server.send(line)
Esempio n. 3
0
    def get_lines(self) -> typing.List[IRCLine.ParsedLine]:
        lines = []
        for line in self._lines:
            line.add_tag("batch", self.identifier)
            lines.append(line)

        lines.insert(0, IRCLine.ParsedLine("BATCH",
            ["+%s" % self.identifier, self.type]))
        lines.append(IRCLine.ParsedLine("BATCH", ["-%s" % self.identifier]))
        return lines
Esempio n. 4
0
    def send_message(self, event):
        our_hostmask = IRCLine.parse_hostmask(event["server"].hostmask())

        echo = IRCLine.ParsedLine(event["line"].command,
                                  event["line"].args,
                                  source=our_hostmask,
                                  tags=event["line"].tags)
        echo.id = event["line"].id

        self.events.on("raw.received").call(line=echo, server=event["server"])
Esempio n. 5
0
    def raw(self, event):
        if IRCLine.is_human(event["spec"][0]):
            line = IRCLine.parse_human(event["spec"][0])
        else:
            line = IRCLine.parse_line(event["spec"][0])
        line = event["server"].send(line)

        if not line == None:
            event["stdout"].write("Sent: %s" % line.parsed_line.format())
        else:
            event["stderr"].write("Line was filtered")
Esempio n. 6
0
    def rawctl(self, event):
        rawargs = str(event["data"]).split(" ", 1)
        server = self._server_from_alias(rawargs[0])
        if IRCLine.is_human(rawargs[1]):
            line = IRCLine.parse_human(rawargs[1])
        else:
            line = IRCLine.parse_line(rawargs[1])
        line = server.send(line)

        if not line == None:
            return "Sent: " + line.parsed_line.format()
        else:
            return "Line was filtered"
Esempio n. 7
0
    def preprocess_send_privmsg(self, event):
        if len(event["line"].args) > 1:
            if ("\n" in event["line"].args[1]
                    and event["server"].has_capability(CAP)):
                event["line"].invalidate()

                target = event["line"].args[0]
                lines = event["line"].args[1].split("\n")
                batch = IRCLine.IRCSendBatch("draft/multiline", [target])
                for line in lines:
                    line = IRCLine.ParsedLine("PRIVMSG", [target, line])
                    batch.add_line(line)
                for line in batch.get_lines():
                    event["server"].send(line)
Esempio n. 8
0
def handle_353(event):
    channel = event["server"].channels.get(event["line"].args[2])
    nicknames = event["line"].args.get(3).split(" ")

    # there can sometimes be a dangling space at the end of a 353
    if nicknames and not nicknames[-1]:
        nicknames.pop(-1)

    for nickname in nicknames:
        modes = set([])

        while nickname[0] in event["server"].prefix_symbols:
            modes.add(event["server"].prefix_symbols[nickname[0]])
            nickname = nickname[1:]

        if event["server"].has_capability_str("userhost-in-names"):
            hostmask = IRCLine.parse_hostmask(nickname)
            nickname = hostmask.nickname
            user = event["server"].get_user(hostmask.nickname,
                                            username=hostmask.username,
                                            hostname=hostmask.hostname)
        else:
            user = event["server"].get_user(nickname)
        user.join_channel(channel)
        channel.add_user(user)

        for mode in modes:
            channel.add_mode(mode, nickname)
Esempio n. 9
0
    def send(self,
             line_parsed: IRCLine.ParsedLine,
             immediate: bool = False) -> typing.Optional[IRCLine.SentLine]:
        if not self.send_enabled:
            return None

        line_events = self.events.new_root()

        self.events.on("preprocess.send").on(line_parsed.command).call_unsafe(
            server=self, line=line_parsed, events=line_events)
        self.events.on("preprocess.send").call_unsafe(server=self,
                                                      line=line_parsed,
                                                      events=line_events)

        if line_parsed.valid() or line_parsed.assured():
            line = line_parsed.format()
            line_obj = IRCLine.SentLine(line_events,
                                        datetime.datetime.utcnow(),
                                        self.hostmask(), line_parsed)
            self.socket.send(line_obj, immediate=immediate)

            if immediate:
                self.bot.trigger_write()

            return line_obj
        return None
Esempio n. 10
0
    def send(self, method):
        if self.has_text():
            prefix = ""
            if not self._hide_prefix:
                prefix = utils.consts.RESET + "[%s] " % self._prefix

            text = self._text[:].replace("\r", "")
            while "\n\n" in text:
                text = text.replace("\n\n", "\n")

            full_text = "%s%s" % (prefix, text)
            message_factory = _message_factory(method)

            line = message_factory(self._target_str,
                                   full_text,
                                   tags=self._tags)
            if self._assured:
                line.assure()

            valid, truncated = line.truncate(self.server.hostmask(),
                                             margin=STR_MORE_LEN)

            if truncated:
                valid, truncated = self._adjust_to_word_boundaries(
                    valid, truncated)

                line = IRCLine.parse_line(valid + STR_MORE)
                self._text = "%s%s" % (STR_CONTINUED, truncated)
            else:
                self._text = ""

            sent_line = self.server.send(line)
Esempio n. 11
0
def parse_line(line: str) -> IRCLine.ParsedLine:
    tags = {}  # type: typing.Dict[str, typing.Any]
    source = None  # type: typing.Optional[IRCLine.Hostmask]
    command = None

    if line[0] == "@":
        tags_prefix, line = line[1:].split(" ", 1)

        for tag in filter(None, tags_prefix.split(";")):
            tag, sep, value = tag.partition("=")
            if value:
                tags[tag] = message_tag_unescape(value)
            else:
                tags[tag] = None

    line, trailing_separator, trailing_split = line.partition(" :")

    trailing = None  # type: typing.Optional[str]
    if trailing_separator:
        trailing = trailing_split

    if line[0] == ":":
        source_str, line = line[1:].split(" ", 1)
        source = seperate_hostmask(source_str)

    command, sep, line = line.partition(" ")
    args = []  # type: typing.List[str]
    if line:
        # this is so that `args` is empty if `line` is empty
        args = line.split(" ")

    if not trailing == None:
        args.append(typing.cast(str, trailing))

    return IRCLine.ParsedLine(command, args, source, tags)
Esempio n. 12
0
    def add_server(self, event):
        alias = event["spec"][0]
        hostname, sep, port = event["spec"][1].partition(":")
        tls = port.startswith("+")
        port = port.lstrip("+")

        if not hostname or not port or not port.isdigit():
            raise utils.EventError("Please provide <hostname>:[+]<port>")
        port = int(port)

        hostmask = IRCLine.parse_hostmask(event["spec"][2])
        nickname = hostmask.nickname
        username = hostmask.username or nickname
        realname = nickname
        bindhost = hostmask.hostname or None

        try:
            server_id = self.bot.database.servers.add(alias, hostname, port,
                                                      "", tls, bindhost,
                                                      nickname, username,
                                                      realname)
        except Exception as e:
            event["stderr"].write("Failed to add server")
            self.log.error("failed to add server \"%s\"", [alias],
                           exc_info=True)
            return
        event["stdout"].write("Added server '%s'" % alias)
Esempio n. 13
0
    def batch(self, event):
        identifier = event["line"].args[0]
        modifier, identifier = identifier[0], identifier[1:]

        if modifier == "+":
            batch_type = event["line"].args[1]
            args = event["line"].args[2:]

            batch = IRCLine.IRCBatch(identifier,
                                     batch_type,
                                     args,
                                     event["line"].tags,
                                     source=event["line"].source)
            event["server"].batches[identifier] = batch

            self.events.on("received.batch.start").call(batch=batch,
                                                        server=event["server"])
        else:
            batch = event["server"].batches[identifier]
            del event["server"].batches[identifier]

            lines = batch.get_lines()

            results = self.events.on("received.batch.end").call(
                batch=batch, server=event["server"])

            for result in results:
                if not result == None:
                    lines = result
                    break

            for line in lines:
                self._handle(event["server"], line)
Esempio n. 14
0
    def raw(self, event):
        """
        :help: Send a line of raw IRC data
        :usage: <raw line>
        :permission: raw
        """
        if IRCLine.is_human(event["args"]):
            line = IRCLine.parse_human(event["args"])
        else:
            line = IRCLine.parse_line(event["args"])
        line = event["server"].send(line)

        if not line == None:
            event["stdout"].write("Sent: %s" % line.parsed_line.format())
        else:
            event["stderr"].write("Line was filtered")
Esempio n. 15
0
def mode(target: str, mode: str=None, args: typing.List[str]=None
        ) -> IRCLine.ParsedLine:
    command_args = [target]
    if mode:
        command_args.append(mode)
        if args:
            command_args = command_args+args
    return IRCLine.ParsedLine("MODE", command_args)
Esempio n. 16
0
def whowas(target: str, amount: int=None, server: str=None
        ) -> IRCLine.ParsedLine:
    command_args = [target]
    if amount:
        command_args.append(str(amount))
        if server:
            command_args.append(server)
    return IRCLine.ParsedLine("WHOWAS", command_args)
Esempio n. 17
0
def handle_333(events, event):
    channel = event["server"].channels.get(event["line"].args[1])

    topic_setter = IRCLine.parse_hostmask(event["line"].args[2])
    topic_time = int(event["line"].args[3])

    channel.set_topic_setter(topic_setter)
    channel.set_topic_time(topic_time)
    events.on("received.333").call(channel=channel,
        setter=topic_setter, set_at=topic_time, server=event["server"])
Esempio n. 18
0
 def send(self, line: str):
     results = self.events.on("preprocess.send").call_unsafe(
         server=self, line=line)
     for result in results:
         if result:
             line = result
             break
     line_stripped = line.split("\n", 1)[0].strip("\r")
     line_obj = IRCLine.Line(self, datetime.datetime.utcnow(), line_stripped)
     self.socket.send(line_obj)
     return line_obj
Esempio n. 19
0
    def send(self, line_parsed: IRCLine.ParsedLine):
        if not self.send_enabled:
            return None

        self.events.on("preprocess.send").on(line_parsed.command).call_unsafe(
            server=self, line=line_parsed)

        line = line_parsed.format()
        line_obj = IRCLine.SentLine(datetime.datetime.utcnow(),
                                    self.hostmask(), line_parsed)
        self.socket.send(line_obj)
        return line_obj
Esempio n. 20
0
    def batch_end(self, event):
        if BATCH.match(event["batch"].type):
            messages = []
            lines = event["batch"].get_lines()
            for line in lines:
                message = line.args[1]
                if TAG.present(line.tags):
                    last_message = ""
                    if messages:
                        last_message = messages.pop(-1)
                    message = last_message + message
                messages.append(message)

            target = event["batch"].args[0]
            message = "\n".join(messages)
            return [
                IRCLine.ParsedLine("PRIVMSG", [target, message],
                                   source=event["batch"].source)
            ]
Esempio n. 21
0
    def _kill(self, signum):
        if self._exited:
            return
        self._exited = True

        self.events.on("signal.interrupt").call(signum=signum)

        written = False
        for server in list(self.bot.servers.values()):
            if server.connected:
                server.socket.clear_send_buffer()

                line = IRCLine.ParsedLine("QUIT", ["Shutting down"])
                sent_line = server.send(line, immediate=True)
                sent_line.events.on("send").hook(self._make_hook(server))

                server.send_enabled = False
                written = True

        if not written:
            sys.exit()
Esempio n. 22
0
 def _line(self, command: str,
         unfiltered_args: typing.Sequence[typing.Optional[str]], tags={}):
     args: typing.List[str] = [a for a in unfiltered_args if not a is None]
     return IRCLine.ParsedLine(command, args, tags=tags)
Esempio n. 23
0
def batch_end(identifier: str, tags: typing.Dict[str, str]={}):
    return IRCLine.ParsedLine("BATCH", ["-%s" % identifier], tags=tags)
Esempio n. 24
0
def message(events, event):
    from_self = _from_self(event["server"], event["line"].source)
    if from_self == None:
        return

    direction = "send" if from_self else "received"

    target_str = event["line"].args[0]

    message = None
    if len(event["line"].args) > 1:
        message = event["line"].args[1]

    source = event["line"].source
    if (not event["server"].nickname
            or not source
            or source.hostmask == event["server"].name):
        if source:
            event["server"].name = event["line"].source.hostmask
        else:
            source = IRCLine.parse_hostmask(event["server"].name)
        target_str = event["server"].nickname or "*"

    if from_self:
        user = event["server"].get_user(event["server"].nickname)
    else:
        user = event["server"].get_user(source.nickname,
            username=source.username,
            hostname=source.hostname)

    # strip prefix_symbols from the start of target, for when people use
    # e.g. 'PRIVMSG +#channel :hi' which would send a message to only
    # voiced-or-above users
    statusmsg = ""
    for char in target_str:
        if char in event["server"].statusmsg:
            statusmsg += char
        else:
            break
    target = target_str.replace(statusmsg, "", 1)

    is_channel = event["server"].is_channel(target)

    if is_channel:
        if not target in event["server"].channels:
            return
        target_obj = event["server"].channels.get(target)
    else:
        target_obj = event["server"].get_user(target)

    kwargs = {"server": event["server"], "target": target_obj,
        "target_str": target_str, "user": user, "tags": event["line"].tags,
        "is_channel": is_channel, "from_self": from_self, "line": event["line"],
        "statusmsg": statusmsg}

    action = False

    if message:
        ctcp_message = utils.irc.parse_ctcp(message)

        if ctcp_message:
            if (not ctcp_message.command == "ACTION" or not
                    event["line"].command == "PRIVMSG"):
                if event["line"].command == "PRIVMSG":
                    ctcp_action = "request"
                else:
                    ctcp_action = "response"
                events.on(direction).on("ctcp").on(ctcp_action).call(
                    message=ctcp_message.message, **kwargs)
                events.on(direction).on("ctcp").on(ctcp_action).on(
                    ctcp_message.command).call(message=ctcp_message.message,
                    **kwargs)
                return
            else:
                message = ctcp_message.message
                action = True

    if not message == None:
        kwargs["message"] = message
        kwargs["message_split"] = message.split(" ")
        kwargs["action"] = action

    event_type = event["line"].command.lower()
    if event_type == "privmsg":
        event_type = "message"

    context = "channel" if is_channel else "private"
    hook = events.on(direction).on(event_type).on(context)

    buffer_line = None
    if message:
        buffer_line = IRCBuffer.BufferLine(user.nickname, message, action,
            event["line"].tags, from_self, event["line"].command)

    buffer_obj = target_obj
    if is_channel:
        hook.call(channel=target_obj, buffer_line=buffer_line, **kwargs)
    else:
        buffer_obj = target_obj
        if not from_self:
            buffer_obj = user

        hook.call(buffer_line=buffer_line, **kwargs)

    if buffer_line:
        buffer_obj.buffer.add(buffer_line)
Esempio n. 25
0
 def _tagmsg(self, target, state):
     return IRCLine.ParsedLine("TAGMSG", [target],
                               tags={
                                   "+typing": state,
                                   "+draft/typing": state
                               })
Esempio n. 26
0
 def _(target, message, tags):
     return IRCLine.ParsedLine(command, [target, message], tags=tags)
Esempio n. 27
0
def seperate_hostmask(hostmask: str) -> IRCLine.Hostmask:
    nickname, _, username = hostmask.partition("!")
    username, _, hostname = username.partition("@")
    return IRCLine.Hostmask(nickname, username, hostname, hostmask)
Esempio n. 28
0
 def new_line(self, command: str, args: typing.List[str]=None,
         tags: typing.Dict[str, str]=None) -> IRCLine.SendableLine:
     return IRCLine.SendableLine(command, args or [],
         len((":%s " % self.hostmask()).encode("utf8")), tags)
Esempio n. 29
0
 def send_raw(self, line: str):
     return self.send(IRCLine.parse_line(line))
Esempio n. 30
0
 def _post_read(self, lines: typing.List[str]):
     for line in lines:
         self.bot.log.debug("%s (raw recv) | %s", [str(self), line])
         self.events.on("raw.received").call_unsafe(server=self,
             line=IRCLine.parse_line(line))
         self.check_users()