Beispiel #1
0
def _shared_login(request):
    """
    Handle the shared login between website and webclient.

    """
    csession = request.session
    account = request.user
    website_uid = csession.get("website_authenticated_uid", None)
    webclient_uid = csession.get("webclient_authenticated_uid", None)

    if not csession.session_key:
        # this is necessary to build the sessid key
        csession.save()

    if account.is_authenticated():
        # Logged into website
        if not website_uid:
            # fresh website login (just from login page)
            csession["website_authenticated_uid"] = account.id
            if webclient_uid is None:
                # auto-login web client
                csession["webclient_authenticated_uid"] = account.id

    elif webclient_uid:
        # Not logged into website, but logged into webclient
        if not website_uid:
            csession["website_authenticated_uid"] = account.id
            account = AccountDB.objects.get(id=webclient_uid)
            try:
                # calls our custom authenticate, in web/utils/backend.py
                authenticate(autologin=account)
                login(request, account)
            except AttributeError:
                logger.log_trace()
Beispiel #2
0
    def stop(self, kill=False):
        """
        Called to stop the script from running.  This also deletes the
        script.

        Args:
            kill (bool, optional): - Stop the script without
                calling any relevant script hooks.

        Returns:
            result (int): 0 if the script failed to stop, 1 otherwise.
                Used in counting.

        """
        if not kill:
            try:
                self.at_stop()
            except Exception:
                logger.log_trace()
        self._stop_task()
        try:
            self.delete()
        except AssertionError:
            logger.log_trace()
            return 0
        return 1
Beispiel #3
0
    def open_parent_menu(self):
        """Open the parent menu, using `self.parents`.

        Note:
            You probably don't need to call this method directly,
            since the caller can go back to the parent menu using the
            `keys_go_back` automatically.

        """
        parents = list(self.parents)
        if parents:
            parent_class, parent_obj, parent_keys = parents[-1]
            del parents[-1]

            if self.caller.cmdset.has(BuildingMenuCmdSet):
                self.caller.cmdset.remove(BuildingMenuCmdSet)

            try:
                menu_class = class_from_module(parent_class)
            except Exception:
                log_trace("BuildingMenu: attempting to load class {} failed".format(
                    repr(parent_class)))
                return

            # Create the parent menu
            try:
                building_menu = menu_class(self.caller, parent_obj,
                                           keys=parent_keys, parents=tuple(parents))
            except Exception:
                log_trace("An error occurred while creating building menu {}".format(
                    repr(parent_class)))
                return
            else:
                return building_menu.open()
Beispiel #4
0
    def start(self, force_restart=False):
        """
        Called every time the script is started (for persistent
        scripts, this is usually once every server start)

        Args:
            force_restart (bool, optional): Normally an already
                started script will not be started again. if
                `force_restart=True`, the script will always restart
                the script, regardless of if it has started before.

        Returns:
            result (int): 0 or 1 depending on if the script successfully
                started or not. Used in counting.

        """
        if self.is_active and not force_restart:
            # The script is already running, but make sure we have a _task if this is after a cache flush
            if not self.ndb._task and self.db_interval >= 0:
                self.ndb._task = ExtendedLoopingCall(self._step_task)
                try:
                    start_delay, callcount = SCRIPT_FLUSH_TIMERS[self.id]
                    del SCRIPT_FLUSH_TIMERS[self.id]
                    now = False
                except (KeyError, ValueError, TypeError):
                    now = not self.db_start_delay
                    start_delay = None
                    callcount = 0
                self.ndb._task.start(self.db_interval, now=now, start_delay=start_delay, count_start=callcount)
            return 0

        obj = self.obj
        if obj:
            # check so the scripted object is valid and initalized
            try:
                obj.cmdset
            except AttributeError:
                # this means the object is not initialized.
                logger.log_trace()
                self.is_active = False
                return 0

        # try to restart a paused script
        try:
            if self.unpause(manual_unpause=False):
                return 1
        except RuntimeError:
            # manually paused.
            return 0

        # start the script from scratch
        self.is_active = True
        try:
            self.at_start()
        except Exception:
            logger.log_trace()

        if self.db_interval > 0:
            self._start_task()
        return 1
Beispiel #5
0
    def dataReceived(self, data):
        """
        This method will split the incoming data depending on if it
        starts with IAC (a telnet command) or not. All other data will
        be handled in line mode. Some clients also sends an erroneous
        line break after IAC, which we must watch out for.

        OOB protocols (MSDP etc) already intercept subnegotiations
        on their own, never entering this method. They will relay
        their parsed data directly to self.data_in.

        """

        if data and data[0] == IAC or self.iaw_mode:
            try:
                #print "IAC mode"
                super(TelnetProtocol, self).dataReceived(data)
                if len(data) == 1:
                    self.iaw_mode = True
                else:
                    self.iaw_mode = False
                return
            except Exception, err1:
                conv = ""
                try:
                    for b in data:
                        conv += " " + repr(ord(b))
                except Exception, err2:
                    conv = str(err2) + ":", str(data)
                out = "Telnet Error (%s): %s (%s)" % (err1, data, conv)
                logger.log_trace(out)
                return
Beispiel #6
0
    def dataReceived(self, data):
        """
        Handle incoming data over the wire.

        This method will split the incoming data depending on if it
        starts with IAC (a telnet command) or not. All other data will
        be handled in line mode. Some clients also sends an erroneous
        line break after IAC, which we must watch out for.

        Args:
            data (str): Incoming data.

        Notes:
            OOB protocols (MSDP etc) already intercept subnegotiations on
            their own, never entering this method. They will relay their
            parsed data directly to self.data_in.

        """
        if data and data[0] == IAC or self.iaw_mode:
            try:
                super(TelnetProtocol, self).dataReceived(data)
                if len(data) == 1:
                    self.iaw_mode = True
                else:
                    self.iaw_mode = False
                return
            except Exception as err1:
                conv = ""
                try:
                    for b in data:
                        conv += " " + repr(ord(b))
                except Exception as err2:
                    conv = str(err2) + ":", str(data)
                out = "Telnet Error (%s): %s (%s)" % (err1, data, conv)
                logger.log_trace(out)
                return

        if data and data.strip() == NULL:
            # This is an ancient type of keepalive still used by some
            # legacy clients. There should never be a reason to send
            # a lone NULL character so this seems ok to support for
            # backwards compatibility.
            data = _IDLE_COMMAND

        if self.no_lb_mode and _RE_LEND.search(data):
            # we are in no_lb_mode and receive a line break;
            # this means we should empty the buffer and send
            # the command.
            data = "".join(self.line_buffer) + data
            data = data.rstrip("\r\n") + "\n"
            self.line_buffer = []
            self.no_lb_mode = False
        elif not _RE_LEND.search(data):
            # no line break at the end of the command, buffer instead.
            self.line_buffer.append(data)
            self.no_lb_mode = True
            return

        # if we get to this point the command should end with a linebreak.
        StatefulTelnetProtocol.dataReceived(self, data)
Beispiel #7
0
    def unpause(self, manual_unpause=True):
        """
        Restart a paused script. This WILL call the `at_start()` hook.

        Args:
            manual_unpause (bool, optional): This is False if unpause is
                called by the server reload/reset mechanism.
        Returns:
            result (bool): True if unpause was triggered, False otherwise.

        Raises:
            RuntimeError: If trying to automatically resart this script
                (usually after a reset/reload), but it was manually paused,
                and so should not the auto-unpaused.

        """
        if not manual_unpause and self.db._manual_pause:
            # if this script was paused manually (by a direct call of pause),
            # it cannot be automatically unpaused (e.g. by a @reload)
            raise RuntimeError
        if self.db._paused_time:
            # only unpause if previously paused
            self.is_active = True

            try:
                self.at_start()
            except Exception:
                logger.log_trace()

            self._start_task()
            return True
Beispiel #8
0
    def _callback(self):
        """
        This will be called repeatedly every `self.interval` seconds.
        `self.subscriptions` contain tuples of (obj, args, kwargs) for
        each subscribing object.

        If overloading, this callback is expected to handle all
        subscriptions when it is triggered. It should not return
        anything and should not traceback on poorly designed hooks.
        The callback should ideally work under @inlineCallbacks so it
        can yield appropriately.

        The _hook_key, which is passed down through the handler via
        kwargs is used here to identify which hook method to call.

        """
        for store_key, (obj, args, kwargs) in self.subscriptions.items():
            hook_key = yield kwargs.pop("_hook_key", "at_tick")
            if not obj or not obj.pk:
                # object was deleted between calls
                self.remove(store_key)
                continue
            try:
                yield _GA(obj, hook_key)(*args, **kwargs)
            except ObjectDoesNotExist:
                log_trace()
                self.remove(store_key)
            except Exception:
                log_trace()
            finally:
                # make sure to re-store
                kwargs["_hook_key"] = hook_key
Beispiel #9
0
    def call_inputfuncs(self, session, **kwargs):
        """
        Split incoming data into its inputfunc counterparts.
        This should be called by the serversession.data_in
        as sessionhandler.call_inputfunc(self, **kwargs).

        We also intercept OOB communication here.

        Args:
            sessions (Session): Session.

        Kwargs:
            kwargs (any): Incoming data from protocol on
                the form `{"commandname": ((args), {kwargs}),...}`

        """

        # distribute incoming data to the correct receiving methods.
        if session:
            input_debug = session.protocol_flags.get("INPUTDEBUG", False)
            for cmdname, (cmdargs, cmdkwargs) in kwargs.iteritems():
                cname = cmdname.strip().lower()
                try:
                    cmdkwargs.pop("options", None)
                    if cname in _INPUT_FUNCS:
                        _INPUT_FUNCS[cname](session, *cmdargs, **cmdkwargs)
                    else:
                        _INPUT_FUNCS["default"](session, cname, *cmdargs, **cmdkwargs)
                except Exception as err:
                    if input_debug:
                        session.msg(err)
                    log_trace()
Beispiel #10
0
def create_help_entry(key, entrytext, category="General", locks=None):
    """
    Create a static help entry in the help database. Note that Command
    help entries are dynamic and directly taken from the __doc__ entries
    of the command. The database-stored help entries are intended for more
    general help on the game, more extensive info, in-game setting information
    and so on.
    """
    global _HelpEntry
    if not _HelpEntry:
        from evennia.help.models import HelpEntry as _HelpEntry

    try:
        new_help = _HelpEntry()
        new_help.key = key
        new_help.entrytext = entrytext
        new_help.help_category = category
        if locks:
            new_help.locks.add(locks)
        new_help.save()
        return new_help
    except IntegrityError:
        string = "Could not add help entry: key '%s' already exists." % key
        logger.log_errmsg(string)
        return None
    except Exception:
        logger.log_trace()
        return None
Beispiel #11
0
    def start_server(self, server_twistd_cmd):
        """
        (Re-)Launch the Evennia server.

        Args:
            server_twisted_cmd (list): The server start instruction
                to pass to POpen to start the server.

        """
        # start the Server
        process = None
        with open(settings.SERVER_LOG_FILE, 'a') as logfile:
            # we link stdout to a file in order to catch
            # eventual errors happening before the Server has
            # opened its logger.
            try:
                if _is_windows():
                    # Windows requires special care
                    create_no_window = 0x08000000
                    process = Popen(server_twistd_cmd, env=getenv(), bufsize=-1,
                                    stdout=logfile, stderr=STDOUT,
                                    creationflags=create_no_window)

                else:
                    process = Popen(server_twistd_cmd, env=getenv(), bufsize=-1,
                                    stdout=logfile, stderr=STDOUT)
            except Exception:
                logger.log_trace()

            self.factory.portal.server_twistd_cmd = server_twistd_cmd
            logfile.flush()
        if process and not _is_windows():
            # avoid zombie-process on Unix/BSD
            process.wait()
        return
Beispiel #12
0
def _shared_login(request):
    """
    Handle the shared login between website and webclient.

    """
    csession = request.session
    account = request.user
    # these can have 3 values:
    #   None - previously unused (auto-login)
    #   False - actively logged out (don't auto-login)
    #   <uid> - logged in User/Account id
    website_uid = csession.get("website_authenticated_uid", None)
    webclient_uid = csession.get("webclient_authenticated_uid", None)

    # check if user has authenticated to website
    if not csession.session_key:
        # this is necessary to build the sessid key
        csession.save()

    if webclient_uid:
        # The webclient has previously registered a login to this browser_session
        if not account.is_authenticated() and not website_uid:
            account = AccountDB.objects.get(id=webclient_uid)
            try:
                # calls our custom authenticate in web/utils/backends.py
                account = authenticate(autologin=account)
                login(request, account)
                csession["website_authenticated_uid"] = webclient_uid
            except AttributeError:
                logger.log_trace()
Beispiel #13
0
    def distribute_message(self, msgobj, online=False):
        """
        Method for grabbing all listeners that a message should be
        sent to on this channel, and sending them a message.

        Args:
            msgobj (Msg or TempMsg): Message to distribute.
            online (bool): Only send to receivers who are actually online
                (not currently used):

        Notes:
            This is also where logging happens, if enabled.

        """
        # get all players or objects connected to this channel and send to them
        for entity in self.subscriptions.all():
            # if the entity is muted, we don't send them a message
            if entity in self.mutelist:
                continue
            try:
                # note our addition of the from_channel keyword here. This could be checked
                # by a custom player.msg() to treat channel-receives differently.
                entity.msg(msgobj.message, from_obj=msgobj.senders, options={"from_channel":self.id})
            except AttributeError as e:
                logger.log_trace("%s\nCannot send msg to '%s'." % (e, entity))

        if msgobj.keep_log:
            # log to file
            logger.log_file(msgobj.message, self.attributes.get("log_file") or "channel_%s.log" % self.key)
Beispiel #14
0
def _shared_login(request):
    """
    Handle the shared login between website and webclient.

    """
    csession = request.session
    player = request.user
    sesslogin = csession.get("logged_in", None)

    # check if user has authenticated to website
    if csession.session_key is None:
        # this is necessary to build the sessid key
        csession.save()
    elif player.is_authenticated():
        if not sesslogin:
            # User has already authenticated to website
            csession["logged_in"] = player.id
    elif sesslogin:
        # The webclient has previously registered a login to this browser_session
        player = PlayerDB.objects.get(id=sesslogin)
        try:
            # calls our custom authenticate in web/utils/backends.py
            player = authenticate(autologin=player)
            login(request, player)
        except AttributeError:
            logger.log_trace()
Beispiel #15
0
    def data_in(self, session, **kwargs):
        """
        Data Portal -> Server.
        We also intercept OOB communication here.

        Args:
            sessions (Session): Session.

        Kwargs:
            kwargs (any): Other data from protocol.

        """

        # distribute incoming data to the correct receiving methods.
        if session:
            input_debug = session.protocol_flags.get("INPUTDEBUG", False)
            for cmdname, (cmdargs, cmdkwargs) in kwargs.iteritems():
                cname = cmdname.strip().lower()
                try:
                    cmdkwargs.pop("options", None)
                    if cname in _INPUT_FUNCS:
                        _INPUT_FUNCS[cname](session, *cmdargs, **cmdkwargs)
                    else:
                        _INPUT_FUNCS["default"](session, cname, *cmdargs, **cmdkwargs)
                except Exception, err:
                    if input_debug:
                        session.msg(err)
                    log_trace()
Beispiel #16
0
    def func(self):
        """This is called when user enters anything."""
        caller = self.caller
        try:
            getinput = caller.ndb._getinput
            if not getinput and hasattr(caller, "account"):
                getinput = caller.account.ndb._getinput
                caller = caller.account
            callback = getinput._callback

            caller.ndb._getinput._session = self.session
            prompt = caller.ndb._getinput._prompt
            args = caller.ndb._getinput._args
            kwargs = caller.ndb._getinput._kwargs
            result = self.raw_string.strip()  # we strip the ending line break caused by sending

            ok = not callback(caller, prompt, result, *args, **kwargs)
            if ok:
                # only clear the state if the callback does not return
                # anything
                del caller.ndb._getinput
                caller.cmdset.remove(InputCmdSet)
        except Exception:
            # make sure to clean up cmdset if something goes wrong
            caller.msg("|rError in get_input. Choice not confirmed (report to admin)|n")
            logger.log_trace("Error in get_input")
            caller.cmdset.remove(InputCmdSet)
Beispiel #17
0
def _create_character(character_key, level, session, new_player, typeclass, home, permissions, nickname):
    """
    Helper function, creates a character based on a player's name.
    This is meant for Guest and MULTISESSION_MODE < 2 situations.
    """
    try:
        new_character = create.create_object(typeclass, key=new_player.key,
                                             home=home, permissions=permissions)

        # set character info
        new_character.set_data_info(character_key)
        new_character.set_level(level)

        # set playable character list
        new_player.db._playable_characters.append(new_character)

        # allow only the character itself and the player to puppet this character (and Immortals).
        new_character.locks.add("puppet:id(%i) or pid(%i) or perm(Immortals) or pperm(Immortals)" %
                                (new_character.id, new_player.id))

        # If no description is set, set a default description
        if not new_character.db.desc:
            new_character.db.desc = "This is a Player."

        # Add nickname
        if not nickname:
            nickname = character_key
        new_character.set_nickname(nickname)
        
        # We need to set this to have @ic auto-connect to this character
        new_player.db._last_puppet = new_character
    except Exception, e:
        session.msg("There was an error creating the Character:\n%s\n If this problem persists, contact an admin." % e)
        logger.log_trace()
        return False
Beispiel #18
0
    def restart(self, interval=None, repeats=None, start_delay=None):
        """
        Restarts an already existing/running Script from the
        beginning, optionally using different settings. This will
        first call the stop hooks, and then the start hooks again.

        Args:
            interval (int, optional): Allows for changing the interval
                of the Script. Given in seconds.  if `None`, will use the
                already stored interval.
            repeats (int, optional): The number of repeats. If unset, will
                use the previous setting.
            start_delay (bool, optional): If we should wait `interval` seconds
                before starting or not. If `None`, re-use the previous setting.

        """
        try:
            self.at_stop()
        except Exception:
            logger.log_trace()
        self._stop_task()
        self.is_active = False
        if interval is not None:
            self.interval = interval
        if repeats is not None:
            self.repeats = repeats
        if start_delay is not None:
            self.start_delay = start_delay
        self.start()
Beispiel #19
0
 def _step_task(self):
     """
     Step task. This groups error handling.
     """
     try:
         return maybeDeferred(self._step_callback).addErrback(self._step_errback)
     except Exception:
         logger.log_trace()
Beispiel #20
0
    def server_receive_adminportal2server(self, packed_data):
        """
        Receives admin data from the Portal (allows the portal to
        perform admin operations on the server). This is executed on
        the Server.

        Args:
            packed_data (str): Incoming, pickled data.

        """
        sessid, kwargs = self.data_in(packed_data)
        operation = kwargs.pop("operation", "")
        server_sessionhandler = self.factory.server.sessions

        try:
            if operation == amp.PCONN:  # portal_session_connect
                # create a new session and sync it
                server_sessionhandler.portal_connect(kwargs.get("sessiondata"))

            elif operation == amp.PCONNSYNC:  # portal_session_sync
                server_sessionhandler.portal_session_sync(kwargs.get("sessiondata"))

            elif operation == amp.PDISCONN:  # portal_session_disconnect
                # session closed from portal sid
                session = server_sessionhandler.get(sessid)
                if session:
                    server_sessionhandler.portal_disconnect(session)

            elif operation == amp.PDISCONNALL:  # portal_disconnect_all
                # portal orders all sessions to close
                server_sessionhandler.portal_disconnect_all()

            elif operation == amp.PSYNC:  # portal_session_sync
                # force a resync of sessions from the portal side. This happens on
                # first server-connect.
                server_restart_mode = kwargs.get("server_restart_mode", "shutdown")
                self.factory.server.run_init_hooks(server_restart_mode)
                server_sessionhandler.portal_sessions_sync(kwargs.get("sessiondata"))

            elif operation == amp.SRELOAD:  # server reload
                # shut down in reload mode
                server_sessionhandler.all_sessions_portal_sync()
                server_sessionhandler.server.shutdown(mode='reload')

            elif operation == amp.SRESET:
                # shut down in reset mode
                server_sessionhandler.all_sessions_portal_sync()
                server_sessionhandler.server.shutdown(mode='reset')

            elif operation == amp.SSHUTD:  # server shutdown
                # shutdown in stop mode
                server_sessionhandler.server.shutdown(mode='shutdown')

            else:
                raise Exception("operation %(op)s not recognized." % {'op': operation})
        except Exception:
            logger.log_trace()
        return {}
Beispiel #21
0
def create_guest_player(session):
    """
    Creates a guest player/character for this session, if one is available.

    Args:
    session (Session): the session which will use the guest player/character.

    Returns:
    GUEST_ENABLED (boolean), player (Player):
    the boolean is whether guest accounts are enabled at all.
    the Player which was created from an available guest name.
    """
    # check if guests are enabled.
    if not settings.GUEST_ENABLED:
        return False, None

    # Check IP bans.
    bans = ServerConfig.objects.conf("server_bans")
    if bans and any(tup[2].match(session.address) for tup in bans if tup[2]):
        # this is a banned IP!
        string = "{rYou have been banned and cannot continue from here." \
            "\nIf you feel this ban is in error, please email an admin.{x"
        session.msg(string)
        session.sessionhandler.disconnect(session, "Good bye! Disconnecting.")
        return True, None

    try:
        # Find an available guest name.
        for playername in settings.GUEST_LIST:
            if not PlayerDB.objects.filter(username__iexact=playername):
                break
                playername = None
            if playername == None:
                session.msg("All guest accounts are in use. Please try again later.")
                return True, None

        password = "******" % getrandbits(64)
        home = ObjectDB.objects.get_id(settings.GUEST_HOME)
        permissions = settings.PERMISSION_GUEST_DEFAULT
        typeclass = settings.BASE_CHARACTER_TYPECLASS
        ptypeclass = settings.BASE_GUEST_TYPECLASS
        new_player = _create_player(session, playername, password,
                                    permissions, ptypeclass)
        if new_player:
            _create_character(GAME_SETTINGS.get("default_player_character_key"), 1, session,
                              new_player, typeclass, home,
                              home, permissions, playername)

    except Exception:
        # We are in the middle between logged in and -not, so we have
        # to handle tracebacks ourselves at this point. If we don't,
        # we won't see any errors at all.
        session.msg("An error occurred. Please e-mail an admin if the problem persists.")
        logger.log_trace()
    finally:
        return True, new_player
Beispiel #22
0
 def load_buffer(self):
     """
     Load the buffer using the load function hook.
     """
     try:
         self._buffer = self._loadfunc(self._caller)
     except Exception as e:
         from evennia.utils import logger
         logger.log_trace()
         self._caller.msg(_ERROR_LOADFUNC.format(error=e))
Beispiel #23
0
 def decorator(*args, **kwargs):
     try:
         func(*args, **kwargs)
     except Exception as err:
         global _LOGGER
         if not _LOGGER:
             from evennia.utils import logger as _LOGGER
         _LOGGER.log_trace()
         raise  # make sure the error is visible on the other side of the connection too
         print(err)
Beispiel #24
0
    def __location_set(self, location):
        "Set location, checking for loops and allowing dbref"
        if isinstance(location, (basestring, int)):
            # allow setting of #dbref
            dbid = dbref(location, reqhash=False)
            if dbid:
                try:
                    location = ObjectDB.objects.get(id=dbid)
                except ObjectDoesNotExist:
                    # maybe it is just a name that happens to look like a dbid
                    pass
        try:
            def is_loc_loop(loc, depth=0):
                "Recursively traverse target location, trying to catch a loop."
                if depth > 10:
                    return
                elif loc == self:
                    raise RuntimeError
                elif loc == None:
                    raise RuntimeWarning
                return is_loc_loop(loc.db_location, depth + 1)
            try:
                is_loc_loop(location)
            except RuntimeWarning:
                pass

            # if we get to this point we are ready to change location

            old_location = self.db_location

            # this is checked in _db_db_location_post_save below
            self._safe_contents_update = True

            # actually set the field (this will error if location is invalid)
            self.db_location = location
            self.save(update_fields=["db_location"])

            # remove the safe flag
            del self._safe_contents_update

            # update the contents cache
            if old_location:
                old_location.contents_cache.remove(self)
            if self.db_location:
                self.db_location.contents_cache.add(self)

        except RuntimeError:
            errmsg = "Error: %s.location = %s creates a location loop." % (self.key, location)
            logger.log_trace(errmsg)
            raise
        except Exception as e:
            errmsg = "Error (%s): %s is not a valid location." % (str(e), location)
            logger.log_trace(errmsg)
            raise
Beispiel #25
0
    def msg(self, text=None, from_obj=None, session=None, **kwargs):
        """
        Emits something to a session attached to the object.

        Args:
            text (str, optional): The message to send
            from_obj (obj, optional): object that is sending. If
                given, at_msg_send will be called
            session (Session or list, optional): Session or list of
                Sessions to relay data to, if any. If set, will
                force send to these sessions. If unset, who receives the
                message depends on the MULTISESSION_MODE.

        Notes:
            `at_msg_receive` will be called on this Object.
            All extra kwargs will be passed on to the protocol.

        """
        # Send messages to the client. Messages are in format of JSON.
        """
        raw = kwargs.get("raw", False)
        if not raw:
            try:
                text = json.dumps(text)
            except Exception, e:
                text = json.dumps({"err": "There is an error occurred while outputing messages."})
                logger.log_errmsg("json.dumps failed: %s" % e)
        else:
            text = to_str(text, force_string=True) if text != None else ""

        # set raw=True
        if kwargs:
            kwargs["raw"] = True
        else:
            kwargs = {"raw": True}
        """

        # try send hooks
        if from_obj:
            try:
                from_obj.at_msg_send(text=text, to_obj=self, **kwargs)
            except Exception:
                logger.log_trace()
        try:
            if not self.at_msg_receive(text=text, **kwargs):
                # if at_msg_receive returns false, we abort message to this object
                return
        except Exception:
            logger.log_trace()
                                                        
        # relay to session(s)
        sessions = make_iter(session) if session else self.sessions.all()
        for session in sessions:
            session.msg(text=text, **kwargs)
Beispiel #26
0
 def _get_channel_cmdsets(player, player_cmdset):
     "Channel-cmdsets"
     # Create cmdset for all player's available channels
     try:
         channel_cmdset = None
         if not player_cmdset.no_channels:
             channel_cmdset = yield CHANNELHANDLER.get_cmdset(player)
         returnValue(channel_cmdset)
     except Exception:
         logger.log_trace()
         _msg_err(caller, _ERROR_CMDSETS)
         raise ErrorReported
Beispiel #27
0
    def restore(self, server_reload=True):
        """
        Restore ticker_storage from database and re-initialize the
        handler from storage. This is triggered by the server at
        restart.

        Args:
            server_reload (bool, optional): If this is False, it means
                the server went through a cold reboot and all
                non-persistent tickers must be killed.

        """
        # load stored command instructions and use them to re-initialize handler
        restored_tickers = ServerConfig.objects.conf(key=self.save_name)
        if restored_tickers:
            # the dbunserialize will convert all serialized dbobjs to real objects

            restored_tickers = dbunserialize(restored_tickers)
            self.ticker_storage = {}
            for store_key, (args, kwargs) in restored_tickers.iteritems():
                try:
                    # at this point obj is the actual object (or None) due to how
                    # the dbunserialize works
                    obj, callfunc, path, interval, idstring, persistent = store_key
                    if not persistent and not server_reload:
                        # this ticker will not be restarted
                        continue
                    if isinstance(callfunc, basestring) and not obj:
                        # methods must have an existing object
                        continue
                    # we must rebuild the store_key here since obj must not be
                    # stored as the object itself for the store_key to be hashable.
                    store_key = self._store_key(obj, path, interval, callfunc, idstring, persistent)

                    if obj and callfunc:
                        kwargs["_callback"] = callfunc
                        kwargs["_obj"] = obj
                    elif path:
                        modname, varname = path.rsplit(".", 1)
                        callback = variable_from_module(modname, varname)
                        kwargs["_callback"] = callback
                        kwargs["_obj"] = None
                    else:
                        # Neither object nor path - discard this ticker
                        log_err("Tickerhandler: Removing malformed ticker: %s" % str(store_key))
                        continue
                except Exception:
                    # this suggests a malformed save or missing objects
                    log_trace("Tickerhandler: Removing malformed ticker: %s" % str(store_key))
                    continue
                # if we get here we should create a new ticker
                self.ticker_storage[store_key] = (args, kwargs)
                self.ticker_pool.add(store_key, *args, **kwargs)
Beispiel #28
0
def _create_player(session, playername, password, permissions, typeclass=None):
    """
    Helper function, creates a player of the specified typeclass.
    """
    try:
        new_player = create.create_player(playername, None, password,
                                          permissions=permissions, typeclass=typeclass)

    except Exception, e:
        session.msg("There was an error creating the Player:\n%s\n If this problem persists, contact an admin." % e)
        logger.log_trace()
        return False
Beispiel #29
0
def mod_import(module):
    """
    A generic Python module loader.

    Args:
        module (str, module): This can be either a Python path
            (dot-notation like `evennia.objects.models`), an absolute path
            (e.g. `/home/eve/evennia/evennia/objects.models.py`) or an
            already imported module object (e.g. `models`)
    Returns:
        module (module or None): An imported module. If the input argument was
        already a module, this is returned as-is, otherwise the path is
        parsed and imported. Returns `None` and logs error if import failed.

    """

    if not module:
        return None

    if isinstance(module, types.ModuleType):
        # if this is already a module, we are done
        mod = module
    else:
        # first try to import as a python path
        try:
            mod = __import__(module, fromlist=["None"])
        except ImportError as ex:
            # check just where the ImportError happened (it could have been
            # an erroneous import inside the module as well). This is the
            # trivial way to do it ...
            if str(ex) != "Import by filename is not supported.":
                raise

            # error in this module. Try absolute path import instead

            if not os.path.isabs(module):
                module = os.path.abspath(module)
            path, filename = module.rsplit(os.path.sep, 1)
            modname = re.sub(r"\.py$", "", filename)

            try:
                result = imp.find_module(modname, [path])
            except ImportError:
                logger.log_trace("Could not find module '%s' (%s.py) at path '%s'" % (modname, modname, path))
                return
            try:
                mod = imp.load_module(modname, *result)
            except ImportError:
                logger.log_trace("Could not find or import module %s at path '%s'" % (modname, path))
                mod = None
            # we have to close the file handle manually
            result[0].close()
    return mod
Beispiel #30
0
 def _get_cmdset(obj):
     "Get cmdset, triggering all hooks"
     try:
         yield obj.at_cmdset_get()
     except Exception:
         logger.log_trace()
         _msg_err(caller, _ERROR_CMDSETS)
         raise ErrorReported
     try:
         returnValue(obj.cmdset.current)
     except AttributeError:
         returnValue(None)
Beispiel #31
0
 def at_start(self):
     """
     This is called once every server restart.
     We reset the up time and load the relevant
     times.
     """
     global SERVER_RUNTIME
     SERVER_RUNTIME = self.attributes.get("run_time")
     #In case of an error loading script from database, we'll check time
     #versus the last saved gametime in the logfile
     try:
         logfile = open(BACKUP_FILE)
         lines = [line.strip() for line in logfile if line[0].isdigit()]
         #get the last recorded time in file
         last_time = float(lines[-1])
         if SERVER_RUNTIME < last_time:
             SERVER_RUNTIME = last_time
     except Exception:
         from evennia.utils import logger
         logger.log_trace()
Beispiel #32
0
    def distribute_message(self, msg, online=False):
        """
        Method for grabbing all listeners that a message should be
        sent to on this channel, and sending them a message.

        msg (str): Message to distribute.
        online (bool): Only send to receivers who are actually online
            (not currently used):

        """
        # get all players connected to this channel and send to them
        for entity in self.subscriptions.all():
            try:
                # note our addition of the from_channel keyword here. This could be checked
                # by a custom player.msg() to treat channel-receives differently.
                entity.msg(msg.message,
                           from_obj=msg.senders,
                           from_channel=self.id)
            except AttributeError, e:
                logger.log_trace("%s\nCannot send msg to '%s'." % (e, entity))
Beispiel #33
0
    def json_decode(self, data):
        """
        Decodes incoming data from the client.

        Args:
            data (JSON): JSON object to unpack.

        Raises:
            Exception: If receiving a malform OOB request.

        Notes:
            [cmdname, [args],{kwargs}] -> cmdname *args **kwargs

        """
        try:
            cmdname, args, kwargs = json.loads(data)
        except Exception:
            log_trace("Websocket malformed OOB request: %s" % data)
            raise
        self.sessionhandler.data_in(self, oob=(cmdname, args, kwargs))
Beispiel #34
0
    def start_server(self, server_twistd_cmd):
        """
        (Re-)Launch the Evennia server.

        Args:
            server_twisted_cmd (list): The server start instruction
                to pass to POpen to start the server.

        """
        # start the Server
        process = None
        with open(settings.SERVER_LOG_FILE, 'a') as logfile:
            # we link stdout to a file in order to catch
            # eventual errors happening before the Server has
            # opened its logger.
            try:
                if _is_windows():
                    # Windows requires special care
                    create_no_window = 0x08000000
                    process = Popen(server_twistd_cmd,
                                    env=getenv(),
                                    bufsize=-1,
                                    stdout=logfile,
                                    stderr=STDOUT,
                                    creationflags=create_no_window)

                else:
                    process = Popen(server_twistd_cmd,
                                    env=getenv(),
                                    bufsize=-1,
                                    stdout=logfile,
                                    stderr=STDOUT)
            except Exception:
                logger.log_trace()

            self.factory.portal.server_twistd_cmd = server_twistd_cmd
            logfile.flush()
        if process and not _is_windows():
            # avoid zombie-process on Unix/BSD
            process.wait()
        return
Beispiel #35
0
def create_help_entry(key, entrytext, category="General", locks=None, aliases=None):
    """
    Create a static help entry in the help database. Note that Command
    help entries are dynamic and directly taken from the __doc__
    entries of the command. The database-stored help entries are
    intended for more general help on the game, more extensive info,
    in-game setting information and so on.

    Args:
        key (str): The name of the help entry.
        entrytext (str): The body of te help entry
        category (str, optional): The help category of the entry.
        locks (str, optional): A lockstring to restrict access.
        aliases (list of str): List of alternative (likely shorter) keynames.

    Returns:
        help (HelpEntry): A newly created help entry.

    """
    global _HelpEntry
    if not _HelpEntry:
        from evennia.help.models import HelpEntry as _HelpEntry

    try:
        new_help = _HelpEntry()
        new_help.key = key
        new_help.entrytext = entrytext
        new_help.help_category = category
        if locks:
            new_help.locks.add(locks)
        if aliases:
            new_help.aliases.add(aliases)
        new_help.save()
        return new_help
    except IntegrityError:
        string = "Could not add help entry: key '%s' already exists." % key
        logger.log_err(string)
        return None
    except Exception:
        logger.log_trace()
        return None
Beispiel #36
0
def build_matches(raw_string, cmdset, include_prefixes=False):
    """
    Build match tuples by matching raw_string against available commands.

    Args:
        raw_string (str): Input string that can look in any way; the only assumption is
            that the sought command's name/alias must be *first* in the string.
        cmdset (CmdSet): The current cmdset to pick Commands from.
        include_prefixes (bool): If set, include prefixes like @, ! etc (specified in settings)
            in the match, otherwise strip them before matching.

    Returns:
        matches (list) A list of match tuples created by `cmdparser.create_match`.

    """
    matches = []
    try:
        if include_prefixes:
            # use the cmdname as-is
            l_raw_string = raw_string.lower()
            for cmd in cmdset:
                matches.extend([create_match(cmdname, raw_string, cmd, cmdname)
                                for cmdname in [cmd.key] + cmd.aliases
                                if cmdname and l_raw_string.startswith(cmdname.lower()) and
                                (not cmd.arg_regex or
                                    cmd.arg_regex.match(l_raw_string[len(cmdname):]))])
        else:
            # strip prefixes set in settings
            raw_string = (raw_string.lstrip(_CMD_IGNORE_PREFIXES)
                          if len(raw_string) > 1 else raw_string)
            l_raw_string = raw_string.lower()
            for cmd in cmdset:
                for raw_cmdname in [cmd.key] + cmd.aliases:
                    cmdname = (raw_cmdname.lstrip(_CMD_IGNORE_PREFIXES)
                               if len(raw_cmdname) > 1 else raw_cmdname)
                    if cmdname and l_raw_string.startswith(cmdname.lower()) and \
                            (not cmd.arg_regex or cmd.arg_regex.match(l_raw_string[len(cmdname):])):
                        matches.append(create_match(cmdname, raw_string, cmd, raw_cmdname))
    except Exception:
        log_trace("cmdhandler error. raw_input:%s" % raw_string)
    return matches
Beispiel #37
0
def _create_character(character_key, level, session, new_player, typeclass,
                      home, permissions, nickname):
    """
    Helper function, creates a character based on a player's name.
    This is meant for Guest and MULTISESSION_MODE < 2 situations.
    """
    try:
        new_character = create.create_object(typeclass,
                                             key=new_player.key,
                                             home=home,
                                             permissions=permissions)

        # set character info
        new_character.set_data_info(character_key)
        new_character.set_level(level)

        # set playable character list
        new_player.db._playable_characters.append(new_character)

        # allow only the character itself and the player to puppet this character (and Immortals).
        new_character.locks.add(
            "puppet:id(%i) or pid(%i) or perm(Immortals) or pperm(Immortals)" %
            (new_character.id, new_player.id))

        # If no description is set, set a default description
        if not new_character.db.desc:
            new_character.db.desc = "This is a Player."

        # Add nickname
        if not nickname:
            nickname = character_key
        new_character.set_nickname(nickname)

        # We need to set this to have @ic auto-connect to this character
        new_player.db._last_puppet = new_character
    except Exception, e:
        session.msg(
            "There was an error creating the Character:\n%s\n If this problem persists, contact an admin."
            % e)
        logger.log_trace()
        return False
Beispiel #38
0
    def msg(self, text=None, from_obj=None, session=None, options=None, **kwargs):
        """
        Evennia -> User
        This is the main route for sending data back to the user from the
        server.

        Args:
            text (str, optional): text data to send
            from_obj (Object or Account or list, optional): Object sending. If given, its
                at_msg_send() hook will be called. If iterable, call on all entities.
            session (Session or list, optional): Session object or a list of
                Sessions to receive this send. If given, overrules the
                default send behavior for the current
                MULTISESSION_MODE.
            options (list): Protocol-specific options. Passed on to the protocol.
        Kwargs:
            any (dict): All other keywords are passed on to the protocol.

        """
        if from_obj:
            # call hook
            for obj in make_iter(from_obj):
                try:
                    obj.at_msg_send(text=text, to_obj=self, **kwargs)
                except Exception:
                    # this may not be assigned.
                    logger.log_trace()
        try:
            if not self.at_msg_receive(text=text, **kwargs):
                # abort message to this account
                return
        except Exception:
            # this may not be assigned.
            pass

        kwargs["options"] = options

        # session relay
        sessions = make_iter(session) if session else self.sessions.all()
        for session in sessions:
            session.data_out(text=text, **kwargs)
Beispiel #39
0
 def at_script_creation(self):
     """
     Setup the script
     """
     self.key = GAMETIME_SCRIPT_NAME
     self.desc = "Keeps track of the game time"
     self.interval = 60
     self.persistent = True
     self.start_delay = True
     self.attributes.add("run_time", 0.0)  # OOC time
     self.attributes.add("up_time", 0.0)  # OOC time
     try:
         logfile = open(BACKUP_FILE)
         lines = [line.strip() for line in logfile if line[0].isdigit()]
         #get the last recorded time in file
         last_time = float(lines[-1])
         if last_time:
             self.attributes.add("run_time", last_time)
     except Exception:
         from evennia.utils import logger
         logger.log_trace()
Beispiel #40
0
    def execute_cmd(self, session, oobfuncname, *args, **kwargs):
        """
        Execute an oob command

        Args:
            session (Session or int):  Session or Session.sessid calling
                the oob command
            oobfuncname (str): The name of the oob command (case sensitive)

        Notes:
            If the oobfuncname is a valid oob function, `args` and
            `kwargs` are passed into the oob command.

        """
        if not session:
            errmsg = "OOB Error: execute_cmd(%s,%s,%s,%s) - no valid session" % \
                                                    (session, oobfuncname, args, kwargs)
            raise RuntimeError(errmsg)

        try:
            oobfunc = _OOB_FUNCS[oobfuncname]
        except Exception:
            errmsg = "'%s' is not a valid OOB command. Commands available:\n %s" % (
                oobfuncname, ", ".join(_OOB_FUNCS))
            if _OOB_ERROR:
                _OOB_ERROR(session, errmsg, *args, **kwargs)
            errmsg = "OOB ERROR: %s" % errmsg
            logger.log_trace(errmsg)
            return

        # we found an oob command. Execute it.
        try:
            oobfunc(session, *args, **kwargs)
        except Exception as err:
            errmsg = "Exception in %s(*%s, **%s):\n%s" % (oobfuncname, args,
                                                          kwargs, err)
            if _OOB_ERROR:
                _OOB_ERROR(session, errmsg, *args, **kwargs)
            errmsg = "OOB ERROR: %s" % errmsg
            logger.log_trace(errmsg)
Beispiel #41
0
    def make_shared_login(cls, request):
        csession = request.session
        account = request.user
        website_uid = csession.get("website_authenticated_uid", None)
        webclient_uid = csession.get("webclient_authenticated_uid", None)

        if not csession.session_key:
            # this is necessary to build the sessid key
            csession.save()

        if account.is_authenticated:
            # Logged into website
            if website_uid is None:
                # fresh website login (just from login page)
                csession["website_authenticated_uid"] = account.id
            if webclient_uid is None:
                # auto-login web client
                csession["webclient_authenticated_uid"] = account.id

        elif webclient_uid:
            # Not logged into website, but logged into webclient
            if website_uid is None:
                csession["website_authenticated_uid"] = account.id
                account = AccountDB.objects.get(id=webclient_uid)
                try:
                    # calls our custom authenticate, in web/utils/backend.py
                    authenticate(autologin=account)
                    login(request, account)
                except AttributeError:
                    logger.log_trace()

        if csession.get("webclient_authenticated_uid", None):
            # set a nonce to prevent the webclient from erasing the webclient_authenticated_uid value
            csession["webclient_authenticated_nonce"] = (
                csession.get("webclient_authenticated_nonce", 0) + 1
            )
            # wrap around to prevent integer overflows
            if csession["webclient_authenticated_nonce"] > 32:
                csession["webclient_authenticated_nonce"] = 0
Beispiel #42
0
    def disableLocal(self, option):
        """
        Disable a given option locally.

        Args:
            option (char): The telnet option to disable locally.

        """
        if option == LINEMODE:
            return True
        if option == ECHO:
            return True
        if option == MCCP:
            self.mccp.no_mccp(option)
            return True
        else:
            try:
                return super().disableLocal(option)
            except Exception:
                from evennia.utils import logger

                logger.log_trace()
Beispiel #43
0
    def _send_to_connect_channel(self, message):
        """
        Helper method for loading and sending to the comm channel
        dedicated to connection messages.

        Args:
            message (str): A message to send to the connect channel.

        """
        global _CONNECT_CHANNEL
        if not _CONNECT_CHANNEL:
            try:
                _CONNECT_CHANNEL = ChannelDB.objects.filter(db_key=settings.DEFAULT_CHANNELS[1]["key"])[0]
            except Exception:
                logger.log_trace()
        now = timezone.now()
        now = "%02i-%02i-%02i(%02i:%02i)" % (now.year, now.month,
                                             now.day, now.hour, now.minute)
        if _CONNECT_CHANNEL:
            _CONNECT_CHANNEL.tempmsg("[%s, %s]: %s" % (_CONNECT_CHANNEL.key, now, message))
        else:
            logger.log_info("[%s]: %s" % (now, message))
Beispiel #44
0
    def distribute_message(self, msgobj, online=False, **kwargs):
        """
        Method for grabbing all listeners that a message should be
        sent to on this channel, and sending them a message.

        Args:
            msgobj (Msg or TempMsg): Message to distribute.
            online (bool): Only send to receivers who are actually online
                (not currently used):
            **kwargs (dict): Arbitrary, optional arguments for users
                overriding the call (unused by default).

        Notes:
            This is also where logging happens, if enabled.

        """
        # get all accounts or objects connected to this channel and send to them
        if online:
            subs = self.subscriptions.online()
        else:
            subs = self.subscriptions.all()
        for entity in subs:
            # if the entity is muted, we don't send them a message
            if entity in self.mutelist:
                continue
            try:
                # note our addition of the from_channel keyword here. This could be checked
                # by a custom account.msg() to treat channel-receives differently.
                entity.msg(msgobj.message,
                           from_obj=msgobj.senders,
                           options={"from_channel": self.id})
            except AttributeError as e:
                logger.log_trace("%s\nCannot send msg to '%s'." % (e, entity))

        if msgobj.keep_log:
            # log to file
            logger.log_file(
                msgobj.message,
                self.attributes.get("log_file") or "channel_%s.log" % self.key)
Beispiel #45
0
def _shared_login(request):
    """
    Handle the shared login between website and webclient.

    """
    csession = request.session
    player = request.user
    sesslogin = csession.get("logged_in", None)

    if csession.session_key is None:
        # this is necessary to build the sessid key
        csession.save()
    elif player.is_authenticated():
        if not sesslogin:
            csession["logged_in"] = player.id
    elif sesslogin:
        # The webclient has previously registered a login to this csession
        player = PlayerDB.objects.get(id=sesslogin)
        try:
            login(request, player)
        except AttributeError:
            logger.log_trace()
Beispiel #46
0
    def data_out(self, text=None, **kwargs):
        """
        Data Evennia -> Player access hook.

        webclient flags checked are
        raw=True - no parsing at all (leave ansi-to-html markers unparsed)
        nomarkup=True - clean out all ansi/html markers and tokens

        """
        # string handling is similar to telnet
        try:
            text = utils.to_str(text if text else "", encoding=self.encoding)
            raw = kwargs.get("raw", False)
            nomarkup = kwargs.get("nomarkup", False)
            if raw:
                self.client.lineSend(self.suid, text)
            else:
                self.client.lineSend(self.suid,
                                     parse_html(text, strip_ansi=nomarkup))
            return
        except Exception:
            logger.log_trace()
Beispiel #47
0
    def __init__(self):
        self.storage = dict()
        pspace_dict = dict()

        def get_or_create_pspace(pspace):
            if pspace in pspace_dict:
                return pspace_dict[pspace]
            model, created = Pluginspace.objects.get_or_create(db_name=pspace)
            if created:
                model.save()
            pspace_dict[pspace] = model
            return model

        from django.conf import settings
        from evennia.utils.utils import class_from_module

        from evmush.models import Pluginspace, Namespace

        for plugin in settings.EVMUSH_PLUGINS.keys():
            get_or_create_pspace(plugin)

        for namespaces in settings.IDENTITY_NAMESPACES:
            nspace, created = Namespace.objects.get_or_create(db_name=namespaces)
            if created:
                nspace.save()

        styler_class = class_from_module(settings.STYLER_CLASS)
        self.storage['styler'] = styler_class
        styler_class.load()

        try:
            manager = class_from_module(settings.CONTROLLER_MANAGER_CLASS)(self)
            self.storage['controller_manager'] = manager
            manager.load()

        except Exception as e:
            from evennia.utils import logger
            logger.log_trace(e)
            print(e)
Beispiel #48
0
def _create_character(session, new_account, typeclass, home, permissions):
    """
    Helper function, creates a character based on an account's name.
    This is meant for Guest and MULTISESSION_MODE < 2 situations.
    """
    try:
        new_character = create.create_object(typeclass, key=new_account.key, home=home, permissions=permissions)
        # set playable character list
        new_account.db._playable_characters.append(new_character)

        # allow only the character itself and the account to puppet this character (and Developers).
        new_character.locks.add("puppet:id(%i) or pid(%i) or perm(Developer) or pperm(Developer)" %
                                (new_character.id, new_account.id))

        # If no description is set, set a default description
        if not new_character.db.desc:
            new_character.db.desc = "This is a character."
        # We need to set this to have ic auto-connect to this character
        new_account.db._last_puppet = new_character
    except Exception as e:
        session.msg("There was an error creating the Character:\n%s\n If this problem persists, contact an admin." % e)
        logger.log_trace()
Beispiel #49
0
    def dataReceived(self, data):
        """
        Handle incoming data over the wire.

        This method will split the incoming data depending on if it
        starts with IAC (a telnet command) or not. All other data will
        be handled in line mode. Some clients also sends an erroneous
        line break after IAC, which we must watch out for.

        Args:
            data (str): Incoming data.

        Notes:
            OOB protocols (MSDP etc) already intercept subnegotiations on
            their own, never entering this method. They will relay their
            parsed data directly to self.data_in.

        """

        if data and data[0] == IAC or self.iaw_mode:
            try:
                #print "IAC mode"
                super(TelnetProtocol, self).dataReceived(data)
                if len(data) == 1:
                    self.iaw_mode = True
                else:
                    self.iaw_mode = False
                return
            except Exception, err1:
                conv = ""
                try:
                    for b in data:
                        conv += " " + repr(ord(b))
                except Exception, err2:
                    conv = str(err2) + ":", str(data)
                out = "Telnet Error (%s): %s (%s)" % (err1, data, conv)
                logger.log_trace(out)
                return
Beispiel #50
0
    def open_parent_menu(self):
        """Open the parent menu, using `self.parents`.

        Note:
            You probably don't need to call this method directly,
            since the caller can go back to the parent menu using the
            `keys_go_back` automatically.

        """
        parents = list(self.parents)
        if parents:
            parent_class, parent_obj, parent_keys = parents[-1]
            del parents[-1]

            if self.caller.cmdset.has(BuildingMenuCmdSet):
                self.caller.cmdset.remove(BuildingMenuCmdSet)

            try:
                menu_class = class_from_module(parent_class)
            except Exception:
                log_trace(
                    "BuildingMenu: attempting to load class {} failed".format(
                        repr(parent_class)))
                return

            # Create the parent menu
            try:
                building_menu = menu_class(self.caller,
                                           parent_obj,
                                           keys=parent_keys,
                                           parents=tuple(parents))
            except Exception:
                log_trace(
                    "An error occurred while creating building menu {}".format(
                        repr(parent_class)))
                return
            else:
                return building_menu.open()
Beispiel #51
0
    def msg(self, text=None, from_obj=None, session=None, options=None, **kwargs):
        """
        Emits something to a session attached to the object.

        Args:
            text (str, optional): The message to send
            from_obj (obj, optional): object that is sending. If
                given, at_msg_send will be called
            session (Session or list, optional): Session or list of
                Sessions to relay data to, if any. If set, will
                force send to these sessions. If unset, who receives the
                message depends on the MULTISESSION_MODE.

        Notes:
            `at_msg_receive` will be called on this Object.
            All extra kwargs will be passed on to the protocol.

        """
        # Send messages to the client. Messages are in format of JSON.
        # try send hooks
        if from_obj:
            try:
                from_obj.at_msg_send(text=text, to_obj=self, **kwargs)
            except Exception:
                logger.log_trace()
        try:
            if not self.at_msg_receive(text=text, **kwargs):
                # if at_msg_receive returns false, we abort message to this object
                return
        except Exception:
            logger.log_trace()

        kwargs["options"] = options
                                                        
        # relay to session(s)
        sessions = make_iter(session) if session else self.sessions.all()
        for session in sessions:
            session.msg(text=text, **kwargs)
Beispiel #52
0
    def get_client_session(self):
        """
        Get the Client browser session (used for auto-login based on browser session)

        Returns:
            csession (ClientSession): This is a django-specific internal representation
                of the browser session.

        """
        try:
            self.csessid = self.http_request_uri.split("?", 1)[1]
        except IndexError:
            # this may happen for custom webclients not caring for the
            # browser session.
            self.csessid = None
            return None
        except AttributeError:
            from evennia.utils import logger
            self.csessid = None
            logger.log_trace(str(self))
            return None
        if self.csessid:
            return _CLIENT_SESSIONS(session_key=self.csessid)
Beispiel #53
0
def _msg_err(receiver, stringtuple):
    """
    Helper function for returning an error to the caller.

    Args:
        receiver (Object): object to get the error message.
        stringtuple (tuple): tuple with two strings - one for the
        _IN_GAME_ERRORS mode (with the traceback) and one with the
        production string (with a timestamp) to be shown to the user.

    """
    string = "{traceback}\n{errmsg}\n(Traceback was logged {timestamp})."
    timestamp = logger.timeformat()
    tracestring = format_exc()
    logger.log_trace()
    if _IN_GAME_ERRORS:
        receiver.msg(string.format(traceback=tracestring,
                                   errmsg=stringtuple[0].strip(),
                                   timestamp=timestamp).strip())
    else:
        receiver.msg(string.format(traceback=tracestring.splitlines()[-1],
                                   errmsg=stringtuple[1].strip(),
                                   timestamp=timestamp).strip())
Beispiel #54
0
def _create_account(session, accountname, password, permissions, typeclass=None, email=None):
    """
    Helper function, creates an account of the specified typeclass.
    """
    try:
        new_account = create.create_account(accountname, email, password, permissions=permissions, typeclass=typeclass)

    except Exception as e:
        session.msg("There was an error creating the Account:\n%s\n If this problem persists, contact an admin." % e)
        logger.log_trace()
        return False

    # This needs to be set so the engine knows this account is
    # logging in for the first time. (so it knows to call the right
    # hooks during login later)
    new_account.db.FIRST_LOGIN = True

    # join the new account to the public channel
    pchannel = ChannelDB.objects.get_channel(settings.DEFAULT_CHANNELS[0]["key"])
    if not pchannel or not pchannel.connect(new_account):
        string = "New account '%s' could not connect to public channel!" % new_account.key
        logger.log_err(string)
    return new_account
Beispiel #55
0
def _shared_login(request):
    """
    Handle the shared login between website and webclient.

    """
    csession = request.session
    account = request.user
    sesslogin = csession.get("logged_in", None)

    if csession.session_key is None:
        # this is necessary to build the sessid key
        csession.save()
    elif account.is_authenticated():
        if not sesslogin:
            csession["logged_in"] = account.id
    elif sesslogin:
        # The webclient has previously registered a login to this session
        account = AccountDB.objects.get(id=sesslogin)
        try:
            authenticate(autologin=account
                         )  # calls custom authenticate in web/utils/backend.py
            login(request, account)
        except AttributeError:
            logger.log_trace()
Beispiel #56
0
    def msg(self, text=None, from_obj=None, session=None, **kwargs):
        """
        Emits something to a session attached to the object.
        Overloads the default msg() implementation to include
        gender-aware markers in output.

        Args:
            text (str or tuple, optional): The message to send. This
                is treated internally like any send-command, so its
                value can be a tuple if sending multiple arguments to
                the `text` oob command.
            from_obj (obj, optional): object that is sending. If
                given, at_msg_send will be called
            session (Session or list, optional): session or list of
                sessions to relay to, if any. If set, will
                force send regardless of MULTISESSION_MODE.
        Notes:
            `at_msg_receive` will be called on this Object.
            All extra kwargs will be passed on to the protocol.

        """
        if text is None:
            super().msg(from_obj=from_obj, session=session, **kwargs)
            return

        try:
            if text and isinstance(text, tuple):
                text = (_RE_GENDER_PRONOUN.sub(self._get_pronoun,
                                               text[0]), *text[1:])
            else:
                text = _RE_GENDER_PRONOUN.sub(self._get_pronoun, text)
        except TypeError:
            pass
        except Exception as e:
            logger.log_trace(e)
        super().msg(text, from_obj=from_obj, session=session, **kwargs)
Beispiel #57
0
def _shared_login(request):
    """
    Handle the shared login between website and webclient.

    """
    csession = request.session
    account = request.user
    # these can have 3 values:
    #   None - previously unused (auto-login)
    #   False - actively logged out (don't auto-login)
    #   <uid> - logged in User/Account id
    website_uid = csession.get("website_authenticated_uid", None)
    webclient_uid = csession.get("webclient_authenticated_uid", None)

    # check if user has authenticated to website
    if not csession.session_key:
        # this is necessary to build the sessid key
        csession.save()

    if webclient_uid:
        # The webclient has previously registered a login to this browser_session
        if not account.is_authenticated() and not website_uid:
            try:
                account = AccountDB.objects.get(id=webclient_uid)
            except AccountDB.DoesNotExist:
                # this can happen e.g. for guest accounts or deletions
                csession["website_authenticated_uid"] = False
                csession["webclient_authenticated_uid"] = False
                return
            try:
                # calls our custom authenticate in web/utils/backends.py
                account = authenticate(autologin=account)
                login(request, account)
                csession["website_authenticated_uid"] = webclient_uid
            except AttributeError:
                logger.log_trace()
Beispiel #58
0
    def data_out(self, session, **kwargs):
        """
        Called by server for having the portal relay messages and data
        to the correct session protocol.

        Args:
            session (Session): Session sending data.

        Kwargs:
            kwargs (any): Each key is a command instruction to the
            protocol on the form key = [[args],{kwargs}]. This will
            call a method send_<key> on the protocol. If no such
            method exixts, it sends the data to a method send_default.

        """
        # from evennia.server.profiling.timetrace import timetrace  # DEBUG
        # text = timetrace(text, "portalsessionhandler.data_out")  # DEBUG

        # distribute outgoing data to the correct session methods.
        if session:
            for cmdname, (cmdargs, cmdkwargs) in kwargs.iteritems():
                funcname = "send_%s" % cmdname.strip().lower()
                if hasattr(session, funcname):
                    # better to use hassattr here over try..except
                    # - avoids hiding AttributeErrors in the call.
                    try:
                        getattr(session, funcname)(*cmdargs, **cmdkwargs)
                    except Exception:
                        log_trace()
                else:
                    try:
                        # note that send_default always takes cmdname
                        # as arg too.
                        session.send_default(cmdname, *cmdargs, **cmdkwargs)
                    except Exception:
                        log_trace()
Beispiel #59
0
    def unpause(self, manual_unpause=True):
        """
        Restart a paused script. This WILL call the `at_start()` hook.

        Args:
            manual_unpause (bool, optional): This is False if unpause is
                called by the server reload/reset mechanism.
        Returns:
            result (bool): True if unpause was triggered, False otherwise.

        Raises:
            RuntimeError: If trying to automatically resart this script
                (usually after a reset/reload), but it was manually paused,
                and so should not the auto-unpaused.

        """
        if not manual_unpause and self.db._manual_pause:
            # if this script was paused manually (by a direct call of pause),
            # it cannot be automatically unpaused (e.g. by a @reload)
            raise RuntimeError

        # Ensure that the script is fully unpaused, so that future calls
        # to unpause do not raise a RuntimeError
        self.db._manual_pause = False

        if self.db._paused_time:
            # only unpause if previously paused
            self.is_active = True

            try:
                self.at_start()
            except Exception:
                logger.log_trace()

            self._start_task()
            return True
Beispiel #60
0
    def getChild(self, path, request):
        """
        Create and return a proxy resource with the same proxy configuration
        as this one, except that its path also contains the segment given by
        path at the end.

        Args:
            path (str): Url path.
            request (Request object): Incoming request.

        Return:
            resource (EvenniaReverseProxyResource): A proxy resource.

        """
        request.notifyFinish().addErrback(lambda f: logger.log_trace("%s\nCaught errback in webserver.py:75." % f))
        return EvenniaReverseProxyResource(
            self.host, self.port, self.path + '/' + urlquote(path, safe=""),
            self.reactor)