Userland/scripting API

x84.bbs.door

Door package for x/84.

This implements the concept of “Doors”, popular for DOS BBS software.

It also supports executing external Unix paths. See wikipedia article for details: http://en.wikipedia.org/wiki/BBS_door

class x84.bbs.door.DOSDoor(cmd='/bin/uname', args=(), env=None, cp437=True)[source]

Bases: x84.bbs.door.Door

Door-derived class with special handlers for executing dosemu.

This Door-derived class removes the “report cursor position” query sequence, which is sent by DOSEMU on startup. It also removes the “switch to alternate screen mode” set and reset (blessings terminals provide this with the context manager, using statement with term.fullscreen():).

It would appear that any early keyboard input received (esp. in response to “report cursor position”) prior to DOOR execution in DOSEMU causes all input to be bitshifted and invalid and/or broken.

This class resolves that issue by overriding output_filter to remove such sequences, and input_filter which only allows input after a few seconds have elapsed.

Class initializer.

Parameters:
  • cmd (str) – full path of command to execute.
  • args (tuple) – command arguments as tuple.
  • cp437 (bool) – When true, forces decoding of external program as codepage 437. This is the most common encoding used by DOS doors.
  • env (dict) – Environment variables to extend to the sub-process. You should more than likely specify values for TERM, PATH, HOME, and LANG.
RE_REPWITH_CLEAR = '\\033\\[(1;80H.*\\033\\[1;1H|H\\033\\[2J|\\d+;1H.*\\033\\[1;1H)'

regular expression of sequences to be replaced by term.clear during START_BLOCK delay in output_filter

RE_REPWITH_NONE = '\\033\\[(6n|\\?1049[lh]|\\d+;\\d+r|1;1H\\033\\[\\dM)'

regular expression of sequences to strip entirely during START_BLOCK delay in output_filter.

START_BLOCK = 4.0

Number of seconds to allow to elapse for input_filter and output_filter as a workaround for stripping startup sequences and working around a strange keyboard input bug.

input_filter(data)[source]

filter keyboard input (used for “throway” bug workaround).

output_filter(data)[source]

filter screen output (removes dosemu startup sequences).

resize()[source]

Signal resize of terminal to DOS – does nothing.

run()[source]

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.

class x84.bbs.door.Door(cmd='/bin/uname', args=(), env=None, cp437=False, raw=False)[source]

Bases: object

Spawns a subprocess and pipes input and output over bbs session.

Class initializer.

Parameters:
  • cmd (str) – full path of command to execute.
  • args (tuple) – command arguments as tuple.
  • cp437 (bool) – When true, forces decoding of external program as codepage 437. This is the most common encoding used by DOS doors.
  • env (dict) – Environment variables to extend to the sub-process. You should more than likely specify values for TERM, PATH, HOME, and LANG.
  • raw (bool) – Whether or not to use raw output
input_filter(data)[source]

Derive and modify to implement a keyboard-input filter.

When keyboard input is detected, this method may filter such input. This base class method simply returns data as-is.

output_filter(data)[source]

Filter output (performs cp437 encoding).

Given door output in bytes, if ‘cp437’ is specified in class initializer, convert to utf8 glyphs using cp437 encoding; otherwise decode output naturally as utf8.

resize()[source]

Signal resize of terminal to pty.

run()[source]

Begin door execution.

pty.fork() is called, child process calls execvpe() while the parent process pipes session IPC data to and from the slave pty, until the child process exits.

class x84.bbs.door.Dropfile(filetype=None, node=None)[source]

Bases: object

Dropfile export class.

From http://en.wikipedia.org/wiki/BBS_door

> the 1990s on, most BBS software had the capability to “drop to” doors. > Several standards were developed for passing connection and user > information to doors; this was usually done with “dropfiles”, small > binary or text files dropped into known locations in the BBS’s file > system.

Class initializer.

Parameters:
  • filetype (int) – dropfile type. One of Dropfile.DOORSYS, Dropfile.DOOR32, Dropfile.CALLINFOBBS, or Dropfile.DORINFO.
  • node (int) – A node number specified by caller; for some DOS doors, this is a very specific and limited number bounded and lock-acquired per-door by sesame.py. For others, it is inconsequential, in which case the session’s system-wide node number is used.
CALLINFOBBS = 2

Dropfile type constants

DOOR32 = 1

Dropfile type constants

DOORSYS = 0

Dropfile type constants

DORINFO = 3

Dropfile type constants

alias

current session’s handle.

comhandle

Com handle (always returns 0).

comport

Com port (always returns COM1).

comspeed

Com speed (always returns 57600).

comtype

Com type (always returns 0).

filename

Filename of given dropfile.

fullname

User fullname. Returns <handle> <handle>.

lastcall_date

Date of last call (format is %m/%d/%y).

lastcall_time

Time of last call (format is %H:%M).

location

User location.

node

User’s node number.

numcalls

Number of calls by user.

pageheight

Terminal height.

parity

Data parity.

password

Password of user.

remaining_mins

Remaining minutes (always returns 256).

remaining_secs

Remaining seconds (always returns 15360).

save(folder)[source]

Save dropfile to destination folder.

securitylevel

User security level. Always 30, or 100 for sysop.

sysopname

name of sysop.

systemname

BBS System name.

time_used

Time used (session duration) in seconds.

usernum

User record number.

xferprotocol

preferred transfer protocol.

x84.bbs.editor

Editor package for x/84.

class x84.bbs.editor.LineEditor(width=None, content=u'', hidden=False, colors=None, glyphs=None, keyset=None)[source]

Bases: object

This unicode line editor is unaware of its (y, x) position.

It is great for prompting a quick phrase on any terminal, such as a login: prompt.

Class initializer.

Parameters:
  • width (int) – the maximum input length.
  • content (str) – given default content.
  • hidden (str) – When non-False, a single ‘mask’ character for output.
  • colors (dict) – optional dictionary containing key ‘highlight’.
  • glyphs (dict) – optional dictionary of window border characters.
  • keyset (dict) – optional dictionary of line editing values.
carriage_returned

Whether the carriage return character has been handled.

hidden

When non-False, a single ‘mask’ character for hiding input.

Used by password prompts.

init_keystrokes(keyset)[source]

Sets keyboard keys for various editing keystrokes.

init_theme(colors=None, glyphs=None, hidden=False)[source]

Set color, bordering glyphs, and hidden attribute theme.

process_keystroke(keystroke)[source]

Process the keystroke and return string to refresh.

Parameters:keystroke (blessed.keyboard.Keystroke) – input from inkey().
Return type:str
Returns:string sequence suitable for refresh.
quit

Whether a ‘quit’ character has been handled, such as escape.

read()[source]

Reads input until the ENTER or ESCAPE key is pressed (Blocking).

Allows backspacing. Returns unicode text, or None when canceled.

refresh()[source]

Return string sequence suitable for refreshing editor.

No movement or positional sequences are returned.

width

Limit of characters to receive on input.

x84.bbs.editor.PC_KEYSET = {'backspace': [u'\x08', u'\x7f'], 'backword': [u'\x17'], 'enter': [u'\r'], 'exit': [u'\x1b'], 'refresh': [u'\x0c']}

default command-key mapping.

class x84.bbs.editor.ScrollingEditor(*args, **kwargs)[source]

Bases: x84.bbs.ansiwin.AnsiWindow

A single line Editor, requires absolute (yloc, xloc) position.

Infinite horizontal scrolling is enabled or limited using max_length.

Class initializer.

Parameters:
  • width (int) – width of window.
  • yloc (int) – y-location of window.
  • xloc (int) – x-location of window.
  • max_length (int) – maximum length of input (even when scrolled).
  • colors (dict) – color theme.
  • glyphs (dict) – bordering window character glyphs.
  • keyset (dict) – command keys, global PC_KEYSET is default.
add(u_chr)[source]

Return output sequence of changes after adding a character to editor.

An empty string is returned if no data could be inserted. Sequences for re-displaying the full input line are returned when the character addition caused the window to scroll horizontally.

Otherwise, the input is simply returned to be displayed.

backspace()[source]

Remove character from end of buffer, scroll as necessary.

backword()[source]

Delete word behind cursor, using ‘ ‘ as boundary.

In gnu-readline this is unix-word-rubout (C-w).

bell

Whether the user has neared the margin.

carriage_returned

Whether the carriage return character has been handled.

content

The contents of the editor.

eol

Whether more input may be accepted (end of line reached).

fixate(x_adjust=0)[source]

Return string sequence suitable for “fixating” cursor position.

Set x_adjust to -1 to position cursor ‘on’ the last character, or 0 for ‘after’ (default).

init_keystrokes(keyset)[source]

Sets keyboard keys for various editing keystrokes.

init_theme(colors=None, glyphs=None)[source]

Set color and bordering glyphs theme.

is_scrolled

Whether the horizontal editor is in a scrolled state.

margin_amt

Absolute number of columns from margin until bell is signaled.

Indicating that the end is near and the carriage should be soon returned.

margin_pct

Percentage of visible width from-end until bell is signaled.

Number of columns away from input length limit, as a percentage of its total visible width, that will alarm the bell. This simulates the bell of a typewriter as a signaling mechanism. Default is 10.

Unofficially intended for a faked multi-line editor: by using the bell as a wrap signal to instantiate another line editor and ‘return the carriage’.

max_length

Maximum line length.

This also limits infinite scrolling when enable_scrolling is True. When unset, the maximum length is infinite!

position

Tuple of shift amount and column position of line editor.

process_keystroke(keystroke)[source]

Process the keystroke and return string to refresh.

Parameters:keystroke (blessed.keyboard.Keystroke) – input from inkey().
Return type:str
Returns:string sequence suitable for refresh.
quit

Whether a ‘quit’ character has been handled, such as escape.

read()[source]

Reads input until the ENTER or ESCAPE key is pressed (Blocking).

Allows backspacing. Returns unicode text, or None when canceled.

refresh()[source]

Return string sequence suitable for refreshing editor.

A strange by-product; if scrolling was not previously enabled, it is if wrapping must occur; this can happen if a non-scrolling editor was provided a very large .content buffer, then later .refresh()’d. – essentially enabling infinite scrolling.

scroll_amt

Number of columns from-end until horizontal editor will scroll

Calculated by scroll_pct.

scroll_pct

Percentage of visible width from-end until scrolling occurs.

Number of columns, as a percentage of its total visible width, that will be scrolled when a user reaches the margin by percent. Default is 25.

update(ucs=u'')[source]

Replace or reset content.

Resets properties carriage_returned and quit to False.

x84.bbs.ini

Configuration package x/84.

x84.bbs.ini.CFG = None

Singleton representing configuration after load

x84.bbs.ini.get_ini(section=None, key=None, getter='get', split=False, splitsep=', ')[source]

Get an ini configuration of section and key.

If the option does not exist, an empty list, string, or False is returned – return type decided by the given arguments.

The getter method is ‘get’ by default, returning a string. For booleans, use getter='get_boolean'.

To return a list, use split=True.

x84.bbs.ini.init(lookup_bbs, lookup_log)[source]

Initialize global ‘CFG’ variable, a singleton to contain bbs settings.

Each variable (lookup_bbs, lookup_log) is tuple lookup path of in-order preferences for .ini files. If none are found, defaults are initialized, and the last item of each tuple is created.

x84.bbs.ini.init_bbs_ini()[source]

Returns ConfigParser instance of bbs system defaults.

x84.bbs.ini.init_log_ini()[source]

Return ConfigParser instance of logger defaults.

x84.bbs.ipc

Session IPC package for x/84.

class x84.bbs.ipc.IPCLogHandler(out_queue)[source]

Bases: logging.Handler

Log handler that sends the log up the ‘event pipe’.

This is a rather novel solution that seems overlooked in documentation, a forked process must have some method to propagate its logging records up through the main process, otherwise they are lost.

Constructor method, requires multiprocessing.Pipe.

emit(record)[source]

Emit log record via IPC output queue.

class x84.bbs.ipc.IPCStream(writer)[source]

Bases: object

Connect blessed.Terminal argument ‘stream’ to ‘writer’ queue.

The writer queue is a multiprocessing.Pipe whose master-side is polled for output in x84.engine. Only the write() method of this “stream” and is_a_tty attribute is called or evaluated by blessed.Terminal. The attribute is_a_tty is mocked as True.

write(ucs, encoding='ascii')[source]

Sends unicode text to Pipe.

Default encoding is ‘ascii’, which is unset only when used with blessings, which rarely writes directly to the stream (context managers, such as “with term.location(0, 0):” have such side effects).

x84.bbs.ipc.make_root_logger(out_queue)[source]

Remove and re-address the root logging handler.

Any existing handlers of the current process are removed and the root logger is re-address to send via an IPC output event queue.

x84.bbs.lightbar

Lightbar package for x/84.

class x84.bbs.lightbar.Lightbar(*args, **kwargs)[source]

Bases: x84.bbs.ansiwin.AnsiWindow

This Windowing class offers a classic ‘lightbar’ interface.

Instantiate with yloc, xloc, height, and width, then call the update method with a list of unicode strings. send keycodes to process_keystroke () to interactive with the ‘lightbar’.

Class initializer.

Initialize a lightbar of height, width, y and x, and position.

Parameters:
  • width (int) – width of window.
  • height (int) – height of window.
  • yloc (int) – y-location of window.
  • xloc (int) – x-location of window.
  • colors (dict) – color theme, only key value of highlight is used.
  • glyphs (dict) – bordering window character glyphs.
  • keyset (dict) – command keys, global NETHACK_KEYSET is used by default, augmented by application keys such as home, end, pgup, etc.
  • content (list) – Lightbar content as list of tuples, an empty list is used by default. Tuples must be in form of (key, str). key may have any suitable significance for the caller. str, however, must be of a unicode terminal sequence.
at_bottom

Whether current selection is pointed at final entry.

at_top

Whether current selection is pointed at the first entry.

fixate()[source]

Return string sequence suitable for “fixating” cursor position.

goto(index)[source]

Move selection to given index.

index

Selected index of self.content.

init_keystrokes(keyset)[source]

Sets keyboard keys for various editing keystrokes.

init_theme(colors=None, glyphs=None)[source]

Set color and bordering glyphs theme.

last_index

Previously selected index of self.content.

move_down()[source]

Move selection down one row, return string suitable for refresh.

move_end()[source]

Move selection to final row, return string suitable for refresh.

move_home()[source]

Move selection to first row, return string suitable for refresh.

move_pagedown()[source]

Move selection down one page, return string suitable for refresh.

move_pageup()[source]

Move selection up one page, return string suitable for refresh.

move_up()[source]

Move selection up one row, return string suitable for refresh.

position

Tuple pair (row, page).

row is the index from top of window, and ‘page’ is number of page items scrolled.

process_keystroke(keystroke)[source]

Process the keystroke and return string to refresh.

Parameters:keystroke (blessed.keyboard.Keystroke) – input from inkey().
Return type:str
Returns:string sequence suitable for refresh.
quit

Whether a ‘quit’ character has been handled, such as escape.

read()[source]

Reads input until the ENTER or ESCAPE key is pressed (Blocking).

Returns selection content, or None when canceled.

refresh()[source]

Return string sequence suitable for refreshing lightbar.

refresh_quick()[source]

Redraw only the ‘dirty’ portions after a ‘move’ has occurred.

refresh_row(row)[source]

Return string sequence suitable for refreshing current selection.

Return unicode byte sequence suitable for moving to location ypos of window-relative row, and displaying any valid entry there, or using glyphs[‘erase’] if out of bounds. Strings are ansi color safe, and will be trimmed using glyphs[‘strip’] if their displayed width is wider than window.

selected

Whether carriage return was detected by process_keystroke.

selection

Selected content of self.content by index.

update(keyed_uchars=None)[source]

Replace content with with sequence of (key, str).

key may have any suitable significance for the caller. str, however, must be of a unicode terminal sequence.

visible_bottom

Visible bottom-most item of lightbar.

visible_content

Returns visible content only.

vitem_idx

Relative visible item index within view.

Index of selected item relative by index to only the length of the list that is visible, without accounting for scrolled content.

vitem_shift

Index of top-most item in viewable window, non-zero when scrolled.

This value effectively represents the number of items not in view due to paging.

x84.bbs.lightbar.NETHACK_KEYSET = {'down': [u'j'], 'end': [u'n', 'G'], 'enter': [u'\r'], 'exit': [u'q', u'Q', u'\x1b'], 'home': [u'y', '0'], 'pgdown': [u'l', u'f'], 'pgup': [u'h', u'b'], 'up': [u'k']}

default command-key mapping.

x84.bbs.output

Terminal output package for x/84.

x84.bbs.output.RE_ANSI_COLOR = <_sre.SRE_Pattern object>

simple regular expression for matching simple ansi colors, for use by encode_pipe().

x84.bbs.output.SAUCE_FONT_MAP = {'Amiga MicroKnight': 'amiga', 'Amiga MicroKnight+': 'amiga', 'Amiga P0T-NOoDLE': 'amiga', 'Amiga Topaz 1': 'amiga', 'Amiga Topaz 1+': 'amiga', 'Amiga Topaz 2': 'amiga', 'Amiga Topaz 2+': 'amiga', 'Amiga mOsOul': 'amiga', 'Atari ATASCII': 'atari', 'IBM EGA': 'cp437', 'IBM EGA 437': 'cp437', 'IBM EGA 720': 'cp720', 'IBM EGA 737': 'cp737', 'IBM EGA 775': 'cp775', 'IBM EGA 819': 'cp819', 'IBM EGA 850': 'cp850', 'IBM EGA 852': 'cp852', 'IBM EGA 855': 'cp855', 'IBM EGA 857': 'cp857', 'IBM EGA 858': 'cp858', 'IBM EGA 860': 'cp860', 'IBM EGA 861': 'cp861', 'IBM EGA 862': 'cp862', 'IBM EGA 863': 'cp863', 'IBM EGA 864': 'cp864', 'IBM EGA 865': 'cp865', 'IBM EGA 866': 'cp866', 'IBM EGA 869': 'cp869', 'IBM EGA 872': 'cp872', 'IBM EGA43': 'cp437', 'IBM EGA43 437': 'cp437', 'IBM EGA43 720': 'cp720', 'IBM EGA43 737': 'cp737', 'IBM EGA43 775': 'cp775', 'IBM EGA43 819': 'cp819', 'IBM EGA43 850': 'cp850', 'IBM EGA43 852': 'cp852', 'IBM EGA43 855': 'cp855', 'IBM EGA43 857': 'cp857', 'IBM EGA43 858': 'cp858', 'IBM EGA43 860': 'cp860', 'IBM EGA43 861': 'cp861', 'IBM EGA43 862': 'cp862', 'IBM EGA43 863': 'cp863', 'IBM EGA43 864': 'cp864', 'IBM EGA43 865': 'cp865', 'IBM EGA43 866': 'cp866', 'IBM EGA43 869': 'cp869', 'IBM EGA43 872': 'cp872', 'IBM VGA': 'cp437', 'IBM VGA 437': 'cp437', 'IBM VGA 720': 'cp720', 'IBM VGA 737': 'cp737', 'IBM VGA 775': 'cp775', 'IBM VGA 819': 'cp819', 'IBM VGA 850': 'cp850', 'IBM VGA 852': 'cp852', 'IBM VGA 855': 'cp855', 'IBM VGA 857': 'cp857', 'IBM VGA 858': 'cp858', 'IBM VGA 860': 'cp860', 'IBM VGA 861': 'cp861', 'IBM VGA 862': 'cp862', 'IBM VGA 863': 'cp863', 'IBM VGA 864': 'cp864', 'IBM VGA 865': 'cp865', 'IBM VGA 866': 'cp866', 'IBM VGA 869': 'cp869', 'IBM VGA 872': 'cp872', 'IBM VGA25G': 'cp437', 'IBM VGA25g 437': 'cp437', 'IBM VGA25g 720': 'cp720', 'IBM VGA25g 737': 'cp737', 'IBM VGA25g 775': 'cp775', 'IBM VGA25g 819': 'cp819', 'IBM VGA25g 850': 'cp850', 'IBM VGA25g 852': 'cp852', 'IBM VGA25g 855': 'cp855', 'IBM VGA25g 857': 'cp857', 'IBM VGA25g 858': 'cp858', 'IBM VGA25g 860': 'cp860', 'IBM VGA25g 861': 'cp861', 'IBM VGA25g 862': 'cp862', 'IBM VGA25g 863': 'cp863', 'IBM VGA25g 864': 'cp864', 'IBM VGA25g 865': 'cp865', 'IBM VGA25g 866': 'cp866', 'IBM VGA25g 869': 'cp869', 'IBM VGA25g 872': 'cp872', 'IBM VGA50': 'cp437', 'IBM VGA50 437': 'cp437', 'IBM VGA50 720': 'cp720', 'IBM VGA50 737': 'cp737', 'IBM VGA50 775': 'cp775', 'IBM VGA50 819': 'cp819', 'IBM VGA50 850': 'cp850', 'IBM VGA50 852': 'cp852', 'IBM VGA50 855': 'cp855', 'IBM VGA50 857': 'cp857', 'IBM VGA50 858': 'cp858', 'IBM VGA50 860': 'cp860', 'IBM VGA50 861': 'cp861', 'IBM VGA50 862': 'cp862', 'IBM VGA50 863': 'cp863', 'IBM VGA50 864': 'cp864', 'IBM VGA50 865': 'cp865', 'IBM VGA50 866': 'cp866', 'IBM VGA50 869': 'cp869', 'IBM VGA50 872': 'cp872'}

Translation map for embedded font hints in SAUCE records as documented at http://www.acid.org/info/sauce/sauce.htm section FontName. Used by showart() to automatically determine which codepage to be used by utf8 terminals to provide an approximate translation.

x84.bbs.output.SYNCTERM_FONTMAP = ('cp437', 'cp1251', 'koi8_r', 'iso8859_2', 'iso8859_4', 'cp866', 'iso8859_9', 'haik8', 'iso8859_8', 'koi8_u', 'iso8859_15', 'iso8859_4', 'koi8_r_b', 'iso8859_4', 'iso8859_5', 'ARMSCII_8', 'iso8859_15', 'cp850', 'cp850', 'cp885', 'cp1251', 'iso8859_7', 'koi8-r_c', 'iso8859_4', 'iso8859_1', 'cp866', 'cp437', 'cp866', 'cp885', 'cp866_u', 'iso8859_1', 'cp1131', 'c64_upper', 'c64_lower', 'c128_upper', 'c128_lower', 'atari', 'pot_noodle', 'mo_soul', 'microknight', 'topaz')

A mapping of SyncTerm fonts/code pages to their sequence value, for use as argument font_name of syncterm_setfont().

Where matching, their python-standard encoding value is used, (fe. ‘cp437’). Otherwise, the lower-case named of the font is used.

source: http://cvs.synchro.net/cgi-bin/viewcvs.cgi/checkout/src/conio/cterm.txt

x84.bbs.output.decode_pipe(ucs)[source]

Return ucs containing ‘pipe codes’ with terminal color sequences.

These are sometimes known as LORD codes, as they were used in the DOS Door game of the same name. Compliments encode_pipe().

Parameters:ucs (str) – string containing ‘pipe codes’.
Return type:str
x84.bbs.output.echo(ucs)[source]

Display unicode terminal sequence.

Parameters:ucs (str) – unicode sequence to write to terminal.
x84.bbs.output.encode_pipe(ucs)[source]

Given a string containing ECMA-48 sequence, replace with “pipe codes”.

These are sometimes known as LORD codes, as they were used in the DOS Door game of the same name. Compliments decode_pipe().

Parameters:ucs (str) – string containing ECMA-48 sequences.
Return type:str
x84.bbs.output.from_cp437(text)[source]

Deprecated form of bytes.decode('cp437_art').

x84.bbs.output.ropen(filename, mode='rb')[source]

Open random file using wildcard (glob).

x84.bbs.output.showart(filepattern, encoding=None, auto_mode=True, center=False, poll_cancel=False, msg_cancel=None, force=False)[source]

Yield unicode sequences for any given ANSI Art (of art_encoding).

Effort is made to parse SAUCE data, translate input to unicode, and trim artwork too large to display. If poll_cancel is not False, represents time as float for each line to block for keypress – if any is received, then iteration ends and msg_cancel is displayed as last line of art.

If you provide no encoding, the piece encoding will be based on either the encoding in the SAUCE record, the configured default or the default fallback CP437 encoding.

Alternate codecs are available if you provide the encoding argument. For example, if you want to show an Amiga style ASCII art file:

>>> from x84.bbs import echo, showart
>>> for line in showart('test.asc', 'topaz'):
...     echo(line)

The auto_mode flag will, if set, only respect the selected encoding if the active session is UTF-8 capable.

If center is set to True, the piece will be centered respecting the current terminal’s width.

If force is set to true then the artwork will be displayed even if it’s wider than the screen.

x84.bbs.output.syncterm_setfont(font_name, font_page=0)[source]

Send SyncTerm’s sequence for selecting a “font” codepage.

Parameters:

Reference:

CSI [ p1 [ ; p2 ] ] sp D
Font Selection
Defaults: p1 = 0  p2 = 0
"sp" indicates a single space character.
Sets font p1 to be the one indicated by p2.  Currently only the primary
font (Font zero) and secondary font (Font one) are supported.  p2 must
be between 0 and 255.  Not all output types support font selection.
Only X11 and SDL currently do.

source: http://cvs.synchro.net/cgi-bin/viewcvs.cgi/checkout/src/conio/cterm.txt

x84.bbs.output.timeago(secs, precision=0)[source]

Return human-readable string of seconds elapsed.

Parameters:
  • secs (int) – number of seconds “ago”.
  • precision (int) – optional decimal precision of returned seconds.

Pass a duration of time and return human readable shorthand, fe:

>>> asctime(126.32)
' 2m 6s',
>>> asctime(70.9999, 2)
' 1m 10.99s'

x84.bbs.pager

Pager package for x/84.

class x84.bbs.pager.Pager(*args, **kwargs)[source]

Bases: x84.bbs.ansiwin.AnsiWindow

Scrolling viewer.

Class initializer.

Parameters:
  • width (int) – width of window.
  • height (int) – height of window.
  • yloc (int) – y-location of window.
  • xloc (int) – x-location of window.
  • content (str) – initial pager contents.
  • colors (dict) – color theme.
  • glyphs (dict) – bordering window character glyphs.
  • keyset (dict) – command keys, global VI_KEYSET is default.
append(ucs)[source]

Update content buffer with additional line(s) of text.

“pipe codes” in ucs are decoded by decode_pipe().

Parameters:ucs (str) – unicode string to append-to content buffer.

:rtype str :return: terminal sequence suitable for refreshing window.

bottom

Bottom-most position that contains content.

content

Content of pager.

Return value is “pipe encoded” by encode_pipe(). :rtype: str

init_keystrokes(keyset)[source]

Sets keyboard keys for various editing keystrokes.

move_down(num=1)[source]

Scroll down num rows and return refresh string.

Return type:str
move_end()[source]

Scroll to bottom and return refresh string.

Return type:str
move_home()[source]

Scroll to top and return refresh string.

Return type:str
move_pgdown(num=1)[source]

Scroll down num pages and return refresh string.

Return type:str
move_pgup(num=1)[source]

Scroll up num pages and return refresh string.

Return type:str
move_up(num=1)[source]

Scroll up num rows and return refresh string.

Return type:str
position

Index of content buffer displayed at top of window.

position_last

Previous position before last move.

process_keystroke(keystroke)[source]

Process the keystroke and return string to refresh.

Parameters:keystroke (blessed.keyboard.Keystroke) – input from inkey().
Return type:str
Returns:string sequence suitable for refresh.
quit

Whether a ‘quit’ character has been handled, such as escape.

read()[source]

Blocking read-eval-print loop for pager.

Processes user input, taking action upon and refreshing pager until the escape key is pressed.

Return type:None
refresh(start_row=0)[source]

Return unicode string suitable for refreshing pager window.

Parameters:start_row (int) – refresh from only visible row ‘start_row’ and downward. This can be useful if only the last line is modified; or in an ‘insert’ operation: only the last line need be refreshed.
Return type:str
refresh_row(row)[source]

Return unicode string suitable for refreshing pager row.

Parameters:row (int) – target row by visible index.
Return type:str
update(ucs)[source]

Update content buffer with newline-delimited text.

Return type:str
visible_bottom

Bottom-most window row that contains content.

visible_content

Content that is visible in window.

x84.bbs.session

Session engine for x/84.

x84.bbs.session.SESSION = None

singleton representing the session connected by current process

class x84.bbs.session.Session(terminal, sid, env, child_pipes, kind, addrport, matrix_args, matrix_kwargs)[source]

Bases: object

A per-process Session. Begins by the run().

Instantiate a Session.

Only one session may be instantiated per process.

Parameters:
  • terminal (blessed.Terminal) – interactive terminal associated with this session.
  • sid (str) – session identification string
  • env (dict) – transport-negotiated environment variables, should contain at least values for TERM and ‘encoding’.
  • child_pipes (tuple) – tuple of (writer, reader).
  • kind (str) – transport description string (ssh, telnet)
  • addrport (str) – transport ip address and port as string
  • matrix_args (tuple) – When non-None, a tuple of positional arguments passed to the matrix script.
  • matrix_kwargs (dict) – When non-None, a dictionary of keyword arguments passed to the matrix script.
activity

Current session activity.

This is arbitrarily set by session scripts.

This also updates xterm titles, and is globally broadcasted as a “current activity” in the Who’s online script, for example.

buffer_event(event, data=None)[source]

Buffer and handle IPC data keyed by event.

Parameters:
  • event (str) – event name.
  • data – event data.
Return type:

bool

Returns:

True if the event was internally handled, and the caller should take no further action.

Methods internally handled by this method:

  • global: events where the first index of data is AYT. This is sent by other sessions using the broadcast event, to discover “who is online”.
  • info-req: Where the first data value is the remote session-id that requested it, expecting a return value event of info-ack whose data values is a dictionary describing a session. This is an extension of the “who is online” event described above.
  • gosub: Allows one session to send another to a different script, this is used by the default board chat.py for a chat request.
buffer_input(data, pushback=False)[source]

Receive keyboard input ,``data``, into input buffer.

Updates idle time, buffering raw bytes received from telnet client via event queue. Sometimes a script may poll for, and receive keyboard data, but wants to push it back in to the top of the stack to be decoded by a later call to term.inkey(); in such case, pushback should be set.

Parameters:
  • data (bytes) – keyboard input data.
  • pushback (bool) – whether it should be pushed to front of stack.
close()[source]

Close session, currently releases node lock..

connect_time

Time of session start (as float).

current_script

The current script being executed.

duration

Seconds elapsed since connection began (as float).

encoding

Session encoding, both input and output.

flush_event(event)[source]

Flush and return all data buffered for event.

Parameters:event (str) – event name.
Return type:list
idle

Seconds elapsed since last keypress as float.

last_input_time

Time of last keypress (as epoch, float).

node

Unique numeric constant for this session.

This makes it simpler to refer to users who are online, instead of by their full session-id (such as telnet-92.32.10.132:57331) one can simply refer to node #1, etc..

pid

Process ID of this session (int).

poll_event(event)[source]

Non-blocking poll for session event.

Parameters:event (str) – an IPC event queue by name, such as input.
Returns:first matching IPC event data, or None.
read_event(event, timeout=None)[source]

Return data for given event by timeout.

Parameters:
  • event (str) – an IPC event queue by name, such as input.
  • timeout (int) – Value of None is blocking (default), -1 is non-blocking poll. All other values are blocking up to value of timeout.
Returns:

first matching IPC event data. If timeout is specified and no matching IPC event is discovered, None is returned.

read_events(events, timeout=None)[source]

Return the first matched IPC data for any event specified by timeout.

Parameters:
  • events (tuple) – events to search for, for example ('input', 'refresh').
  • timeout (int) – Value of None is blocking (default), -1 is non-blocking poll. All other values are blocking up to value of timeout.
Return type:

tuple

Returns:

first matching IPC event, data tuple, where event matches one of the given events. If timeout is specified and no matching IPC event is discovered, (None, None) is returned.

run()[source]

Begin main execution of session.

Scripts manipulate control flow of scripts by raising the Goto exception, or the gosub function.

runscript(script)[source]

Execute the main() callable of script identified by script.

Parameters:script (Script) – target script to execute.
Returns:the return value of the given script’s main() function.
script_module

Base python module instance for userland scripts.

Return type:list
script_path

Base filepath folder for all scripts.

Return type:list
send_event(event, data)[source]

Send data to IPC output queue in form of (event, data).

Supported event strings:

  • disconnect: Session wishes to disconnect.
  • logger: Data is logging record, used by IPCLogHandler.
  • output: Unicode data to write to client.
  • global: Broadcast event to other sessions.
  • route: Send an event to another session.
  • db-<schema>: Request sqlite dict method result.
  • db=<schema>: Request sqlite dict method result as iterable.
  • lock-<name>: Fine-grained global bbs locking.
Parameters:
  • event (str) – event name.
  • data – event data.
show_traceback

Whether traceback errors should be displayed to user (bool).

tap_input

Whether keyboard input should be logged (bool).

tap_output

Whether screen output should be logged (bool).

to_dict()[source]

Dictionary describing this session.

user

User instance of this session.

write(ucs, encoding=None)[source]

Write unicode data ucs to terminal.

x84.bbs.session.disconnect(reason=u'')[source]

Disconnect session. Does not return.

x84.bbs.session.getch(timeout=None)[source]

A deprecated form of getterminal().inkey().

This is old behavior – upstream blessed project does the correct thing. please use term.inkey() and see the documentation for blessed’s inkey() method, it always returns unicode, never None, and definitely never an integer. However some internal UI libraries were built upon getch(), and as such, this remains …

x84.bbs.session.getsession()[source]

Return Session instance of current process.

x84.bbs.session.getterminal()[source]

Return blessed.Terminal instance of current session.

x84.bbs.session.gosub(script, *args, **kwargs)[source]

Call bbs script with optional arguments, Returns value.

x84.bbs.session.goto(script_name, *args, **kwargs)[source]

Change bbs script. Does not return.

x84.bbs.userbase

Userbase record database and utility functions for x/84.

class x84.bbs.userbase.Group(name, members=())[source]

Bases: object

A simple group record object.

Class initializer.

add(handle)[source]

Add user to group.

delete()[source]

Delete group record, enforces referential integrity with Users.

members

Members of this group as user handles.

name

Name of this group.

remove(handle)[source]

Remove user from group.

save()[source]

Save group record to database.

class x84.bbs.userbase.User(handle=u'anonymous')[source]

Bases: object

A simple user record.

Class initializer.

auth(try_pass)[source]

Authenticate user with given password, try_pass.

Return type:bool
Returns:whether the password is correct.
calls

Legacy, number of times user has ‘called’ this board.

delete()[source]

Remove user from user and group databases.

email

E-mail address. May be used for password resets.

get(k[, d]) → D[k] if k in D, else d. d defaults to None.[source]
group_add(group)[source]

Add user to group.

group_del(group)[source]

Remove user from group.

groups

Set of groups user is a member of (set of strings).

handle

User handle, also the database key.

is_sysop

Whether the user is in the ‘sysop’ group.

lastcall

Time last called, time.time() epoch-formatted (float).

location

Legacy, used as a geographical location, group names, etc.

password

Password in encrypted form as tuple (salt, hash).

Not generally used directly, but by auth().

The setter of this property is provided a password in plain-text and encrypts it as given.

If a password has not yet been set, it is (None, None).

save()[source]

Save user record to database.

x84.bbs.userbase.check_anonymous_user(username)[source]

Boolean return when user is anonymous and is allowed.

x84.bbs.userbase.check_bye_user(username)[source]

Boolean return when username matches byecmds in ini cfg.

x84.bbs.userbase.check_new_user(username)[source]

Boolean return when username matches newcmds ini cfg.

x84.bbs.userbase.check_user_password(username, password)[source]

Boolean return when username and password match user record.

x84.bbs.userbase.check_user_pubkey(username, public_key)[source]

Boolean return when public_key matches user record.

x84.bbs.userbase.find_user(handle)[source]

Discover and return matching user by handle, case-insensitive.

Returns:matching handle as str, or None if not found.
Return type:None or str.
x84.bbs.userbase.get_digestpw()[source]

Returns singleton to password digest routine.

x84.bbs.userbase.get_user(handle)[source]

Returns User record by handle.

Return type:User
Returns:instance of User
x84.bbs.userbase.list_users()[source]

Returns all user handles.

Return type:list

:returns list of user handles.

x84.bbs.userbase.parse_public_key(user_pubkey)[source]

Return paramiko key class instance of a user’s public key text.

x84.bbs.ansiwin

Ansi Windowing package for x/84.

class x84.bbs.ansiwin.AnsiWindow(height, width, yloc, xloc, colors=None, glyphs=None)[source]

Bases: object

Provides position-relative drawing routines within a region.

The AnsiWindow base class provides position-relative window drawing routines to terminal interfaces, such as pager windows, editors, and lightbar lists, as well as some drawing niceties such as borders, text alignment

Class initializer for base windowing class.

Parameters:
  • width (int) – width of window.
  • height (int) – height of window.
  • yloc (int) – y-location of window.
  • xloc (int) – x-location of window.
  • colors (dict) – color theme.
  • glyphs (dict) – bordering window character glyphs.
align(text, width=None)[source]

Return text aligned to width using self.alignment.

When None (default), the visible width of this window is used.

alignment

Horizontal justification of text content for method align.

border()[source]

Return sequence suitable for drawing window border.

clear()[source]

Return sequence suitable for erasing contents window.

erase()[source]

Return sequence suitable for erasing full window (with border).

erase_border()[source]

Return sequence suitable for erasing only the window border.

footer(text)[source]

Return sequence for displaying text on bottom border of window.

init_theme(colors=None, glyphs=None)[source]

Set glyphs and colors appropriate for “theming”.

This is called by the class initializer.

isinview()[source]

Whether this window is in bounds of terminal dimensions.

iswithin(win)

Whether target window, win is within this windows bounds.

moved

Whether movement has occurred (bool).

pos(yloc=None, xloc=None)[source]

Return sequence to move cursor to window-relative position.

resize(height=None, width=None, yloc=None, xloc=None)[source]

Adjust window dimensions by given parameter.

title(ansi_text)[source]

Return sequence for displaying text on top border of window.

visible_height

Visible height of window after accounting for padding.

visible_width

Visible width of window after accounting for padding.

willfit(win)[source]

Whether target window, win is within this windows bounds.

xpadding

Horizontal padding of window border.

ypadding

Vertical padding of window border.

x84.bbs.dbproxy

Database proxy helper for x/84.

class x84.bbs.dbproxy.DBProxy(schema, table='unnamed', use_session=True)[source]

Bases: object

Provide dictionary-like object interface to shared database.

A database call, such as __len__() or keys() is issued as a command to the main engine when use_session is True, which spawns a thread to acquire a lock on the database and return the results via IPC pipe transfer.

Class initializer.

Parameters:
  • scheme (str) – database key, becomes basename of .sqlite3 file.
  • table (str) – optional database table.
  • use_session (bool) – Whether iterable returns should be sent over an IPC pipe (client is a x84.bbs.session.Session instance), or returned directly (such as used by the main thread engine components.)
acquire()[source]

Acquire system-wide lock on database.

copy() → a shallow copy of D[source]
get(k[, d]) → D[k] if k in D, else d. d defaults to None.[source]
has_key(k) → True if D has a key k, else False[source]
items() → list of D's (key, value) pairs, as 2-tuples[source]
iteritems() → an iterator over the (key, value) items of D[source]
iterkeys() → an iterator over the keys of D[source]
itervalues() → an iterator over the values of D[source]
keys() → list of D's keys[source]
pop(k[, d]) → v, remove specified key and return the corresponding value.[source]

If key is not found, d is returned if given, otherwise KeyError is raised

popitem() → (k, v), remove and return some (key, value) pair as a[source]

2-tuple; but raise KeyError if D is empty.

proxy_iter(method, *args)[source]

Proxy for iterable dictionary method calls.

proxy_iter_session(method, *args)[source]

Proxy for iterable-return method calls over session IPC pipe.

proxy_method(method, *args)[source]

Proxy for dictionary method calls.

proxy_method_direct(method, *args)[source]

Proxy for direct dictionary method calls.

proxy_method_session(method, *args)[source]

Proxy for dictionary method calls over IPC pipe.

release()[source]

Release system-wide lock on database.

setdefault(k[, d]) → D.get(k,d), also set D[k]=d if k not in D[source]
update([E, ]**F) → None. Update D from dict/iterable E and F.[source]

If E present and has a .keys() method, does: for k in E: D[k] = E[k] If E present and lacks .keys() method, does: for (k, v) in E: D[k] = v In either case, this is followed by: for k in F: D[k] = F[k]

values() → list of D's values[source]

x84.bbs.exception

Custom exceptions for x/84.

exception x84.bbs.exception.Disconnected[source]

Bases: exceptions.Exception

Thrown when a client is disconnected.

exception x84.bbs.exception.Goto(script, *args, **kwargs)[source]

Bases: exceptions.Exception

Thrown to change script without returning.

x84.bbs.msgbase

Messaging database package for x/84.

class x84.bbs.msgbase.Msg(recipient=None, subject=u'', body=u'')[source]

Bases: object

A record spec for messages held in the msgbase.

It contains many default properties to describe a conversation:

  • stime, the time the message was sent.
  • author, recipient, subject, and body are envelope parameters.
  • tags is for use with message groupings, containing a list of strings that other messages may share in relation.
  • parent points to the message this message directly refers to.
  • children is a set of indices replied by this message.
ctime

Datetime message was instantiated

Return type:datetime.datetime
queue_for_network()[source]

Queue message for networks, hosting or sending.

save(send_net=True, ctime=None)[source]

Save message to database, recording ‘tags’ db.

As a side-effect, it may queue message for delivery to external systems, when configured.

stime

Datetime message was saved to database

Return type:datetime.datetime
x84.bbs.msgbase.format_origin_line()[source]

Format origin line for message quoting.

x84.bbs.msgbase.get_msg(idx=0)[source]

Return Msg record instance by index idx.

x84.bbs.msgbase.get_origin_line()[source]

Return origin configuration item of [msg] section.

x84.bbs.msgbase.list_msgs(tags=None)[source]

Return set of indices matching tags, or all by default.

x84.bbs.msgbase.list_privmsgs(handle=None)[source]

Return all private messages for given user handle.

x84.bbs.msgbase.list_tags()[source]

Return set of available tags.

x84.bbs.msgbase.to_localtime(tm_value)[source]

convert given UTC time to local time

x84.bbs.msgbase.to_utctime(tm_value)[source]

convert given local time to UTC time

x84.bbs.selector

Left/Right lightbar choice selector for x/84.

class x84.bbs.selector.Selector(yloc, xloc, width, left, right, **kwargs)[source]

Bases: x84.bbs.ansiwin.AnsiWindow

A two-state horizontal lightbar interface.

Class initializer.

Initialize a selector of width, y x, and left/right values.

Parameters:
  • width (int) – width of window.
  • yloc (int) – y-location of selector.
  • xloc (int) – x-location of selector.
  • colors (dict) – color theme, only key value of selected and unselected is used.
  • keyset (dict) – command keys, global VI_KEYSET is used by default, augmented by application keys such as home, end, pgup, etc.
  • left (str) – text string of left-side selection.
  • right (str) – text string of right-side selection.
init_keystrokes(keyset)[source]

Sets keyboard keys for various editing keystrokes.

init_theme(colors=None, glyphs=None)[source]

Set glyphs and colors appropriate for “theming”.

This is called by the class initializer.

left

Left-side value.

move_left()[source]

Move selection left, return string suitable for refresh.

move_right()[source]

Move selection right, return string suitable for refresh.

process_keystroke(keystroke)[source]

Process the keystroke and return string to refresh.

Parameters:keystroke (blessed.keyboard.Keystroke) – input from inkey().
Return type:str
Returns:string sequence suitable for refresh.
quit

Whether a ‘quit’ character has been handled, such as escape.

read()[source]

Reads input until the ENTER or ESCAPE key is pressed (Blocking).

refresh()[source]

Return string sequence suitable for refresh.

right

Right-side value.

selected

Whether the carriage return character has been handled.

selection

Current selection.

toggle()[source]

Toggle selection, return string suitable for refresh.

x84.bbs.telnet

Utility functions for clients based on telnetlib for x/84.

x84.bbs.telnet.callback_cmdopt(socket, cmd, opt, env_term=None, width=None, height=None)[source]

Callback for telnetlib.Telnet.set_option_negotiation_callback.