<commit_before>from twisted.words.protocols import irc
from txircd.modbase import Command
from txircd.utils import epoch, now, irc_lower, parse_duration, CaseInsensitiveDictionary
from fnmatch import fnmatch

class ElineCommand(Command):
	def __init__(self):
		self.exceptList = CaseInsensitiveDictionary()
	
	def onUse(self, user, data):
		if "reason" in data:
			self.exceptList[data["mask"]] = {
				"setter": user.nickname,
				"created": epoch(now()),
				"duration": data["duration"],
				"reason": data["reason"]
			}
		else:
			mask = data["mask"]
			del self.exceptList[mask]
			for u in self.ircd.users.itervalues():
				if self.match_eline(u):
					u.cache["except_line"] = True
			now_banned = []
			for uid, udata in self.ircd.users.iteritems():
				for modfunc in self.ircd.actions["xline_rematch"]:
					reason = modfunc(udata)
					if reason:
						now_banned.append(uid)
						break # If the user is banned, the user is banned. We don't need to gather a consensus or something.
			for uid in now_banned:
				udata = self.ircd.users[uid]
				udata.sendMessage("NOTICE", ":{}".format(self.ircd.client_ban_msg))
				quit_to = set()
				for chan in user.channels.iterkeys():
					cdata = self.ircd.channels[chan]
					self.leave(chan)
					for u in cdata.users:
						quit_to.add(u)
				for u in quit_to:
					u.sendMessage("QUIT", ":Banned: Exception Removed", to=None, prefix=user.prefix())
				user.sendMessage("ERROR", ":Closing Link {} [Banned: Exception Removed]".format(user.prefix()), to=None, prefix=None)
				del self.ircd.users[user.nickname]
				user.socket.transport.loseConnection()
	
	def processParams(self, user, params):
		if user.registered > 0:
			user.sendMessage(irc.ERR_NOTYETREGISTERED, "ELINE", ":You have not registered")
			return {}
		if "o" not in user.mode:
			user.sendMessage(irc.ERR_NOPRIVILEGES, ":Permission denied - You do not have the correct operator privileges")
			return {}
		if not params:
			user.sendMessage(irc.ERR_NEEDMOREPARAMS, "ELINE", ":Not enough parameters")
			return {}
		banmask = params[0]
		if banmask in self.ircd.users:
			udata = self.ircd.users[banmask]
			banmask = "{}@{}".format(udata.username, udata.hostname)
		elif "@" not in banmask:
			banmask = "*@{}".format(banmask)
		self.expire_elines()
		if len(params) < 3 or not params[2]:
			if banmask not in self.exceptList:
				user.sendMessage("NOTICE", ":*** E:line for {} not found! Check /stats E to view currently set e:lines.".format(banmask))
				return {}
			return {
				"user": user,
				"mask": banmask
			}
		if banmask in self.exceptList:
			user.sendMessage("NOTICE", ":*** An e:line is already set on {}!  Check /stats E to view currently set e:lines.".format(banmask))
			return {}
		return {
			"user": user,
			"mask": banmask,
			"duration": parse_duration(params[1]),
			"reason": " ".join(params[2:])
		}
	
	def statsList(self, cmd, data):
		if cmd != "STATS":
			return
		if data["statstype"] != "E":
			return
		self.expire_elines()
		for mask, linedata in self.exceptList.iteritems():
			user.sendMessage(irc.RPL_STATSELINES, "{} {} {} {} :{}".format(mask, linedata["created"], linedata["duration"], linedata["setter"], linedata["reason"]))
	
	def check_register(self, user):
		if self.match_eline(user):
			user.cache["except_line"] = True
		return True
	
	def match_eline(self, user):
		self.expire_elines()
		matchMask = irc_lower("{}@{}".format(user.username, user.hostname))
		for mask, linedata in self.exceptList.iteritems():
			if fnmatch(matchMask, mask):
				user.cache["except_line"] = True
				return linedata["reason"]
		user.cache["except_line"] = False
		return None
	
	def expire_elines(self):
		current_time = epoch(now())
		expired = []
		for mask, linedata in self.exceptList.iteritems():<commit_msg>Show original ban reason on exception removal and match user@ip in addition to user@host<commit_after>from twisted.words.protocols import irc
from txircd.modbase import Command
from txircd.utils import epoch, now, irc_lower, parse_duration, CaseInsensitiveDictionary
from fnmatch import fnmatch

class ElineCommand(Command):
	def __init__(self):
		self.exceptList = CaseInsensitiveDictionary()
	
	def onUse(self, user, data):
		if "reason" in data:
			self.exceptList[data["mask"]] = {
				"setter": user.nickname,
				"created": epoch(now()),
				"duration": data["duration"],
				"reason": data["reason"]
			}
		else:
			mask = data["mask"]
			del self.exceptList[mask]
			for u in self.ircd.users.itervalues():
				if self.match_eline(u):
					u.cache["except_line"] = True
			now_banned = {}
			for uid, udata in self.ircd.users.iteritems():
				for modfunc in self.ircd.actions["xline_rematch"]:
					reason = modfunc(udata)
					if reason:
						now_banned[uid] = reason
						break # If the user is banned, the user is banned. We don't need to gather a consensus or something.
			for uid, reason in now_banned.iteritems():
				udata = self.ircd.users[uid]
				udata.sendMessage("NOTICE", ":{}".format(self.ircd.client_ban_msg))
				quit_to = set()
				for chan in user.channels.iterkeys():
					cdata = self.ircd.channels[chan]
					self.leave(chan)
					for u in cdata.users:
						quit_to.add(u)
				for u in quit_to:
					u.sendMessage("QUIT", ":Banned: Exception Removed ({})".format(reason), to=None, prefix=user.prefix())
				user.sendMessage("ERROR", ":Closing Link {} [Banned: Exception Removed ({})]".format(user.prefix(), reason), to=None, prefix=None)
				del self.ircd.users[user.nickname]
				user.socket.transport.loseConnection()
	
	def processParams(self, user, params):
		if user.registered > 0:
			user.sendMessage(irc.ERR_NOTYETREGISTERED, "ELINE", ":You have not registered")
			return {}
		if "o" not in user.mode:
			user.sendMessage(irc.ERR_NOPRIVILEGES, ":Permission denied - You do not have the correct operator privileges")
			return {}
		if not params:
			user.sendMessage(irc.ERR_NEEDMOREPARAMS, "ELINE", ":Not enough parameters")
			return {}
		banmask = params[0]
		if banmask in self.ircd.users:
			udata = self.ircd.users[banmask]
			banmask = "{}@{}".format(udata.username, udata.hostname)
		elif "@" not in banmask:
			banmask = "*@{}".format(banmask)
		self.expire_elines()
		if len(params) < 3 or not params[2]:
			if banmask not in self.exceptList:
				user.sendMessage("NOTICE", ":*** E:line for {} not found! Check /stats E to view currently set e:lines.".format(banmask))
				return {}
			return {
				"user": user,
				"mask": banmask
			}
		if banmask in self.exceptList:
			user.sendMessage("NOTICE", ":*** An e:line is already set on {}!  Check /stats E to view currently set e:lines.".format(banmask))
			return {}
		return {
			"user": user,
			"mask": banmask,
			"duration": parse_duration(params[1]),
			"reason": " ".join(params[2:])
		}
	
	def statsList(self, cmd, data):
		if cmd != "STATS":
			return
		if data["statstype"] != "E":
			return
		self.expire_elines()
		for mask, linedata in self.exceptList.iteritems():
			user.sendMessage(irc.RPL_STATSELINES, "{} {} {} {} :{}".format(mask, linedata["created"], linedata["duration"], linedata["setter"], linedata["reason"]))
	
	def check_register(self, user):
		if self.match_eline(user):
			user.cache["except_line"] = True
		return True
	
	def match_eline(self, user):
		self.expire_elines()
		matchMask = irc_lower("{}@{}".format(user.username, user.hostname))
		for mask, linedata in self.exceptList.iteritems():
			if fnmatch(matchMask, mask):
				user.cache["except_line"] = True
				return linedata["reason"]
		matchMask = irc_lower("{}@{}".format(user.username, user.ip))
		for mask, linedata in self.exceptList.iteritems():
			if fnmatch(matchMask, mask):
				user.cache["except_line"] = True
				return linedata["reason"]
		user.cache["except_line"] = False
		return None
	
	def expire_elines(self):
		current_time = epoch(now())
		expired = []
		for mask, linedata in self.exceptList.iteritems():
{'fraction_non_alphanumeric': 0.14709611970580777, 'fraction_numerical': 0.001521683996956632, 'mean_word_length': 4.001268230818009, 'pattern_counts': {'":': 40, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '787580', 'n_tokens_mistral': 3084, 'n_tokens_neox': 2641, 'n_words': 664}