Expand host-based variabls to take full-on hostmasks

This allows for things like making ADMINS/OWNERS take a full hostmask,
or fallowing/fdenying a full hostmask with wildcards. It also allows for
a distinction between two people that share a hostmask but have a
different ident.

stasis now checks all matching stasis and returns the highest amount

fallow/fdeny have two new options -acc and -host to explicitly specify
what type the argument is

-cmds in fallow/fdeny show commands from all matching masks, to bring it
in line with how actual allow/deny parsing works, before it would only
show the first match
This commit is contained in:
skizzerz 2015-08-25 18:39:01 -05:00
parent 0d316d1ec6
commit f5ec9c9627
3 changed files with 276 additions and 220 deletions

View File

@ -52,10 +52,13 @@ class cmd:
largs = list(args) largs = list(args)
cli, rawnick, chan, rest = largs cli, rawnick, chan, rest = largs
nick, mode, user, cloak = parse_nick(rawnick) nick, mode, ident, host = parse_nick(rawnick)
if cloak is None: if ident is None:
cloak = "" ident = ""
if host is None:
host = ""
if not self.raw_nick: if not self.raw_nick:
largs[1] = nick largs[1] = nick
@ -110,7 +113,7 @@ class cmd:
return self.func(*largs) # don't check restrictions for role commands return self.func(*largs) # don't check restrictions for role commands
if self.owner_only: if self.owner_only:
if var.is_owner(nick, cloak): if var.is_owner(nick, ident, host):
adminlog(chan, rawnick, self.name, rest) adminlog(chan, rawnick, self.name, rest)
return self.func(*largs) return self.func(*largs)
@ -120,33 +123,31 @@ class cmd:
cli.notice(nick, "You are not the owner.") cli.notice(nick, "You are not the owner.")
return return
if var.is_admin(nick, cloak): if var.is_admin(nick, ident, host):
if self.admin_only: if self.admin_only:
adminlog(chan, rawnick, self.name, rest) adminlog(chan, rawnick, self.name, rest)
return self.func(*largs) return self.func(*largs)
if not var.DISABLE_ACCOUNTS and acc: if not var.DISABLE_ACCOUNTS and acc:
for pattern in var.DENY_ACCOUNTS: if acc in var.DENY_ACCOUNTS:
if fnmatch.fnmatch(acc.lower(), pattern.lower()): for command in self.cmds:
for command in self.cmds: if command in var.DENY_ACCOUNTS[acc]:
if command in var.DENY_ACCOUNTS[pattern]: if chan == nick:
if chan == nick: pm(cli, nick, "You do not have permission to use that command.")
pm(cli, nick, "You do not have permission to use that command.") else:
else: cli.notice(nick, "You do not have permission to use that command.")
cli.notice(nick, "You do not have permission to use that command.") return
return
for pattern in var.ALLOW_ACCOUNTS: if acc in var.ALLOW_ACCOUNTS:
if fnmatch.fnmatch(acc.lower(), pattern.lower()): for command in self.cmds:
for command in self.cmds: if command in var.ALLOW_ACCOUNTS[acc]:
if command in var.ALLOW_ACCOUNTS[pattern]: if self.admin_only:
if self.admin_only: adminlog(chan, rawnick, self.name, rest)
adminlog(chan, rawnick, self.name, rest) return self.func(*largs)
return self.func(*largs)
if not var.ACCOUNTS_ONLY and cloak: if not var.ACCOUNTS_ONLY and host:
for pattern in var.DENY: for pattern in var.DENY:
if fnmatch.fnmatch(cloak.lower(), pattern.lower()): if var.match_hostmask(pattern, nick, ident, host):
for command in self.cmds: for command in self.cmds:
if command in var.DENY[pattern]: if command in var.DENY[pattern]:
if chan == nick: if chan == nick:
@ -156,7 +157,7 @@ class cmd:
return return
for pattern in var.ALLOW: for pattern in var.ALLOW:
if fnmatch.fnmatch(cloak.lower(), pattern.lower()): if var.match_hostmask(pattern, nick, ident, host):
for command in self.cmds: for command in self.cmds:
if command in var.ALLOW[pattern]: if command in var.ALLOW[pattern]:
if self.admin_only: if self.admin_only:

View File

@ -2,6 +2,7 @@ import fnmatch
import math import math
import random import random
import sqlite3 import sqlite3
import re
from collections import defaultdict, OrderedDict from collections import defaultdict, OrderedDict
import botconfig import botconfig
@ -328,6 +329,18 @@ PING_IF_NUMS_ACCS = {}
is_role = lambda plyr, rol: rol in ROLES and plyr in ROLES[rol] is_role = lambda plyr, rol: rol in ROLES and plyr in ROLES[rol]
def match_hostmask(hostmask, nick, ident, host):
# support n!u@h, u@h, or just h by itself
matches = re.match('(?:(?:(.*?)!)?(.*?)@)?(.*)', hostmask.lower())
if ((not matches.group(1) or fnmatch.fnmatch(nick.lower(), matches.group(1))) and
(not matches.group(2) or fnmatch.fnmatch(ident.lower(), matches.group(2))) and
fnmatch.fnmatch(host.lower(), matches.group(3))):
return True
return False
def check_priv(priv): def check_priv(priv):
assert priv in ("owner", "admin") assert priv in ("owner", "admin")
@ -339,10 +352,12 @@ def check_priv(priv):
hosts.update(botconfig.ADMINS) hosts.update(botconfig.ADMINS)
accounts.update(botconfig.ADMINS_ACCOUNTS) accounts.update(botconfig.ADMINS_ACCOUNTS)
def do_check(nick, cloak=None, acc=None): def do_check(nick, ident=None, host=None, acc=None):
if nick in USERS.keys(): if nick in USERS.keys():
if not cloak: if not ident:
cloak = USERS[nick]["cloak"] ident = USERS[nick]["ident"]
if not host:
host = USERS[nick]["host"]
if not acc: if not acc:
acc = USERS[nick]["account"] acc = USERS[nick]["account"]
@ -351,9 +366,9 @@ def check_priv(priv):
if fnmatch.fnmatch(acc.lower(), pattern.lower()): if fnmatch.fnmatch(acc.lower(), pattern.lower()):
return True return True
if cloak: if host:
for pattern in hosts: for hostmask in hosts:
if fnmatch.fnmatch(cloak.lower(), pattern.lower()): if match_hostmask(hostmask, nick, ident, host):
return True return True
return False return False

View File

@ -194,15 +194,15 @@ def connect_callback(cli):
if not stat in var.MODES_PREFIXES: if not stat in var.MODES_PREFIXES:
continue continue
newstat += var.MODES_PREFIXES[stat] newstat += var.MODES_PREFIXES[stat]
var.USERS[nick] = dict(cloak=host,account="*",inchan=True,modes=set(newstat),moded=set()) var.USERS[nick] = dict(ident=user,host=host,account="*",inchan=True,modes=set(newstat),moded=set())
@hook("whospcrpl", hookid=295) @hook("whospcrpl", hookid=295)
def on_whoreply(cli, server, nick, ident, cloak, _, user, status, acc): def on_whoreply(cli, server, nick, ident, host, _, user, status, acc):
if user in var.USERS: return # Don't add someone who is already there if user in var.USERS: return # Don't add someone who is already there
if user == botconfig.NICK: if user == botconfig.NICK:
cli.nickname = user cli.nickname = user
cli.ident = ident cli.ident = ident
cli.hostmask = cloak cli.hostmask = host
if acc == "0": if acc == "0":
acc = "*" acc = "*"
if "+" in status: if "+" in status:
@ -212,7 +212,7 @@ def connect_callback(cli):
if not stat in var.MODES_PREFIXES: if not stat in var.MODES_PREFIXES:
continue continue
newstat += var.MODES_PREFIXES[stat] newstat += var.MODES_PREFIXES[stat]
var.USERS[user] = dict(cloak=cloak,account=acc,inchan=True,modes=set(newstat),moded=set()) var.USERS[user] = dict(ident=ident,host=host,account=acc,inchan=True,modes=set(newstat),moded=set())
@hook("endofwho", hookid=295) @hook("endofwho", hookid=295)
def afterwho(*args): def afterwho(*args):
@ -431,7 +431,7 @@ def reset():
var.DEAD = set() var.DEAD = set()
var.ROLES = {"person" : set()} var.ROLES = {"person" : set()}
var.ALL_PLAYERS = [] var.ALL_PLAYERS = []
var.JOINED_THIS_GAME = set() # keeps track of who already joined this game at least once (cloaks) var.JOINED_THIS_GAME = set() # keeps track of who already joined this game at least once (hostmasks)
var.JOINED_THIS_GAME_ACCS = set() # same, except accounts var.JOINED_THIS_GAME_ACCS = set() # same, except accounts
var.PINGED_ALREADY = set() var.PINGED_ALREADY = set()
var.PINGED_ALREADY_ACCS = set() var.PINGED_ALREADY_ACCS = set()
@ -450,13 +450,14 @@ reset()
def make_stasis(nick, penalty): def make_stasis(nick, penalty):
if nick in var.USERS: if nick in var.USERS:
cloak = var.USERS[nick]["cloak"] ident = var.USERS[nick]["ident"]
host = var.USERS[nick]["host"]
acc = var.USERS[nick]["account"] acc = var.USERS[nick]["account"]
else: else:
return # Can't do it return # Can't do it
if not acc or acc == "*": if not acc or acc == "*":
acc = None acc = None
if not cloak and not acc: if not host and not acc:
return # Can't do it, either return # Can't do it, either
if acc: if acc:
if penalty == 0: if penalty == 0:
@ -466,14 +467,15 @@ def make_stasis(nick, penalty):
else: else:
var.STASISED_ACCS[acc] += penalty var.STASISED_ACCS[acc] += penalty
var.set_stasis_acc(acc, var.STASISED_ACCS[acc]) var.set_stasis_acc(acc, var.STASISED_ACCS[acc])
if (not var.ACCOUNTS_ONLY or not acc) and cloak: if (not var.ACCOUNTS_ONLY or not acc) and host:
hostmask = ident + "@" + host
if penalty == 0: if penalty == 0:
if cloak in var.STASISED: if hostmask in var.STASISED:
del var.STASISED[cloak] del var.STASISED[hostmask]
var.set_stasis(cloak, 0) var.set_stasis(hostmask, 0)
else: else:
var.STASISED[cloak] += penalty var.STASISED[hostmask] += penalty
var.set_stasis(cloak, var.STASISED[cloak]) var.set_stasis(hostmask, var.STASISED[hostmask])
@cmd("fsync", admin_only=True, pm=True) @cmd("fsync", admin_only=True, pm=True)
def fsync(cli, nick, chan, rest): def fsync(cli, nick, chan, rest):
@ -610,7 +612,7 @@ def restart_program(cli, nick, chan, rest):
@hook("quit") @hook("quit")
def restart_buffer(cli, raw_nick, reason): def restart_buffer(cli, raw_nick, reason):
nick, _, __, cloak = parse_nick(raw_nick) nick, _, __, host = parse_nick(raw_nick)
# restart the bot once our quit message goes though to ensure entire IRC queue is sent # restart the bot once our quit message goes though to ensure entire IRC queue is sent
# if the bot is using a nick that isn't botconfig.NICK, then stop breaking things and fdie # if the bot is using a nick that isn't botconfig.NICK, then stop breaking things and fdie
if nick == botconfig.NICK: if nick == botconfig.NICK:
@ -636,9 +638,10 @@ def pinger(cli, nick, chan, rest):
def mark_simple_notify(cli, nick, chan, rest): def mark_simple_notify(cli, nick, chan, rest):
"""Makes the bot give you simple role instructions, in case you are familiar with the roles.""" """Makes the bot give you simple role instructions, in case you are familiar with the roles."""
nick, _, __, cloak = parse_nick(nick) nick, _, ident, host = parse_nick(nick)
if nick in var.USERS: if nick in var.USERS:
cloak = var.USERS[nick]["cloak"] ident = var.USERS[nick]["ident"]
host = var.USERS[nick]["host"]
acc = var.USERS[nick]["account"] acc = var.USERS[nick]["account"]
else: else:
acc = None acc = None
@ -649,9 +652,9 @@ def mark_simple_notify(cli, nick, chan, rest):
if acc in var.SIMPLE_NOTIFY_ACCS: if acc in var.SIMPLE_NOTIFY_ACCS:
var.SIMPLE_NOTIFY_ACCS.remove(acc) var.SIMPLE_NOTIFY_ACCS.remove(acc)
var.remove_simple_rolemsg_acc(acc) var.remove_simple_rolemsg_acc(acc)
if cloak in var.SIMPLE_NOTIFY: if host in var.SIMPLE_NOTIFY:
var.SIMPLE_NOTIFY.remove(cloak) var.SIMPLE_NOTIFY.remove(host)
var.remove_simple_rolemsg(cloak) var.remove_simple_rolemsg(host)
cli.notice(nick, "You now no longer receive simple role instructions.") cli.notice(nick, "You now no longer receive simple role instructions.")
return return
@ -663,21 +666,22 @@ def mark_simple_notify(cli, nick, chan, rest):
return return
else: # Not logged in, fall back to hostmask else: # Not logged in, fall back to hostmask
if cloak in var.SIMPLE_NOTIFY: if host in var.SIMPLE_NOTIFY:
var.SIMPLE_NOTIFY.remove(cloak) var.SIMPLE_NOTIFY.remove(host)
var.remove_simple_rolemsg(cloak) var.remove_simple_rolemsg(host)
cli.notice(nick, "You now no longer receive simple role instructions.") cli.notice(nick, "You now no longer receive simple role instructions.")
return return
var.SIMPLE_NOTIFY.add(cloak) var.SIMPLE_NOTIFY.add(host)
var.add_simple_rolemsg(cloak) var.add_simple_rolemsg(host)
cli.notice(nick, "You now receive simple role instructions.") cli.notice(nick, "You now receive simple role instructions.")
def is_user_simple(nick): def is_user_simple(nick):
if nick in var.USERS: if nick in var.USERS:
cloak = var.USERS[nick]["cloak"] ident = var.USERS[nick]["ident"]
host = var.USERS[nick]["host"]
acc = var.USERS[nick]["account"] acc = var.USERS[nick]["account"]
else: else:
return False return False
@ -685,17 +689,20 @@ def is_user_simple(nick):
if acc in var.SIMPLE_NOTIFY_ACCS: if acc in var.SIMPLE_NOTIFY_ACCS:
return True return True
return False return False
elif cloak in var.SIMPLE_NOTIFY and not var.ACCOUNTS_ONLY: elif not var.ACCOUNTS_ONLY:
return True for hostmask in var.SIMPLE_NOTIFY:
if var.match_hostmask(hostmask, nick, ident, host):
return True
return False return False
@cmd("notice", raw_nick=True, pm=True) @cmd("notice", raw_nick=True, pm=True)
def mark_prefer_notice(cli, nick, chan, rest): def mark_prefer_notice(cli, nick, chan, rest):
"""Makes the bot NOTICE you for every interaction.""" """Makes the bot NOTICE you for every interaction."""
nick, _, __, cloak = parse_nick(nick) nick, _, ident, host = parse_nick(nick)
if nick in var.USERS: if nick in var.USERS:
cloak = var.USERS[nick]["cloak"] ident = var.USERS[nick]["ident"]
host = var.USERS[nick]["host"]
acc = var.USERS[nick]["account"] acc = var.USERS[nick]["account"]
else: else:
acc = None acc = None
@ -706,9 +713,9 @@ def mark_prefer_notice(cli, nick, chan, rest):
if acc in var.PREFER_NOTICE_ACCS: if acc in var.PREFER_NOTICE_ACCS:
var.PREFER_NOTICE_ACCS.remove(acc) var.PREFER_NOTICE_ACCS.remove(acc)
var.remove_prefer_notice_acc(acc) var.remove_prefer_notice_acc(acc)
if cloak in var.PREFER_NOTICE: if host in var.PREFER_NOTICE:
var.PREFER_NOTICE.remove(cloak) var.PREFER_NOTICE.remove(host)
var.remove_prefer_notice(cloak) var.remove_prefer_notice(host)
cli.notice(nick, "Gameplay interactions will now use PRIVMSG for you.") cli.notice(nick, "Gameplay interactions will now use PRIVMSG for you.")
return return
@ -720,15 +727,15 @@ def mark_prefer_notice(cli, nick, chan, rest):
return return
else: # Not logged in else: # Not logged in
if cloak in var.PREFER_NOTICE: if host in var.PREFER_NOTICE:
var.PREFER_NOTICE.remove(cloak) var.PREFER_NOTICE.remove(host)
var.remove_prefer_notice(cloak) var.remove_prefer_notice(host)
cli.notice(nick, "Gameplay interactions will now use PRIVMSG for you.") cli.notice(nick, "Gameplay interactions will now use PRIVMSG for you.")
return return
var.PREFER_NOTICE.add(cloak) var.PREFER_NOTICE.add(host)
var.add_prefer_notice(cloak) var.add_prefer_notice(host)
cli.notice(nick, "The bot will now always NOTICE you.") cli.notice(nick, "The bot will now always NOTICE you.")
@ -736,8 +743,12 @@ def is_user_notice(nick):
if nick in var.USERS and var.USERS[nick]["account"] and var.USERS[nick]["account"] != "*" and not var.DISABLE_ACCOUNTS: if nick in var.USERS and var.USERS[nick]["account"] and var.USERS[nick]["account"] != "*" and not var.DISABLE_ACCOUNTS:
if var.USERS[nick]["account"] in var.PREFER_NOTICE_ACCS: if var.USERS[nick]["account"] in var.PREFER_NOTICE_ACCS:
return True return True
if nick in var.USERS and var.USERS[nick]["cloak"] in var.PREFER_NOTICE and not var.ACCOUNTS_ONLY: if nick in var.USERS and not var.ACCOUNTS_ONLY:
return True ident = var.USERS[nick]["ident"]
host = var.USERS[nick]["host"]
for hostmask in var.PREFER_NOTICE:
if var.match_hostmask(hostmask, nick, ident, host):
return True
return False return False
@cmd("swap", "replace", pm=True, phases=("join", "day", "night")) @cmd("swap", "replace", pm=True, phases=("join", "day", "night"))
@ -821,7 +832,8 @@ def altpinger(cli, nick, chan, rest):
players = is_user_altpinged(nick) players = is_user_altpinged(nick)
rest = rest.split() rest = rest.split()
if nick in var.USERS: if nick in var.USERS:
cloak = var.USERS[nick]["cloak"] ident = var.USERS[nick]["ident"]
host = var.USERS[nick]["host"]
acc = var.USERS[nick]["account"] acc = var.USERS[nick]["account"]
else: else:
if chan == nick: if chan == nick:
@ -880,20 +892,24 @@ def altpinger(cli, nick, chan, rest):
def is_user_altpinged(nick): def is_user_altpinged(nick):
if nick in var.USERS.keys(): if nick in var.USERS.keys():
cloak = var.USERS[nick]["cloak"] ident = var.USERS[nick]["ident"]
host = var.USERS[nick]["host"]
acc = var.USERS[nick]["account"] acc = var.USERS[nick]["account"]
else: else:
return 0 return 0
if not var.DISABLE_ACCOUNTS and acc and acc != "*": if not var.DISABLE_ACCOUNTS and acc and acc != "*":
if acc in var.PING_IF_PREFS_ACCS.keys(): if acc in var.PING_IF_PREFS_ACCS.keys():
return var.PING_IF_PREFS_ACCS[acc] return var.PING_IF_PREFS_ACCS[acc]
elif not var.ACCOUNTS_ONLY and cloak in var.PING_IF_PREFS.keys(): elif not var.ACCOUNTS_ONLY:
return var.PING_IF_PREFS[cloak] for hostmask, pref in var.PING_IF_PREFS.items():
if var.match_hostmask(hostmask, nick, ident, host):
return pref
return 0 return 0
def toggle_altpinged_status(nick, value, old=None): def toggle_altpinged_status(nick, value, old=None):
# nick should be in var.USERS if not fake; if not, let the error propagate # nick should be in var.USERS if not fake; if not, let the error propagate
cloak = var.USERS[nick]["cloak"] ident = var.USERS[nick]["ident"]
host = var.USERS[nick]["host"]
acc = var.USERS[nick]["account"] acc = var.USERS[nick]["account"]
if value == 0: if value == 0:
if not var.DISABLE_ACCOUNTS and acc and acc != "*": if not var.DISABLE_ACCOUNTS and acc and acc != "*":
@ -904,13 +920,16 @@ def toggle_altpinged_status(nick, value, old=None):
with var.WARNING_LOCK: with var.WARNING_LOCK:
if old in var.PING_IF_NUMS_ACCS: if old in var.PING_IF_NUMS_ACCS:
var.PING_IF_NUMS_ACCS[old].discard(acc) var.PING_IF_NUMS_ACCS[old].discard(acc)
if not var.ACCOUNTS_ONLY and cloak in var.PING_IF_PREFS: if not var.ACCOUNTS_ONLY:
del var.PING_IF_PREFS[cloak] for hostmask in list(var.PING_IF_PREFS.keys()):
var.set_pingif_status(cloak, False, 0) if var.match_hostmask(hostmask, nick, ident, host):
if old is not None: del var.PING_IF_PREFS[hostmask]
with var.WARNING_LOCK: var.set_pingif_status(hostmask, False, 0)
if old in var.PING_IF_NUMS: if old is not None:
var.PING_IF_NUMS[old].discard(cloak) with var.WARNING_LOCK:
if old in var.PING_IF_NUMS.keys():
var.PING_IF_NUMS[old].discard(host)
var.PING_IF_NUMS[old].discard(hostmask)
else: else:
if not var.DISABLE_ACCOUNTS and acc and acc != "*": if not var.DISABLE_ACCOUNTS and acc and acc != "*":
var.PING_IF_PREFS_ACCS[acc] = value var.PING_IF_PREFS_ACCS[acc] = value
@ -923,15 +942,17 @@ def toggle_altpinged_status(nick, value, old=None):
if old in var.PING_IF_NUMS_ACCS: if old in var.PING_IF_NUMS_ACCS:
var.PING_IF_NUMS_ACCS[old].discard(acc) var.PING_IF_NUMS_ACCS[old].discard(acc)
elif not var.ACCOUNTS_ONLY: elif not var.ACCOUNTS_ONLY:
var.PING_IF_PREFS[cloak] = value hostmask = ident + "@" + host
var.set_pingif_status(cloak, False, value) var.PING_IF_PREFS[hostmask] = value
var.set_pingif_status(hostmask, False, value)
with var.WARNING_LOCK: with var.WARNING_LOCK:
if value not in var.PING_IF_NUMS: if value not in var.PING_IF_NUMS.keys():
var.PING_IF_NUMS[value] = set() var.PING_IF_NUMS[value] = set()
var.PING_IF_NUMS[value].add(cloak) var.PING_IF_NUMS[value].add(hostmask)
if old is not None: if old is not None:
if old in var.PING_IF_NUMS: if old in var.PING_IF_NUMS.keys():
var.PING_IF_NUMS[old].discard(cloak) var.PING_IF_NUMS[old].discard(host)
var.PING_IF_NUMS[old].discard(hostmask)
def join_timer_handler(cli): def join_timer_handler(cli):
with var.WARNING_LOCK: with var.WARNING_LOCK:
@ -963,9 +984,9 @@ def join_timer_handler(cli):
if acc in var.PINGED_ALREADY_ACCS: if acc in var.PINGED_ALREADY_ACCS:
chk_acc.remove(acc) chk_acc.remove(acc)
for cloak in frozenset(checker): for hostmask in frozenset(checker):
if cloak in var.PINGED_ALREADY: if hostmask in var.PINGED_ALREADY:
checker.remove(cloak) checker.remove(hostmask)
# If there is nobody to ping, do nothing # If there is nobody to ping, do nothing
if not chk_acc and not checker: if not chk_acc and not checker:
@ -973,17 +994,18 @@ def join_timer_handler(cli):
return return
@hook("whoreply", hookid=387) @hook("whoreply", hookid=387)
def ping_altpingers_noacc(cli, svr, botnick, chan, user, host, server, nick, status, rest): def ping_altpingers_noacc(cli, svr, botnick, chan, ident, host, server, nick, status, rest):
if ("G" in status or is_user_stasised(nick) or not var.PINGING_IFS or if ("G" in status or is_user_stasised(nick) or not var.PINGING_IFS or
nick == botnick or nick in pl): nick == botnick or nick in pl):
return return
if host in checker: hostmask = ident + "@" + host
if hostmask in checker:
to_ping.append(nick) to_ping.append(nick)
var.PINGED_ALREADY.add(host) var.PINGED_ALREADY.add(hostmask)
@hook("whospcrpl", hookid=387) @hook("whospcrpl", hookid=387)
def ping_altpingers(cli, server, nick, ident, cloak, _, user, status, acc): def ping_altpingers(cli, server, nick, ident, host, _, user, status, acc):
if ("G" in status or is_user_stasised(user) or not var.PINGING_IFS or if ("G" in status or is_user_stasised(user) or not var.PINGING_IFS or
user == botconfig.NICK or user in pl): user == botconfig.NICK or user in pl):
@ -996,8 +1018,9 @@ def join_timer_handler(cli):
var.PINGED_ALREADY_ACCS.add(acc) var.PINGED_ALREADY_ACCS.add(acc)
elif not var.ACCOUNTS_ONLY: elif not var.ACCOUNTS_ONLY:
hostmask = ident + "@" + host
to_ping.append(user) to_ping.append(user)
var.PINGED_ALREADY.add(cloak) var.PINGED_ALREADY.add(hostmask)
@hook("endofwho", hookid=387) @hook("endofwho", hookid=387)
def fetch_altpingers(*stuff): def fetch_altpingers(*stuff):
@ -1054,11 +1077,13 @@ def join_player(cli, player, chan, who = None, forced = False):
return return
if player in var.USERS: if player in var.USERS:
cloak = var.USERS[player]["cloak"] ident = var.USERS[player]["ident"]
host = var.USERS[player]["host"]
acc = var.USERS[player]["account"] acc = var.USERS[player]["account"]
elif is_fake_nick(player) and botconfig.DEBUG_MODE: elif is_fake_nick(player) and botconfig.DEBUG_MODE:
# fakenick # fakenick
cloak = None ident = None
host = None
acc = None acc = None
else: else:
return # Not normal return # Not normal
@ -1069,9 +1094,10 @@ def join_player(cli, player, chan, who = None, forced = False):
if stasis: if stasis:
if forced and stasis == 1: if forced and stasis == 1:
if cloak in var.STASISED: for hostmask in list(var.STASISED.keys()):
var.set_stasis(cloak, 0) if var.match_hostmask(hostmask, nick, ident, host):
del var.STASISED[cloak] var.set_stasis(hostmask, 0)
del var.STASISED[hostmask]
if not var.DISABLE_ACCOUNTS and acc in var.STASISED_ACCS: if not var.DISABLE_ACCOUNTS and acc in var.STASISED_ACCS:
var.set_stasis_acc(acc, 0) var.set_stasis_acc(acc, 0)
del var.STASISED_ACCS[acc] del var.STASISED_ACCS[acc]
@ -1099,8 +1125,8 @@ def join_player(cli, player, chan, who = None, forced = False):
var.GAME_ID = time.time() var.GAME_ID = time.time()
var.PINGED_ALREADY_ACCS = set() var.PINGED_ALREADY_ACCS = set()
var.PINGED_ALREADY = set() var.PINGED_ALREADY = set()
if cloak: if host:
var.JOINED_THIS_GAME.add(cloak) var.JOINED_THIS_GAME.add(ident + "@" + host)
if acc: if acc:
var.JOINED_THIS_GAME_ACCS.add(acc) var.JOINED_THIS_GAME_ACCS.add(acc)
var.CAN_START_TIME = datetime.now() + timedelta(seconds=var.MINIMUM_WAIT) var.CAN_START_TIME = datetime.now() + timedelta(seconds=var.MINIMUM_WAIT)
@ -1145,9 +1171,10 @@ def join_player(cli, player, chan, who = None, forced = False):
var.USERS[player]["modes"] = set() var.USERS[player]["modes"] = set()
mass_mode(cli, cmodes, []) mass_mode(cli, cmodes, [])
cli.msg(chan, "\u0002{0}\u0002 has joined the game and raised the number of players to \u0002{1}\u0002.".format(player, len(pl) + 1)) cli.msg(chan, "\u0002{0}\u0002 has joined the game and raised the number of players to \u0002{1}\u0002.".format(player, len(pl) + 1))
if not is_fake_nick(player) and not cloak in var.JOINED_THIS_GAME and (not acc or not acc in var.JOINED_THIS_GAME_ACCS): hostmask = ident + "@" + host
if not is_fake_nick(player) and not hostmask in var.JOINED_THIS_GAME and (not acc or not acc in var.JOINED_THIS_GAME_ACCS):
# make sure this only happens once # make sure this only happens once
var.JOINED_THIS_GAME.add(cloak) var.JOINED_THIS_GAME.add(hostmask)
if acc: if acc:
var.JOINED_THIS_GAME_ACCS.add(acc) var.JOINED_THIS_GAME_ACCS.add(acc)
now = datetime.now() now = datetime.now()
@ -1289,22 +1316,24 @@ def on_kicked(cli, nick, chan, victim, reason):
@hook("account") @hook("account")
def on_account(cli, rnick, acc): def on_account(cli, rnick, acc):
nick, mode, user, cloak = parse_nick(rnick) nick, _, ident, host = parse_nick(rnick)
hostmask = ident + "@" + host
chan = botconfig.CHANNEL chan = botconfig.CHANNEL
if acc == "*" and var.ACCOUNTS_ONLY and nick in var.list_players(): if acc == "*" and var.ACCOUNTS_ONLY and nick in var.list_players():
cli.mode(chan, "-v", nick) cli.mode(chan, "-v", nick)
leave(cli, "account", nick) leave(cli, "account", nick)
cli.notice(nick, "Please reidentify to the account \u0002{0}\u0002".format(var.USERS[nick]["account"])) cli.notice(nick, "Please reidentify to the account \u0002{0}\u0002".format(var.USERS[nick]["account"]))
if nick in var.USERS.keys(): if nick in var.USERS.keys():
var.USERS[nick]["cloak"] = cloak var.USERS[nick]["ident"] = ident
var.USERS[nick]["host"] = host
var.USERS[nick]["account"] = acc var.USERS[nick]["account"] = acc
if nick in var.DISCONNECTED.keys(): if nick in var.DISCONNECTED.keys():
if acc == var.DISCONNECTED[nick][0]: if acc == var.DISCONNECTED[nick][0]:
if nick in var.USERS and var.USERS[nick]["inchan"]: if nick in var.USERS and var.USERS[nick]["inchan"]:
with var.GRAVEYARD_LOCK: with var.GRAVEYARD_LOCK:
clk = var.DISCONNECTED[nick][1] hm = var.DISCONNECTED[nick][1]
act = var.DISCONNECTED[nick][0] act = var.DISCONNECTED[nick][0]
if (acc == act and not var.DISABLE_ACCOUNTS) or (cloak == clk and not var.ACCOUNTS_ONLY): if (acc == act and not var.DISABLE_ACCOUNTS) or (hostmask == hm and not var.ACCOUNTS_ONLY):
cli.mode(chan, "+v", nick, nick+"!*@*") cli.mode(chan, "+v", nick, nick+"!*@*")
del var.DISCONNECTED[nick] del var.DISCONNECTED[nick]
var.LAST_SAID_TIME[nick] = datetime.now() var.LAST_SAID_TIME[nick] = datetime.now()
@ -3014,7 +3043,7 @@ def reaper(cli, gameid):
mass_privmsg(cli, msg_targets, ("\u0002You have been idling in {0} for a while. Please say something in {0} "+ mass_privmsg(cli, msg_targets, ("\u0002You have been idling in {0} for a while. Please say something in {0} "+
"or you will be declared dead.\u0002").format(chan), privmsg=True) "or you will be declared dead.\u0002").format(chan), privmsg=True)
for dcedplayer in list(var.DISCONNECTED.keys()): for dcedplayer in list(var.DISCONNECTED.keys()):
acc, cloak, timeofdc, what = var.DISCONNECTED[dcedplayer] acc, hostmask, timeofdc, what = var.DISCONNECTED[dcedplayer]
if what in ("quit", "badnick") and (datetime.now() - timeofdc) > timedelta(seconds=var.QUIT_GRACE_TIME): if what in ("quit", "badnick") and (datetime.now() - timeofdc) > timedelta(seconds=var.QUIT_GRACE_TIME):
if var.get_role(dcedplayer) != "person" and var.ROLE_REVEAL in ("on", "team"): if var.get_role(dcedplayer) != "person" and var.ROLE_REVEAL in ("on", "team"):
cli.msg(chan, ("\u0002{0}\u0002 was mauled by wild animals and has died. It seems that "+ cli.msg(chan, ("\u0002{0}\u0002 was mauled by wild animals and has died. It seems that "+
@ -3071,12 +3100,13 @@ def update_last_said(cli, nick, chan, rest):
@hook("join") @hook("join")
def on_join(cli, raw_nick, chan, acc="*", rname=""): def on_join(cli, raw_nick, chan, acc="*", rname=""):
nick,m,u,cloak = parse_nick(raw_nick) nick, _, ident, host = parse_nick(raw_nick)
if nick != botconfig.NICK: if nick != botconfig.NICK:
if nick not in var.USERS.keys(): if nick not in var.USERS.keys():
var.USERS[nick] = dict(cloak=cloak,account=acc,inchan=chan == botconfig.CHANNEL,modes=set(),moded=set()) var.USERS[nick] = dict(ident=ident,host=host,account=acc,inchan=chan == botconfig.CHANNEL,modes=set(),moded=set())
else: else:
var.USERS[nick]["cloak"] = cloak var.USERS[nick]["ident"] = ident
var.USERS[nick]["host"] = host
var.USERS[nick]["account"] = acc var.USERS[nick]["account"] = acc
if not var.USERS[nick]["inchan"]: if not var.USERS[nick]["inchan"]:
# Will be True if the user joined the main channel, else False # Will be True if the user joined the main channel, else False
@ -3084,10 +3114,11 @@ def on_join(cli, raw_nick, chan, acc="*", rname=""):
if chan != botconfig.CHANNEL: if chan != botconfig.CHANNEL:
return return
with var.GRAVEYARD_LOCK: with var.GRAVEYARD_LOCK:
hostmask = ident + "@" + host
if nick in var.DISCONNECTED.keys(): if nick in var.DISCONNECTED.keys():
clk = var.DISCONNECTED[nick][1] hm = var.DISCONNECTED[nick][1]
act = var.DISCONNECTED[nick][0] act = var.DISCONNECTED[nick][0]
if (acc == act and not var.DISABLE_ACCOUNTS) or (cloak == clk and not var.ACCOUNTS_ONLY): if (acc == act and not var.DISABLE_ACCOUNTS) or (hostmask == hm and not var.ACCOUNTS_ONLY):
cli.mode(chan, "+v", nick, nick+"!*@*") cli.mode(chan, "+v", nick, nick+"!*@*")
del var.DISCONNECTED[nick] del var.DISCONNECTED[nick]
var.LAST_SAID_TIME[nick] = datetime.now() var.LAST_SAID_TIME[nick] = datetime.now()
@ -3351,16 +3382,18 @@ def rename_player(cli, prefix, nick):
if var.PHASE in ("night", "day"): if var.PHASE in ("night", "day"):
with var.GRAVEYARD_LOCK: with var.GRAVEYARD_LOCK:
if nick in var.DISCONNECTED.keys(): if nick in var.DISCONNECTED.keys():
clk = var.DISCONNECTED[nick][1] hm = var.DISCONNECTED[nick][1]
act = var.DISCONNECTED[nick][0] act = var.DISCONNECTED[nick][0]
if nick in var.USERS: if nick in var.USERS:
cloak = var.USERS[nick]["cloak"] ident = var.USERS[nick]["ident"]
host = var.USERS[nick]["host"]
acc = var.USERS[nick]["account"] acc = var.USERS[nick]["account"]
else: else:
acc = None acc = None
if not acc or acc == "*": if not acc or acc == "*":
acc = None acc = None
if (acc and acc == act) or (cloak == clk and not var.ACCOUNTS_ONLY): hostmask = ident + "@" + host
if (acc and acc == act) or (hostmask == hm and not var.ACCOUNTS_ONLY):
cli.mode(chan, "+v", nick, nick+"!*@*") cli.mode(chan, "+v", nick, nick+"!*@*")
del var.DISCONNECTED[nick] del var.DISCONNECTED[nick]
var.LAST_SAID_TIME[nick] = datetime.now() var.LAST_SAID_TIME[nick] = datetime.now()
@ -3378,7 +3411,7 @@ def rename_player(cli, prefix, nick):
@hook("nick") @hook("nick")
def on_nick(cli, oldnick, nick): def on_nick(cli, oldnick, nick):
prefix,u,m,cloak = parse_nick(oldnick) prefix, _, ident, host = parse_nick(oldnick)
chan = botconfig.CHANNEL chan = botconfig.CHANNEL
if (nick.startswith("Guest") or nick[0].isdigit() or (nick != "away" and "away" in nick.lower())) and nick not in var.DISCONNECTED.keys() and prefix in var.list_players(): if (nick.startswith("Guest") or nick[0].isdigit() or (nick != "away" and "away" in nick.lower())) and nick not in var.DISCONNECTED.keys() and prefix in var.list_players():
@ -3403,10 +3436,11 @@ def on_nick(cli, oldnick, nick):
rename_player(cli, prefix, nick) rename_player(cli, prefix, nick)
def leave(cli, what, nick, why=""): def leave(cli, what, nick, why=""):
nick, _, _, cloak = parse_nick(nick) nick, _, ident, host = parse_nick(nick)
if nick in var.USERS: if nick in var.USERS:
acc = var.USERS[nick]["account"] acc = var.USERS[nick]["account"]
cloak = var.USERS[nick]["cloak"] ident = var.USERS[nick]["ident"]
host = var.USERS[nick]["host"]
if what == "quit" or (not what in ("account",) and why == botconfig.CHANNEL): if what == "quit" or (not what in ("account",) and why == botconfig.CHANNEL):
var.USERS[nick]["inchan"] = False var.USERS[nick]["inchan"] = False
else: else:
@ -3479,7 +3513,7 @@ def leave(cli, what, nick, why=""):
if killplayer: if killplayer:
del_player(cli, nick, death_triggers = False) del_player(cli, nick, death_triggers = False)
else: else:
var.DISCONNECTED[nick] = (acc, cloak, datetime.now(), what) var.DISCONNECTED[nick] = (acc, ident + "@" + host, datetime.now(), what)
#Functions decorated with hook do not parse the nick by default #Functions decorated with hook do not parse the nick by default
hook("part")(lambda cli, nick, *rest: leave(cli, "part", nick, rest[0])) hook("part")(lambda cli, nick, *rest: leave(cli, "part", nick, rest[0]))
@ -6701,7 +6735,7 @@ def start(cli, nick, chan, forced = False, restart = ""):
return return
if not var.FGAMED: if not var.FGAMED:
votes = {} #key = gamemode, not cloak votes = {} #key = gamemode, not hostmask
for gamemode in var.GAMEMODE_VOTES.values(): for gamemode in var.GAMEMODE_VOTES.values():
if len(villagers) >= var.GAME_MODES[gamemode][1] and len(villagers) <= var.GAME_MODES[gamemode][2]: if len(villagers) >= var.GAME_MODES[gamemode][1] and len(villagers) <= var.GAME_MODES[gamemode][2]:
votes[gamemode] = votes.get(gamemode, 0) + 1 votes[gamemode] = votes.get(gamemode, 0) + 1
@ -6987,11 +7021,11 @@ def start(cli, nick, chan, forced = False, restart = ""):
var.GAMEPHASE = "day" var.GAMEPHASE = "day"
transition_day(cli) transition_day(cli)
for cloak in list(var.STASISED.keys()): for hostmask in list(var.STASISED.keys()):
var.STASISED[cloak] -= 1 var.STASISED[hostmask] -= 1
var.set_stasis(cloak, var.STASISED[cloak]) var.set_stasis(hostmask, var.STASISED[hostmask])
if var.STASISED[cloak] <= 0: if var.STASISED[hostmask] <= 0:
del var.STASISED[cloak] del var.STASISED[hostmask]
if not var.DISABLE_ACCOUNTS: if not var.DISABLE_ACCOUNTS:
for acc in list(var.STASISED_ACCS.keys()): for acc in list(var.STASISED_ACCS.keys()):
@ -7027,26 +7061,28 @@ def fstasis(cli, nick, chan, rest):
user = data[0] user = data[0]
if user.lower() in lusers: if user.lower() in lusers:
cloak = lusers[user.lower()]["cloak"] ident = lusers[user.lower()]["ident"]
host = lusers[user.lower()]["host"]
acc = lusers[user.lower()]["account"] acc = lusers[user.lower()]["account"]
hostmask = ident + "@" + host
else: else:
cloak = user hostmask = user
acc = None acc = None
if var.ACCOUNTS_ONLY and acc == "*": if var.ACCOUNTS_ONLY and acc == "*":
acc = None acc = None
cloak = None hostmask = None
msg = "{0} is not logged in to NickServ.".format(user) msg = "{0} is not logged in to NickServ.".format(user)
if not acc and user in var.STASISED_ACCS: if not acc and user in var.STASISED_ACCS:
acc = user acc = user
err_msg = "The amount of stasis has to be a non-negative integer." err_msg = "The amount of stasis has to be a non-negative integer."
if (not var.ACCOUNTS_ONLY or not acc) and cloak: if (not var.ACCOUNTS_ONLY or not acc) and hostmask:
if len(data) == 1: if len(data) == 1:
if cloak in var.STASISED: if hostmask in var.STASISED:
plural = "" if var.STASISED[cloak] == 1 else "s" plural = "" if var.STASISED[hostmask] == 1 else "s"
msg = "\u0002{0}\u0002 (Host: {1}) is in stasis for \u0002{2}\u0002 game{3}.".format(data[0], cloak, var.STASISED[cloak], plural) msg = "\u0002{0}\u0002 (Host: {1}) is in stasis for \u0002{2}\u0002 game{3}.".format(data[0], hostmask, var.STASISED[hostmask], plural)
else: else:
msg = "\u0002{0}\u0002 (Host: {1}) is not in stasis.".format(data[0], cloak) msg = "\u0002{0}\u0002 (Host: {1}) is not in stasis.".format(data[0], hostmask)
else: else:
try: try:
amt = int(data[1]) amt = int(data[1])
@ -7069,17 +7105,17 @@ def fstasis(cli, nick, chan, rest):
amt = 2**31-1 amt = 2**31-1
if amt > 0: if amt > 0:
var.STASISED[cloak] = amt var.STASISED[hostmask] = amt
var.set_stasis(cloak, amt) var.set_stasis(hostmask, amt)
plural = "" if amt == 1 else "s" plural = "" if amt == 1 else "s"
msg = "\u0002{0}\u0002 (Host: {1}) is now in stasis for \u0002{2}\u0002 game{3}.".format(data[0], cloak, amt, plural) msg = "\u0002{0}\u0002 (Host: {1}) is now in stasis for \u0002{2}\u0002 game{3}.".format(data[0], hostmask, amt, plural)
elif amt == 0: elif amt == 0:
if cloak in var.STASISED: if hostmask in var.STASISED:
del var.STASISED[cloak] del var.STASISED[hostmask]
var.set_stasis(cloak, 0) var.set_stasis(hostmask, 0)
msg = "\u0002{0}\u0002 (Host: {1}) is no longer in stasis.".format(data[0], cloak) msg = "\u0002{0}\u0002 (Host: {1}) is no longer in stasis.".format(data[0], hostmask)
else: else:
msg = "\u0002{0}\u0002 (Host: {1}) is not in stasis.".format(data[0], cloak) msg = "\u0002{0}\u0002 (Host: {1}) is not in stasis.".format(data[0], hostmask)
if not var.DISABLE_ACCOUNTS and acc: if not var.DISABLE_ACCOUNTS and acc:
if len(data) == 1: if len(data) == 1:
if acc in var.STASISED_ACCS: if acc in var.STASISED_ACCS:
@ -7120,26 +7156,14 @@ def fstasis(cli, nick, chan, rest):
msg = "\u0002{0}\u0002 (Account: {1}) is not in stasis.".format(data[0], acc) msg = "\u0002{0}\u0002 (Account: {1}) is not in stasis.".format(data[0], acc)
elif var.STASISED or var.STASISED_ACCS: elif var.STASISED or var.STASISED_ACCS:
stasised = {} stasised = {}
cloakstas = dict(var.STASISED) for hostmask in var.STASISED:
accstas = dict(var.STASISED_ACCS)
for stas in var.USERS:
if not var.DISABLE_ACCOUNTS and var.USERS[stas]["account"] in accstas:
stasised[var.USERS[stas]["account"]+" (Account)"] = accstas.pop(var.USERS[stas]["account"])
#if var.USERS[stas]["cloak"] in cloakstas:
# del cloakstas[var.USERS[stas]["cloak"]]
elif var.USERS[stas]["cloak"] in cloakstas:
if var.DISABLE_ACCOUNTS:
stasised[var.USERS[stas]["cloak"]] = cloakstas.pop(var.USERS[stas]["cloak"])
else:
stasised[var.USERS[stas]["cloak"]+" (Host)"] = cloakstas.pop(var.USERS[stas]["cloak"])
for oldcloak in cloakstas:
if var.DISABLE_ACCOUNTS: if var.DISABLE_ACCOUNTS:
stasised[oldcloak] = cloakstas[oldcloak] stasised[hostmask] = var.STASISED[hostmask]
else: else:
stasised[oldcloak+" (Host)"] = cloakstas[oldcloak] stasised[hostmask+" (Host)"] = var.STASISED[hostmask]
if not var.DISABLE_ACCOUNTS: if not var.DISABLE_ACCOUNTS:
for oldacc in accstas: for acc in var.STASISED_ACCS:
stasised[oldacc+" (Account)"] = accstas[oldacc] stasised[acc+" (Account)"] = var.STASISED_ACCS[acc]
msg = "Currently stasised: {0}".format(", ".join( msg = "Currently stasised: {0}".format(", ".join(
"\u0002{0}\u0002 ({1})".format(usr, number) "\u0002{0}\u0002 ({1})".format(usr, number)
for usr, number in stasised.items())) for usr, number in stasised.items()))
@ -7147,14 +7171,6 @@ def fstasis(cli, nick, chan, rest):
msg = "Nobody is currently stasised." msg = "Nobody is currently stasised."
if msg: if msg:
if data:
tokens = msg.split()
if ((data[0] == cloak and tokens[1] == "({0})".format(cloak)) or
(data[0] == acc and tokens[1] == "({0})".format(acc))):
# Don't show the cloak/account twice.
msg = " ".join((tokens[0], " ".join(tokens[2:])))
if chan == nick: if chan == nick:
pm(cli, nick, msg) pm(cli, nick, msg)
else: else:
@ -7164,17 +7180,19 @@ def is_user_stasised(nick):
"""Checks if a user is in stasis. Returns a number of games in stasis.""" """Checks if a user is in stasis. Returns a number of games in stasis."""
if nick in var.USERS: if nick in var.USERS:
cloak = var.USERS[nick]["cloak"] ident = var.USERS[nick]["ident"]
host = var.USERS[nick]["host"]
acc = var.USERS[nick]["account"] acc = var.USERS[nick]["account"]
else: else:
return 0 return 0
amount = 0
if not var.DISABLE_ACCOUNTS and acc and acc != "*": if not var.DISABLE_ACCOUNTS and acc and acc != "*":
if acc in var.STASISED_ACCS: if acc in var.STASISED_ACCS:
return var.STASISED_ACCS[acc] amount = var.STASISED_ACCS[acc]
for clk in var.STASISED: for hostmask in var.STASISED:
if fnmatch.fnmatch(cloak, clk): if var.match_hostmask(hostmask, nick, ident, host):
return var.STASISED[clk] amount = max(amount, var.STASISED[hostmask])
return 0 return amount
def allow_deny(cli, nick, chan, rest, mode): def allow_deny(cli, nick, chan, rest, mode):
data = rest.split() data = rest.split()
@ -7199,6 +7217,11 @@ def allow_deny(cli, nick, chan, rest, mode):
opts["cmd"] = data[1] opts["cmd"] = data[1]
data = data[1:] data = data[1:]
elif data[0] == "-acc":
opts["acc"] = True
data = data[1:]
elif data[0] == "-host":
opts["host"] = True
else: else:
if chan == nick: if chan == nick:
pm(cli, nick, "Invalid option: {0}".format(data[0][1:])) pm(cli, nick, "Invalid option: {0}".format(data[0][1:]))
@ -7214,22 +7237,42 @@ def allow_deny(cli, nick, chan, rest, mode):
user = data[0] user = data[0]
if user.lower() in lusers: if user.lower() in lusers:
cloak = lusers[user.lower()]["cloak"] ident = lusers[user.lower()]["ident"]
host = lusers[user.lower()]["host"]
acc = lusers[user.lower()]["account"] acc = lusers[user.lower()]["account"]
hostmask = ident + "@" + host
elif opts["acc"]:
hostmask = None
acc = user
else: else:
cloak = user hostmask = user
m = re.match('(?:(?:(.*?)!)?(.*)@)?(.*)', hostmask)
user = m.group(1)
ident = m.group(2)
host = m.group(3)
acc = None acc = None
if not acc or acc == "*": if not acc or acc == "*" or opts["host"]:
acc = None acc = None
if not var.DISABLE_ACCOUNTS and acc: if not var.DISABLE_ACCOUNTS and acc:
if mode == "allow": if mode == "allow":
variable = var.ALLOW_ACCOUNTS variable = var.ALLOW_ACCOUNTS
noaccvar = var.ALLOW
else: else:
variable = var.DENY_ACCOUNTS variable = var.DENY_ACCOUNTS
noaccvar = var.DENY
if len(data) == 1: if len(data) == 1:
cmds = []
if acc in variable: if acc in variable:
cmds.extend(variable[acc])
if hostmask:
for mask in noaccvar:
if var.match_hostmask(mask, user, ident, host):
cmds.extend(noaccvar[mask])
if cmds:
msg = "\u0002{0}\u0002 (Account: {1}) is {2} the following {3}commands: {4}.".format( msg = "\u0002{0}\u0002 (Account: {1}) is {2} the following {3}commands: {4}.".format(
data[0], acc, "allowed" if mode == "allow" else "denied", "special " if mode == "allow" else "", ", ".join(variable[acc])) data[0], acc, "allowed" if mode == "allow" else "denied", "special " if mode == "allow" else "", ", ".join(variable[acc]))
else: else:
@ -7277,30 +7320,34 @@ def allow_deny(cli, nick, chan, rest, mode):
msg = "\u0002{0}\u0002 (Account: {1}) is no longer {2} commands.".format(data[0], acc, "allowed any special" if mode == 'allow' else "denied any") msg = "\u0002{0}\u0002 (Account: {1}) is no longer {2} commands.".format(data[0], acc, "allowed any special" if mode == 'allow' else "denied any")
elif var.ACCOUNTS_ONLY: elif var.ACCOUNTS_ONLY:
msg = "Error: \u0002{0}\u0002 is not logged in to NickServ.".format(data[0]) msg = "Error: \u0002{0}\u0002 is not logged in to NickServ.".format(data[0])
else: else:
if mode == "allow": if mode == "allow":
variable = var.ALLOW variable = var.ALLOW
else: else:
variable = var.DENY variable = var.DENY
if len(data) == 1: # List commands for a specific hostmask if len(data) == 1: # List commands for a specific hostmask
if cloak in variable: cmds = []
for mask in variable:
if var.match_hostmask(mask, user, ident, host):
cmds.extend(variable[mask])
if cmds:
msg = "\u0002{0}\u0002 (Host: {1}) is {2} the following {3}commands: {4}.".format( msg = "\u0002{0}\u0002 (Host: {1}) is {2} the following {3}commands: {4}.".format(
data[0], cloak, "allowed" if mode == "allow" else "denied", "special " if mode == "allow" else "", ", ".join(variable[cloak])) data[0], hostmask, "allowed" if mode == "allow" else "denied", "special " if mode == "allow" else "", ", ".join(cmds))
else: else:
msg = "\u0002{0}\u0002 (Host: {1}) is not {2} commands.".format(data[0], cloak, "allowed any special" if mode == "allow" else "denied any") msg = "\u0002{0}\u0002 (Host: {1}) is not {2} commands.".format(data[0], hostmask, "allowed any special" if mode == "allow" else "denied any")
else: else:
if cloak not in variable: if hostmask not in variable:
variable[cloak] = [] variable[hostmask] = []
commands = data[1:] commands = data[1:]
for command in commands: #add or remove commands one at a time to a specific hostmask for command in commands: #add or remove commands one at a time to a specific hostmask
if "-*" in commands: # Remove all if "-*" in commands: # Remove all
for cmd in variable[cloak]: for cmd in variable[hostmask]:
if mode == "allow": if mode == "allow":
var.remove_allow(cloak, cmd) var.remove_allow(hostmask, cmd)
else: else:
var.remove_deny(cloak, cmd) var.remove_deny(hostmask, cmd)
del variable[cloak] del variable[hostmask]
break break
if command[0] == '-': #starting with - removes if command[0] == '-': #starting with - removes
rem = True rem = True
@ -7311,26 +7358,26 @@ def allow_deny(cli, nick, chan, rest, mode):
command = command[len(botconfig.CMD_CHAR):] command = command[len(botconfig.CMD_CHAR):]
if not rem: if not rem:
if command in COMMANDS and command not in ("fdeny", "fallow", "fsend", "exec", "eval") and command not in variable[cloak]: if command in COMMANDS and command not in ("fdeny", "fallow", "fsend", "exec", "eval") and command not in variable[hostmask]:
variable[cloak].append(command) variable[hostmask].append(command)
if mode == "allow": if mode == "allow":
var.add_allow(cloak, command) var.add_allow(hostmask, command)
else: else:
var.add_deny(cloak, command) var.add_deny(hostmask, command)
elif command in variable[cloak]: elif command in variable[hostmask]:
variable[cloak].remove(command) variable[hostmask].remove(command)
if mode == "allow": if mode == "allow":
var.remove_allow(cloak, command) var.remove_allow(hostmask, command)
else: else:
var.remove_deny(cloak, command) var.remove_deny(hostmask, command)
if cloak in variable and variable[cloak]: if hostmask in variable and variable[hostmask]:
msg = "\u0002{0}\u0002 (Host: {1}) is now {2} the following {3}commands: {4}{5}.".format( msg = "\u0002{0}\u0002 (Host: {1}) is now {2} the following {3}commands: {4}{5}.".format(
data[0], cloak, "allowed" if mode == "allow" else "denied", "special " if mode == "allow" else "", botconfig.CMD_CHAR, ", {0}".format(botconfig.CMD_CHAR).join(variable[cloak])) data[0], hostmask, "allowed" if mode == "allow" else "denied", "special " if mode == "allow" else "", botconfig.CMD_CHAR, ", {0}".format(botconfig.CMD_CHAR).join(variable[hostmask]))
else: else:
if cloak in variable: if hostmask in variable:
del variable[cloak] del variable[hostmask]
msg = "\u0002{0}\u0002 (Host: {1}) is no longer {2} commands.".format(data[0], cloak, "allowed any special" if mode == "allow" else "denied any") msg = "\u0002{0}\u0002 (Host: {1}) is no longer {2} commands.".format(data[0], hostmask, "allowed any special" if mode == "allow" else "denied any")
else: else:
users_to_cmds = {} users_to_cmds = {}
@ -7351,11 +7398,11 @@ def allow_deny(cli, nick, chan, rest, mode):
else: else:
variable = var.DENY variable = var.DENY
if variable: if variable:
for cloak, varied in variable.items(): for hostmask, varied in variable.items():
if var.DISABLE_ACCOUNTS: if var.DISABLE_ACCOUNTS:
users_to_cmds[cloak] = sorted(varied, key=str.lower) users_to_cmds[hostmask] = sorted(varied, key=str.lower)
else: else:
users_to_cmds[cloak+" (Host)"] = sorted(varied, key=str.lower) users_to_cmds[hostmask+" (Host)"] = sorted(varied, key=str.lower)
if not users_to_cmds: # Deny or Allow list is empty if not users_to_cmds: # Deny or Allow list is empty
@ -7394,14 +7441,6 @@ def allow_deny(cli, nick, chan, rest, mode):
user, ", ".join(cmds)) for user, cmds in sorted(users_to_cmds.items(), key=lambda t: t[0].lower()))) user, ", ".join(cmds)) for user, cmds in sorted(users_to_cmds.items(), key=lambda t: t[0].lower())))
if msg: if msg:
if data:
tokens = msg.split()
if ((data[0] == acc and tokens[1] == "({0})".format(acc)) or
(data[0] == cloak and tokens[1] == "({0})".format(cloak))):
# Don't show the cloak/account twice.
msg = " ".join((tokens[0], " ".join(tokens[2:])))
msg = var.break_long_message(msg.split("; "), "; ") msg = var.break_long_message(msg.split("; "), "; ")
if chan == nick: if chan == nick:
@ -7507,7 +7546,7 @@ def show_rules(cli, nick, chan, rest):
@cmd("help", raw_nick=True, pm=True) @cmd("help", raw_nick=True, pm=True)
def get_help(cli, rnick, chan, rest): def get_help(cli, rnick, chan, rest):
"""Gets help.""" """Gets help."""
nick, mode, user, cloak = parse_nick(rnick) nick, _, ident, host = parse_nick(rnick)
fns = [] fns = []
rest = rest.strip().replace(botconfig.CMD_CHAR, "", 1).lower() rest = rest.strip().replace(botconfig.CMD_CHAR, "", 1).lower()
@ -7551,7 +7590,7 @@ def get_help(cli, rnick, chan, rest):
name not in fn[0].aliases and fn[0].chan): name not in fn[0].aliases and fn[0].chan):
fns.append("{0}{1}{0}".format("\u0002", name)) fns.append("{0}{1}{0}".format("\u0002", name))
afns = [] afns = []
if is_admin(nick, cloak): if is_admin(nick, ident, host):
for name, fn in COMMANDS.items(): for name, fn in COMMANDS.items():
if fn[0].admin_only and name not in fn[0].aliases: if fn[0].admin_only and name not in fn[0].aliases:
afns.append("{0}{1}{0}".format("\u0002", name)) afns.append("{0}{1}{0}".format("\u0002", name))
@ -7609,8 +7648,8 @@ def on_invite(cli, raw_nick, something, chan):
if chan == botconfig.CHANNEL: if chan == botconfig.CHANNEL:
cli.join(chan) cli.join(chan)
return # No questions return # No questions
(nick, _, _, cloak) = parse_nick(raw_nick) (nick, _, ident, host) = parse_nick(raw_nick)
if is_admin(nick, cloak): if is_admin(nick, ident, host):
cli.join(chan) # Allows the bot to be present in any channel cli.join(chan) # Allows the bot to be present in any channel
debuglog(nick, "INVITE", chan, display=True) debuglog(nick, "INVITE", chan, display=True)
else: else:
@ -7657,7 +7696,7 @@ def show_admins(cli, nick, chan, rest):
var.ADMIN_PINGING = True var.ADMIN_PINGING = True
@hook("whoreply", hookid=4) @hook("whoreply", hookid=4)
def on_whoreply(cli, server, _, chan, __, cloak, ___, user, status, ____): def on_whoreply(cli, server, _, chan, ident, host, ___, user, status, ____):
if not var.ADMIN_PINGING: if not var.ADMIN_PINGING:
return return
@ -7971,7 +8010,7 @@ def aftergame(cli, rawnick, chan, rest):
@cmd("flastgame", admin_only=True, raw_nick=True, pm=True) @cmd("flastgame", admin_only=True, raw_nick=True, pm=True)
def flastgame(cli, rawnick, chan, rest): def flastgame(cli, rawnick, chan, rest):
"""Disables starting or joining a game, and optionally schedules a command to run after the current game ends.""" """Disables starting or joining a game, and optionally schedules a command to run after the current game ends."""
nick, _, __, cloak = parse_nick(rawnick) nick, _, ident, host = parse_nick(rawnick)
chan = botconfig.CHANNEL chan = botconfig.CHANNEL
if var.PHASE != "join": if var.PHASE != "join":
@ -8189,7 +8228,7 @@ def fsend(cli, nick, chan, rest):
cli.send(rest) cli.send(rest)
def _say(cli, raw_nick, rest, command, action=False): def _say(cli, raw_nick, rest, command, action=False):
(nick, _, _, cloak) = parse_nick(raw_nick) (nick, _, ident, host) = parse_nick(raw_nick)
rest = rest.split(" ", 1) rest = rest.split(" ", 1)
if len(rest) < 2: if len(rest) < 2:
@ -8200,7 +8239,7 @@ def _say(cli, raw_nick, rest, command, action=False):
(target, message) = rest (target, message) = rest
if not is_admin(nick, cloak): if not is_admin(nick, ident, host):
if nick not in var.USERS: if nick not in var.USERS:
pm(cli, nick, "You have to be in {0} to use this command.".format( pm(cli, nick, "You have to be in {0} to use this command.".format(
botconfig.CHANNEL)) botconfig.CHANNEL))
@ -8272,7 +8311,8 @@ if botconfig.DEBUG_MODE or botconfig.ALLOWED_NORMAL_MODE_COMMANDS:
if nick in var.USERS and var.USERS[nick]["account"] in [var.USERS[player]["account"] for player in pl if player in var.USERS]: if nick in var.USERS and var.USERS[nick]["account"] in [var.USERS[player]["account"] for player in pl if player in var.USERS]:
return False return False
if nick in var.USERS and var.USERS[nick]["cloak"] in [var.USERS[player]["cloak"] for player in pl if player in var.USERS]: hostmask = var.USERS[nick]["ident"] + "@" + var.USERS[nick]["host"]
if nick in var.USERS and hostmask in [var.USERS[player]["ident"] + "@" + var.USERS[player]["host"] for player in pl if player in var.USERS]:
return False return False
return True return True