"""
Legacy Comms-commands
Griatch 2021
In Evennia 1.0, the old Channel commands (originally inspired by MUX) were
replaced by the single `channel` command that performs all these function.
That command is still required to talk on channels. This contrib (extracted
from Evennia 0.9.5) reuses the channel-management of the base Channel command
but breaks out its functionality into separate Commands with MUX-familiar names.
- `allcom` - `channel/all` and `channel`
- `addcom` - `channel/alias`, `channel/sub` and `channel/unmute`
- `delcom` - `channel/unalias`, `alias/unsub` and `channel/mute`
- `cboot` - `channel/boot` (`channel/ban` and `/unban` not supported)
- `cwho` - `channel/who`
- `ccreate` - `channel/create`
- `cdestroy` - `channel/destroy`
- `clock` - `channel/lock`
- `cdesc` - `channel/desc`
Installation:
- Import the `CmdSetLegacyComms` cmdset from this module into `mygame/commands/default_cmdsets.py`
- Add it to the CharacterCmdSet's `at_cmdset_creation` method.
- Reload the server.
Example:
```python
# in mygame/commands/default_cmdsets.py
# ..
from evennia.contrib.base_systems.mux_comms_cmds import CmdSetLegacyComms # <----
class CharacterCmdSet(default_cmds.CharacterCmdSet):
# ...
def at_cmdset_creation(self):
# ...
self.add(CmdSetLegacyComms) # <----
```
"""
from django.conf import settings
from evennia.commands.cmdset import CmdSet
from evennia.commands.default.comms import CmdChannel
from evennia.utils import logger
CHANNEL_DEFAULT_TYPECLASS = settings.BASE_CHANNEL_TYPECLASS
[docs]class CmdAddCom(CmdChannel):
"""
Add a channel alias and/or subscribe to a channel
Usage:
addcom [alias=] <channel>
Joins a given channel. If alias is given, this will allow you to
refer to the channel by this alias rather than the full channel
name. Subsequent calls of this command can be used to add multiple
aliases to an already joined channel.
"""
key = "addcom"
aliases = ["aliaschan", "chanalias"]
help_category = "Comms"
locks = "cmd:not pperm(channel_banned)"
# this is used by the COMMAND_DEFAULT_CLASS parent
account_caller = True
[docs] def func(self):
"""Implement the command"""
caller = self.caller
args = self.args
if not args:
self.msg("Usage: addcom [alias =] channelname.")
return
if self.rhs:
# rhs holds the channelname
channelname = self.rhs
alias = self.lhs
else:
channelname = self.args
alias = None
channel = self.search_channel(channelname)
if not channel:
return
string = ""
if not channel.has_connection(caller):
# we want to connect as well.
success, err = self.sub_to_channel(channel)
if success:
# if this would have returned True, the account is connected
self.msg(f"You now listen to the channel {channel.key}")
else:
self.msg(f"{channel.key}: You are not allowed to join this channel.")
return
if channel.unmute(caller):
self.msg(f"You unmute channel {channel.key}.")
else:
self.msg(f"You are already connected to channel {channel.key}.")
if alias:
# create a nick and add it to the caller.
self.add_alias(channel, alias)
self.msg(f" You can now refer to the channel {channel} with the alias '{alias}'.")
else:
string += " No alias added."
self.msg(string)
[docs]class CmdDelCom(CmdChannel):
"""
remove a channel alias and/or unsubscribe from channel
Usage:
delcom <alias or channel>
delcom/all <channel>
If the full channel name is given, unsubscribe from the
channel. If an alias is given, remove the alias but don't
unsubscribe. If the 'all' switch is used, remove all aliases
for that channel.
"""
key = "delcom"
aliases = ["delaliaschan", "delchanalias"]
help_category = "Comms"
locks = "cmd:not perm(channel_banned)"
# this is used by the COMMAND_DEFAULT_CLASS parent
account_caller = True
[docs] def func(self):
"""Implementing the command."""
caller = self.caller
if not self.args:
self.msg("Usage: delcom <alias or channel>")
return
ostring = self.args.lower().strip()
channel = self.search_channel(ostring)
if not channel:
return
if not channel.has_connection(caller):
self.msg("You are not listening to that channel.")
return
if ostring == channel.key.lower():
# an exact channel name - unsubscribe
delnicks = "all" in self.switches
# find all nicks linked to this channel and delete them
if delnicks:
aliases = self.get_channel_aliases(channel)
for alias in aliases:
self.remove_alias(alias)
success, err = self.unsub_from_channel(channel)
if success:
wipednicks = " Eventual aliases were removed." if delnicks else ""
self.msg(f"You stop listening to channel '{channel.key}'.{wipednicks}")
else:
self.msg(err)
return
else:
# we are removing a channel nick
self.remove_alias(ostring)
self.msg(f"Any alias '{ostring}' for channel {channel.key} was cleared.")
[docs]class CmdAllCom(CmdChannel):
"""
perform admin operations on all channels
Usage:
allcom [on | off | who | destroy]
Allows the user to universally turn off or on all channels they are on, as
well as perform a 'who' for all channels they are on. Destroy deletes all
channels that you control.
Without argument, works like comlist.
"""
key = "allcom"
aliases = [] # important to not inherit parent's aliases
locks = "cmd: not pperm(channel_banned)"
help_category = "Comms"
# this is used by the COMMAND_DEFAULT_CLASS parent
account_caller = True
[docs] def func(self):
"""Runs the function"""
caller = self.caller
args = self.args
if not args:
subscribed, available = self.list_channels()
self.msg("\n|wAvailable channels:\n{table}")
return
return
if args == "on":
# get names of all channels available to listen to
# and activate them all
channels = [
chan
for chan in CHANNEL_DEFAULT_TYPECLASS.objects.get_all_channels()
if chan.access(caller, "listen")
]
for channel in channels:
self.execute_cmd("addcom %s" % channel.key)
elif args == "off":
# get names all subscribed channels and disconnect from them all
channels = CHANNEL_DEFAULT_TYPECLASS.objects.get_subscriptions(caller)
for channel in channels:
self.execute_cmd("delcom %s" % channel.key)
elif args == "destroy":
# destroy all channels you control
channels = [
chan
for chan in CHANNEL_DEFAULT_TYPECLASS.objects.get_all_channels()
if chan.access(caller, "control")
]
for channel in channels:
self.execute_cmd("cdestroy %s" % channel.key)
elif args == "who":
# run a who, listing the subscribers on visible channels.
string = "\n|CChannel subscriptions|n"
channels = [
chan
for chan in CHANNEL_DEFAULT_TYPECLASS.objects.get_all_channels()
if chan.access(caller, "listen")
]
if not channels:
string += "No channels."
for channel in channels:
string += "\n|w%s:|n\n %s" % (channel.key, channel.wholist)
self.msg(string.strip())
else:
# wrong input
self.msg("Usage: allcom on | off | who | clear")
[docs]class CmdCdestroy(CmdChannel):
"""
destroy a channel you created
Usage:
cdestroy <channel>
Destroys a channel that you control.
"""
key = "cdestroy"
aliases = []
help_category = "Comms"
locks = "cmd: not pperm(channel_banned)"
# this is used by the COMMAND_DEFAULT_CLASS parent
account_caller = True
[docs] def func(self):
"""Destroy objects cleanly."""
caller = self.caller
if not self.args:
self.msg("Usage: cdestroy <channelname>")
return
channel = self.search_channel(self.args)
if not channel:
self.msg("Could not find channel %s." % self.args)
return
if not channel.access(caller, "control"):
self.msg("You are not allowed to do that.")
return
channel_key = channel.key
message = f"{channel.key} is being destroyed. Make sure to change your aliases."
self.destroy_channel(channel, message)
self.msg("Channel '%s' was destroyed." % channel_key)
logger.log_sec(
"Channel Deleted: %s (Caller: %s, IP: %s)."
% (channel_key, caller, self.session.address)
)
[docs]class CmdCBoot(CmdChannel):
"""
kick an account from a channel you control
Usage:
cboot[/quiet] <channel> = <account> [:reason]
Switch:
quiet - don't notify the channel
Kicks an account or object from a channel you control.
"""
key = "cboot"
aliases = []
switch_options = ("quiet",)
locks = "cmd: not pperm(channel_banned)"
help_category = "Comms"
# this is used by the COMMAND_DEFAULT_CLASS parent
account_caller = True
[docs] def func(self):
"""implement the function"""
if not self.args or not self.rhs:
string = "Usage: cboot[/quiet] <channel> = <account> [:reason]"
self.msg(string)
return
channel = self.search_channel(self.lhs)
if not channel:
return
reason = ""
if ":" in self.rhs:
target, reason = self.rhs.rsplit(":", 1)
is_account = target.strip().startswith("*")
searchstring = target.lstrip("*")
else:
is_account = target.strip().startswith("*")
searchstring = self.rhs.lstrip("*")
target = self.caller.search(searchstring, account=is_account)
if not target:
return
if reason:
reason = " (reason: %s)" % reason
if not channel.access(self.caller, "control"):
string = "You don't control this channel."
self.msg(string)
return
success, err = self.boot_user(target, quiet="quiet" in self.switches)
if success:
self.msg(f"Booted {target.key} from {channel.key}")
logger.log_sec(
"Channel Boot: %s (Channel: %s, Reason: %s, Caller: %s, IP: %s)."
% (self.caller, channel, reason, self.caller, self.session.address)
)
else:
self.msg(err)
[docs]class CmdCWho(CmdChannel):
"""
show who is listening to a channel
Usage:
cwho <channel>
List who is connected to a given channel you have access to.
"""
key = "cwho"
aliases = []
locks = "cmd: not pperm(channel_banned)"
help_category = "Comms"
# this is used by the COMMAND_DEFAULT_CLASS parent
account_caller = True
[docs] def func(self):
"""implement function"""
if not self.args:
string = "Usage: cwho <channel>"
self.msg(string)
return
channel = self.search_channel(self.lhs)
if not channel:
return
if not channel.access(self.caller, "listen"):
string = "You can't access this channel."
self.msg(string)
return
string = "\n|CChannel subscriptions|n"
string += "\n|w%s:|n\n %s" % (channel.key, channel.wholist)
self.msg(string.strip())
[docs]class CmdChannelCreate(CmdChannel):
"""
create a new channel
Usage:
ccreate <new channel>[;alias;alias...] = description
Creates a new channel owned by you.
"""
key = "ccreate"
aliases = "channelcreate"
locks = "cmd:not pperm(channel_banned) and pperm(Player)"
help_category = "Comms"
# this is used by the COMMAND_DEFAULT_CLASS parent
account_caller = True
[docs] def func(self):
"""Implement the command"""
if not self.args:
self.msg("Usage ccreate <channelname>[;alias;alias..] = description")
return
description = ""
if self.rhs:
description = self.rhs
lhs = self.lhs
channame = lhs
aliases = None
if ";" in lhs:
channame, aliases = lhs.split(";", 1)
aliases = [alias.strip().lower() for alias in aliases.split(";")]
new_chan, err = self.create_channel(channame, description, aliases=aliases)
if new_chan:
self.msg(f"Created channel {new_chan.key} and connected to it.")
else:
self.msg(err)
[docs]class CmdClock(CmdChannel):
"""
change channel locks of a channel you control
Usage:
clock <channel> [= <lockstring>]
Changes the lock access restrictions of a channel. If no
lockstring was given, view the current lock definitions.
"""
key = "clock"
aliases = ["clock"]
locks = "cmd:not pperm(channel_banned) and perm(Admin)"
help_category = "Comms"
# this is used by the COMMAND_DEFAULT_CLASS parent
account_caller = True
[docs] def func(self):
"""run the function"""
if not self.args:
string = "Usage: clock channel [= lockstring]"
self.msg(string)
return
channel = self.search_channel(self.lhs)
if not channel:
return
if not self.rhs:
# no =, so just view the current locks
self.msg(f"Current locks on {channel.key}\n{channel.locks}")
return
# we want to add/change a lock.
if not channel.access(self.caller, "control"):
string = "You don't control this channel."
self.msg(string)
return
# Try to add the lock
success, err = self.set_lock(channel, self.rhs)
if success:
self.msg(f"Lock(s) applied. Current locks on {channel.key}:\n{channel.locks}")
else:
self.msg(err)
[docs]class CmdCdesc(CmdChannel):
"""
describe a channel you control
Usage:
cdesc <channel> = <description>
Changes the description of the channel as shown in
channel lists.
"""
key = "cdesc"
aliases = []
locks = "cmd:not pperm(channel_banned)"
help_category = "Comms"
# this is used by the COMMAND_DEFAULT_CLASS parent
account_caller = True
[docs] def func(self):
"""Implement command"""
caller = self.caller
if not self.rhs:
self.msg("Usage: cdesc <channel> = <description>")
return
channel = self.search_channel(self.lhs)
if not channel:
return
# check permissions
if not channel.access(caller, "control"):
self.msg("You cannot admin this channel.")
return
self.set_desc(channel, self.rhs)
self.msg(f"Description of channel '{channel.key}' set to '{self.rhs}'.")
[docs]class CmdSetLegacyComms(CmdSet):
[docs] def at_cmdset_createion(self):
self.add(CmdAddCom())
self.add(CmdAllCom())
self.add(CmdDelCom())
self.add(CmdCdestroy())
self.add(CmdCBoot())
self.add(CmdCWho())
self.add(CmdChannelCreate())
self.add(CmdClock())
self.add(CmdCdesc())