diff --git a/game/manage.py b/game/manage.py index 55cfb3c7de..7784e23620 100755 --- a/game/manage.py +++ b/game/manage.py @@ -112,11 +112,10 @@ except Exception: string += """\n Error: Couldn't import the file 'settings.py' in the directory containing %r. There can be two reasons for this: - 1) You moved your settings.py elsewhere. In that case you need to run - django-admin.py, passing it the true location of your settings module. - 2) The settings module is where it's supposed to be, but an exception - was raised when trying to load it. Review the traceback above to - resolve the problem, then try again. + 1) You moved your settings.py elsewhere. In that case move it back or + create a link to it from this folder. + 2) The settings module is where it's supposed to be, but contains errors. + Review the traceback above to resolve the problem, then try again. """ % __file__ print string sys.exit(1) diff --git a/src/commands/default/admin.py b/src/commands/default/admin.py index c1fed242a9..0bc76723b2 100644 --- a/src/commands/default/admin.py +++ b/src/commands/default/admin.py @@ -43,8 +43,10 @@ class CmdBoot(MuxCommand): if ':' in args: args, reason = [a.strip() for a in args.split(':', 1)] + else: + args, reason = args, "" + boot_list = [] - reason = "" if 'port' in self.switches: # Boot a particular port. diff --git a/src/commands/default/cmdset_default.py b/src/commands/default/cmdset_default.py index cef12f2b0f..881ed72c29 100644 --- a/src/commands/default/cmdset_default.py +++ b/src/commands/default/cmdset_default.py @@ -90,6 +90,7 @@ class DefaultCmdSet(CmdSet): self.add(comms.CmdPage()) self.add(comms.CmdIRC2Chan()) self.add(comms.CmdIMC2Chan()) + self.add(comms.CmdIMCInfo()) # Batchprocessor commands self.add(batchprocess.CmdBatchCommands()) diff --git a/src/commands/default/comms.py b/src/commands/default/comms.py index e3ae3e595f..7b31285a7f 100644 --- a/src/commands/default/comms.py +++ b/src/commands/default/comms.py @@ -937,7 +937,7 @@ class CmdIMC2Chan(MuxCommand): """ key = "@imc2chan" - locks = "cmd:serversetting(IMC2_ENABLED) and perm(Wizards)" + locks = "cmd:serversetting(IMC2_ENABLED) and perm(Immortals)" help_category = "Comms" def func(self): @@ -1003,3 +1003,105 @@ class CmdIMC2Chan(MuxCommand): self.caller.msg("This IMC2 connection already exists.") return self.caller.msg("Connection created. Connecting to IMC2 server.") + +class CmdIMCInfo(MuxCommand): + """ + imcchanlist + + Usage: + @imcinfo[/switches] + @imcchanlist - list imc2 channels + @imclist - list connected muds + + Switches: + channels - as imcchanlist (default) + games - as imclist + update - force an update of all lists + + + Shows lists of games or channels on the IMC2 network. + """ + + key = "@imcinfo" + aliases = ["@imcchanlist", "@imclist"] + locks = "cmd: serversetting(IMC2_ENABLED) or perm(Immortals)" + help_category = "Comms" + + def func(self): + "Run the command" + + if "update" in self.switches: + # update the lists + import time + from src.comms.imc2lib import imc2_packets as pck + from src.comms.imc2 import IMC2_MUDLIST, IMC2_CHANLIST, IMC2_CHANNELS + # update connected muds + for chan in IMC2_CHANNELS: + chan.send_packet(pck.IMC2PacketKeepAliveRequest()) + # prune inactive muds + for name, mudinfo in IMC2_MUDLIST.mud_list.items(): + if time.time() - mudinfo.last_updated > 3599: + del IMC2_MUDLIST.mud_list[name] + # update channel list + checked_networks = [] + for channel in IMC2_CHANNELS: + network = channel.factory.network + if not network in checked_networks: + channel.send_packet(pck.IMC2PacketIceRefresh()) + checked_networks.append(network) + self.caller.msg("IMC2 lists were re-synced.") + + elif "games" in self.switches or self.cmdstring == "@imclist": + # list muds + from src.comms.imc2 import IMC2_MUDLIST + + muds = IMC2_MUDLIST.get_mud_list() + networks = set(mud.networkname for mud in muds) + string = "" + nmuds = 0 + for network in networks: + string += "\n {GMuds registered on %s:{n" % network + cols = [["Name"], ["Url"], ["Host"], ["Port"]] + for mud in (mud for mud in muds if mud.networkname == network): + nmuds += 1 + cols[0].append(mud.name) + cols[1].append(mud.url) + cols[2].append(mud.host) + cols[3].append(mud.port) + ftable = utils.format_table(cols) + for ir, row in enumerate(ftable): + if ir == 0: + string += "\n{w" + "".join(row) + "{n" + else: + string += "\n" + "".join(row) + string += "\n %i Muds found." % nmuds + self.caller.msg(string) + elif not self.switches or "channels" in self.switches or self.cmdstring == "@imcchanlist": + # show channels + from src.comms.imc2 import IMC2_CHANLIST, IMC2_CHANNELS + + channels = IMC2_CHANLIST.get_channel_list() + string = "" + nchans = 0 + string += "\n {GChannels on %s:{n" % (", ".join(conn.factory.network for conn in IMC2_CHANNELS)) + cols = [["Full name"], ["Name"], ["Owner"], ["Perm"], ["Policy"]] + for channel in channels: + nchans += 1 + cols[0].append(channel.name) + cols[1].append(channel.localname) + cols[2].append(channel.owner) + cols[3].append(channel.level) + cols[4].append(channel.policy) + ftable = utils.format_table(cols) + for ir, row in enumerate(ftable): + if ir == 0: + string += "\n{w" + "".join(row) + "{n" + else: + string += "\n" + "".join(row) + string += "\n %i Channels found." % nchans + self.caller.msg(string) + + else: + # no valid inputs + string = "Usage: imcinfo|imcchanlist|imclist" + self.caller(string) diff --git a/src/comms/imc2.py b/src/comms/imc2.py index bfcd9b6920..af6f6012e0 100644 --- a/src/comms/imc2.py +++ b/src/comms/imc2.py @@ -62,7 +62,7 @@ class Send_IsAlive(Script): channel.send_packet(pck.IMC2PacketIsAlive()) def is_valid(self): "Is only valid as long as there are channels to update" - return IMC2_CHANNELS + return any(service for service in SESSIONS.server.services if service.name.startswith("IMC2:")) class Send_Keepalive_Request(Script): """ @@ -79,7 +79,7 @@ class Send_Keepalive_Request(Script): channel.send_packet(pck.IMC2PacketKeepAliveRequest()) def is_valid(self): "Is only valid as long as there are channels to update" - return IMC2_CHANNELS + return any(service for service in SESSIONS.server.services if service.name.startswith("IMC2:")) class Prune_Inactive_Muds(Script): """ @@ -99,7 +99,7 @@ class Prune_Inactive_Muds(Script): del IMC2_MUDLIST.mud_list[name] def is_valid(self): "Is only valid as long as there are channels to update" - return IMC2_CHANNELS + return any(service for service in SESSIONS.server.services if service.name.startswith("IMC2:")) class Sync_Server_Channel_List(Script): """ @@ -116,11 +116,12 @@ class Sync_Server_Channel_List(Script): def at_repeat(self): checked_networks = [] for channel in self.IMC2_CHANNELS: - network = channel.external_config.split['|'][0] + network = channel.factory.network if not network in checked_networks: channel.send_packet(pkg.IMC2PacketIceRefresh()) checked_networks.append(network) - + def is_valid(self): + return any(service for service in SESSIONS.server.services if service.name.startswith("IMC2:")) # # IMC2 protocol # @@ -420,6 +421,7 @@ def delete_connection(channel, imc2_network, imc2_port, imc2_channel, mudname): def connect_to_imc2(connection): "Create the imc instance and connect to the IMC2 network and channel." + # get config key = utils.to_str(connection.external_key) service_key = build_service_key(key) @@ -427,8 +429,8 @@ def connect_to_imc2(connection): [utils.to_str(conf) for conf in connection.external_config.split('|')] # connect imc = internet.TCPClient(imc2_network, int(imc2_port), IMC2Factory(key, imc2_channel, imc2_network, imc2_port, imc2_mudname, - imc2_client_pwd, imc2_server_pwd, connection.channel.key)) - imc.setName(service_key) + imc2_client_pwd, imc2_server_pwd, connection.channel.key)) + imc.setName(service_key) SESSIONS.server.services.addService(imc) def connect_all(): diff --git a/src/settings_default.py b/src/settings_default.py index fa62d76e8d..fc2b559206 100644 --- a/src/settings_default.py +++ b/src/settings_default.py @@ -266,7 +266,8 @@ CHANNEL_CONNECTINFO = ("MUDconnections", ('connections, mud_conns'), # Note: You do *not* have to make your MUD open to # the public to use the external connections, they # operate as long as you have an internet connection, -# just like stand-alone chat clients. +# just like stand-alone chat clients. IRC and IMC2 +# requires that you have twisted.words installed. # Evennia can connect to external IRC channels and # echo what is said on the channel to IRC and vice diff --git a/src/utils/utils.py b/src/utils/utils.py index 123f8514f3..54cb83422a 100644 --- a/src/utils/utils.py +++ b/src/utils/utils.py @@ -441,6 +441,15 @@ def check_evennia_dependencies(): errstring += "\n WARNING: South version %s found. Evennia recommends version %s or higher." % (sversion, south_min) except ImportError: pass + # IRC support + if settings.IRC_ENABLED: + try: + import twisted.words + except ImportError: + errstring += "\n ERROR: IRC is enabled, but twisted.words is not installed. Please install it." + errstring += "\n Linux Debian/Ubuntu users should install package 'python-twisted-words', others" + errstring += "\n can get it from http://twistedmatrix.com/trac/wiki/TwistedWords." + no_error = False errstring = errstring.strip() if errstring: print "%s\n %s\n%s" % ("-"*78, errstring, '-'*78)