def call(self, cmdobj, args, msg=None, cmdset=None, noansi=True, caller=None, receiver=None, cmdstring=None, obj=None): """ Test a command by assigning all the needed properties to cmdobj and running cmdobj.at_pre_cmd() cmdobj.parse() cmdobj.func() cmdobj.at_post_cmd() The msgreturn value is compared to eventual output sent to caller.msg in the game Returns: msg (str): The received message that was sent to the caller. """ caller = caller if caller else self.char1 receiver = receiver if receiver else caller cmdobj.caller = caller cmdobj.cmdstring = cmdstring if cmdstring else cmdobj.key cmdobj.args = args cmdobj.cmdset = cmdset cmdobj.session = SESSIONS.session_from_sessid(1) cmdobj.player = self.player cmdobj.raw_string = cmdobj.key + " " + args cmdobj.obj = obj or (caller if caller else self.char1) # test old_msg = receiver.msg returned_msg = "" try: receiver.msg = Mock() cmdobj.at_pre_cmd() cmdobj.parse() cmdobj.func() cmdobj.at_post_cmd() except InterruptCommand: pass finally: # clean out prettytable sugar. We only operate on text-type stored_msg = [args[0] if args and args[0] else kwargs.get("text",utils.to_str(kwargs, force_string=True)) for name, args, kwargs in receiver.msg.mock_calls] # Get the first element of a tuple if msg received a tuple instead of a string stored_msg = [smsg[0] if isinstance(smsg, tuple) else smsg for smsg in stored_msg] if msg is not None: returned_msg = "||".join(_RE.sub("", mess) for mess in stored_msg) returned_msg = ansi.parse_ansi(returned_msg, strip_ansi=noansi).strip() if msg == "" and returned_msg or not returned_msg.startswith(msg.strip()): sep1 = "\n" + "="*30 + "Wanted message" + "="*34 + "\n" sep2 = "\n" + "="*30 + "Returned message" + "="*32 + "\n" sep3 = "\n" + "="*78 retval = sep1 + msg.strip() + sep2 + returned_msg + sep3 raise AssertionError(retval) else: returned_msg = "\n".join(str(msg) for msg in stored_msg) returned_msg = ansi.parse_ansi(returned_msg, strip_ansi=noansi).strip() receiver.msg = old_msg return returned_msg
def send_text(self, *args, **kwargs): """ Send text data. This is an in-band telnet operation. Args: text (str): The first argument is always the text string to send. No other arguments are considered. Kwargs: options (dict): Send-option flags - mxp: Enforce MXP link support. - ansi: Enforce no ANSI colors. - xterm256: Enforce xterm256 colors, regardless of TTYPE setting. - nocolor: Strip all colors. - raw: Pass string through without any ansi processing (i.e. include Evennia ansi markers but do not convert them into ansi tokens) - echo: Turn on/off line echo on the client. Turn off line echo for client, for example for password. Note that it must be actively turned back on again! """ # print "telnet.send_text", args,kwargs # DEBUG text = args[0] if args else "" if text is None: return text = to_str(text, force_string=True) # handle arguments options = kwargs.get("options", {}) flags = self.protocol_flags xterm256 = options.get("xterm256", flags.get('XTERM256', True)) useansi = options.get("ansi", flags.get('ANSI', True)) raw = options.get("raw", flags.get("RAW", False)) nocolor = options.get("nocolor", flags.get("NOCOLOR") or not (xterm256 or useansi)) # echo = options.get("echo", None) # DEBUG screenreader = options.get("screenreader", flags.get("SCREENREADER", False)) if screenreader: # screenreader mode cleans up output text = ansi.parse_ansi(text, strip_ansi=True, xterm256=False, mxp=False) text = _RE_SCREENREADER_REGEX.sub("", text) if raw: # no processing self.sendLine(text) return else: # we need to make sure to kill the color at the end in order # to match the webclient output. linetosend = ansi.parse_ansi(_RE_N.sub("", text) + ("||n" if text.endswith("|") else "|n"), strip_ansi=nocolor, xterm256=xterm256, mxp=False) self.sendLine(linetosend)
def parse_msg_mock(char): """Separates text and prompt updates from a mocked msg.""" msg = [args[0] if args else kwargs.get("text", "") for name, args, kwargs in char.msg.mock_calls] msg = "||".join(_RE.sub("", mess) for mess in msg if mess) msg = ansi.parse_ansi(msg, strip_ansi=True).strip() prompt = [kwargs.get("prompt", "") for name, args, kwargs in char.msg.mock_calls if "prompt" in kwargs] prompt = "&".join(p for p in prompt) prompt = ansi.parse_ansi(prompt, strip_ansi=True).strip() char.msg.reset_mock() return msg, prompt
def data_out(self, text=None, **kwargs): """ Send Evennia -> User """ text = text if text else "" if _INLINEFUNC_ENABLED and not "raw" in kwargs: text = parse_inlinefunc(text, strip="strip_inlinefunc" in kwargs, session=self) if self.screenreader: global _ANSI if not _ANSI: from evennia.utils import ansi as _ANSI text = _ANSI.parse_ansi(text, strip_ansi=True, xterm256=False, mxp=False) text = _RE_SCREENREADER_REGEX.sub("", text) session = kwargs.pop('session', None) session = session or self self.sessionhandler.data_out(session, text=text, **kwargs)
def send_text(self, *args, **kwargs): """ Send text data. This will pre-process the text for color-replacement, conversion to html etc. Args: text (str): Text to send. Kwargs: options (dict): Options-dict with the following keys understood: - raw (bool): No parsing at all (leave ansi-to-html markers unparsed). - nocolor (bool): Remove all color. - screenreader (bool): Use Screenreader mode. - send_prompt (bool): Send a prompt with parsed html """ if args: args = list(args) text = args[0] if text is None: return else: return flags = self.protocol_flags text = utils.to_str(text, force_string=True) options = kwargs.pop("options", {}) raw = options.get("raw", flags.get("RAW", False)) xterm256 = options.get("xterm256", flags.get('XTERM256', True)) useansi = options.get("ansi", flags.get('ANSI', True)) nocolor = options.get("nocolor", flags.get("NOCOLOR") or not (xterm256 or useansi)) screenreader = options.get("screenreader", flags.get("SCREENREADER", False)) prompt = options.get("send_prompt", False) if screenreader: # screenreader mode cleans up output text = parse_ansi(text, strip_ansi=True, xterm256=False, mxp=False) text = _RE_SCREENREADER_REGEX.sub("", text) cmd = "prompt" if prompt else "text" if raw: args[0] = text else: args[0] = parse_html(text, strip_ansi=nocolor) # send to client on required form [cmdname, args, kwargs] self.client.lineSend(self.csessid, [cmd, args, kwargs])
def send_text(self, *args, **kwargs): """ Send text data. This will pre-process the text for color-replacement, conversion to html etc. Args: text (str): Text to send. Kwargs: options (dict): Options-dict with the following keys understood: - raw (bool): No parsing at all (leave ansi-to-html markers unparsed). - nomarkup (bool): Clean out all ansi/html markers and tokens. - screenreader (bool): Use Screenreader mode. - send_prompt (bool): Send a prompt with parsed html """ if args: args = list(args) text = args[0] if text is None: return else: return flags = self.protocol_flags text = to_str(text, force_string=True) options = kwargs.pop("options", {}) raw = options.get("raw", flags.get("RAW", False)) nomarkup = options.get("nomarkup", flags.get("NOMARKUP", False)) screenreader = options.get("screenreader", flags.get("SCREENREADER", False)) prompt = options.get("send_prompt", False) if screenreader: # screenreader mode cleans up output text = parse_ansi(text, strip_ansi=True, xterm256=False, mxp=False) text = _RE_SCREENREADER_REGEX.sub("", text) cmd = "prompt" if prompt else "text" if raw: args[0] = text else: args[0] = parse_html(text, strip_ansi=nomarkup) print "send_text:", cmd, args, kwargs # send to client on required form [cmdname, args, kwargs] self.sendLine(json.dumps([cmd, args, kwargs]))
def call(self, cmdobj, args, msg=None, cmdset=None, noansi=True, caller=None, receiver=None): """ Test a command by assigning all the needed properties to cmdobj and running cmdobj.at_pre_cmd() cmdobj.parse() cmdobj.func() cmdobj.at_post_cmd() The msgreturn value is compared to eventual output sent to caller.msg in the game """ caller = caller if caller else self.char1 receiver = receiver if receiver else caller cmdobj.caller = caller cmdobj.cmdstring = cmdobj.key cmdobj.args = args cmdobj.cmdset = cmdset cmdobj.sessid = 1 cmdobj.session = SESSIONS.session_from_sessid(1) cmdobj.player = self.player cmdobj.raw_string = cmdobj.key + " " + args cmdobj.obj = caller if caller else self.char1 # test old_msg = receiver.msg try: receiver.msg = Mock() cmdobj.at_pre_cmd() cmdobj.parse() cmdobj.func() cmdobj.at_post_cmd() # clean out prettytable sugar stored_msg = [args[0] for name, args, kwargs in receiver.msg.mock_calls] returned_msg = "|".join(_RE.sub("", mess) for mess in stored_msg) returned_msg = ansi.parse_ansi(returned_msg, strip_ansi=noansi).strip() if msg is not None: if msg == "" and returned_msg or not returned_msg.startswith(msg.strip()): sep1 = "\n" + "="*30 + "Wanted message" + "="*34 + "\n" sep2 = "\n" + "="*30 + "Returned message" + "="*32 + "\n" sep3 = "\n" + "="*78 retval = sep1 + msg.strip() + sep2 + returned_msg + sep3 raise AssertionError(retval) finally: receiver.msg = old_msg
def data_out(self, text=None, **kwargs): """ Send Evennia -> User Kwargs: text (str): A text to relay kwargs (any): Other parameters to the protocol. """ # from evennia.server.profiling.timetrace import timetrace # text = timetrace(text, "ServerSession.data_out") text = text if text else "" if _INLINEFUNC_ENABLED and not "raw" in kwargs: text = parse_inlinefunc(text, strip="strip_inlinefunc" in kwargs, session=self) if self.screenreader: global _ANSI if not _ANSI: from evennia.utils import ansi as _ANSI text = _ANSI.parse_ansi(text, strip_ansi=True, xterm256=False, mxp=False) text = _RE_SCREENREADER_REGEX.sub("", text) self.sessionhandler.data_out(self, text=text, **kwargs)
def data_out(self, text=None, **kwargs): """ Data Evennia -> User access hook. 'data' argument is a dict parsed for string settings. Kwargs: text (str): Text to send. raw (bool): Leave all ansi markup and tokens unparsed nomarkup (bool): Remove all ansi markup. """ try: text = utils.to_str(text if text else "", encoding=self.encoding) except Exception as e: self.lineSend(str(e)) return raw = kwargs.get("raw", False) nomarkup = kwargs.get("nomarkup", False) if raw: self.lineSend(text) else: self.lineSend(ansi.parse_ansi(text.strip("{r") + "{r", strip_ansi=nomarkup))
def add_gmnote(self, eventid, msg): msg = parse_ansi(msg, strip_ansi=True) msg = "\n" + msg + "\n" with open(self.get_gmlog_path(eventid), "a+") as log: log.write(msg)
def test_exit(self): """Test the callbacks of an exit.""" self.char1.key = "char1" code = dedent(""" if character.key == "char1": character.msg("You can leave.") else: character.msg("You cannot leave.") deny() """.strip("\n")) # Enforce self.exit.destination since swapping typeclass lose it self.exit.destination = self.room2 # Try the can_traverse callback self.handler.add_callback(self.exit, "can_traverse", code, author=self.char1, valid=True) # Have char1 move through the exit self.call(ExitCommand(), "", "You can leave.", obj=self.exit) self.assertIs(self.char1.location, self.room2) # Have char2 move through this exit self.call(ExitCommand(), "", "You cannot leave.", obj=self.exit, caller=self.char2) self.assertIs(self.char2.location, self.room1) # Try the traverse callback self.handler.del_callback(self.exit, "can_traverse", 0) self.handler.add_callback(self.exit, "traverse", "character.msg('Fine!')", author=self.char1, valid=True) # Have char2 move through the exit self.call(ExitCommand(), "", obj=self.exit, caller=self.char2) self.assertIs(self.char2.location, self.room2) self.handler.del_callback(self.exit, "traverse", 0) # Move char1 and char2 back self.char1.location = self.room1 self.char2.location = self.room1 # Test msg_arrive and msg_leave code = 'message = "{character} goes out."' self.handler.add_callback(self.exit, "msg_leave", code, author=self.char1, valid=True) # Have char1 move through the exit old_msg = self.char2.msg try: self.char2.msg = Mock() self.call(ExitCommand(), "", obj=self.exit) stored_msg = [args[0] if args and args[0] else kwargs.get("text",utils.to_str(kwargs, force_string=True)) for name, args, kwargs in self.char2.msg.mock_calls] # Get the first element of a tuple if msg received a tuple instead of a string stored_msg = [smsg[0] if isinstance(smsg, tuple) else smsg for smsg in stored_msg] returned_msg = ansi.parse_ansi("\n".join(stored_msg), strip_ansi=True) self.assertEqual(returned_msg, "char1 goes out.") finally: self.char2.msg = old_msg # Create a return exit back = create_object("evennia.objects.objects.DefaultExit", key="in", location=self.room2, destination=self.room1) code = 'message = "{character} goes in."' self.handler.add_callback(self.exit, "msg_arrive", code, author=self.char1, valid=True) # Have char1 move through the exit old_msg = self.char2.msg try: self.char2.msg = Mock() self.call(ExitCommand(), "", obj=back) stored_msg = [args[0] if args and args[0] else kwargs.get("text",utils.to_str(kwargs, force_string=True)) for name, args, kwargs in self.char2.msg.mock_calls] # Get the first element of a tuple if msg received a tuple instead of a string stored_msg = [smsg[0] if isinstance(smsg, tuple) else smsg for smsg in stored_msg] returned_msg = ansi.parse_ansi("\n".join(stored_msg), strip_ansi=True) self.assertEqual(returned_msg, "char1 goes in.") finally: self.char2.msg = old_msg
def send_text(self, *args, **kwargs): """ Send text data. This is an in-band telnet operation. Args: text (str): The first argument is always the text string to send. No other arguments are considered. Kwargs: options (dict): Send-option flags - mxp: Enforce MXP link support. - ansi: Enforce no ANSI colors. - xterm256: Enforce xterm256 colors, regardless of TTYPE. - noxterm256: Enforce no xterm256 color support, regardless of TTYPE. - nomarkup: Strip all ANSI markup. This is the same as noxterm256,noansi - raw: Pass string through without any ansi processing (i.e. include Evennia ansi markers but do not convert them into ansi tokens) - echo: Turn on/off line echo on the client. Turn off line echo for client, for example for password. Note that it must be actively turned back on again! """ text = args[0] if args else "" if text is None: return text = to_str(text, force_string=True) # handle arguments options = kwargs.get("options", {}) flags = self.protocol_flags xterm256 = options.get("xterm256", flags.get('XTERM256', False) if flags["TTYPE"] else True) useansi = options.get("ansi", flags.get('ANSI', False) if flags["TTYPE"] else True) raw = options.get("raw", flags.get("RAW", False)) nomarkup = options.get("nomarkup", flags.get("NOMARKUP", not (xterm256 or useansi))) echo = options.get("echo", None) mxp = options.get("mxp", flags.get("MXP", False)) screenreader = options.get("screenreader", flags.get("SCREENREADER", False)) if screenreader: # screenreader mode cleans up output text = ansi.parse_ansi(text, strip_ansi=True, xterm256=False, mxp=False) text = _RE_SCREENREADER_REGEX.sub("", text) if options.get("send_prompt"): # send a prompt instead. if not raw: # processing prompt = ansi.parse_ansi(_RE_N.sub("", text) + "{n", strip_ansi=nomarkup, xterm256=xterm256) if mxp: prompt = mxp_parse(prompt) prompt = prompt.replace(IAC, IAC + IAC).replace('\n', '\r\n') prompt += IAC + GA self.transport.write(mccp_compress(self, prompt)) else: if echo is not None: # turn on/off echo. Note that this is a bit turned around since we use # echo as if we are "turning off the client's echo" when telnet really # handles it the other way around. if echo: # by telling the client that WE WON'T echo, the client knows # that IT should echo. This is the expected behavior from # our perspective. self.transport.write(mccp_compress(self, IAC+WONT+ECHO)) else: # by telling the client that WE WILL echo, the client can # safely turn OFF its OWN echo. self.transport.write(mccp_compress(self, IAC+WILL+ECHO)) if raw: # no processing self.sendLine(text) return else: # we need to make sure to kill the color at the end in order # to match the webclient output. linetosend = ansi.parse_ansi(_RE_N.sub("", text) + "{n", strip_ansi=nomarkup, xterm256=xterm256, mxp=mxp) if mxp: linetosend = mxp_parse(linetosend) self.sendLine(linetosend)
from evennia.comms.models import ChannelDB from evennia.commands.cmdset import CmdSet from evennia.utils import create, logger, utils, ansi from evennia.commands.default.muxcommand import MuxCommand from evennia.commands.cmdhandler import CMD_LOGINSTART # limit symbol import for API __all__ = ("CmdUnconnectedConnect", "CmdUnconnectedCreate", "CmdUnconnectedQuit", "CmdUnconnectedLook", "CmdUnconnectedHelp") MULTISESSION_MODE = settings.MULTISESSION_MODE CONNECTION_SCREEN_MODULE = settings.CONNECTION_SCREEN_MODULE CONNECTION_SCREEN = "" try: CONNECTION_SCREEN = ansi.parse_ansi(utils.random_string_from_module(CONNECTION_SCREEN_MODULE)) except Exception: pass if not CONNECTION_SCREEN: CONNECTION_SCREEN = "\nEvennia: Error in CONNECTION_SCREEN MODULE (randomly picked connection screen variable is not a string). \nEnter 'help' for aid." class CmdUnconnectedConnect(MuxCommand): """ Connect to the game. Usage (at login screen): connect <email> <password> Use the create command to first create an account before logging in. """
raw = kwargs.get("raw", False) nomarkup = kwargs.get("nomarkup", not (xterm256 or useansi)) prompt = kwargs.get("prompt") echo = kwargs.get("echo", None) mxp = kwargs.get("mxp", self.protocol_flags.get("MXP", False)) #print "telnet kwargs=%s, message=%s" % (kwargs, text) #print "xterm256=%s, useansi=%s, raw=%s, nomarkup=%s, init_done=%s" % (xterm256, useansi, raw, nomarkup, ttype.get("init_done")) if raw: # no processing whatsoever self.sendLine(text) elif text: # we need to make sure to kill the color at the end in order # to match the webclient output. #print "telnet data out:", self.protocol_flags, id(self.protocol_flags), id(self), "nomarkup: %s, xterm256: %s" % (nomarkup, xterm256) linetosend = ansi.parse_ansi(_RE_N.sub("", text) + "{n", strip_ansi=nomarkup, xterm256=xterm256, mxp=mxp) if mxp: linetosend = mxp_parse(linetosend) self.sendLine(linetosend) if prompt: # Send prompt separately prompt = ansi.parse_ansi(_RE_N.sub("", prompt) + "{n", strip_ansi=nomarkup, xterm256=xterm256) if mxp: prompt = mxp_parse(prompt) prompt = prompt.replace(IAC, IAC + IAC).replace('\n', '\r\n') prompt += IAC + GA self.transport.write(mccp_compress(self, prompt)) if echo: self.transport.write(mccp_compress(self, IAC+WONT+ECHO)) elif echo == False:
def convert_descs_to_written_works(apps, schema_editor): """ This iterates over all the Readable typeclassed objects we have, and tries to convert their descriptions into WrittenWorks. In cases where their descs are built up of templates or translated texts, those are converted to WrittenWorks first, and then the BookChapters are created to associate the works with the book. For descs, a WrittenWork is created, which we'll compare future descs against to see if there's duplicates. """ ObjectDB = apps.get_model("objects", "ObjectDB") WrittenWork = apps.get_model("templates", "WrittenWork") BookChapter = apps.get_model("templates", "BookChapter") ChapterSignature = apps.get_model("templates", "ChapterSignature") readable = ObjectDB.objects.filter( db_typeclass_path="typeclasses.readable.readable.Readable" ) # different mappings desc_to_work = {} template_to_work = {} authors = {} def get_author(book_object): try: author_tuple = book_object.db_attributes.get(db_key="author").db_value return get_dbobj_from_tuple(author_tuple) except (ObjectDoesNotExist, TypeError, IndexError): return None def get_dbobj_from_tuple(obj_tuple): try: obj_pk = obj_tuple[-1] if obj_pk in authors: return authors[obj_pk] else: author_obj = ObjectDB.objects.get(id=obj_pk) authors[obj_pk] = author_obj return author_obj except (ObjectDoesNotExist, TypeError, IndexError): return None def get_desc(book_object): try: desc_attr = book_object.db_attributes.get(db_key="desc") except ObjectDoesNotExist: # if they have no desc, it's an empty book. skip it return # if its desc was that it's a blank book, delete the attribute and skip it if desc_attr.db_value == OLD_BASE_DESC: desc_attr.delete() return return desc_attr def get_signers(book_object): try: signed_attr = book_object.db_attributes.get(db_key="signed") signers_objects = [] for tup in signed_attr.db_value: obj = get_dbobj_from_tuple(tup) if obj: signers_objects.append(obj) signed_attr.delete() return signers_objects except (ObjectDoesNotExist, ValueError, TypeError): return [] def add_work_and_chapter_for_desc(book_object, desc_attr, chapter_num, author_obj): # check if work already exists body = desc_attr.db_value if body in desc_to_work: work_obj = desc_to_work[body] else: work_title = book_object.db_key num_matches = WrittenWork.objects.filter( title__startswith=book_object.db_key ).count() if num_matches: work_title += f" {num_matches + 1}" # create the work_obj for the body work_obj = WrittenWork.objects.create( body=desc_attr.db_value, title=work_title, author=author_obj ) desc_to_work[body] = work_obj # create chapter return BookChapter.objects.get_or_create( defaults=dict(number=chapter_num), written_work=work_obj, objectdb=book_object, )[0] def get_max_chapter_num(book_object): agg = book_object.book_chapters.aggregate(max_chapter=models.Max("number")) return agg.get("max_chapter", 0) or 0 readable.update(db_cmdset_storage=None) for book in readable: chapter_number = 1 desc = get_desc(book) if not desc: continue templates = book.template_set.all() if templates: # if we have templates, the desc is assumed it just be a list of templates # we'll convert templates to WrittenWorks and add chapters for them print(f"Processing templates for {book.db_key} (ID #{book.id})") for template in templates: if template.id in template_to_work: new_work = template_to_work[template.id] elif template.desc in desc_to_work: new_work = desc_to_work[template.desc] else: colored_title = sub_old_ansi(template.title) title = parse_ansi(colored_title, strip_ansi=True) if colored_title == title: colored_title = "" # try to get author author = get_author(book) # check for unique title title_matches = WrittenWork.objects.filter( title__startswith=title ).count() if title_matches: title += f" {title_matches + 1}" colored_title += f" {title_matches + 1}" new_work = WrittenWork.objects.create( body=template.desc, title=title, colored_title=colored_title, owner=template.owner, author=author, ) template_to_work[template.id] = new_work desc_to_work[template.desc] = new_work # add work to chapters for the book BookChapter.objects.get_or_create( defaults=dict(number=chapter_number), written_work=new_work, objectdb=book, ) chapter_number += 1 # get rid of old desc and move on desc.delete() continue # convert books with translated descs translations = book.translations.all() if translations: print(f"Processing translations for {book.db_key} (ID #{book.id})") base_title = book.db_key chapter_number = get_max_chapter_num(book) + 1 # desc should be first chapter author = get_author(book) add_work_and_chapter_for_desc(book, desc, chapter_number, author) for translation in translations: chapter_number += 1 if translation.description in desc_to_work: work = desc_to_work[translation.description] else: # convert translations into WrittenWorks of appropriate language title = base_title if chapter_number > 1: title += f" Chapter {chapter_number}" work = WrittenWork.objects.create( language=translation.language, body=translation.description, title=title, author=author, ) desc_to_work[translation.description] = work # add bookchapter for each converted translation BookChapter.objects.get_or_create( defaults=dict(number=chapter_number), written_work=work, objectdb=book, ) # get rid of old translation translation.delete() desc.delete() continue print(f"Processing book {book.db_key} (ID #{book.id})") author = get_author(book) chapter = add_work_and_chapter_for_desc(book, desc, 1, author) desc.delete() signers = get_signers(book) for signer in signers: ChapterSignature.objects.create(book_chapter=chapter, signer=signer)
def send_text(self, *args, **kwargs): """ Send text data. This is an in-band telnet operation. Args: text (str): The first argument is always the text string to send. No other arguments are considered. Kwargs: options (dict): Send-option flags - mxp: Enforce MXP link support. - ansi: Enforce no ANSI colors. - xterm256: Enforce xterm256 colors, regardless of TTYPE setting. - nocolor: Strip all colors. - raw: Pass string through without any ansi processing (i.e. include Evennia ansi markers but do not convert them into ansi tokens) - echo: Turn on/off line echo on the client. Turn off line echo for client, for example for password. Note that it must be actively turned back on again! """ # print "telnet.send_text", args,kwargs # DEBUG text = args[0] if args else "" if text is None: return text = to_str(text) # handle arguments options = kwargs.get("options", {}) flags = self.protocol_flags xterm256 = options.get("xterm256", flags.get("XTERM256", True)) useansi = options.get("ansi", flags.get("ANSI", True)) raw = options.get("raw", flags.get("RAW", False)) nocolor = options.get( "nocolor", flags.get("NOCOLOR") or not (xterm256 or useansi)) # echo = options.get("echo", None) # DEBUG screenreader = options.get("screenreader", flags.get("SCREENREADER", False)) if screenreader: # screenreader mode cleans up output text = ansi.parse_ansi(text, strip_ansi=True, xterm256=False, mxp=False) text = _RE_SCREENREADER_REGEX.sub("", text) if raw: # no processing self.sendLine(text) return else: # we need to make sure to kill the color at the end in order # to match the webclient output. linetosend = ansi.parse_ansi( _RE_N.sub("", text) + ("||n" if text.endswith("|") else "|n"), strip_ansi=nocolor, xterm256=xterm256, mxp=False, ) self.sendLine(linetosend)
def call(self, cmdobj, args, msg=None, cmdset=None, noansi=True, caller=None, receiver=None, cmdstring=None, obj=None): """ Test a command by assigning all the needed properties to cmdobj and running cmdobj.at_pre_cmd() cmdobj.parse() cmdobj.func() cmdobj.at_post_cmd() The msgreturn value is compared to eventual output sent to caller.msg in the game Returns: msg (str): The received message that was sent to the caller. """ caller = caller if caller else self.char1 receiver = receiver if receiver else caller cmdobj.caller = caller cmdobj.cmdname = cmdstring if cmdstring else cmdobj.key cmdobj.raw_cmdname = cmdobj.cmdname cmdobj.cmdstring = cmdobj.cmdname # deprecated cmdobj.args = args cmdobj.cmdset = cmdset cmdobj.session = SESSIONS.session_from_sessid(1) cmdobj.account = self.account cmdobj.raw_string = cmdobj.key + " " + args cmdobj.obj = obj or (caller if caller else self.char1) # test old_msg = receiver.msg returned_msg = "" try: receiver.msg = Mock() cmdobj.at_pre_cmd() cmdobj.parse() ret = cmdobj.func() if isinstance(ret, types.GeneratorType): ret.next() cmdobj.at_post_cmd() except StopIteration: pass except InterruptCommand: pass finally: # clean out evtable sugar. We only operate on text-type stored_msg = [args[0] if args and args[0] else kwargs.get("text", utils.to_str(kwargs, force_string=True)) for name, args, kwargs in receiver.msg.mock_calls] # Get the first element of a tuple if msg received a tuple instead of a string stored_msg = [smsg[0] if isinstance(smsg, tuple) else smsg for smsg in stored_msg] if msg is not None: returned_msg = "||".join(_RE.sub("", mess) for mess in stored_msg) returned_msg = ansi.parse_ansi(returned_msg, strip_ansi=noansi).strip() if msg == "" and returned_msg or not returned_msg.startswith(msg.strip()): sep1 = "\n" + "=" * 30 + "Wanted message" + "=" * 34 + "\n" sep2 = "\n" + "=" * 30 + "Returned message" + "=" * 32 + "\n" sep3 = "\n" + "=" * 78 retval = sep1 + msg.strip() + sep2 + returned_msg + sep3 raise AssertionError(retval) else: returned_msg = "\n".join(str(msg) for msg in stored_msg) returned_msg = ansi.parse_ansi(returned_msg, strip_ansi=noansi).strip() receiver.msg = old_msg return returned_msg
def data_out(self, text=None, **kwargs): """ Data Evennia -> User. A generic hook method for engine to call in order to send data through the telnet connection. Kwargs: text (str): Text to send. oob (list): `[(cmdname,args,kwargs), ...]`, supply an Out-of-Band instruction. xterm256 (bool): Enforce xterm256 setting. If not given, ttype result is used. If client does not suport xterm256, the ansi fallback will be used mxp (bool): Enforce mxp setting. If not given, enables if we detected client support for it ansi (bool): Enforce ansi setting. If not given, ttype result is used. nomarkup (bool): If True, strip all ansi markup (this is the same as `xterm256=False, ansi=False`) raw (bool):Pass string through without any ansi processing (i.e. include Evennia ansi markers but do not convert them into ansi tokens) prompt (str): Supply a prompt text which gets sent without a newline added to the end. echo (str): Turn on/off line echo on the client, if the client supports it (e.g. for password input). Remember that you must manually activate it again later. Notes: The telnet TTYPE negotiation flags, if any, are used if no kwargs are given. """ ## profiling, debugging #if text.startswith("TEST_MESSAGE"): 1/0 #from evennia.server.profiling.timetrace import timetrace #text = timetrace(text, "telnet.data_out", final=True) try: text = utils.to_str(text if text else "", encoding=self.encoding) except Exception as e: self.sendLine(str(e)) return if "oob" in kwargs and "OOB" in self.protocol_flags: # oob is a list of [(cmdname, arg, kwarg), ...] for cmdname, args, okwargs in kwargs["oob"]: self.oob.data_out(cmdname, *args, **okwargs) # parse **kwargs, falling back to ttype if nothing is given explicitly ttype = self.protocol_flags.get('TTYPE', {}) xterm256 = kwargs.get("xterm256", ttype.get('256 COLORS', False) if ttype.get("init_done") else True) useansi = kwargs.get("ansi", ttype and ttype.get('ANSI', False) if ttype.get("init_done") else True) raw = kwargs.get("raw", False) nomarkup = kwargs.get("nomarkup", not (xterm256 or useansi)) prompt = kwargs.get("prompt") echo = kwargs.get("echo", None) mxp = kwargs.get("mxp", self.protocol_flags.get("MXP", False)) if raw: # no processing whatsoever self.sendLine(text) elif text: # we need to make sure to kill the color at the end in order # to match the webclient output. linetosend = ansi.parse_ansi(_RE_N.sub("", text) + "{n", strip_ansi=nomarkup, xterm256=xterm256, mxp=mxp) if mxp: linetosend = mxp_parse(linetosend) self.sendLine(linetosend) if prompt: # Send prompt separately prompt = ansi.parse_ansi(_RE_N.sub("", prompt) + "{n", strip_ansi=nomarkup, xterm256=xterm256) if mxp: prompt = mxp_parse(prompt) prompt = prompt.replace(IAC, IAC + IAC).replace('\n', '\r\n') prompt += IAC + GA self.transport.write(mccp_compress(self, prompt)) if echo: self.transport.write(mccp_compress(self, IAC+WONT+ECHO)) elif echo == False: self.transport.write(mccp_compress(self, IAC+WILL+ECHO))
def test_exit(self): """Test the callbacks of an exit.""" self.char1.key = "char1" code = dedent(""" if character.key == "char1": character.msg("You can leave.") else: character.msg("You cannot leave.") deny() """.strip("\n")) # Enforce self.exit.destination since swapping typeclass lose it self.exit.destination = self.room2 # Try the can_traverse callback self.handler.add_callback(self.exit, "can_traverse", code, author=self.char1, valid=True) # Have char1 move through the exit self.call(ExitCommand(), "", "You can leave.", obj=self.exit) self.assertIs(self.char1.location, self.room2) # Have char2 move through this exit self.call(ExitCommand(), "", "You cannot leave.", obj=self.exit, caller=self.char2) self.assertIs(self.char2.location, self.room1) # Try the traverse callback self.handler.del_callback(self.exit, "can_traverse", 0) self.handler.add_callback(self.exit, "traverse", "character.msg('Fine!')", author=self.char1, valid=True) # Have char2 move through the exit self.call(ExitCommand(), "", obj=self.exit, caller=self.char2) self.assertIs(self.char2.location, self.room2) self.handler.del_callback(self.exit, "traverse", 0) # Move char1 and char2 back self.char1.location = self.room1 self.char2.location = self.room1 # Test msg_arrive and msg_leave code = 'message = "{character} goes out."' self.handler.add_callback(self.exit, "msg_leave", code, author=self.char1, valid=True) # Have char1 move through the exit old_msg = self.char2.msg try: self.char2.msg = Mock() self.call(ExitCommand(), "", obj=self.exit) stored_msg = [ args[0] if args and args[0] else kwargs.get( "text", utils.to_str(kwargs, force_string=True)) for name, args, kwargs in self.char2.msg.mock_calls ] # Get the first element of a tuple if msg received a tuple instead of a string stored_msg = [ smsg[0] if isinstance(smsg, tuple) else smsg for smsg in stored_msg ] returned_msg = ansi.parse_ansi("\n".join(stored_msg), strip_ansi=True) self.assertEqual(returned_msg, "char1 goes out.") finally: self.char2.msg = old_msg # Create a return exit back = create_object("evennia.objects.objects.DefaultExit", key="in", location=self.room2, destination=self.room1) code = 'message = "{character} goes in."' self.handler.add_callback(self.exit, "msg_arrive", code, author=self.char1, valid=True) # Have char1 move through the exit old_msg = self.char2.msg try: self.char2.msg = Mock() self.call(ExitCommand(), "", obj=back) stored_msg = [ args[0] if args and args[0] else kwargs.get( "text", utils.to_str(kwargs, force_string=True)) for name, args, kwargs in self.char2.msg.mock_calls ] # Get the first element of a tuple if msg received a tuple instead of a string stored_msg = [ smsg[0] if isinstance(smsg, tuple) else smsg for smsg in stored_msg ] returned_msg = ansi.parse_ansi("\n".join(stored_msg), strip_ansi=True) self.assertEqual(returned_msg, "char1 goes in.") finally: self.char2.msg = old_msg
from evennia.commands.cmdset import CmdSet from evennia.utils import logger, utils, ansi from evennia.commands.default.muxcommand import MuxCommand from evennia.commands.cmdhandler import CMD_LOGINSTART from evennia.commands.default import unloggedin as default_unloggedin # Used in CmdUnconnectedCreate # limit symbol import for API __all__ = ("CmdUnconnectedConnect", "CmdUnconnectedCreate", "CmdUnconnectedQuit", "CmdUnconnectedLook", "CmdUnconnectedHelp") MULTISESSION_MODE = settings.MULTISESSION_MODE CONNECTION_SCREEN_MODULE = settings.CONNECTION_SCREEN_MODULE CONNECTION_SCREEN = "" try: CONNECTION_SCREEN = ansi.parse_ansi( utils.random_string_from_module(CONNECTION_SCREEN_MODULE)) except Exception: # malformed connection screen or no screen given pass if not CONNECTION_SCREEN: CONNECTION_SCREEN = "\nEvennia: Error in CONNECTION_SCREEN MODULE" \ " (randomly picked connection screen variable is not a string). \nEnter 'help' for aid." class CmdUnconnectedConnect(MuxCommand): """ Connect to the game. Usage (at login screen): connect <email> <password>
def call(self, cmdobj, args, msg=None, cmdset=None, noansi=True, caller=None, receiver=None, cmdstring=None, obj=None): """ Test a command by assigning all the needed properties to cmdobj and running cmdobj.at_pre_cmd() cmdobj.parse() cmdobj.func() cmdobj.at_post_cmd() The msgreturn value is compared to eventual output sent to caller.msg in the game Returns: msg (str): The received message that was sent to the caller. """ caller = caller if caller else self.char1 receiver = receiver if receiver else caller cmdobj.caller = caller cmdobj.cmdstring = cmdstring if cmdstring else cmdobj.key cmdobj.args = args cmdobj.cmdset = cmdset cmdobj.session = SESSIONS.session_from_sessid(1) cmdobj.account = self.account cmdobj.raw_string = cmdobj.key + " " + args cmdobj.obj = obj or (caller if caller else self.char1) # test old_msg = receiver.msg try: receiver.msg = Mock() if cmdobj.at_pre_cmd(): return cmdobj.parse() cmdobj.func() cmdobj.at_post_cmd() except Exception: import traceback receiver.msg(traceback.format_exc()) finally: # clean out prettytable sugar. We only operate on text-type stored_msg = [ args[0] if args and args[0] else kwargs.get( "text", utils.to_str(kwargs, force_string=True)) for name, args, kwargs in receiver.msg.mock_calls ] # Get the first element of a tuple if msg received a tuple instead of a string stored_msg = [ smsg[0] if hasattr(smsg, '__iter__') else smsg for smsg in stored_msg ] if msg is not None: returned_msg = self.format_returned_msg(stored_msg, noansi) if msg == "" and returned_msg or returned_msg != msg.strip(): sep1 = "\n" + "=" * 30 + "Wanted message" + "=" * 34 + "\n" sep2 = "\n" + "=" * 30 + "Returned message" + "=" * 32 + "\n" sep3 = "\n" + "=" * 78 # important - use raw strings for wanted/returned messages so we can see whitespace retval = "%s%r%s%r%s" % (sep1, msg.strip(), sep2, returned_msg, sep3) raise AssertionError(retval) else: returned_msg = "\n".join(str(msg) for msg in stored_msg) returned_msg = ansi.parse_ansi(returned_msg, strip_ansi=noansi).strip() receiver.msg = old_msg return returned_msg
def func(self): "Show the connect screen." connection_screen = ansi.parse_ansi(utils.random_string_from_module(CONNECTION_SCREEN_MODULE)) if not connection_screen: connection_screen = "No connection screen found. Please contact an admin." self.caller.msg(connection_screen)
def add_gemit(self, msg): msg = parse_ansi(msg, strip_ansi=True) for event_id in self.db.active_events: self.add_msg(event_id, msg)
def call(self, cmdobj, args, msg=None, cmdset=None, noansi=True, caller=None, receiver=None, cmdstring=None, obj=None, inputs=None): """ Test a command by assigning all the needed properties to cmdobj and running cmdobj.at_pre_cmd() cmdobj.parse() cmdobj.func() cmdobj.at_post_cmd() The msgreturn value is compared to eventual output sent to caller.msg in the game Returns: msg (str): The received message that was sent to the caller. """ caller = caller if caller else self.char1 receiver = receiver if receiver else caller cmdobj.caller = caller cmdobj.cmdname = cmdstring if cmdstring else cmdobj.key cmdobj.raw_cmdname = cmdobj.cmdname cmdobj.cmdstring = cmdobj.cmdname # deprecated cmdobj.args = args cmdobj.cmdset = cmdset cmdobj.session = SESSIONS.session_from_sessid(1) cmdobj.account = self.account cmdobj.raw_string = cmdobj.key + " " + args cmdobj.obj = obj or (caller if caller else self.char1) # test old_msg = receiver.msg inputs = inputs or [] try: receiver.msg = Mock() if cmdobj.at_pre_cmd(): return cmdobj.parse() ret = cmdobj.func() # handle func's with yield in them (generators) if isinstance(ret, types.GeneratorType): while True: try: inp = inputs.pop() if inputs else None if inp: try: ret.send(inp) except TypeError: ret.next() ret = ret.send(inp) else: ret.next() except StopIteration: break cmdobj.at_post_cmd() except StopIteration: pass except InterruptCommand: pass # clean out evtable sugar. We only operate on text-type stored_msg = [args[0] if args and args[0] else kwargs.get("text", utils.to_str(kwargs, force_string=True)) for name, args, kwargs in receiver.msg.mock_calls] # Get the first element of a tuple if msg received a tuple instead of a string stored_msg = [smsg[0] if isinstance(smsg, tuple) else smsg for smsg in stored_msg] if msg is not None: # set our separator for returned messages based on parsing ansi or not msg_sep = "|" if noansi else "||" # Have to strip ansi for each returned message for the regex to handle it correctly returned_msg = msg_sep.join(_RE.sub("", ansi.parse_ansi(mess, strip_ansi=noansi)) for mess in stored_msg).strip() if msg == "" and returned_msg or not returned_msg.startswith(msg.strip()): sep1 = "\n" + "=" * 30 + "Wanted message" + "=" * 34 + "\n" sep2 = "\n" + "=" * 30 + "Returned message" + "=" * 32 + "\n" sep3 = "\n" + "=" * 78 retval = sep1 + msg.strip() + sep2 + returned_msg + sep3 raise AssertionError(retval) else: returned_msg = "\n".join(str(msg) for msg in stored_msg) returned_msg = ansi.parse_ansi(returned_msg, strip_ansi=noansi).strip() receiver.msg = old_msg return returned_msg
nomarkup = kwargs.get("nomarkup", not (xterm256 or useansi)) prompt = kwargs.get("prompt") echo = kwargs.get("echo", None) mxp = kwargs.get("mxp", self.protocol_flags.get("MXP", False)) #print "telnet kwargs=%s, message=%s" % (kwargs, text) #print "xterm256=%s, useansi=%s, raw=%s, nomarkup=%s, init_done=%s" % (xterm256, useansi, raw, nomarkup, ttype.get("init_done")) if raw: # no processing whatsoever self.sendLine(text) elif text: # we need to make sure to kill the color at the end in order # to match the webclient output. #print "telnet data out:", self.protocol_flags, id(self.protocol_flags), id(self), "nomarkup: %s, xterm256: %s" % (nomarkup, xterm256) linetosend = ansi.parse_ansi(_RE_N.sub("", text) + "{n", strip_ansi=nomarkup, xterm256=xterm256, mxp=mxp) if mxp: linetosend = mxp_parse(linetosend) self.sendLine(linetosend) if prompt: # Send prompt separately prompt = ansi.parse_ansi(_RE_N.sub("", prompt) + "{n", strip_ansi=nomarkup, xterm256=xterm256) if mxp: prompt = mxp_parse(prompt) prompt = prompt.replace(IAC, IAC + IAC).replace('\n', '\r\n') prompt += IAC + GA self.transport.write(mccp_compress(self, prompt))
def call(self, cmdobj, args, msg=None, cmdset=None, noansi=True, caller=None, receiver=None, cmdstring=None, obj=None, inputs=None, raw_string=None): """ Test a command by assigning all the needed properties to cmdobj and running cmdobj.at_pre_cmd() cmdobj.parse() cmdobj.func() cmdobj.at_post_cmd() The msgreturn value is compared to eventual output sent to caller.msg in the game Returns: msg (str): The received message that was sent to the caller. """ caller = caller if caller else self.char1 receiver = receiver if receiver else caller cmdobj.caller = caller cmdobj.cmdname = cmdstring if cmdstring else cmdobj.key cmdobj.raw_cmdname = cmdobj.cmdname cmdobj.cmdstring = cmdobj.cmdname # deprecated cmdobj.args = args cmdobj.cmdset = cmdset cmdobj.session = SESSIONS.session_from_sessid(1) cmdobj.account = self.account cmdobj.raw_string = raw_string if raw_string is not None else cmdobj.key + " " + args cmdobj.obj = obj or (caller if caller else self.char1) # test old_msg = receiver.msg inputs = inputs or [] try: receiver.msg = Mock() if cmdobj.at_pre_cmd(): return cmdobj.parse() ret = cmdobj.func() # handle func's with yield in them (generators) if isinstance(ret, types.GeneratorType): while True: try: inp = inputs.pop() if inputs else None if inp: try: ret.send(inp) except TypeError: next(ret) ret = ret.send(inp) else: next(ret) except StopIteration: break cmdobj.at_post_cmd() except StopIteration: pass except InterruptCommand: pass # clean out evtable sugar. We only operate on text-type stored_msg = [args[0] if args and args[0] else kwargs.get("text", utils.to_str(kwargs)) for name, args, kwargs in receiver.msg.mock_calls] # Get the first element of a tuple if msg received a tuple instead of a string stored_msg = [str(smsg[0]) if isinstance(smsg, tuple) else str(smsg) for smsg in stored_msg] if msg is not None: msg = str(msg) # to be safe, e.g. `py` command may return ints # set our separator for returned messages based on parsing ansi or not msg_sep = "|" if noansi else "||" # Have to strip ansi for each returned message for the regex to handle it correctly returned_msg = msg_sep.join(_RE.sub("", ansi.parse_ansi(mess, strip_ansi=noansi)) for mess in stored_msg).strip() if msg == "" and returned_msg or not returned_msg.startswith(msg.strip()): sep1 = "\n" + "=" * 30 + "Wanted message" + "=" * 34 + "\n" sep2 = "\n" + "=" * 30 + "Returned message" + "=" * 32 + "\n" sep3 = "\n" + "=" * 78 retval = sep1 + msg.strip() + sep2 + returned_msg + sep3 raise AssertionError(retval) else: returned_msg = "\n".join(str(msg) for msg in stored_msg) returned_msg = ansi.parse_ansi(returned_msg, strip_ansi=noansi).strip() receiver.msg = old_msg return returned_msg