def is_admin(self): if self.is_fake: return False flags = var.FLAGS[self.rawnick] + var.FLAGS_ACCS[self.account] if "F" not in flags: try: hosts = set(botconfig.ADMINS) accounts = set(botconfig.ADMINS_ACCOUNTS) if not var.DISABLE_ACCOUNTS and self.account is not None: for pattern in accounts: if fnmatch.fnmatch(lower(self.account), lower(pattern)): return True for hostmask in hosts: if self.match_hostmask(hostmask): return True except AttributeError: pass return self.is_owner() return True
def lower(self): temp = type(self)(self.client, lower(self.nick), lower(self.ident), lower(self.host, casemapping="ascii"), lower(self.account)) if temp is not self: # If everything is already lowercase, we'll get back the same instance temp.channels = self.channels temp.ref = self.ref or self return temp
def match_hostmask(self, hostmask): """Match n!u@h, u@h, or just h by itself.""" nick, ident, host = re.match("(?:(?:(.*?)!)?(.*?)@)?(.*)", hostmask).groups("") temp = self.lower() return ((not nick or fnmatch.fnmatch(temp.nick, lower(nick))) and (not ident or fnmatch.fnmatch(temp.ident, lower(ident))) and fnmatch.fnmatch(temp.host, lower(host, casemapping="ascii")))
def complete_match(pattern: str, scope=None): """ Find a user or users who match the given pattern. :param pattern: Pattern to match on. The format is "[nick][:account]", with [] denoting an optional field. Exact matches are tried, and then prefix matches (stripping special characters as needed). If both a nick and an account are specified, both must match. :param Optional[Iterable[User]] scope: Users to match pattern against. If None, search against all users. :returns: A Match object describing whether or not the match succeeded. :rtype: Match[User] """ if scope is None: scope = _users matches = [] nick_search, _, acct_search = lower(pattern).partition(":") if not nick_search and not acct_search: return Match([]) direct_match = False for user in scope: nick = lower(user.nick) stripped_nick = nick.lstrip("[{\\^_`|}]") if nick_search: if nick == nick_search: if not direct_match: matches.clear() direct_match = True matches.append(user) elif not direct_match and (nick.startswith(nick_search) or stripped_nick.startswith(nick_search)): matches.append(user) else: matches.append(user) if acct_search: scope = list(matches) matches.clear() direct_match = False for user in scope: if not user.account: continue # fakes don't have accounts, so this search won't be able to find them acct = lower(user.account) stripped_acct = acct.lstrip("[{\\^_`|}]") if acct == acct_search: if not direct_match: matches.clear() direct_match = True matches.append(user) elif not direct_match and (acct.startswith(acct_search) or stripped_acct.startswith(acct_search)): matches.append(user) return Match(matches)
def lower(self): temp = type(self)(self.client, lower(self.nick)) if temp is not self: temp.ident = lower(self.ident) temp.host = lower(self.host, casemapping="ascii") temp.realname = lower(self.realname) temp.account = lower(self.account) temp.modes = self.modes temp.channels = self.channels temp.ref = self.ref or self return temp
def complete_match(string, users): matches = [] string = lower(string) for user in users: nick = lower(user.nick) if nick == string: return user, 1 elif nick.startswith(string) or nick.lstrip("[{\\^_`|}]").startswith(string): matches.append(user) if len(matches) != 1: return None, len(matches) return matches[0], 1
def get(name, *, allow_none=False): try: return _channels[lower(name)] except KeyError: if allow_none: return None raise
def _clear(self): for user in self.users: del user.channels[self] self.users.clear() self.modes.clear() self.state = _States.Cleared self.timestamp = None del _channels[lower(self.name)]
def is_owner(self): if self.is_fake: return False hosts = set(botconfig.OWNERS) accounts = set(botconfig.OWNERS_ACCOUNTS) if not var.DISABLE_ACCOUNTS and self.account is not None: for pattern in accounts: if fnmatch.fnmatch(lower(self.account), lower(pattern)): return True for hostmask in hosts: if self.match_hostmask(hostmask): return True return False
def add(name, cli, key=""): """Add and return a new channel, or an existing one if it exists.""" # We use add() in a bunch of places where the channel probably (but # not surely) already exists. If it does, obviously we want to use # that one. However, if the client is *not* the same, that means we # would be trying to send something from one connection over to # another one (or some other weird stuff like that). Instead of # jumping through hoops, we just disallow it here. if lower(name) in _channels: if cli is not _channels[lower(name)].client: raise RuntimeError("different IRC client for channel {0}".format(name)) return _channels[lower(name)] cls = Channel if predicate(name): cls = FakeChannel chan = _channels[lower(name)] = cls(name, cli) chan._key = key chan.join() return chan
def add(name, cli, key=""): """Add and return a new channel, or an existing one if it exists.""" # We use add() in a bunch of places where the channel probably (but # not surely) already exists. If it does, obviously we want to use # that one. However, if the client is *not* the same, that means we # would be trying to send something from one connection over to # another one (or some other weird stuff like that). Instead of # jumping through hoops, we just disallow it here. if lower(name) in _channels: if cli is not _channels[lower(name)].client: raise RuntimeError( "different IRC client for channel {0}".format(name)) return _channels[lower(name)] cls = Channel if predicate(name): cls = FakeChannel chan = _channels[lower(name)] = cls(name, cli) chan._key = key chan.join() return chan
def exists(name): """Return True if a channel by the name exists, False otherwise.""" return lower(name) in _channels
def init_vars(): from src.context import lower with var.GRAVEYARD_LOCK: conn = _conn() c = conn.cursor() c.execute("""SELECT pl.account_display, pe.notice, pe.deadchat, pe.pingif, pe.stasis_amount, pe.stasis_expires, COALESCE(at.flags, a.flags) FROM person pe JOIN player pl ON pl.person = pe.id LEFT JOIN access a ON a.person = pe.id LEFT JOIN access_template at ON at.id = a.template WHERE pl.active = 1""") var.PREFER_NOTICE_ACCS = set() # Same as above, except accounts. takes precedence var.STASISED_ACCS = defaultdict(int) var.PING_IF_PREFS_ACCS = {} var.PING_IF_NUMS_ACCS = defaultdict(set) var.DEADCHAT_PREFS_ACCS = set() var.FLAGS_ACCS = defaultdict(str) var.DENY_ACCS = defaultdict(set) for acc, notice, dc, pi, stasis, stasisexp, flags in c: if acc is not None: lacc = lower(acc) if notice == 1: var.PREFER_NOTICE_ACCS.add(lacc) if stasis > 0: var.STASISED_ACCS[lacc] = stasis if pi is not None and pi > 0: var.PING_IF_PREFS_ACCS[lacc] = pi var.PING_IF_NUMS_ACCS[pi].add(lacc) if dc == 1: var.DEADCHAT_PREFS_ACCS.add(lacc) if flags: var.FLAGS_ACCS[lacc] = flags c.execute("""SELECT pl.account_display, ws.data FROM warning w JOIN warning_sanction ws ON ws.warning = w.id JOIN person pe ON pe.id = w.target JOIN player pl ON pl.person = pe.id WHERE ws.sanction = 'deny command' AND w.deleted = 0 AND ( w.expires IS NULL OR w.expires > datetime('now') )""") for acc, command in c: if acc is not None: lacc = lower(acc) var.DENY_ACCS[lacc].add(command)
def _get_ids(acc, add=False, casemap="ascii"): from src.context import lower conn = _conn() c = conn.cursor() if acc == "*": acc = None if acc is None: return (None, None) ascii_acc = lower(acc, casemapping="ascii") rfc1459_acc = lower(acc, casemapping="rfc1459") strict_acc = lower(acc, casemapping="strict-rfc1459") c.execute("""SELECT pe.id, pl.id, pl.account_display FROM player pl JOIN person pe ON pe.id = pl.person WHERE pl.account_lower_{0} = ? AND pl.active = 1""".format(casemap), (acc,)) row = c.fetchone() peid = None plid = None if not row: # Maybe have an IRC casefolded version of this account in the db # Check in order of most restrictive to least restrictive # If all three casemappings fail to match, row will still be None if casemap == "ascii": peid, plid = _get_ids(strict_acc, add=add, casemap="rfc1459_strict") row = peid, plid, None elif casemap == "rfc1459_strict": peid, plid = _get_ids(rfc1459_acc, add=add, casemap="rfc1459") row = peid, plid, None if row: peid, plid, display_acc = row if acc != display_acc: # normalize case in the db to what it should be c.execute("""UPDATE player SET account_display=?, account_lower_ascii=?, account_lower_rfc1459=?, account_lower_rfc1459_strict=? WHERE id=?""", (acc, ascii_acc, rfc1459_acc, strict_acc, row[1])) conn.commit() # fix up our vars init_vars() elif add: c.execute("""INSERT INTO player ( account_display, account_lower_ascii, account_lower_rfc1459, account_lower_rfc1459_strict ) VALUES (?, ?, ?, ?)""", (acc, ascii_acc, rfc1459_acc, strict_acc)) plid = c.lastrowid c.execute("INSERT INTO person (primary_player) VALUES (?)", (plid,)) peid = c.lastrowid c.execute("UPDATE player SET person=? WHERE id=?", (peid, plid)) conn.commit() return (peid, plid)
def irc_lower(nick): from src.context import lower return lower(nick)
def irc_lower(nick): # FIXME: deprecated, use src.context.lower from src.context import lower return lower(nick)