diff --git a/game/manage.py b/game/manage.py index fc6c87a3cf..5d115b722d 100755 --- a/game/manage.py +++ b/game/manage.py @@ -124,8 +124,6 @@ SECRET_KEY = '%s' # Test the import of the settings file #------------------------------------------------------------ try: - # i18n - from django.utils.translation import ugettext as _ from game import settings except Exception: import traceback @@ -157,11 +155,11 @@ if __name__ == "__main__": # checks if the settings file was created this run if _CREATED_SETTINGS: - print _(""" + print """ Edit your new settings.py file as needed, then run 'python manage syncdb' and follow the prompts to create the database and your superuser account. - """) + """ sys.exit() # run the standard django manager, if dependencies match diff --git a/locale/sv/LC_MESSAGES/django.mo b/locale/sv/LC_MESSAGES/django.mo index 7c07e2f8de..8dd1ea2f92 100644 Binary files a/locale/sv/LC_MESSAGES/django.mo and b/locale/sv/LC_MESSAGES/django.mo differ diff --git a/locale/sv/LC_MESSAGES/django.po b/locale/sv/LC_MESSAGES/django.po index a123dce36d..e09da6843c 100644 --- a/locale/sv/LC_MESSAGES/django.po +++ b/locale/sv/LC_MESSAGES/django.po @@ -2,263 +2,295 @@ # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. +# Griatch , 2012. # msgid "" msgstr "" -"Project-Id-Version: 0.1\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-02-19 10:36+0100\n" -"PO-Revision-Date: 2012-02-19 10:45+0100\n" +"Project-Id-Version: Evennia Beta\n" +"Report-Msgid-Bugs-To: www.evennia.com\n" +"POT-Creation-Date: 2012-06-13 23:11+0200\n" +"PO-Revision-Date: 2012-06-14 02:40+0100\n" "Last-Translator: Griatch \n" -"Language-Team: Griatch \n" +"Language-Team: Swedish <>\n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" -"X-Poedit-Language: Swedish\n" -"X-Poedit-Country: Sweden\n" -"X-Poedit-SourceCharset: utf-8\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: game/manage.py:116 +#: src/commands/cmdhandler.py:201 +#, python-format +msgid "Command '%s' is not available." +msgstr "Kommandot '%s' är inte tillgängligt." + +#: src/commands/cmdhandler.py:204 +#, python-format +msgid " Maybe you meant %s?" +msgstr "Menade du kanske %s?" + +#: src/commands/cmdhandler.py:204 +msgid "or" +msgstr "eller" + +#: src/commands/cmdhandler.py:206 +msgid " Type \"help\" for help." +msgstr "Skriv \"help\" för hjälp." + +#: src/commands/cmdhandler.py:212 +msgid "There where multiple matches." +msgstr "Det fanns många träffar." + +#: src/commands/cmdparser.py:144 +#, python-format +msgid "Could not find '%s'." +msgstr "Kunde inte hitta '%s'." + +#: src/commands/cmdparser.py:160 +msgid "location" +msgstr "plats" + +#: src/commands/cmdparser.py:161 +msgid " (carried)" +msgstr "(buren)" + +#: src/commands/cmdparser.py:240 +msgid " (channel)" +msgstr "(kanal)" + +#: src/commands/cmdparser.py:244 +#, python-format +msgid " (exit to %s)" +msgstr "(utgång till %s)" + +#: src/commands/cmdsethandler.py:115 +#, python-format +msgid "Error loading cmdset: Couldn't import module '%s'." +msgstr "Fel medan cmdset laddades: Kunde inte importera modulen '%s'." + +#: src/commands/cmdsethandler.py:119 +#, python-format +msgid "Error in loading cmdset: No cmdset class '%(classname)s' in %(modulepath)s." +msgstr "Fel medan cmdset laddades: Ingen cmdset-klass med namn '%(classname)s' i %(modulepath)s." + +#: src/commands/cmdsethandler.py:123 +#, python-format +msgid "Compile/Run error when loading cmdset '%s'. Error was logged." +msgstr "Kompilerings/Körningsfel när cmdset '%s' laddades. Felet skrevs i loggen." + +#: src/commands/cmdsethandler.py:199 +#, python-format +msgid "custom %(mergetype)s on cmdset '%(merged_on)s'" +msgstr "särskild %(mergetype)s på cmdset '%(merged_on)s'" + +#: src/commands/cmdsethandler.py:201 +#, python-format +msgid " : %(current)s" +msgstr ": %(current)s" + +#: src/commands/cmdsethandler.py:207 +#, python-format +msgid " <%(key)s (%(mergetype)s, prio %(prio)i, %(permstring)s)>: %(keylist)s" +msgstr " <%(key)s (%(mergetype)s, prio %(prio)i, %(permstring)s)>: %(keylist)s" + +#: src/commands/cmdsethandler.py:281 +#: src/commands/cmdsethandler.py:313 +msgid "Only CmdSets can be added to the cmdsethandler!" +msgstr "Bara CmdSets can läggas till cmdsethandler!" + +#: src/comms/imc2.py:66 +msgid "Send an IMC2 is-alive packet" +msgstr "Skicka ett IMC2-is-alive paket" + +#: src/comms/imc2.py:82 +msgid "Send an IMC2 keepalive-request packet" +msgstr "Skicka ett IMC2 keepalive-request paket" + +#: src/comms/imc2.py:99 +msgid "Check IMC2 list for inactive games" +msgstr "Genomsök IMC2-listan efter inaktiva spel" + +#: src/comms/imc2.py:120 +msgid "Re-sync IMC2 network channel list" +msgstr "Återsynca nätverkslistan över IMC2 kanaler" + +#: src/comms/imc2.py:204 +msgid "IMC2 server rejected connection." +msgstr "IMC2 server avvisade uppkopplingen." + +#: src/comms/imc2.py:213 +msgid "IMC2: Autosetup response found." +msgstr "IMC2: Autosetup-svar hittat." + +#: src/comms/imc2.py:220 +#, python-format +msgid "Successfully authenticated to the '%s' network." +msgstr "Identifierade sig framgångsrikt till nätverket '%s'." + +#: src/comms/imc2.py:260 +#, python-format +msgid "{c%(sender)s@%(origin)s{n {wpages (over IMC):{n %(msg)s" +msgstr "{c%(sender)s@%(origin)s{n {wskickar (over IMC):{n %(msg)s" + +#: src/comms/imc2.py:371 +#, python-format +msgid "Connection failed: %s" +msgstr "Uppkopplingen misslyckades: %s" + +#: src/comms/imc2.py:376 +#, python-format +msgid "Connection lost: %s" +msgstr "Uppkopplingen förlorades: %s" + +#: src/comms/imc2.py:413 +#, python-format +msgid "Cannot attach IMC2<->Evennia: Evennia Channel '%s' not found" +msgstr "Kan inte sammankoppla IMC2<->Evennia: Evennia-kanalen '%s' gick inte att hitta." + +#: src/comms/irc.py:51 +#, python-format +msgid "joined %s." +msgstr "lyssnar till %s." + +#: src/comms/irc.py:66 +msgid "Unknown" +msgstr "Okänd" + +#: src/comms/irc.py:97 +msgid "Connection closed." +msgstr "Uppkopplingen stängdes." + +#: src/comms/irc.py:99 +#, python-format +msgid "Lost connection %(key)s. Reason: '%(reason)s'. Reconnecting." +msgstr "Förlorade uppkopplingen %(key)s. Anledning: '%(reason)s'. Försöker igen." + +#: src/comms/irc.py:102 +#, python-format +msgid "Could not connect %(key)s Reason: '%(reason)s'" +msgstr "Kunde inte koppla upp %(key)s Reason: '%(reason)s'" + +#: src/comms/irc.py:122 +#, python-format +msgid "Cannot attach IRC<->Evennia: Evennia Channel '%s' not found" +msgstr "Kan inte sammankoppla IRC<->Evennia: Evennia-kanalen '%s' gick inte att hitta" + +#: src/comms/imc2lib/imc2_listeners.py:20 +#, python-format +msgid "Whois reply from %(origin)s: %(msg)s" +msgstr "Whois-svar från %(origin)s: %(msg)s" + +#: src/locks/lockhandler.py:221 +#, python-format +msgid "Lock: function '%s' is not available." +msgstr "Lås: funktionen '%s' kunde inte hittas." + +#: src/locks/lockhandler.py:234 +#, python-format +msgid "Lock: definition '%s' has syntax errors." +msgstr "Lås: definitionen '%s' har syntaktiska fel." + +#: src/locks/lockhandler.py:238 +#, python-format +msgid "Lock: access type '%(access_type)s' changed from '%(source)s' to '%(goal)s' " +msgstr "Lås: låstypen '%(access_type)s' ändrade sig från '%(source)s' till '%(goal)s'" + +#: src/locks/lockhandler.py:272 +#, python-format +msgid "Lock: '%s' contains no colon (:)." +msgstr "Lås: '%s' innehåller inget kolon (:)." + +#: src/locks/lockhandler.py:276 +#, python-format +msgid "Lock: '%s' has no access_type (left-side of colon is empty)." +msgstr "Lås: '%s' saknar låstyp (ingenting till vänster om kolonet)." + +#: src/locks/lockhandler.py:279 +#, python-format +msgid "Lock: '%s' has mismatched parentheses." +msgstr "Lås: '%s' has ickematchande parenteser." + +#: src/locks/lockhandler.py:282 +#, python-format +msgid "Lock: '%s' has no valid lock functions." +msgstr "Lås: '%s' innehåller inga acceptabla låsfunktioner." + +#: src/scripts/scripthandler.py:43 #, python-format msgid "" "\n" -"\n" -" Error: Couldn't import the file 'settings.py' in the directory \n" -" containing %(file)r. There are usually two reasons for this: \n" -" 1) You moved your settings.py elsewhere. In that case move it back or \n" -" create a link to it from this folder. \n" -" 2) The settings module is where it's supposed to be, but contains errors.\n" -" Review the traceback above to resolve the problem, then try again. \n" -" 3) If you get errors on finding DJANGO_SETTINGS_MODULE you might have \n" -" set up django wrong in some way. If you run a virtual machine, it might be worth\n" -" to restart it to see if this resolves the issue. Evennia should not require you \n" -" to define any environment variables manually. \n" -" " +" '%(key)s' (%(next_repeat)s/%(interval)s, %(repeats)s repeats): %(desc)s" msgstr "" "\n" -"\n" -" Fel: Kunde inte importera filen 'settings.py' från den hårddiskplats som\n" -" innehåller %(file)r. Detta beror vanligtvis på en av två anledningar: \n" -" 1) Du har flyttat settings.py någon annanstans. Flytta tillbaka filen eller länka \n" -" den hit.\n" -" 2) settings.py är där den ska vara men innehåller fel. Läs felmeddelandet ovan\n" -" och fixa till problemet. \n" -" 3) Om du ser ett felmeddelande som nämner DJANGO_SETTINGS_MODULE så \n" -" är django felkonfigurerat på något vis. Om du kör i en virtuell maskin så kan det\n" -" vara värt att starta om för att se om detta löser problemet. Evennia kräver normalt\n" -" inte att du definierar några miljövariabler manuellt. \n" -" " +" '%(key)s' (%(next_repeat)s/%(interval)s, %(repeats)s repetitioner): %(desc)s" -#: game/manage.py:140 -msgid "" -"\n" -" Edit your new settings.py file as needed, then run\n" -" 'python manage syncdb' and follow the prompts to\n" -" create the database and your superuser account.\n" -" " -msgstr "" -"\n" -" Modifiera din nya settings.py fil som du önskar, kör\n" -" sedan 'python manage.py syncdb' och följ instruktionerna\n" -" för att skapa databasen och ditt superuser-konto.\n" -" " +#: src/scripts/scripts.py:70 +#, python-format +msgid "Script %(key)s(#%(dbid)i) of type '%(cname)s': at_repeat() error '%(err)s'." +msgstr "Script %(key)s(#%(dbid)i) av typ '%(cname)s': at_repeat() fel '%(err)s'." -#: src/server/amp.py:109 -msgid " Portal lost connection to Server." -msgstr "Portalen förlorade sin koppling till terminalen. " +#: src/scripts/scripts.py:397 +msgid "This is an empty placeholder script." +msgstr "Detta är ett tomt platshållar-script." -#: src/server/amp.py:218 +#: src/scripts/scripts.py:404 +msgid "Checks sessions so they are live." +msgstr "Kollar sessioner så att de är aktiva." + +#: src/scripts/scripts.py:419 +msgid "Validates all scripts regularly." +msgstr "Validerar alla script regelbundet." + +#: src/scripts/scripts.py:433 +msgid "Updates the channel handler" +msgstr "Uppdaterar kanalhanteraren" + +#: src/scripts/scripts.py:447 +msgid "Clears the Attribute Cache" +msgstr "Nollställer Attribut-cachen" + +#: src/server/amp.py:394 msgid " ... Server restarted." -msgstr "... Servern startades om. " +msgstr "... Servern startades om." -#: src/server/amp.py:227 -#, python-format -msgid "AMP Error for %(info)s: %(e)s" -msgstr "AMP-fel: %(info)s: %(e)s" - -#: src/server/amp.py:366 -#: src/server/amp.py:428 -#, python-format -msgid "operation %(op)s not recognized." -msgstr "kommando av typ %(op)s kunde inte kännas igen." - -#: src/server/initial_setup.py:37 -msgid " Creating objects (Player #1 and Limbo room) ..." -msgstr "Skapar objekt (Spelare #1 och Limbo) ..." - -#: src/server/initial_setup.py:62 -msgid "#1 could not be created. Check the Player/Character typeclass for bugs." -msgstr "#1 kunde inte skapas. Kolla efter fel i typklassen för Player/Character. " - -#: src/server/initial_setup.py:65 +#: src/server/initial_setup.py:61 msgid "This is User #1." msgstr "Detta är användare #1." -#: src/server/initial_setup.py:73 +#: src/server/initial_setup.py:69 msgid "Limbo" msgstr "Limbo" -#: src/server/initial_setup.py:96 -msgid " Creating default channels ..." -msgstr "Skapar standardkanaler ..." - -#: src/server/initial_setup.py:119 -msgid " Importing MUX help database (devel reference only) ..." -msgstr "Importerar MUX:s hjälpdatabas (enbart för utvecklare)..." - -#: src/server/initial_setup.py:123 -#, python-format -msgid " Moving imported help db to help category '%(default)s'." -msgstr "Flyttar de importerade hjälpfileran till hjälpkategorin '%(default)s'." - -#: src/server/initial_setup.py:134 -msgid " Creating and starting global scripts ..." -msgstr "Skapar och startar globala skript ..." - -#: src/server/initial_setup.py:143 -msgid " Error creating system scripts." -msgstr "Fel under skapandet av System-skript." - -#: src/server/initial_setup.py:152 -msgid " Starting in-game time ..." -msgstr "Startar spelets tid ..." - -#: src/server/initial_setup.py:171 -msgid " ADMIN_MEDIA_ROOT already exists. Ignored." -msgstr "ADMIN_MEDIA_ROOT existerar redan. Ignorerar." - -#: src/server/initial_setup.py:174 -msgid " Admin-media files copied to ADMIN_MEDIA_ROOT (Windows mode)." -msgstr "Admin-media-filer kopierades till ADMIN_MEDIA_ROOT (Windows-läge)" - -#: src/server/initial_setup.py:179 -msgid " Admin-media symlinked to ADMIN_MEDIA_ROOT." -msgstr "Admin-media länkades till ADMIN_MEDIA_ROOT." - -#: src/server/initial_setup.py:181 -msgid " Admin-media files should be copied manually to ADMIN_MEDIA_ROOT." -msgstr "Admin-media-filer bör kopieras manuellt till ADMIN_MEDIA_ROOT." - -#: src/server/initial_setup.py:194 -msgid " Running at_initial_setup() hook." -msgstr "Kör kroken at_initial_setup()." - -#: src/server/models.py:88 -#, python-format -msgid "ServerConfig cannot store db objects! (%s)" -msgstr "ServerConfig kan inte lagra databas-objekt! (%s)" - -#: src/server/portal.py:106 -#, python-format -msgid " %(servername)s Portal (%(version)s) started." -msgstr " %(servername)s Portal (%(version)s) startades." - -#: src/server/portal.py:138 -#, python-format -msgid "writing mode=%(mode)s to %(portal_restart)s" -msgstr "writing mode = %(mode)s till %(portal_restart)s" - -#: src/server/server.py:137 -msgid " Server started for the first time. Setting defaults." -msgstr "Servern startades för första gången. Sätter standardvärden." - -#: src/server/server.py:145 -#, python-format -msgid " Resuming initial setup from step %(last)s." -msgstr "Startar om uppstarten från steg nummer %(last)s." - -#: src/server/server.py:165 -#, fuzzy, python-format -msgid " %(servername)s Server (%(version)s) started." -msgstr " %(servername)s Portal (%(version)s) startades." - -#: src/server/serversession.py:109 +#: src/server/serversession.py:108 #, python-format msgid "Logged in: %(self)s" -msgstr "%(self)s loggade in. " +msgstr "Loggade in: %(self)s" -#: src/server/sessionhandler.py:204 +#: src/server/sessionhandler.py:189 +msgid "You have been disconnected." +msgstr "Du har blivit frånkopplad." + +#: src/server/sessionhandler.py:202 msgid "Logged in from elsewhere. Disconnecting." -msgstr "Inloggad från någon annanstans. Kopplas ifrån." +msgstr "Inloggad från någon annanstans ifrån. Kopplas ifrån." -#: src/server/sessionhandler.py:220 +#: src/server/sessionhandler.py:222 msgid "Idle timeout exceeded, disconnecting." -msgstr "Passivitetstimer överskriden. Kopplas ifrån." - -#: src/server/ssh.py:298 -msgid " Generating SSH RSA keypair ..." -msgstr "Genererar SSH RSA-nyckerlpar. " - -#: src/server/ssh.py:343 -#, python-format -msgid "" -" getKeyPair error: %(e)s\n" -" WARNING: Evennia could not auto-generate SSH keypair. Using conch default keys instead." -msgstr "" -"getKeyPair-fel: %(e)s\n" -"VARNING: Evennia kunde inte auomatiskt generera SSH-nyckelparet. Använder standardnycklar istället." - -#: src/server/ssh.py:344 -#, python-format -msgid " If this error persists, create game/%(pub)s and game/%(priv)s yourself using third-party tools." -msgstr "Om detta fel består, skapa game/%(pub)s och game/%(priv)s själv med hjälp av tredjepartsverktyg. " - -#: src/server/ssl.py:11 -msgid " SSL_ENABLED requires PyOpenSSL." -msgstr "För att använde SSL_ENABLED måste PyOpenSSL vara installerat. " - -#: src/server/ssl.py:36 -msgid " Creating SSL key and certificate ... " -msgstr "Skapar SSL-nyckel och certifikat ..." - -#: src/server/ssl.py:45 -#, python-format -msgid "" -"rsaKey error: %(e)s\n" -" WARNING: Evennia could not auto-generate SSL private key." -msgstr "" -"rsaKey fel: %(e)s\n" -"VARNING: Evennia kunde inte automatiskt generera den privata SSL-nyckeln. " - -#: src/server/ssl.py:46 -#, python-format -msgid "If this error persists, create game/%(keyfile)s yourself using third-party tools." -msgstr "Om detta fel består, skapa game/%(keyfile)s själv med hjälp av tredjepartsverktyg. " - -#: src/server/ssl.py:59 -#, python-format -msgid " Evennia's SSL context factory could not automatically create an SSL certificate game/%(cert)s." -msgstr "Evennia's SSL-rutiner kunde inte automatiskt skapa SSL-certifikatet game/%(cert)s." - -#: src/server/ssl.py:60 -#, python-format -msgid " A private key 'ssl.key' was already created. Please create %(cert)s manually using the commands valid" -msgstr "En privat nyckel 'ssl.key' har redan skapats. Skapa %(cert)s manuellt med hjälp av kommandona för ditt operativsystem." - -#: src/server/ssl.py:61 -msgid " for your operating system." -msgstr "för ditt operativsystem." - -#: src/server/ssl.py:62 -msgid " Example (linux, using the openssl program): " -msgstr "Exempel för Linux, med openssl:" +msgstr "Timeout. Kopplar ur." #: src/web/templates/admin/base_site.html:4 msgid "Evennia site admin" -msgstr "Evennia webside-admin" +msgstr "Evennia site admin" #: src/web/templates/admin/base_site.html:7 msgid "Evennia database administration" -msgstr "Evennia databas-administration" +msgstr "Evennia databasadministration" #: src/web/templates/admin/index.html:29 #: src/web/templates/admin/index.html:73 #: src/web/templates/admin/index.html:117 #, python-format msgid "Models available in the %(name)s application." -msgstr "Modeller tillgängliga i %(name)s." +msgstr "Modeller tillgängliga i %(name)s applikation." #: src/web/templates/admin/index.html:30 #: src/web/templates/admin/index.html:74 @@ -282,15 +314,15 @@ msgstr "Ändra" #: src/web/templates/admin/index.html:149 msgid "You don't have permission to edit anything." -msgstr "Du har inte tillstånd att ändra någonting." +msgstr "Du har inte rättigheter att ändra någonting." #: src/web/templates/admin/index.html:157 msgid "Recent Actions" -msgstr "Senaste Handlingar" +msgstr "Senaste Aktiviteter" #: src/web/templates/admin/index.html:158 msgid "My Actions" -msgstr "Mina Handlingar" +msgstr "Mina Aktiviteter" #: src/web/templates/admin/index.html:162 msgid "None yet." @@ -302,11 +334,11 @@ msgstr "Okänt innehåll" #: src/web/templates/admin/players/add_form.html:6 msgid "First, enter a username and password. Then you'll be able to edit more Player options." -msgstr "Mata först in ett användarnamn och lösenord. Sedan kommer du att kunna ändra fler Spelarinställningar." +msgstr "Först, ange ett användarnamn och lösenord. Då kommer du att kunna modifiera fler Player-inställningar." #: src/web/templates/admin/players/add_form.html:8 msgid "Enter a username and password." -msgstr "Mata in ett användarnamn och lösenord." +msgstr "Ange ett användarnamn och lösenord." #: src/web/templates/admin/players/change_form.html:20 #: src/web/templates/admin/players/change_list.html:42 @@ -320,14 +352,14 @@ msgstr "Historia" #: src/web/templates/admin/players/change_form.html:32 #: src/web/templates/admin/players/stacked.html:9 msgid "View on site" -msgstr "Se på Websida" +msgstr "Inspektera på sida" #: src/web/templates/admin/players/change_form.html:43 #: src/web/templates/admin/players/change_list.html:73 msgid "Please correct the error below." msgid_plural "Please correct the errors below." msgstr[0] "Vänligen korrigera felet nedan." -msgstr[1] "Vänligen korrigera felen nedan." +msgstr[1] "Vänligen korrigera felet nedan.\t\t\t\t" #: src/web/templates/admin/players/change_list.html:64 #, python-format @@ -341,552 +373,9 @@ msgstr "Filtrera" #: src/web/templates/admin/players/stacked.html:67 #, python-format msgid "Add another %(verbose_name)s" -msgstr "Lägg till ett annat %(verbose_name)s" +msgstr "Lägg till ännu ett %(verbose_name)s" #: src/web/templates/admin/players/stacked.html:70 msgid "Remove" msgstr "Ta bort" -#~ msgid "" -#~ "\n" -#~ " (version %s) \n" -#~ "\n" -#~ "This program launches Evennia with various options. You can access all\n" -#~ "this functionality directly from the command line; for example option\n" -#~ "five (restart server) would be \"evennia.py restart server\". Use\n" -#~ "\"evennia.py -h\" for command line options.\n" -#~ "\n" -#~ "Evennia consists of two separate programs that both must be running\n" -#~ "for the game to work as it should:\n" -#~ "\n" -#~ "Portal - the connection to the outside world (via telnet, web, ssh\n" -#~ " etc). This is normally running as a daemon and don't need to\n" -#~ " be reloaded unless you are debugging a new connection\n" -#~ " protocol. As long as this is running, players won't loose\n" -#~ " their connection to your game. Only one instance of Portal\n" -#~ " will be started, more will be ignored.\n" -#~ "Server - the game server itself. This will often need to be reloaded\n" -#~ " as you develop your game. The Portal will auto-connect to the\n" -#~ " Server whenever the Server activates. We will also make sure\n" -#~ " to automatically restart this whenever it is shut down (from\n" -#~ " here or from inside the game or via task manager etc). Only\n" -#~ " one instance of Server will be started, more will be ignored.\n" -#~ "\n" -#~ "In a production environment you will want to run with the default\n" -#~ "option (1), which runs as much as possible as a background\n" -#~ "process. When developing your game it is however convenient to\n" -#~ "directly see tracebacks on standard output, so starting with options\n" -#~ "2-4 may be a good bet. As you make changes to your code, reload the\n" -#~ "server (option 5) to make it available to users.\n" -#~ "\n" -#~ "Reload and stop is not well supported in Windows. If you have issues, " -#~ "log\n" -#~ "into the game to stop or restart the server instead. \n" -#~ msgstr "" -#~ "\n" -#~ " (version %s) \n" -#~ "\n" -#~ "Detta program startar Evennia med olika funktionalitet. Du kan se alla\n" -#~ "functioner direkt från kommandoraden; t.ex så motsvarar val nummer 5\n" -#~ "(starta om servern) kommandot \"evennia.py restart server\" Använd \n" -#~ "\"evennia.py -h för att lista alla möjliga kommandon. \n" -#~ "\n" -#~ "Evennia består av tvp separata program som båda måste vara igång\n" -#~ "för att servern ska fungera:\n" -#~ "\n" -#~ "Portal - Kopplingen till omvärlden (via telnet, web, ssh etc). Portalen\n" -#~ " körs vanligen som en \"demon\" och behöver inte startas om\n" -#~ " såtillvida du inte debuggar ett nytt nätverksprotokoll. Så " -#~ "länge\n" -#~ " Portalen kör så kommer inte spelare att förlora kontakten med\n" -#~ " spelet. Bara en instans av Portalen kan starts p¨ en gång, " -#~ "ytterligare\n" -#~ " instanser kommer att ignoreras\n" -#~ "Server - Spelservern själv. Denna kan ofta behöva starts om medan\n" -#~ " du utvecklar ditt spel. Portalen kommer att automatiskt ansluta\n" -#~ " till Servern så fort denna startar. Servern startar också " -#~ "automatiskt\n" -#~ " om så fort den stängs ner (innfrån spelet eller via " -#~ "operativsystemet).\n" -#~ " Bara en instans av Server kan vara igång samtidigt. \n" -#~ "\n" -#~ "När servern är öppen för allmänheten är det lämpligt att använda val (1)\n" -#~ "som innebär att så mycket som möjligt jörs i bakgrunden.\n" -#~ " När man utvecklar sitt spel är det dock bekvämt att direkt se " -#~ "felmeddanden\n" -#~ "i terminalen. För detta är val 2-4 bra val. Starta om servern när ny kod " -#~ "är\n" -#~ "på plats genom att använda val (5).\n" -#~ "\n" -#~ "Omstart och stopp fungerar inte så bra i Windows. Om du har problem, \n" -#~ "loggin in i spelet och starta om innifrån istället.\n" - -#~ msgid "" -#~ "\n" -#~ "+---------------------------------------------------------------------------" -#~ "+\n" -#~ "| " -#~ "|\n" -#~ "| Welcome to the Evennia " -#~ "launcher! |\n" -#~ "| " -#~ "|\n" -#~ "| Pick an option below. Use 'h' to get " -#~ "help. |\n" -#~ "| " -#~ "|\n" -#~ "+--- Starting (will not restart already running processes) " -#~ "-----------------+\n" -#~ "| " -#~ "|\n" -#~ "| 1) (default): Start Server and Portal. Portal starts in daemon " -#~ "mode.|\n" -#~ "| All output is to " -#~ "logfiles. |\n" -#~ "| 2) (game debug): Start Server and Portal. Portal starts in daemon " -#~ "mode.|\n" -#~ "| Server outputs to stdout instead of " -#~ "logfile. |\n" -#~ "| 3) (portal debug): Start Server and Portal. Portal starts in non-" -#~ "daemon |\n" -#~ "| mode (can be reloaded) and logs to " -#~ "stdout. |\n" -#~ "| 4) (full debug): Start Server and Portal. Portal starts in non-" -#~ "daemon |\n" -#~ "| mode (can be reloaded). Both log to " -#~ "stdout. |\n" -#~ "| " -#~ "|\n" -#~ "+--- Restarting (must first be started) " -#~ "------------------------------------+\n" -#~ "| " -#~ "|\n" -#~ "| 5) Reload the " -#~ "Server |\n" -#~ "| 6) Reload the Portal (only works in non-daemon mode. If " -#~ "running |\n" -#~ "| in daemon mode, Portal needs to be restarted manually (option " -#~ "1-4)) |\n" -#~ "| " -#~ "|\n" -#~ "+--- Stopping (must first be started) " -#~ "--------------------------------------+\n" -#~ "| " -#~ "|\n" -#~ "| 7) Stopping both Portal and Server. Server will not " -#~ "restart. |\n" -#~ "| 8) Stopping only Server. Server will not " -#~ "restart. |\n" -#~ "| 9) Stopping only " -#~ "Portal. |\n" -#~ "| " -#~ "|\n" -#~ "+---------------------------------------------------------------------------" -#~ "+\n" -#~ "| h) " -#~ "Help |\n" -#~ "| q) " -#~ "Quit |\n" -#~ "+---------------------------------------------------------------------------" -#~ "+\n" -#~ msgstr "" -#~ "\n" -#~ "+---------------------------------------------------------------------------" -#~ "+\n" -#~ "| " -#~ "|\n" -#~ "| Välkommen till " -#~ "Evennia! |\n" -#~ "| " -#~ "|\n" -#~ "| Välj nedan. Ge '-h' för att få " -#~ "hjälp. |\n" -#~ "| " -#~ "|\n" -#~ "+--- Starta (kommer inte att starta om existerande processer)-------------" -#~ "+\n" -#~ "| " -#~ "|\n" -#~ "| 1) (förvalt): Start Server och Portal. Portalen startar som demon|" -#~ "n| Alla meddelanden till " -#~ "loggfiler |\n" -#~ "| 2) (spelutveckling): Starta Server och Portal. Portalen startar " -#~ "som .|\n" -#~ "| demon. Server meddelar till " -#~ "terminal. |\n" -#~ "| 3) (portal debug): StartaServer and Portal. Portal startar " -#~ "som |\n" -#~ "| icke-" -#~ "demon. |\n" -#~ "| 4) (full debug): StartaServer and Portal. Båda startar " -#~ "som |\n" -#~ "| icke-demon. Båda meddear till " -#~ "terminal. |\n" -#~ "| " -#~ "|\n" -#~ "+--- Starta om (måste först vara " -#~ "startad)-----------------------------------+\n" -#~ "| " -#~ "|\n" -#~ "| 5) Starta om " -#~ "Server |\n" -#~ "| 6) Starta om Portalen (funkar bara som icke-demon). Om man " -#~ "kör |\n" -#~ "| som demon så måste Portalen startas om manuellt (val " -#~ "1-4) |\n" -#~ "| " -#~ "|\n" -#~ "+--- Stopp (måste först vara startad) " -#~ "--------------------------------------+\n" -#~ "| " -#~ "|\n" -#~ "| 7) Stoppa både Portal och Server. Server startar inte " -#~ "om. |\n" -#~ "| 8) Stoppa bara Server. Server kommer inte att starta " -#~ "om. |\n" -#~ "| 9) Stoppa bara " -#~ "Portalen. |\n" -#~ "| " -#~ "|\n" -#~ "+---------------------------------------------------------------------------" -#~ "+\n" -#~ "| h) " -#~ "Hjälp |\n" -#~ "| q) " -#~ "Avsluta |\n" -#~ "+---------------------------------------------------------------------------" -#~ "+\n" - -#~ msgid " No settings.py file found. launching manage.py ..." -#~ msgstr " Filen \"settings.py\" hittades inte. Startar manage.py ..." - -#~ msgid "" -#~ "\n" -#~ " ... A new settings file was created. Edit this file to configure\n" -#~ " Evennia as desired by copy&pasting options from\n" -#~ " src/settings_default.py.\n" -#~ "\n" -#~ " You should then also create/configure the database using\n" -#~ "\n" -#~ " python manage.py syncdb\n" -#~ "\n" -#~ " Make sure to create a new admin user when prompted -- this will be\n" -#~ " user #1 in-game. If you use django-south, you'll see mentions of\n" -#~ " migrating things in the above run. You then also have to run\n" -#~ "\n" -#~ " python manage.py migrate\n" -#~ "\n" -#~ " If you use default sqlite3 database, you will find a file\n" -#~ " evennia.db appearing. This is the database file. Just delete this\n" -#~ " and repeat the above manage.py steps to start with a fresh\n" -#~ " database.\n" -#~ "\n" -#~ " When you are set up, run evennia.py again to start the server." -#~ msgstr "" -#~ "\n" -#~ " ... En ny settings-fil har skapats. Modifiera denna fil för att " -#~ "konfigurera\n" -#~ " Evennia som önskas genom att klippa och klistra från originalet i \n" -#~ " src/settings_default.py.\n" -#~ "\n" -#~ " Du bör sedan återskapa databasen med\n" -#~ "\n" -#~ " python manage.py syncdb\n" -#~ "\n" -#~ " Se till att skapa ett nytt admin-lösenord när så tillfrågas - detta " -#~ "används\n" -#~ " för användare #1 i spelet. Om nu använder django-south kommer du \n" -#~ " se ett omnämnande om migrationer efter de ovanstående kommandona.\n" -#~ " Du måste då köra: \n" -#~ " python manage.py migrate\n" -#~ "\n" -#~ " Om du använder sqlite3-databasen kommer du att hitta en fil\n" -#~ " evennia.db i game/. Detta är databas-filen. Radera denna fil \n" -#~ " och upprepa de ovannämnda stegen för att starta om med en \n" -#~ " ny, tom databas. \n" -#~ "\n" -#~ " När allt är klart, kör evennia.py igen rör att starta servern." - -#~ msgid "" -#~ "\n" -#~ " Your database does not seem to be set up correctly.\n" -#~ "\n" -#~ " Please run:\n" -#~ " \n" -#~ " python manage.py syncdb\n" -#~ "\n" -#~ " (make sure to create an admin user when prompted). If you use\n" -#~ " pyhon-south you will get mentions of migrating in the above\n" -#~ " run. You then need to also run\n" -#~ "\n" -#~ " python manage.py migrate\n" -#~ "\n" -#~ " When you have a database set up, rerun evennia.py.\n" -#~ " " -#~ msgstr "" -#~ "\n" -#~ " Din databas verkar inte korrekt konfigurerad.\n" -#~ "\n" -#~ " Vänligen kör:\n" -#~ " \n" -#~ " python manage.py syncdb\n" -#~ "\n" -#~ " (Se till att skapa ett administrationskonto när det tillfrågas.\n" -#~ " Om du använder pyhon-south kommer du att se omnämnande om \n" -#~ " Se till att då också köra\n" -#~ "\n" -#~ " python manage.py migrate\n" -#~ "\n" -#~ " När databasen fungeran, kör evennia.py igen.\n" -#~ " " - -#~ msgid "" -#~ "\n" -#~ " ERROR: Unable to import win32api, which Twisted requires to run.\n" -#~ " You may download it from:\n" -#~ "\n" -#~ " http://sourceforge.net/projects/pywin32\n" -#~ " or\n" -#~ " http://starship.python.net/crew/mhammond/win32/Downloads.html" -#~ msgstr "" -#~ "\n" -#~ " FEL: Kunde inte importera win32api. Twisted behöver detta. \n" -#~ " Ladda ner från:\n" -#~ "\n" -#~ " http://sourceforge.net/projects/pywin32\n" -#~ " eller\n" -#~ " http://starship.python.net/crew/mhammond/win32/Downloads.html" - -#~ msgid "" -#~ "\n" -#~ " INFO: Since you are running Windows, a file 'twistd.bat' was\n" -#~ " created for you. This is a simple batch file that tries to call\n" -#~ " the twisted executable. Evennia determined this to be:\n" -#~ "\n" -#~ " %{twistd_path}s\n" -#~ "\n" -#~ " If you run into errors at startup you might need to edit\n" -#~ " twistd.bat to point to the actual location of the Twisted\n" -#~ " executable (usually called twistd.py) on your machine.\n" -#~ "\n" -#~ " This procedure is only done once. Run evennia.py again when you\n" -#~ " are ready to start the server.\n" -#~ " " -#~ msgstr "" -#~ "\n" -#~ " INFO: Efersom du kör Windows har en fil 'twistd.bat' skapats\n" -#~ " Detta är en enkel batch-file som försöker anropa twisted:s\n" -#~ " exeutiva fil. Evennia bedömde att detta är:\n" -#~ "\n" -#~ " %{twistd_path}s\n" -#~ "\n" -#~ " Om du stöter på fel under starten så kanske du behöver \n" -#~ " modifiera twistd.dat så att den hittar Twisted:s binärfil (vanligen\n" -#~ " kallad twistd.py) just på din dator.\n" -#~ "\n" -#~ " Denna procedur behöver bara göras en gång. Kör evennia.py\n" -#~ " igen när du är redo att starta servern.\n" -#~ " " - -#~ msgid "Windows requires Python 2.7 or higher for this operation." -#~ msgstr "Windows kräver Python 2.7 för att utföra detta. " - -#~ msgid "" -#~ "Process %(pid)s could not be signalled. The PID file '%(pidfile)s' seems " -#~ "stale. Try removing it." -#~ msgstr "" -#~ "Processen %(pid)s kunde inte signaleras. PID-filen '%(pidfile)s' verkar " -#~ "vara ur synk. Ta bort den manuellt." - -#~ msgid " option > " -#~ msgstr "val >" - -#~ msgid "press to continue ..." -#~ msgstr "tryck för att fortsätta ..." - -#~ msgid "Not a valid option." -#~ msgstr "Inte ett lämpligt val." - -#~ msgid "The %s does not seem to be running." -#~ msgstr "%s verkar inte köra. " - -#~ msgid "" -#~ "This operation is not supported under Windows. Log into the game to " -#~ "restart/reload the server." -#~ msgstr "Detta stöds inte under Windows. Logga in för att starta om servern." - -#~ msgid "Server reloaded." -#~ msgstr "Servern startades om." - -#~ msgid "This operation is not supported under Windows." -#~ msgstr "Detta stöds inte under Windows." - -#~ msgid "Portal reloaded (or stopped if in daemon mode)." -#~ msgstr "Portalen startades om (eller stoppades, om den körde some demon)" - -#~ msgid "Stopped Portal." -#~ msgstr "Stoppade Portalen." - -#~ msgid "Stopped Server." -#~ msgstr "Stoppade Portalen." - -#~ msgid "" -#~ "Restarting from command line is not supported under Windows. Log into the " -#~ "game to restart." -#~ msgstr "" -#~ "Att starta om från kommandoraden stöds inte under Windows. Logga in för " -#~ "att starta om. " - -#~ msgid "" -#~ "Note: Portal usually don't need to be reloaded unless you are debugging " -#~ "in interactive mode." -#~ msgstr "" -#~ "Obs: Portalen behöver oftast inte startas om såtillvida man inte håller " -#~ "på att debugga portalen. " - -#~ msgid "" -#~ "If Portal was running in default Daemon mode, it cannot be restarted. In " -#~ "that case you have " -#~ msgstr "" -#~ "Om Portalen kördes som en demon så kan den inte startas om. I såfall " -#~ "måste du" - -#~ msgid "to restart it manually with 'evennia.py start portal'" -#~ msgstr "starta om den manuellt med 'evennia.py start portal'" - -#~ msgid "Portal reloaded (or stopped, if it was in daemon mode)." -#~ msgstr "Portalen startades om (eller stoppades om den kördes som demon)" - -#~ msgid "Server reload." -#~ msgstr "Serven laddades om." - -#~ msgid "Server stopped." -#~ msgstr "Servern stoppades." - -#~ msgid "Portal stopped." -#~ msgstr "Portalen stoppades." - -#~ msgid "" -#~ "This is the main Evennia launcher. It handles the Portal and Server, the " -#~ "two services making up Evennia. Default is to operate on both services. " -#~ "Use --interactive together with start to launch services as " -#~ "'interactive'. Note that when launching 'all' services with the --" -#~ "interactive flag, both services will be started, but only Server will " -#~ "actually be started in interactive mode. This is simply because this is " -#~ "the most commonly useful state. To activate interactive mode also for " -#~ "Portal, launch the two services explicitly as two separate calls to this " -#~ "program. You can also use the menu." -#~ msgstr "" -#~ "Detta är Evennias huvudprogram. Det hanterar Portalen och Servern, de två " -#~ "program so utgör Evennia. Normal verkar alla kommandon på båda " -#~ "programmen. Använd --interactive tillsammans med start för att starta " -#~ "interaktiva lägen. Notera att normalt startar bara Servern i interaktivt " -#~ "läge eftersom detta är det oftast använda läget. För att aktivera " -#~ "interaktivt läge även för Portalen så måste man starta programmen var för " -#~ "sig. Man kan också använde menyn. " - -#~ msgid "" -#~ "Start given processes in interactive mode (log to stdout, don't start as " -#~ "a daemon)." -#~ msgstr "" -#~ "Starta den angivna processen i interaktivt läge (alla meddelanden till " -#~ "terminalen, starta inte som demon)" - -#~ msgid "mode should be none or one of 'menu', 'start', 'reload' or 'stop'." -#~ msgstr "" -#~ "'mode' (om den anges) måste antingen vara 'menu', 'start', 'reload' eller " -#~ "'stop'." - -#~ msgid "service should be none or 'server', 'portal' or 'all'." -#~ msgstr "" -#~ "'service' (om den anges) måste antingen vara 'server', 'portal' eller " -#~ "'all'." - -#~ msgid "No settings.py file found. Run evennia.py to create it." -#~ msgstr "" -#~ "Ingen settings.py-fil kunde hittas. Kör evennia.py för att skapa den. " - -#~ msgid "" -#~ "Twisted binary for Windows is not ready to use. Please run evennia.py." -#~ msgstr "" -#~ "Twisted:s Windows-binärfil är inte klar att användas. Vänligen kör " -#~ "evennia.py först. " - -#~ msgid "Server process error: %(e)s" -#~ msgstr "Server: Process-fel: %(e)s" - -#~ msgid "Portal process error: %(e)s" -#~ msgstr "Portal: Process-fel: %(e)s" - -#~ msgid "Evennia Server stopped. Restarting ..." -#~ msgstr "Evennia:s Serverprocess stoppades. Startar om ..." - -#~ msgid "Evennia Portal stopped in interactive mode. Restarting ..." -#~ msgstr "" -#~ "Evennia:s Portal-process stoppades i interaktivt läge. Startar om ..." - -#~ msgid "" -#~ "This runner should normally *not* be called directly - it is called " -#~ "automatically from the evennia.py main program. It manages the Evennia " -#~ "game server and portal processes an hosts a threaded loop to restart the " -#~ "Server whenever it is stopped (this constitues Evennia's reload " -#~ "mechanism)." -#~ msgstr "" -#~ "Detta program bör normalt *inte* anropas direkt - det startas automatiskt " -#~ "från evennia.py. Programmet styr Evennia:s Server- och Portal-processer " -#~ "med hj'lp av en trådbaserad loop som gör att Servern kan startas om. " - -#~ msgid "Do not start Server process" -#~ msgstr "Starta inte Server-processen." - -#~ msgid "Do not start Portal process" -#~ msgstr "Starta inte Portal-processen" - -#~ msgid "output server log to stdout instead of logfile" -#~ msgstr "Avge Server-data till stdout istället för till en logfil" - -#~ msgid "output portal log to stdout. Does not make portal a daemon." -#~ msgstr "Avge Portal-data till stdout. Starta inte som demon." - -#~ msgid "" -#~ "\n" -#~ "Evennia Server is already running as process %(pid)s. Not restarted." -#~ msgstr "" -#~ "\n" -#~ " Evennias Server-process kör redan som %(pid)s. Behöver inte startas. " - -#~ msgid "" -#~ "\n" -#~ "Starting Evennia Server (output to stdout)." -#~ msgstr "" -#~ "\n" -#~ "Startar Evennias Server-process (meddelanden till terminalen)." - -#~ msgid "" -#~ "\n" -#~ "Starting Evennia Server (output to server logfile)." -#~ msgstr "" -#~ "\n" -#~ "Startar Evennias Server (meddelanden till logfil)." - -#~ msgid "" -#~ "\n" -#~ "Evennia Portal is already running as process %(pid)s. Not restarted." -#~ msgstr "" -#~ "\n" -#~ "Evennias portal kör redan som %(pid)s. Behöver inte startas." - -#~ msgid "" -#~ "\n" -#~ "Starting Evennia Portal in non-Daemon mode (output to stdout)." -#~ msgstr "" -#~ "\n" -#~ "Startar Evennias Portal-process som icke-demon (meddelanden till " -#~ "terminalen)" - -#~ msgid "" -#~ "\n" -#~ "Starting Evennia Portal in Daemon mode (output to portal logfile)." -#~ msgstr "" -#~ "\n" -#~ "Startar Evennias Portal-process som en demon (meddelanden till logfil)." diff --git a/src/commands/cmdhandler.py b/src/commands/cmdhandler.py index aaebe95312..dd5f8f95f6 100644 --- a/src/commands/cmdhandler.py +++ b/src/commands/cmdhandler.py @@ -45,6 +45,8 @@ from src.commands.cmdset import CmdSet from src.commands.cmdparser import at_multimatch_cmd from src.utils.utils import string_suggestions +from django.utils.translation import ugettext as _ + __all__ = ("cmdhandler",) # This decides which command parser is to be used. @@ -196,18 +198,18 @@ def cmdhandler(caller, raw_string, testing=False): if syscmd: sysarg = raw_string else: - sysarg = "Command '%s' is not available." % raw_string + sysarg = _("Command '%s' is not available.") % raw_string suggestions = string_suggestions(raw_string, cmdset.get_all_cmd_keys_and_aliases(caller), cutoff=0.7, maxnum=3) if suggestions: - sysarg += " Maybe you meant %s?" % utils.list_to_string(suggestions, 'or', addquote=True) + sysarg += _(" Maybe you meant %s?") % utils.list_to_string(suggestions, _('or'), addquote=True) else: - sysarg += " Type \"help\" for help." + sysarg += _(" Type \"help\" for help.") raise ExecSystemCommand(syscmd, sysarg) if len(matches) > 1: # We have a multiple-match syscmd = yield cmdset.get(CMD_MULTIMATCH) - sysarg = "There where multiple matches." + sysarg = _("There where multiple matches.") if syscmd: syscmd.matches = matches else: @@ -301,19 +303,19 @@ def cmdhandler(caller, raw_string, testing=False): string += "If logging out/in doesn't solve the problem, try to " string += "contact the server admin through some other means " string += "for assistance." - caller.msg(string) + caller.msg(_(string)) logger.log_errmsg("No cmdsets found: %s" % caller) except Exception: # We should not end up here. If we do, it's a programming bug. string = "%s\nAbove traceback is from an untrapped error." string += " Please file a bug report." - logger.log_trace(string) + logger.log_trace(_(string)) caller.msg(string % format_exc()) except Exception: # This catches exceptions in cmdhandler exceptions themselves string = "%s\nAbove traceback is from a Command handler bug." string += " Please contact an admin and/or file a bug report." - logger.log_trace(string) + logger.log_trace(_(string)) caller.msg(string % format_exc()) diff --git a/src/commands/cmdparser.py b/src/commands/cmdparser.py index 0d97ce283f..2a7cd7659d 100644 --- a/src/commands/cmdparser.py +++ b/src/commands/cmdparser.py @@ -6,6 +6,7 @@ return a CommandCandidates object. """ from src.utils.logger import log_trace +from django.utils.translation import ugettext as _ def cmdparser(raw_string, cmdset, caller, match_index=None): """ @@ -140,7 +141,7 @@ def at_search_result(msg_obj, ostring, results, global_search=False): string = "" if not results: # no results. - string = "Could not find '%s'." % ostring + string = _("Could not find '%s'." % ostring) results = None elif len(results) > 1: @@ -152,11 +153,12 @@ def at_search_result(msg_obj, ostring, results, global_search=False): string += "More than one match for '%s'" % ostring string += " (please narrow target):" + string = _(string) for num, result in enumerate(results): invtext = "" dbreftext = "" - if hasattr(result, "location") and result.location == msg_obj: - invtext = " (carried)" + if hasattr(result, _("location")) and result.location == msg_obj: + invtext = _(" (carried)") if show_dbref: dbreftext = "(#%i)" % result.dbid string += "\n %i-%s%s%s" % (num+1, result.name, @@ -235,11 +237,11 @@ def at_multimatch_cmd(caller, matches): is_channel = hasattr(cmd, "is_channel") and cmd.is_channel if is_channel: - is_channel = " (channel)" + is_channel = _(" (channel)") else: is_channel = "" if cmd.is_exit and cmd.destination: - is_exit = " (exit to %s)" % cmd.destination + is_exit = _(" (exit to %s)") % cmd.destination else: is_exit = "" diff --git a/src/commands/cmdset.py b/src/commands/cmdset.py index 614315d93d..a6da8e0be4 100644 --- a/src/commands/cmdset.py +++ b/src/commands/cmdset.py @@ -15,6 +15,7 @@ together to create interesting in-game effects. """ import copy +from django.utils.translation import ugettext as _ from src.utils.utils import inherits_from, is_iter __all__ = ("CmdSet",) @@ -303,9 +304,9 @@ class CmdSet(object): try: cmd = self._instantiate(cmd) except RuntimeError, e: - string = "Adding cmdset %s to %s lead to an infinite loop. When adding a cmdset to another, " + string = "Adding cmdset %(cmd)s to %(class)s lead to an infinite loop. When adding a cmdset to another, " string += "make sure they are not themself cyclically added to the new cmdset somewhere in the chain." - raise RuntimeError(string % (cmd, self.__class__)) + raise RuntimeError(_(string) % {"cmd":cmd, "class":self.__class__}) cmds = cmd.commands elif is_iter(cmd): cmds = [self._instantiate(c) for c in cmd] diff --git a/src/commands/cmdsethandler.py b/src/commands/cmdsethandler.py index 6f58e3021f..8608b6bdd4 100644 --- a/src/commands/cmdsethandler.py +++ b/src/commands/cmdsethandler.py @@ -67,6 +67,8 @@ import traceback from src.utils import logger, utils from src.commands.cmdset import CmdSet from src.server.models import ServerConfig + +from django.utils.translation import ugettext as _ __all__ = ("import_cmdset", "CmdSetHandler") _CACHED_CMDSETS = {} @@ -110,15 +112,15 @@ def import_cmdset(python_path, cmdsetobj, emit_to_obj=None, no_logging=False): return cmdsetclass except ImportError: - errstring = "Error loading cmdset: Couldn't import module '%s'." + errstring = _("Error loading cmdset: Couldn't import module '%s'.") errstring = errstring % modulepath raise except KeyError: - errstring = "Error in loading cmdset: No cmdset class '%s' in %s." - errstring = errstring % (classname, modulepath) + errstring = _("Error in loading cmdset: No cmdset class '%(classname)s' in %(modulepath)s.") + errstring = errstring % {"classname":classname, "modulepath":modulepath} raise except Exception: - errstring = "Compile/Run error when loading cmdset '%s'. Error was logged." + errstring = _("Compile/Run error when loading cmdset '%s'. Error was logged.") errstring = errstring % (python_path) raise except Exception: @@ -194,15 +196,17 @@ class CmdSetHandler(object): mergetype = self.mergetype_stack[-1] if mergetype != self.current.mergetype: merged_on = self.cmdset_stack[-2].key - mergetype = "custom %s on cmdset '%s'" % (mergetype, merged_on) + mergetype = _("custom %(mergetype)s on cmdset '%(merged_on)s'") % {"mergetype":mergetype, "merged_on":merged_on} if mergelist: - string += " : %s" % ("+".join(mergelist), mergetype, self.current.priority, self.current) + string += _(" : %(current)s") % \ + {"mergelist": "+".join(mergelist), "mergetype":mergetype, "prio":self.current.priority, "current":self.current} else: permstring = "non-perm" if self.current.permanent: permstring = "perm" - string += " <%s (%s, prio %i, %s)>: %s" % (self.current.key, mergetype, self.current.priority, permstring, - ", ".join(cmd.key for cmd in sorted(self.current, key=lambda o:o.key))) + string += _(" <%(key)s (%(mergetype)s, prio %(prio)i, %(permstring)s)>: %(keylist)s") % \ + {"key":self.current.key, "mergetype":mergetype, "prio":self.current.priority, "permstring":permstring, + "keylost":", ".join(cmd.key for cmd in sorted(self.current, key=lambda o:o.key))} return string.strip() def _import_cmdset(self, cmdset_path, emit_to_obj=None): @@ -274,7 +278,7 @@ class CmdSetHandler(object): """ if callable(cmdset): if not utils.inherits_from(cmdset, CmdSet): - raise Exception("Only CmdSets can be added to the cmdsethandler!") + raise Exception(_("Only CmdSets can be added to the cmdsethandler!")) cmdset = cmdset(self.obj) elif isinstance(cmdset, basestring): # this is (maybe) a python path. Try to import from cache. @@ -306,7 +310,7 @@ class CmdSetHandler(object): """ if callable(cmdset): if not utils.inherits_from(cmdset, CmdSet): - raise Exception("Only CmdSets can be added to the cmdsethandler!") + raise Exception(_("Only CmdSets can be added to the cmdsethandler!")) cmdset = cmdset(self.obj) elif isinstance(cmdset, basestring): # this is (maybe) a python path. Try to import from cache. diff --git a/src/comms/admin.py b/src/comms/admin.py index 4ce9886978..e207fb2660 100644 --- a/src/comms/admin.py +++ b/src/comms/admin.py @@ -1,20 +1,20 @@ # -# This sets up how models are displayed -# in the web admin interface. +# This sets up how models are displayed +# in the web admin interface. # from django.contrib import admin from src.comms.models import Channel, Msg, PlayerChannelConnection, ExternalChannelConnection -class MsgAdmin(admin.ModelAdmin): - list_display = ('id', 'db_date_sent', 'db_sender', 'db_receivers', 'db_channels', 'db_message', 'db_lock_storage') +class MsgAdmin(admin.ModelAdmin): + list_display = ('id', 'db_date_sent', 'db_sender', 'db_receivers', 'db_channels', 'db_message', 'db_lock_storage') list_display_links = ("id",) ordering = ["db_date_sent", 'db_sender', 'db_receivers', 'db_channels'] #readonly_fields = ['db_message', 'db_sender', 'db_receivers', 'db_channels'] search_fields = ['id', '^db_date_sent', '^db_message'] - save_as = True - save_on_top = True - list_select_related = True + save_as = True + save_on_top = True + list_select_related = True #admin.site.register(Msg, MsgAdmin) class PlayerChannelConnectionInline(admin.TabularInline): @@ -41,12 +41,12 @@ class ChannelAdmin(admin.ModelAdmin): list_display_links = ("id", 'db_key') ordering = ["db_key"] search_fields = ['id', 'db_key', 'db_aliases'] - save_as = True - save_on_top = True - list_select_related = True + save_as = True + save_on_top = True + list_select_related = True fieldsets = ( (None, {'fields':(('db_key', 'db_aliases', 'db_desc'),'db_lock_storage', 'db_keep_log')}), - ) + ) admin.site.register(Channel, ChannelAdmin) @@ -55,9 +55,9 @@ admin.site.register(Channel, ChannelAdmin) # list_display_links = ("db_player", 'db_channel') # ordering = ["db_channel"] # search_fields = ['db_channel', 'db_player'] -# save_as = True -# save_on_top = True -# list_select_related = True +# save_as = True +# save_on_top = True +# list_select_related = True # admin.site.register(PlayerChannelConnection, PlayerChannelConnectionAdmin) # class ExternalChannelConnectionAdmin(admin.ModelAdmin): @@ -65,8 +65,8 @@ admin.site.register(Channel, ChannelAdmin) # list_display_links = ("db_channel", 'db_external_key', 'db_external_config') # ordering = ["db_channel"] # search_fields = ['db_channel', 'db_external_key'] -# save_as = True -# save_on_top = True -# list_select_related = True +# save_as = True +# save_on_top = True +# list_select_related = True # admin.site.register(ExternalChannelConnection, ExternalChannelConnectionAdmin) diff --git a/src/comms/imc2.py b/src/comms/imc2.py index 1b46b62731..1f04c0502e 100644 --- a/src/comms/imc2.py +++ b/src/comms/imc2.py @@ -16,6 +16,8 @@ from src.comms.imc2lib import imc2_packets as pck from src.comms.imc2lib.imc2_trackers import IMC2MudList, IMC2ChanList from src.comms.imc2lib.imc2_listeners import handle_whois_reply +from django.utils.translation import ugettext as _ + # IMC2 network setup IMC2_MUDNAME = settings.SERVERNAME IMC2_NETWORK = settings.IMC2_NETWORK @@ -26,8 +28,8 @@ IMC2_SERVER_PWD = settings.IMC2_SERVER_PWD # channel to send info to INFOCHANNEL = Channel.objects.channel_search(settings.CHANNEL_MUDINFO[0]) # all linked channel connections -IMC2_CLIENT = None -# IMC2 debug mode +IMC2_CLIENT = None +# IMC2 debug mode IMC2_DEBUG = False # Use this instance to keep track of the other games on the network. IMC2_MUDLIST = IMC2MudList() @@ -41,7 +43,7 @@ IMC2_CHANLIST = IMC2ChanList() def msg_info(message): """ Send info to default info channel - """ + """ try: INFOCHANNEL[0].msg(message) message = '[%s][IMC2]: %s' % (INFOCHANNEL[0].key, message) @@ -49,7 +51,7 @@ def msg_info(message): logger.log_infomsg("MUDinfo (imc2): %s" % message) # -# Regular scripts +# Regular scripts # class Send_IsAlive(Script): @@ -61,8 +63,8 @@ class Send_IsAlive(Script): def at_script_creation(self): self.key = 'IMC2_Send_IsAlive' self.interval = 900 - self.desc = "Send an IMC2 is-alive packet" - self.persistent = True + self.desc = _("Send an IMC2 is-alive packet") + self.persistent = True def at_repeat(self): IMC2_CLIENT.send_packet(pck.IMC2PacketIsAlive()) def is_valid(self): @@ -77,9 +79,9 @@ class Send_Keepalive_Request(Script): def at_script_creation(self): self.key = "IMC2_Send_Keepalive_Request" self.interval = 3500 - self.desc = "Send an IMC2 keepalive-request packet" - self.persistent = True - def at_repeat(self): + self.desc = _("Send an IMC2 keepalive-request packet") + self.persistent = True + def at_repeat(self): IMC2_CLIENT.channel.send_packet(pck.IMC2PacketKeepAliveRequest()) def is_valid(self): "Is only valid as long as there are channels to update" @@ -94,8 +96,8 @@ class Prune_Inactive_Muds(Script): def at_script_creation(self): self.key = "IMC2_Prune_Inactive_Muds" self.interval = 1800 - self.desc = "Check IMC2 list for inactive games" - self.persistent = True + self.desc = _("Check IMC2 list for inactive games") + self.persistent = True self.inactive_threshold = 3599 def at_repeat(self): for name, mudinfo in IMC2_MUDLIST.mud_list.items(): @@ -104,7 +106,7 @@ class Prune_Inactive_Muds(Script): def is_valid(self): "Is only valid as long as there are channels to update" return any(service for service in SESSIONS.server.services if service.name.startswith("imc2_")) - + class Sync_Server_Channel_List(Script): """ Re-syncs the network's channel list. This will @@ -114,11 +116,11 @@ class Sync_Server_Channel_List(Script): """ def at_script_creation(self): self.key = "IMC2_Sync_Server_Channel_List" - self.interval = 24 * 3600 # once every day - self.desc = "Re-sync IMC2 network channel list" - self.persistent = True + self.interval = 24 * 3600 # once every day + self.desc = _("Re-sync IMC2 network channel list") + self.persistent = True def at_repeat(self): - checked_networks = [] + checked_networks = [] network = IMC2_CLIENT.factory.network if not network in checked_networks: channel.send_packet(pkg.IMC2PacketIceRefresh()) @@ -126,7 +128,7 @@ class Sync_Server_Channel_List(Script): def is_valid(self): return any(service for service in SESSIONS.server.services if service.name.startswith("imc2_")) # -# IMC2 protocol +# IMC2 protocol # class IMC2Protocol(telnet.StatefulTelnetProtocol): @@ -143,7 +145,7 @@ class IMC2Protocol(telnet.StatefulTelnetProtocol): self.network_name = None self.sequence = None - + def connectionMade(self): """ Triggered after connecting to the IMC2 network. @@ -153,19 +155,19 @@ class IMC2Protocol(telnet.StatefulTelnetProtocol): logger.log_infomsg("IMC2: Connected to network server.") logger.log_infomsg("IMC2: Sending authentication packet.") self.send_packet(pck.IMC2PacketAuthPlaintext()) - + def connectionLost(self, reason=None): """ - This is executed when the connection is lost for - whatever reason. + This is executed when the connection is lost for + whatever reason. """ try: service = SESSIONS.server.services.getServiceNamed("imc2_%s:%s(%s)" % (IMC2_NETWORK, IMC2_PORT, IMC2_MUDNAME)) except Exception: - return + return if service.running: service.stopService() - + def send_packet(self, packet): """ Given a sub-class of IMC2Packet, assemble the packet and send it @@ -182,14 +184,14 @@ class IMC2Protocol(telnet.StatefulTelnetProtocol): logger.log_infomsg("IMC2: SENT> %s" % packet_str) logger.log_infomsg(str(packet)) self.sendLine(packet_str) - + def _parse_auth_response(self, line): """ Parses the IMC2 network authentication packet. """ if self.auth_type == "plaintext": - # Plain text passwords. - # SERVER Sends: PW version= + # Plain text passwords. + # SERVER Sends: PW version= if IMC2_DEBUG: logger.log_infomsg("IMC2: AUTH< %s" % line) @@ -199,26 +201,26 @@ class IMC2Protocol(telnet.StatefulTelnetProtocol): autosetup_present = line_split[0] == 'autosetup' if "reject" in line_split: - auth_message = "IMC2 server rejected connection." + auth_message = _("IMC2 server rejected connection.") logger.log_infomsg(auth_message) msg_info(auth_message) - return - + return + if pw_present: self.server_name = line_split[1] self.network_name = line_split[4] elif autosetup_present: - logger.log_infomsg("IMC2: Autosetup response found.") + logger.log_infomsg(_("IMC2: Autosetup response found.")) self.server_name = line_split[1] - self.network_name = line_split[3] + self.network_name = line_split[3] self.is_authenticated = True self.sequence = int(time()) - + # Log to stdout and notify over MUDInfo. - auth_message = "Successfully authenticated to the '%s' network." % self.factory.network + auth_message = _("Successfully authenticated to the '%s' network.") % self.factory.network logger.log_infomsg('IMC2: %s' % auth_message) msg_info(auth_message) - + # Ask to see what other MUDs are connected. self.send_packet(pck.IMC2PacketKeepAliveRequest()) # IMC2 protocol states that KeepAliveRequests should be followed @@ -226,7 +228,7 @@ class IMC2Protocol(telnet.StatefulTelnetProtocol): self.send_packet(pck.IMC2PacketIsAlive()) # Get a listing of channels. self.send_packet(pck.IMC2PacketIceRefresh()) - + def _msg_evennia(self, packet): """ Handle the sending of packet data to Evennia channel @@ -235,34 +237,35 @@ class IMC2Protocol(telnet.StatefulTelnetProtocol): conn_name = packet.optional_data.get('channel', None) # If the packet lacks the 'echo' key, don't bother with it. - if not conn_name or not packet.optional_data.get('echo', None): - return + if not conn_name or not packet.optional_data.get('echo', None): + return imc2_channel = conn_name.split(':', 1)[1] # Look for matching IMC2 channel maps mapping to this imc2 channel. conns = ExternalChannelConnection.objects.filter(db_external_key__startswith="imc2_") conns = [conn for conn in conns if imc2_channel in conn.db_external_config.split(",")] if not conns: - # we are not listening to this imc2 channel. - return - + # we are not listening to this imc2 channel. + return + # Format the message to send to local channel(s). for conn in conns: - message = '[%s] %s@%s: %s' % (conn.channel.key, packet.sender, packet.origin, packet.optional_data.get('text')) + message = '[%s] %s@%s: %s' % (conn.channel.key, packet.sender, packet.origin, packet.optional_data.get('text')) conn.to_channel(message) - + def _format_tell(self, packet): """ - Handle tells over IMC2 by formatting the text properly + Handle tells over IMC2 by formatting the text properly """ - return "{c%s@%s{n {wpages (over IMC):{n %s" % (packet.sender, packet.origin, - packet.optional_data.get('text', 'ERROR: No text provided.')) + return _("{c%(sender)s@%(origin)s{n {wpages (over IMC):{n %(msg)s") % {"sender":packet.sender, + "origin":packet.origin, + "msg":packet.optional_data.get('text', 'ERROR: No text provided.')} def lineReceived(self, line): """ Triggered when text is received from the IMC2 network. Figures out what to do with the packet. - IMC2 -> Evennia + IMC2 -> Evennia """ line = line.strip() @@ -271,18 +274,18 @@ class IMC2Protocol(telnet.StatefulTelnetProtocol): else: if IMC2_DEBUG and not 'is-alive' in line: # if IMC2_DEBUG mode is on, print the contents of the packet - # to stdout. + # to stdout. logger.log_infomsg("IMC2: RECV> %s" % line) - + # Parse the packet and encapsulate it for easy access packet = pck.IMC2Packet(self.factory.mudname, packet_str=line) - + if IMC2_DEBUG and packet.packet_type not in ('is-alive', 'keepalive-request'): # Print the parsed packet's __str__ representation. # is-alive and keepalive-requests happen pretty frequently. # Don't bore us with them in stdout. logger.log_infomsg(str(packet)) - + # Figure out what kind of packet we're dealing with and hand it # off to the correct handler. @@ -305,9 +308,9 @@ class IMC2Protocol(telnet.StatefulTelnetProtocol): elif packet.packet_type == 'tell': player = search.players(packet.target) if not player: - return + return player[0].msg(self._format_tell(packet)) - + def msg_imc2(self, message, from_obj=None, packet_type="imcbroadcast", data=None): """ Called by Evennia to send a message through the imc2 connection @@ -319,33 +322,33 @@ class IMC2Protocol(telnet.StatefulTelnetProtocol): from_name = from_obj else: from_name = self.factory.mudname - + if packet_type == "imcbroadcast": - if type(data) == dict: - conns = ExternalChannelConnection.objects.filter(db_external_key__startswith="imc2_", - db_channel=data.get("channel", "Unknown")) + if type(data) == dict: + conns = ExternalChannelConnection.objects.filter(db_external_key__startswith="imc2_", + db_channel=data.get("channel", "Unknown")) if not conns: return # we remove the extra channel info since imc2 supplies this anyway if ":" in message: header, message = [part.strip() for part in message.split(":", 1)] - # send the packet + # send the packet imc2_channel = conns[0].db_external_config.split(',')[0] # only send to the first channel self.send_packet(pck.IMC2PacketIceMsgBroadcasted(self.factory.servername, imc2_channel, from_name, message)) elif packet_type == "imctell": - # send a tell + # send a tell if type(data) == dict: target = data.get("target", "Unknown") destination = data.get("destination", "Unknown") self.send_packet(pck.IMC2PacketTell(from_name, target, destination, message)) - + elif packet_type == "imcwhois": - # send a whois request + # send a whois request if type(data) == dict: target = data.get("target", "Unknown") self.send_packet(pck.IMC2PacketWhois(from_obj.id, target)) - + class IMC2Factory(protocol.ClientFactory): """ Creates instances of the IMC2Protocol. Should really only ever @@ -353,24 +356,24 @@ class IMC2Factory(protocol.ClientFactory): """ protocol = IMC2Protocol - def __init__(self, network, port, mudname, client_pwd, server_pwd): + def __init__(self, network, port, mudname, client_pwd, server_pwd): self.pretty_key = "%s:%s(%s)" % (network, port, mudname) self.network = network sname, host = network.split(".", 1) self.servername = sname.strip() - self.port = port + self.port = port self.mudname = mudname self.protocol_version = '2' self.client_pwd = client_pwd - self.server_pwd = server_pwd + self.server_pwd = server_pwd - def clientConnectionFailed(self, connector, reason): - message = 'Connection failed: %s' % reason.getErrorMessage() + def clientConnectionFailed(self, connector, reason): + message = _('Connection failed: %s') % reason.getErrorMessage() msg_info(message) logger.log_errmsg('IMC2: %s' % message) def clientConnectionLost(self, connector, reason): - message = 'Connection lost: %s' % reason.getErrorMessage() + message = _('Connection lost: %s') % reason.getErrorMessage() msg_info(message) logger.log_errmsg('IMC2: %s' % message) @@ -386,10 +389,10 @@ def start_scripts(validate=False): Start all the needed scripts """ - if validate: + if validate: from src.scripts.models import ScriptDB ScriptDB.objects.validate() - return + return if not search.scripts("IMC2_Send_IsAlive"): create.create_script(Send_IsAlive) if not search.scripts("IMC2_Send_Keepalive_Request"): @@ -397,7 +400,7 @@ def start_scripts(validate=False): if not search.scripts("IMC2_Prune_Inactive_Muds"): create.create_script(Prune_Inactive_Muds) if not search.scripts("IMC2_Sync_Server_Channel_List"): - create.create_script(Sync_Server_Channel_List) + create.create_script(Sync_Server_Channel_List) def create_connection(channel, imc2_channel): """ @@ -407,61 +410,61 @@ def create_connection(channel, imc2_channel): if not type(channel) == Channel: new_channel = Channel.objects.filter(db_key=channel) if not new_channel: - logger.log_errmsg("Cannot attach IMC2<->Evennia: Evennia Channel '%s' not found" % channel) + logger.log_errmsg(_("Cannot attach IMC2<->Evennia: Evennia Channel '%s' not found") % channel) return False channel = new_channel[0] key = build_connection_key(channel, imc2_channel) old_conns = ExternalChannelConnection.objects.filter(db_external_key=key) if old_conns: - # this evennia channel is already connected to imc. Check if imc2_channel is different. + # this evennia channel is already connected to imc. Check if imc2_channel is different. # connection already exists. We try to only connect a new channel - old_config = old_conns[0].db_external_config.split(",") + old_config = old_conns[0].db_external_config.split(",") if imc2_channel in old_config: return False # we already listen to this channel else: # We add a new imc2_channel to listen to old_config.append(imc2_channel) old_conns[0].db_external_config = ",".join(old_config) - old_conns[0].save() + old_conns[0].save() return True else: # no old connection found; create a new one. config = imc2_channel - # how the evennia channel will be able to contact this protocol in reverse + # how the evennia channel will be able to contact this protocol in reverse send_code = "from src.comms.imc2 import IMC2_CLIENT\n" send_code += "data={'channel':from_channel}\n" send_code += "IMC2_CLIENT.msg_imc2(message, from_obj=from_obj, data=data)\n" - conn = ExternalChannelConnection(db_channel=channel, db_external_key=key, db_external_send_code=send_code, - db_external_config=config) - conn.save() - return True + conn = ExternalChannelConnection(db_channel=channel, db_external_key=key, db_external_send_code=send_code, + db_external_config=config) + conn.save() + return True def delete_connection(channel, imc2_channel): "Destroy a connection" if hasattr(channel, "key"): channel = channel.key key = build_connection_key(channel, imc2_channel) - + try: conn = ExternalChannelConnection.objects.get(db_external_key=key) except ExternalChannelConnection.DoesNotExist: - return False - conn.delete() - return True + return False + conn.delete() + return True def connect_to_imc2(): - "Create the imc instance and connect to the IMC2 network." + "Create the imc instance and connect to the IMC2 network." - # connect - imc = internet.TCPClient(IMC2_NETWORK, int(IMC2_PORT), IMC2Factory(IMC2_NETWORK, IMC2_PORT, IMC2_MUDNAME, + # connect + imc = internet.TCPClient(IMC2_NETWORK, int(IMC2_PORT), IMC2Factory(IMC2_NETWORK, IMC2_PORT, IMC2_MUDNAME, IMC2_CLIENT_PWD, IMC2_SERVER_PWD)) - imc.setName("imc2_%s:%s(%s)" % (IMC2_NETWORK, IMC2_PORT, IMC2_MUDNAME)) + imc.setName("imc2_%s:%s(%s)" % (IMC2_NETWORK, IMC2_PORT, IMC2_MUDNAME)) SESSIONS.server.services.addService(imc) def connect_all(): """ - Activates the imc2 system. Called by the server if IMC2_ENABLED=True. + Activates the imc2 system. Called by the server if IMC2_ENABLED=True. """ connect_to_imc2() start_scripts() diff --git a/src/comms/imc2lib/imc2_ansi.py b/src/comms/imc2lib/imc2_ansi.py index d561e9329d..25fe055bea 100644 --- a/src/comms/imc2lib/imc2_ansi.py +++ b/src/comms/imc2lib/imc2_ansi.py @@ -1,6 +1,6 @@ """ ANSI parser - this adds colour to text according to -special markup strings. +special markup strings. This is a IMC2 complacent version. """ @@ -14,9 +14,9 @@ class IMCANSIParser(ansi.ANSIParser): """ def __init__(self): normal = ansi.ANSI_NORMAL - hilite = ansi.ANSI_HILITE + hilite = ansi.ANSI_HILITE self.ansi_map = [ - (r'~Z', normal), # Random + (r'~Z', normal), # Random (r'~x', normal + ansi.ANSI_BLACK), # Black (r'~D', hilite + ansi.ANSI_BLACK), # Dark Grey (r'~z', hilite + ansi.ANSI_BLACK), @@ -25,21 +25,21 @@ class IMCANSIParser(ansi.ANSIParser): (r'~g', normal + ansi.ANSI_GREEN), # Dark Green (r'~G', hilite + ansi.ANSI_GREEN), # Green (r'~p', normal + ansi.ANSI_MAGENTA), # Dark magenta - (r'~m', normal + ansi.ANSI_MAGENTA), + (r'~m', normal + ansi.ANSI_MAGENTA), (r'~M', hilite + ansi.ANSI_MAGENTA), # Magenta (r'~P', hilite + ansi.ANSI_MAGENTA), (r'~c', normal + ansi.ANSI_CYAN), # Cyan (r'~y', normal + ansi.ANSI_YELLOW), # Dark Yellow (brown) - (r'~Y', hilite + ansi.ANSI_YELLOW), # Yellow + (r'~Y', hilite + ansi.ANSI_YELLOW), # Yellow (r'~b', normal + ansi.ANSI_BLUE), # Dark Blue (r'~B', hilite + ansi.ANSI_BLUE), # Blue - (r'~C', hilite + ansi.ANSI_BLUE), + (r'~C', hilite + ansi.ANSI_BLUE), (r'~r', normal + ansi.ANSI_RED), # Dark Red - (r'~R', hilite + ansi.ANSI_RED), # Red + (r'~R', hilite + ansi.ANSI_RED), # Red ## Formatting (r'~L', hilite), # Bold/hilite - (r'~!', normal), # reset + (r'~!', normal), # reset (r'\\r', normal), (r'\\n', ansi.ANSI_RETURN), ] @@ -51,7 +51,7 @@ class IMCANSIParser(ansi.ANSIParser): ANSI_PARSER = IMCANSIParser() - + def parse_ansi(string, strip_ansi=False, parser=ANSI_PARSER): """ Shortcut to use the IMC2 ANSI parser. diff --git a/src/comms/imc2lib/imc2_listeners.py b/src/comms/imc2lib/imc2_listeners.py index 88dec66500..bef1b4ae04 100644 --- a/src/comms/imc2lib/imc2_listeners.py +++ b/src/comms/imc2lib/imc2_listeners.py @@ -5,6 +5,8 @@ This module handles some of the -reply packets like whois-reply. from src.objects.models import ObjectDB from src.comms.imc2lib import imc2_ansi +from django.utils.translation import ugettext as _ + def handle_whois_reply(packet): """ When the player sends an imcwhois request, the outgoing @@ -15,7 +17,7 @@ def handle_whois_reply(packet): try: pobject = ObjectDB.objects.get(id=packet.target) response_text = imc2_ansi.parse_ansi(packet.optional_data.get('text', 'Unknown')) - string = 'Whois reply from %s: %s' % (packet.origin, response_text) + string = _('Whois reply from %(origin)s: %(msg)s') % {"origin":packet.origin, "msg":response_text} pobject.msg(string.strip()) except ObjectDB.DoesNotExist: # No match found for whois sender. Ignore it. diff --git a/src/comms/imc2lib/imc2_packets.py b/src/comms/imc2lib/imc2_packets.py index 9f51f06a74..b427f14a6c 100644 --- a/src/comms/imc2lib/imc2_packets.py +++ b/src/comms/imc2lib/imc2_packets.py @@ -4,7 +4,7 @@ http://www.mudbytes.net/index.php?a=articles&s=imc2_protocol """ import shlex -from django.conf import settings +from django.conf import settings class Lexxer(shlex.shlex): """ @@ -28,7 +28,7 @@ class IMC2Packet(object): Optionally, parse a packet and load it up. """ # The following fields are all according to the basic packet format of: - # @ @ + # @ @ self.sender = None if not mudname: mudname = settings.SERVERNAME @@ -42,13 +42,13 @@ class IMC2Packet(object): self.optional_data = {} # Reference to the IMC2Protocol object doing the sending. self.imc2_protocol = None - + if packet_str: # The lexxer handles the double quotes correctly, unlike just # splitting. Spaces throw things off, so shlex handles it # gracefully, ala POSIX shell-style parsing. lex = Lexxer(packet_str) - + # Token counter. counter = 0 for token in lex: @@ -90,7 +90,7 @@ class IMC2Packet(object): pass # Increment and continue to the next token (if applicable) counter += 1 - + def __str__(self): retval = """ --IMC2 package (%s) @@ -101,15 +101,15 @@ class IMC2Packet(object): Type: %s Target: %s Dest.: %s - Data: - %s + Data: + %s ------------------------""" % (self.packet_type, self.sender, self.origin, self.sequence, self.route, self.packet_type, self.target, self.destination, "\n ".join(["%s: %s" % items for items in self.optional_data.items()])) return retval.strip() - + def _get_optional_data_string(self): """ Generates the optional data string to tack on to the end of the packet. @@ -126,7 +126,7 @@ class IMC2Packet(object): return data_string.strip() else: return '' - + def _get_sender_name(self): """ Calculates the sender name to be sent with the packet. @@ -139,9 +139,9 @@ class IMC2Packet(object): elif type(self.sender) in [type(u""),type(str())]: #this is used by e.g. IRC where no user object is present. return self.sender.strip().replace(' ', '_') - elif self.sender: + elif self.sender: # Player object. - name = self.sender.get_name(fullname=False, show_dbref=False, + name = self.sender.get_name(fullname=False, show_dbref=False, show_flags=False, no_ansi=True) # IMC2 does not allow for spaces. @@ -149,12 +149,12 @@ class IMC2Packet(object): else: # None value. Do something or other. return 'Unknown' - + def assemble(self, mudname=None, client_pwd=None, server_pwd=None): """ Assembles the packet and returns the ready-to-send string. - Note that the arguments are not used, they are there for - consistency across all packets. + Note that the arguments are not used, they are there for + consistency across all packets. """ self.sequence = self.imc2_protocol.sequence packet = "%s@%s %s %s %s %s@%s %s\n" % ( @@ -167,29 +167,29 @@ class IMC2Packet(object): self.destination, self._get_optional_data_string()) return packet.strip() - + class IMC2PacketAuthPlaintext(object): """ IMC2 plain-text authentication packet. Auth packets are strangely formatted, so this does not sub-class IMC2Packet. The SHA and plain text auth packets are the two only non-conformers. - - CLIENT Sends: + + CLIENT Sends: PW version= autosetup (SHA256) - + Optional Arguments( required if using the specified authentication method: - (SHA256) The literal string: SHA256. This is sent to notify the server - that the MUD is SHA256-Enabled. All future logins from this - client will be expected in SHA256-AUTH format if the server - supports it. - """ + (SHA256) The literal string: SHA256. This is sent to notify the server + that the MUD is SHA256-Enabled. All future logins from this + client will be expected in SHA256-AUTH format if the server + supports it. + """ def assemble(self, mudname=None, client_pwd=None, server_pwd=None): """ This is one of two strange packets, just assemble the packet manually and go. """ return 'PW %s %s version=2 autosetup %s\n' %(mudname, client_pwd, server_pwd) - + class IMC2PacketKeepAliveRequest(IMC2Packet): """ Description: @@ -197,15 +197,15 @@ class IMC2PacketKeepAliveRequest(IMC2Packet): This packet is usually followed by the sending MUD's own is-alive packet. It is used in the filling of a client's MUD list, thus any MUD that doesn't respond with an is-alive isn't marked as online on the sending MUD's mudlist. - + Data: (none) - + Example of a received keepalive-request: *@YourMUD 1234567890 YourMUD!Hub1 keepalive-request *@* - + Example of a sent keepalive-request: - *@YourMUD 1234567890 YourMUD keepalive-request *@* + *@YourMUD 1234567890 YourMUD keepalive-request *@* """ def __init__(self): super(IMC2PacketKeepAliveRequest, self).__init__() @@ -213,40 +213,40 @@ class IMC2PacketKeepAliveRequest(IMC2Packet): self.packet_type = 'keepalive-request' self.target = '*' self.destination = '*' - + class IMC2PacketIsAlive(IMC2Packet): """ Description: - This packet is the reply to a keepalive-request packet. It is responsible + This packet is the reply to a keepalive-request packet. It is responsible for filling a client's mudlist with the information about other MUDs on the network. - + Data: - versionid= + versionid= Where is the text version ID of the client. ("IMC2 4.5 MUD-Net") - - url= + + url= Where is the proper URL of the client. (http://www.domain.com) - - host= + + host= Where is the telnet address of the MUD. (telnet://domain.com) - - port= + + port= Where is the telnet port of the MUD. - + (These data fields are not sent by the MUD, they are added by the server.) - networkname= + networkname= Where is the network name that the MUD/server is on. ("MyNetwork") - + sha256= - This is an optional tag that denotes the SHA-256 capabilities of a + This is an optional tag that denotes the SHA-256 capabilities of a MUD or server. - + Example of a received is-alive: *@SomeMUD 1234567890 SomeMUD!Hub2 is-alive *@YourMUD versionid="IMC2 4.5 MUD-Net" url="http://www.domain.com" networkname="MyNetwork" sha256=1 host=domain.com port=5500 - + Example of a sent is-alive: - *@YourMUD 1234567890 YourMUD is-alive *@* versionid="IMC2 4.5 MUD-Net" url="http://www.domain.com" host=domain.com port=5500 + *@YourMUD 1234567890 YourMUD is-alive *@* versionid="IMC2 4.5 MUD-Net" url="http://www.domain.com" host=domain.com port=5500 """ def __init__(self): super(IMC2PacketIsAlive, self).__init__() @@ -258,19 +258,19 @@ class IMC2PacketIsAlive(IMC2Packet): 'url': '"http://www.evennia.com"', 'host': 'test.com', 'port': '5555'} - + class IMC2PacketIceRefresh(IMC2Packet): """ Description: - This packet is sent by the MUD to request data about the channels on the - network. Servers with channels reply with an ice-update packet for each + This packet is sent by the MUD to request data about the channels on the + network. Servers with channels reply with an ice-update packet for each channel they control. The usual target for this packet is IMC@$. - + Data: (none) - + Example: - *@YourMUD 1234567890 YourMUD!Hub1 ice-refresh IMC@$ + *@YourMUD 1234567890 YourMUD!Hub1 ice-refresh IMC@$ """ def __init__(self): super(IMC2PacketIceRefresh, self).__init__() @@ -284,40 +284,40 @@ class IMC2PacketIceUpdate(IMC2Packet): Description: A server returns this packet with the data of a channel when prompted with an ice-refresh request. - + Data: - channel= + channel= The channel's network name in the format of ServerName:ChannelName - - owner= + + owner= The Name@MUD of the channel's owner - - operators= + + operators= A space-seperated list of the Channel's operators, in the format of Person@MUD - + policy= The policy is either "open" or "private" with no quotes. - + invited= - The space-seperated list of invited User@MUDs, only valid for a + The space-seperated list of invited User@MUDs, only valid for a "private" channel. - + excluded= - The space-seperated list of banned User@MUDs, only valid for "open" + The space-seperated list of banned User@MUDs, only valid for "open" channels. - - level= The default level of the channel: Admin, Imp, Imm, + + level= The default level of the channel: Admin, Imp, Imm, Mort, or None - + localname= The suggested local name of the channel. - + Examples: - + Open Policy: ICE@Hub1 1234567890 Hub1!Hub2 ice-update *@YourMUD channel=Hub1:ichat owner=Imm@SomeMUD operators=Other@SomeMUD policy=open excluded="Flamer@badMUD Jerk@dirtyMUD" level=Imm localname=ichat - + Private Policy: - ICE@Hub1 1234567890 Hub1!Hub2 ice-update *@YourMUD channel=Hub1:secretchat owner=Imm@SomeMUD operators=Other@SomeMUD policy=private invited="SpecialDude@OtherMUD CoolDude@WeirdMUD" level=Mort localname=schat + ICE@Hub1 1234567890 Hub1!Hub2 ice-update *@YourMUD channel=Hub1:secretchat owner=Imm@SomeMUD operators=Other@SomeMUD policy=private invited="SpecialDude@OtherMUD CoolDude@WeirdMUD" level=Mort localname=schat """ pass @@ -328,29 +328,29 @@ class IMC2PacketIceMsgRelayed(IMC2Packet): ice-msg-p packet, are used with private policy channels. The 'r' stands for 'relay'. All incoming channel messages are from ICE@, where is the server hosting the channel. - + Data: - realfrom= + realfrom= The User@MUD the message came from. - - channel= + + channel= The Server:Channel the message is intended to be displayed on. - - text= + + text= The message text. - - emote= - An integer value designating emotes. 0 for no emote, 1 for an emote, + + emote= + An integer value designating emotes. 0 for no emote, 1 for an emote, and 2 for a social. - + Examples: ICE@Hub1 1234567890 Hub1!Hub2 ice-msg-r *@YourMUD realfrom=You@YourMUD channel=hub1:secret text="Aha! I got it!" emote=0 - + ICE@Hub1 1234567890 Hub1!Hub2 ice-msg-r *@YourMUD realfrom=You@YourMUD channel=hub1:secret text=Ahh emote=0 - + ICE@Hub1 1234567890 Hub1!Hub2 ice-msg-r *@YourMUD realfrom=You@YourMUD channel=hub1:secret text="grins evilly." emote=1 - - ICE@Hub1 1234567890 Hub1!Hub2 ice-msg-r *@YourMUD realfrom=You@YourMUD channel=hub1:secret text="You@YourMUD grins evilly!" emote=2 + + ICE@Hub1 1234567890 Hub1!Hub2 ice-msg-r *@YourMUD realfrom=You@YourMUD channel=hub1:secret text="You@YourMUD grins evilly!" emote=2 """ pass @@ -360,27 +360,27 @@ class IMC2PacketIceMsgPrivate(IMC2Packet): This packet is sent when a player sends a message to a private channel. This packet should never be seen as incoming to a client. The target of this packet should be IMC@ of the server hosting the channel. - + Data: - channel= + channel= The Server:Channel the message is intended to be displayed on. - + text= The message text. - + emote= An integer value designating emotes. 0 for no emote, 1 for an emote, and 2 for a social. - + echo= Tells the server to echo the message back to the sending MUD. This is only seen on out-going messages. - + Examples: You@YourMUD 1234567890 YourMUD ice-msg-p IMC@Hub1 channel=Hub1:secret text="Ahh! I got it!" emote=0 echo=1 You@YourMUD 1234567890 YourMUD ice-msg-p IMC@Hub1 channel=Hub1:secret text=Ahh! emote=0 echo=1 You@YourMUD 1234567890 YourMUD ice-msg-p IMC@Hub1 channel=Hub1:secret text="grins evilly." emote=1 echo=1 - You@YourMUD 1234567890 YourMUD ice-msg-p IMC@Hub1 channel=Hub1:secret text="You@YourMUD grins evilly." emote=2 echo=1 + You@YourMUD 1234567890 YourMUD ice-msg-p IMC@Hub1 channel=Hub1:secret text="You@YourMUD grins evilly." emote=2 echo=1 """ pass @@ -392,34 +392,34 @@ class IMC2PacketIceMsgBroadcasted(IMC2Packet): as it was sent by the originating MUD. The server that hosts the channel sends the packet back to the originating MUD as an 'echo' by removing the "echo=1" and attaching the "sender=Person@MUD" data field. - + Data: channel= The Server:Channel the message is intended to be displayed on. - + text= The message text. - + emote= - An integer value designating emotes. 0 for no emote, 1 for an emote, + An integer value designating emotes. 0 for no emote, 1 for an emote, and 2 for a social. - + *echo= This stays on broadcasted messages. It tells the channel's server to relay an echo back. - + *sender= The hosting server replaces "echo=1" with this when sending the echo back to the originating MUD. - - Examples: + + Examples: (See above for emote/social examples as they are pretty much the same) - + Return Echo Packet: You-YourMUD@Hub1 1234567890 Hub1 ice-msg-b *@YourMUD text=Hi! channel=Hub1:ichat sender=You@YourMUD emote=0 - + Broadcasted Packet: - You@YourMUD 1234567890 YourMUD!Hub1 ice-msg-b *@* channel=Hub1:ichat text=Hi! emote=0 echo=1 + You@YourMUD 1234567890 YourMUD!Hub1 ice-msg-b *@* channel=Hub1:ichat text=Hi! emote=0 echo=1 """ def __init__(self, server, channel, pobject, message): """ @@ -445,27 +445,27 @@ class IMC2PacketUserCache(IMC2Packet): Sent by a MUD with a new IMC2-able player or when a player's gender changes, this packet contains only the gender for data. The packet's origination should be the Player@MUD. - + Data: gender= 0 is male, 1 is female, 2 is anything else such as neuter. Will be referred to as "it". - + Example: - Dude@someMUD 1234567890 SomeMUD!Hub2!Hub1 user-cache *@* gender=0 + Dude@someMUD 1234567890 SomeMUD!Hub2!Hub1 user-cache *@* gender=0 """ pass class IMC2PacketUserCacheRequest(IMC2Packet): """ Description: - The MUD sends this packet out when making a request for the user-cache + The MUD sends this packet out when making a request for the user-cache information of the user included in the data part of the packet. - + Data: user= The Person@MUD whose data the MUD is seeking. - + Example: - *@YourMUD 1234567890 YourMUD user-cache-request *@SomeMUD user=Dude@SomeMUD + *@YourMUD 1234567890 YourMUD user-cache-request *@SomeMUD user=Dude@SomeMUD """ pass @@ -474,16 +474,16 @@ class IMC2PacketUserCacheReply(IMC2Packet): Description: A reply to the user-cache-request packet. It contains the user and gender for the user. - + Data: user= The Person@MUD whose data the MUD requested. - + gender= The gender of the Person@MUD in the 'user' field. - + Example: - *@someMUD 1234567890 SomeMUD!Hub2!Hub1 user-cache-reply *@YourMUD user=Dude@SomeMUD gender=0 + *@someMUD 1234567890 SomeMUD!Hub2!Hub1 user-cache-reply *@YourMUD user=Dude@SomeMUD gender=0 """ pass @@ -492,18 +492,18 @@ class IMC2PacketTell(IMC2Packet): Description: This packet is used to communicate private messages between users on MUDs across the network. - + Data: text= Message text isreply= Two settings: 1 denotes a reply, 2 denotes a tell social. - + Example: - + Originating: You@YourMUD 1234567890 YourMUD tell Dude@SomeMUD text="Having fun?" - + Reply from Dude: - Dude@SomeMUD 1234567890 SomeMUD!Hub1 tell You@YourMUD text="Yeah, this is cool!" isreply=1 + Dude@SomeMUD 1234567890 SomeMUD!Hub1 tell You@YourMUD text="Yeah, this is cool!" isreply=1 """ def __init__(self, pobject, target, destination, message): super(IMC2PacketTell, self).__init__() @@ -511,94 +511,94 @@ class IMC2PacketTell(IMC2Packet): self.packet_type = "tell" self.target = target self.destination = destination - self.optional_data = {"text": message, + self.optional_data = {"text": message, "isreply":None} - + def assemble(self, mudname=None, client_pwd=None, server_pwd=None): self.sequence = self.imc2_protocol.sequence #self.route = "%s!%s" % (self.origin, self.imc2_protocol.factory.servername.capitalize()) - return '''"%s@%s %s %s tell %s@%s text="%s"''' % (self.sender, self.origin, self.sequence, - self.route, self.target, self.destination, + return '''"%s@%s %s %s tell %s@%s text="%s"''' % (self.sender, self.origin, self.sequence, + self.route, self.target, self.destination, self.optional_data.get("text","NO TEXT GIVEN")) - + class IMC2PacketEmote(IMC2Packet): """ Description: This packet seems to be sent by servers when notifying the network of a new channel or the destruction of a channel. - + Data: - channel= - Unsure of what this means. The channel seen in both creation and + channel= + Unsure of what this means. The channel seen in both creation and destruction packets is 15. - + level= I am assuming this is the permission level of the sender. In both creation and destruction messages, this is -1. - + text= This is the message to be sent to the users. - + Examples: - ICE@Hub1 1234567890 Hub1 emote *@* channel=15 level=-1 text="the channel called hub1:test has been destroyed by You@YourMUD." + ICE@Hub1 1234567890 Hub1 emote *@* channel=15 level=-1 text="the channel called hub1:test has been destroyed by You@YourMUD." """ pass class IMC2PacketRemoteAdmin(IMC2Packet): """ Description: - This packet is used in remote server administration. Please note that - SHA-256 Support is *required* for a client to use this feature. The command - can vary, in fact this very packet is highly dependant on the server it's - being directed to. In most cases, sending the 'list' command will have a + This packet is used in remote server administration. Please note that + SHA-256 Support is *required* for a client to use this feature. The command + can vary, in fact this very packet is highly dependant on the server it's + being directed to. In most cases, sending the 'list' command will have a remote-admin enabled server send you the list of commands it will accept. - + Data: - command= + command= The command being sent to the server for processing. - - data= + + data= Data associated with the command. This is not always required. - - hash= - The SHA-256 hash that is verified by the server. This hash is generated in + + hash= + The SHA-256 hash that is verified by the server. This hash is generated in the same manner as an authentication packet. - + Example: - You@YourMUD 1234567890 YourMUD remote-admin IMC@Hub1 command=list hash= + You@YourMUD 1234567890 YourMUD remote-admin IMC@Hub1 command=list hash= """ pass class IMC2PacketIceCmd(IMC2Packet): """ Description: - Used for remote channel administration. In most cases, one must be listed - as a channel creator on the target server in order to do much with this + Used for remote channel administration. In most cases, one must be listed + as a channel creator on the target server in order to do much with this packet. Other cases include channel operators. - + Data: - channel= + channel= The target server:channel for the command. - - command= + + command= The command to be processed. - - data= + + data= Data associated with the command. This is not always required. - + Example: - You@YourMUD 1234567890 YourMUD ice-cmd IMC@hub1 channel=hub1:ichat command=list + You@YourMUD 1234567890 YourMUD ice-cmd IMC@hub1 channel=hub1:ichat command=list """ pass class IMC2PacketDestroy(IMC2Packet): """ Description: - Sent by a server to indicate the destruction of a channel it hosted. + Sent by a server to indicate the destruction of a channel it hosted. The mud should remove this channel from its local configuration. - + Data: - channel= The server:channel being destroyed. + channel= The server:channel being destroyed. """ pass @@ -606,39 +606,39 @@ class IMC2PacketWho(IMC2Packet): """ Description: A seemingly mutli-purpose information-requesting packet. The istats - packet currently only works on servers, or at least that's the case on - MUD-Net servers. The 'finger' type takes a player name in addition to the + packet currently only works on servers, or at least that's the case on + MUD-Net servers. The 'finger' type takes a player name in addition to the type name. - - Example: "finger Dude". The 'who' and 'info' types take no argument. - The MUD is responsible for building the reply text sent in the who-reply + + Example: "finger Dude". The 'who' and 'info' types take no argument. + The MUD is responsible for building the reply text sent in the who-reply packet. - + Data: type= Types: who, info, "finger ", istats (server only) - + Example: - Dude@SomeMUD 1234567890 SomeMUD!Hub1 who *@YourMUD type=who + Dude@SomeMUD 1234567890 SomeMUD!Hub1 who *@YourMUD type=who """ pass class IMC2PacketWhoReply(IMC2Packet): """ Description: - The multi-purpose reply to the multi-purpose information-requesting 'who' - packet. The MUD is responsible for building the return data, including the - format of it. The mud can use the permission level sent in the original who + The multi-purpose reply to the multi-purpose information-requesting 'who' + packet. The MUD is responsible for building the return data, including the + format of it. The mud can use the permission level sent in the original who packet to filter the output. The example below is the MUD-Net format. - + Data: text= The formatted reply to a 'who' packet. - + Additional Notes: - The example below is for the who list packet. The same construction would + The example below is for the who list packet. The same construction would go into formatting the other types of who packets. - + Example: - *@YourMUD 1234567890 YourMUD who-reply Dude@SomeMUD text="\n\r~R-=< ~WPlayers on YourMUD ~R>=-\n\r ~Y-=< ~Wtelnet://yourmud.domain.com:1234 ~Y>=-\n\r\n\r~B--------------------------------=< ~WPlayers ~B>=---------------------------------\n\r\n\r ~BPlayer ~z<--->~G Mortal the Toy\n\r\n\r~R-------------------------------=< ~WImmortals ~R>=--------------------------------\n\r\n\r ~YStaff ~z<--->~G You the Immortal\n\r\n\r~Y<~W2 Players~Y> ~Y<~WHomepage: http://www.yourmud.com~Y> <~W 2 Max Since Reboot~Y>\n\r~Y<~W3 logins since last reboot on Tue Feb 24, 2004 6:55:59 PM EST~Y>" + *@YourMUD 1234567890 YourMUD who-reply Dude@SomeMUD text="\n\r~R-=< ~WPlayers on YourMUD ~R>=-\n\r ~Y-=< ~Wtelnet://yourmud.domain.com:1234 ~Y>=-\n\r\n\r~B--------------------------------=< ~WPlayers ~B>=---------------------------------\n\r\n\r ~BPlayer ~z<--->~G Mortal the Toy\n\r\n\r~R-------------------------------=< ~WImmortals ~R>=--------------------------------\n\r\n\r ~YStaff ~z<--->~G You the Immortal\n\r\n\r~Y<~W2 Players~Y> ~Y<~WHomepage: http://www.yourmud.com~Y> <~W 2 Max Since Reboot~Y>\n\r~Y<~W3 logins since last reboot on Tue Feb 24, 2004 6:55:59 PM EST~Y>" """ pass @@ -646,12 +646,12 @@ class IMC2PacketWhois(IMC2Packet): """ Description: Sends a request to the network for the location of the specified player. - + Data: level= The permission level of the person making the request. - + Example: - You@YourMUD 1234567890 YourMUD whois dude@* level=5 + You@YourMUD 1234567890 YourMUD whois dude@* level=5 """ def __init__(self, pobject_id, whois_target): super(IMC2PacketWhois, self).__init__() @@ -664,98 +664,98 @@ class IMC2PacketWhois(IMC2Packet): class IMC2PacketWhoisReply(IMC2Packet): """ Description: - The reply to a whois packet. The MUD is responsible for building and formatting - the text sent back to the requesting player, and can use the permission level + The reply to a whois packet. The MUD is responsible for building and formatting + the text sent back to the requesting player, and can use the permission level sent in the original whois packet to filter or block the response. - + Data: text= The whois text. - + Example: - *@SomeMUD 1234567890 SomeMUD!Hub1 whois-reply You@YourMUD text="~RIMC Locate: ~YDude@SomeMUD: ~cOnline.\n\r" + *@SomeMUD 1234567890 SomeMUD!Hub1 whois-reply You@YourMUD text="~RIMC Locate: ~YDude@SomeMUD: ~cOnline.\n\r" """ pass class IMC2PacketBeep(IMC2Packet): """ Description: - Sends out a beep packet to the Player@MUD. The client receiving this should + Sends out a beep packet to the Player@MUD. The client receiving this should then send a bell-character to the target player to 'beep' them. - + Example: - You@YourMUD 1234567890 YourMUD beep dude@somemud + You@YourMUD 1234567890 YourMUD beep dude@somemud """ pass class IMC2PacketIceChanWho(IMC2Packet): """ Description: - Sends a request to the specified MUD or * to list all the users listening + Sends a request to the specified MUD or * to list all the users listening to the specified channel. - + Data: - level= + level= Sender's permission level. - - channel= + + channel= The server:chan name of the channel. - - lname= + + lname= The localname of the channel. - + Example: - You@YourMUD 1234567890 YourMUD ice-chan-who somemud level=5 channel=Hub1:ichat lname=ichat + You@YourMUD 1234567890 YourMUD ice-chan-who somemud level=5 channel=Hub1:ichat lname=ichat """ pass class IMC2PacketIceChanWhoReply(IMC2Packet): """ Description: - This is the reply packet for an ice-chan-who. The MUD is responsible for - creating and formatting the list sent back in the 'list' field. The - permission level sent in the original ice-chan-who packet can be used to + This is the reply packet for an ice-chan-who. The MUD is responsible for + creating and formatting the list sent back in the 'list' field. The + permission level sent in the original ice-chan-who packet can be used to filter or block the response. - + Data: - channel= + channel= The server:chan of the requested channel. - - list= + + list= The formatted list of local listeners for that MUD. - + Example: - *@SomeMUD 1234567890 SomeMUD!Hub1 ice-chan-whoreply You@YourMUD channel=Hub1:ichat list="The following people are listening to ichat on SomeMUD:\n\r\n\rDude\n\r" + *@SomeMUD 1234567890 SomeMUD!Hub1 ice-chan-whoreply You@YourMUD channel=Hub1:ichat list="The following people are listening to ichat on SomeMUD:\n\r\n\rDude\n\r" """ pass class IMC2PacketLaston(IMC2Packet): """ Description: - This packet queries the server the mud is connected to to find out when a + This packet queries the server the mud is connected to to find out when a specified user was last seen by the network on a public channel. - + Data: - username= The user, user@mud, or "all" being queried. Responses + username= The user, user@mud, or "all" being queried. Responses to this packet will be sent by the server in the form of a series of tells. - - Example: User@MUD 1234567890 MUD imc-laston SERVER username=somenamehere + + Example: User@MUD 1234567890 MUD imc-laston SERVER username=somenamehere """ pass class IMC2PacketCloseNotify(IMC2Packet): """ Description: - This packet alerts the network when a server or MUD has disconnected. The - server hosting the server or MUD is responsible for sending this packet - out across the network. Clients need only process the packet to remove the + This packet alerts the network when a server or MUD has disconnected. The + server hosting the server or MUD is responsible for sending this packet + out across the network. Clients need only process the packet to remove the disconnected MUD from their MUD list (or mark it as Disconnected). - + Data: - host= + host= The MUD or server that has disconnected from the network. - + Example: - *@Hub2 1234567890 Hub2!Hub1 close-notify *@* host=DisconnMUD + *@Hub2 1234567890 Hub2!Hub1 close-notify *@* host=DisconnMUD """ pass @@ -763,4 +763,4 @@ if __name__ == "__main__": packstr = "Kayle@MW 1234567 MW!Server02!Server01 ice-msg-b *@* channel=Server01:ichat text=\"*they're going woot\" emote=0 echo=1" packstr = "*@Lythelian 1234567 Lythelian!Server01 is-alive *@* versionid=\"Tim's LPC IMC2 client 30-Jan-05 / Dead Souls integrated\" networkname=Mudbytes url=http://dead-souls.net host=70.32.76.142 port=6666 sha256=0" print IMC2Packet(packstr) - + diff --git a/src/comms/imc2lib/imc2_trackers.py b/src/comms/imc2lib/imc2_trackers.py index f2ce2bf45c..f38d1fdfd7 100644 --- a/src/comms/imc2lib/imc2_trackers.py +++ b/src/comms/imc2lib/imc2_trackers.py @@ -2,7 +2,7 @@ Certain periodic packets are sent by connected MUDs (is-alive, user-cache, etc). The IMC2 protocol assumes that each connected MUD will capture these and populate/maintain their own lists of other servers connected. This module -contains stuff like this. +contains stuff like this. """ from time import time @@ -20,7 +20,7 @@ class IMC2Mud(object): self.sha256 = packet.optional_data.get('sha256', None) # This is used to determine when a Mud has fallen into inactive status. self.last_updated = time() - + class IMC2MudList(object): """ Keeps track of other MUDs connected to the IMC network. @@ -28,7 +28,7 @@ class IMC2MudList(object): def __init__(self): # Mud list is stored in a dict, key being the IMC Mud name. self.mud_list = {} - + def get_mud_list(self): """ Returns a sorted list of connected Muds. @@ -36,7 +36,7 @@ class IMC2MudList(object): muds = self.mud_list.items() muds.sort() return [value for key, value in muds] - + def update_mud_from_packet(self, packet): """ This grabs relevant info from the packet and stuffs it in the @@ -44,7 +44,7 @@ class IMC2MudList(object): """ mud = IMC2Mud(packet) self.mud_list[mud.name] = mud - + def remove_mud_from_packet(self, packet): """ Removes a mud from the Mud list when given a packet. @@ -55,7 +55,7 @@ class IMC2MudList(object): except KeyError: # No matching entry, no big deal. pass - + class IMC2Channel(object): """ Stores information about channels available on the network. @@ -67,7 +67,7 @@ class IMC2Channel(object): self.owner = packet.optional_data.get('owner', None) self.policy = packet.optional_data.get('policy', None) self.last_updated = time() - + class IMC2ChanList(object): """ Keeps track of other MUDs connected to the IMC network. @@ -75,7 +75,7 @@ class IMC2ChanList(object): def __init__(self): # Chan list is stored in a dict, key being the IMC Mud name. self.chan_list = {} - + def get_channel_list(self): """ Returns a sorted list of cached channels. @@ -83,7 +83,7 @@ class IMC2ChanList(object): channels = self.chan_list.items() channels.sort() return [value for key, value in channels] - + def update_channel_from_packet(self, packet): """ This grabs relevant info from the packet and stuffs it in the @@ -91,7 +91,7 @@ class IMC2ChanList(object): """ channel = IMC2Channel(packet) self.chan_list[channel.name] = channel - + def remove_channel_from_packet(self, packet): """ Removes a channel from the Channel list when given a packet. diff --git a/src/comms/irc.py b/src/comms/irc.py index f66798b8e7..f61ddae70d 100644 --- a/src/comms/irc.py +++ b/src/comms/irc.py @@ -11,6 +11,8 @@ from src.comms.models import ExternalChannelConnection, Channel from src.utils import logger, utils from src.server.sessionhandler import SESSIONS +from django.utils.translation import ugettext as _ + INFOCHANNEL = Channel.objects.channel_search(settings.CHANNEL_MUDINFO[0]) IRC_CHANNELS = [] @@ -27,77 +29,77 @@ def msg_info(message): class IRC_Bot(irc.IRCClient): """ This defines an IRC bot that connects to an IRC channel - and relays data to and from an evennia game. + and relays data to and from an evennia game. """ - + def _get_nickname(self): "required for correct nickname setting" return self.factory.nickname nickname = property(_get_nickname) - - def signedOn(self): + + def signedOn(self): # This is the first point the protocol is instantiated. # add this protocol instance to the global list so we - # can access it later to send data. + # can access it later to send data. global IRC_CHANNELS self.join(self.factory.channel) - IRC_CHANNELS.append(self) + IRC_CHANNELS.append(self) #msg_info("Client connecting to %s.'" % (self.factory.channel)) - + def joined(self, channel): - msg = "joined %s." % self.factory.pretty_key + msg = _("joined %s.") % self.factory.pretty_key msg_info(msg) logger.log_infomsg(msg) def privmsg(self, user, irc_channel, msg): - "Someone has written something in irc channel. Echo it to the evennia channel" - #find irc->evennia channel mappings + "Someone has written something in irc channel. Echo it to the evennia channel" + #find irc->evennia channel mappings conns = ExternalChannelConnection.objects.filter(db_external_key=self.factory.key) if not conns: - return - #format message: + return + #format message: user = user.split("!")[0] if user: user.strip() else: - user = "Unknown" + user = _("Unknown") msg = "[%s] %s@%s: %s" % (self.factory.evennia_channel, user, irc_channel, msg.strip()) - #logger.log_infomsg("channel connection. + This will create a new IRC<->channel connection. """ if not type(channel) == Channel: new_channel = Channel.objects.filter(db_key=channel) if not new_channel: - logger.log_errmsg("Cannot attach IRC<->Evennia: Evennia Channel '%s' not found" % channel) + logger.log_errmsg(_("Cannot attach IRC<->Evennia: Evennia Channel '%s' not found") % channel) return False channel = new_channel[0] key = build_connection_key(channel, irc_network, irc_port, irc_channel, irc_bot_nick) old_conns = ExternalChannelConnection.objects.filter(db_external_key=key) if old_conns: - return False + return False config = "%s|%s|%s|%s" % (irc_network, irc_port, irc_channel, irc_bot_nick) # how the channel will be able to contact this protocol - send_code = "from src.comms.irc import IRC_CHANNELS\n" + send_code = "from src.comms.irc import IRC_CHANNELS\n" send_code += "matched_ircs = [irc for irc in IRC_CHANNELS if irc.factory.key == '%s']\n" % key send_code += "[irc.msg_irc(message, from_obj=from_obj) for irc in matched_ircs]\n" - conn = ExternalChannelConnection(db_channel=channel, db_external_key=key, db_external_send_code=send_code, - db_external_config=config) + conn = ExternalChannelConnection(db_channel=channel, db_external_key=key, db_external_send_code=send_code, + db_external_config=config) conn.save() - # connect + # connect connect_to_irc(conn) - return True + return True def delete_connection(channel, irc_network, irc_port, irc_channel, irc_bot_nick): "Destroy a connection" if hasattr(channel, 'key'): channel = channel.key - key = build_connection_key(channel, irc_network, irc_port, irc_channel, irc_bot_nick) + key = build_connection_key(channel, irc_network, irc_port, irc_channel, irc_bot_nick) service_key = build_service_key(key) try: conn = ExternalChannelConnection.objects.get(db_external_key=key) except Exception: - return False - conn.delete() + return False + conn.delete() try: service = SESSIONS.server.services.getServiceNamed(service_key) except Exception: - return True - if service.running: + return True + if service.running: SESSIONS.server.services.removeService(service) - return True + return True def connect_to_irc(connection): - "Create the bot instance and connect to the IRC network and channel." + "Create the bot instance and connect to the IRC network and channel." # get config key = utils.to_str(connection.external_key) service_key = build_service_key(key) irc_network, irc_port, irc_channel, irc_bot_nick = [utils.to_str(conf) for conf in connection.external_config.split('|')] - # connect - bot = internet.TCPClient(irc_network, int(irc_port), IRCbotFactory(key, irc_channel, irc_network, irc_port, irc_bot_nick, + # connect + bot = internet.TCPClient(irc_network, int(irc_port), IRCbotFactory(key, irc_channel, irc_network, irc_port, irc_bot_nick, connection.channel.key)) bot.setName(service_key) SESSIONS.server.services.addService(bot) def connect_all(): """ - Activate all irc bots. + Activate all irc bots. """ for connection in ExternalChannelConnection.objects.filter(db_external_key__startswith='irc_'): connect_to_irc(connection) - + diff --git a/src/comms/managers.py b/src/comms/managers.py index 955c172a08..411bcdc4dc 100644 --- a/src/comms/managers.py +++ b/src/comms/managers.py @@ -1,5 +1,5 @@ """ -These managers handles the +These managers handles the """ import itertools @@ -18,7 +18,7 @@ def to_object(inp, objtype='player'): Locates the object related to the given playername or channel key. If input was already the correct object, return it. - inp - the input object/string + inp - the input object/string objtype - 'player' or 'channel' """ from src.players.models import PlayerDB @@ -30,43 +30,43 @@ def to_object(inp, objtype='player'): else: umatch = PlayerDB.objects.filter(user__username__iexact=inp) if umatch: - return umatch[0] + return umatch[0] elif objtype == 'external': from src.comms.models import ExternalChannelConnection if type (inp) == ExternalChannelConnection: return inp umatch = ExternalChannelConnection.objects.filter(db_key=inp) if umatch: - return umatch[0] + return umatch[0] else: # have to import this way to avoid circular imports - from src.comms.models import Channel - #= ContentType.objects.get(app_label="comms", + from src.comms.models import Channel + #= ContentType.objects.get(app_label="comms", # model="channel").model_class() if type(inp) == Channel: return inp cmatch = Channel.objects.filter(db_key__iexact=inp) if cmatch: return cmatch[0] - return None - + return None + # # Msg manager # class MsgManager(models.Manager): """ - This MsgManager implements methods for searching + This MsgManager implements methods for searching and manipulating Messages directly from the database. - These methods will all return database objects + These methods will all return database objects (or QuerySets) directly. - A Message represents one unit of communication, be it over a + A Message represents one unit of communication, be it over a Channel or via some form of in-game mail system. Like an e-mail, it always has a sender and can have any number of receivers (some - of which may be Channels). - + of which may be Channels). + Evennia-specific: get_message_by_id get_messages_by_sender @@ -75,22 +75,22 @@ class MsgManager(models.Manager): text_search message_search (equivalent to ev.search_messages) """ - + def get_message_by_id(self, idnum): - "Retrieve message by its id." + "Retrieve message by its id." try: idnum = int(idnum) return self.get(id=id) except Exception: return None - + def get_messages_by_sender(self, player): """ Get all messages sent by one player """ - player = to_object(player, objtype='player') + player = to_object(player, objtype='player') if not player: - return None + return None return self.filter(db_sender=player).exclude(db_hide_from_sender=True) def get_messages_by_receiver(self, receiver): @@ -99,7 +99,7 @@ class MsgManager(models.Manager): """ receiver = to_object(receiver) if not receiver: - return None + return None return [msg for msg in self.all() if receiver in msg.receivers and receiver not in msg.hide_from_receivers] @@ -110,30 +110,30 @@ class MsgManager(models.Manager): """ channel = to_object(channel, objtype='channel') if not channel: - return None + return None return [msg for msg in self.all() - if channel in msg.channels + if channel in msg.channels and channel not in msg.hide_from_channels] - #TODO add search limited by send_times + #TODO add search limited by send_times def text_search(self, searchstring, filterdict=None): """ Returns all messages that contain the matching search string. To avoid too many results, and also since this can be a very computing- heavy operation, it's recommended to be filtered - by at least channel or sender/receiver. + by at least channel or sender/receiver. searchstring - string to search for filterdict - {'channels':[list], 'senders':[list], 'receivers':[list]} lists can contain either the name/keys of the - objects or the actual objects to filter by. - """ + objects or the actual objects to filter by. + """ if filterdict: - # obtain valid objects for all filters + # obtain valid objects for all filters channels = [chan for chan in [to_object(chan, objtype='channel') for chan in filterdict.get('channels',[])] @@ -141,23 +141,23 @@ class MsgManager(models.Manager): senders = [sender for sender in [to_object(sender) for sender in filterdict.get('senders',[])] - if sender] + if sender] receivers = [receiver for receiver in [to_object(receiver) for receiver in filterdict.get('receivers',[])] if receiver] - # filter the messages lazily using the filter objects + # filter the messages lazily using the filter objects msgs = [] for sender in senders: msgs = list(sender.message_set.filter( - db_message__icontains=searchstring)) + db_message__icontains=searchstring)) for receiver in receivers: rec_msgs = receiver.message_set.filter( db_message__icontains=searchstring) if msgs: msgs = [msg for msg in rec_msgs if msg in msgs] else: - msgs = rec_msgs + msgs = rec_msgs for channel in channels: chan_msgs = list(channel.message_set.filter( db_message__icontains=searchstring)) @@ -168,21 +168,21 @@ class MsgManager(models.Manager): return list(set(msgs)) return list(self.all().filter(db_message__icontains=searchstring)) - def message_search(self, sender=None, receiver=None, channel=None, freetext=None, dbref=None): + def message_search(self, sender=None, receiver=None, channel=None, freetext=None, dbref=None): """ - Search the message database for particular messages. At least one - of the arguments must be given to do a search. + Search the message database for particular messages. At least one + of the arguments must be given to do a search. sender - get messages sent by a particular player receiver - get messages received by a certain player or players channel - get messages sent to a particular channel or channels - freetext - Search for a text string in a message. + freetext - Search for a text string in a message. NOTE: This can potentially be slow, so make sure to supply - one of the other arguments to limit the search. - dbref - (int) the exact database id of the message. This will override + one of the other arguments to limit the search. + dbref - (int) the exact database id of the message. This will override all other search crieteria since it's unique and always gives a list with only one match. - """ + """ if dbref: return self.filter(id=dbref) if freetext: @@ -199,12 +199,12 @@ class MsgManager(models.Manager): msgs = [] if sender: msgs = self.get_messages_by_sender(sender) - if receiver: + if receiver: rec_msgs = self.get_messages_by_receiver(receiver) if msgs: msgs = [msg for msg in rec_msgs if msg in msgs] else: - msgs = rec_msgs + msgs = rec_msgs if channel: chan_msgs = self.get_messaqge_by_channel(channel) if msgs: @@ -212,20 +212,20 @@ class MsgManager(models.Manager): else: msgs = chan_msgs return msgs - + # # Channel manager # class ChannelManager(models.Manager): """ - This ChannelManager implements methods for searching + This ChannelManager implements methods for searching and manipulating Channels directly from the database. - These methods will all return database objects + These methods will all return database objects (or QuerySets) directly. - A Channel is an in-game venue for communication. It's + A Channel is an in-game venue for communication. It's essentially representation of a re-sender: Users sends Messages to the Channel, and the Channel re-sends those messages to all users subscribed to the Channel. @@ -248,9 +248,9 @@ class ChannelManager(models.Manager): def get_channel(self, channelkey): """ Return the channel object if given its key. - Also searches its aliases. + Also searches its aliases. """ - # first check the channel key + # first check the channel key channels = self.filter(db_key__iexact=channelkey) if not channels: # also check aliases @@ -258,23 +258,23 @@ class ChannelManager(models.Manager): if channelkey in channel.aliases] if channels: return channels[0] - return None + return None def del_channel(self, channelkey): """ Delete channel matching channelkey. - Also cleans up channelhandler. + Also cleans up channelhandler. """ channels = self.filter(db_key__iexact=channelkey) if not channels: # no aliases allowed for deletion. - return False + return False for channel in channels: - channel.delete() + channel.delete() from src.comms.channelhandler import CHANNELHANDLER CHANNELHANDLER.update() - return None - + return None + def get_all_connections(self, channel): """ Return the connections of all players listening @@ -282,9 +282,9 @@ class ChannelManager(models.Manager): """ # import here to avoid circular imports #from src.comms.models import PlayerChannelConnection - PlayerChannelConnection = ContentType.objects.get(app_label="comms", + PlayerChannelConnection = ContentType.objects.get(app_label="comms", model="playerchannelconnection").model_class() - ExternalChannelConnection = ContentType.objects.get(app_label="comms", + ExternalChannelConnection = ContentType.objects.get(app_label="comms", model="externalchannelconnection").model_class() return itertools.chain(PlayerChannelConnection.objects.get_all_connections(channel), ExternalChannelConnection.objects.get_all_connections(channel)) @@ -297,10 +297,10 @@ class ChannelManager(models.Manager): """ channels = [] try: - # try an id match first + # try an id match first dbref = int(ostring.strip('#')) channels = self.filter(id=dbref) - except Exception: + except Exception: pass if not channels: # no id match. Search on the key. @@ -308,17 +308,17 @@ class ChannelManager(models.Manager): if not channels: # still no match. Search by alias. channels = [channel for channel in self.all() if ostring.lower in [a.lower for a in channel.aliases]] - return channels + return channels # # PlayerChannelConnection manager # class PlayerChannelConnectionManager(models.Manager): """ - This PlayerChannelConnectionManager implements methods for searching + This PlayerChannelConnectionManager implements methods for searching and manipulating PlayerChannelConnections directly from the database. - These methods will all return database objects + These methods will all return database objects (or QuerySets) directly. A PlayerChannelConnection defines a user's subscription to an in-game @@ -333,7 +333,7 @@ class PlayerChannelConnectionManager(models.Manager): break_connection """ - + def get_all_player_connections(self, player): "Get all connections that the given player has." player = to_object(player) @@ -346,18 +346,18 @@ class PlayerChannelConnectionManager(models.Manager): if player and channel: return self.filter(db_player=player).filter(db_channel=channel).count() > 0 return False - + def get_all_connections(self, channel): """ Get all connections for a channel """ channel = to_object(channel, objtype='channel') return self.filter(db_channel=channel) - + def create_connection(self, player, channel): """ Connect a player to a channel. player and channel - can be actual objects or keystrings. + can be actual objects or keystrings. """ player = to_object(player) channel = to_object(channel, objtype='channel') @@ -379,13 +379,13 @@ class PlayerChannelConnectionManager(models.Manager): class ExternalChannelConnectionManager(models.Manager): """ - This ExternalChannelConnectionManager implements methods for searching + This ExternalChannelConnectionManager implements methods for searching and manipulating HelpEntries directly from the database. - These methods will all return database objects + These methods will all return database objects (or QuerySets) directly. - An ExternalChannelConnetion describes the connection between an in-game + An ExternalChannelConnetion describes the connection between an in-game channel and some external source, such as an IRC or IMC channel. Evennia-specific: @@ -394,9 +394,9 @@ class ExternalChannelConnectionManager(models.Manager): get_all_connections create_connection break_connection - + """ - + def get_all_external_connections(self, external): "Get all connections that the given as external." external = to_object(external, objtype='external') @@ -409,18 +409,18 @@ class ExternalChannelConnectionManager(models.Manager): if external and channel: return self.filter(db_external_key=external).filter(db_channel=channel).count() > 0 return False - + def get_all_connections(self, channel): """ Get all connections for a channel """ channel = to_object(channel, objtype='channel') return self.filter(db_channel=channel) - + def create_connection(self, external, channel, config=""): """ Connect a external to a channel. external and channel - can be actual objects or keystrings. + can be actual objects or keystrings. """ channel = to_object(channel, objtype='channel') if not channel: diff --git a/src/comms/rss.py b/src/comms/rss.py index 2a4e638c07..dbfec7a65a 100644 --- a/src/comms/rss.py +++ b/src/comms/rss.py @@ -1,24 +1,24 @@ """ RSS parser for Evennia -This connects an RSS feed to an in-game Evennia channel, sending messages -to the channel whenever the feed updates. +This connects an RSS feed to an in-game Evennia channel, sending messages +to the channel whenever the feed updates. """ import re from twisted.internet import task -from django.conf import settings -from src.comms.models import ExternalChannelConnection, Channel +from django.conf import settings +from src.comms.models import ExternalChannelConnection, Channel from src.utils import logger, utils from src.scripts.models import ScriptDB -RSS_ENABLED = settings.RSS_ENABLED +RSS_ENABLED = settings.RSS_ENABLED RSS_UPDATE_INTERVAL = settings.RSS_UPDATE_INTERVAL INFOCHANNEL = Channel.objects.channel_search(settings.CHANNEL_MUDINFO[0]) RETAG = re.compile(r'<[^>]*?>') -# holds rss readers they can be shut down at will. +# holds rss readers they can be shut down at will. RSS_READERS = {} def msg_info(message): @@ -35,8 +35,8 @@ if RSS_ENABLED: try: import feedparser except ImportError: - raise ImportError("RSS requirs python-feedparser to be installed. Install or set RSS_ENABLED=False.") - + raise ImportError("RSS requires python-feedparser to be installed. Install or set RSS_ENABLED=False.") + class RSSReader(object): """ Reader script used to connect to each individual RSS feed @@ -45,47 +45,47 @@ class RSSReader(object): """ The reader needs an rss url and It also needs an interval for how often it is to check for new updates (defaults - to 10 minutes) + to 10 minutes) """ self.key = key - self.url = url - self.interval = interval + self.url = url + self.interval = interval self.entries = {} # stored feeds - self.task = None - # first we do is to load the feed so we don't resend - # old entries whenever the reader starts. - self.update_feed() + self.task = None + # first we do is to load the feed so we don't resend + # old entries whenever the reader starts. + self.update_feed() # start runner self.start() - + def update_feed(self): "Read the url for new updated data and determine what's new." feed = feedparser.parse(self.url) new = [] for entry in (e for e in feed['entries'] if e['id'] not in self.entries): - txt = "[RSS] %s: %s" % (RETAG.sub("", entry['title']), entry['link'].replace('\n','').encode('utf-8')) + txt = "[RSS] %s: %s" % (RETAG.sub("", entry['title']), entry['link'].replace('\n','').encode('utf-8')) self.entries[entry['id']] = txt - new.append(txt) - return new + new.append(txt) + return new def update(self): """ Called every self.interval seconds - tries to get new feed entries, and if so, uses the appropriate ExternalChannelConnection to send the - data to subscribing channels. + data to subscribing channels. """ new = self.update_feed() - if not new: - return - conns = ExternalChannelConnection.objects.filter(db_external_key=self.key) - for conn in (conn for conn in conns if conn.channel): - for txt in new: + if not new: + return + conns = ExternalChannelConnection.objects.filter(db_external_key=self.key) + for conn in (conn for conn in conns if conn.channel): + for txt in new: conn.to_channel("%s:%s" % (conn.channel.key, txt)) - + def start(self): """ - Starting the update task and store a reference in the - global variable so it can be found and shut down later. + Starting the update task and store a reference in the + global variable so it can be found and shut down later. """ global RSS_READERS self.task = task.LoopingCall(self.update) @@ -95,7 +95,7 @@ class RSSReader(object): def build_connection_key(channel, url): "This is used to id the connection" if hasattr(channel, 'key'): - channel = channel.key + channel = channel.key return "rss_%s>%s" % (url, channel) def create_connection(channel, url, interval): @@ -106,19 +106,19 @@ def create_connection(channel, url, interval): new_channel = Channel.objects.filter(db_key=channel) if not new_channel: logger.log_errmsg("Cannot attach RSS->Evennia: Evennia Channel '%s' not found." % channel) - return False + return False channel = new_channel[0] key = build_connection_key(channel, url) old_conns = ExternalChannelConnection.objects.filter(db_external_key=key) if old_conns: - return False + return False config = "%s|%i" % (url, interval) # There is no sendback from evennia to the rss, so we need not define any sendback code. conn = ExternalChannelConnection(db_channel=channel, db_external_key=key, db_external_config=config) - conn.save() + conn.save() connect_to_rss(conn) - return True + return True def delete_connection(channel, url): """ @@ -128,29 +128,29 @@ def delete_connection(channel, url): try: conn = ExternalChannelConnection.objects.get(db_external_key=key) except Exception: - return False + return False conn.delete() reader = RSS_READERS.get(key, None) - if reader and reader.task: + if reader and reader.task: reader.task.stop() - return True - + return True + def connect_to_rss(connection): """ Create the parser instance and connect to RSS feed and channel """ global RSS_READERS - key = utils.to_str(connection.external_key) + key = utils.to_str(connection.external_key) url, interval = [utils.to_str(conf) for conf in connection.external_config.split('|')] # Create reader (this starts the running task and stores a reference in RSS_TASKS) RSSReader(key, url, int(interval)) def connect_all(): """ - Activate all rss feed parsers + Activate all rss feed parsers """ if not RSS_ENABLED: - return + return for connection in ExternalChannelConnection.objects.filter(db_external_key__startswith="rss_"): print "connecting RSS: %s" % connection connect_to_rss(connection) diff --git a/src/locks/lockhandler.py b/src/locks/lockhandler.py index 6c69012a7a..069b66fbb0 100644 --- a/src/locks/lockhandler.py +++ b/src/locks/lockhandler.py @@ -107,7 +107,10 @@ to any other identifier you can use. import re, inspect from django.conf import settings from src.utils import logger, utils +from django.utils.translation import ugettext as _ + __all__ = ("LockHandler", ) + # # Exception class # @@ -215,7 +218,7 @@ class LockHandler(object): funcname, rest = (part.strip().strip(')') for part in funcstring.split('(', 1)) func = _LOCKFUNCS.get(funcname, None) if not callable(func): - elist.append("Lock: function '%s' is not available." % funcstring) + elist.append(_("Lock: function '%s' is not available.") % funcstring) continue args = list(arg.strip() for arg in rest.split(',') if not '=' in arg) kwargs = dict([arg.split('=', 1) for arg in rest.split(',') if '=' in arg]) @@ -228,12 +231,12 @@ class LockHandler(object): evalstring = " ".join(_RE_OK.findall(evalstring)) eval(evalstring % tuple(True for func in funclist), {}, {}) except Exception: - elist.append("Lock: definition '%s' has syntax errors." % raw_lockstring) + elist.append(_("Lock: definition '%s' has syntax errors.") % raw_lockstring) continue if access_type in locks: duplicates += 1 - wlist.append("Lock: access type '%s' changed from '%s' to '%s' " % \ - (access_type, locks[access_type][2], raw_lockstring)) + wlist.append(_("Lock: access type '%(access_type)s' changed from '%(source)s' to '%(goal)s' " % \ + {"access_type":access_type, "source":locks[access_type][2], "goal":raw_lockstring})) locks[access_type] = (evalstring, tuple(lock_funcs), raw_lockstring) if wlist and self.log_obj: # a warning text was set, it's not an error, so only report if log_obj is available. @@ -266,17 +269,17 @@ class LockHandler(object): # sanity checks for lockdef in lockstring.split(';'): if not ':' in lockstring: - self._log_error("Lock: '%s' contains no colon (:)." % lockdef) + self._log_error(_("Lock: '%s' contains no colon (:).") % lockdef) return False access_type, rhs = [part.strip() for part in lockdef.split(':', 1)] if not access_type: - self._log_error("Lock: '%s' has no access_type (left-side of colon is empty)." % lockdef) + self._log_error(_("Lock: '%s' has no access_type (left-side of colon is empty).") % lockdef) return False if rhs.count('(') != rhs.count(')'): - self._log_error("Lock: '%s' has mismatched parentheses." % lockdef) + self._log_error(_("Lock: '%s' has mismatched parentheses.") % lockdef) return False if not _RE_FUNCS.findall(rhs): - self._log_error("Lock: '%s' has no valid lock functions." % lockdef) + self._log_error(_("Lock: '%s' has no valid lock functions.") % lockdef) return False # get the lock string storage_lockstring = self.obj.lock_storage diff --git a/src/scripts/scripthandler.py b/src/scripts/scripthandler.py index 750f0cf4ed..b91cf48750 100644 --- a/src/scripts/scripthandler.py +++ b/src/scripts/scripthandler.py @@ -9,6 +9,8 @@ from src.scripts.models import ScriptDB from src.utils import create from src.utils import logger +from django.utils.translation import ugettext as _ + class ScriptHandler(object): """ Implements the handler. This sits on each game object. @@ -38,11 +40,8 @@ class ScriptHandler(object): repeats = script.repeats try: next_repeat = script.time_until_next_repeat() except: next_repeat = "?" - string += "\n '%s' (%s/%s, %s repeats): %s" % (script.key, - next_repeat, - interval, - repeats, - script.desc) + string += _("\n '%(key)s' (%(next_repeat)s/%(interval)s, %(repeats)s repeats): %(desc)s") % \ + {"key":script.key, "next_repeat":next_repeat, "interval":interval,"repeats":repeats,"desc":script.desc} return string.strip() def add(self, scriptclass, key=None, autostart=True): diff --git a/src/scripts/scripts.py b/src/scripts/scripts.py index 9383eb1edd..9b494446ec 100644 --- a/src/scripts/scripts.py +++ b/src/scripts/scripts.py @@ -17,6 +17,7 @@ from src.typeclasses.models import _ATTRIBUTE_CACHE from src.scripts.models import ScriptDB from src.comms import channelhandler from src.utils import logger +from django.utils.translation import ugettext as _ __all__ = ("Script", "DoNothing", "CheckSessions", "ValidateScripts", "ValidateChannelHandler", "ClearAttributeCache") @@ -66,7 +67,8 @@ class ScriptClass(TypeClass): def _step_err_callback(self, e): "callback for runner errors" cname = self.__class__.__name__ - estring = "Script %s(#%i) of type '%s': at_repeat() error '%s'." % (self.key, self.dbid, cname, e.getErrorMessage()) + estring = _("Script %(key)s(#%(dbid)i) of type '%(cname)s': at_repeat() error '%(err)s'.") % \ + {"key":self.key, "dbid":self.dbid, "cname":cname, "err":e.getErrorMessage()} try: self.dbobj.db_obj.msg(estring) except Exception: @@ -392,14 +394,14 @@ class DoNothing(Script): def at_script_creation(self): "Setup the script" self.key = "sys_do_nothing" - self.desc = "This is an empty placeholder script." + self.desc = _("This is an empty placeholder script.") class CheckSessions(Script): "Check sessions regularly." def at_script_creation(self): "Setup the script" self.key = "sys_session_check" - self.desc = "Checks sessions so they are live." + self.desc = _("Checks sessions so they are live.") self.interval = 60 # repeat every 60 seconds self.persistent = True @@ -414,7 +416,7 @@ class ValidateScripts(Script): def at_script_creation(self): "Setup the script" self.key = "sys_scripts_validate" - self.desc = "Validates all scripts regularly." + self.desc = _("Validates all scripts regularly.") self.interval = 3600 # validate every hour. self.persistent = True @@ -428,7 +430,7 @@ class ValidateChannelHandler(Script): def at_script_creation(self): "Setup the script" self.key = "sys_channels_validate" - self.desc = "Updates the channel handler" + self.desc = _("Updates the channel handler") self.interval = 3700 # validate a little later than ValidateScripts self.persistent = True @@ -442,7 +444,7 @@ class ClearAttributeCache(Script): def at_script_creation(self): "Setup the script" self.key = "sys_cache_clear" - self.desc = "Clears the Attribute Cache" + self.desc = _("Clears the Attribute Cache") self.interval = 3600 * 2 self.persistent = True def at_repeat(self): diff --git a/src/server/initial_setup.py b/src/server/initial_setup.py index 92f9415b4b..eff1603b8e 100644 --- a/src/server/initial_setup.py +++ b/src/server/initial_setup.py @@ -13,7 +13,6 @@ from src.server.models import ServerConfig from src.help.models import HelpEntry from src.utils import create -# i18n from django.utils.translation import ugettext as _ def create_config_values(): @@ -34,7 +33,7 @@ def create_objects(): Creates the #1 player and Limbo room. """ - print _(" Creating objects (Player #1 and Limbo room) ...") + print " Creating objects (Player #1 and Limbo room) ..." # Set the initial User's account object's username on the #1 object. # This object is pure django and only holds name, email and password. @@ -89,7 +88,7 @@ def create_channels(): """ Creates some sensible default channels. """ - print _(" Creating default channels ...") + print " Creating default channels ..." # public channel key, aliases, desc, locks = settings.CHANNEL_PUBLIC @@ -112,12 +111,11 @@ def import_MUX_help_files(): """ Imports the MUX help files. """ - print _(" Importing MUX help database (devel reference only) ...") + print " Importing MUX help database (devel reference only) ..." management.call_command('loaddata', '../src/help/mux_help_db.json', verbosity=0) # categorize the MUX help files into its own category. default_category = "MUX" - print _(" Moving imported help db to help category '%(default)s'." \ - % {'default': default_category}) + print " Moving imported help db to help category '%(default)s'." % {'default': default_category} HelpEntry.objects.all_to_category(default_category) def create_system_scripts(): @@ -127,7 +125,7 @@ def create_system_scripts(): """ from src.scripts import scripts - print _(" Creating and starting global scripts ...") + print " Creating and starting global scripts ..." # check so that all sessions are alive. script1 = create.create_script(scripts.CheckSessions) @@ -138,7 +136,7 @@ def create_system_scripts(): # clear the attribute cache regularly script4 = create.create_script(scripts.ClearAttributeCache) if not script1 or not script2 or not script3 or not script4: - print _(" Error creating system scripts.") + print " Error creating system scripts." def start_game_time(): """ @@ -147,7 +145,7 @@ def start_game_time(): the total run time of the server as well as its current uptime (the uptime can also be found directly from the server though). """ - print _(" Starting in-game time ...") + print " Starting in-game time ..." from src.utils import gametime gametime.init_gametime() @@ -170,20 +168,20 @@ def create_admin_media_links(): dpath = os.path.join(django.__path__[0], 'contrib', 'admin', 'static', 'admin') apath = os.path.join(settings.ADMIN_MEDIA_ROOT) if os.path.isdir(apath): - print _(" ADMIN_MEDIA_ROOT already exists. Ignored.") + print " ADMIN_MEDIA_ROOT already exists. Ignored." return if os.name == 'nt': - print _(" Admin-media files copied to ADMIN_MEDIA_ROOT (Windows mode).") + print " Admin-media files copied to ADMIN_MEDIA_ROOT (Windows mode)." os.mkdir(apath) os.system('xcopy "%s" "%s" /e /q /c' % (dpath, apath)) if os.name == 'posix': try: os.symlink(dpath, apath) - print _(" Admin-media symlinked to ADMIN_MEDIA_ROOT.") + print " Admin-media symlinked to ADMIN_MEDIA_ROOT." except OSError, e: - print _(" There was an error symlinking Admin-media to ADMIN_MEDIA_ROOT:\n %s\n -> \n %s\n (%s)\n If you see issues, link manually." % (dpath, apath, e)) + print " There was an error symlinking Admin-media to ADMIN_MEDIA_ROOT:\n %s\n -> \n %s\n (%s)\n If you see issues, link manually." % (dpath, apath, e) else: - print _(" Admin-media files should be copied manually to ADMIN_MEDIA_ROOT.") + print " Admin-media files should be copied manually to ADMIN_MEDIA_ROOT." def at_initial_setup(): """ @@ -199,7 +197,7 @@ def at_initial_setup(): mod = __import__(modname, fromlist=[None]) except (ImportError, ValueError): return - print _(" Running at_initial_setup() hook.") + print " Running at_initial_setup() hook." if mod.__dict__.get("at_initial_setup", None): mod.at_initial_setup() @@ -211,7 +209,7 @@ def reset_server(): It also checks so the warm-reset mechanism works as it should. """ from src.server.sessionhandler import SESSIONS - print _(" Initial setup complete. Resetting/reloading Server.") + print " Initial setup complete. Resetting/reloading Server." SESSIONS.server.shutdown(mode='reset') def handle_setup(last_step): diff --git a/src/server/models.py b/src/server/models.py index 2560a4e02a..6291c50527 100644 --- a/src/server/models.py +++ b/src/server/models.py @@ -18,9 +18,6 @@ from src.utils.idmapper.models import SharedMemoryModel from src.utils import logger, utils from src.server.manager import ServerConfigManager -# i18n -from django.utils.translation import ugettext as _ - #------------------------------------------------------------ # # ServerConfig @@ -88,7 +85,7 @@ class ServerConfig(SharedMemoryModel): "Setter. Allows for self.value = value" if utils.has_parent('django.db.models.base.Model', value): # we have to protect against storing db objects. - logger.log_errmsg(_("ServerConfig cannot store db objects! (%s)" % value)) + logger.log_errmsg("ServerConfig cannot store db objects! (%s)" % value) return self.db_value = pickle.dumps(value) self.save() diff --git a/src/server/portal.py b/src/server/portal.py index 885953fadd..4b4300fb2c 100644 --- a/src/server/portal.py +++ b/src/server/portal.py @@ -26,9 +26,6 @@ if os.name == 'nt': # For Windows we need to handle pid files manually. PORTAL_PIDFILE = os.path.join(settings.GAME_DIR, 'portal.pid') -# i18n -from django.utils.translation import ugettext as _ - #------------------------------------------------------------ # Evennia Portal settings #------------------------------------------------------------ @@ -103,7 +100,7 @@ class Portal(object): """ Outputs server startup info to the terminal. """ - print _(' %(servername)s Portal (%(version)s) started.') % {'servername': SERVERNAME, 'version': VERSION} + print ' %(servername)s Portal (%(version)s) started.' % {'servername': SERVERNAME, 'version': VERSION} if AMP_ENABLED: print " amp (Server): %s" % AMP_PORT if TELNET_ENABLED: @@ -135,7 +132,7 @@ class Portal(object): if mode == None: return f = open(PORTAL_RESTART, 'w') - print _("writing mode=%(mode)s to %(portal_restart)s") % {'mode': mode, 'portal_restart': PORTAL_RESTART} + print "writing mode=%(mode)s to %(portal_restart)s" % {'mode': mode, 'portal_restart': PORTAL_RESTART} f.write(str(mode)) f.close() diff --git a/src/server/server.py b/src/server/server.py index bfbfe9bb78..8e02547baa 100644 --- a/src/server/server.py +++ b/src/server/server.py @@ -172,7 +172,7 @@ class Evennia(object): if not last_initial_setup_step: # None is only returned if the config does not exist, # i.e. this is an empty DB that needs populating. - print _(' Server started for the first time. Setting defaults.') + print ' Server started for the first time. Setting defaults.' initial_setup.handle_setup(0) print '-'*50 elif int(last_initial_setup_step) >= 0: @@ -180,8 +180,8 @@ class Evennia(object): # modules and setup will resume from this step, retrying # the last failed module. When all are finished, the step # is set to -1 to show it does not need to be run again. - print _(' Resuming initial setup from step %(last)s.' % \ - {'last': last_initial_setup_step}) + print ' Resuming initial setup from step %(last)s.' % \ + {'last': last_initial_setup_step} initial_setup.handle_setup(int(last_initial_setup_step)) print '-'*50 @@ -207,7 +207,7 @@ class Evennia(object): """ Outputs server startup info to the terminal. """ - print _(' %(servername)s Server (%(version)s) started.') % {'servername': SERVERNAME, 'version': VERSION} + print ' %(servername)s Server (%(version)s) started.' % {'servername': SERVERNAME, 'version': VERSION} print ' amp (Portal): %s' % AMP_PORT def set_restart_mode(self, mode=None): diff --git a/src/server/ssh.py b/src/server/ssh.py index ec5f974b77..ab6f313537 100644 --- a/src/server/ssh.py +++ b/src/server/ssh.py @@ -28,9 +28,6 @@ from src.server import session from src.players.models import PlayerDB from src.utils import ansi, utils, logger -# i18n -from django.utils.translation import ugettext as _ - ENCODINGS = settings.ENCODINGS CTRL_C = '\x03' @@ -295,7 +292,7 @@ def getKeyPair(pubkeyfile, privkeyfile): if not (os.path.exists(pubkeyfile) and os.path.exists(privkeyfile)): # No keypair exists. Generate a new RSA keypair - print _(" Generating SSH RSA keypair ..."), + print " Generating SSH RSA keypair ...", from Crypto.PublicKey import RSA KEY_LENGTH = 1024 @@ -340,8 +337,8 @@ def makeFactory(configdict): factory.publicKeys = {'ssh-rsa': publicKey} factory.privateKeys = {'ssh-rsa': privateKey} except Exception, e: - print _(" getKeyPair error: %(e)s\n WARNING: Evennia could not auto-generate SSH keypair. Using conch default keys instead.") % {'e': e} - print _(" If this error persists, create game/%(pub)s and game/%(priv)s yourself using third-party tools.") % {'pub': pubkeyfile, 'priv': privkeyfile} + print " getKeyPair error: %(e)s\n WARNING: Evennia could not auto-generate SSH keypair. Using conch default keys instead." % {'e': e} + print " If this error persists, create game/%(pub)s and game/%(priv)s yourself using third-party tools." % {'pub': pubkeyfile, 'priv': privkeyfile} factory.services = factory.services.copy() factory.services['ssh-userauth'] = ExtraInfoAuthServer diff --git a/src/server/ssl.py b/src/server/ssl.py index 433edd0273..b3064731e3 100644 --- a/src/server/ssl.py +++ b/src/server/ssl.py @@ -8,7 +8,7 @@ from twisted.internet import ssl as twisted_ssl try: import OpenSSL except ImportError: - print _(" SSL_ENABLED requires PyOpenSSL.") + print " SSL_ENABLED requires PyOpenSSL." sys.exit(5) from src.server.telnet import TelnetProtocol @@ -33,7 +33,7 @@ def verify_SSL_key_and_cert(keyfile, certfile): from Crypto.PublicKey import RSA from twisted.conch.ssh.keys import Key - print _(" Creating SSL key and certificate ... "), + print " Creating SSL key and certificate ... ", try: # create the RSA key and store it. @@ -42,8 +42,8 @@ def verify_SSL_key_and_cert(keyfile, certfile): keyString = rsaKey.toString(type="OPENSSH") file(keyfile, 'w+b').write(keyString) except Exception,e: - print _("rsaKey error: %(e)s\n WARNING: Evennia could not auto-generate SSL private key.") % {'e': e} - print _("If this error persists, create game/%(keyfile)s yourself using third-party tools.") % {'keyfile': keyfile} + print "rsaKey error: %(e)s\n WARNING: Evennia could not auto-generate SSL private key." % {'e': e} + print "If this error persists, create game/%(keyfile)s yourself using third-party tools." % {'keyfile': keyfile} sys.exit(5) # try to create the certificate @@ -55,12 +55,14 @@ def verify_SSL_key_and_cert(keyfile, certfile): try: err = subprocess.call(exestring)#, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) except OSError, e: - print " %s\n" % e - print _(" Evennia's SSL context factory could not automatically create an SSL certificate game/%(cert)s.") % {'cert': certfile} - print _(" A private key 'ssl.key' was already created. Please create %(cert)s manually using the commands valid") % {'cert': certfile} - print _(" for your operating system.") - print _(" Example (linux, using the openssl program): ") - print " %s" % exestring + string = "\n".join([ + " %s\n" % e, + " Evennia's SSL context factory could not automatically create an SSL certificate game/%(cert)s." % {'cert': certfile}, + " A private key 'ssl.key' was already created. Please create %(cert)s manually using the commands valid" % {'cert': certfile}, + " for your operating system.", + " Example (linux, using the openssl program): ", + " %s" % exestring]) + print string sys.exit(5) print "done." diff --git a/src/utils/batchprocessors.py b/src/utils/batchprocessors.py index dc7bb59197..08fa056ff5 100644 --- a/src/utils/batchprocessors.py +++ b/src/utils/batchprocessors.py @@ -42,11 +42,11 @@ simple format. The engine runs each command in sequence, as if they had been run at the game prompt. Each evennia command must be delimited by a line comment to mark its -end. +end. #INSERT path.batchcmdfile - this as the first entry on a line will - import and run a batch.ev file in this position, as if it was - written in this file. + import and run a batch.ev file in this position, as if it was + written in this file. This way entire game worlds can be created and planned offline; it is especially useful in order to create long room descriptions where a @@ -54,11 +54,11 @@ real offline text editor is often much better than any online text editor or prompt. Example of batch.ev file: ----------------------------- +---------------------------- # batch file # all lines starting with # are comments; they also indicate -# that a command definition is over. +# that a command definition is over. @create box @@ -66,10 +66,10 @@ Example of batch.ev file: @set box/desc = A large box. -Inside are some scattered piles of clothing. +Inside are some scattered piles of clothing. -It seems the bottom of the box is a bit loose. +It seems the bottom of the box is a bit loose. # Again, this comment indicates the @set command is over. Note how # the description could be freely added. Excess whitespace on a line @@ -81,7 +81,7 @@ It seems the bottom of the box is a bit loose. # (Assuming #221 is a warehouse or something.) # (remember, this comment ends the @teleport command! Don'f forget it) -# Example of importing another file at this point. +# Example of importing another file at this point. #IMPORT examples.batch @drop box @@ -90,7 +90,7 @@ It seems the bottom of the box is a bit loose. # close the @drop command since it's the end of the file) ------------------------- -An example batch file is game/gamesrc/commands/examples/batch_example.ev. +An example batch file is game/gamesrc/commands/examples/batch_example.ev. ========================================================================== @@ -114,9 +114,9 @@ code words. automatically be pasted at the top of all code blocks. Observe that changes to these variables made in one block is not preserved between blocks! -#CODE +#CODE #CODE (info) -#CODE (info) objname1, objname1, ... - +#CODE (info) objname1, objname1, ... - This designates a code block that will be executed like a stand-alone piece of code together with any #HEADER defined. (info) text is used by the interactive mode to @@ -140,12 +140,12 @@ caller - the object executing the script Example batch.py file ----------------------------------- -#HEADER +#HEADER -import traceback +import traceback from django.config import settings from src.utils import create -from game.gamesrc.typeclasses import basetypes +from game.gamesrc.typeclasses import basetypes GOLD = 10 @@ -188,12 +188,12 @@ def read_batchfile(pythonpath, file_ending='.py'): Filename is considered to be the name of the batch file relative the directory specified in settings.py. - file_ending specify which batchfile ending should be + file_ending specify which batchfile ending should be assumed (.ev or .py). - """ + """ # open the file - if pythonpath and not (pythonpath.startswith('src.') or pythonpath.startswith('game.') + if pythonpath and not (pythonpath.startswith('src.') or pythonpath.startswith('game.') or pythonpath.startswith('contrib.')): abspaths = [] for basepath in settings.BASE_BATCHPROCESS_PATHS: @@ -202,24 +202,24 @@ def read_batchfile(pythonpath, file_ending='.py'): abspaths = [utils.pypath_to_realpath(pythonpath, file_ending)] fobj, lines, err = None, [], None for file_encoding in ENCODINGS: - # try different encodings, in order + # try different encodings, in order load_errors = [] for abspath in abspaths: - # try different paths, until we get a match - try: + # try different paths, until we get a match + try: # we read the file directly into unicode. fobj = codecs.open(abspath, 'r', encoding=file_encoding) except IOError: load_errors.append("Could not open batchfile '%s'." % abspath) - continue + continue break if not fobj: - continue + continue load_errors = [] - err =None + err =None # We have successfully found and opened the file. Now actually - # try to decode it using the given protocol. + # try to decode it using the given protocol. try: lines = fobj.readlines() except UnicodeDecodeError: @@ -230,19 +230,19 @@ def read_batchfile(pythonpath, file_ending='.py'): for lnum, line in enumerate(fobj): pass except UnicodeDecodeError, err: - # lnum starts from 0, so we add +1 line, + # lnum starts from 0, so we add +1 line, # besides the faulty line is never read # so we add another 1 (thus +2) to get - # the actual line number seen in an editor. - err.linenum = lnum + 2 + # the actual line number seen in an editor. + err.linenum = lnum + 2 fobj.close() # possibly try another encoding - continue + continue # if we get here, the encoding worked. Stop iteration. - break - if load_errors: + break + if load_errors: logger.log_errmsg("\n".join(load_errors)) - if err: + if err: return err else: return lines @@ -257,7 +257,7 @@ class BatchCommandProcessor(object): """ This class implements a batch-command processor. - """ + """ def parse_file(self, pythonpath): """ This parses the lines of a batchfile according to the following @@ -266,15 +266,15 @@ class BatchCommandProcessor(object): It is also a comment and any number of # can exist on subsequent lines (but not inside comments). 2) #INSERT at the beginning of a line imports another - batch-cmd file file and pastes it into the batch file as if - it was written there. + batch-cmd file file and pastes it into the batch file as if + it was written there. 3) Commands are placed alone at the beginning of a line and their arguments are considered to be everything following (on any number of lines) until the next comment line beginning with #. 4) Newlines are ignored in command definitions 5) A completely empty line in a command line definition is condered a newline (so two empty lines is a paragraph). - 6) Excess spaces and indents inside arguments are stripped. + 6) Excess spaces and indents inside arguments are stripped. """ @@ -287,7 +287,7 @@ class BatchCommandProcessor(object): if line.strip().startswith("#INSERT"): return "insert" elif line.strip()[0] == '#': - return "comment" + return "comment" else: return "commanddef" except IndexError: @@ -295,10 +295,10 @@ class BatchCommandProcessor(object): #read the indata, if possible. lines = read_batchfile(pythonpath, file_ending='.ev') - + #line = utils.to_unicode(line) if not lines: - return None + return None commands = [] curr_cmd = "" @@ -309,34 +309,34 @@ class BatchCommandProcessor(object): #parse all command definitions into a list. for line in lines: - + typ = identify_line(line) - + if typ == "commanddef": curr_cmd += line elif typ == "empty" and curr_cmd: curr_cmd += "\r\n" elif typ == "insert": - # note that we are not safeguarding for + # note that we are not safeguarding for # cyclic imports here! if curr_cmd: commands.append(curr_cmd.strip()) curr_cmd = "" - filename = line.lstrip("#INSERT").strip() + filename = line.lstrip("#INSERT").strip() insert_commands = self.parse_file(filename) if insert_commands == None: insert_commands = ["{rINSERT ERROR: %s{n" % filename] - commands.extend(insert_commands) + commands.extend(insert_commands) else: #comment if curr_cmd: - commands.append(curr_cmd.strip()) - curr_cmd = "" - if curr_cmd: + commands.append(curr_cmd.strip()) + curr_cmd = "" + if curr_cmd: commands.append(curr_cmd.strip()) #second round to clean up now merged line edges etc. reg2 = re.compile(r"[ \t\f\v]+") - commands = [reg2.sub(" ", c) for c in commands] + commands = [reg2.sub(" ", c) for c in commands] #remove eventual newline at the end of commands commands = [c.strip('\r\n') for c in commands] @@ -359,7 +359,7 @@ def tb_iter(tb): class BatchCodeProcessor(object): """ This implements a batch-code processor - + """ def parse_file(self, pythonpath): @@ -369,8 +369,8 @@ class BatchCodeProcessor(object): 1) Lines starting with #HEADER starts a header block (ends other blocks) 2) Lines starting with #CODE begins a code block (ends other blocks) - 3) #CODE headers may be of the following form: #CODE (info) objname, objname2, ... - 4) Lines starting with #INSERT are on form #INSERT filename. + 3) #CODE headers may be of the following form: #CODE (info) objname, objname2, ... + 4) Lines starting with #INSERT are on form #INSERT filename. 3) All lines outside blocks are stripped. 4) All excess whitespace beginning/ending a block is stripped. @@ -379,9 +379,9 @@ class BatchCodeProcessor(object): # helper function def parse_line(line): """ - Identifies the line type: block command, comment, empty or normal code. + Identifies the line type: block command, comment, empty or normal code. - """ + """ parseline = line.strip() if parseline.startswith("#HEADER"): @@ -399,7 +399,7 @@ class BatchCodeProcessor(object): if info: info = info[0] line = line.replace(info, "") - objs = [o.strip() for o in line.split(",") if o.strip()] + objs = [o.strip() for o in line.split(",") if o.strip()] return ("codeheader", info, objs) elif parseline.startswith('#'): return ('comment', "", "%s" % line) @@ -422,25 +422,25 @@ class BatchCodeProcessor(object): in_code = False for line in lines: - # parse line + # parse line mode, info, line = parse_line(line) # try: - # print "::", in_header, in_code, mode, line.strip() + # print "::", in_header, in_code, mode, line.strip() # except: - # print "::", in_header, in_code, mode, line - if mode == 'insert': + # print "::", in_header, in_code, mode, line + if mode == 'insert': # recursive load of inserted code files - note that we # are not checking for cyclic imports! in_header = False in_code = False inserted_codes = self.parse_file(line) or [{'objs':"", 'info':line, 'code':""}] - for codedict in inserted_codes: - codedict["inserted"] = True + for codedict in inserted_codes: + codedict["inserted"] = True codes.extend(inserted_codes) elif mode == 'header': in_header = True in_code = False - elif mode == 'codeheader': + elif mode == 'codeheader': in_header = False in_code = True # the line is a list of object variable names @@ -468,9 +468,9 @@ class BatchCodeProcessor(object): # just check for errors. if not codedict['code']: codedict['code'] = "{r#INSERT ERROR: %s{n" % codedict['info'] - else: + else: objs = ", ".join(codedict["objs"]) - if objs: + if objs: objs = "[%s]" % objs codedict["code"] = "#CODE %s %s \n%s\n\n%s" % (codedict['info'], objs, @@ -486,7 +486,7 @@ class BatchCodeProcessor(object): """ # define the execution environment environ = "setup_environ(settings_module)" - environdict = {"setup_environ":setup_environ, + environdict = {"setup_environ":setup_environ, "settings_module":settings_module} if extra_environ: for key, value in extra_environ.items(): @@ -499,11 +499,11 @@ class BatchCodeProcessor(object): for obj in codedict['objs']: code += "\ntry: %s.delete()\nexcept: pass" % obj - # execute the block + # execute the block try: exec(code, environdict) except Exception: - etype, value, tb = sys.exc_info() + etype, value, tb = sys.exc_info() fname = tb_filename(tb) for tb in tb_iter(tb): @@ -512,15 +512,15 @@ class BatchCodeProcessor(object): lineno = tb.tb_lineno - 1 err = "" for iline, line in enumerate(code.split("\n")): - if iline == lineno: - err += "\n{w%02i{n: %s" % (iline + 1, line) - elif lineno - 5 < iline < lineno + 5: - err += "\n%02i: %s" % (iline + 1, line) + if iline == lineno: + err += "\n{w%02i{n: %s" % (iline + 1, line) + elif lineno - 5 < iline < lineno + 5: + err += "\n%02i: %s" % (iline + 1, line) - err += "\n".join(traceback.format_exception(etype, value, tb)) + err += "\n".join(traceback.format_exception(etype, value, tb)) #errlist = format_exc().split('\n') #if len(errlist) > 4: - # errlist = errlist[4:] + # errlist = errlist[4:] #err = "\n".join(" %s" % line for line in errlist if line) if debug: