Ejemplo n.º 1
0
  def runtimer(self):
    """
    This timer thread sleeps for a second, then calls everything
    in the queue with the current tick.
    """
    from time import time
    
    self._current_tick = 0
    wakeup_time = current_time = time()

    import threading
    ev = threading.Event()
    exported.hook_register("shutdown_hook", lambda *_: ev.set())

    while not ev.isSet():
      try:
        tout = wakeup_time - current_time
        if tout > 0:
          ev.wait(timeout = tout)
          current_time = time()
        elif tout < -10:
          # we are late too much; drop 10 ticks
          wakeup_time += 10
          continue
        event.SpamEvent(hookname="timer_hook", 
                        argmap={"tick": self._current_tick}
                       ).enqueue()
        self._current_tick += 1
        wakeup_time += 1
      except KeyboardInterrupt:
        return
      except SystemExit:
        return
      except:
        exported.write_traceback("ticker: ticker hiccupped.")
Ejemplo n.º 2
0
    def runtimer(self):
        """
    This timer thread sleeps for a second, then calls everything
    in the queue with the current tick.

    Note: This will almost always be slightly behind and will
    get worse as there are more things that get executed each
    tick.
    """
        import time, event

        self._current_tick = 0
        while not self._shutdownflag:
            try:
                time.sleep(1)
                event.SpamEvent(hookname="timer_hook",
                                argmap={
                                    "tick": self._current_tick
                                }).enqueue()
                self._current_tick += 1
            except KeyboardInterrupt:
                return
            except SystemExit:
                return
            except:
                exported.write_traceback("ticker: ticker hiccupped.")
Ejemplo n.º 3
0
  def runtimer(self):
    """
    This timer thread sleeps for a second, then calls everything
    in the queue with the current tick.

    Note: This will almost always be slightly behind and will
    get worse as there are more things that get executed each
    tick.
    """
    import time, event

    self._current_tick = 0
    while not self._shutdownflag:
      try:
        time.sleep(1)
        event.SpamEvent(hookname="timer_hook", 
                        argmap={"tick": self._current_tick}
                       ).enqueue()
        self._current_tick += 1
      except KeyboardInterrupt:
        return
      except SystemExit:
        return
      except:
        exported.write_traceback("ticker: ticker hiccupped.")
Ejemplo n.º 4
0
  def checkActions(self, text):
    """
    Checks to see if text triggered any actions.  Any resulting 
    actions will get added as an InputEvent to the queue.

    @param text: the data coming from the mud to check for triggers
    @type  text: string
    """
    # FIXME - make sure this works even when lines are broken up.

    actionlist = self._actionlist
    if not actionlist:
      actionlist = [x for x in list(self._actions.values()) if x[6] not in self._disabled]
      actionlist.sort(key = lambda x:x[3])
      self._actionlist = actionlist

    colorline = utils.filter_cm(text)
    nocolorline = ansi.filter_ansi(colorline)

    # go through all the lines in the data and see if we have
    # any matches
    for (action, actioncompiled, response, color, priority, onetime, tag) in actionlist:
      if color:
        match = actioncompiled.search(colorline)
        line = colorline
      else:
        match = actioncompiled.search(nocolorline)
        line = nocolorline

      if match:
        # for every match we figure out what the expanded response
        # is and add it as an InputEvent in the queue.  the reason
        # we do a series of separate events rather than one big
        # event with ; separators is due to possible issues with 
        # braces and such in malformed responses.

        # get variables from the action
        actionvars = get_ordered_vars(action)

        # fill in values for all the variables in the match
        varvals = {}
        for i in range(len(actionvars)):
          varvals[actionvars[i]] = match.group(i+1)

        # add special variables
        varvals['a'] = line.replace(';', '_')
            
        # fill in response variables from those that
        # matched on the trigger
        response = utils.expand_vars(response, varvals)

        # event.InputEvent(response, internal=1, ses=self._ses).enqueue()
        try:
          exported.lyntin_command(response, internal=1, session=self._ses)
        except:
          exported.write_traceback()

        if onetime and action in self._actions:
          del self._actions[action]
          self._actionlist = None           # invalidate the list
Ejemplo n.º 5
0
  def runtimer(self):
    """
    This timer thread sleeps for a second, then calls everything
    in the queue with the current tick.
    """
    from time import time
    
    self._current_tick = 0
    wakeup_time = current_time = time()

    import threading
    ev = threading.Event()
    exported.hook_register("shutdown_hook", lambda *_: ev.set())

    while not ev.isSet():
      try:
        tout = wakeup_time - current_time
        if tout > 0:
          ev.wait(timeout = tout)
          current_time = time()
        elif tout < -10:
          # we are late too much; drop 10 ticks
          wakeup_time += 10
          continue
        event.SpamEvent(hookname="timer_hook", 
                        argmap={"tick": self._current_tick}
                       ).enqueue()
        self._current_tick += 1
        wakeup_time += 1
      except KeyboardInterrupt:
        return
      except SystemExit:
        return
      except:
        exported.write_traceback("ticker: ticker hiccupped.")
Ejemplo n.º 6
0
def unload_cmd(ses, args, input):
  """
  Unloads a module from Lyntin by calling the module's "unload" function
  and then removing references to it in the Python environment.

  examples:
    #unload wbgscheduler
    #unload modules.alias

  category: commands
  """
  mod = args["modulename"]

  if sys.modules.has_key(mod):
    _module = sys.modules[mod]

    if _module.__dict__.has_key("lyntin_import"):
      if _module.__dict__.has_key("unload"):
        try:
          _module.unload()
        except:
          exported.write_traceback("unload: module %s didn't unload properly." % mod)
      else:
        exported.write_error("unload: module %s doesn't have an unload function." % mod)

      del sys.modules[mod]
      exported.write_message("unload: module %s unloaded." % mod)
      config.lyntinmodules.remove(mod)
      return
    else:
      exported.write_error("unload: module %s cannot be unloaded." % mod)
      return

  exported.write_error("unload: module %s is not loaded." % mod)
Ejemplo n.º 7
0
def load_modules():
  """
  Magically dynamically loads all the modules in the modules
  package.  This is truly a semi-magic function.
  """
  # handle modules.*
  _module_list = []
  for loader, name, isPkg in pkgutil.iter_modules(lyntin.modules.__path__):
    _module_list.append(name)
  _module_list.sort()

  for mem in _module_list:
    # we skip over all files that start with a _
    # this allows hackers to be working on a module and not have
    # it die every time.
    mem2 = get_module_name(mem)
    if mem2.startswith("_"):
      continue

    try:
      name = "lyntin.modules." + mem2
      _module = __import__(name)
      _module = sys.modules[name]

      if _module.__dict__.has_key("load"):
        _module.load()

      _module.__dict__["lyntin_import"] = 1
      config.lyntinmodules.append(name)
    except:
      exported.write_traceback("Module '%s' refuses to load." % name)

  # handle modules found in the moduledir
  moduledirlist = config.options["moduledir"]
  if moduledirlist:
    for moduledir in moduledirlist:
      # grab the contents of the moduledir directory
      _module_list = glob.glob( os.path.join( moduledir, "*.py"))

      # toss the moduledir in the sys.path
      sys.path.append(moduledir)

      # and toss all the contents of the directory in our _module_list
      for mem in _module_list:
        mem2 = get_module_name(mem)
        if mem2.startswith("_"):
          continue

        try:
          _module = __import__(mem2)
          if _module.__dict__.has_key("load"):
            _module.load()

          test_for_conflicts(mem, _module)

          _module.__dict__["lyntin_import"] = 1
          config.lyntinmodules.append(mem2)
        except:
          exported.write_traceback("Module '%s' refuses to load." % mem)
Ejemplo n.º 8
0
def clear_cmd(ses, words, input):
  """
  This command clears a session of all session data (except the actual 
  connection).  This covers gags, subs, actions, aliases...

  category: commands
  """
  try:
    ses.clear()
    exported.write_message("clear: session %s cleared." % ses.getName(), ses)
  except Exception, e:
    exported.write_traceback("clear: error in clearing session %s" % ses)
Ejemplo n.º 9
0
def clear_cmd(ses, words, input):
    """
  This command clears a session of all session data (except the actual 
  connection).  This covers gags, subs, actions, aliases...

  category: commands
  """
    try:
        ses.clear()
        exported.write_message("clear: session %s cleared." % ses.getName(),
                               ses)
    except Exception, e:
        exported.write_traceback("clear: error in clearing session %s" % ses)
Ejemplo n.º 10
0
    def timeUpdate(self, args):
        """
    This gets called by the timer_hook in the engine every
    second.  It goes through and executes all the events for this
    Lyntin tick as well as events who are supposed to execute at
    this seconds since the epoch or before.

    It also handles tossing events back in the schedule if they
    need repeating.
    """
        tick = args["tick"]

        events = []

        if self._events.has_key(tick):
            for mem in self._events[tick]:
                events.append(mem)

            del self._events[tick]

        self._current_tick = tick

        # we want to execute for this second and any previous seconds
        # that have been missed.
        sec = int(time.time())
        keys = self._tevents.keys()
        keys = [mem for mem in keys if mem < sec]
        for key in keys:
            for mem in self._tevents[key]:
                events.append(mem)
            del self._tevents[key]

        # go through and execute all the events we've found
        for mem in events:
            if not mem._quiet:
                exported.write_message("Executing %r." % mem)

            if not callable(mem._cmd):
                exported.lyntin_command(mem._cmd, internal=1, session=mem._ses)
            else:
                try:
                    mem._cmd(*mem._args, **mem._xargs)
                except:
                    exported.write_traceback(
                        "exception kicked up while trying to execute event.")

            # handles repeating events
            if mem._repeat == 1:
                self.addEvent(tick + mem._offset, mem, id=mem._id)
Ejemplo n.º 11
0
  def timeUpdate(self, args):
    """
    This gets called by the timer_hook in the engine every
    second.  It goes through and executes all the events for this
    Lyntin tick as well as events who are supposed to execute at
    this seconds since the epoch or before.

    It also handles tossing events back in the schedule if they
    need repeating.
    """
    tick = args["tick"]

    events = []

    if self._events.has_key(tick):
      for mem in self._events[tick]:
        events.append(mem)

      del self._events[tick]

    self._current_tick = tick

    # we want to execute for this second and any previous seconds
    # that have been missed.
    sec = int(time.time())
    keys = self._tevents.keys()
    keys = [mem for mem in keys if mem < sec]
    for key in keys:
      for mem in self._tevents[key]:
        events.append(mem)
      del self._tevents[key]

    # go through and execute all the events we've found
    for mem in events:
      if not mem._quiet:
        exported.write_message("Executing %r." % mem)

      if not callable(mem._cmd):
        exported.lyntin_command(mem._cmd, internal=1, session=mem._ses)
      else:
        try:
          mem._cmd(*mem._args, **mem._xargs)
        except:
          exported.write_traceback("exception kicked up while trying to execute event.")

      # handles repeating events
      if mem._repeat == 1:
        self.addEvent(tick + mem._offset, mem, id=mem._id)
Ejemplo n.º 12
0
def write_cmd(ses, args, input):
    """
  Writes all aliases, actions, gags, etc to the file specified.
  You can then use the #read command to read this file in and
  restore your session settings.

  The quiet argument lets you specify whether you want command data
  to be written to the file so that when you read it back in with #read,
  the commands are executed quietly.

  If you don't specify a directory, it will be written to your datadir.

  Note: Windows users should either use two \\'s or use / to separate
  directory names.

  category: commands
  """
    filename = args["file"]
    quiet = args["quiet"]

    f = None

    c = exported.myengine.getConfigManager().get("commandchar")

    if os.sep not in filename:
        filename = config.options["datadir"] + filename

    data = exported.get_write_data(ses, quiet)

    if data:
        try:
            f = open(filename, "w")
            to_encode = c + (u"\n" + c).join(data)
            f.write(to_encode.encode("utf-8"))
            f.close()
            exported.write_message(
                "write: file %s has been written for session %s." %
                (filename, ses.getName()), ses)
        except Exception:
            exported.write_traceback(
                "write: error writing to file %s." % filename, ses)
            try:
                f.close()
            except:
                pass
        return

    exported.write_message("write: no data to write.")
Ejemplo n.º 13
0
def write_cmd(ses, args, input):
  """
  Writes all aliases, actions, gags, etc to the file specified.
  You can then use the #read command to read this file in and
  restore your session settings.

  The quiet argument lets you specify whether you want command data
  to be written to the file so that when you read it back in with #read,
  the commands are executed quietly.

  If you don't specify a directory, it will be written to your datadir.

  Note: Windows users should either use two \\'s or use / to separate
  directory names.

  category: commands
  """
  filename = args["file"]
  quiet = args["quiet"]

  f = None

  c = exported.myengine.getConfigManager().get("commandchar")

  if os.sep not in filename:
    filename = config.options["datadir"] + filename

  data = exported.get_write_data(ses, quiet)

  if data:
    try:
      f = open(filename, "w")
      f.write(c + ("\n" + c).join(data))
      f.close()
      exported.write_message("write: file %s has been written for session %s." % 
                             (filename, ses.getName()), ses)
    except Exception:
      exported.write_traceback("write: error writing to file %s." % filename, ses)
      try:
        f.close()
      except:
        pass
    return

  exported.write_message("write: no data to write.")
Ejemplo n.º 14
0
 def runengine(self):
     """
 This gets kicked off in a thread and just keep going through
 events until it detects a shutdown.
 """
     while not self._shutdownflag:
         try:
             # blocks on the event queue
             e = self._event_queue.get()
             e.execute()
         except KeyboardInterrupt:
             return
         except SystemExit:
             return
         except:
             self.tallyError()
             exported.write_traceback("engine: unhandled error in engine.")
         self._num_events_processed += 1
Ejemplo n.º 15
0
 def runengine(self):
   """
   This gets kicked off in a thread and just keep going through
   events until it detects a shutdown.
   """
   while not self._shutdownflag:
     try:
       # blocks on the event queue
       e = self._event_queue.get()
       e.execute()
     except KeyboardInterrupt:
       return
     except SystemExit:
       return
     except:
       self.tallyError()
       exported.write_traceback("engine: unhandled error in engine.")
     self._num_events_processed += 1
Ejemplo n.º 16
0
    def run(self):
        """ This is the poll loop for user input."""
        try:
            while not self.shutdownflag:
                if os.name == 'posix':
                    if self._rline == 1:
                        data = self._posix_readline_input()
                    else:
                        data = self._posix_input()
                else:
                    data = self._non_posix_input()

                if data != None:
                    self.handleinput(data)

                    # FIXME - this is just plain icky.  the issue is that
                    # we need to know we're ending _before_ we block for
                    # the next input.  otherwise Lyntin will shut down except
                    # for this thread which will hang around blocking until
                    # the user hits the enter key.
                    #
                    # any good ideas for dealing with this are more than welcome.
                    if data.find("#end") == 0:
                        break

        except select.error as e:
            (errno, name) = e
            if errno == 4:
                exported.write_message("system exit: select.error.")
                event.ShutdownEvent().enqueue()
                return

        except SystemExit:
            exported.write_message("system exit: you'll be back...")
            event.ShutdownEvent().enqueue()

        except:
            exported.write_traceback()
            event.ShutdownEvent().enqueue()
Ejemplo n.º 17
0
  def log(self, input):
    """
    Logs text to a file instance self._logfile and optionally
    filters ansi according to self._strip_ansi.

    @param input: the string to log to the logfile for this session
    @type  input: string
    """
    if self._logfile == None:
      return

    try:
      if self._strip_ansi == 1:
        input = ansi.filter_ansi(input)

      text = utils.filter_cm(input)
      text = text.replace("\n", os.linesep)
      self._logfile.write(text)
      self._logfile.flush()
    except:
      self._logfile = None
      exported.write_traceback("Logfile cannot be written to.", self._session)
Ejemplo n.º 18
0
def unload_cmd(ses, args, input):
    """
  Unloads a module from Lyntin by calling the module's "unload" function
  and then removing references to it in the Python environment.

  examples:
    #unload wbgscheduler
    #unload modules.alias

  category: commands
  """
    mod = args["modulename"]

    if mod in sys.modules:
        _module = sys.modules[mod]

        if "lyntin_import" in _module.__dict__:
            if "unload" in _module.__dict__:
                try:
                    _module.unload()
                except:
                    exported.write_traceback(
                        "unload: module %s didn't unload properly." % mod)
            else:
                exported.write_error(
                    "unload: module %s doesn't have an unload function." % mod)

            del sys.modules[mod]
            exported.write_message("unload: module %s unloaded." % mod)
            config.lyntinmodules.remove(mod)
            return
        else:
            exported.write_error("unload: module %s cannot be unloaded." % mod)
            return

    exported.write_error("unload: module %s is not loaded." % mod)
Ejemplo n.º 19
0
def python_cmd(ses, words, input):
    """
  #@ allows you to execute arbitrary Python code inside of Lyntin.
  It will first look for a module named "lyntinuser" and execute
  the code inside that module's __dict__ environment.  If no
  such module exists, it will execute the code inside 
  modules.advanced .  At present it can only handle one-line
  Python statements.

  examples:
    #@ print "hello"
    #@ print "\\n".join(exported.get_commands())

  category: commands
  """
    global execdictglobals, execdictlocals

    # NOTE: if we ever get to handling multiple-lines, we'll need
    # to change this function completely.

    try:
        if execdictlocals == None:
            execdictlocals = {}

        execdictlocals["session"] = ses
        execdictlocals["exported"] = exported

        my_usermodule = _get_user_module()
        if my_usermodule:
            dictglobals = my_usermodule.__dict__
        else:
            if execdictglobals == None:
                execdictglobals = {}
                exported.write_error(
                    "No lyntinuser module loaded--executing with no context.")
            dictglobals = execdictglobals

        source = input[1:].lstrip()
        compiled = compile_command(source)

        #
        # XXX for one-liners only:
        #
        if not compiled:
            compiled = compile_command(source + "\n")

        old_stdout = sys.stdout
        old_stderr = sys.stderr
        old_stdin = sys.stdin
        sys_stdout = io.StringIO()
        sys_stderr = io.StringIO()
        sys_stdin = io.StringIO()
        try:
            sys.stdout = sys_stdout
            sys.stderr = sys_stderr
            sys.stdin = sys_stdin

            exec(compiled, dictglobals, execdictlocals)

        finally:
            sys.stdout = old_stdout
            sys.stderr = old_stderr
            sys.stdin = old_stdin

        error = sys_stderr.getvalue()
        if error:
            exported.write_error(error)

        text = sys_stdout.getvalue()
        if text.endswith("\n"):
            text = text[:-1]
        if text:
            exported.write_message(text)

    except (OverflowError, SyntaxError, ValueError, NameError):
        import traceback
        exported.write_error("".join(
            traceback.format_exception_only(*(sys.exc_info()[:2]))))

    except:
        exported.write_traceback("@: error in raw python stuff.")
        exported.tally_error()
Ejemplo n.º 20
0
def load_cmd(ses, args, input):
    """
  Loads/reloads a module.

  When reloading, it looks for an "unload" function and executes 
  it prior to reloading the module.  After reloading/loading, it 
  looks for a "load" function and executes it.

  Lyntin modules located in the modules package are safe to reload 
  in-game.  Lyntin core modules (engine, helpmanager, event...) are
  NOT safe to import in-game.

  examples:
    #load modules.action
    #load exportuser

  #load will look for the module on the sys.path.  So if your module
  is not on the sys.path, you should first add the directory using #@:

    #@ import sys
    #@ sys.path.append("/directory/where/my/module/exists")

  Directories specified by the moduledir command-line argument are
  added to the sys.path upon Lyntin startup.

  category: commands
  """
    mod = args["modulename"]
    reload = args["reload"]

    # if this module has previously been loaded, we try to reload it.
    if mod in sys.modules:

        _module = sys.modules[mod]
        _oldmodule = _module
        try:
            if "lyntin_import" in _module.__dict__:
                # if we're told not to reload it, we toss up a message and then
                # do nothing
                if not reload:
                    exported.write_message(
                        "load: module %s has already been loaded." % mod)
                    return

                # if we loaded it via a lyntin_import mechanism and it has an
                # unload method, then we try calling that
                if "unload" in _module.__dict__:
                    try:
                        _module.unload()
                    except:
                        exported.write_traceback(
                            "load: module %s didn't unload properly." % mod)
            del sys.modules[mod]
            exported.write_message("load: reloading %s." % mod)

        except:
            exported.write_traceback("load: had problems unloading %s." % mod)
            return
    else:
        _oldmodule = None

    # here's where we import the module
    try:
        _module = __import__(mod)
        _module = sys.modules[mod]

        if (_oldmodule and "reload" in _oldmodule.__dict__):
            try:
                _oldmodule.reload()
            except:
                exported.write_traceback(
                    "load: had problems calling reload on %s." % mod)

        if ("load" in _module.__dict__):
            _module.load()

        _module.__dict__["lyntin_import"] = 1
        exported.write_message("load successful.")
        if mod not in config.lyntinmodules:
            config.lyntinmodules.append(mod)

    except:
        exported.write_traceback("load: had problems with %s." % mod)
Ejemplo n.º 21
0
  def run(self):
    """
    While the connection hasn't been shut down, we spin through this
    loop retrieving data from the mud,
    """
    from lyntin import exported
    try:
      data = ''
      while not self._shutdownflag:
        newdata = self._pollForData()

        if newdata:
          newdata = self._filterIncomingData(newdata)
          if newdata == "":
            continue

          last_index = 0
          alldata = (data+newdata).replace("\r","")
          # incrementally walk through each line in the data,
          # adjusting last_index to the end of the previous match
          for (m) in self._line_regex.finditer(alldata):
            oneline = alldata[last_index:m.end()]
            last_index = m.end()
            self.handleData(oneline)
          # keep the remainder (empty if alldata ended with a delimiter)
          data = alldata[last_index:]

        elif newdata == '':
          # if we got back an empty string, then something's amiss
          # and we should dump them.
          if data:
            self.handleData(data)
          if self._shutdownflag == 0 and self._session:
            self._session.shutdown(())
          break

        elif not self._good_prompts and data:
          # Now we have rest of the input which is neither delimited prompt
          # nor complete line, and we yet did not see this server
          # delimiting it's prompts with telnet GA or EOR option.
          # We'll handle these data because the socket read was timed out.
          self.handleData(data)
          data = ''

    except SystemExit:
      if self._session:
        self._session.shutdown(())

    except:
      exported.write_traceback("socket exception")
      if self._session:
        self._session.shutdown(())

    # if we hit this point, we want to shut down the socket
    try:    self._sock.shutdown(2)
    except: pass

    try:    self._sock.close()
    except: pass

    self._sock = None
    self._session = None

    # sometimes the mud will hose up with echo off--we want to kick it
    # on again.
    self._config.change("mudecho", "on")

    # output message so the user knows what happened.
    event.OutputEvent(message.Message("Lost connection to: %s\n" % self._host)).enqueue()
Ejemplo n.º 22
0
                    if data.find("#end") == 0:
                        break

        except select.error, e:
            (errno, name) = e
            if errno == 4:
                exported.write_message("system exit: select.error.")
                event.ShutdownEvent().enqueue()
                return

        except SystemExit:
            exported.write_message("system exit: you'll be back...")
            event.ShutdownEvent().enqueue()

        except:
            exported.write_traceback()
            event.ShutdownEvent().enqueue()

    def write(self, args):
        """
    Handles writing information from the mud and/or Lyntin
    to the user.
    """
        msg = args["message"]

        if type(msg) == types.StringType:
            msg = message.Message(msg, message.LTDATA)

        line = msg.data
        ses = msg.session
Ejemplo n.º 23
0
            break


    except select.error, e:
      (errno,name) = e
      if errno == 4:
        exported.write_message("system exit: select.error.")
        event.ShutdownEvent().enqueue()
        return

    except SystemExit:
      exported.write_message("system exit: you'll be back...")
      event.ShutdownEvent().enqueue()

    except:
      exported.write_traceback()
      event.ShutdownEvent().enqueue()


  def write(self, args):
    """
    Handles writing information from the mud and/or Lyntin
    to the user.
    """
    msg = args["message"]

    if type(msg) == types.StringType:
      msg = message.Message(msg, message.LTDATA)

    line = msg.data
    ses = msg.session
Ejemplo n.º 24
0
def python_cmd(ses, words, input):
  """
  #@ allows you to execute arbitrary Python code inside of Lyntin.
  It will first look for a module named "lyntinuser" and execute
  the code inside that module's __dict__ environment.  If no
  such module exists, it will execute the code inside 
  modules.advanced .  At present it can only handle one-line
  Python statements.

  examples:
    #@ print "hello"
    #@ print "\\n".join(exported.get_commands())

  category: commands
  """
  global execdictglobals, execdictlocals

  # NOTE: if we ever get to handling multiple-lines, we'll need
  # to change this function completely.

  try:
    if execdictlocals == None:
      execdictlocals = {}
      
    execdictlocals["session"] = ses
    execdictlocals["exported"] = exported

    my_usermodule = _get_user_module() 
    if my_usermodule:
      dictglobals = my_usermodule.__dict__
    else:
      if execdictglobals == None:
        execdictglobals = {}
        exported.write_error("No lyntinuser module loaded--executing with no context.")
      dictglobals = execdictglobals

    source = input[1:].lstrip()
    compiled = compile_command(source)

    #
    # XXX for one-liners only:
    #
    if not compiled:
      compiled = compile_command(source+"\n")

    old_stdout = sys.stdout
    old_stderr = sys.stderr
    old_stdin = sys.stdin
    sys_stdout = StringIO.StringIO()
    sys_stderr = StringIO.StringIO()
    sys_stdin = StringIO.StringIO()
    try:
      sys.stdout = sys_stdout
      sys.stderr = sys_stderr
      sys.stdin = sys_stdin
      
      exec compiled in dictglobals, execdictlocals

    finally:
      sys.stdout = old_stdout
      sys.stderr = old_stderr
      sys.stdin = old_stdin
      
    error = sys_stderr.getvalue()
    if error:
      exported.write_error(error)

    text = sys_stdout.getvalue()
    if text.endswith("\n"):
      text = text[:-1]
    if text:  
      exported.write_message(text)  

  except (OverflowError, SyntaxError, ValueError, NameError):
    import traceback
    exported.write_error("".join(traceback.format_exception_only( *(sys.exc_info()[:2]) )))

  except:
    exported.write_traceback("@: error in raw python stuff.")
    exported.tally_error()
Ejemplo n.º 25
0
def main(defaultoptions={}):
  """
  This parses the command line arguments and makes sure they're all valid,
  instantiates a ui, does some setup, spins off an engine thread, and
  goes into the ui's mainloop.

  @param defaultoptions: the boot options to use.  we update the 
      config.options dict with these options--this is the easiest
      way to override the ui, moduledir, datadir, et al from a
      Lyntin run script.
  @type  defaultoptions: dict
  """
  try:
    import sys, os, traceback, ConfigParser
    from lyntin import config, event, utils, exported
    from lyntin.ui import base
    import locale

    locale.setlocale(locale.LC_ALL, '')

    config.options.update(defaultoptions)

    # read through options and arguments
    optlist = utils.parse_args(sys.argv[1:])

    for mem in optlist:
      if mem[0] == '--help':
        print constants.HELPTEXT
        sys.exit(0)

      elif mem[0] == '--version':
        print constants.VERSION
        sys.exit(0)

      elif mem[0] in ["--configuration", "-c"]:
        # ini files OVERRIDE the default options
        # they can provide multiple ini files, but each new
        # ini file will OVERRIDE the contents of the previous ini file
        # where the two files intersect.
        parser = ConfigParser.ConfigParser()
        parser.read([mem[1]])

        newoptions = {}
        for s in parser.sections():
          for o in parser.options(s):
            c = parser.get(s, o).split(",")
            if newoptions.has_key(o):
              newoptions[o] += c
            else:
              newoptions[o] = c
            
        config.options.update(newoptions)

      else:
        opt = mem[0]
        while opt.startswith("-"):
          opt = opt[1:]

        if len(opt) > 0:
          if config.options.has_key(opt):
            if type(config.options[opt]) is list:
              config.options[opt].append(mem[1])
            else:
              config.options[opt] = mem[1]
          else:
            config.options[opt] = [mem[1]]

    for mem in ["datadir", "ui", "commandchar"]:
      if config.options.has_key(mem) and type(config.options[mem]) is list:
        config.options[mem] = config.options[mem][0]

    # if they haven't set the datadir via the command line, then
    # we go see if they have a HOME in their environment variables....
    if not config.options["datadir"]:
      if os.environ.has_key("HOME"):
        config.options["datadir"] = os.environ["HOME"]
    config.options["datadir"] = utils.fixdir(config.options["datadir"])

    def on_shutdown():
      """
      This gets called by the Python interpreter atexit.  The reason
      we do shutdown stuff here is we're more likely to catch things
      here than we are to let everything cycle through the 
      ShutdownEvent.  This should probably get fixed up at some point
      in the future.
      """
      if not hasattr(sys, 'frozen'):
        sys.stderr.write("goodbye.\n")
      #exported.hook_spam("shutdown_hook", {})
    import atexit
    atexit.register(on_shutdown)

    # instantiate the engine
    Engine.instance = Engine()
    exported.myengine = Engine.instance
    Engine.instance._setupConfiguration()

    # instantiate the ui
    uiinstance = None
    try:
      uiname = str(config.options['ui'])
      modulename = uiname + "ui"
      uiinstance = base.get_ui(modulename)
      if not uiinstance:
        raise ValueError("No ui instance.")
    except Exception, e:
      print "Cannot start '%s': %s" % (uiname, e)
      traceback.print_exc()
      sys.exit(0)

    Engine.instance.setUI(uiinstance)

    # do some more silly initialization stuff
    # adds the .lyntinrc file to the readfile list if it exists.
    if config.options["datadir"]:
      lyntinrcfile = config.options["datadir"] + ".lyntinrc"
      if os.path.exists(lyntinrcfile):
        # we want the .lyntinrc file read in first, so then other
        # files can overwrite the contents therein
        config.options['readfile'].insert(0, lyntinrcfile)
  
    # import modules listed in modulesinit
    exported.write_message("Loading Lyntin modules.")
  
    try:
      import lyntin.modules
      lyntin.modules.load_modules()
    except:
      exported.write_traceback("Modules did not load correctly.")
      sys.exit(1)
  
    commandchar = Engine.instance._managers["config"].get("commandchar")

    # handle command files
    for mem in config.options['readfile']:
      exported.write_message("Reading in file " + mem)
      # we have to escape windows os separators because \ has a specific
      # meaning in the argparser
      mem = mem.replace("\\", "\\\\")
      exported.lyntin_command("%sread %s" % (commandchar, mem), internal=1)
  
    # spam the startup hook 
    exported.hook_spam("startup_hook", {})
  
    # we're done initialization!
    exported.write_message(constants.STARTUPTEXT)
    Engine.instance.writePrompt()

    engine_thread = Engine.instance.startthread("engine", Engine.instance.runengine)
    timer_thread = Engine.instance.startthread("timer", Engine.instance.runtimer)
    try:
      Engine.instance._ui.runui()
    finally:
      if not hasattr(sys, 'frozen'):
        sys.stderr.write("Shutting down...")
      event.ShutdownEvent().enqueue()
      engine_thread.join(10)
      timer_thread.join(10)
Ejemplo n.º 26
0
def main(defaultoptions={}):
    """
  This parses the command line arguments and makes sure they're all valid,
  instantiates a ui, does some setup, spins off an engine thread, and
  goes into the ui's mainloop.

  @param defaultoptions: the boot options to use.  we update the 
      config.options dict with these options--this is the easiest
      way to override the ui, moduledir, datadir, et al from a
      Lyntin run script.
  @type  defaultoptions: dict
  """
    try:
        import sys, os, traceback, ConfigParser
        from lyntin import config, event, utils, exported
        from lyntin.ui import base
        import locale

        locale.setlocale(locale.LC_ALL, '')

        config.options.update(defaultoptions)

        # read through options and arguments
        optlist = utils.parse_args(sys.argv[1:])

        for mem in optlist:
            if mem[0] == '--help':
                print constants.HELPTEXT
                sys.exit(0)

            elif mem[0] == '--version':
                print constants.VERSION
                sys.exit(0)

            elif mem[0] in ["--configuration", "-c"]:
                # ini files OVERRIDE the default options
                # they can provide multiple ini files, but each new
                # ini file will OVERRIDE the contents of the previous ini file
                # where the two files intersect.
                parser = ConfigParser.ConfigParser()
                parser.read([mem[1]])

                newoptions = {}
                for s in parser.sections():
                    for o in parser.options(s):
                        c = parser.get(s, o).split(",")
                        if newoptions.has_key(o):
                            newoptions[o] += c
                        else:
                            newoptions[o] = c

                config.options.update(newoptions)

            else:
                opt = mem[0]
                while opt.startswith("-"):
                    opt = opt[1:]

                if len(opt) > 0:
                    if config.options.has_key(opt):
                        if type(config.options[opt]) is list:
                            config.options[opt].append(mem[1])
                        else:
                            config.options[opt] = mem[1]
                    else:
                        config.options[opt] = [mem[1]]

        for mem in ["datadir", "ui", "commandchar"]:
            if config.options.has_key(mem) and type(
                    config.options[mem]) is list:
                config.options[mem] = config.options[mem][0]

        # if they haven't set the datadir via the command line, then
        # we go see if they have a HOME in their environment variables....
        if not config.options["datadir"]:
            if os.environ.has_key("HOME"):
                config.options["datadir"] = os.environ["HOME"]
        config.options["datadir"] = utils.fixdir(config.options["datadir"])

        def on_shutdown():
            """
      This gets called by the Python interpreter atexit.  The reason
      we do shutdown stuff here is we're more likely to catch things
      here than we are to let everything cycle through the 
      ShutdownEvent.  This should probably get fixed up at some point
      in the future.
      """
            sys.stderr.write("goodbye.\n")
            #exported.hook_spam("shutdown_hook", {})

        import atexit
        atexit.register(on_shutdown)

        # instantiate the engine
        Engine.instance = Engine()
        exported.myengine = Engine.instance
        Engine.instance._setupConfiguration()

        # instantiate the ui
        uiinstance = None
        try:
            uiname = str(config.options['ui'])
            modulename = uiname + "ui"
            uiinstance = base.get_ui(modulename)
            if not uiinstance:
                raise ValueError("No ui instance.")
        except Exception, e:
            print "Cannot start '%s': %s" % (uiname, e)
            traceback.print_exc()
            sys.exit(0)

        Engine.instance.setUI(uiinstance)

        # do some more silly initialization stuff
        # adds the .lyntinrc file to the readfile list if it exists.
        if config.options["datadir"]:
            lyntinrcfile = config.options["datadir"] + ".lyntinrc"
            if os.path.exists(lyntinrcfile):
                # we want the .lyntinrc file read in first, so then other
                # files can overwrite the contents therein
                config.options['readfile'].insert(0, lyntinrcfile)

        # import modules listed in modulesinit
        exported.write_message("Loading Lyntin modules.")

        try:
            import modules.__init__
            modules.__init__.load_modules()
        except:
            exported.write_traceback("Modules did not load correctly.")
            sys.exit(1)

        # spam the startup hook
        exported.hook_spam("startup_hook", {})

        commandchar = Engine.instance._managers["config"].get("commandchar")

        # handle command files
        for mem in config.options['readfile']:
            exported.write_message("Reading in file " + mem)
            # we have to escape windows os separators because \ has a specific
            # meaning in the argparser
            mem = mem.replace("\\", "\\\\")
            exported.lyntin_command("%sread %s" % (commandchar, mem),
                                    internal=1)

        # we're done initialization!
        exported.write_message(constants.STARTUPTEXT)
        Engine.instance.writePrompt()

        engine_thread = Engine.instance.startthread("engine",
                                                    Engine.instance.runengine)
        timer_thread = Engine.instance.startthread("timer",
                                                   Engine.instance.runtimer)
        try:
            Engine.instance._ui.runui()
        finally:
            sys.stderr.write("Shutting down...")
            event.ShutdownEvent().enqueue()
            engine_thread.join(10)
            timer_thread.join(10)
Ejemplo n.º 27
0
  def checkActions(self, text):
    """
    Checks to see if text triggered any actions.  Any resulting 
    actions will get added as an InputEvent to the queue.

    @param text: the data coming from the mud to check for triggers
    @type  text: string
    """
    # FIXME - make sure this works even when lines are broken up.

    actionlist = self._actionlist
    if not actionlist:
      actionlist = filter(lambda x: not self._disabled.has_key(x[6]),
                          self._actions.values())
      actionlist.sort(key=lambda i: i[3])
      self._actionlist = actionlist

    colorline = utils.filter_cm(text)
    nocolorline = ansi.filter_ansi(colorline)

    # go through all the lines in the data and see if we have
    # any matches
    for (action, actioncompiled, response, color, priority, onetime, tag) in actionlist:
      if color:
        match = actioncompiled.search(colorline)
        line = colorline
      else:
        match = actioncompiled.search(nocolorline)
        line = nocolorline

      if match:
        # for every match we figure out what the expanded response
        # is and add it as an InputEvent in the queue.  the reason
        # we do a series of separate events rather than one big
        # event with ; separators is due to possible issues with 
        # braces and such in malformed responses.

        # fill in values for all the variables in the match
        varvals = {}
        if match.lastindex is not None:
          if action.startswith('r['):
            for i in xrange(match.lastindex):
              varvals[str(i+1)] = match.group(i+1)
          else:
            # get variables from the action
            actionvars = get_ordered_vars(action)
            for i in xrange(len(actionvars)):
              varvals[actionvars[i]] = match.group(i+1)

        # add special variables
        varvals['a'] = line.replace(';', '_')
            
        # fill in response variables from those that
        # matched on the trigger
        response = utils.expand_vars(response, varvals)

        # event.InputEvent(response, internal=1, ses=self._ses).enqueue()
        try:
          exported.lyntin_command(response, internal=1, session=self._ses)
        except:
          exported.write_traceback()

        if onetime and self._actions.has_key(action):
          del self._actions[action]
          self._actionlist = None           # invalidate the list
Ejemplo n.º 28
0
def action_cmd(ses, args, input):
  """
  With no trigger, no action and no tag, prints all actions.
  With no trigger and no action, prints all actions with given tag.
  With a trigger and no action, prints actions that match the
  trigger statement.
  With a trigger and an action, creates an action.

  When data from the mud matches the trigger clause, the response
  will be executed.  Trigger clauses can use anchors (^ and $)
  to anchor the text to the beginning and end of the line 
  respectively.

  Triggers can also contain Lyntin pattern-variables which start
  with a % sign and have digits: %0, %1, %10...  When Lyntin sees 
  a pattern-variable in an action trigger, it tries to match any 
  pattern against it, and saves any match it finds so you can 
  use it in the response.  See below for examples.

  Note: As a note, actions are matched via regular expressions.
  %1 gets translated to (.+?) and %_1 gets translated to (\S+?).
  The special variable "%a" means "the whole matched line".

  We handle regular expressions with a special r[ ... ] syntax.  If
  you put an "i" or "I" after the ], then we'll ignorecase as well.

  The onetime argument can be set to true to have the action remove
  itself automatically after it is triggered.

  examples:
    #action {^You are hungry} {get bread bag;eat bread}
    #action {%0 gives you %5} {say thanks for the %5, %0!}
    #action {r[^%_1 tells\\s+you %2$]} {say %1 just told me %2}
    #action {r[sven dealt .+? to %1$]i} {say i just killed %1!}

  see also: unaction, enable, disable, atags
  
  category: commands
  """
  trigger = args["trigger"]
  action = args["action"]
  color = args["color"]
  priority = args["priority"]
  onetime = args["onetime"]
  quiet = args["quiet"]
  tag = args["tag"]

  am = exported.get_manager("action")
  ad = am.getActionData(ses)

  # they typed '#action'--print out all the current actions
  if not action:
    data = ad.getInfo(trigger, tag)
    if not data:
      data = ["action: no actions defined."]

    message = "actions"
    if tag:
      message += " with tag={%s}" % tag
      data += ad.getDisabledInfo(tag)
    exported.write_message(message + "\n" + "\n".join(data), ses)
    return

  try:
    ad.addAction(trigger, action, color, priority, onetime, tag)
    if not quiet:
      exported.write_message("action: {%s} {%s} color={%d} priority={%d} tag={%s} added." % (trigger, action, color, priority, str(tag)), ses)
  except:
    exported.write_traceback("action: exception thrown.", ses)
Ejemplo n.º 29
0
def load_cmd(ses, args, input):
  """
  Loads/reloads a module.

  When reloading, it looks for an "unload" function and executes 
  it prior to reloading the module.  After reloading/loading, it 
  looks for a "load" function and executes it.

  Lyntin modules located in the modules package are safe to reload 
  in-game.  Lyntin core modules (engine, helpmanager, event...) are
  NOT safe to import in-game.

  examples:
    #load modules.action
    #load exportuser

  #load will look for the module on the sys.path.  So if your module
  is not on the sys.path, you should first add the directory using #@:

    #@ import sys
    #@ sys.path.append("/directory/where/my/module/exists")

  Directories specified by the moduledir command-line argument are
  added to the sys.path upon Lyntin startup.

  category: commands
  """
  mod = args["modulename"]
  reload = args["reload"]

  # if this module has previously been loaded, we try to reload it.
  if sys.modules.has_key(mod):

    _module = sys.modules[mod]
    _oldmodule = _module
    try:
      if _module.__dict__.has_key("lyntin_import"):
        # if we're told not to reload it, we toss up a message and then
        # do nothing
        if not reload:
          exported.write_message("load: module %s has already been loaded." % mod)
          return

        # if we loaded it via a lyntin_import mechanism and it has an
        # unload method, then we try calling that
        if _module.__dict__.has_key("unload"):
          try:
            _module.unload()
          except:
            exported.write_traceback("load: module %s didn't unload properly." % mod)
      del sys.modules[mod]
      exported.write_message("load: reloading %s." % mod)

    except:
      exported.write_traceback("load: had problems unloading %s." % mod)
      return
  else:
    _oldmodule = None


  # here's where we import the module
  try:
    _module = __import__( mod )
    _module = sys.modules[mod]

    if (_oldmodule and _oldmodule.__dict__.has_key("reload")):
      try:
        _oldmodule.reload()
      except:
        exported.write_traceback("load: had problems calling reload on %s." % mod)
    
    if (_module.__dict__.has_key("load")):
      _module.load()

    _module.__dict__["lyntin_import"] = 1
    exported.write_message("load successful.")
    if mod not in config.lyntinmodules:
      config.lyntinmodules.append(mod)

  except:
    exported.write_traceback("load: had problems with %s." % mod)
Ejemplo n.º 30
0
def session_cmd(ses, args, input):
  """
  This command creates a connection to a specific mud.  When you create
  a session, that session becomes the active Lyntin session.

  To create a session to 3k.org named "3k":

    #session 3k www.3k.org 5000

  To create a session and initialize it with commands from a specific
  file:

    #session 3k www.3k.org 5000 /home/david/3k/3k.lyntin

  Then to create another session to another mud:

    #session eto gytje.pvv.unit.no 4000

  Then if 3k was your active session, you could do things on the eto
  session by prepending your command with "#eto ":

    #eto say hello

  or switch to the eto session by typing just "#eto".

  category: commands
  """
  name = args["sessionname"]
  host = args["host"]
  port = args["port"]
  filename = args["filename"]

  if not name and not host and (not port or port == -1):
    data = "Sessions available:\n"
    for mem in exported.get_active_sessions():
      data += "   %s: %r\n" % (mem.getName(), mem._socket)

    exported.write_message(data[:-1])
    return

  if not name or not host or port == -1:
    exported.write_error("syntax: #session <sesname> <host> <port>")
    return

  if name.isdigit():
    exported.write_error("session: session name cannot be all numbers.")
    return

  e = exported.myengine
  ses = e.getSession(name)

  if ses != None:
    preexistingsession = 1
  else:
    preexistingsession = 0

  if preexistingsession == 1 and ses.isConnected():
    exported.write_error("session: session of that name already exists.")
    return

  try:
    # create and register a session for this connection....
    if ses == None:
      ses = e.createSession(name)

    sock = net.SocketCommunicator(e, ses, host, port)
    ses.setSocketCommunicator(sock)

    ses._host = host
    ses._port = port

    e.changeSession(name)

    # connect to the mud...
    # this might take a while--we block here until this is done.
    sock.connect(host, port, name)

    # start the network thread
    e.startthread("network", sock.run)

  except:
    exported.write_traceback("session: had problems creating the session.")
    ses.setSocketCommunicator(None)

    if preexistingsession == 0:
      try:    e.unregisterSession(ses)
      except: pass

      try:    e.closeSession(name)
      except: pass

  # populate the session using the specified file
  if filename:
    read_cmd(ses, args, '')
Ejemplo n.º 31
0
def load_modules():
    """
  Magically dynamically loads all the modules in the modules
  package.  This is truly a semi-magic function.
  """
    # handle modules.*
    index = __file__.rfind(os.sep)
    if index == -1:
        path = "." + os.sep
    else:
        path = __file__[:index]

    _module_list = glob.glob(os.path.join(path, "*.py"))
    _module_list.sort()

    for mem in _module_list:
        # we skip over all files that start with a _
        # this allows hackers to be working on a module and not have
        # it die every time.
        mem2 = get_module_name(mem)
        if mem2.startswith("_"):
            continue

        try:
            name = "lyntin.modules." + mem2
            _module = __import__(name)
            _module = sys.modules[name]

            if "load" in _module.__dict__:
                _module.load()

            _module.__dict__["lyntin_import"] = 1
            config.lyntinmodules.append(name)
        except:
            exported.write_traceback("Module '%s' refuses to load." % name)

    # handle modules found in the moduledir
    moduledirlist = config.options["moduledir"]
    if moduledirlist:
        for moduledir in moduledirlist:
            # grab the contents of the moduledir directory
            _module_list = glob.glob(os.path.join(moduledir, "*.py"))

            # toss the moduledir in the sys.path
            sys.path.append(moduledir)

            # and toss all the contents of the directory in our _module_list
            for mem in _module_list:
                mem2 = get_module_name(mem)
                if mem2.startswith("_"):
                    continue

                try:
                    _module = __import__(mem2)
                    if "load" in _module.__dict__:
                        _module.load()

                    test_for_conflicts(mem, _module)

                    _module.__dict__["lyntin_import"] = 1
                    config.lyntinmodules.append(mem2)
                except:
                    exported.write_traceback("Module '%s' refuses to load." %
                                             mem)
Ejemplo n.º 32
0
def action_cmd(ses, args, input):
    """
  With no trigger, no action and no tag, prints all actions.
  With no trigger and no action, prints all actions with given tag.
  With a trigger and no action, prints actions that match the
  trigger statement.
  With a trigger and an action, creates an action.

  When data from the mud matches the trigger clause, the response
  will be executed.  Trigger clauses can use anchors (^ and $)
  to anchor the text to the beginning and end of the line 
  respectively.

  Triggers can also contain Lyntin pattern-variables which start
  with a % sign and have digits: %0, %1, %10...  When Lyntin sees 
  a pattern-variable in an action trigger, it tries to match any 
  pattern against it, and saves any match it finds so you can 
  use it in the response.  See below for examples.

  Note: As a note, actions are matched via regular expressions.
  %1 gets translated to (.+?) and %_1 gets translated to (\S+?).
  The special variable "%a" means "the whole matched line".

  We handle regular expressions with a special r[ ... ] syntax.  If
  you put an "i" or "I" after the ], then we'll ignorecase as well.

  The onetime argument can be set to true to have the action remove
  itself automatically after it is triggered.

  examples:
    #action {^You are hungry} {get bread bag;eat bread}
    #action {%0 gives you %5} {say thanks for the %5, %0!}
    #action {r[^%_1 tells\\s+you %2$]} {say %1 just told me %2}
    #action {r[sven dealt .+? to %1$]i} {say i just killed %1!}

  see also: unaction, enable, disable, atags
  
  category: commands
  """
    trigger = args["trigger"]
    action = args["action"]
    color = args["color"]
    priority = args["priority"]
    onetime = args["onetime"]
    quiet = args["quiet"]
    tag = args["tag"]

    am = exported.get_manager("action")
    ad = am.getActionData(ses)

    # they typed '#action'--print out all the current actions
    if not action:
        data = ad.getInfo(trigger, tag)
        if not data:
            data = ["action: no actions defined."]

        message = "actions"
        if tag:
            message += " with tag={%s}" % tag
            data += ad.getDisabledInfo(tag)
        exported.write_message(message + "\n" + "\n".join(data), ses)
        return

    try:
        ad.addAction(trigger, action, color, priority, onetime, tag)
        if not quiet:
            exported.write_message(
                "action: {%s} {%s} color={%d} priority={%d} tag={%s} added." %
                (trigger, action, color, priority, str(tag)), ses)
    except:
        exported.write_traceback("action: exception thrown.", ses)
Ejemplo n.º 33
0
def session_cmd(ses, args, input):
    """
  This command creates a connection to a specific mud.  When you create
  a session, that session becomes the active Lyntin session.

  To create a session to 3k.org named "3k":

    #session 3k www.3k.org 5000

  To create a session and initialize it with commands from a specific
  file:

    #session 3k www.3k.org 5000 /home/david/3k/3k.lyntin

  Then to create another session to another mud:

    #session eto gytje.pvv.unit.no 4000

  Then if 3k was your active session, you could do things on the eto
  session by prepending your command with "#eto ":

    #eto say hello

  or switch to the eto session by typing just "#eto".

  category: commands
  """
    name = args["sessionname"]
    host = args["host"]
    port = args["port"]
    filename = args["filename"]

    if not name and not host and (not port or port == -1):
        data = "Sessions available:\n"
        for mem in exported.get_active_sessions():
            data += "   %s: %r\n" % (mem.getName(), mem._socket)

        exported.write_message(data[:-1])
        return

    if not name or not host or port == -1:
        exported.write_error("syntax: #session <sesname> <host> <port>")
        return

    if name.isdigit():
        exported.write_error("session: session name cannot be all numbers.")
        return

    e = exported.myengine
    ses = e.getSession(name)

    if ses != None:
        preexistingsession = 1
    else:
        preexistingsession = 0

    if preexistingsession == 1 and ses.isConnected():
        exported.write_error("session: session of that name already exists.")
        return

    try:
        # create and register a session for this connection....
        if ses == None:
            ses = e.createSession(name)

        sock = net.SocketCommunicator(e, ses, host, port)
        ses.setSocketCommunicator(sock)

        ses._host = host
        ses._port = port

        e.changeSession(name)

        # connect to the mud...
        # this might take a while--we block here until this is done.
        sock.connect(host, port, name)

        # start the network thread
        e.startthread("network", sock.run)

    except:
        exported.write_traceback("session: had problems creating the session.")
        ses.setSocketCommunicator(None)

        if preexistingsession == 0:
            try:
                e.unregisterSession(ses)
            except:
                pass

            try:
                e.closeSession(name)
            except:
                pass

    # populate the session using the specified file
    if filename:
        read_cmd(ses, args, '')