def lottery_buy(self, event): amount = event["spec"][0] or 1 user_coins = self._get_user_coins(event["user"]) coin_amount = decimal.Decimal(LOTTERY_BUYIN) * amount new_user_coins = user_coins - coin_amount redeem_amount = self._redeem_amount(event["server"]) if coin_amount > user_coins: raise utils.EventError("%s: You don't have enough coins" % event["user"].nickname) elif new_user_coins < redeem_amount: raise utils.EventError( "%s: you can't play the lottery if it puts your total coins " "below %s" % (event["user"].nickname, self._coin_str(redeem_amount))) self._take(event["server"], event["user"], coin_amount) lottery = event["server"].get_setting("lottery", {}) nickname = event["user"].nickname_lower if not nickname in lottery: lottery[nickname] = 0 lottery[nickname] += amount event["server"].set_setting("lottery", lottery) event["stdout"].write( "%s: You bought %d lottery ticket%s for %s" % (event["user"].nickname, amount, "" if amount == 1 else "s", self._coin_str(coin_amount)))
def _mute(self, event): add = event.name == "received.command.mute" target_name = event["args_split"][0] if not event["server"].has_user(target_name): raise utils.EventError("No such user") target_user = event["server"].get_user(target_name) if not event["target"].has_user(target_user): raise utils.EventError("No such user") mode, mask = self._mute_method(event["server"], target_user) if mode == None: raise utils.EventError("This network doesn't support mutes") if add and len(event["args_split"]) > 1: duration = utils.from_pretty_time(event["args_split"][1]) if duration == None: raise utils.EventError("Invalid duration") self.timers.add_persistent("unmute", duration, server_id=event["server"].id, channel_name=event["target"].name, mode=mode, mask=mask) mode_modifier = "+" if add else "-" event["target"].send_mode("%s%s" % (mode_modifier, mode), [mask])
def flip(self, event): side_name = event["spec"][0] coin_bet = event["spec"][1] if coin_bet == "all": coin_bet = self._get_user_coins(event["user"]) if coin_bet <= DECIMAL_ZERO: raise utils.EventError("%s: You have no coins to bet" % event["user"].nickname) user_coins = self._get_user_coins(event["user"]) if coin_bet > user_coins: raise utils.EventError("%s: You don't have enough coins to bet" % event["user"].nickname) chosen_side = random.SystemRandom().choice(list(SIDES.keys())) win = side_name == chosen_side coin_bet_str = self._coin_str_human(coin_bet) if win: new_total = self._give(event["server"], event["user"], coin_bet) event["stdout"].write( "%s flips %s and wins %s coin%s! (new total: %s)" % (event["user"].nickname, side_name, coin_bet_str, "" if coin_bet == 1 else "s", self._coin_str_human(new_total))) else: self._take(event["server"], event["user"], coin_bet) event["stdout"].write( "%s flips %s and loses %s coin%s! (new total: %s)" % (event["user"].nickname, side_name, coin_bet_str, "" if coin_bet == 1 else "s", self._coin_str_human(user_coins - coin_bet)))
def roll_dice(self, event): dice_count, side_count = 1, 6 roll = "1d6" modifiers = [] if event["spec"][0]: dice_count = int(event["spec"][0].group(1) or "1") side_count = int(event["spec"][0].group(2)) roll = event["spec"][0].group(0) modifiers = RE_MODIFIERS.findall(event["spec"][0].group(3)) if dice_count > 6: raise utils.EventError("Max number of dice is %s" % MAX_DICE) if side_count > MAX_SIDES: raise utils.EventError("Max number of sides is %s" % MAX_SIDES) results = random.choices(range(1, side_count+1), k=dice_count) total_n = sum(results) for modifier in modifiers: if modifier[0] == "+": total_n += int(modifier[1:]) else: total_n -= int(modifier[1:]) total = "" if len(results) > 1 or modifiers: total = " (total: %d)" % total_n results_str = ", ".join(str(r) for r in results) event["stdout"].write("Rolled %s and got %s%s" % ( roll, results_str, total))
def vote(self, event): """ :help: Vote in the channel's current vote :usage: <id> [choice] """ vote_id = event["args_split"][0] vote = self._get_vote(event["target"], vote_id) if vote == None: raise utils.EventError(STR_NOVOTE % vote_id) if not len(event["args_split"]) > 1: closed = "" if vote["open"] else " (closed)" event["stdout"].write("Vote %s%s: %s" % (vote_id, closed, self._format_vote(vote))) else: if not vote["open"]: raise utils.EventError("%s: vote %s is closed" % (event["user"].nickname, vote_id)) choice = event["args_split"][1].lower() if not choice in vote["options"]: raise utils.EventError("Vote options: %s" % self._format_options(vote)) cast_result = self._cast_vote(event["target"], vote_id, event["user"], choice) cast_desc = "has been cast" if cast_result == VoteCastResult.Changed: cast_desc = "has been changed" elif cast_result == VoteCastResult.Unchanged: cast_desc = "is unchanged" event["stdout"].write("%s: your vote %s." % (event["user"].nickname, cast_desc))
def in_list(self, event): """ :help: List reminders :usage: [index] """ timers = self.timers.find_all("in") found = [] for timer in timers: nickname_match = (event["server"].irc_lower( timer.kwargs["nickname"]) == event["user"].nickname_lower) target_match = timer.kwargs["target"] == event["target"].name if nickname_match and target_match: found.append(timer) if len(event["args_split"]) > 0: index = event["args_split"][0] if not index.isdigit() or index == "0": raise utils.EventError("Please provide a valid reminder index") index = int(index) actual_index = index - 1 if actual_index > len(found): raise utils.EventError("You do not have that many reminders") timer = found[actual_index] event["stdout"].write("Reminder %d: %s" % (index, timer.kwargs["message"])) else: event["stdout"].write("%s: you have %d reminders" % (event["user"].nickname, len(found)))
def tfollow(self, event): """ :help: Stream tweets from a given account to the current channel :usage: add|remove @<username> :permission: twitter-follow """ username = event["args_split"][1] if username.startswith("@"): username = username[1:] subcommand = event["args_split"][0].lower() follows = event["target"].get_setting("twitter-follow", []) action = None if subcommand == "add": action = "followed" if username in follows: raise utils.EventError("Already following %s" % username) follows.append(username) elif subcommand == "remove": action = "unfollowed" if not username in follows: raise utils.EventError("Not following %s" % username) follows.remove(username) else: raise utils.EventError("Unknown subcommand") event["target"].set_setting("twitter-follow", follows) self._start_stream() event["stdout"].write("%s @%s" % (action.title(), username))
def _perform(self, target, args_split): subcommand = args_split[0].lower() current_perform = target.get_setting("perform", []) if subcommand == "list": return "Configured commands: %s" % ", ".join(current_perform) message = None if subcommand == "add": if not len(args_split) > 1: raise utils.EventError("Please provide a raw command to add") current_perform.append(" ".join(args_split[1:])) message = "Added command" elif subcommand == "remove": if not len(args_split) > 1: raise utils.EventError("Please provide an index to remove") if not args_split[1].isdigit(): raise utils.EventError("Please provide a number") index = int(args_split[1]) if not index < len(current_perform): raise utils.EventError("Index out of bounds") current_perform.pop(index) message = "Removed command" else: raise utils.EventError("Unknown subcommand '%s'" % subcommand) target.set_setting("perform", current_perform) return message
def title(self, event): """ :help: Get the title of a URL :usage: [URL] """ url = None if len(event["args"]) > 0: url = event["args_split"][0] else: url = event["target"].buffer.find(REGEX_URL) if url: url = re.search(REGEX_URL, url.message).group(0) if not url: raise utils.EventError("No URL provided/found.") try: page = utils.http.request(url, soup=True) except Exception as e: self.log.error("failed to get URL title", exc_info=True) page = None pass if not page: raise utils.EventError("Failed to get URL.") title = page.data.title if title: title = title.text.replace("\n", " ").replace("\r", "").replace(" ", " ").strip() event["stdout"].write(title) else: event["stderr"].write("No title found.")
def relay_group(self, event): subcommand = event["args_split"][0].lower() group_settings = self.bot.find_settings(prefix="relay-group-") groups = {} for setting, value in group_settings: name = setting.replace("relay-group-", "", 1) groups[name] = value if subcommand == "list": event["stdout"].write("Relay groups: %s" % ", ".join(groups.keys())) return if not len(event["args_split"]) > 1: raise utils.EventError("Please provide a group name") name = event["args_split"][1].lower() event["check_assert"](utils.Check("is-channel")) current_channel = [event["server"].id, event["target"].name] channel_groups = event["target"].get_setting("relay-groups", []) message = None remove = False if subcommand == "join": if not name in groups: groups[name] = [] if current_channel in groups[name] or name in channel_groups: raise utils.EventError("Already joined group '%s'" % name) groups[name].append(current_channel) channel_groups.append(name) message = "Joined" elif subcommand == "leave": if (not name in groups or not current_channel in groups[name] or not name in channel_groups): raise utils.EventError("Not in group '%s'" % name) groups[name].remove(current_channel) channel_groups.remove(name) message = "Left" else: raise utils.EventError("Unknown subcommand '%s'" % subcommand) if not message == None: if not groups[name]: self.bot.del_setting("relay-group-%s" % name) else: self.bot.set_setting("relay-group-%s" % name, groups[name]) if channel_groups: event["target"].set_setting("relay-groups", channel_groups) else: event["target"].del_setting("relay-groups") event["stdout"].write("%s group '%s'" % (message, name))
def edit_server(self, event): alias = event["spec"][0] server_id = self._id_from_alias(alias) if server_id == None: raise utils.EventError("Unknown server '%s'" % alias) option = event["spec"][1].lower() value = event["spec"][2] value_parsed = None if option == "hostname": value_parsed = value elif option == "port": if not value.isdigit(): raise utils.EventError("Invalid port") value_parsed = int(value.lstrip("0")) elif option == "tls": value_lower = value.lower() if not value_lower in ["yes", "no"]: raise utils.EventError("TLS should be either 'yes' or 'no'") value_parsed = value_lower == "yes" elif option == "password": value_parsed = value elif option == "bindhost": value_parsed = value elif option in ["nickname", "username", "realname"]: value_parsed = value else: raise utils.EventError("Unknown option '%s'" % option) self.bot.database.servers.edit(server_id, option, value_parsed) event["stdout"].write("Set %s for %s" % (option, alias))
def send(self, event): target_user = event["spec"][0] if event["user"].get_id() == target_user.get_id(): raise utils.EventError("%s: You can't send coins to yourself" % event["user"].nickname) send_amount = event["spec"][1] user_coins = self._get_user_coins(event["user"]) redeem_amount = self._redeem_amount(event["server"]) new_total_coins = self._get_user_coins(event["user"]) - send_amount if user_coins == DECIMAL_ZERO: raise utils.EventError("%s: You have no coins" % event["user"].nickname) elif new_total_coins < redeem_amount: raise utils.EventError( "%s: You cannot send an amount of money that puts" " you below %s coins" % (event["user"].nickname, self._coin_str(redeem_amount))) target_user_coins = self._get_user_coins(target_user) if target_user_coins == None: raise utils.EventError("%s: You can only send coins to users that " "have had coins before" % event["user"].nickname) self._move(event["user"], target_user, send_amount) event["stdout"].write( "%s sent %s coins to %s" % (event["user"].nickname, self._coin_str(send_amount), target_user.nickname))
def _mute(self, event): add = event["command"] == "mute" time, args = utils.parse.timed_args(event["args_split"], 1) target_name = args[0] if not event["server"].has_user(target_name): raise utils.EventError("No such user") target_user = event["server"].get_user(target_name) if not event["target"].has_user(target_user): raise utils.EventError("No such user") mode, mask = self._mute_method(event["server"], event["target"], target_user) if mode == None: raise utils.EventError("This network doesn't support mutes") if add and time: self.timers.add_persistent("unmute", time, server_id=event["server"].id, channel_name=event["target"].name, mode=mode, mask=mask) mode_modifier = "+" if add else "-" event["target"].send_mode("%s%s" % (mode_modifier, mode), [mask])
def fedi(self, event): account = None url = None strict_cw = True args_split = event["args_split"][:] for i, arg in enumerate(args_split): if arg == "!": strict_cw = False args_split.pop(i) break if not args_split: account = event["user"].get_setting("fediverse", None) elif utils.http.REGEX_URL.match(args_split[0]): url = args_split[0] elif not "@" in args_split[0]: target = args_split[0] if event["server"].has_user_id(target): target_user = event["server"].get_user(target) account = target_user.get_setting("fediverse", None) else: account = args_split[0] note = None type = "Create" if not url == None: note_page = ap_utils.activity_request(url) if not note_page.content_type == ap_utils.ACTIVITY_TYPE: raise utils.EventError("That's not a fediverse URL") note = note_page.data actor = ap_actor.Actor(note["attributedTo"]) actor.load() else: username = None instance = None if account: username, instance = ap_utils.split_username(account) if not username or not instance: raise utils.EventError("Please provide @<user>@<instance>") actor, note = self._get_from_outbox(username, instance) type = note["type"] note = note["object"] cw, out, url = ap_utils.format_note(actor, note, type) shorturl = self.exports.get_one("shorturl")(event["server"], url, context=event["target"]) if cw: if strict_cw: out = "CW: %s - %s" % (cw, shorturl) else: out = "(CW %s) %s - %s" % (cw, out, shorturl) else: out = "%s - %s" % (out, shorturl) event["stdout"].write(out)
def apikey(self, event): subcommand = event["args_split"][0].lower() alias = None alias_lower = None found = None if len(event["args_split"]) > 1: alias = event["args_split"][1] alias_lower = alias.lower() api_keys = {} for key, value in self.bot.find_settings(prefix="api-key-"): api_keys[key] = value if alias and value["comment"].lower() == alias_lower: alias = value["comment"] found = key if subcommand == "list": aliases = [v["comment"] for v in api_keys.values()] aliases.sort() event["stdout"].write("API keys: %s" % ", ".join(aliases)) elif subcommand == "add": if not len(event["args_split"]) > 1: raise utils.EventError( "Please provide an alias for the API key") if found == None: comment = event["args_split"][1] new_key = binascii.hexlify(os.urandom(16)).decode("ascii") self.bot.set_setting("api-key-%s" % new_key, { "comment": comment, "permissions": event["args_split"][2:] }) event["stdout"].write("New API key '%s': %s" % (comment, new_key)) else: event["stderr"].write("API key alias '%s' already exists" % alias) elif subcommand == "remove": if not len(event["args_split"]) > 1: raise utils.EventError("Please provide a key alias to remove") if not found == None: self.bot.del_setting(found) key = found.replace("api-key-", "", 1) event["stdout"].write("Deleted API key %s ('%s')" % (key, alias)) else: event["stderr"].write("Count not find API key '%s'" % alias) elif subcommand == "info": if not len(event["args_split"]) > 1: raise utils.EventError("Please provide a key alias to remove") if not found == None: key = found.replace("api-key-", "", 1) event["stdout"].write( "API key %s ('%s') can access: %s" % (key, alias, " ".join(api_keys[found]["permissions"]))) else: event["stderr"].write("Count not find API key '%s'" % alias)
def dns(self, event): """ :help: Get all addresses for a given hostname (IPv4/IPv6) :usage: <hostname> [type [type ...]] :prefix: DNS """ args = event["args_split"][:] nameserver = None if self.bot.get_setting("configurable-nameservers", True): nameserver = event["target"].get_setting( "dns-nameserver", event["server"].get_setting("dns-nameserver", None)) for i, arg in enumerate(args): if arg[0] == "@": nameserver = args.pop(i)[1:] break hostname = args[0] record_types = args[1:] if not record_types: record_types = ["A?", "AAAA?"] if not nameserver == None: resolver = dns.resolver.Resolver(configure=False) resolver.nameservers = [nameserver] else: resolver = dns.resolver results = [] for record_type in record_types: record_type_strip = record_type.rstrip("?").upper() try: query_result = resolver.query(hostname, record_type_strip, lifetime=4) query_results = [q.to_text() for q in query_result] results.append( [record_type_strip, query_result.rrset.ttl, query_results]) except dns.resolver.NXDOMAIN: raise utils.EventError("Domain not found") except dns.resolver.NoAnswer: if not record_type.endswith("?"): raise utils.EventError( "Domain does not have a '%s' record" % record_type_strip) except dns.rdatatype.UnknownRdatatype: raise utils.EventError("Unknown record type '%s'" % record_type_strip) except dns.exception.DNSException: message = "Failed to get DNS records" self.log.warn(message, exc_info=True) raise utils.EventError(message) results_str = [ "%s (TTL %s): %s" % (t, ttl, ", ".join(r)) for t, ttl, r in results ] event["stdout"].write("(%s) %s" % (hostname, " | ".join(results_str)))
def badge(self, event): now = self._round_up_day(utils.datetime.utcnow()) if event["spec"][0] == "list": target = event["spec"][1] or event["user"] badges = self._get_badges(target) if not badges: raise utils.EventError("%s has no badges" % target.nickname) outs = [] for name in sorted(badges.keys()): dt = utils.datetime.parse.iso8601(badges[name]) days_since = self._days_since(now, dt) human = utils.datetime.format.date_human(dt) outs.append("%s on day %d (%s)" % (name, days_since, human)) event["stdout"].write("badges for %s: %s" % (target.nickname, ", ".join(outs))) else: badges = self._get_badges(event["user"]) mut_badges = badges.copy() name = event["spec"][1] if event["spec"][0] == "add": if event["spec"][2] in ["now", "today"]: dt = utils.datetime.utcnow() else: dt = event["spec"][2] exists = name in badges action = "updated" if exists else "added" mut_badges[name] = utils.datetime.format.iso8601(dt) human = utils.datetime.format.date_human(dt) event["stdout"].write( "%s: %s badge %s (%s)" % (event["user"].nickname, action, name, human)) else: if not name in badges: raise utils.EventError("%s: you don't have a '%s' badge" % (event["user"].nickname, name)) dt = utils.datetime.parse.iso8601(badges[name]) human = utils.datetime.format.date_human(dt) if event["spec"][0] == "remove": del mut_badges[name] event["stdout"].write( "%s: removed badge '%s' (%s)" % (event["user"].nickname, name, human)) elif event["spec"][0] == "show": days_since = self._days_since(now, dt) event["stdout"].write( "%s: your %s badge is on day %d (%s)" % (event["user"].nickname, name, days_since, human)) if not mut_badges == badges: self._set_badges(event["user"], mut_badges)
def _parse_time(self, args, min_args): if args[0][0] == "+": if len(args[1:]) < min_args: raise utils.EventError("Not enough arguments") time = utils.from_pretty_time(args[0][1:]) if time == None: raise utils.EventError("Invalid timeframe") return time, args[1:] return None, args
def todo(self, event): user_todo = event["user"].get_setting("todo", []) if event["spec"][0] == "list": if not user_todo: raise utils.EventError("%s: you have no todo items" % event["user"].nickname) if not event["spec"][1] == None: index = event["spec"][1] - 1 if not index in dict(enumerate(user_todo)): raise utils.EventError( "%s: unknown todo index %d" % (event["user"].nickname, event["spec"][1])) event["stdout"].write( "%s: (%d) %s" % (event["user"].nickname, event["spec"][1], user_todo[index])) else: outs = [ "(%d) %s" % (i + 1, s) for i, s in enumerate(user_todo) ] event["stdout"].write( "%s: %s" % (event["user"].nickname, ", ".join(outs))) elif event["spec"][0] == "add": user_todo.append(event["spec"][1]) event["user"].set_setting("todo", user_todo) event["stdout"].write("%s: todo item %d added" % (event["user"].nickname, len(user_todo))) elif event["spec"][0] == "remove": index = event["spec"][1] - 1 if not index in dict(enumerate(user_todo)): raise utils.EventError("%s: unknown todo index %d" % event["user"].nickname) description = user_todo.pop(index) event["user"].set_setting("todo", user_todo) event["stdout"].write( "%s: todo item %d removed: %s" % (event["user"].nickname, event["spec"][1], description)) elif event["spec"][0] == "move": todo_dict = dict(enumerate(user_todo)) start_index, end_index = event["spec"][1] - 1, event["spec"][2] - 1 for i, name in [[start_index, "start"], [end_index, "end"]]: if not i in todo_dict: raise utils.EventError( "%s: unknown todo %s index %d" % (event["user"].nickname, name, i + 1)) description = user_todo.pop(start_index) user_todo.insert(end_index, description) event["user"].set_setting("todo", user_todo) event["stdout"].write( "%s: todo item moved to %d: %s" % (event["user"].nickname, event["spec"][2], description))
def _catch(self, name, func): try: func() except ModuleManager.ModuleNotFoundException: raise utils.EventError("Module '%s' isn't loaded" % name) except ModuleManager.ModuleWarning as warning: raise utils.EventError("Module '%s' not loaded: %s" % (name, str(warning))) except Exception as e: raise utils.EventError("Failed to reload module '%s': %s" % (name, str(e)))
def _parse_ref(self, channel, ref): repo, _, number = ref.rpartition("#") if not repo: repo = channel.get_setting("github-default-repo", None) username, _, repository = repo.partition("/") if not username or not repository or not number: raise utils.EventError("Please provide username/repo#number") if not number.isdigit(): raise utils.EventError("Issue number must be a number") return username, repository, number
def weather(self, event): """ :help: Get current weather for you or someone else :usage: [nickname] :require_setting: location :require_setting_unless: 1 """ api_key = self.bot.config["openweathermap-api-key"] location = None if event["args"]: if len(event["args_split"]) == 1 and event["server"].has_user_id( event["args_split"][0]): target_user = event["server"].get_user(event["args_split"][0]) location = self._user_location(target_user) if location == None: raise utils.EventError("%s doesn't have a location set" % target_user.nickname) else: location = self._user_location(event["user"]) if location == None: raise utils.EventError("You don't have a location set") args = {"units": "metric", "APPID": api_key} if location: lat, lon = location args["lat"] = lat args["lon"] = lon else: args["q"] = event["args"] page = utils.http.request(URL_WEATHER, get_params=args, json=True) if page: if "weather" in page.data: location = "%s, %s" % (page.data["name"], page.data["sys"]["country"]) celsius = "%dC" % page.data["main"]["temp"] fahrenheit = "%dF" % ((page.data["main"]["temp"] * (9 / 5)) + 32) description = page.data["weather"][0]["description"].title() humidity = "%s%%" % page.data["main"]["humidity"] wind_speed = "%sKM/h" % page.data["wind"]["speed"] event["stdout"].write( "(%s) %s/%s | %s | Humidity: %s | Wind: %s" % (location, celsius, fahrenheit, description, humidity, wind_speed)) else: event["stderr"].write( "No weather information for this location") else: raise utils.EventsResultsError()
def dns(self, event): """ :help: Get all addresses for a given hostname (IPv4/IPv6) :usage: <hostname> [type [type ...]] :prefix: DNS """ hostname = event["args_split"][0] nameserver = event["server"].get_setting("dns-nameserver", None) record_types = [] if len(event["args_split"]) > 1: for arg in event["args_split"][1:]: if arg.startswith("@"): nameserver = arg[1:] else: record_types.append(arg.upper()) if not record_types: record_types = ["A?", "AAAA?"] if not nameserver == None: resolver = dns.resolver.Resolver(configure=False) resolver.nameservers = [nameserver] else: resolver = dns.resolver results = [] for record_type in record_types: try: record_type_strip = record_type.rstrip("?") query_result = resolver.query(hostname, record_type_strip) query_results = [q.to_text() for q in query_result] results.append([record_type_strip, query_results]) except dns.resolver.NXDOMAIN: raise utils.EventError("Domain not found") except dns.resolver.NoAnswer: if not record_type.endswith("?"): raise utils.EventError( "Domain does not have a '%s' record" % record_type_strip) except dns.rdatatype.UnknownRdatatype: raise utils.EventError("Unknown record type '%s'" % record_type_strip) except dns.exception.DNSException: message = "Failed to get DNS records" self.log.warn(message, exc_info=True) raise utils.EventError(message) results_str = ["%s: %s" % (t, ", ".join(r)) for t, r in results] event["stdout"].write("(%s) %s" % (hostname, " | ".join(results_str)))
def access(self, event): """ :help: Show/modify channel access for a user :usage: list <nickname> :usage: add <nickname> <permission1 permission2 ...> :usage: remove <nickname> <permission1 permission2 ...> :usage: set <nickname> <permission1 permission2 ...> :require_mode: high """ subcommand = event["args_split"][0].lower() target = event["server"].get_user(event["args_split"][1]) access = event["target"].get_user_setting(target.get_id(), "access", []) if subcommand == "list": event["stdout"].write("Access for %s: %s" % (target.nickname, " ".join(access))) elif subcommand == "set": if not len(event["args_split"]) > 2: raise utils.EventError("Please provide a list of permissions") event["target"].set_user_setting(target.get_id(), "access", event["args_split"][2:]) elif subcommand == "add": if not len(event["args_split"]) > 2: raise utils.EventError("Please provide a list of permissions") for acc in event["args_split"][2:]: if acc in access: raise utils.EventError("%s already has '%s' permission" % (target.nickname, acc)) access.append(acc) event["target"].set_user_setting(target.get_id(), "access", access) event["stdout"].write( "Added permission to %s: %s" % (target.nickname, " ".join(event["args_split"][2:]))) elif subcommand == "remove": if not len(event["args_split"]) > 2: raise utils.EventError("Please provide a list of permissions") for acc in event["args_split"][2:]: if not acc in access: raise utils.EventError("%s does not have '%s' permission" % (target.nickname, acc)) access.remove(acc) if access: event["target"].set_user_setting(target.get_id(), "access", access) else: event["target"].del_user_setting(target.get_id(), "access") event["stdout"].write( "Removed permission from %s: %s" % (target.nickname, " ".join(event["args_split"][2:]))) else: event["stderr"].write("Unknown command '%s'" % subcommand)
def _format_relay_summary_message(relays, search): if len(relays) > 1: raise utils.EventError( f"There were {len(relays)} relays found for " f"this query. {URL_RELAY_SEARCH_SEARCH}{search}") if not relays: raise utils.EventError("There were no relays found for this query.") details = relays[0] nickname = details["nickname"] consensus_weight = details["consensus_weight"] flags = " ".join(details["flags"]) url = URL_RELAY_SEARCH_DETAILS + details["fingerprint"] return f"{nickname} - CW: {consensus_weight} [{flags}] {url}"
def send(self, event): """ :help: Send coins to another user :usage: <nickname> <amount> [wallet_in:wallet_out] """ target_user = event["server"].get_user(event["args_split"][0]) wallet_in, _ = self._default_wallets(event["user"]) _, wallet_out = self._default_wallets(target_user) if len(event["args_split"]) > 2: wallet_in, _ = self._parse_wallets(event["user"], event["args_split"][2]) _, wallet_out = self._parse_wallets(target_user, event["args_split"][2]) if event["user"].get_id() == target_user.get_id(): raise utils.EventError("%s: You can't send coins to yourself" % event["user"].nickname) send_amount = event["args_split"][1] try: send_amount = self._parse_coins(send_amount, DECIMAL_ZERO) except CoinParseException as e: raise utils.EventError("%s: %s" % (event["user"].nickname, str(e))) user_coins = self._get_user_coins(event["user"], wallet_in) redeem_amount = self._redeem_amount(event["server"]) new_total_coins = self._get_all_user_coins(event["user"]) - send_amount if user_coins == DECIMAL_ZERO: raise utils.EventError("%s: You have no coins" % event["user"].nickname) elif new_total_coins < redeem_amount: raise utils.EventError( "%s: You cannot send an amount of money that puts" " you below %s coins" % (event["user"].nickname, self._coin_str(redeem_amount))) target_user_coins = self._get_user_coins(target_user, wallet_out) if target_user_coins == None: raise utils.EventError("%s: You can only send coins to users that " "have had coins before" % event["user"].nickname) self._move(event["user"], target_user, send_amount, wallet_in, wallet_out) event["stdout"].write( "%s sent %s coins to %s" % (event["user"].nickname, self._coin_str(send_amount), target_user.nickname))
def flip(self, event): """ :help: Bet on a coin flip :usage: heads|tails <coin amount> [wallet_in:wallet_out] """ wallet_in, wallet_out = self._default_wallets(event["user"]) if len(event["args_split"]) > 2: wallet_in, wallet_out = self._parse_wallets( event["user"], event["args_split"][2]) side_name = event["args_split"][0].lower() coin_bet = event["args_split"][1].lower() if coin_bet == "all": coin_bet = self._get_user_coins(event["user"], wallet_in) if coin_bet <= DECIMAL_ZERO: raise utils.EventError("%s: You have no coins to bet" % event["user"].nickname) else: try: coin_bet = self._parse_coins(coin_bet, DECIMAL_BET_MINIMUM) except CoinParseException as e: raise utils.EventError("%s: %s" % (event["user"].nickname, str(e))) if not side_name in SIDES: raise utils.EventError("%s: Please provide 'heads' or 'tails'" % event["user"].nickname) user_coins = self._get_user_coins(event["user"], wallet_in) if coin_bet > user_coins: raise utils.EventError("%s: You don't have enough coins to bet" % event["user"].nickname) chosen_side = random.SystemRandom().choice(list(SIDES.keys())) win = side_name == chosen_side coin_bet_str = self._coin_str(coin_bet) if win: new_total = self._give(event["server"], event["user"], coin_bet, wallet_out) event["stdout"].write( "%s flips %s and wins %s coin%s! (new total: %s)" % (event["user"].nickname, side_name, coin_bet_str, "" if coin_bet == 1 else "s", self._coin_str(new_total))) else: self._take(event["server"], event["user"], coin_bet, wallet_in) event["stdout"].write( "%s flips %s and loses %s coin%s! (new total: %s)" % (event["user"].nickname, side_name, coin_bet_str, "" if coin_bet == 1 else "s", self._coin_str(user_coins - coin_bet)))
def mumble(self, event): server = None if not event["args"]: server = event["target"].get_setting( "mumble-server", event["server"].get_setting("mumble-server", None)) elif event["args"]: server = event["args_split"][0] if not server: raise utils.EventError("Please provide a server") server, _, port = server.partition(":") if port: if not port.isdigit(): raise utils.EventError("Port must be numeric") port = int(port) else: port = DEFAULT_PORT timestamp = datetime.datetime.utcnow() ping_packet = struct.pack(">iQ", 0, 123) s = socket.socket(type=socket.SOCK_DGRAM) s.settimeout(5) with utils.deadline(): try: s.sendto(ping_packet, (server, port)) except socket.gaierror as e: raise utils.EventError(str(e)) try: pong_packet = s.recv(24) except socket.timeout: raise utils.EventError( "Timed out waiting for response from %s:%d" % (server, port)) pong = struct.unpack(">bbbbQiii", pong_packet) version = ".".join(str(v) for v in pong[1:4]) ping = (datetime.datetime.utcnow() - timestamp).total_seconds() * 1000 users = pong[5] max_users = pong[6] bandwidth = pong[7] / 1000 # kbit/s event["stdout"].write( "%s:%d (v%s): %d/%d users, %.1fms ping, %dkbit/s bandwidth" % (server, port, version, users, max_users, ping, bandwidth))
def add_server(self, event): alias = event["spec"][0] hostname, sep, port = event["spec"][1].partition(":") tls = port.startswith("+") port = port.lstrip("+") if not hostname or not port or not port.isdigit(): raise utils.EventError("Please provide <hostname>:[+]<port>") port = int(port) hostmask = IRCLine.parse_hostmask(event["spec"][2]) nickname = hostmask.nickname username = hostmask.username or nickname realname = nickname bindhost = hostmask.hostname or None try: server_id = self.bot.database.servers.add(alias, hostname, port, "", tls, bindhost, nickname, username, realname) except Exception as e: event["stderr"].write("Failed to add server") self.log.error("failed to add server \"%s\"", [alias], exc_info=True) return event["stdout"].write("Added server '%s'" % alias)
def add_server(self, event): """ :help: Add a new server :usage: <alias> <hostname>:[+]<port> <nickname>!<username>[@<bindhost>] :permission: addserver """ alias = event["args_split"][0] hostname, sep, port = event["args_split"][1].partition(":") tls = port.startswith("+") port = port.lstrip("+") if not hostname or not port or not port.isdigit(): raise utils.EventError("Please provide <hostname>:[+]<port>") port = int(port) hostmask = utils.irc.seperate_hostmask(event["args_split"][2]) nickname = hostmask.nickname username = hostmask.username or nickname realname = nickname bindhost = hostmask.hostname or None try: server_id = self.bot.database.servers.add(alias, hostname, port, "", tls, bindhost, nickname, username, realname) except Exception as e: event["stderr"].write("Failed to add server") self.log.error("failed to add server \"%s\"", [alias], exc_info=True) return event["stdout"].write("Added server '%s'" % alias)