Пример #1
0
    def kh_putenv(self, arg0, tokens, ref):
        '''
        process an instance of putenv

        :param tokens: token list
        :param ref: instance of :class:`FileRef`
        :raise UnhandledTokenPattern: unhandled token pattern
        '''
        argument_list = []
        for tkn in tokens[1:]:
            if tkn['tokName'] == 'STRING':
                argument_list.append( tkn['tokStr'] )

        if len(argument_list) == 1:
            var, arg = utils.strip_quotes( argument_list[0].strip() ).split('=')
            arg = utils.strip_quotes(arg.strip())
            self.env.set(var, arg, self, ref)
        elif len(argument_list) == 2:
            var, arg = argument_list
            arg = utils.strip_quotes(arg.strip())
            self.env.set(var, arg)
        else:
            msg = str(ref) + reconstruct_line(tokens).strip()
            raise UnhandledTokenPattern, msg

        self.kh_shell_command(arg0, tokens, ref)
Пример #2
0
 def tokens_to_list(self):
     '''
     parse an enclosed list of tokens into a list
     
     Assume ``token_pointer`` is pointing at start terminator
     
     examples::
     
         (DESC, "motor $(P)$(M)") --> ['DESC', 'motor $(P)$(M)']
         {P,      S, BL,    T1, T2, A}  --> ['P', 'S', 'BL', 'T1', 'T2', 'A']
         {12ida1: A  "##ID" 1   2   1}  --> ['12ida1:', 'A', '##ID', '1', '2', '1']
         
         TODO: alias($(IOC):IOC_CPU_LOAD,"$(IOC):load")
 
     '''
     # first, decide the list terminators
     tok = self.getCurrentToken()
     t_start = token_key(tok)
     if t_start not in ('OP (', 'OP {'):
         msg = 'incorrect token type'
         raise ValueError, msg
     t_end = {'OP (': 'OP )', 'OP {': 'OP }'}[t_start]
     #content_names = ('NAME', 'NUMBER', 'OP', 'STRING', 'ERRORTOKEN')
     skip_list = ('COMMENT', 'NEWLINE', 'ENDMARKER', 
             #'ERRORTOKEN', 
             'INDENT', 'DEDENT')
     v = ''
     end = tok['start'][1]
     items = []
     depth = 1
     while depth>0 or token_key(tok) not in ('', t_end):
         tok = self.nextActionable(skip_list)
         key = token_key(tok)
         if key == t_start:
             depth += 1
         elif key == t_end:
             depth -= 1
             if depth == 0:
                 break
         if tok['start'][1] == end and key != 'OP ,':
             v += tok['tokStr']
             end = tok['end'][1]
         else:
             if len(v) > 0:
                 v = utils.strip_quotes(v)
                 if len(v) == 0:  v = '""'
                 items.append(v)
             if key not in (t_end, 'OP ,'):
                 v = tok['tokStr']
             else:
                 v=''
             end = tok['end'][1]
 
     if len(v) > 0:      # last chance
         v = utils.strip_quotes(v)
         if len(v) == 0:  v = '""'
         items.append(v)
 
     return items
def action_form(parser, token):
    arguments = token.split_contents()
    if len(arguments) > 4:
        raise template.TemplateSyntaxError, "%(tag_name)s tag takes 3 arguments at most {%% %(tag_name)s \
            [complete_title] [commit_title] [undo_title] %%}" % {"tag_name": token.contents.split()[0]}
    params = []
    if len(arguments) > 1:
        params.append(strip_quotes(arguments[1]))
    if len(arguments) > 2:
        params.append(strip_quotes(arguments[2]))
    if len(arguments) > 3:
        params.append(strip_quotes(arguments[3]))
    return ActionFormNode(*params)
Пример #4
0
 def kh_epicsEnvSet(self, arg0, tokens, ref):
     '''symbol assignment'''
     if len(tokens) == 7:
         var = tokens[2]['tokStr']
         value = tokens[4]['tokStr']
     else:
         text = utils.strip_parentheses(reconstruct_line(tokens).strip())
         parts = text.split(',')
         if len(parts) == 1:
             parts = text.split(' ')
         if len(parts) != 2:
             raise UnhandledTokenPattern('epicsEnvSet'+text)
         var, value = parts
     self.env.set(utils.strip_quotes( var ), utils.strip_quotes( value ), self, ref)
     self.kh_shell_command(arg0, tokens, ref)
Пример #5
0
def action_form(parser, token):
    arguments = token.split_contents()
    if len(arguments) > 4:
        raise template.TemplateSyntaxError, "%(tag_name)s tag takes 3 arguments at most {%% %(tag_name)s \
            [complete_title] [commit_title] [undo_title] %%}" % {
            "tag_name": token.contents.split()[0]
        }
    params = []
    if len(arguments) > 1:
        params.append(strip_quotes(arguments[1]))
    if len(arguments) > 2:
        params.append(strip_quotes(arguments[2]))
    if len(arguments) > 3:
        params.append(strip_quotes(arguments[3]))
    return ActionFormNode(*params)
Пример #6
0
    def kh_dbLoadRecords(self, arg0, tokens, ref):
        local_macros = macros.Macros(**self.env.db)
        full_line = reconstruct_line(tokens).strip()
        tokenLog = TokenLog()
        tokenLog.tokenList = tokens
        tokenLog.token_pointer = 1
        args = parse_bracketed_macro_definitions(tokenLog)
        nargs = len(args)
        if nargs not in (1, 2, 3,):
            msg = str(ref) + full_line
            raise UnhandledTokenPattern, msg
        utils.logMessage(arg0 + full_line, utils.LOGGING_DETAIL__NOISY)

        dbFileName = local_macros.replace(utils.strip_quotes(args[0]))

        if nargs in (2, 3,):    # accumulate additional macro definitions
            local_macros = self.parse_macro_args(args[1], ref, tokens, local_macros)

        if nargs in (3,):
            path = args[2]
            # msg = str(ref) + full_line
            if self.symbols.exists(path):   # substitute from symbol table
                path = self.symbols.get(path).value
            if os.path.exists(path):
                dbFileName = os.path.join(path, dbFileName)

        try:
            obj = database.Database(self, dbFileName, ref, **local_macros.db)
            self.database_list.append(obj)
            self.kh_shell_command(arg0, tokens, ref)
        except text_file.FileNotFound, _exc:
            msg = 'Could not find database file: ' + dbFileName
            utils.detailedExceptionLog(msg)
            return
async def execute(ctx, params):
    params_str = ' '.join(params)
    guild = ctx['guild']
    settings = ctx['settings']
    author = ctx['message'].author
    new_prefix = utils.strip_quotes(params_str)
    if not new_prefix:
        return False, ("You need to define a new prefix, e.g. `{}prefix avc-` to make "
                       "`avc-` the new prefix.".format(ctx['print_prefix']))
    disallowed_characters = ['\n', '\t', '`']
    for c in disallowed_characters:
        if c in new_prefix:
            return False, "Your prefix can't contain **new lines**, **tab characters**, or **\`**."
    response = ("Done! My prefix in your server is now `{0}`. Try running `{0}ping` to test it out.\n"
                "Remember, you can always mention me instead of using my prefix (e.g: **{1} ping**)"
                ".".format(new_prefix, ctx['message'].guild.me.mention))
    if len(new_prefix) == 1:
        response += ("\n\n:information_source: Note: If you use the **same prefix as another bot**, "
                     "you should also run `{}dcnf` to prevent error messages when using that bot's commands."
                     "".format(new_prefix))
    cfg.PREFIXES[guild.id] = new_prefix
    settings['prefix'] = new_prefix
    utils.set_serv_settings(guild, settings)
    await func.server_log(
        guild,
        "💬 {} (`{}`) set the server's prefix to `{}`".format(
            func.user_hash(author), author.id, new_prefix
        ), 1, settings)
    return True, response
async def execute(ctx, params):
    params_str = ' '.join(params)
    guild = ctx['guild']
    settings = ctx['settings']
    author = ctx['message'].author
    new_word = params_str.replace('\n',
                                  ' ')  # Can't have newlines in channel name.
    new_word = utils.strip_quotes(new_word)
    previous_word = ("text" if 'text_channel_name' not in settings else
                     func.esc_md(settings['text_channel_name']))
    if not new_word:
        return False, (
            "You need to define a new name, e.g. `{}textchannelname links` to make "
            "**links** shown instead of **{}**.".format(
                ctx['print_prefix'], previous_word))
    settings['text_channel_name'] = new_word
    utils.set_serv_settings(guild, settings)
    e_new_word = func.esc_md(new_word)
    await func.server_log(
        guild,
        "💬 {} (`{}`) définissez le nom \"text\" du serveur sur **{}**".
        format(func.user_hash(author), author.id, e_new_word), 2, settings)

    for p, pv in settings['auto_channels'].items():
        for s, sv in pv['secondaries'].items():
            if 'tc' in sv:
                tc = guild.get_channel(sv['tc'])
                try:
                    await tc.edit(name=utils.nice_cname(new_word))
                except discord.errors.Forbidden:
                    pass

    return True, (
        "Done! From now on I'll use **{}** instead of **{}**.".format(
            e_new_word, previous_word))
Пример #9
0
async def execute(ctx, params):
    params_str = ' '.join(params)
    guild = ctx['guild']
    settings = ctx['settings']
    author = ctx['message'].author
    nick = utils.strip_quotes(params_str)

    if nick.lower() == 'reset':
        try:
            del settings['custom_nicks'][str(author.id)]
            utils.set_serv_settings(guild, settings)
        except KeyError:
            return False, "You haven't set a custom nickname."
        return True, "Your custom nickname has been removed."

    if 'custom_nicks' not in settings:
        settings['custom_nicks'] = {}
    settings['custom_nicks'][str(author.id)] = nick
    utils.set_serv_settings(guild, settings)

    await func.server_log(
        guild, "🙋 {} (`{}`) set their custom nick to {}".format(
            func.user_hash(author), author.id, nick), 2, settings)
    return True, (
        "Done! Channels that show the creator's name will now call you **{}** instead of **{}**."
        .format(nick, author.display_name))
Пример #10
0
async def execute(ctx, params):
    params_str = ' '.join(params)
    guild = ctx['guild']
    settings = ctx['settings']
    limit = utils.strip_quotes(params_str)
    author = ctx['message'].author
    vc = ctx['voice_channel']

    if limit:
        try:
            limit = abs(int(limit))
        except ValueError:
            return False, "`{}` is not a number.".format(limit)
    else:
        limit = len(vc.members)

    if limit > 99:
        return False, "The user limit cannot be higher than 99."

    await vc.edit(user_limit=limit)
    if limit != 0:
        log_msg = "👪 {} (`{}`) set the user limit of \"**{}**\" (`{}`) to {}".format(
            func.user_hash(author), author.id, func.esc_md(vc.name), vc.id,
            limit)
    else:
        log_msg = "👨‍👩‍👧‍👦 {} (`{}`) removed the user limit of \"**{}**\" (`{}`)".format(
            func.user_hash(author), author.id, func.esc_md(vc.name), vc.id)
    await func.server_log(guild, log_msg, 2, settings)
    return True, None
def dated_static(parser, token):
    bits = token.contents.split()
    if len(bits) <> 2:
        raise template.TemplateSyntaxError(
            "Wrong number of arguments passed. All we need is the path")

    return DatedStaticNode(strip_quotes(bits[1]))
Пример #12
0
async def execute(ctx, params):
    params_str = ' '.join(params)
    guild = ctx['guild']
    username = utils.strip_quotes(params_str)
    if username:
        # Show roles of particular user if param is provided
        found_user = False
        for m in guild.members:
            if m.name == username or m.mention == username:
                roles = m.roles
                found_user = True
                break
        if not found_user:
            return False, "There is no user named \"{}\"".format(username)
    else:
        # If no param is provided, show all roles in server
        roles = guild.roles

    l = ["```{:^16}".format("ID") + " Creation Date    Name```"]
    roles = sorted(roles, key=lambda x: x.created_at)
    for r in roles:
        if r.name != "@everyone":
            l.append("`{0}`  `{1}`  {2}".format(
                str(r.id), r.created_at.strftime("%Y/%m/%d"), r.name))
    for c in utils.chunks(l, 10):
        await echo('\n'.join(c), ctx['channel'], ctx['message'].author)

    return True, "NO RESPONSE"
Пример #13
0
 def kh_symbol(self, arg0, tokens, ref):
     '''symbol assignment'''
     # TODO: handle this:  sym=func(key,value)
     # iocSubString=asdCreateSubstitutionString("IOC",iocprefix)
     arg = utils.strip_quotes( tokens[2]['tokStr'] )
     self.symbols.set(arg0, arg, self, ref)
     self.kh_shell_command(arg0, tokens, ref)
Пример #14
0
def parse_prod(query):
  """
      Returns a list of commprods if any
      are found in the query, otherise
      returns None. Run query through strip_old()
      before passing in.
  """
  btb_regex = '((^)|(\s))((a btb)|(abtb)|(btb))'
  comm_regex = '(comm)(()|( )|(\.)|(\. )|( \.)|(\,)|(\, )|( \,))'
  prod_regex = '((prod)|(prodd))((\s)|(\.\s)|(\.\.\s))'

  commprod_regex = """((%(comm)s%(prod)s)|(%(comm)s\s%(prod)s))""" % {
      'comm': comm_regex,
      'prod': prod_regex,
  }
  regex = '%(btb)s(?P<comm_prod>.+?)%(commprod)s+' % {
      'btb': btb_regex,
      'commprod': commprod_regex,
  }
  pattern = re.compile(regex, re.I | re.DOTALL)
  if pattern.search(query):
    prods = []
    for m in pattern.finditer(query):
      m = utils.strip_quotes(m.group('comm_prod'))
      prods.append(m)
    return prods

  return None
Пример #15
0
async def execute(ctx, params):
    params_str = ' '.join(params)
    guild = ctx['guild']
    settings = ctx['settings']
    author = ctx['message'].author
    new_word = params_str.replace('\n',
                                  ' ')  # Can't have newlines in channel name.
    new_word = utils.strip_quotes(new_word)
    previous_word = "General" if 'general' not in settings else func.esc_md(
        settings['general'])
    if not new_word:
        return False, (
            "You need to define a new word, e.g. `{}general Lounge` to make "
            "**Lounge** shown instead of **{}**.".format(
                ctx['print_prefix'], previous_word))
    settings['general'] = new_word
    utils.set_serv_settings(guild, settings)
    e_new_word = func.esc_md(new_word)
    await func.server_log(
        guild,
        "🎮 {} (`{}`) set the server's \"General\" word to **{}**".format(
            func.user_hash(author), author.id, e_new_word), 2, settings)
    return True, (
        "Done! From now on I'll use **{}** instead of **{}**.".format(
            e_new_word, previous_word))
def signal_received_email(sender, sma, app_id, html, text, from_field, **kwargs):
    from utils import reply_to_thread, strip_quotes # circular dependency fix
    logger.debug("Sendgrid signal receive: %s, %s, %s, %s, %s, %s"%(sender, sma, app_id,
                                                                    html, text, from_field) )
    if app_id == sendgrid_settings.THREADED_MESSAGES_ID:
        body =''

        if text:
            body = text

        if not body:
            body = strip_tags(html)

        if body:
            strip_quotes(body)
            thread = sma.content_object
            reply_to_thread(thread, sma.user, body)
Пример #17
0
 def invoke(self, message, warnings):
     payload = message.get_payload()
     if isinstance(payload, basestring):
         if message.get('Content-Disposition', 'inline') == 'inline' and message.get_content_maintype() == 'text':
             message.set_payload(strip_quotes(payload))
     else:
         for _message in payload:
             self.invoke(_message, warnings)
     return message
Пример #18
0
def signal_received_email(sender, sma, app_id, html, text, from_field,
                          **kwargs):
    from utils import reply_to_thread, strip_quotes  # circular dependency fix
    logger.debug("Sendgrid signal receive: %s, %s, %s, %s, %s, %s" %
                 (sender, sma, app_id, html, text, from_field))
    if app_id == sendgrid_settings.THREADED_MESSAGES_ID:
        body = ''

        if text:
            body = text

        if not body:
            body = strip_tags(html)

        if body:
            strip_quotes(body)
            thread = sma.content_object
            reply_to_thread(thread, sma.user, body)
Пример #19
0
 def invoke(self, message, warnings):
     payload = message.get_payload()
     if isinstance(payload, basestring):
         if message.get(
                 'Content-Disposition', 'inline'
         ) == 'inline' and message.get_content_maintype() == 'text':
             message.set_payload(strip_quotes(payload))
     else:
         for _message in payload:
             self.invoke(_message, warnings)
     return message
Пример #20
0
 def kh_cd(self, arg0, tokens, ref):
     path = reconstruct_line(tokens).strip()
     path = utils.strip_quotes(path)           # strip double-quotes
     if self.symbols.exists(path):       # symbol substitution
         path = self.symbols.get(path).value
     path = self.env.replace(path)       # macro substitution
     if len(path) == 0:
         path = self.startup_directory
     if len(path) > 0 and os.path.exists(path):
         if os.path.abspath(path) != os.getcwd():    # only cd if it is really different
             os.chdir(path)
             self.kh_shell_command(arg0, tokens, ref)
             utils.logMessage(arg0 + ' ' + path, utils.LOGGING_DETAIL__MEDIUM)
async def execute(ctx, params):
    params_str = ' '.join(params)
    guild = ctx['guild']
    settings = ctx['settings']
    gsplit = params_str.split('>>')
    if len(gsplit) != 2 or not gsplit[0] or not gsplit[-1]:
        return False, (
            "Incorrect syntax for alias command. Should be: `{}alias [Actual game name] >> "
            "[New name]` (without square brackets).".format(
                ctx['print_prefix']))
    else:
        gname = utils.strip_quotes(gsplit[0])
        aname = utils.strip_quotes(gsplit[1])
        if gname in settings['aliases']:
            oaname = settings['aliases'][gname]
            response = "'{}' already has an alias ('{}'), it will be replaced with '{}'.".format(
                gname, oaname, aname)
        else:
            response = "'{}' will now be shown as '{}'.".format(gname, aname)
        settings['aliases'][gname] = aname
        utils.set_serv_settings(guild, settings)
        return True, response
Пример #22
0
 def kh_dbLoadTemplate(self, arg0, tokens, ref):
     # TODO: Can one template call another?
     local_macros = macros.Macros(**self.env.db)
     args = utils.strip_parentheses(reconstruct_line(tokens).strip()).split(',')
     if len(args) in (1, 2):
         tfile = os.path.join(os.getcwd(), utils.strip_quotes(args[0]))
     if len(args) == 2:
         # such as in 8idi:  dbLoadTemplate("aiRegister.substitutions", top)
         # This is an ERROR.  The IOC should be corrected.
         '''from the EPICS documentation regarding dbLoadTemplate():
         
         dbLoadTemplate(char *subfile, char *substitutions)
         
         This IOC command reads a template substitutions file which 
         provides instructions for loading database instance files 
         and gives values for the $(xxx) macros they may contain. 
         This command performs those substitutions while loading the 
         database instances requested.
         
         The subfile parameter gives the name of the template substitution file to be used. 
         The optional substitutions parameter may contain additional global macro values, 
         which can be overridden by values given within the substitution file.
         '''
         path = self.symbols.get(utils.strip_quotes(args[1]).strip(), None)
         if isinstance(path, macros.KVpair):
             alternative = os.path.join(path.value, tfile)
             if os.path.exists(alternative):
                 tfile = alternative
         else:
             msg = 'problem parsing: ' + arg0 + reconstruct_line(tokens).strip()
             utils.logMessage(msg, utils.LOGGING_DETAIL__IMPORTANT)
     obj = template.Template(tfile, ref, **local_macros.db)
     self.template_list.append(obj)
     self.database_list += obj.database_list
     self.kh_shell_command(arg0, tokens, ref)
     for k, v in obj.getPVs():
         self.pv_dict[k] = v
Пример #23
0
 def parse_macro_args(self, arg, ref, tokens, parent_macros):
     local_macros = macros.Macros(**parent_macros.db)
     for definition in utils.strip_quotes(arg).split(','):
         if definition.find('=') < 0:
             # if self.symbols.get(definition, None)
             # such as:  iocSubString=asdCreateSubstitutionString("IOC",iocprefix)
             msg = str(ref) + reconstruct_line(tokens).strip()
             utils.logMessage(msg, utils.LOGGING_DETAIL__IMPORTANT)
             #raise UnhandledTokenPattern, msg
         else:
             k, v = [_.strip() for _ in definition.split('=')]
             # expand macros now to avoid possible infinite loop while replacing
             # example:   PORT=IP_$(PORT)
             v = local_macros.replace(v)
             local_macros.set(k, v, self, ref)
     return local_macros
Пример #24
0
async def execute(ctx, params):
    params_str = ' '.join(params)
    guild = ctx['guild']
    settings = ctx['settings']
    author = ctx['message'].author
    bitrate = utils.strip_quotes(params_str)
    v = author.voice
    in_vc = v is not None and v.channel.id in func.get_secondaries(
        guild, settings)
    if bitrate.lower() == 'reset':
        try:
            del settings['custom_bitrates'][str(author.id)]
            utils.set_serv_settings(guild, settings)
        except KeyError:
            return False, "You haven't set a custom bitrate."
        if in_vc:
            await func.update_bitrate(v.channel, settings, reset=True)
        return True, "Your custom bitrate has been reset, the channel default will be used for you from now on."

    try:
        bitrate = float(bitrate)
    except ValueError:
        return False, "`{}` is not a number.".format(bitrate)

    if bitrate < 8:
        return False, "The bitrate must be higher than 8."

    if bitrate * 1000 > guild.bitrate_limit:
        return False, "{} is higher than the maximum bitrate in this server ({}).".format(
            bitrate, guild.bitrate_limit / 1000)

    if 'custom_bitrates' not in settings:
        settings['custom_bitrates'] = {}
    settings['custom_bitrates'][str(author.id)] = bitrate
    utils.set_serv_settings(guild, settings)

    if in_vc:
        await func.update_bitrate(v.channel, settings)

    await func.server_log(
        guild, "🎚 {} (`{}`) set their custom bitrate to {}kbps".format(
            func.user_hash(author), author.id, bitrate), 2, settings)
    return True, (
        "Done! From now on, channels you join will have their bitrate set to {}kbps.\n"
        "If multiple users in the channel have set custom bitrates, the average will be used.\n\n"
        "Use `{}channelinfo` to check the current bitrate of your channel.".
        format(bitrate, ctx['print_prefix']))
    def test_strip_quotes(self):
        body = """nyan nyan nyan nyan nyan
        nyan nyan nyan nyan nyan
        nyan nyan nyan nyan nyan

        2011/10/28 Nyan Cat <*****@*****.**>:
         > hey guys
        > sarete il 31 dicembre con Pascal a Firenze?
        > lo spero tanto, nel caso ditemi qualcosa...
        >
        >>>
        >
        >>
        >"""
        
        body_stripped = """nyan nyan nyan nyan nyan
        nyan nyan nyan nyan nyan
        nyan nyan nyan nyan nyan
        """
        
        self.assertEquals(body_stripped.strip(), strip_quotes(body).strip())
Пример #26
0
    def test_strip_quotes(self):
        body = """nyan nyan nyan nyan nyan
        nyan nyan nyan nyan nyan
        nyan nyan nyan nyan nyan

        2011/10/28 Nyan Cat <*****@*****.**>:
         > hey guys
        > sarete il 31 dicembre con Pascal a Firenze?
        > lo spero tanto, nel caso ditemi qualcosa...
        >
        >>>
        >
        >>
        >"""

        body_stripped = """nyan nyan nyan nyan nyan
        nyan nyan nyan nyan nyan
        nyan nyan nyan nyan nyan
        """

        self.assertEquals(body_stripped.strip(), strip_quotes(body).strip())
async def execute(ctx, params):
    params_str = ' '.join(params)
    guild = ctx['guild']
    settings = ctx['settings']
    param = utils.strip_quotes(params_str)

    if param.lower() == 'none':
        try:
            del settings['stct']
            utils.set_serv_settings(guild, settings)
            return (
                True,
                "From now on, new text channels will only be visible to the channel's occupants. "
                "Existing channels will not be affected.")
        except KeyError:
            return False, "Text channels are already invisible to everyone but the channel's occupants."

    role = None
    try:
        param = int(param)
        role = guild.get_role(param)
    except ValueError:
        if param == "@everyone":
            role = guild.default_role
        else:
            for r in guild.roles:
                if r.mention == param:
                    role = r
                    break

    if role is None:
        return False, "I can't find that role. You need to specify either the role ID, or `@mention` it."

    settings['stct'] = role.id
    utils.set_serv_settings(guild, settings)
    return (
        True,
        "From now on, new text channels can be seen by users with the \"{}\" role. "
        "Existing channels will not be affected.".format(
            discord.utils.escape_mentions(role.name)))
async def execute(ctx, params):
    params_str = ' '.join(params)
    guild = ctx['guild']
    limit = utils.strip_quotes(params_str)
    try:
        limit = int(limit)
    except ValueError:
        if limit:
            return False, "`{}` is not a number.".format(limit)
        else:
            return False, ("You need to specify a number to set the limit to. "
                           "E.g. '{}defaultlimit 4'".format(
                               ctx['print_prefix']))
    await func.set_default_limit(guild, ctx['voice_channel'], limit)
    if int(limit) != 0:
        return True, (
            "Done! From now on, voice channels like the one you're in now will be limited to "
            "{0} users. You can reset this by running `{1}defaultlimit 0`.\n"
            "If you want to set the limit of *only* your channel, "
            "use `{1}limit` instead.".format(limit, ctx['print_prefix']))
    else:
        return True, (
            "Done! From now on, voice channels like the one you're in now will have no user limit."
        )
Пример #29
0
async def admin_command(cmd, ctx):
    client = ctx['client']
    message = ctx['message']
    channel = message.channel
    params = ctx['params']
    params_str = ctx['params_str']
    guilds = ctx['guilds']
    LAST_COMMIT = ctx['LAST_COMMIT']

    if cmd == 'log':
        logfile = "log{}.txt".format("" if cfg.SAPPHIRE_ID is None else cfg.SAPPHIRE_ID)
        if not os.path.exists(logfile):
            await channel.send("No log file")
            return
        with open(logfile, 'r', encoding="utf8") as f:
            data = f.read()
        data = data[-10000:]  # Drop everything but the last 10k characters to make string ops quicker
        data = data.replace('  Creating channel for ', '  ✅')
        data = data.replace('  Deleting ', '    ❌')
        data = data.replace('  Renaming ⌛  to  ', ' ⏩ ')
        data = data.replace('  Renaming ', ' 🔄')
        data = data.replace('  to  ', ' ⏩ ')
        data = data.replace('  CMD Y: ', '  C✔ ')
        data = data.replace('  CMD F: ', '  C✖ ')
        data = data.replace(" creating channels too quickly", " creating channels too quickly❗❗")
        data = data.replace(" where I don't have permissions", " where I don't have permissions❗❗")
        data = data.replace("Traceback (most recent", "❗❗Traceback (most recent")
        data = data.replace("discord.errors.", "❗❗discord.errors.")
        data = data.replace("Remembering channel ", "❗❗Remembering ")
        data = data.replace("New tickrate is ", "🕐")
        data = data.replace(", seed interval is ", " 🕐")
        data = data.replace('  ', ' ')  # Reduce indent to save character space
        today = datetime.now(pytz.timezone(cfg.CONFIG['log_timezone'])).strftime("%Y-%m-%d")
        data = data.replace(today, 'T')
        character_limit = 2000 - 17  # 17 for length of ```autohotkey\n at start and ``` at end.
        data = data[character_limit * -1:]
        data = data.split('\n', 1)[1]
        lines = data.split('\n')
        for i, l in enumerate(lines):
            # Fake colon (U+02D0) to prevent highlighting the line
            if " ⏩" in l:
                lines[i] = l.replace(':', 'ː')
            elif l.startswith('T '):
                if '[' in l:
                    s = l.split('[', 1)
                    lines[i] = s[0] + '[' + s[1].replace(':', 'ː')
        data = '\n'.join(lines)
        data = '```autohotkey\n' + data
        data = data + '```'
        await channel.send(data)

    if cmd == 'stats':
        r = await channel.send(". . .")
        t1 = message.created_at
        t2 = r.created_at
        response_time = (t2 - t1).total_seconds()
        num_users = 0
        for g in guilds:
            num_users += len([m for m in g.members if not m.bot])

        lines_of_code = 0
        for f in os.listdir(cfg.SCRIPT_DIR):
            if f.lower().endswith('.py'):
                lines_of_code += utils.count_lines(os.path.join(cfg.SCRIPT_DIR, f))
            elif f == "commands":
                for sf in os.listdir(os.path.join(cfg.SCRIPT_DIR, f)):
                    if sf.lower().endswith('.py'):
                        lines_of_code += utils.count_lines(os.path.join(cfg.SCRIPT_DIR, f, sf))

        cpu = psutil.cpu_percent()
        mem = psutil.virtual_memory()
        disk = psutil.disk_usage('/')
        await r.edit(content=(
            "Servers: **{tot_servs}** (A:{active_servs} S:{shards}) \t "
            "Users: **{users}** \t Channels: **{channels}** \n"
            "Response time: **{rt}** \t Tick rate: **{tr}** \t Tick time: **{tt}** | **{gtt}**\n"
            "CPU: **{cpu}%** \t MEM: **{memg} ({memp}%)** \t DISK: **{diskg} ({diskp}%)**\n"
            "**Last commit:** {commit}\n"
            "**Lines of code:** {lines}\n"
            "**Timings:** \n{timings}".format(
                tot_servs=len(guilds),
                active_servs=utils.num_active_guilds(guilds),
                shards=utils.num_shards(guilds),
                users=num_users,
                channels=utils.num_active_channels(guilds),
                rt="{0:.2f}s".format(response_time),
                tr="{0:.1f}s".format(cfg.TICK_RATE),
                tt="{0:.2f}s".format(cfg.TICK_TIME),
                gtt="{0:.2f}s".format(cfg.G_TICK_TIME),
                cpu=cpu, memg="{0:.1f}GB".format(mem.used / 1024 / 1024 / 1024), memp=round(mem.percent),
                diskg="{0:.1f}GB".format(disk.used / 1024 / 1024 / 1024), diskp=round(disk.percent),
                commit=LAST_COMMIT,
                lines=lines_of_code,
                timings=utils.format_timings()
            )
        ))

    if cmd == 'ping':
        r = await channel.send(". . .")
        t1 = message.created_at
        t2 = r.created_at
        response_time = (t2 - t1).total_seconds()
        e = '🔴🔴🔴' if response_time > 5 else ('🟠🟠' if response_time > 1 else '🟢')
        await r.edit(content="**{0} {1:.1f}s**".format(e, response_time))

    if cmd == 'top':
        top_guilds = []
        for g in guilds:
            s = func.get_secondaries(g)
            top_guilds.append({"name": g.name,
                               "size": len([m for m in g.members if not m.bot]),
                               "num": len(s) if s is not None else 0})
        top_guilds = sorted(top_guilds, key=lambda x: x['num'], reverse=True)[:10]
        r = "**Top Guilds:**"
        for g in top_guilds:
            r += "\n`{}` {}: \t**{}**".format(
                g['size'],
                func.esc_md(g['name']),
                g['num']
            )
        r += "\n\n**{}**".format(utils.num_active_channels(guilds))
        await channel.send(r)

    if cmd == 'patrons':
        if patreon_info is None:
            await channel.send(content='❌')
            return

        patrons = patreon_info.fetch_patrons(force_update=True)
        if not patrons:
            await channel.send(content='❌')
            return
        fields = {}
        auths = patreon_info.update_patron_servers(patrons)
        for p, pv in patrons.items():
            pu = client.get_user(p)
            if pu is not None:
                pn = pu.name
            else:
                pn = "Unknown"
            gn = ""
            if str(p) in auths:
                for s in auths[str(p)]['servers']:
                    gn += "`{}` ".format(s)
                if 'extra_gold' in auths[str(p)]:
                    for s in auths[str(p)]['extra_gold']:
                        gn += "+g`{}` ".format(s)
            fields["`{}` **{}** {}".format(p, pn, cfg.TIER_ICONS[pv])] = gn
        try:
            for field_chunk in utils.dict_chunks(fields, 25):
                e = discord.Embed(color=discord.Color.from_rgb(205, 220, 57))
                e.title = "{} Patrons".format(len(field_chunk))
                for f, fv in field_chunk.items():
                    fv = fv if fv else "None"
                    e.add_field(name=f, value=fv)
                await channel.send(embed=e)
        except:
            await channel.send(traceback.format_exc())
            await func.react(message, '❌')

    if cmd == 'sapphiredebug':
        if cfg.SAPPHIRE_ID is None:
            await channel.send(content='❌ Not a sapphire')
            return

        if patreon_info is None:
            await channel.send(content='❌ No patreon_info')
            return

        auths = utils.read_json(os.path.join(cfg.SCRIPT_DIR, "patron_auths.json"))
        initiator_id = cfg.CONFIG["sapphires"][str(cfg.SAPPHIRE_ID)]['initiator']
        msg = ("Sapphire ID: {}\n"
               "User: `{}`\n"
               "Actual guilds: {}\n"
               "Config guilds: {}\n"
               "Authenticated guilds: {}\n"
               "get_guilds: {}".format(
                   cfg.SAPPHIRE_ID,
                   initiator_id,
                   ", ".join(['`' + str(g.id) + '`' for g in client.guilds]),
                   ", ".join(['`' + str(g) + '`' for g in cfg.CONFIG["sapphires"][str(cfg.SAPPHIRE_ID)]['servers']]),
                   ", ".join(['`' + str(g) + '`' for g in auths[str(initiator_id)]['servers']]),
                   ", ".join(['`' + str(g.id) + '`' for g in func.get_guilds(client)]))
               )
        await channel.send(msg)

    if cmd == 'status':
        g = utils.strip_quotes(params_str)
        if not g:
            await func.react(message, '❌')
            return
        try:
            await client.change_presence(
                activity=discord.Activity(name=g, type=discord.ActivityType.watching)
            )
            await func.react(message, '✅')
        except:
            await channel.send(traceback.format_exc())
            await func.react(message, '❌')

    if cmd == 'settings':
        gid = utils.strip_quotes(params_str)
        try:
            int(gid)
        except ValueError:
            for x in guilds:
                if x.name == gid:
                    gid = str(x.id)
                    break
        fname = gid + '.json'
        fp = os.path.join(cfg.SCRIPT_DIR, "guilds", fname)
        if os.path.exists(fp):
            gid = int(gid)
            g = client.get_guild(gid)
            head = "**{}** `{}`{}".format(g.name, gid, ("✅" if g in func.get_guilds(client) else "❌"))
            head += "💎" if func.is_sapphire(gid) else ("💳" if func.is_gold(gid) else "")
            s = head
            s += "\n```json\n"
            with open(fp, 'r') as f:
                file_content = f.read()
            s += file_content
            s += '```'
            try:
                await channel.send(s)
            except discord.errors.HTTPException:
                # Usually because message is over character limit
                haste_url = await utils.hastebin(file_content)
                await channel.send("{}\n{}".format(head, haste_url))
        else:
            await func.react(message, '❌')

    if cmd == 'refetch':
        gid = utils.strip_quotes(params_str)
        try:
            gid = int(gid)
        except ValueError:
            await func.react(message, '❌')
            return

        g = client.get_guild(gid)

        if g is None:
            await func.react(message, '❓')
            return

        utils.get_serv_settings(g, force_refetch=True)
        await func.react(message, '✅')
        return

    if cmd == 'disable':
        try:
            g = client.get_guild(int(utils.strip_quotes(params_str)))
            settings = utils.get_serv_settings(g)
            settings['enabled'] = False
            utils.set_serv_settings(g, settings)
            log("Force Disabling", g)
            await func.react(message, '✅')
        except:
            await channel.send(traceback.format_exc())
            await func.react(message, '❌')

    if cmd == 'enable':
        try:
            g = client.get_guild(int(utils.strip_quotes(params_str)))
            settings = utils.get_serv_settings(g)
            settings['enabled'] = True
            utils.set_serv_settings(g, settings)
            log("Force Enabling", g)
            await func.react(message, '✅')
        except:
            await channel.send(traceback.format_exc())
            await func.react(message, '❌')

    if cmd == 'info':
        cid = utils.strip_quotes(params_str)
        try:
            c = client.get_channel(int(cid))
            members = [m.display_name + " \t {}".format(utils.debug_unicode(m.display_name)) for m in c.members]
            games = []
            for m in c.members:
                if m.activity:
                    games.append(m.activity.name + " \t {}".format(utils.debug_unicode(m.activity.name)))
            s = "**__Server:__** {} `{}`\n**__Name:__** {}\n{}\n\n".format(
                c.guild.name, c.guild.id, c.name, utils.debug_unicode(c.name)
            )
            if c.id in cfg.ATTEMPTED_CHANNEL_NAMES:
                s += "**__Attempted Name:__** {}\n{}\n\n".format(
                    cfg.ATTEMPTED_CHANNEL_NAMES[c.id],
                    utils.debug_unicode(cfg.ATTEMPTED_CHANNEL_NAMES[c.id])
                )
            s += "**__{} Members:__**\n".format(len(members))
            s += '\n'.join(members)
            s += '\n\n**__{} Games:__**\n'.format(len(games))
            s += '\n'.join(games)
            s = s.replace('\n\n\n', '\n\n')
            await channel.send(s)
        except:
            await channel.send(traceback.format_exc())
            await func.react(message, '❌')

    if cmd == 'whois':
        uid = utils.strip_quotes(params_str)
        try:
            u = client.get_user(int(uid))
            in_guilds = {}
            for g in client.guilds:
                if u in g.members:
                    m = g.get_member(int(uid))
                    in_guilds[g.id] = {
                        "guild_name": func.esc_md(g.name),
                        "guild_size": g.member_count,
                        "patron": "💎" if func.is_sapphire(g) else ("💳" if func.is_gold(g) else ""),
                        "user_name": func.esc_md(m.display_name),
                        "role": m.top_role.name,
                    }
            if in_guilds:
                s = "**{}**".format(func.user_hash(u))
                s += " \t :b: :regional_indicator_o: :regional_indicator_t:" if u.bot else ""
                can_dm = True
                try:
                    await u.create_dm()
                    can_dm = client.user.permissions_in(u.dm_channel).send_messages
                except discord.errors.Forbidden:
                    can_dm = False
                s += " \t Can DM: {}".format('✅' if can_dm else '❌')

                for gid, g in in_guilds.items():
                    s += "\n{}`{}` **{}** (`{}`) \t {} ({})".format(
                        g['patron'], gid, g['guild_name'], g['guild_size'], g['user_name'], g['role']
                    )

                await echo(s, channel)
            else:
                await channel.send("¯\\_(ツ)_/¯")
        except:
            await channel.send(traceback.format_exc())
            await func.react(message, '❌')

    if cmd == 'votekicks':
        try:
            readable = {}
            for k, kv in cfg.VOTEKICKS.items():
                readable[k] = {
                    "initiator": kv['initiator'].display_name,
                    "participants": [m.display_name for m in kv['participants']],
                    "required_votes": kv['required_votes'],
                    "offender": kv['offender'].display_name,
                    "reason": kv['reason'],
                    "in_favor": [m.display_name for m in kv['in_favor']],
                    "voice_channel": kv['voice_channel'].id,
                    "message": kv['message'].id,
                    "end_time": datetime.fromtimestamp(kv['end_time']).strftime("%Y-%m-%d %H:%M")
                }
            s = "```json\n" + json.dumps(readable, indent=1, sort_keys=True) + "```"
            print(s)
            try:
                await channel.send(s)
            except discord.errors.HTTPException:
                # Usually because message is over character limit
                haste_url = await utils.hastebin(s)
                await channel.send(haste_url)
        except:
            await channel.send(traceback.format_exc())
            await func.react(message, '❌')

    if cmd == 'exit':
        attempts = 0
        while attempts < 100:
            attempts += 1
            if not cfg.WRITES_IN_PROGRESS:
                print("Exiting!")
                await client.close()
                sys.exit()
                break
        else:
            print("Failed to close", cfg.WRITES_IN_PROGRESS)
            await func.react(message, '❌')

    if cmd == 'loop':
        mode = params[0]
        loop_name = params[1]
        try:
            loop = ctx['loops'][loop_name]
            modes = {  # Dict of possible loop functions/attrs as [fn, arg]
                'current_loop': [loop.current_loop, None],
                'next_iteration': [loop.next_iteration, None],
                'next_run': [loop.next_iteration, None],  # Alias
                'start': [loop.start, client],
                'stop': [loop.stop, None],
                'cancel': [loop.cancel, None],
                'restart': [loop.restart, client],
                'is_being_cancelled': [loop.is_being_cancelled, None],
                'last_run': [loop.last_run, None],
            }
            if mode not in modes:
                await func.react(message, '❓')
                return
            fn, arg = modes[mode]
            if callable(fn):
                if arg is None:
                    r = fn()
                else:
                    r = fn(arg)
            else:
                r = fn
            if r is not None:
                if isinstance(r, date):
                    r = r.astimezone(pytz.timezone(cfg.CONFIG['log_timezone']))
                    await channel.send(r.strftime("%Y-%m-%d %H:%M:%S"))
                else:
                    await channel.send(str(r))
            await func.react(message, '✅')
        except:
            await channel.send(traceback.format_exc())
            await channel.send("Loops: \n{}".format('\n'.join(ctx['loops'].keys())))
            await func.react(message, '❌')

    if cmd == 'rename':
        try:
            cid = utils.strip_quotes(params[0])
            c = client.get_channel(int(cid))
            new_name = ' '.join(params[1:])
            if not new_name:
                new_name = "⌛"
            await c.edit(name=new_name)
        except:
            await channel.send(traceback.format_exc())
            await func.react(message, '❌')
        else:
            await func.react(message, '✅')
            log("{0}  Force Renaming to {1}".format(cid[-4:], new_name), c.guild)

    if cmd == 'forget':
        try:
            cid = int(utils.strip_quotes(params[0]))
            c = client.get_channel(cid)
            settings = utils.get_serv_settings(c.guild)
            for p, pv in settings['auto_channels'].items():
                tmp = settings['auto_channels'][p]['secondaries'].copy()
                for s, sv in pv['secondaries'].items():
                    if s == cid:
                        del settings['auto_channels'][p]['secondaries'][s]
                        break
            utils.set_serv_settings(c.guild, settings)
        except:
            await channel.send(traceback.format_exc())
            await func.react(message, '❌')
        else:
            await func.react(message, '✅')

    if cmd == 'delete':
        try:
            cid = int(utils.strip_quotes(params[0]))
            c = client.get_channel(cid)
            await c.delete()
        except:
            await channel.send(traceback.format_exc())
            await func.react(message, '❌')
        else:
            await func.react(message, '✅')

    if cmd == 'whisper':
        params_str = utils.strip_quotes(params_str)
        if '\n' not in params_str:
            await func.react(message, '❌')
            return
        uid, msg = params_str.split('\n', 1)
        try:
            u = await client.fetch_user(uid)
        except discord.errors.NotFound:
            await func.react(message, '❌')
            return
        if u.dm_channel is None:
            await u.create_dm()
        try:
            await u.dm_channel.send(msg)
        except:
            await channel.send(traceback.format_exc())
            await func.react(message, '❌')
        else:
            await func.react(message, '✅')

    if cmd == 'cleanprimaries':
        try:
            n_primaries = 0
            n_real_primaries = 0
            for g in client.guilds:
                settings = utils.get_serv_settings(g)
                tmp = {}
                n_primaries += len(settings['auto_channels'])
                for p, pv in settings['auto_channels'].items():
                    c = g.get_channel(p)
                    if c:
                        tmp[p] = pv
                n_real_primaries += len(tmp)
                if len(settings['auto_channels']) != len(tmp):
                    settings['auto_channels'] = tmp
                    utils.set_serv_settings(g, settings)
            await channel.send("Cleaned {} of {} primaries".format(n_real_primaries, n_primaries))
        except:
            await channel.send(traceback.format_exc())
            await func.react(message, '❌')

    if cmd == 'leaveinactive':
        params_str = utils.strip_quotes(params_str)
        try:
            total_guilds = 0
            inactive_guilds = 0
            cfg.CONFIG['leave_inactive'] = []
            for g in client.guilds:
                total_guilds += 1
                if g and (not utils.guild_is_active(g) or g not in guilds):
                    cfg.CONFIG['leave_inactive'].append(g.id)
                    inactive_guilds += 1
                    if params_str == "go":
                        try:
                            await g.leave()
                        except discord.errors.NotFound:
                            pass
            if params_str == "go":
                await channel.send("Left {} of {} guilds.".format(inactive_guilds, total_guilds))
            else:
                await channel.send("Will leave {} of {} guilds. "
                                   "Rerun command with 'go' at end to actually leave them.".format(
                                       inactive_guilds, total_guilds))
            cfg.CONFIG['leave_inactive'] = []
        except:
            await channel.send(traceback.format_exc())
            await func.react(message, '❌')
Пример #30
0
def dated_static(parser, token):
    bits = token.contents.split()
    if len(bits) <> 2:
        raise template.TemplateSyntaxError("Wrong number of arguments passed. All we need is the path")

    return DatedStaticNode(strip_quotes(bits[1]))
Пример #31
0
async def on_message(message):
    if not client.is_ready():
        return

    if message.author.bot:
        # Don't respond to self or bots
        return

    guilds = func.get_guilds(client)

    admin = ADMIN
    admin_channels = []
    if admin is not None:
        admin_channels = [admin.dm_channel]
    if 'admin_channel' in cfg.CONFIG:
        admin_channels.append(ADMIN_CHANNEL)
    if message.channel in admin_channels:
        split = message.content.split(' ')
        cmd = split[0].split('\n')[0].lower()
        params_str = message.content[len(cmd):].strip()
        params = params_str.split(' ')

        if cmd == 'stop':
            m = utils.strip_quotes(params_str)
            success = await reload_modules(m)
            await func.react(message, '⌛' if success else '❌')
            await asyncio.sleep(3)
            await func.react(message, '🌑' if success else '❌')
            await asyncio.sleep(1)
            await func.react(message, '🌓' if success else '❌')
            await asyncio.sleep(1)
            await func.react(message, '🌔' if success else '❌')
            await asyncio.sleep(1)
            await func.react(message, '✅' if success else '❌')
            await message.channel.send("restarting..")

            await client.logout()
        else:
            ctx = {
                'client': client,
                'admin': admin,
                'message': message,
                'params': params,
                'params_str': params_str,
                'guilds': guilds,
                'LAST_COMMIT': LAST_COMMIT,
            }

            await admin_commands.admin_command(cmd, ctx)
        return

    if not message.guild:  # DM
        if 'help' in message.content and len(
                message.content) <= len("@Auto Voice Channels help"):
            await message.channel.send(
                "Sorry I don't respond to commands in DMs, "
                "you need to type the commands in a channel in your server.\n"
                "If you've tried that already, then make sure I have the right permissions "
                "to see and reply to your commands in that channel.")
        else:
            await admin_channels[-1].send(
                embed=discord.Embed(title="DM from **{}** [`{}`]:".format(
                    message.author.name, message.author.id),
                                    description=message.content))
        return

    if message.guild not in guilds:
        return

    prefix_m = message.guild.me.mention
    prefix_mx = "<@!" + prefix_m[2:]
    if message.guild.id in cfg.PREFIXES:
        prefix_p = cfg.PREFIXES[message.guild.id]
    else:
        prefix_p = 'vc/'

    prefix = None
    if message.content.startswith(prefix_m):
        prefix = prefix_m
        print_prefix = "@{} ".format(message.guild.me.display_name)
    elif message.content.startswith(prefix_mx):
        prefix = prefix_mx
        print_prefix = "@{} ".format(message.guild.me.display_name)
    elif message.content.lower().startswith(prefix_p.lower()):
        prefix = prefix_p
        print_prefix = prefix_p

    # Commands
    if prefix:
        msg = message.content[len(prefix):].strip()  # Remove prefix
        split = msg.split(' ')
        cmd = split[0].lower()
        params = split[1:]
        params_str = ' '.join(params)
        clean_paramstr = ' '.join(
            message.clean_content[len(prefix):].strip().split(' ')[1:])

        guild = message.guild
        channel = message.channel

        settings = utils.get_serv_settings(guild)
        if channel.id not in func.get_voice_context_channel_ids(
                guild, settings):
            settings['last_channel'] = channel.id
            utils.set_serv_settings(guild, settings)

        ctx = {
            'client': client,
            'guild': guild,
            'prefix': prefix,
            'print_prefix': print_prefix,
            'prefix_p': prefix_p,
            'command': cmd,
            'gold': func.is_gold(guild),
            'sapphire': func.is_sapphire(guild),
            'settings': settings,
            'message': message,
            'channel': channel,
            'clean_paramstr': clean_paramstr,
        }

        # Restricted commands
        perms = message.author.permissions_in(channel)
        perms_required = [
            perms.manage_channels,
            perms.manage_roles,
        ]
        ctx['admin'] = all(perms_required)

        success, response = await commands.run(cmd, ctx, params)

        if success or response != "NO RESPONSE":
            log("CMD {}: {}".format("Y" if success else "F", msg), guild)

        if success:
            if response:
                if response != "NO RESPONSE":
                    await echo(response, channel, message.author)
            else:
                await func.react(message, '✅')
        else:
            if response != "NO RESPONSE":
                await func.react(message, '❌')
                if response:
                    await echo(response, channel, message.author)
async def on_message(message):
    if not client.is_ready():
        return

    if message.author.bot:
        # Don't respond to self or bots
        return

    guilds = func.get_guilds(client)

    admin = ADMIN
    admin_channels = []
    if admin is not None:
        admin_channels = [admin.dm_channel]
    if 'admin_channel' in cfg.CONFIG and ADMIN_CHANNEL is not None:
        admin_channels.append(ADMIN_CHANNEL)
    if message.channel in admin_channels:
        split = message.content.split(' ')
        cmd = split[0].split('\n')[0].lower()
        params_str = message.content[len(cmd):].strip()
        params = params_str.split(' ')

        if cmd == 'reload':
            m = utils.strip_quotes(params_str)
            success = await reload_modules(m)
            await func.react(message, '✅' if success else '❌')
        else:
            ctx = {
                'client': client,
                'admin': admin,
                'message': message,
                'params': params,
                'params_str': params_str,
                'guilds': guilds,
                'LAST_COMMIT': LAST_COMMIT,
            }
            await admin_commands.admin_command(cmd, ctx)
        return

    if not message.guild:  # DM
        if 'help' in message.content and len(
                message.content) <= len("@Auto Voice Channels help"):
            await message.channel.send(
                "Sorry I don't respond to commands in DMs, "
                "you need to type the commands in a channel in your server.\n"
                "If you've tried that already, then make sure I have the right permissions "
                "to see and reply to your commands in that channel.")
        elif message.content.lower().startswith("power-overwhelming"):
            channel = message.channel
            params_str = message.content[len("power-overwhelming"):].strip()
            if not params_str:
                await channel.send(
                    "You need to specify a guild ID. "
                    "Try typing `who am I` to get a list of guilds we're both in"
                )
                return
            auth_guilds = params_str.replace(' ', '\n').split('\n')
            for auth_guild in auth_guilds:
                try:
                    g = client.get_guild(int(auth_guild))
                    if g is None:
                        await channel.send(
                            "`{}` is not a guild I know about, "
                            "maybe you need to invite me there first?".format(
                                auth_guild))
                        return
                except ValueError:
                    await channel.send(
                        "`{}` is not a valid guild ID, try typing "
                        "`who am I` to get a list of guilds we're both in.".
                        format(auth_guild))
                    return
                except Exception as e:
                    error_text = "Auth Error `{}`\nUser `{}`\nCMD `{}`".format(
                        type(e).__name__, message.author.id, message.content)
                    await func.admin_log(error_text, ctx['client'])
                    log(error_text)
                    error_text = traceback.format_exc()
                    await func.admin_log(error_text, ctx['client'])
                    log(error_text)
                    return False, (
                        "A `{}` error occured :(\n"
                        "An admin has been notified and will be in touch.\n"
                        "In the meantime, try asking for help in the support server: "
                        "https://discord.gg/qhMrz6u".format(type(e).__name__))

            ctx = {
                'message': message,
                'channel': channel,
                'client': client,
            }
            auth_guilds = [int(g) for g in auth_guilds]
            success, response = await func.power_overwhelming(ctx, auth_guilds)

            if success or response != "NO RESPONSE":
                log("DM CMD {}: {}".format("Y" if success else "F",
                                           message.content))

            if success:
                if response:
                    if response != "NO RESPONSE":
                        await echo(response, channel, message.author)
                else:
                    await func.react(message, '✅')
            else:
                if response != "NO RESPONSE":
                    await func.react(message, '❌')
                    if response:
                        await echo(response, channel, message.author)
        elif message.content.lower() in ["who am i", "who am i?"]:
            in_guilds = []
            for g in client.guilds:
                if message.author in g.members:
                    in_guilds.append("`{}` **{}**".format(g.id, g.name))
            if in_guilds:
                await message.channel.send(
                    "We're both in the following guilds:\n{}".format(
                        '\n'.join(in_guilds)))
            else:
                await message.channel.send(
                    "I'm not in any of the same guilds as you.")
        else:
            await admin_channels[-1].send(
                embed=discord.Embed(title="DM from **{}** [`{}`]:".format(
                    message.author.name, message.author.id),
                                    description=message.content))
        return

    if message.guild not in guilds:
        return

    prefix_m = message.guild.me.mention
    prefix_mx = "<@!" + prefix_m[2:]
    if message.guild.id in cfg.PREFIXES:
        prefix_p = cfg.PREFIXES[message.guild.id]
    else:
        prefix_p = 'vc/'

    prefix = None
    if message.content.startswith(prefix_m):
        prefix = prefix_m
        print_prefix = "@{} ".format(message.guild.me.display_name)
    elif message.content.startswith(prefix_mx):
        prefix = prefix_mx
        print_prefix = "@{} ".format(message.guild.me.display_name)
    elif message.content.lower().startswith(prefix_p.lower()):
        prefix = prefix_p
        print_prefix = prefix_p

    # Commands
    if prefix:
        msg = message.content[len(prefix):].strip()  # Remove prefix
        split = msg.split(' ')
        cmd = split[0].lower()
        params = split[1:]
        params_str = ' '.join(params)
        clean_paramstr = ' '.join(
            message.clean_content[len(prefix):].strip().split(' ')[1:])

        guild = message.guild
        channel = message.channel

        settings = utils.get_serv_settings(guild)
        if channel.id not in func.get_voice_context_channel_ids(
                guild, settings):
            settings['last_channel'] = channel.id
            utils.set_serv_settings(guild, settings)

        ctx = {
            'client': client,
            'guild': guild,
            'prefix': prefix,
            'print_prefix': print_prefix,
            'prefix_p': prefix_p,
            'command': cmd,
            'gold': func.is_gold(guild),
            'sapphire': func.is_sapphire(guild),
            'settings': settings,
            'message': message,
            'channel': channel,
            'clean_paramstr': clean_paramstr,
        }

        # Restricted commands
        perms = message.author.permissions_in(channel)
        perms_required = [
            perms.manage_channels,
            perms.manage_roles,
        ]
        ctx['admin'] = all(perms_required)

        success, response = await commands.run(cmd, ctx, params)

        if success or response != "NO RESPONSE":
            log("CMD {}: {}".format("Y" if success else "F", msg), guild)

        if success:
            if response:
                if response != "NO RESPONSE":
                    await echo(response, channel, message.author)
            else:
                await func.react(message, '✅')
        else:
            if response != "NO RESPONSE":
                await func.react(message, '❌')
                if response:
                    await echo(response, channel, message.author)