Merge pull request #159 from lykoss/ident-support

Expand host-based variables to take full-on hostmasks
This commit is contained in:
Ryan Schmidt 2015-09-05 19:59:01 -07:00
commit 458d678009
3 changed files with 276 additions and 220 deletions

View File

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

View File

@ -2,6 +2,7 @@ import fnmatch
import math
import random
import sqlite3
import re
from collections import defaultdict, OrderedDict
import botconfig
@ -328,6 +329,18 @@ PING_IF_NUMS_ACCS = {}
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):
assert priv in ("owner", "admin")
@ -339,10 +352,12 @@ def check_priv(priv):
hosts.update(botconfig.ADMINS)
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 not cloak:
cloak = USERS[nick]["cloak"]
if not ident:
ident = USERS[nick]["ident"]
if not host:
host = USERS[nick]["host"]
if not acc:
acc = USERS[nick]["account"]
@ -351,9 +366,9 @@ def check_priv(priv):
if fnmatch.fnmatch(acc.lower(), pattern.lower()):
return True
if cloak:
for pattern in hosts:
if fnmatch.fnmatch(cloak.lower(), pattern.lower()):
if host:
for hostmask in hosts:
if match_hostmask(hostmask, nick, ident, host):
return True
return False

View File

@ -194,15 +194,15 @@ def connect_callback(cli):
if not stat in var.MODES_PREFIXES:
continue
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)
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 == botconfig.NICK:
cli.nickname = user
cli.ident = ident
cli.hostmask = cloak
cli.hostmask = host
if acc == "0":
acc = "*"
if "+" in status:
@ -212,7 +212,7 @@ def connect_callback(cli):
if not stat in var.MODES_PREFIXES:
continue
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)
def afterwho(*args):
@ -431,7 +431,7 @@ def reset():
var.DEAD = set()
var.ROLES = {"person" : set()}
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.PINGED_ALREADY = set()
var.PINGED_ALREADY_ACCS = set()
@ -450,13 +450,14 @@ reset()
def make_stasis(nick, penalty):
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"]
else:
return # Can't do it
if not acc or acc == "*":
acc = None
if not cloak and not acc:
if not host and not acc:
return # Can't do it, either
if acc:
if penalty == 0:
@ -466,14 +467,15 @@ def make_stasis(nick, penalty):
else:
var.STASISED_ACCS[acc] += penalty
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 cloak in var.STASISED:
del var.STASISED[cloak]
var.set_stasis(cloak, 0)
if hostmask in var.STASISED:
del var.STASISED[hostmask]
var.set_stasis(hostmask, 0)
else:
var.STASISED[cloak] += penalty
var.set_stasis(cloak, var.STASISED[cloak])
var.STASISED[hostmask] += penalty
var.set_stasis(hostmask, var.STASISED[hostmask])
@cmd("fsync", admin_only=True, pm=True)
def fsync(cli, nick, chan, rest):
@ -610,7 +612,7 @@ def restart_program(cli, nick, chan, rest):
@hook("quit")
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
# if the bot is using a nick that isn't botconfig.NICK, then stop breaking things and fdie
if nick == botconfig.NICK:
@ -636,9 +638,10 @@ def pinger(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."""
nick, _, __, cloak = parse_nick(nick)
nick, _, ident, host = parse_nick(nick)
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"]
else:
acc = None
@ -649,9 +652,9 @@ def mark_simple_notify(cli, nick, chan, rest):
if acc in var.SIMPLE_NOTIFY_ACCS:
var.SIMPLE_NOTIFY_ACCS.remove(acc)
var.remove_simple_rolemsg_acc(acc)
if cloak in var.SIMPLE_NOTIFY:
var.SIMPLE_NOTIFY.remove(cloak)
var.remove_simple_rolemsg(cloak)
if host in var.SIMPLE_NOTIFY:
var.SIMPLE_NOTIFY.remove(host)
var.remove_simple_rolemsg(host)
cli.notice(nick, "You now no longer receive simple role instructions.")
return
@ -663,21 +666,22 @@ def mark_simple_notify(cli, nick, chan, rest):
return
else: # Not logged in, fall back to hostmask
if cloak in var.SIMPLE_NOTIFY:
var.SIMPLE_NOTIFY.remove(cloak)
var.remove_simple_rolemsg(cloak)
if host in var.SIMPLE_NOTIFY:
var.SIMPLE_NOTIFY.remove(host)
var.remove_simple_rolemsg(host)
cli.notice(nick, "You now no longer receive simple role instructions.")
return
var.SIMPLE_NOTIFY.add(cloak)
var.add_simple_rolemsg(cloak)
var.SIMPLE_NOTIFY.add(host)
var.add_simple_rolemsg(host)
cli.notice(nick, "You now receive simple role instructions.")
def is_user_simple(nick):
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"]
else:
return False
@ -685,17 +689,20 @@ def is_user_simple(nick):
if acc in var.SIMPLE_NOTIFY_ACCS:
return True
return False
elif cloak in var.SIMPLE_NOTIFY and not var.ACCOUNTS_ONLY:
return True
elif not var.ACCOUNTS_ONLY:
for hostmask in var.SIMPLE_NOTIFY:
if var.match_hostmask(hostmask, nick, ident, host):
return True
return False
@cmd("notice", raw_nick=True, pm=True)
def mark_prefer_notice(cli, nick, chan, rest):
"""Makes the bot NOTICE you for every interaction."""
nick, _, __, cloak = parse_nick(nick)
nick, _, ident, host = parse_nick(nick)
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"]
else:
acc = None
@ -706,9 +713,9 @@ def mark_prefer_notice(cli, nick, chan, rest):
if acc in var.PREFER_NOTICE_ACCS:
var.PREFER_NOTICE_ACCS.remove(acc)
var.remove_prefer_notice_acc(acc)
if cloak in var.PREFER_NOTICE:
var.PREFER_NOTICE.remove(cloak)
var.remove_prefer_notice(cloak)
if host in var.PREFER_NOTICE:
var.PREFER_NOTICE.remove(host)
var.remove_prefer_notice(host)
cli.notice(nick, "Gameplay interactions will now use PRIVMSG for you.")
return
@ -720,15 +727,15 @@ def mark_prefer_notice(cli, nick, chan, rest):
return
else: # Not logged in
if cloak in var.PREFER_NOTICE:
var.PREFER_NOTICE.remove(cloak)
var.remove_prefer_notice(cloak)
if host in var.PREFER_NOTICE:
var.PREFER_NOTICE.remove(host)
var.remove_prefer_notice(host)
cli.notice(nick, "Gameplay interactions will now use PRIVMSG for you.")
return
var.PREFER_NOTICE.add(cloak)
var.add_prefer_notice(cloak)
var.PREFER_NOTICE.add(host)
var.add_prefer_notice(host)
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 var.USERS[nick]["account"] in var.PREFER_NOTICE_ACCS:
return True
if nick in var.USERS and var.USERS[nick]["cloak"] in var.PREFER_NOTICE and not var.ACCOUNTS_ONLY:
return True
if nick in var.USERS and not var.ACCOUNTS_ONLY:
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
@cmd("swap", "replace", pm=True, phases=("join", "day", "night"))
@ -821,7 +832,8 @@ def altpinger(cli, nick, chan, rest):
players = is_user_altpinged(nick)
rest = rest.split()
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"]
else:
if chan == nick:
@ -880,20 +892,24 @@ def altpinger(cli, nick, chan, rest):
def is_user_altpinged(nick):
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"]
else:
return 0
if not var.DISABLE_ACCOUNTS and acc and acc != "*":
if acc in var.PING_IF_PREFS_ACCS.keys():
return var.PING_IF_PREFS_ACCS[acc]
elif not var.ACCOUNTS_ONLY and cloak in var.PING_IF_PREFS.keys():
return var.PING_IF_PREFS[cloak]
elif not var.ACCOUNTS_ONLY:
for hostmask, pref in var.PING_IF_PREFS.items():
if var.match_hostmask(hostmask, nick, ident, host):
return pref
return 0
def toggle_altpinged_status(nick, value, old=None):
# 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"]
if value == 0:
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:
if old in var.PING_IF_NUMS_ACCS:
var.PING_IF_NUMS_ACCS[old].discard(acc)
if not var.ACCOUNTS_ONLY and cloak in var.PING_IF_PREFS:
del var.PING_IF_PREFS[cloak]
var.set_pingif_status(cloak, False, 0)
if old is not None:
with var.WARNING_LOCK:
if old in var.PING_IF_NUMS:
var.PING_IF_NUMS[old].discard(cloak)
if not var.ACCOUNTS_ONLY:
for hostmask in list(var.PING_IF_PREFS.keys()):
if var.match_hostmask(hostmask, nick, ident, host):
del var.PING_IF_PREFS[hostmask]
var.set_pingif_status(hostmask, False, 0)
if old is not None:
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:
if not var.DISABLE_ACCOUNTS and acc and acc != "*":
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:
var.PING_IF_NUMS_ACCS[old].discard(acc)
elif not var.ACCOUNTS_ONLY:
var.PING_IF_PREFS[cloak] = value
var.set_pingif_status(cloak, False, value)
hostmask = ident + "@" + host
var.PING_IF_PREFS[hostmask] = value
var.set_pingif_status(hostmask, False, value)
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].add(cloak)
var.PING_IF_NUMS[value].add(hostmask)
if old is not None:
if old in var.PING_IF_NUMS:
var.PING_IF_NUMS[old].discard(cloak)
if old in var.PING_IF_NUMS.keys():
var.PING_IF_NUMS[old].discard(host)
var.PING_IF_NUMS[old].discard(hostmask)
def join_timer_handler(cli):
with var.WARNING_LOCK:
@ -963,9 +984,9 @@ def join_timer_handler(cli):
if acc in var.PINGED_ALREADY_ACCS:
chk_acc.remove(acc)
for cloak in frozenset(checker):
if cloak in var.PINGED_ALREADY:
checker.remove(cloak)
for hostmask in frozenset(checker):
if hostmask in var.PINGED_ALREADY:
checker.remove(hostmask)
# If there is nobody to ping, do nothing
if not chk_acc and not checker:
@ -973,17 +994,18 @@ def join_timer_handler(cli):
return
@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
nick == botnick or nick in pl):
return
if host in checker:
hostmask = ident + "@" + host
if hostmask in checker:
to_ping.append(nick)
var.PINGED_ALREADY.add(host)
var.PINGED_ALREADY.add(hostmask)
@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
user == botconfig.NICK or user in pl):
@ -996,8 +1018,9 @@ def join_timer_handler(cli):
var.PINGED_ALREADY_ACCS.add(acc)
elif not var.ACCOUNTS_ONLY:
hostmask = ident + "@" + host
to_ping.append(user)
var.PINGED_ALREADY.add(cloak)
var.PINGED_ALREADY.add(hostmask)
@hook("endofwho", hookid=387)
def fetch_altpingers(*stuff):
@ -1054,11 +1077,13 @@ def join_player(cli, player, chan, who = None, forced = False):
return
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"]
elif is_fake_nick(player) and botconfig.DEBUG_MODE:
# fakenick
cloak = None
ident = None
host = None
acc = None
else:
return # Not normal
@ -1069,9 +1094,10 @@ def join_player(cli, player, chan, who = None, forced = False):
if stasis:
if forced and stasis == 1:
if cloak in var.STASISED:
var.set_stasis(cloak, 0)
del var.STASISED[cloak]
for hostmask in list(var.STASISED.keys()):
if var.match_hostmask(hostmask, nick, ident, host):
var.set_stasis(hostmask, 0)
del var.STASISED[hostmask]
if not var.DISABLE_ACCOUNTS and acc in var.STASISED_ACCS:
var.set_stasis_acc(acc, 0)
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.PINGED_ALREADY_ACCS = set()
var.PINGED_ALREADY = set()
if cloak:
var.JOINED_THIS_GAME.add(cloak)
if host:
var.JOINED_THIS_GAME.add(ident + "@" + host)
if acc:
var.JOINED_THIS_GAME_ACCS.add(acc)
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()
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))
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
var.JOINED_THIS_GAME.add(cloak)
var.JOINED_THIS_GAME.add(hostmask)
if acc:
var.JOINED_THIS_GAME_ACCS.add(acc)
now = datetime.now()
@ -1289,22 +1316,24 @@ def on_kicked(cli, nick, chan, victim, reason):
@hook("account")
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
if acc == "*" and var.ACCOUNTS_ONLY and nick in var.list_players():
cli.mode(chan, "-v", nick)
leave(cli, "account", nick)
cli.notice(nick, "Please reidentify to the account \u0002{0}\u0002".format(var.USERS[nick]["account"]))
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
if nick in var.DISCONNECTED.keys():
if acc == var.DISCONNECTED[nick][0]:
if nick in var.USERS and var.USERS[nick]["inchan"]:
with var.GRAVEYARD_LOCK:
clk = var.DISCONNECTED[nick][1]
hm = var.DISCONNECTED[nick][1]
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+"!*@*")
del var.DISCONNECTED[nick]
var.LAST_SAID_TIME[nick] = datetime.now()
@ -3019,7 +3048,7 @@ def reaper(cli, gameid):
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)
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 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 "+
@ -3076,12 +3105,13 @@ def update_last_said(cli, nick, chan, rest):
@hook("join")
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 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:
var.USERS[nick]["cloak"] = cloak
var.USERS[nick]["ident"] = ident
var.USERS[nick]["host"] = host
var.USERS[nick]["account"] = acc
if not var.USERS[nick]["inchan"]:
# Will be True if the user joined the main channel, else False
@ -3089,10 +3119,11 @@ def on_join(cli, raw_nick, chan, acc="*", rname=""):
if chan != botconfig.CHANNEL:
return
with var.GRAVEYARD_LOCK:
hostmask = ident + "@" + host
if nick in var.DISCONNECTED.keys():
clk = var.DISCONNECTED[nick][1]
hm = var.DISCONNECTED[nick][1]
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+"!*@*")
del var.DISCONNECTED[nick]
var.LAST_SAID_TIME[nick] = datetime.now()
@ -3356,16 +3387,18 @@ def rename_player(cli, prefix, nick):
if var.PHASE in ("night", "day"):
with var.GRAVEYARD_LOCK:
if nick in var.DISCONNECTED.keys():
clk = var.DISCONNECTED[nick][1]
hm = var.DISCONNECTED[nick][1]
act = var.DISCONNECTED[nick][0]
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"]
else:
acc = None
if not acc or acc == "*":
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+"!*@*")
del var.DISCONNECTED[nick]
var.LAST_SAID_TIME[nick] = datetime.now()
@ -3383,7 +3416,7 @@ def rename_player(cli, prefix, nick):
@hook("nick")
def on_nick(cli, oldnick, nick):
prefix,u,m,cloak = parse_nick(oldnick)
prefix, _, ident, host = parse_nick(oldnick)
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():
@ -3408,10 +3441,11 @@ def on_nick(cli, oldnick, nick):
rename_player(cli, prefix, nick)
def leave(cli, what, nick, why=""):
nick, _, _, cloak = parse_nick(nick)
nick, _, ident, host = parse_nick(nick)
if nick in var.USERS:
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):
var.USERS[nick]["inchan"] = False
else:
@ -3484,7 +3518,7 @@ def leave(cli, what, nick, why=""):
if killplayer:
del_player(cli, nick, death_triggers = False)
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
hook("part")(lambda cli, nick, *rest: leave(cli, "part", nick, rest[0]))
@ -6706,7 +6740,7 @@ def start(cli, nick, chan, forced = False, restart = ""):
return
if not var.FGAMED:
votes = {} #key = gamemode, not cloak
votes = {} #key = gamemode, not hostmask
for gamemode in var.GAMEMODE_VOTES.values():
if len(villagers) >= var.GAME_MODES[gamemode][1] and len(villagers) <= var.GAME_MODES[gamemode][2]:
votes[gamemode] = votes.get(gamemode, 0) + 1
@ -6992,11 +7026,11 @@ def start(cli, nick, chan, forced = False, restart = ""):
var.GAMEPHASE = "day"
transition_day(cli)
for cloak in list(var.STASISED.keys()):
var.STASISED[cloak] -= 1
var.set_stasis(cloak, var.STASISED[cloak])
if var.STASISED[cloak] <= 0:
del var.STASISED[cloak]
for hostmask in list(var.STASISED.keys()):
var.STASISED[hostmask] -= 1
var.set_stasis(hostmask, var.STASISED[hostmask])
if var.STASISED[hostmask] <= 0:
del var.STASISED[hostmask]
if not var.DISABLE_ACCOUNTS:
for acc in list(var.STASISED_ACCS.keys()):
@ -7032,26 +7066,28 @@ def fstasis(cli, nick, chan, rest):
user = data[0]
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"]
hostmask = ident + "@" + host
else:
cloak = user
hostmask = user
acc = None
if var.ACCOUNTS_ONLY and acc == "*":
acc = None
cloak = None
hostmask = None
msg = "{0} is not logged in to NickServ.".format(user)
if not acc and user in var.STASISED_ACCS:
acc = user
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 cloak in var.STASISED:
plural = "" if var.STASISED[cloak] == 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)
if hostmask in var.STASISED:
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], hostmask, var.STASISED[hostmask], plural)
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:
try:
amt = int(data[1])
@ -7074,17 +7110,17 @@ def fstasis(cli, nick, chan, rest):
amt = 2**31-1
if amt > 0:
var.STASISED[cloak] = amt
var.set_stasis(cloak, amt)
var.STASISED[hostmask] = amt
var.set_stasis(hostmask, amt)
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:
if cloak in var.STASISED:
del var.STASISED[cloak]
var.set_stasis(cloak, 0)
msg = "\u0002{0}\u0002 (Host: {1}) is no longer in stasis.".format(data[0], cloak)
if hostmask in var.STASISED:
del var.STASISED[hostmask]
var.set_stasis(hostmask, 0)
msg = "\u0002{0}\u0002 (Host: {1}) is no longer in stasis.".format(data[0], hostmask)
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 len(data) == 1:
if acc in var.STASISED_ACCS:
@ -7125,26 +7161,14 @@ def fstasis(cli, nick, chan, rest):
msg = "\u0002{0}\u0002 (Account: {1}) is not in stasis.".format(data[0], acc)
elif var.STASISED or var.STASISED_ACCS:
stasised = {}
cloakstas = dict(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:
for hostmask in var.STASISED:
if var.DISABLE_ACCOUNTS:
stasised[oldcloak] = cloakstas[oldcloak]
stasised[hostmask] = var.STASISED[hostmask]
else:
stasised[oldcloak+" (Host)"] = cloakstas[oldcloak]
stasised[hostmask+" (Host)"] = var.STASISED[hostmask]
if not var.DISABLE_ACCOUNTS:
for oldacc in accstas:
stasised[oldacc+" (Account)"] = accstas[oldacc]
for acc in var.STASISED_ACCS:
stasised[acc+" (Account)"] = var.STASISED_ACCS[acc]
msg = "Currently stasised: {0}".format(", ".join(
"\u0002{0}\u0002 ({1})".format(usr, number)
for usr, number in stasised.items()))
@ -7152,14 +7176,6 @@ def fstasis(cli, nick, chan, rest):
msg = "Nobody is currently stasised."
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:
pm(cli, nick, msg)
else:
@ -7169,17 +7185,19 @@ def is_user_stasised(nick):
"""Checks if a user is in stasis. Returns a number of games in stasis."""
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"]
else:
return 0
amount = 0
if not var.DISABLE_ACCOUNTS and acc and acc != "*":
if acc in var.STASISED_ACCS:
return var.STASISED_ACCS[acc]
for clk in var.STASISED:
if fnmatch.fnmatch(cloak, clk):
return var.STASISED[clk]
return 0
amount = var.STASISED_ACCS[acc]
for hostmask in var.STASISED:
if var.match_hostmask(hostmask, nick, ident, host):
amount = max(amount, var.STASISED[hostmask])
return amount
def allow_deny(cli, nick, chan, rest, mode):
data = rest.split()
@ -7204,6 +7222,11 @@ def allow_deny(cli, nick, chan, rest, mode):
opts["cmd"] = data[1]
data = data[1:]
elif data[0] == "-acc":
opts["acc"] = True
data = data[1:]
elif data[0] == "-host":
opts["host"] = True
else:
if chan == nick:
pm(cli, nick, "Invalid option: {0}".format(data[0][1:]))
@ -7219,22 +7242,42 @@ def allow_deny(cli, nick, chan, rest, mode):
user = data[0]
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"]
hostmask = ident + "@" + host
elif opts["acc"]:
hostmask = None
acc = user
else:
cloak = user
hostmask = user
m = re.match('(?:(?:(.*?)!)?(.*)@)?(.*)', hostmask)
user = m.group(1)
ident = m.group(2)
host = m.group(3)
acc = None
if not acc or acc == "*":
if not acc or acc == "*" or opts["host"]:
acc = None
if not var.DISABLE_ACCOUNTS and acc:
if mode == "allow":
variable = var.ALLOW_ACCOUNTS
noaccvar = var.ALLOW
else:
variable = var.DENY_ACCOUNTS
noaccvar = var.DENY
if len(data) == 1:
cmds = []
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(
data[0], acc, "allowed" if mode == "allow" else "denied", "special " if mode == "allow" else "", ", ".join(variable[acc]))
else:
@ -7282,30 +7325,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")
elif var.ACCOUNTS_ONLY:
msg = "Error: \u0002{0}\u0002 is not logged in to NickServ.".format(data[0])
else:
if mode == "allow":
variable = var.ALLOW
else:
variable = var.DENY
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(
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:
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:
if cloak not in variable:
variable[cloak] = []
if hostmask not in variable:
variable[hostmask] = []
commands = data[1:]
for command in commands: #add or remove commands one at a time to a specific hostmask
if "-*" in commands: # Remove all
for cmd in variable[cloak]:
for cmd in variable[hostmask]:
if mode == "allow":
var.remove_allow(cloak, cmd)
var.remove_allow(hostmask, cmd)
else:
var.remove_deny(cloak, cmd)
del variable[cloak]
var.remove_deny(hostmask, cmd)
del variable[hostmask]
break
if command[0] == '-': #starting with - removes
rem = True
@ -7316,26 +7363,26 @@ def allow_deny(cli, nick, chan, rest, mode):
command = command[len(botconfig.CMD_CHAR):]
if not rem:
if command in COMMANDS and command not in ("fdeny", "fallow", "fsend", "exec", "eval") and command not in variable[cloak]:
variable[cloak].append(command)
if command in COMMANDS and command not in ("fdeny", "fallow", "fsend", "exec", "eval") and command not in variable[hostmask]:
variable[hostmask].append(command)
if mode == "allow":
var.add_allow(cloak, command)
var.add_allow(hostmask, command)
else:
var.add_deny(cloak, command)
elif command in variable[cloak]:
variable[cloak].remove(command)
var.add_deny(hostmask, command)
elif command in variable[hostmask]:
variable[hostmask].remove(command)
if mode == "allow":
var.remove_allow(cloak, command)
var.remove_allow(hostmask, command)
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(
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:
if cloak in variable:
del variable[cloak]
msg = "\u0002{0}\u0002 (Host: {1}) is no longer {2} commands.".format(data[0], cloak, "allowed any special" if mode == "allow" else "denied any")
if hostmask in variable:
del variable[hostmask]
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:
users_to_cmds = {}
@ -7356,11 +7403,11 @@ def allow_deny(cli, nick, chan, rest, mode):
else:
variable = var.DENY
if variable:
for cloak, varied in variable.items():
for hostmask, varied in variable.items():
if var.DISABLE_ACCOUNTS:
users_to_cmds[cloak] = sorted(varied, key=str.lower)
users_to_cmds[hostmask] = sorted(varied, key=str.lower)
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
@ -7399,14 +7446,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())))
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("; "), "; ")
if chan == nick:
@ -7512,7 +7551,7 @@ def show_rules(cli, nick, chan, rest):
@cmd("help", raw_nick=True, pm=True)
def get_help(cli, rnick, chan, rest):
"""Gets help."""
nick, mode, user, cloak = parse_nick(rnick)
nick, _, ident, host = parse_nick(rnick)
fns = []
rest = rest.strip().replace(botconfig.CMD_CHAR, "", 1).lower()
@ -7556,7 +7595,7 @@ def get_help(cli, rnick, chan, rest):
name not in fn[0].aliases and fn[0].chan):
fns.append("{0}{1}{0}".format("\u0002", name))
afns = []
if is_admin(nick, cloak):
if is_admin(nick, ident, host):
for name, fn in COMMANDS.items():
if fn[0].admin_only and name not in fn[0].aliases:
afns.append("{0}{1}{0}".format("\u0002", name))
@ -7614,8 +7653,8 @@ def on_invite(cli, raw_nick, something, chan):
if chan == botconfig.CHANNEL:
cli.join(chan)
return # No questions
(nick, _, _, cloak) = parse_nick(raw_nick)
if is_admin(nick, cloak):
(nick, _, ident, host) = parse_nick(raw_nick)
if is_admin(nick, ident, host):
cli.join(chan) # Allows the bot to be present in any channel
debuglog(nick, "INVITE", chan, display=True)
else:
@ -7662,7 +7701,7 @@ def show_admins(cli, nick, chan, rest):
var.ADMIN_PINGING = True
@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:
return
@ -7976,7 +8015,7 @@ def aftergame(cli, rawnick, chan, rest):
@cmd("flastgame", admin_only=True, raw_nick=True, pm=True)
def flastgame(cli, rawnick, chan, rest):
"""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
if var.PHASE != "join":
@ -8194,7 +8233,7 @@ def fsend(cli, nick, chan, rest):
cli.send(rest)
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)
if len(rest) < 2:
@ -8205,7 +8244,7 @@ def _say(cli, raw_nick, rest, command, action=False):
(target, message) = rest
if not is_admin(nick, cloak):
if not is_admin(nick, ident, host):
if nick not in var.USERS:
pm(cli, nick, "You have to be in {0} to use this command.".format(
botconfig.CHANNEL))
@ -8277,7 +8316,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]:
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 True