Exemple #1
0
    def nicks(self, irc, msg, args, channel):
        """[<channel>]

        Returns the nicks of the people in the linked channels.
        <channel> is only necessary if the message
        isn't sent on the channel itself."""
        for relay in self.relays:
            if relay.sourceChannel == channel and \
                    relay.sourceNetwork == irc.network:
                if not world.getIrc(relay.targetNetwork):
                    irc.reply(_('Not connected to network %s.') %
                              relay.targetNetwork)
                else:
                    users = []
                    ops = []
                    halfops = []
                    voices = []
                    normals = []
                    numUsers = 0
                    target = relay.targetChannel

                    channels = world.getIrc(relay.targetNetwork).state.channels
                    found = False
                    for key, channel_ in channels.items():
                        if re.match(relay.targetChannel, key):
                            found = True
                            break
                    if not found:
                        continue

                    for s in channel_.users:
                        s = s.strip()
                        if not s:
                            continue
                        numUsers += 1
                        if s in channel_.ops:
                            users.append('@%s' % s)
                        elif s in channel_.halfops:
                            users.append('%%%s' % s)
                        elif s in channel_.voices:
                            users.append('+%s' % s)
                        else:
                            users.append(s)
                    #utils.sortBy(ircutils.toLower, ops)
                    #utils.sortBy(ircutils.toLower, halfops)
                    #utils.sortBy(ircutils.toLower, voices)
                    #utils.sortBy(ircutils.toLower, normals)
                    users.sort()
                    msg.tag('relayedMsg')
                    s = _('%d users in %s on %s:  %s') % (numUsers,
                            relay.targetChannel,
                            relay.targetNetwork,
                            utils.str.commaAndify(users))
                    irc.reply(s)
        irc.noReply()
Exemple #2
0
    def nicks(self, irc, msg, args, channel):
        """[<channel>]

        Returns the nicks of the people in the linked channels.
        <channel> is only necessary if the message
        isn't sent on the channel itself."""
        for relay in self.relays:
            if relay.sourceChannel == channel and \
                    relay.sourceNetwork.lower() == irc.network.lower():
                if not world.getIrc(relay.targetNetwork):
                    irc.reply(
                        _('Not connected to network %s.') %
                        relay.targetNetwork)
                else:
                    users = []
                    ops = []
                    halfops = []
                    voices = []
                    normals = []
                    numUsers = 0
                    target = relay.targetChannel

                    channels = world.getIrc(relay.targetNetwork).state.channels
                    found = False
                    for key, channel_ in channels.items():
                        if re.match(relay.targetChannel, key):
                            found = True
                            break
                    if not found:
                        continue

                    for s in channel_.users:
                        s = s.strip()
                        if not s:
                            continue
                        numUsers += 1
                        if s in channel_.ops:
                            users.append('@%s' % s)
                        elif s in channel_.halfops:
                            users.append('%%%s' % s)
                        elif s in channel_.voices:
                            users.append('+%s' % s)
                        else:
                            users.append(s)
                    #utils.sortBy(ircutils.toLower, ops)
                    #utils.sortBy(ircutils.toLower, halfops)
                    #utils.sortBy(ircutils.toLower, voices)
                    #utils.sortBy(ircutils.toLower, normals)
                    users.sort()
                    msg.tag('relayedMsg')
                    s = _('%d users in %s on %s:  %s') % (
                        numUsers, relay.targetChannel, relay.targetNetwork,
                        utils.str.commaAndify(users))
                    irc.reply(s)
        irc.noReply()
Exemple #3
0
 def send(s):
     targetIRC = world.getIrc(relay.targetNetwork)
     if not targetIRC:
         self.log.info('LinkRelay:  Not connected to network %s.' %
                       relay.targetNetwork)
     elif targetIRC.zombie:
         self.log.info('LinkRelay:  IRC %s appears to be a zombie'%
                       relay.targetNetwork)
     elif irc.isChannel(relay.targetChannel) and \
             relay.targetChannel not in targetIRC.state.channels:
         self.log.info('LinkRelay:  I\'m not in in %s on %s' %
                       (relay.targetChannel, relay.targetNetwork))
     else:
         if isPrivmsg or \
                 self.registryValue('nonPrivmsgs', channel) == 'privmsg':
             f = ircmsgs.privmsg
         elif self.registryValue('nonPrivmsgs', channel) == 'notice':
             f = ircmsgs.notice
         else:
             return
         allowedLength = conf.get(conf.supybot.reply.mores.length,
                  relay.targetChannel) or 470
         cont = _('(continuation)')
         remainingLength = allowedLength - len(cont) - 1
         head = s[0:allowedLength]
         tail = [cont + ' ' + s[i:i+remainingLength] for i in
                 range(allowedLength, len(s), remainingLength)]
         for s in [head] + tail:
             msg = f(relay.targetChannel, s)
             msg.tag('relayedMsg')
             targetIRC.sendMsg(msg)
Exemple #4
0
 def send(s):
     targetIRC = world.getIrc(relay.targetNetwork)
     if not targetIRC:
         self.log.info('LinkRelay:  Not connected to network %s.' %
                       relay.targetNetwork)
     elif targetIRC.zombie:
         self.log.info('LinkRelay:  IRC %s appears to be a zombie' %
                       relay.targetNetwork)
     elif irc.isChannel(relay.targetChannel) and \
             relay.targetChannel not in targetIRC.state.channels:
         self.log.info('LinkRelay:  I\'m not in in %s on %s' %
                       (relay.targetChannel, relay.targetNetwork))
     else:
         if isPrivmsg or \
                 self.registryValue('nonPrivmsgs', channel) == 'privmsg':
             f = ircmsgs.privmsg
         elif self.registryValue('nonPrivmsgs', channel) == 'notice':
             f = ircmsgs.notice
         else:
             return
         allowedLength = conf.get(conf.supybot.reply.mores.length,
                                  relay.targetChannel) or 470
         cont = _('(continuation)')
         remainingLength = allowedLength - len(cont) - 1
         head = s[0:allowedLength]
         tail = [
             cont + ' ' + s[i:i + remainingLength]
             for i in range(allowedLength, len(s), remainingLength)
         ]
         for s in [head] + tail:
             msg = f(relay.targetChannel, s)
             msg.tag('relayedMsg')
             targetIRC.sendMsg(msg)
Exemple #5
0
 def _getIrc(self, network):
     irc = world.getIrc(network)
     if irc:
         return irc
     else:
         raise callbacks.Error('I\'m not currently connected to %s.' %
                               network)
Exemple #6
0
    def doPost(self, handler, path, form):
        headers = dict(self.headers)

        network = None
        try:
            information = path.split('/')[1:]
            network = information[0]
        except IndexError:
            self._send_error(handler, _("""Error: You need to provide the
                                        network name in the URL."""))
            return

        irc = world.getIrc(network)
        if irc is None:
            self._send_error(handler, (_('Error: Unknown network %r') % network))
            return

        # Handle payload
        payload = None
        try:
            payload = json.JSONDecoder().decode(form.decode('utf-8'))
        except Exception as e:
            self.log.info(e)
            self._send_error(handler, _('Error: Invalid JSON data sent.'))
            return

        try:
            self.gitlab.handle_payload(headers, payload, irc)
        except Exception as e:
            self.log.info(e)
            self._send_error(handler, _('Error: Invalid data sent.'))
            return

        # Return OK
        self._send_ok(handler)
Exemple #7
0
    def list(self, irc, msg, args):
        """takes no arguments

        Returns all the defined relay links"""
        if not self.relays:
            irc.reply(_('This is no relay enabled. Use "linkrelay add" to '
                'add one.'))
            return
        replies = []
        for relay in self.relays:
            if world.getIrc(relay.targetNetwork):
                hasIRC = 'Link healthy!'
            else:
                hasIRC = '\x03%sNot connected to network.\017' % \
                        self.registryValue('colors.info', msg.args[0])
            s ='\x02%s\x02 on \x02%s\x02 ==> \x02%s\x02 on \x02%s\x02.  %s'
            if not self.registryValue('color', msg.args[0]):
                s = s.replace('\x02', '')
            replies.append(s %
                        (relay.sourceChannel,
                         relay.sourceNetwork,
                         relay.targetChannel,
                         relay.targetNetwork,
                         hasIRC))
        irc.replies(replies)
Exemple #8
0
 def _getIrc(self, network):
     irc = world.getIrc(network)
     if irc:
         return irc
     else:
         raise callbacks.Error, \
               'I\'m not currently connected to %s.' % network
Exemple #9
0
    def list(self, irc, msg, args):
        """takes no arguments

        Returns all the defined relay links"""
        if not self.relays:
            irc.reply(_('This is no relay enabled. Use "linkrelay add" to '
                'add one.'))
            return
        replies = []
        for relay in self.relays:
            if world.getIrc(relay.targetNetwork):
                hasIRC = 'Link healthy!'
            else:
                hasIRC = '\x03%sNot connected to network.\017' % \
                        self.registryValue('colors.info', msg.args[0])
            s ='\x02%s\x02 on \x02%s\x02 ==> \x02%s\x02 on \x02%s\x02.  %s'
            if not self.registryValue('color', msg.args[0]):
                s = s.replace('\x02', '')
            replies.append(s %
                        (relay.sourceChannel,
                         relay.sourceNetwork,
                         relay.targetChannel,
                         relay.targetNetwork,
                         hasIRC))
        irc.replies(replies)
Exemple #10
0
 def onPayload(self, headers, payload):
     if 'reply_env' not in ircmsgs.IrcMsg.__slots__:
         log.error("Got event payload from GitHub, but your version "
                   "of Supybot is not compatible with reply "
                   "environments, so, the GitHub plugin can't "
                   "announce it.")
     if 'full_name' in payload['repository']:
         repo = payload['repository']['full_name']
     elif 'name' in payload['repository']['owner']:
         repo = '%s/%s' % (payload['repository']['owner']['name'],
                           payload['repository']['name'])
     else:
         repo = '%s/%s' % (payload['repository']['owner']['login'],
                           payload['repository']['name'])
     event = headers['X-GitHub-Event']
     announces = self._load()
     repoAnnounces = []
     for (dbRepo, network, channel) in announces:
         if dbRepo == repo:
             repoAnnounces.append((network, channel))
     if len(repoAnnounces) == 0:
         log.info('Commit for repo %s not announced anywhere' % repo)
         return
     for (network, channel) in repoAnnounces:
         # Compatability with DBs without a network
         if network == '':
             for irc in world.ircs:
                 if channel in irc.state.channels:
                     break
         else:
             irc = world.getIrc(network)
             if not irc:
                 log.warning('Received GitHub payload with announcing '
                             'enabled in %s on unloaded network %s.',
                             channel, network)
                 return
         if channel not in irc.state.channels:
             log.info(('Cannot announce event for repo '
                      '%s in %s on %s because I\'m not in %s.') %
                      (repo, channel, irc.network, channel))
         if event == 'push':
             commits = payload['commits']
             if len(commits) == 0:
                 log.warning('GitHub push hook called without any commit.')
             else:
                 hidden = None
                 last_commit = commits[-1]
                 if last_commit['message'].startswith('Merge ') and \
                         len(commits) > 5:
                     hidden = len(commits) + 1
                     commits = [last_commit]
                 payload2 = dict(payload)
                 for commit in commits:
                     payload2['__commit'] = commit
                     self._createPrivmsg(irc, channel, payload2,
                             'push', hidden)
         else:
             self._createPrivmsg(irc, channel, payload, event)
Exemple #11
0
 def f():
     # If the network isn't available, pick any other one
     irc = world.getIrc(network) or world.ircs[0]
     tokens = callbacks.tokenize(command,
                                 channel=msg.channel,
                                 network=irc.network)
     if remove:
         del self.events[str(f.eventId)]
     self.Proxy(irc, msg, tokens)
Exemple #12
0
    def _forwardRequest(self, irc, msg, code):
        freeNode = world.getIrc("FreeNode")
        if not freeNode:
            irc.reply("not connected to geordi yet")
            return

        irc.noReply()
        self._replyIrc = irc
        self._replyMsg = msg

        freeNode.queueMsg(ircmsgs.privmsg("geordi", code))
Exemple #13
0
 def _inchannel(self, irc, channel):
     """
     Returns whether or not the bot is in <channel> on network <irc>,
     which can be either the name of the network or its IrcObj.
     """
     # If <irc> is a string and not an IrcObj, get the IrcObj that
     # matches it, returning False if it wasn't found.
     if isinstance(irc, str):
         irc = world.getIrc(irc)
         if not irc:
             return False
     for inchannel in irc.state.channels.keys():
         if channel.lower() == inchannel.lower():
             return True
     return False
Exemple #14
0
 def _garbagecollect(self, force=False):
     """
     Removes stale activity data.
     """
     if time.time() - self.lastgc < (60 * self.gcinterval) and not force:
         return
     for channel, times in self.times.items():
         irc = world.getIrc(channel[0])
         if not irc or time.time() - times[-1] >= 3600 * 6:
             try:
                 del self.times[channel]
             except KeyError:
                 pass
     self._writeactivityfile()
     self.lastgc = time.time()
Exemple #15
0
    def handle_message(self, path, data):
        try:
            network, channel = urllib.parse.unquote(path[1:]).split('.', 1)
        except:
            raise ValueError("Must pass network.channel as argument")

        irc = world.getIrc(network)
        if not irc:
            raise ValueError("Unknown IRC network %s" % network)

        if not ircutils.isChannel(channel):
            raise ValueError("Wrong IRC channel name %s" % channel)

        if channel not in irc.state.channels:
            raise ValueError("Bot not joined to channel %s" % channel)

        irc.queueMsg(ircmsgs.privmsg(channel, self.format_msg(data)))
Exemple #16
0
 def _sendmsg(self, irc, text, channel=None):
     """
     Send <text> to <channel> on network <irc>.  If <irc> is a list of
     sources, iterate through it and send <text> to each channel on
     network.
     """
     if not isinstance(irc, list):
         if not self._inchannel(irc, channel):
             return False
         msg = ircmsgs.privmsg(channel, text, irc.prefix)
         msg.tag('relayed', True)
         irc.sendMsg(msg)
         return True
     else:
         successful = []
         for source in irc:
             target = world.getIrc(source[0])
             if target and self._sendmsg(target, text, source[1]):
                 successful.append(source)
         return successful
Exemple #17
0
    def _readRelays(self):
        relays = []
        path = dbPath()

        if not os.path.isfile(path):
            return relays

        with open(path) as fd:
            for (i, line) in enumerate(fd):
                try:
                    (network, channel, skype_chat_id) = line.split()
                except ValueError:
                    self.log.error("Skipping invalid line %i in %s: %s", i,
                                   path, line)
                irc = world.getIrc(network)
                if irc is None:
                    self.log.warning("Unknown network %s", network)
                elif not irc.isChannel(channel):
                    self.log.warning("Invalid channel %s", channel)
                relays.append(Relay(network, channel, skype_chat_id))

        return relays
Exemple #18
0
        def onPayload(self, headers, payload):
            if 'reply_env' not in ircmsgs.IrcMsg.__slots__:
                log.error("Got event payload from GitHub, but your version "
                          "of Supybot is not compatible with reply "
                          "environments, so, the GitHub plugin can't "
                          "announce it.")
            if 'full_name' in payload['repository']:
                repo = payload['repository']['full_name']
            elif 'name' in payload['repository']['owner']:
                repo = '%s/%s' % (payload['repository']['owner']['name'],
                                  payload['repository']['name'])
            else:
                repo = '%s/%s' % (payload['repository']['owner']['login'],
                                  payload['repository']['name'])
            if 'X-GitHub-Event' in headers:
                event = headers['X-GitHub-Event']
            else:
                # WTF?
                event = headers['x-github-event']
            announces = self._load()
            repoAnnounces = []
            for (dbRepo, network, channel) in announces:
                if fnmatch.fnmatch(repo, dbRepo):
                    repoAnnounces.append((network, channel))
            if len(repoAnnounces) == 0:
                log.info('Commit for repo %s not announced anywhere' % repo)
                return
            for (network, channel) in repoAnnounces:
                # Compatability with DBs without a network
                if network == '':
                    for irc in world.ircs:
                        if channel in irc.state.channels:
                            break
                else:
                    irc = world.getIrc(network)
                    if not irc:
                        log.warning('Received GitHub payload with announcing '
                                    'enabled in %s on unloaded network %s.',
                                    channel, network)
                        return
                if channel not in irc.state.channels:
                    log.info(('Cannot announce event for repo '
                             '%s in %s on %s because I\'m not in %s.') %
                             (repo, channel, irc.network, channel))
                if event == 'push':
                    commits = payload['commits']
                    hidden = None
                    if len(commits) == 0:
                        log.warning('GitHub push hook called without any commit.')
                    else:
                        last_commit = commits[-1]

                        max_comm = self.plugin.registryValue(
                                'max_announce_commits', channel)

                        if len(commits) > max_comm + 1:
                            # Limit to the specified number of commits,
                            # but if there's only one more, show it
                            hidden = len(commits) - max_comm
                            commits = commits[:max_comm]

                    payload2 = dict(payload)

                    self._createPrivmsg(irc, channel, payload2, 'before.push')

                    for commit in commits:
                        payload2['__commit'] = commit
                        self._createPrivmsg(irc, channel, payload2, 'push')

                    if hidden:
                        payload2['__hidden_commits'] = hidden
                        self._createPrivmsg(irc, channel, payload2,
                                'push.hidden')
                elif event == 'gollum':
                    pages = payload['pages']
                    if len(pages) == 0:
                        log.warning('GitHub gollum hook called without any page.')
                    else:
                        payload2 = dict(payload)
                        for page in pages:
                            payload2['__page'] = page
                            self._createPrivmsg(irc, channel, payload2, 'gollum')
                else:
                    self._createPrivmsg(irc, channel, payload, event)
Exemple #19
0
 def send_msg(self, channel, text):
     irc = world.getIrc(self.registryValue('adminNet'))
     irc.queueMsg(ircmsgs.privmsg(channel, text))
     log.info("Sent Message: \"{}\" to '{}'".format(text, channel))
Exemple #20
0
 def _send(self, network, nick, text):
     irc = world.getIrc(network)
     if irc:
         irc.queueMsg(ircmsgs.privmsg(nick, text))
Exemple #21
0
 def f():
     # If the network isn't available, pick any other one
     irc = world.getIrc(network) or world.ircs[0]
     replyIrc = callbacks.ReplyIrcProxy(irc, msg)
     replyIrc.reply(_('Reminder: %s') % text, msg=msg, prefixNick=True)
     del self.events[str(f.eventId)]
Exemple #22
0
 def onPayload(self, headers, payload):
     if 'reply_env' not in ircmsgs.IrcMsg.__slots__:
         log.error("Got event payload from GitHub, but your version "
                   "of Supybot is not compatible with reply "
                   "environments, so, the GitHub plugin can't "
                   "announce it.")
     if 'full_name' in payload['repository']:
         repo = payload['repository']['full_name']
     elif 'name' in payload['repository']['owner']:
         repo = '%s/%s' % (payload['repository']['owner']['name'],
                           payload['repository']['name'])
     else:
         repo = '%s/%s' % (payload['repository']['owner']['login'],
                           payload['repository']['name'])
     if 'X-GitHub-Event' in headers:
         event = headers['X-GitHub-Event']
     else:
         # WTF?
         event = headers['x-github-event']
     announces = self._load()
     repoAnnounces = []
     for (dbRepo, network, channel) in announces:
         if fnmatch.fnmatch(repo, dbRepo):
             repoAnnounces.append((network, channel))
     if len(repoAnnounces) == 0:
         log.info('Commit for repo %s not announced anywhere' % repo)
         return
     for (network, channel) in repoAnnounces:
         # Compatability with DBs without a network
         if network == '':
             for irc in world.ircs:
                 if channel in irc.state.channels:
                     break
         else:
             irc = world.getIrc(network)
             if not irc:
                 log.warning('Received GitHub payload with announcing '
                             'enabled in %s on unloaded network %s.',
                             channel, network)
                 return
         if channel not in irc.state.channels:
             log.info(('Cannot announce event for repo '
                      '%s in %s on %s because I\'m not in %s.') %
                      (repo, channel, irc.network, channel))
         if event == 'push':
             commits = payload['commits']
             if len(commits) == 0:
                 log.warning('GitHub push hook called without any commit.')
             else:
                 hidden = None
                 last_commit = commits[-1]
                 if last_commit['message'].startswith('Merge ') and \
                         len(commits) > 5:
                     hidden = len(commits) + 1
                     commits = [last_commit]
                 payload2 = dict(payload)
                 for commit in commits:
                     # trim the commit hash down to 7 char long
                     if len(commit['id']) > 7:
                          commit['id'] = commit['id'][:-33]
                     payload2['__commit'] = commit
                     self._createPrivmsg(irc, channel, payload2,
                             'push', hidden)
         elif event == 'commit_comment':
             # Here we get the commit name
             commit_url = 'https://api.github.com/repos/%s/git/commits/%s' % (payload['repository']['full_name'],
                                                                          payload['comment']['commit_id'])
             response = urllib.urlopen(commit_url);
             data = json.loads(response.read())
             commit_name = data['message']
             payload['comment']['commit_name'] = commit_name
             self._createPrivmsg(irc, channel, payload, event)
         else:
             self._createPrivmsg(irc, channel, payload, event)
Exemple #23
0
 def _announce_build_status(self, status):
     msg = '\x02[Nightly builds]\x02 %s' % status
     for (server, channel) in (('freenode', '#limnoria'),):
         world.getIrc(server).sendMsg(ircmsgs.privmsg(channel, msg))
Exemple #24
0
    def relay(self, irc, msg, channel=None):
        channel = (channel or msg.args[0]).lower()
        self.log.debug("RelayNext (%s): got channel %s", irc.network, channel)
        if not channel in irc.state.channels:
            return

        # Check for ignored events first. Checking for "'.' not in msg.nick" is for skipping
        # ignore checks from servers.
        ignoredevents = map(str.upper, self.registryValue('events.userIgnored', channel))
        if msg.command in ignoredevents and msg.nick != irc.nick and '.' not in msg.nick and\
                ircdb.checkIgnored(msg.prefix, channel):
            self.log.debug("RelayNext (%s): ignoring message from %s",
                           irc.network, msg.prefix)
            return

        # Get the source channel
        source = "%s@%s" % (channel, irc.network)
        source = source.lower()

        out_s = self._format(irc, msg, channel)
        if out_s:
            for relay in self.db.values():
                self.log.debug("RelayNext (%s): check if %s in %s", irc.network, source, relay)
                if source in relay:  # If our channel is in a relay
                    self.log.debug("RelayNext: found %s to be in relay %s", source, relay)

                    # Remove ourselves from the target channels so we don't get duplicated messages
                    targets = list(relay)
                    targets.remove(source)

                    self.log.debug("RelayNext: found targets %s for relay %s", targets, relay)

                    if self.registryValue("antiflood.enable", channel):
                        # Flood prevention timeout - how long commands of a certain type
                        # should cease being relayed after flood prevention triggers
                        timeout = self.registryValue("antiflood.timeout", channel)

                        # If <maximum> messages of the same kind on one channel is
                        # received in <seconds> seconds, flood prevention timeout is
                        # triggered.
                        maximum = self.registryValue("antiflood.maximum", channel)
                        seconds = self.registryValue("antiflood.seconds", channel)

                        # Store the message in a counter, with the keys taking the
                        # form of (source channel@network, command name). If the counter
                        # doesn't already exist, create one here.
                        try:
                            self.msgcounters[(source, msg.command)].enqueue(msg.prefix)
                        except KeyError:
                            self.msgcounters[(source, msg.command)] = TimeoutQueue(seconds)

                        # Two different limits: one for messages and one for all others
                        if msg.command == "PRIVMSG":
                            maximum = self.registryValue("antiflood.maximum", channel)
                        else:
                            maximum = self.registryValue("antiflood.maximum.nonPrivmsgs",
                                                         channel)

                        if len(self.msgcounters[(source, msg.command)]) > maximum:
                            # Amount of messages in the counter surpassed our limit,
                            # announce the flood and block relaying messages of the
                            # same type for X seconds
                            self.log.debug("RelayNext (%s): message from %s blocked by "
                                           "flood protection.", irc.network, channel)

                            if self.floodTriggered.get((source, msg.command)):
                                # However, only send the announcement once.
                                return

                            c = msg.command
                            e = format("Flood detected on %s (%s %ss/%s seconds), "
                                       "not relaying %ss for %s seconds!", channel,
                                       maximum, c, seconds, c, timeout)
                            out_s = self._format(irc, msg, channel, announcement=e)

                            self.floodTriggered[(source, msg.command)] = True
                            self.log.info("RelayNext (%s): %s", irc.network, e)
                        else:
                            self.floodTriggered[(source, msg.command)] = False

                    for cn in targets:
                        # Iterate over all the relay targets for this message:
                        # each target is stored internally as a #channel@netname
                        # string.
                        target, net = cn.split("@")
                        otherIrc = world.getIrc(net)
                        if otherIrc is None:
                            self.log.debug("RelayNext: message to network %r"
                                           " dropped, we are not connected "
                                           "there!", net)
                            return

                        target_chanobj = otherIrc.state.channels.get(target)
                        if (not target_chanobj) or otherIrc.nick not in target_chanobj.users:
                            # We're not in the target relay channel!
                            self.log.debug("RelayNext: message to %s@%s "
                                           "dropped, we are not in that "
                                           "channel!", target, net)
                        else:
                            out_msg = ircmsgs.privmsg(target, out_s)

                            # Tag the message as relayed so we (and other relayers) don't
                            # try to relay it again.
                            out_msg.tag('relayedMsg')
                            otherIrc.queueMsg(out_msg)
Exemple #25
0
    def nicks(self, irc, msg, args, channel, optlist):
        """[<channel>] [--count]
        Returns the nicks of the people in the linked channels.
        <channel> is only necessary if the message isn't sent in the channel
        itself.
        If --count is specified, only the amount of users in the relay is given."""
        opts = dict(optlist)

        if irc.nested and 'count' not in keys:
            irc.error('This command cannot be nested.', Raise=True)

        try:
            c = irc.state.channels[channel]
        except KeyError:
            irc.error("Unknown channel '%s'." % channel, Raise=True)

        if msg.nick not in c.users:
            self.log.warning('RelayNext: %s on %s attempted to view '
                             'nicks of %s without being in it.', msg.nick,
                             irc.network, channel)
            irc.error(("You are not in '%s'." % channel), Raise=True)

        source = "%s@%s" % (channel, irc.network)
        source = source.lower()
        channel_count = 0
        user_count = 0
        all_users = []

        # First, enumerate all the relays that the calling channel is it. Use a
        # set to prevent duplicates since one channel can be part of many relays.
        all_relays = set()
        for relay in self.db.values():
            if source in relay:
                for channelpair in relay:
                    # Each channel pair is a "#chan@net" string in the DB.
                    all_relays.add(channelpair)

        for channelpair in all_relays:
            channel_count += 1
            channel, net = channelpair.split("@", 1)
            try:
                c = world.getIrc(net).state.channels[channel]
            except (KeyError, AttributeError):
                # Unknown network or network disconnected.
                continue
            user_count += len(c.users)
            users = []

            # Sort users before listing them, but do so case-insensitively.
            for s in sorted(c.users, key=ircutils.toLower):
                s = s.strip()
                if s in c.ops:
                    users.append('@%s' % s)
                elif s in c.halfops:
                    users.append('%%%s' % s)
                elif s in c.voices:
                    users.append('+%s' % s)
                else:
                    users.append(s)

            all_users += c.users
            s = format('%s users in %s on %s: %L', len(c.users),
                       channel, net, users)

            # In outputting the user list, we need to make sure that the message fits,
            # and if not, wrap it into multiple messages.
            # XXX: This is ugly, but https://github.com/ProgVal/Limnoria/issues/1080
            # means we have to chop off the (XX more messages) part too.
            allowed_length = 466 - len(irc.prefix) - len(irc.nick) - len(msg.nick) - \
                len(_('(XX more messages)'))
            replies = textwrap.wrap(s, allowed_length)

            if 'count' not in opts:
                # Only bother doing this if we're not using --count.
                irc.reply(replies[0], private=True, notice=True)
                for s in replies[1:]:
                    irc.reply("... %s" % s, private=True, notice=True)

        if 'count' in opts:  # --count was specified; just reply with the amount of users.
            irc.reply(user_count)
        elif channel_count:
            irc.reply("Total users across %d channels: %d. Unique nicks: %d" %
                      (channel_count, user_count, len(set(all_users))),
                      private=True)
        else:
            irc.error("No relays for '%s' exist." % channel)
Exemple #26
0
 def _queueRelayedMsg(self, relay, s):
     msg = ircmsgs.privmsg(relay.channel, s)
     msg.tag("relayedMsg")
     world.getIrc(relay.network).queueMsg(msg)
Exemple #27
0
        def onPayload(self, headers, payload):
            if 'reply_env' not in ircmsgs.IrcMsg.__slots__:
                log.error("Got event payload from GitHub, but your version "
                          "of Supybot is not compatible with reply "
                          "environments, so, the GitHub plugin can't "
                          "announce it.")
            if 'full_name' in payload['repository']:
                repo = payload['repository']['full_name']
            elif 'name' in payload['repository']['owner']:
                repo = '%s/%s' % (payload['repository']['owner']['name'],
                                  payload['repository']['name'])
            else:
                repo = '%s/%s' % (payload['repository']['owner']['login'],
                                  payload['repository']['name'])
            if 'X-GitHub-Event' in headers:
                event = headers['X-GitHub-Event']
            else:
                # WTF?
                event = headers['x-github-event']
            announces = self._load()
            repoAnnounces = []
            for (dbRepo, network, channel) in announces:
                if fnmatch.fnmatch(repo, dbRepo):
                    repoAnnounces.append((network, channel))
            if len(repoAnnounces) == 0:
                log.info('Commit for repo %s not announced anywhere' % repo)
                return
            for (network, channel) in repoAnnounces:
                # Compatability with DBs without a network
                if network == '':
                    for irc in world.ircs:
                        if channel in irc.state.channels:
                            break
                else:
                    irc = world.getIrc(network)
                    if not irc:
                        log.warning(
                            'Received GitHub payload with announcing '
                            'enabled in %s on unloaded network %s.', channel,
                            network)
                        return
                if channel not in irc.state.channels:
                    log.info(('Cannot announce event for repo '
                              '%s in %s on %s because I\'m not in %s.') %
                             (repo, channel, irc.network, channel))
                if event == 'push':
                    commits = payload['commits']
                    if len(commits) == 0:
                        log.warning(
                            'GitHub push hook called without any commit.')
                    else:
                        hidden = None
                        last_commit = commits[-1]
                        if last_commit['message'].startswith('Merge ') and \
                                len(commits) > 5:
                            hidden = len(commits) + 1
                            commits = [last_commit]

                    payload2 = dict(payload)

                    self._createPrivmsg(irc, channel, payload2, 'before.push',
                                        None)

                    for commit in commits:
                        payload2['__commit'] = commit
                        self._createPrivmsg(irc, channel, payload2, 'push',
                                            hidden)
                elif event == 'gollum':
                    pages = payload['pages']
                    if len(pages) == 0:
                        log.warning(
                            'GitHub gollum hook called without any page.')
                    else:
                        payload2 = dict(payload)
                        for page in pages:
                            payload2['__page'] = page
                            self._createPrivmsg(irc, channel, payload2,
                                                'gollum', None)
                else:
                    self._createPrivmsg(irc, channel, payload, event)
Exemple #28
0
    def nicks(self, irc, msg, args, channel, optlist):
        """[<channel>] [--count]
        Returns the nicks of the people in the linked channels.
        <channel> is only necessary if the message isn't sent in the channel
        itself.
        If --count is specified, only the amount of users in the relay is given."""
        opts = dict(optlist)

        if irc.nested and 'count' not in keys:
            irc.error('This command cannot be nested.', Raise=True)

        try:
            c = irc.state.channels[channel]
        except KeyError:
            irc.error("Unknown channel '%s'." % channel, Raise=True)

        if msg.nick not in c.users:
            self.log.warning(
                'RelayNext: %s on %s attempted to view '
                'nicks of %s without being in it.', msg.nick, irc.network,
                channel)
            irc.error(("You are not in '%s'." % channel), Raise=True)

        source = "%s@%s" % (channel, irc.network)
        source = source.lower()
        channel_count = 0
        user_count = 0
        all_users = []

        # First, enumerate all the relays that the calling channel is it. Use a
        # set to prevent duplicates since one channel can be part of many relays.
        all_relays = set()
        for relay in self.db.values():
            if source in relay:
                for channelpair in relay:
                    # Each channel pair is a "#chan@net" string in the DB.
                    all_relays.add(channelpair)

        for channelpair in all_relays:
            channel_count += 1
            channel, net = channelpair.split("@", 1)
            try:
                c = world.getIrc(net).state.channels[channel]
            except (KeyError, AttributeError):
                # Unknown network or network disconnected.
                continue
            user_count += len(c.users)
            users = []

            # Sort users before listing them, but do so case-insensitively.
            for s in sorted(c.users, key=ircutils.toLower):
                s = s.strip()
                if s in c.ops:
                    users.append('@%s' % s)
                elif s in c.halfops:
                    users.append('%%%s' % s)
                elif s in c.voices:
                    users.append('+%s' % s)
                else:
                    users.append(s)

            all_users += c.users
            s = format('%s users in %s on %s: %L', len(c.users), channel, net,
                       users)

            # In outputting the user list, we need to make sure that the message fits,
            # and if not, wrap it into multiple messages.
            # XXX: This is ugly, but https://github.com/ProgVal/Limnoria/issues/1080
            # means we have to chop off the (XX more messages) part too.
            allowed_length = 466 - len(irc.prefix) - len(irc.nick) - len(msg.nick) - \
                len(_('(XX more messages)'))
            replies = textwrap.wrap(s, allowed_length)

            if 'count' not in opts:
                # Only bother doing this if we're not using --count.
                irc.reply(replies[0], private=True, notice=True)
                for s in replies[1:]:
                    irc.reply("... %s" % s, private=True, notice=True)

        if 'count' in opts:  # --count was specified; just reply with the amount of users.
            irc.reply(user_count)
        elif channel_count:
            irc.reply("Total users across %d channels: %d. Unique nicks: %d" %
                      (channel_count, user_count, len(set(all_users))),
                      private=True)
        else:
            irc.error("No relays for '%s' exist." % channel)
Exemple #29
0
    def relay(self, irc, msg, channel=None):
        channel = (channel or msg.args[0]).lower()
        self.log.debug("RelayNext (%s): got channel %s", irc.network, channel)
        if not channel in irc.state.channels:
            return

        # Check for ignored events first. Checking for "'.' not in msg.nick" is for skipping
        # ignore checks from servers.
        ignoredevents = map(str.upper,
                            self.registryValue('events.userIgnored', channel))
        if msg.command in ignoredevents and msg.nick != irc.nick and '.' not in msg.nick and\
                ircdb.checkIgnored(msg.prefix, channel):
            self.log.debug("RelayNext (%s): ignoring message from %s",
                           irc.network, msg.prefix)
            return

        # Get the source channel
        source = "%s@%s" % (channel, irc.network)
        source = source.lower()

        out_s = self._format(irc, msg, channel)
        if out_s:
            for relay in self.db.values():
                self.log.debug("RelayNext (%s): check if %s in %s",
                               irc.network, source, relay)
                if source in relay:  # If our channel is in a relay
                    self.log.debug("RelayNext: found %s to be in relay %s",
                                   source, relay)

                    # Remove ourselves from the target channels so we don't get duplicated messages
                    targets = list(relay)
                    targets.remove(source)

                    self.log.debug("RelayNext: found targets %s for relay %s",
                                   targets, relay)

                    if self.registryValue("antiflood.enable", channel):
                        # Flood prevention timeout - how long commands of a certain type
                        # should cease being relayed after flood prevention triggers
                        timeout = self.registryValue("antiflood.timeout",
                                                     channel)

                        # If <maximum> messages of the same kind on one channel is
                        # received in <seconds> seconds, flood prevention timeout is
                        # triggered.
                        maximum = self.registryValue("antiflood.maximum",
                                                     channel)
                        seconds = self.registryValue("antiflood.seconds",
                                                     channel)

                        # Store the message in a counter, with the keys taking the
                        # form of (source channel@network, command name). If the counter
                        # doesn't already exist, create one here.
                        try:
                            self.msgcounters[(source,
                                              msg.command)].enqueue(msg.prefix)
                        except KeyError:
                            self.msgcounters[(
                                source, msg.command)] = TimeoutQueue(seconds)

                        # Two different limits: one for messages and one for all others
                        if msg.command == "PRIVMSG":
                            maximum = self.registryValue(
                                "antiflood.maximum", channel)
                        else:
                            maximum = self.registryValue(
                                "antiflood.maximum.nonPrivmsgs", channel)

                        if len(self.msgcounters[(source,
                                                 msg.command)]) > maximum:
                            # Amount of messages in the counter surpassed our limit,
                            # announce the flood and block relaying messages of the
                            # same type for X seconds
                            self.log.debug(
                                "RelayNext (%s): message from %s blocked by "
                                "flood protection.", irc.network, channel)

                            if self.floodTriggered.get((source, msg.command)):
                                # However, only send the announcement once.
                                return

                            c = msg.command
                            e = format(
                                "Flood detected on %s (%s %ss/%s seconds), "
                                "not relaying %ss for %s seconds!", channel,
                                maximum, c, seconds, c, timeout)
                            out_s = self._format(irc,
                                                 msg,
                                                 channel,
                                                 announcement=e)

                            self.floodTriggered[(source, msg.command)] = True
                            self.log.info("RelayNext (%s): %s", irc.network, e)
                        else:
                            self.floodTriggered[(source, msg.command)] = False

                    for cn in targets:
                        # Iterate over all the relay targets for this message:
                        # each target is stored internally as a #channel@netname
                        # string.
                        target, net = cn.split("@")
                        otherIrc = world.getIrc(net)
                        if otherIrc is None:
                            self.log.debug(
                                "RelayNext: message to network %r"
                                " dropped, we are not connected "
                                "there!", net)
                            return

                        target_chanobj = otherIrc.state.channels.get(target)
                        if (not target_chanobj
                            ) or otherIrc.nick not in target_chanobj.users:
                            # We're not in the target relay channel!
                            self.log.debug(
                                "RelayNext: message to %s@%s "
                                "dropped, we are not in that "
                                "channel!", target, net)
                        else:
                            out_msg = ircmsgs.privmsg(target, out_s)

                            # Tag the message as relayed so we (and other relayers) don't
                            # try to relay it again.
                            out_msg.tag('relayedMsg')
                            otherIrc.queueMsg(out_msg)