def _loop(self): """ Main event loop, polling i/o of pty and session. """ while True: # block up to self.time_opoll for screen output if self.master_fd == -1: # pty file descriptor closed by child, # early termination! break rlist = (self.master_fd,) ret_tuple = select.select(rlist, (), (), self.time_opoll) if self.master_fd in ret_tuple[0]: data = os.read(self.master_fd, self.blocksize) if 0 == len(data): break echo(self.output_filter(data)) # block up to self.time_ipoll for keyboard input event, data = self._session.read_events( ('refresh', 'input',), self.time_ipoll) if event == 'refresh' and data[0] == 'resize': self.resize() elif event == 'input': data = self.input_filter(data) if 0 != len(data): n_written = os.write(self.master_fd, data) if n_written != len(data): # we wrote none or some of our keyboard input, but # not all. re-buffer remaining bytes back into # session for next poll self._session.buffer_input(data[n_written:]) self.log.warn('re-buffer_input(%r)!', data[n_written:])
def run(self): """ Begin door execution. pty.fork() is called, child process calls execvpe() while the parent process pipes telnet session IPC data to and from the slave pty until child process exits. On exit, DOSDoor flushes any keyboard input; DOSEMU appears to send various terminal reset sequences that may cause a reply to be received on input, and later as an invalid menu command. """ self._stime = time.time() Door.run(self) # fight against 'set scrolling region' by resetting, LORD # contains, for example: \x1b[3;22r after 'E'nter the realm echo(u''.join((self._term.normal, self._term.move(self._term.height, self._term.width), u"\x1b[r", self._term.move(self._term.height, 0), u'\r\n\r\n'))) # flush any previously decoded but unreceived keystrokes, # and any unprocessed input from telnet session not yet processed. self._term.kbflush() self._session.flush_event('input')
def read(self): """ Reads input until ESCAPE key is pressed (Blocking). Returns None. """ from x84.bbs import getch from x84.bbs.output import echo self._quit = False echo(self.refresh()) while not self.quit: echo(self.process_keystroke(getch()))
def read(self): """ Reads input until ESCAPE key is pressed (Blocking). Returns None. """ from x84.bbs.session import getsession from x84.bbs.output import echo session = getsession() self._quit = False echo(self.refresh()) while not self.quit: echo(self.process_keystroke(session.read_event('input')))
def read(self): """ Reads input until the ENTER or ESCAPE key is pressed (Blocking). """ from x84.bbs import getch from x84.bbs.output import echo self._selected = False self._quit = False echo(self.refresh()) while not (self.selected or self.quit): echo(self.process_keystroke(getch()) or u'') if self.quit: return None return self.selection
def read(self): """ Reads input until ESCAPE key is pressed (Blocking). Returns None. """ from x84.bbs import getch from x84.bbs.session import getsession from x84.bbs.output import echo session = getsession() self._quit = False echo(self.refresh()) while not self.quit: echo(self.process_keystroke(getch()))
def read(self): """ Blocking read-eval-print loop for pager. Processes user input, taking action upon and refreshing pager until the escape key is pressed. :rtype: None """ self._quit = False echo(self.refresh()) while not self.quit: echo(self.process_keystroke(getch()))
def read(self): """ Reads input until the ENTER or ESCAPE key is pressed (Blocking). Returns selection content, or None when canceled. """ self._selected = False self._quit = False echo(self.refresh()) while not (self.selected or self.quit): echo(self.process_keystroke(getch())) if self.quit: return None return self.selection[0]
def read(self, timeout=None): """ Reads input until the ENTER or ESCAPE key is pressed (Blocking). Allows backspacing. Returns unicode text, or None when canceled. """ self._carriage_returned = False self._quit = False echo(self.refresh()) term = getterminal() ref_time = None inkey_timeout = None if timeout and timeout > 1: inkey_timeout = timeout - 1 ref_time = time.time() while not (self.quit or self.carriage_returned): if inkey_timeout and (time.time() - ref_time > timeout): echo(self.refresh()) return -1 inp = term.inkey(inkey_timeout) if inp: echo(self.process_keystroke(inp)) echo(self._term.normal) if not self.quit: return self.content return None
def read(self): """ Reads input until the ENTER or ESCAPE key is pressed (Blocking). Allows backspacing. Returns unicode text, or None when canceled. """ from x84.bbs import getch from x84.bbs.output import echo self._selected = False self._quit = False echo(self.refresh()) while not (self.selected or self.quit): echo(self.process_keystroke(getch())) if self.quit: return None return self.selection[0]
def read(self): """ Reads input until the ENTER or ESCAPE key is pressed (Blocking). Allows backspacing. Returns unicode text, or None when canceled. """ echo(self.refresh()) self._quit = False self._carriage_returned = False while not (self.quit or self.carriage_returned): inp = getch() echo(self.process_keystroke(inp)) if not self.quit: return self.content return None
def read(self): """ Reads input until the ENTER or ESCAPE key is pressed (Blocking). Allows backspacing. Returns unicode text, or None when cancelled. """ from x84.bbs.session import getsession from x84.bbs.output import echo session = getsession() echo(self.refresh()) self._quit = False self._carriage_returned = False while not (self.quit or self.carriage_returned): inp = session.read_event("input") echo(self.process_keystroke(inp)) if not self.quit: return self.content return None
def _loop(self): """ Main event loop, polling i/o of pty and session. """ # pylint: disable=R0914 # Too many local variables (21/15) logger = logging.getLogger() while True: # block up to self.time_opoll for screen output if self.master_fd == -1: # pty file descriptor closed by child, early termination! break rlist = (self.master_fd,) ret_tuple = select.select(rlist, (), (), self.time_opoll) if self.master_fd in ret_tuple[0]: data = os.read(self.master_fd, self.blocksize) if 0 == len(data): break echo(self.output_filter(data)) # block up to self.time_ipoll for keyboard input event, data = self._session.read_events( ('refresh', 'input',), self.time_ipoll) if event == 'refresh' and data[0] == 'resize': self.resize() elif event == 'input': data = self.input_filter(data) if 0 != len(data): n_written = os.write(self.master_fd, data) if n_written != len(data): # we wrote none or some of our keyboard input, but # not all. re-buffer remaining bytes back into # session for next poll self._session.buffer_input(data[n_written:]) # XXX I've never actually seen this, though. It might # require writing a sub-program that artificially # hangs, such as time.sleep(99999) to assert correct # behavior. Please report, should be ok .. logger.error('re-buffer_input(%r)!', data[n_written:])
def run(self): """ Begin door execution. pty.fork() is called, child process calls execvpe() while the parent process pipes telnet session IPC data to and from the slave pty until child process exits. On exit, DOSDoor flushes any keyboard input; DOSEMU appears to send various terminal reset sequences that may cause a reply to be received on input, and later as an invalid menu command. """ echo(u'\r\n' * self._term.height) Door.run(self) # flush any previously decoded but unreceived keystrokes, # and any unprocessed input from telnet session not yet processed. self._term.kbflush() self._session.flush_event('input') # perform lossless "cls" after dosemu exit; display is garbage echo(self._term.normal + u'\r\n' * self._term.height) # also, fight against 'set scrolling region' by resetting, LORD # contains, for example: \x1b[3;22r after 'E'nter the realm :-( echo(u"\x1b[r")
def read(self): """ Reads input until the ENTER or ESCAPE key is pressed (Blocking). Allows backspacing. Returns unicode text, or None when canceled. """ from x84.bbs import getch from x84.bbs.output import echo from x84.bbs.session import getterminal term = getterminal() self._carriage_returned = False self._quit = False echo(self.refresh()) while not (self.quit or self.carriage_returned): inp = getch() echo(self.process_keystroke(inp)) echo(term.normal) if not self.quit: return self.content return None
def launch(dos=None, cp437=True, drop_type=None, drop_folder=None, name=None, args='', forcesize=None, activity=None, command=None, nodes=None, forcesize_func=None, env_term=None): r""" Helper function for launching an external program as a "Door". the forcesize_func may be overridden if the sysop wants to use their own function for presenting the screen resize prompt. virtual node pools are per-door, based on the 'name' argument, up to a maximum determined by the 'nodes' argument. name='Netrunner' nodes=4 would mean that the door, Netrunner, has a virtual node pool with 4 possible nodes in it. When 4 people are already playing the game, additional users will be notified that there are no nodes available for play until one of them is released. for DOS doors, the [dosemu] section of default.ini is used for defaults:: default.ini --- [dosemu] bin = /usr/bin/dosemu home = /home/bbs path = /usr/bin:/usr/games:/usr/local/bin opts = -u virtual -f /home/bbs/dosemu.conf \ -o /home/bbs/dosemu%%#.log %%c 2> /home/bbs/dosemu_boot%%#.log dropdir = /home/bbs/dos nodes = 4 in 'opts', %%# becomes the virtual node number, %%c becomes the 'command' argument. 'dropdir' is where dropfiles will be created if unspecified. you can give each door a dropdir for each node if you like, for ultimate compartmentalization -- just set the 'dropdir' argument when calling this function. -u virtual can be used to add a section to your dosemu.conf for virtualizing the com port (which allows you to use the same dosemu.conf locally by omitting '-u virtual'):: dosemu.conf --- $_cpu = (80386) $_hogthreshold = (20) $_layout = "us" $_external_charset = "utf8" $_internal_charset = "cp437" $_term_update_freq = (4) $_rdtsc = (on) $_cpuspeed = (166.666) ifdef u_virtual $_com1 = "virtual" endif """ session, term = getsession(), getterminal() logger = logging.getLogger() echo(term.clear) with term.fullscreen(): store_rows, store_cols = None, None env_term = env_term or term.kind strnode = None (dosbin, doshome, dospath, dosopts, dosdropdir, dosnodes) = ( get_ini('dosemu', 'bin'), get_ini('dosemu', 'home'), get_ini('dosemu', 'path'), get_ini('dosemu', 'opts'), get_ini('dosemu', 'dropdir'), get_ini('dosemu', 'nodes', getter='getint')) if drop_folder is not None and drop_type is None: drop_type = 'DOORSYS' if drop_type is not None and drop_folder is None: drop_folder = dosdropdir if drop_folder or drop_type: assert name is not None, ( 'name required for door using node pools') for node in range(nodes if nodes is not None else dosnodes): event = 'lock-%s/%d' % (name, node) session.send_event(event, ('acquire', None)) data = session.read_event(event) if data is True: strnode = str(node + 1) break if strnode is None: logger.warn('No virtual nodes left in pool: %s', name) echo(term.bold_red(u'This door is currently at maximum ' u'capacity. Please try again later.')) term.inkey(3) return logger.info('Requisitioned virtual node %s-%s', name, strnode) dosopts = dosopts.replace('%#', strnode) dosdropdir = dosdropdir.replace('%#', strnode) drop_folder = drop_folder.replace('%#', strnode) args = args.replace('%#', strnode) try: if dos is not None or forcesize is not None: if forcesize is None: forcesize = (80, 25,) else: assert len(forcesize) == 2, forcesize # pylint: disable=W0633 # Attempting to unpack a non-sequence want_cols, want_rows = forcesize if want_cols != term.width or want_rows != term.height: store_cols, store_rows = term.width, term.height echo(u'\x1b[8;%d;%dt' % (want_rows, want_cols,)) term.inkey(timeout=0.25) dirty = True if not (term.width == want_cols and term.height == want_rows): if forcesize_func is not None: forcesize_func() else: while not (term.width == want_cols and term.height == want_rows): if session.poll_event('refresh'): dirty = True if dirty: dirty = False echo(term.clear) echo(term.bold_cyan( u'o' + (u'-' * (forcesize[0] - 2)) + u'>\r\n' + (u'|\r\n' * (forcesize[1] - 2)))) echo(u''.join( (term.bold_cyan(u'V'), term.bold(u' Please resize your screen ' u'to %sx%s and/or press ENTER ' u'to continue' % (want_cols, want_rows))))) ret = term.inkey(timeout=0.25) if ret in (term.KEY_ENTER, u'\r', u'\n'): break if term.width != want_cols or term.height != want_rows: echo(u'\r\nYour dimensions: %s by %s; ' u'emulating %s by %s' % (term.width, term.height, want_cols, want_rows,)) # hand-hack, its ok ... really store_cols, store_rows = term.width, term.height term.columns, term.rows = want_cols, want_rows term.inkey(timeout=1) if activity is not None: session.activity = activity elif name is not None: session.activity = 'Playing %s' % name else: session.activity = 'Playing a door game' if drop_folder is not None: if not os.path.isabs(drop_folder): drop_folder = os.path.join(dosdropdir, drop_folder) Dropfile(getattr(Dropfile, drop_type)).save(drop_folder) door = None if dos is not None: # launch a dosemu door cmd = None if command is not None: cmd = command else: cmd = dosbin args = dosopts.replace('%c', '"' + args + '"') door = DOSDoor(cmd, shlex.split(args), cp437=True, env_home=doshome, env_path=dospath, env_term=env_term) else: # launch a unix program door = Door(command, shlex.split(args), cp437=cp437, env_term=env_term) door.run() finally: if store_rows is not None and store_cols is not None: term.rows, term.columns = store_rows, store_cols echo(u'\x1b[8;%d;%dt' % (store_rows, store_cols,)) term.inkey(timeout=0.25) if name is not None and drop_type: session.send_event( event='lock-%s/%d' % (name, int(strnode) - 1), data=('release', None)) logger.info('Released virtual node %s-%s', name, strnode)