Example #1
0
File: door.py Project: splaice/x84
    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:])
Example #2
0
File: door.py Project: splaice/x84
    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')
Example #3
0
File: pager.py Project: hick/x84
 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()))
Example #4
0
 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')))
Example #5
0
 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
Example #6
0
 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
Example #7
0
 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()))
Example #8
0
File: pager.py Project: splaice/x84
    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()))
Example #9
0
File: pager.py Project: gofore/x84
    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()))
Example #10
0
    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]
Example #11
0
    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]
Example #12
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
Example #13
0
 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]
Example #14
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
Example #15
0
 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]
Example #16
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
Example #17
0
    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
Example #18
0
File: door.py Project: tehmaze/x84
    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:])
Example #19
0
File: door.py Project: tehmaze/x84
    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")
Example #20
0
File: editor.py Project: hick/x84
 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
Example #21
0
File: editor.py Project: hick/x84
 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
Example #22
0
File: door.py Project: tehmaze/x84
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)