def process_keystroke(inp, key=None): """ Process general keystroke and call routines. """ from x84.bbs import getsession, DBProxy, gosub, echo session = getsession() if inp is None: return False elif type(inp) is int: return False elif inp in (u't', u'T') and key is not None: bbs = DBProxy('bbslist')[key] gosub('telnet', bbs['address'], bbs['port'],) elif inp in (u'a', u'A'): add_bbs() elif inp in (u'c', u'C') and key is not None: add_comment(key) elif inp in (u'r', u'R') and key is not None: rate_bbs(key) elif inp in (u'i', u'I') and key is not None: echo(get_bbsinfo(key) + '\r\n') elif inp in (u'v', u'V') and key is not None: view_ansi(key) elif inp in (u'd', u'D') and key is not None and ( 'sysop' in session.user.groups): del DBProxy('bbslist')[key] else: return False # unhandled return True
def main(): """ Main menu entry point. """ from x84.default.common import display_banner session, term = getsession(), getterminal() text, width, height, dirty = u'', -1, -1, 2 menu_items = get_menu_items(session) editor = get_line_editor(term, menu_items) while True: if dirty == 2: # set syncterm font, if any if syncterm_font and term.kind.startswith('ansi'): echo(syncterm_setfont(syncterm_font)) if dirty: session.activity = 'main menu' top_margin = display_banner(art_file, encoding=art_encoding) + 1 echo(u'\r\n') if width != term.width or height != term.height: width, height = term.width, term.height text = render_menu_entries(term, top_margin, menu_items) echo(u''.join((text, display_prompt(term), editor.refresh()))) dirty = 0 event, data = session.read_events(('input', 'refresh')) if event == 'refresh': dirty = True continue elif event == 'input': session.buffer_input(data, pushback=True) # we must loop over inkey(0), we received a 'data' # event, though there may be many keystrokes awaiting for our # decoding -- or none at all (multibyte sequence not yet complete). inp = term.inkey(0) while inp: if inp.code == term.KEY_ENTER: # find matching menu item, for item in menu_items: if item.inp_key == editor.content.strip(): echo(term.normal + u'\r\n') gosub(item.script, *item.args, **item.kwargs) editor.content = u'' dirty = 2 break else: if editor.content: # command not found, clear prompt. echo(u''.join(( (u'\b' * len(editor.content)), (u' ' * len(editor.content)), (u'\b' * len(editor.content)),))) editor.content = u'' echo(editor.refresh()) elif inp.is_sequence: echo(editor.process_keystroke(inp.code)) else: echo(editor.process_keystroke(inp)) inp = term.inkey(0)
def process_keystroke(inp, key=None): """ Process general keystroke and call routines. """ from x84.bbs import getsession, DBProxy, gosub, echo session = getsession() if inp is None: return False elif type(inp) is int: return False elif inp in (u't', u'T') and key is not None: bbs = DBProxy('bbslist')[key] gosub( 'telnet', bbs['address'], bbs['port'], ) elif inp in (u'a', u'A'): add_bbs() elif inp in (u'c', u'C') and key is not None: add_comment(key) elif inp in (u'r', u'R') and key is not None: rate_bbs(key) elif inp in (u'i', u'I') and key is not None: echo(get_bbsinfo(key) + '\r\n') elif inp in (u'v', u'V') and key is not None: view_ansi(key) elif inp in (u'd', u'D') and key is not None and ('sysop' in session.user.groups): del DBProxy('bbslist')[key] else: return False # unhandled return True
def playback(sessions): """ Prompt for node and gosub ttyplay script for ttyrec of target session. """ from x84.bbs import gosub (node, tgt_session) = get_node(sessions) if node is not None: gosub('ttyplay', tgt_session['ttyrec']) return True
def edit(sessions): """ Prompt for node and gosub profile.py script for user of target session. """ from x84.bbs import gosub (node, tgt_session) = get_node(sessions) if node is not None: gosub('profile', tgt_session['handle']) return True
def edit(sessions): """ Prompt for node and gosub profile.py script for user of target session. """ from x84.bbs import gosub (node, tgt_session) = get_node(sessions) if node is not None: gosub('profile', handle=tgt_session['handle']) return True
def chat(sessions): """ Prompt for node and page target session for chat. Sysop will send session id of -1, indicating the chat is forced. """ from x84.bbs import gosub, getsession (_, tgt_session) = get_node(sessions) if tgt_session and tgt_session['sid'] != getsession().sid: gosub('chat', dial=tgt_session['handle'], other_sid=tgt_session['sid'])
def watch(sessions): """ Prompt for node and gosub ttyplay script for ttyrec of target session, with 'peek' boolean set to True. """ from x84.bbs import gosub (node, tgt_session) = get_node(sessions) if node is not None: gosub('ttyplay', tgt_session['ttyrec'], True) return True
def chat(sessions): """ Prompt for node and page target session for chat. Sysop will send session id of -1, indicating the chat is forced. """ from x84.bbs import gosub, getsession (_, tgt_session) = get_node(sessions) if tgt_session and tgt_session["sid"] != getsession().sid: gosub("chat", dial=tgt_session["handle"], other_sid=tgt_session["sid"])
def chat(sessions): """ Prompt for node and page target session for chat. Sysop will send session id of -1, indicating the chat is forced. """ from x84.bbs import gosub, getsession session = getsession() (node, tgt_session) = get_node(sessions) if tgt_session and tgt_session != session: gosub('chat', dial=tgt_session['handle'], other_sid=tgt_session['sid'])
def sendmsg(sessions): """ Prompt for node and gosub 'writemsg' with recipient set to target user. """ from x84.bbs import gosub, Msg (node, tgt_session) = get_node(sessions) if node is not None: msg = Msg() msg.recipient = tgt_session['handle'] msg.tags.add('private') gosub('writemsg', msg) return True
def do_login(term): sep_ok = getattr(term, color_secondary)(u'::') sep_bad = getattr(term, color_primary)(u'::') colors = {'highlight': getattr(term, color_primary)} for _ in range(login_max_attempts): term.goto_y(10) echo(u'\r\n\r\n{sep} Login: '******'' if handle.strip() == u'': continue # user says goodbye if handle.lower() in bye_usernames: return # user applies for new account if new_allowed and handle.lower() in new_usernames: gosub(new_script) display_banner(term) continue # user wants to reset password if reset_allowed and handle.lower() == 'reset': gosub(reset_script) display_banner(term) continue # user wants to login anonymously if anonymous_allowed and handle.lower() in anonymous_names: user = User('anonymous') else: # authenticate password echo(u'\r\n\r\n{sep} Password: '******'' user = authenticate_user(handle, password) if not user: echo(u'\r\n\r\n{sep} Login failed.'.format(sep=sep_bad)) continue goto(top_script, handle=user.handle) echo(u'\r\n\r\n{sep} Too many authentication attempts.\r\n'.format( sep=sep_bad))
def do_intro_art(term, session): """ Display random art file, prompt for quick login. Bonus: allow chosing other artfiles with '<' and '>'. """ from x84.bbs import ini show_intro_art = False if ini.CFG.has_option('system', 'show_intro_art'): show_intro_art = ini.CFG.getboolean('system', 'show_intro_art') # set syncterm font, if any if syncterm_font and term.kind.startswith('ansi'): echo(syncterm_setfont(syncterm_font)) index = int(time.time()) % len(art_files) dirty = True echo(u'\r\n') while True: session.activity = 'top' if session.poll_event('refresh') or dirty: if show_intro_art: display_intro(term, index) else: return True display_prompt(term) dirty = False dirty = True inp = LineEditor(1, colors={'highlight': term.normal}).read() if inp is None or inp.lower() == u'y': # escape/yes: quick login return True # issue #242 : set 'N' as default, by adding a check for an empty # unicode string. elif inp.lower() in (u'n', u'\r', u'\n', u''): break if len(inp) == 1: echo(u'\b') if inp == u'!': echo(u'\r\n' * 3) gosub('charset') dirty = True elif inp == u'<': index -= 1 elif inp == u'>': index += 1 else: dirty = False
def do_login(term): sep_ok = getattr(term, color_secondary)(u'::') sep_bad = getattr(term, color_primary)(u'::') colors = {'highlight': getattr(term, color_primary)} for _ in range(login_max_attempts): echo(u'\r\n\r\n{sep} Login: '******'' if handle.strip() == u'': continue # user says goodbye if handle.lower() in bye_usernames: return # user applies for new account if new_allowed and handle.lower() in new_usernames: gosub(new_script) display_banner(term) continue # user wants to reset password if reset_allowed and handle.lower() == 'reset': gosub(reset_script) display_banner(term) continue # user wants to login anonymously if anonymous_allowed and handle.lower() in anonymous_names: user = User('anonymous') else: # authenticate password echo(u'\r\n\r\n{sep} Password: '******'' user = authenticate_user(handle, password) if not user: echo(u'\r\n\r\n{sep} Login failed.'.format(sep=sep_bad)) continue goto(top_script, handle=user.handle) echo(u'\r\n\r\n{sep} Too many authentication attempts.\r\n' .format(sep=sep_bad))
def prompt_body(msg): """ Prompt for 'body' of message, executing 'editor' script. """ from x84.bbs import echo, Selector, getterminal, getsession, gosub term = getterminal() session = getsession() inp = Selector(yloc=term.height - 1, xloc=term.width - 22, width=20, left=u'CONtiNUE', right=u'CANCEl') # check for previously existing draft if 0 != len(session.user.get('draft', u'')): # XXX display age of message inp = Selector(yloc=term.height - 1, xloc=term.width - 22, width=20, left=u'REStORE', right=u'ERASE') blurb = u'CONtiNUE PREViOUSlY SAVEd dRAft ?' echo(u'\r\n\r\n') echo(term.move(inp.yloc, inp.xloc - len(blurb))) echo(term.bold_yellow(blurb)) selection = inp.read() echo(term.move(inp.yloc, 0) + term.clear_eol) if selection == u'REStORE': msg.body = session.user['draft'] echo(u'\r\n\r\n') session.user['draft'] = msg.body if gosub('editor', 'draft'): echo(u'\r\n\r\n' + term.normal) msg.body = session.user.get('draft', u'') del session.user['draft'] return 0 != len(msg.body.strip()) return False
def chat(sessions): """ Prompt for node and page target session for chat. Sysop will send session id of -1, indicating the chat is forced. """ from x84.bbs import gosub, getsession session = getsession() (node, tgt_session) = get_node(sessions) if node is not None: # page other user, channel = tgt_session['sid'] sender = (session.user.handle if not 'sysop' in session.user.groups else -1) session.send_event('route', (tgt_session['sid'], 'page', channel, sender)) gosub('chat', channel) return True
def chat(sessions): """ Prompt for node and page target session for chat. Sysop will send session id of -1, indicating the chat is forced. """ from x84.bbs import gosub, getsession session = getsession() (node, tgt_session) = get_node(sessions) if node is not None: # page other user, channel = tgt_session['sid'] sender = (session.user.handle if not 'sysop' in session.user.groups else -1) session.send_event('route', ( tgt_session['sid'], 'page', channel, sender)) gosub('chat', channel) return True
def main(): """ Main procedure. """ # by default, nothing is done. from x84.bbs import getsession, gosub assert 'sysop' in getsession().user.groups #return migrate_105lc() #return nothing() return gosub('test_keyboard_keys')
def do_intro_art(term, session): """ Display random art file, prompt for quick login. Bonus: allow chosing other artfiles with '<' and '>'. """ editor_colors = {'highlight': term.black_on_red} # set syncterm font, if any if syncterm_font and term._kind.startswith('ansi'): echo(syncterm_setfont(syncterm_font)) index = int(time.time()) % len(art_files) dirty = True echo(u'\r\n') while True: session.activity = 'top' if session.poll_event('refresh') or dirty: display_intro(term, index) display_prompt(term) dirty = False dirty = True inp = LineEditor(1, colors=editor_colors).read() if inp is None or inp.lower() == u'y': # escape/yes: quick login return True elif inp.lower() == u'n': break if len(inp) == 1: echo(u'\b') if inp == u'!': echo(u'\r\n' * 3) gosub('charset') dirty = True elif inp == u'<': index -= 1 elif inp == u'>': index += 1 else: dirty = False
def main(): """ Main procedure. """ from x84.bbs import getsession, getterminal, echo, getch, gosub session, term = getsession(), getterminal() lcallers, lcalls_txt = lc_retrieve() lbr = None dirty = True handle = None if (0 == term.number_of_colors or session.user.get('expert', False)): echo(redraw(None)) return dummy_pager(lcalls_txt.split('\n')) while lbr is None or not lbr.quit: if dirty or lbr is None or session.poll_event('refresh'): session.activity = u'Viewing last callers' lcallers, lcalls_txt = lc_retrieve() pos = lbr.position if lbr is not None else (0, 0) lbr = get_lightbar(lcallers, lcalls_txt) if pos: lbr.position = pos echo(redraw(lbr)) echo(refresh_opts(lbr, handle)) sel = lbr.selection[0] if sel != handle or dirty: handle = sel echo(refresh_opts(lbr, handle)) echo(lbr.pos(lbr.yloc + (lbr.height - 1))) dirty = False continue inp = getch(1) if inp is not None: if inp in (u'v', u'V'): view_plan(handle) dirty = True elif inp in (u'e', u'E') and 'sysop' in session.user.groups: gosub('profile', handle) dirty = True else: echo(lbr.process_keystroke(inp))
def do_intro_art(term, session): """ Display random art file, prompt for quick login. Bonus: allow chosing other artfiles with '<' and '>'. """ # set syncterm font, if any if syncterm_font and term.kind.startswith('ansi'): echo(syncterm_setfont(syncterm_font)) index = int(time.time()) % len(art_files) dirty = True echo(u'\r\n') while True: session.activity = 'top' if session.poll_event('refresh') or dirty: display_intro(term, index) display_prompt(term) dirty = False dirty = True inp = LineEditor(1, colors={'highlight': term.normal}).read() if inp is None or inp.lower() == u'y': # escape/yes: quick login return True # issue #242 : set 'N' as default, by adding a check for an empty # unicode string. elif inp.lower() in (u'n', u'\r', u'\n', u''): break if len(inp) == 1: echo(u'\b') if inp == u'!': echo(u'\r\n' * 3) gosub('charset') dirty = True elif inp == u'<': index -= 1 elif inp == u'>': index += 1 else: dirty = False
def edit_description(filepath, db_desc): """ Edit file description. """ from x84.bbs import gosub new_desc = None if filepath in db_desc: new_desc = u'\r\n'.join( [line.decode('cp437_art') for line in db_desc[filepath]]) new_desc = gosub('editor', continue_draft=new_desc) if not new_desc: return with db_desc: db_desc[filepath] = new_desc.splitlines()
def try_reset(user): """ Prompt for password reset. """ from x84.bbs import echo, getch, gosub prompt_reset = u'RESEt PASSWORD (bY E-MAil)? [yn]' echo(prompt_reset) while True: inp = getch() if inp in (u'y', u'Y'): return gosub('pwreset', user.handle) elif inp in (u'n', u'N'): echo(u'\r\n\r\n') return False
def edit_description(filepath, db_desc): """ Edit file description. """ from x84.bbs import gosub new_desc = None if filepath in db_desc: new_desc = u'\r\n'.join([line.decode('cp437_art') for line in db_desc[filepath]]) new_desc = gosub('editor', continue_draft=new_desc) if not new_desc: return with db_desc: db_desc[filepath] = new_desc.splitlines()
def main(handle=None): """ Main procedure. """ # pylint: disable=R0914,R0912,R0915 # Too many local variables # Too many branches # Too many statements session, term = getsession(), getterminal() session.activity = 'top' # attempt to coerce encoding of terminal to match session. coerce_terminal_encoding(term, session.encoding) # fetch user record user = get_user_record(handle) # register call login(session, user) # display art and prompt for quick login quick = do_intro_art(term, session) echo(term.move_down() * 3) # only display news if the account has not # yet read the news since last update. gosub('news', quick=True) if not quick: # display last 10 callers, if any gosub('lc') # one-liners gosub('ol') goto('main')
def main(): session, term = getsession(), getterminal() session.activity = u'bulletins menu' dirty = True while True: if dirty or session.poll_event('refresh'): echo(term.clear()) showansi('bulletinsmenu.ans') echo(u'\r\n' + term.normal + term.white + u' [' + term.blue + u'Select bulletin' + term.white + u']: ') inp = getch() dirty = True if inp == u'1': toplist('calls') elif inp == u'2': toplist('msgs') elif inp == u'3': gosub('textbrowse') else: # any other key will return to main menu return
def main(): session, term = getsession(), getterminal() session.activity = u'bulletins menu' dirty = True while True: if dirty or session.poll_event('refresh'): echo(term.clear()) showansi('bulletinsmenu.ans') echo (u'\r\n'+term.normal+term.white+u' ['+term.blue+u'Select bulletin'+term.white+u']: ') inp = getch() dirty = True if inp == u'1': toplist('calls') elif inp == u'2': toplist('msgs') elif inp == u'3': gosub('textbrowse') else: # any other key will return to main menu return
def main(): """ Main procedure. """ from x84.bbs import getsession, echo, getch, gosub import codecs import time import os # pylint: disable=W0603 # Using the global statement global NEWS, NEWSAGE # in-memory cache session = getsession() session.activity = 'Reading news' newsfile = os.path.join(os.path.dirname(__file__), 'art', 'news.txt') if not os.path.exists(newsfile): echo(u'\r\n\r\nNo news.') return pager = None dirty = True while True: if session.poll_event('refresh'): dirty = True if dirty: if NEWS is None or os.stat(newsfile).st_mtime > NEWSAGE: # open a utf-8 file for international encodings/art/language NEWSAGE = time.time() NEWS = [ line.rstrip() for line in codecs.open(newsfile, 'rb', 'utf8') ] if (session.user.get('expert', False)): return dummy_pager(NEWS) pos = pager.position if pager is not None else None pager = get_pager(NEWS, pos) echo(redraw(pager)) dirty = False inp = getch(1) if inp is not None: if inp in ( u'e', u'E', ) and 'sysop' in session.user.groups: session.user['news'] = u'\r\n'.join(NEWS) if gosub('editor', 'news'): NEWS = session.user['news'].splitlines() codecs.open(newsfile, 'wb', 'utf8').write(u'\r\n'.join(NEWS)) dirty = True else: echo(pager.process_keystroke(inp)) if pager.quit: return
def prompt_body(term, msg, colors): """ Prompt for and set 'body' of message by executing 'editor' script. """ with term.fullscreen(): content = gosub("editor", save_key=None, continue_draft=msg.body) # set syncterm font, if any if term.kind.startswith("ansi"): echo(syncterm_setfont(syncterm_font)) echo(term.move(term.height, 0) + term.normal + u"\r\n") if content and content.strip(): msg.body = content return True xpos = max(0, (term.width // 2) - (80 // 2)) echo(u"".join((term.move_x(xpos), colors["highlight"]("Message canceled."), term.clear_eol))) term.inkey(1) return False
def prompt_body(term, msg, colors): """ Prompt for and set 'body' of message by executing 'editor' script. """ with term.fullscreen(): content = gosub('editor', save_key=None, continue_draft=msg.body) # set syncterm font, if any if term.kind.startswith('ansi'): echo(syncterm_setfont(syncterm_font)) echo(term.move(term.height, 0) + term.normal + u'\r\n') if content and content.strip(): msg.body = content return True xpos = max(0, (term.width // 2) - (80 // 2)) echo(u''.join((term.move_x(xpos), colors['highlight']('Message canceled.'), term.clear_eol))) term.inkey(1) return False
def main(): """ Main procedure. """ from x84.bbs import getsession, echo, getch, gosub import codecs import time import os # pylint: disable=W0603 # Using the global statement global NEWS, NEWSAGE # in-memory cache session = getsession() session.activity = 'Reading news' newsfile = os.path.join(os.path.dirname(__file__), 'art', 'news.txt') if not os.path.exists(newsfile): echo(u'\r\n\r\nNo news.') return pager = None dirty = True while True: if session.poll_event('refresh'): dirty = True if dirty: if NEWS is None or os.stat(newsfile).st_mtime > NEWSAGE: # open a utf-8 file for international encodings/art/language NEWSAGE = time.time() NEWS = [line.rstrip() for line in codecs.open(newsfile, 'rb', 'utf8')] if (session.user.get('expert', False)): return dummy_pager(NEWS) pos = pager.position if pager is not None else None pager = get_pager(NEWS, pos) echo(redraw(pager)) dirty = False inp = getch(1) if inp is not None: if inp in (u'e', u'E',) and 'sysop' in session.user.groups: session.user['news'] = u'\r\n'.join(NEWS) if gosub('editor', 'news'): NEWS = session.user['news'].splitlines() codecs.open(newsfile, 'wb', 'utf8').write( u'\r\n'.join(NEWS)) dirty = True else: echo(pager.process_keystroke(inp)) if pager.quit: return
def prompt_body(msg): """ Prompt for 'body' of message, executing 'editor' script. """ from x84.bbs import echo, Selector, getterminal, getsession, gosub term = getterminal() session = getsession() inp = Selector(yloc=term.height - 1, xloc=term.width - 22, width=20, left=u'CONtiNUE', right=u'CANCEl') blurb = u'CONtiNUE tO Edit MESSAGE bOdY' echo(u'\r\n\r\n') echo(term.move(inp.yloc, inp.xloc - len(blurb))) echo(term.bold_yellow(blurb)) selection = inp.read() echo(term.move(inp.yloc, 0) + term.clear_eol) if selection != u'CONtiNUE': return False if 0 != len(session.user.get('draft', u'')): inp = Selector(yloc=term.height - 1, xloc=term.width - 22, width=20, left=u'REStORE', right=u'ERASE') blurb = u'CONtiNUE PREViOUSlY SAVEd dRAft ?' echo(u'\r\n\r\n') echo(term.move(inp.yloc, inp.xloc - len(blurb))) echo(term.bold_yellow(blurb)) selection = inp.read() echo(term.move(inp.yloc, 0) + term.clear_eol) if selection == u'REStORE': msg.body = session.user['draft'] echo(u'\r\n\r\n') session.user['draft'] = msg.body if gosub('editor', 'draft'): echo(u'\r\n\r\n' + term.normal) msg.body = session.user.get('draft', u'') del session.user['draft'] return 0 != len(msg.body.strip()) return False
def main(handle=None): """ Main procedure. """ # pylint: disable=R0914,R0912,R0915 # Too many local variables # Too many branches # Too many statements session, term = getsession(), getterminal() session.activity = 'top' # attempt to coerce encoding of terminal to match session. echo ({ # ESC %G activates UTF-8 with an unspecified implementation # level from ISO 2022 in a way that allows to go back to # ISO 2022 again. 'utf8': unichr(27) + u'%G', # ESC %@ returns to ISO 2022 in case UTF-8 had been entered. # ESC ) U Sets character set G1 to codepage 437, such as on # Linux vga console. 'cp437': unichr(27) + u'%@' + unichr(27) + u')U', }.get(session.encoding, u'')) # fetch user record user = get_user_record(handle) # register call login(session, user) # display art and prompt for quick login quick = do_intro_art(term, session) echo(term.move_down() * 3) # only display news if the account has not # yet read the news since last update. gosub('news', quick=True) if not quick: # display last 10 callers, if any gosub('lc') # one-liners gosub('ol') goto('main')
def prompt_body(msg): """ Prompt for 'body' of message, executing 'editor' script. """ from x84.bbs import echo, Selector, getterminal, getsession, gosub term = getterminal() session = getsession() inp = Selector(yloc=term.height - 1, xloc=term.width - 22, width=20, left=u'CONtiNUE', right=u'CANCEl') # check for previously existing draft if 0 != len(session.user.get('draft', u'')): # XXX display age of message inp = Selector(yloc=term.height - 1, xloc=term.width - 22, width=20, left=u'REStORE', right=u'ERASE') blurb = u'CONtiNUE PREViOUSlY SAVEd dRAft ?' echo(u'\r\n\r\n') echo(term.move(inp.yloc, inp.xloc - len(blurb))) echo(term.bold_yellow(blurb)) selection = inp.read() echo(term.move(inp.yloc, 0) + term.clear_eol) if selection == u'REStORE': msg.body = session.user['draft'] else: # delete the draft del session.user['draft'] echo(u'\r\n\r\n') content = gosub('editor', save_key=None, continue_draft=msg.body) if content and content.strip(): echo(u'\r\n\r\n' + term.normal) msg.body = content return True return False
def dummy_pager(last_callers): """ Dummy pager for displaying last callers """ # pylint: disable=R0914 # Too many local variables from x84.bbs import getterminal, getsession, echo, getch, ini, find_user from x84.bbs import LineEditor, Ansi, list_users, get_user, gosub session, term = getsession(), getterminal() msg_prompt = ( u'\r\n%sONtiNUE, %stOP, %sON-StOP %siEW .PlAN%s ?\b\b' % ( term.bold(u'[c]'), term.bold(u'[s]'), term.bold(u'n'), term.bold(u'[v]'), u' [e]dit USR' if ( 'sysop' in session.user.groups) else u'',)) msg_partial = u'PARtiAl MAtChES' msg_prompt_handle = u'ViEW .PlAN ::- ENtER hANdlE: ' redraw() echo(u'\r\n\r\n') nonstop = False row = 10 # after-art, for txt in last_callers: echo(Ansi(txt).ljust(term.width / 2).center(term.width)) echo(u'\r\n') row += 1 if ((not nonstop and row > 0 and 0 == (row % (term.height - 3))) or (row == len(last_callers) - 1)): echo(msg_prompt) inp = getch() row = 2 if inp in (u's', u'S', u'q', u'Q', term.KEY_EXIT): return if inp in (u'v', u'V') or 'sysop' in session.user.groups and ( inp in (u'e', u'E')): echo(u'\r\n\r\n') echo(msg_prompt_handle) handle = LineEditor(ini.CFG.getint('nua', 'max_user')).read() usrlist = list_users() if handle is None or 0 == len(handle.strip()): continue handle = handle.strip() if handle.lower() in [nick.lower() for nick in list_users()]: nick = ((_nick for _nick in usrlist if _nick.lower() == handle.lower()).next()) if find_user(nick): user = get_user(nick) if 'sysop' in session.user.groups and ( inp in (u'e', u'E')): gosub('profile', user.handle) else: view_plan(user.handle) else: misses = [nick for nick in usrlist.keys() if nick.lower().startswith(handle[:1].lower())] if len(misses) > 0: echo(u'%s:\r\n\r\n%s\r\n' % (msg_partial, Ansi(', '.join(misses)).wrap(term.width))) continue if inp in ('n', u'N'): nonstop = True echo(u'\r\n\r\n') pak()
def main(): """ Main procedure. """ from x84.bbs import getterminal, getsession, getch, goto, gosub from x84.bbs import ini, echo from ConfigParser import Error as ConfigError import os import logging key_map = { '$': 'bulletins', 'n': 'news', 'p': 'writemsg', 'r': 'readmsgs', 'c': 'chat', 'i': 'ircchat', 'l': 'lc', 'o': 'ol', 'b': 'bbslist', 'f': 'weather', 't': 'tetris', 'w': 'online', '!': 'charset', 's': 'si', 'u': 'userlist', 'e': 'profile', 'x': 'main', 'g': 'logoff', '#': 'lord' } # add LORD to menu only if enabled, logger = logging.getLogger() session, term = getsession(), getterminal() session.activity = u'Lightbar Main menu' echo(term.clear) show_banner() lb = lb_init() term_width = term.width term_height = term.height inp = -1 dirty = True while True: if dirty or session.poll_event('refresh'): lb_refresh(lb) inp = getch(1) dirty = True # terminal dimensions may change, so we adapt to that if (term_width != term.width or term_height != term.height): echo(term.clear) show_banner() lb = lb_init() lb_refresh(lb) term_width = term.width term_height = term.height if inp is not None: echo(lb.process_keystroke(inp)) if lb.selected and lb.selection[0] is not None: script = key_map.get(lb.selection[0]) if script: if script == u'x': goto('main') elif script == u'v' and 'sysop' in session.user.groups: gosub('ttyplay') else: echo(term.clear) gosub(script) echo(term.clear) show_banner() else: handled = False try: for option in ini.CFG.options('sesame'): if option.endswith('_key'): door = option.replace('_key', '') key = ini.CFG.get('sesame', option) if inp == key: gosub('sesame', door) handled = True break except ConfigError: pass if not handled: dirty = False
def main(): """ Main procedure. """ # pylint: disable=R0912 # Too many branches from x84.bbs import getsession, getch, goto, gosub, ini from ConfigParser import Error as ConfigError session = getsession() inp = -1 dirty = True while True: if dirty or session.poll_event('refresh'): refresh() inp = getch(1) dirty = True if inp == u'*': goto('main') # reload main menu using hidden option '*' elif inp == u'$': gosub('bulletins') elif inp == u'b': gosub('bbslist') elif inp == u'l': gosub('lc') elif inp == u'o': gosub('ol') elif inp == u's': gosub('si') elif inp == u'u': gosub('userlist') elif inp == u'w': gosub('online') elif inp == u'n': gosub('news') elif inp == u'f': gosub('weather') elif inp == u'e': gosub('profile') elif inp == u'#': gosub('lord') elif inp == u't': gosub('tetris') elif inp == u'c': gosub('chat') elif inp == u'i': gosub('ircchat') elif inp == u'p': gosub('writemsg') elif inp == u'r': gosub('readmsgs') elif inp == u'g': goto('logoff') elif inp == u'!': gosub('charset') elif inp == '\x1f' and 'sysop' in session.user.groups: # ctrl+_, run a debug script gosub('debug') else: handled = False try: for option in ini.CFG.options('sesame'): if option.endswith('_key'): door = option.replace('_key', '') key = ini.CFG.get('sesame', option) if inp == key: gosub('sesame', door) handled = True break except ConfigError: pass if not handled: dirty = False
def read_messages(msgs, title, currentpage, totalpages, threadid, cachetime): """ Provide message reader UI given message list ``msgs``, with new messages in list ``new``. """ # pylint: disable=R0914,R0912,R0915 # Too many local variables # Too many branches # Too many statements from x84.bbs import timeago, get_msg, getterminal, echo, gosub from x84.bbs import ini, Pager, getsession, getch, Ansi, Msg import x84.default.writemsg session, term = getsession(), getterminal() session.activity = 'reading msgs' # build header #len_idx = max([len('%d' % (_idx,)) for _idx in msgs]) len_idx = 40 len_author = ini.CFG.getint('nua', 'max_user') len_ago = 9 len_subject = ini.CFG.getint('msg', 'max_subject') len_preview = min(len_idx + len_author + len_ago + len_subject + -1, term.width - 2) reply_depth = ini.CFG.getint('msg', 'max_depth') indent_start, indent, indent_end = u'\\', u'-', u'> ' def get_header(msgs_idx): """ Return list of tuples, (idx, unicodestring), suitable for Lightbar. """ import datetime msg_list = list() def head(msg, depth=0, maxdepth=reply_depth): """ This recursive routine finds the 'head' message of any relationship, up to maxdepth. """ if (depth <= maxdepth and hasattr(msg, 'parent') and msg.parent is not None): return head(get_msg(msg.parent), depth + 1, maxdepth) return msg.idx, depth for idx, txt in enumerate(msgs_idx): author, subj = txt[0], txt[1] msg_list.append([idx, author, subj]) return msg_list def get_selector(mailbox, prev_sel=None): """ Provide Lightbar UI element given message mailbox returned from function get_header, and prev_sel as previously instantiated Lightbar. """ from x84.bbs import Lightbar pos = prev_sel.position if prev_sel is not None else (0, 0) sel = Lightbar( height=(term.height / 3 if term.width < 140 else term.height - 3), width=len_preview, yloc=2, xloc=0) sel.glyphs['top-horiz'] = u'' sel.glyphs['left-vert'] = u'' sel.colors['highlight'] = term.yellow_reverse sel.update(mailbox) sel.position = pos return sel def get_reader(): """ Provide Pager UI element for message reading. """ reader_height = (term.height - (term.height / 3) - 2) reader_indent = 2 reader_width = min(term.width - 1, min(term.width - reader_indent, 80)) reader_ypos = ((term.height - 1 ) - reader_height if (term.width - reader_width) < len_preview else 2) reader_height = term.height - reader_ypos - 1 msg_reader = Pager( height=reader_height, width=reader_width, yloc=reader_ypos, xloc=min(len_preview + 2, term.width - reader_width)) msg_reader.glyphs['top-horiz'] = u'' msg_reader.glyphs['right-vert'] = u'' return msg_reader # def format_msg(reader, idx): # """ Format message of index ``idx`` into Pager instance ``reader``. """ # msg = msgs[idx] # author = msg[1][0] # body = msg[1][1] # ucs = u'\r\n'.join(( # (u''.join(( # term.yellow('fROM: '), # (u'%s' % term.bold(author,)).rjust(len(author)), # u' ' * (reader.visible_width - (len(author) )), # ))), # u''.join(( # term.yellow('tO: '), # (Ansi( # term.yellow('tAGS: ') # + (u'%s ' % (term.bold(','),)).join(( # [term.bold_red(_tag) # if _tag in SEARCH_TAGS # else term.yellow(_tag) # for _tag in msg.tags]))).wrap( # reader.visible_width, # indent=u' ')), # (term.yellow_underline( # (u'SUbj: %s' % (msg.subject,)).ljust(reader.visible_width) # )), # u'', (msg.body),)) # return ucs def get_selector_title(mbox): return cachetime def get_selector_footer(currentpage, totalpages): return 'Page '+currentpage+'/'+totalpages def get_reader_footer(idx): """ Returns unicode string suitable for displaying as footer of reader when window is active """ return u''.join(( idx, term.yellow(u'- '), u' '.join(( term.yellow_underline(u'<') + u':back ', term.yellow_underline(u'r') + u':eply ', term.yellow_underline(u'q') + u':uit',)), term.yellow(u' -'),)) def refresh(reader, selector, mbox, title): """ Returns unicode string suitable for refreshing the screen. """ if READING: reader.colors['border'] = term.bold_yellow selector.colors['border'] = term.bold_black else: reader.colors['border'] = term.bold_black selector.colors['border'] = term.bold_yellow padd_attr = (term.bold_yellow if not READING else term.bold_black) sel_padd_right = padd_attr( u'-' + selector.glyphs['bot-horiz'] * ( selector.visible_width - len(Ansi(str(title))) - 7) + u'-\u25a0-' if READING else u'- -') sel_padd_left = padd_attr( selector.glyphs['bot-horiz'] * 3) idx = selector.selection[0] return u''.join((term.move(0, 0), term.clear, u'\r\n',cachetime, u'// REAdiNG MSGS ..'.center(term.width).rstrip(), selector.refresh(), selector.border() if READING else reader.border(), reader.border() if READING else selector.border(), selector.title( sel_padd_left + title + sel_padd_right), selector.footer(get_selector_footer(currentpage, totalpages) ) if not READING else u'', #reader.footer(get_reader_footer(u'Post '+str(idx)) reader.footer(get_reader_footer(cachetime) ) if READING else u'', reader.refresh(), )) echo((u'\r\n' + term.clear_eol) * (term.height - 1)) dirty = 2 msg_selector = None msg_reader = None idx = None # pylint: disable=W0603 # Using the global statement global READING while (msg_selector is None and msg_reader is None ) or not (msg_selector.quit or msg_reader.quit): if session.poll_event('refresh'): dirty = 2 if dirty: if dirty == 2: mailbox = get_header(msgs) msg_selector = get_selector(mailbox, msg_selector) idx = msg_selector.selection[0] msg_reader = get_reader() msg_reader.update(msgs[idx][1]) echo(refresh(msg_reader, msg_selector, msgs, title)) dirty = 0 inp = getch(1) if inp in (u'r', u'R'): reply_msgbody = quote_body(msgs[idx][1], max(30, min(79, term.width - 4)), msgs[idx][0]) echo(term.move(term.height, 0) + u'\r\n') session.user['draft'] = reply_msgbody if gosub('editor', 'draft'): makepost(threadid, session.user['draft']) dirty = 2 READING = False else: dirty = 1 #mark_read(idx) # also mark as read # 't' uses writemsg.prompt_tags() routine, how confusing .. elif inp in (u't',) and allow_tag(idx): echo(term.move(term.height, 0)) msg = get_msg(idx) if x84.default.writemsg.prompt_tags(msg): msg.save() dirty = 2 # spacebar marks as read, goes to next message elif inp in (u' ',): dirty = 1#2 if mark_read(idx) else 1 msg_selector.move_down() idx = msg_selector.selection[0] READING = False # D marks as deleted, goes to next message elif inp in (u'D',): dirty = 2 if mark_delete(idx) else 1 msg_selector.move_down() idx = msg_selector.selection[0] READING = False # U undeletes, does not move. elif inp in (u'U',): dirty = 2 if mark_undelete(idx) else 1 msg_selector.move_down() idx = msg_selector.selection[0] READING = False if READING: echo(msg_reader.process_keystroke(inp)) # left, <, or backspace moves UI if inp in (term.KEY_LEFT, u'<', u'h', '\b', term.KEY_BACKSPACE): READING = False dirty = 1 else: echo(msg_selector.process_keystroke(inp)) idx = msg_selector.selection[0] # right, >, or enter marks message read, moves UI if inp in (u'\r', term.KEY_ENTER, u'>', u'l', 'L', term.KEY_RIGHT): dirty = 1#2 if mark_read(idx) else 1 READING = True elif msg_selector.moved: dirty = 1 echo(term.move(term.height, 0) + u'\r\n') return
def read_messages(msgs, new): """ Provide message reader UI given message list ``msgs``, with new messages in list ``new``. """ # pylint: disable=R0914,R0912,R0915 # Too many local variables # Too many branches # Too many statements from x84.bbs import timeago, get_msg, getterminal, echo, gosub from x84.bbs import ini, Pager, getsession, getch, Ansi, Msg import x84.default.writemsg session, term = getsession(), getterminal() session.activity = 'reading msgs' # build header len_idx = max([len('%d' % (_idx,)) for _idx in msgs]) len_author = ini.CFG.getint('nua', 'max_user') len_ago = 9 len_subject = ini.CFG.getint('msg', 'max_subject') len_preview = min(len_idx + len_author + len_ago + len_subject + -1, term.width - 2) reply_depth = ini.CFG.getint('msg', 'max_depth') indent_start, indent, indent_end = u'\\', u'-', u'> ' def get_header(msgs_idx): """ Return list of tuples, (idx, unicodestring), suitable for Lightbar. """ import datetime msg_list = list() thread_indent = lambda depth: (term.red( (indent_start + (indent * depth) + indent_end)) if depth else u'') def head(msg, depth=0, maxdepth=reply_depth): """ This recursive routine finds the 'head' message of any relationship, up to maxdepth. """ if (depth <= maxdepth and hasattr(msg, 'parent') and msg.parent is not None): return head(get_msg(msg.parent), depth + 1, maxdepth) return msg.idx, depth for idx in msgs_idx: msg = get_msg(idx) author, subj = msg.author, msg.subject tm_ago = (datetime.datetime.now() - msg.stime).total_seconds() # pylint: disable=W0631 # Using possibly undefined loop variable 'idx' attr = lambda arg: ( term.bold_green(arg) if ( not idx in ALREADY_READ and msg.recipient == session.user.handle) else term.red(arg) if not idx in ALREADY_READ else term.yellow(arg)) status = [u'U' if not idx in ALREADY_READ else u' ', u'D' if idx in DELETED else u' ', ] row_txt = u'%s %s %s %s %s%s ' % ( u''.join(status), attr(str(idx).rjust(len_idx)), attr(author.ljust(len_author)), (timeago(tm_ago)).rjust(len_ago), attr(u'ago'), term.bold_black(':'),) msg_list.append((head(msg), idx, row_txt, subj)) msg_list.sort() return [(idx, row_txt + thread_indent(depth) + subj) for (_threadid, depth), idx, row_txt, subj in msg_list] def get_selector(mailbox, prev_sel=None): """ Provide Lightbar UI element given message mailbox returned from function get_header, and prev_sel as previously instantiated Lightbar. """ from x84.bbs import Lightbar pos = prev_sel.position if prev_sel is not None else (0, 0) sel = Lightbar( height=(term.height / 3 if term.width < 140 else term.height - 3), width=len_preview, yloc=2, xloc=0) sel.glyphs['top-horiz'] = u'' sel.glyphs['left-vert'] = u'' sel.colors['highlight'] = term.yellow_reverse sel.update(mailbox) sel.position = pos return sel def get_reader(): """ Provide Pager UI element for message reading. """ reader_height = (term.height - (term.height / 3) - 2) reader_indent = 2 reader_width = min(term.width - 1, min(term.width - reader_indent, 80)) reader_ypos = ((term.height - 1 ) - reader_height if (term.width - reader_width) < len_preview else 2) reader_height = term.height - reader_ypos - 1 msg_reader = Pager( height=reader_height, width=reader_width, yloc=reader_ypos, xloc=min(len_preview + 2, term.width - reader_width)) msg_reader.glyphs['top-horiz'] = u'' msg_reader.glyphs['right-vert'] = u'' return msg_reader def format_msg(reader, idx): """ Format message of index ``idx`` into Pager instance ``reader``. """ msg = get_msg(idx) sent = msg.stime.strftime(TIME_FMT) to_attr = term.bold_green if ( msg.recipient == session.user.handle) else term.underline ucs = u'\r\n'.join(( (u''.join(( term.yellow('fROM: '), (u'%s' % term.bold(msg.author,)).rjust(len_author), u' ' * (reader.visible_width - (len_author + len(sent))), sent,))), u''.join(( term.yellow('tO: '), to_attr((u'%s' % to_attr(msg.recipient,)).rjust(len_author) if msg.recipient is not None else u'All'),)), (Ansi( term.yellow('tAGS: ') + (u'%s ' % (term.bold(','),)).join(( [term.bold_red(_tag) if _tag in SEARCH_TAGS else term.yellow(_tag) for _tag in msg.tags]))).wrap( reader.visible_width, indent=u' ')), (term.yellow_underline( (u'SUbj: %s' % (msg.subject,)).ljust(reader.visible_width) )), u'', (msg.body),)) return ucs def get_selector_title(mbox, new): """ Returns unicode string suitable for displaying as title of mailbox. """ newmsg = (term.yellow(u' ]-[ ') + term.yellow_reverse(str(len(new))) + term.bold_underline(u' NEW')) if len(new) else u'' return u''.join((term.yellow(u'[ '), term.bold_yellow(str(len(mbox))), term.bold( u' MSG%s' % (u's' if 1 != len(mbox) else u'',)), newmsg, term.yellow(u' ]'),)) dispcmd_mark = lambda idx: ( (term.yellow_underline(u' ') + u':mark' + u' ') if idx not in ALREADY_READ else u'') dispcmd_delete = lambda idx: ( (term.yellow_underline(u'D') + u':elete' + u' ') if idx not in DELETED else u'') dispcmd_tag = lambda idx: ( (term.yellow_underline(u't') + u':ag' + u' ') if allow_tag(idx) else u'') def get_selector_footer(idx): """ Returns unicode string suitable for displaying as footer of mailbox when window is active. """ return u''.join(( term.yellow(u'- '), u''.join(( term.yellow_underline(u'>') + u':read ', term.yellow_underline(u'r') + u':eply ', dispcmd_mark(idx), dispcmd_delete(idx), dispcmd_tag(idx), term.yellow_underline(u'q') + u':uit',)), term.yellow(u' -'),)) def get_reader_footer(idx): """ Returns unicode string suitable for displaying as footer of reader when window is active """ return u''.join(( term.yellow(u'- '), u' '.join(( term.yellow_underline(u'<') + u':back ', term.yellow_underline(u'r') + u':eply ', dispcmd_delete(idx), dispcmd_tag(idx), term.yellow_underline(u'q') + u':uit',)), term.yellow(u' -'),)) def refresh(reader, selector, mbox, new): """ Returns unicode string suitable for refreshing the screen. """ if READING: reader.colors['border'] = term.bold_yellow selector.colors['border'] = term.bold_black else: reader.colors['border'] = term.bold_black selector.colors['border'] = term.bold_yellow title = get_selector_title(mbox, new) padd_attr = (term.bold_yellow if not READING else term.bold_black) sel_padd_right = padd_attr( u'-' + selector.glyphs['bot-horiz'] * ( selector.visible_width - len(Ansi(title)) - 7) + u'-\u25a0-' if READING else u'- -') sel_padd_left = padd_attr( selector.glyphs['bot-horiz'] * 3) idx = selector.selection[0] return u''.join((term.move(0, 0), term.clear, u'\r\n', u'// REAdiNG MSGS ..'.center(term.width).rstrip(), selector.refresh(), selector.border() if READING else reader.border(), reader.border() if READING else selector.border(), selector.title( sel_padd_left + title + sel_padd_right), selector.footer(get_selector_footer(idx) ) if not READING else u'', reader.footer(get_reader_footer(idx) ) if READING else u'', reader.refresh(), )) echo((u'\r\n' + term.clear_eol) * (term.height - 1)) dirty = 2 msg_selector = None msg_reader = None idx = None # pylint: disable=W0603 # Using the global statement global READING while (msg_selector is None and msg_reader is None ) or not (msg_selector.quit or msg_reader.quit): if session.poll_event('refresh'): dirty = 2 if dirty: if dirty == 2: mailbox = get_header(msgs) msg_selector = get_selector(mailbox, msg_selector) idx = msg_selector.selection[0] msg_reader = get_reader() msg_reader.update(format_msg(msg_reader, idx)) echo(refresh(msg_reader, msg_selector, msgs, new)) dirty = 0 inp = getch(1) if inp in (u'r', u'R'): reply_to = get_msg(idx) reply_msg = Msg() reply_msg.recipient = reply_to.author reply_msg.tags = reply_to.tags reply_msg.subject = reply_to.subject reply_msg.parent = reply_to.idx # quote between 30 and 79, 'screen width - 4' as variable dist. reply_msg.body = quote_body(reply_to, max(30, min(79, term.width - 4))) echo(term.move(term.height, 0) + u'\r\n') if gosub('writemsg', reply_msg): reply_msg.save() dirty = 2 READING = False else: dirty = 1 mark_read(idx) # also mark as read # 't' uses writemsg.prompt_tags() routine, how confusing .. elif inp in (u't',) and allow_tag(idx): echo(term.move(term.height, 0)) msg = get_msg(idx) if x84.default.writemsg.prompt_tags(msg): msg.save() dirty = 2 # spacebar marks as read, goes to next message elif inp in (u' ',): dirty = 2 if mark_read(idx) else 1 msg_selector.move_down() idx = msg_selector.selection[0] READING = False # D marks as deleted, goes to next message elif inp in (u'D',): dirty = 2 if mark_delete(idx) else 1 msg_selector.move_down() idx = msg_selector.selection[0] READING = False # U undeletes, does not move. elif inp in (u'U',): dirty = 2 if mark_undelete(idx) else 1 msg_selector.move_down() idx = msg_selector.selection[0] READING = False if READING: echo(msg_reader.process_keystroke(inp)) # left, <, or backspace moves UI if inp in (term.KEY_LEFT, u'<', u'h', '\b', term.KEY_BACKSPACE): READING = False dirty = 1 else: echo(msg_selector.process_keystroke(inp)) idx = msg_selector.selection[0] # right, >, or enter marks message read, moves UI if inp in (u'\r', term.KEY_ENTER, u'>', u'l', 'L', term.KEY_RIGHT): dirty = 2 if mark_read(idx) else 1 READING = True elif msg_selector.moved: dirty = 1 echo(term.move(term.height, 0) + u'\r\n') return
def process_keystroke(inp, user): """ Process keystroke, ``inp``, for target ``user``. """ # pylint: disable=R0914,R0912,R0915,R0911,W0603 # Too many local variables # Too many branches # Too many statements # Too many return statements # Using the global statement # ^ lol, this is one of those things that should be # refactored into smaller subroutines =) from x84.bbs import getsession, getterminal, echo, getch, gosub from x84.bbs import LineEditor, ScrollingEditor from x84.default.nua import set_email, set_location from x84.bbs.ini import CFG def_timeout = CFG.getint('system', 'timeout') global EXIT session, term = getsession(), getterminal() is_self = bool(user.handle == session.user.handle) invalid = u'\r\niNVAlid.' assert is_self or 'sysop' in session.user.groups if is_self and inp in (u'c', u'C'): gosub('charset') elif is_self and inp in (u't', u'T'): echo(term.move(term.height - 1, 0)) echo(ABOUT_TERM + u'\r\n') echo(u'\r\ntERMiNAl tYPE: ') term = LineEditor(30, session.env.get('TERM')).read() echo(u"\r\n\r\nset TERM to '%s'? [yn]" % (term,)) while True: inp2 = getch() if inp2 in (u'y', u'Y'): session.env['TERM'] = term break elif inp2 in (u'n', u'N'): break elif is_self and inp in (u'w', u'W'): echo(u'\r\ntERMiNAl Width: ') width = LineEditor(3, str(term.width)).read() try: width = int(width) except ValueError: echo(invalid) return True if width < 0 or width > 999: echo(invalid) return True echo(u"\r\n\r\nset COLUMNS=%d? [yn]" % (width,)) while True: inp2 = getch() if inp2 in (u'y', u'Y'): term.columns = width break elif inp2 in (u'n', u'N'): break elif is_self and inp in (u'h', u'H'): echo(u'\r\ntERMiNAl hEiGht: ') height = LineEditor(3, str(term.height)).read() try: height = int(height) except ValueError: echo(invalid) return True if height < 0 or height > 999: echo(invalid) return True echo(u"\r\n\r\nset LINES=%d? [yn]" % (height,)) while True: inp2 = getch() if inp2 in (u'y', u'Y'): term.rows = height break elif inp2 in (u'n', u'N'): break elif 'sysop' in session.user.groups and inp in (u'd', u'D',): echo(u"\r\n\r\ndElEtE %s ? [yn]" % (user.handle,)) while True: inp2 = getch() if inp2 in (u'y', u'Y'): user.delete() break elif inp2 in (u'n', u'N'): break EXIT = True elif 'sysop' in session.user.groups and inp in (u's', u'S',): sysop = not 'sysop' in user.groups echo(u"\r\n\r\n%s SYSOP ACCESS? [yn]" % ( 'ENAblE' if sysop else 'diSAblE',)) while True: inp2 = getch() if inp2 in (u'y', u'Y'): if sysop: user.groups.add('sysop') else: user.groups.remove('sysop') user.save() break elif inp2 in (u'n', u'N'): break elif inp in (u'p', u'P'): from x84.default.nua import set_password set_password(user) echo(u"\r\n\r\nSEt PASSWORd ? [yn]") while True: inp2 = getch() if inp2 in (u'y', u'Y'): user.save() break elif inp2 in (u'n', u'N'): break elif inp in (u'k', 'K',): change = True if user.get('pubkey', False): echo(u"\r\n\r\nSSh PUbliC kEY AlREAdY SEt, ChANGE ? [yn]") while True: inp2 = getch() if inp2 in (u'y', u'Y'): break elif inp2 in (u'n', u'N'): change = False break if change: echo(u"\r\n\r\njUSt PAStE iN YOUR PUbliC kEY, MAkE SURE itS " u"All iN ONE lINE!\r\n\r\n\r\n") editor = ScrollingEditor(width=term.width - 6, yloc=term.height - 3, xloc=3) echo(term.reverse_yellow) pubkey = editor.read() echo(term.normal) if pubkey is not None: if not pubkey.strip(): if user.get('pubkey', None): del user['pubkey'] echo(u'\r\n\r\nYOUR SECREtS ARE NEVER SAfE!\r\n') else: echo(u'\r\n\r\nWElCOME tO thE bROthERhOOd!\r\n') user['pubkey'] = pubkey user.save() getch(timeout=1.5) else: echo(u'\r\n\r\nCANCElEd!!\r\n') getch(timeout=0.5) elif inp in (u'.',): echo(term.move(0, 0) + term.normal + term.clear) echo(term.move(int(term.height * .8), 0)) for line in term.wrap(ABOUT_DOT_PLAN, term.width / 3): echo(line.center(term.width).rstrip() + u'\r\n') echo(u'\r\n\r\nPRESS ANY kEY ...') getch() if is_self: gosub('editor', '.plan') else: tmpkey = '%s-%s' % (user.handle, user.plan) draft = user.get('.plan', u'') session.user[tmpkey] = draft gosub('editor', tmpkey) if session.user.get(tmpkey, u'') != draft: echo(u"\r\n\r\nSEt .PlAN ? [yn]") while True: inp2 = getch() if inp2 in (u'y', u'Y'): user['.plan'] = session.user[tmpkey] break elif inp2 in (u'n', u'N'): break elif inp in (u'l', u'L'): echo(term.move(term.height - 1, 0)) set_location(user) echo(u"\r\n\r\nSEt lOCAtiON tO '%s'? [yn]" % (user.location,)) while True: inp2 = getch() if inp2 in (u'y', u'Y'): user.save() break elif inp2 in (u'n', u'N'): break elif inp in (u'e', u'E'): echo(term.move(term.height - 1, 0)) set_email(user) echo(u"\r\n\r\nSEt EMAil tO '%s'? [yn]" % (user.email,)) while True: inp2 = getch() if inp2 in (u'y', u'Y'): user.save() break elif inp2 in (u'n', u'N'): break elif inp in (u'i', u'I'): echo(u'\r\ntiMEOUt (0=NONE): ') timeout = LineEditor(6, str(user.get('timeout', def_timeout))).read() try: timeout = int(timeout) except ValueError: echo(invalid) return True if timeout < 0: echo(invalid) return True echo(u"\r\n\r\nSet tiMEOUt=%s? [yn]" % ( timeout if timeout else 'None',)) while True: inp2 = getch() if inp2 in (u'y', u'Y'): user['timeout'] = timeout session.send_event('set-timeout', timeout) break elif inp2 in (u'n', u'N'): break elif inp in (u'm', u'M'): mesg = False if user.get('mesg', True) else True echo(u"\r\n\r\n%s iNStANt MESSAGiNG? [yn]" % ( 'ENAblE' if mesg else 'DiSAblE',)) while True: inp2 = getch() if inp2 in (u'y', u'Y'): user['mesg'] = mesg break elif inp2 in (u'n', u'N'): break elif inp in (u'x', u'X'): expert = not user.get('expert', False) echo(u"\r\n\r\n%s EXPERt MOdE? [yn]" % ( 'ENAblE' if expert else 'DiSAblE',)) while True: inp2 = getch() if inp2 in (u'y', u'Y'): user['expert'] = expert break elif inp2 in (u'n', u'N'): break elif inp in (u'q', u'Q',): EXIT = True else: return False return True
def process_keystroke(lightbar, inp, user): """ Process keystroke, ``inp``, for target ``user``. """ # pylint: disable=R0914,R0912,R0915,R0911,W0603 # Too many local variables # Too many branches # Too many statements # Too many return statements # Using the global statement from x84.bbs import getsession, getterminal, echo, getch, gosub from x84.bbs import LineEditor, Ansi from x84.default.nua import set_email, set_location global EXIT session, term = getsession(), getterminal() is_self = bool(user.handle == session.user.handle) invalid = u'\r\niNVAlid.' if lightbar is not None: echo(lightbar.process_keystroke(inp)) if lightbar.moved: return False assert is_self or 'sysop' in session.user.groups # pylint: disable=W0311 # Bad indentation. Found 12 spaces, expected 8 if is_self and ( inp in (u'c', u'C') or (inp == term.KEY_ENTER and lightbar is not None and lightbar.selection[0] == u'c')): gosub('charset') elif is_self and ( inp in (u't', u'T') or (inp == term.KEY_ENTER and lightbar is not None and lightbar.selection[0] == u't')): echo(term.move(term.height - 1, 0)) echo(ABOUT_TERM + u'\r\n') echo(u'\r\ntERMiNAl tYPE: ') term = LineEditor(30, session.env.get('TERM')).read() echo(u"\r\n\r\nset TERM to '%s'? [yn]" % (term,)) while True: inp2 = getch() if inp2 in (u'y', u'Y'): session.env['TERM'] = term break elif inp2 in (u'n', u'N'): break elif is_self and ( inp in (u'w', u'W') or (inp == term.KEY_ENTER and lightbar is not None and lightbar.selection[0] == u'w')): echo(u'\r\ntERMiNAl Width: ') width = LineEditor(3, str(term.width)).read() try: width = int(width) except ValueError: echo(invalid) return True if width < 0 or width > 999: echo(invalid) return True echo(u"\r\n\r\nset COLUMNS=%d? [yn]" % (width,)) while True: inp2 = getch() if inp2 in (u'y', u'Y'): term.columns = width break elif inp2 in (u'n', u'N'): break elif is_self and ( inp in (u'h', u'H') or (inp == term.KEY_ENTER and lightbar is not None and lightbar.selection[0] == u'h')): echo(u'\r\ntERMiNAl hEiGht: ') height = LineEditor(3, str(term.height)).read() try: height = int(height) except ValueError: echo(invalid) return True if height < 0 or height > 999: echo(invalid) return True echo(u"\r\n\r\nset LINES=%d? [yn]" % (height,)) while True: inp2 = getch() if inp2 in (u'y', u'Y'): term.rows = height break elif inp2 in (u'n', u'N'): break elif ('sysop' in session.user.groups and ( inp in (u'd', u'D',) or (inp == term.KEY_ENTER and lightbar is not None and lightbar.selection[0] == u'd'))): echo(u"\r\n\r\ndElEtE %s ? [yn]" % (user.handle,)) while True: inp2 = getch() if inp2 in (u'y', u'Y'): user.delete() break elif inp2 in (u'n', u'N'): break EXIT = True elif 'sysop' in session.user.groups and ( inp in (u's', u'S',) or (inp == term.KEY_ENTER and lightbar is not None and lightbar.selection[0] == u's')): sysop = not 'sysop' in user.groups echo(u"\r\n\r\n%s SYSOP ACCESS? [yn]" % ( 'ENAblE' if sysop else 'diSAblE',)) while True: inp2 = getch() if inp2 in (u'y', u'Y'): if sysop: user.groups.add('sysop') else: user.groups.remove('sysop') user.save() break elif inp2 in (u'n', u'N'): break elif inp in (u'p',) or (inp == term.KEY_ENTER and lightbar is not None and lightbar.selection[0] == u'p'): from x84.default.nua import set_password set_password(user) echo(u"\r\n\r\nSEt PASSWORd ? [yn]") while True: inp2 = getch() if inp2 in (u'y', u'Y'): user.save() break elif inp2 in (u'n', u'N'): break elif inp in (u'.',) or (inp == term.KEY_ENTER and lightbar is not None and lightbar.selection[0] == u'.'): echo(term.move(0, 0) + term.normal + term.clear) echo(term.move(int(term.height * .8), 0)) for line in Ansi(ABOUT_DOT_PLAN).wrap( term.width / 3).splitlines(): echo(line.center(term.width).rstrip() + u'\r\n') echo(u'\r\n\r\nPRESS ANY kEY ...') getch() if is_self: gosub('editor', '.plan') else: tmpkey = '%s-%s' % (user.handle, user.plan) draft = user.get('.plan', u'') session.user[tmpkey] = draft gosub('editor', tmpkey) if session.user.get(tmpkey, u'') != draft: echo(u"\r\n\r\nSEt .PlAN ? [yn]") while True: inp2 = getch() if inp2 in (u'y', u'Y'): user['.plan'] = session.user[tmpkey] break elif inp2 in (u'n', u'N'): break elif inp in (u'l', u'L') or (inp == term.KEY_ENTER and lightbar is not None and lightbar.selection[0] == u'l'): echo(term.move(term.height - 1, 0)) set_location(user) echo(u"\r\n\r\nSEt lOCAtiON tO '%s'? [yn]" % (user.location,)) while True: inp2 = getch() if inp2 in (u'y', u'Y'): user.save() break elif inp2 in (u'n', u'N'): break elif inp in (u'e', u'E') or (inp == term.KEY_ENTER and lightbar is not None and lightbar.selection[0] == u'e'): echo(term.move(term.height - 1, 0)) set_email(user) echo(u"\r\n\r\nSEt EMAil tO '%s'? [yn]" % (user.email,)) while True: inp2 = getch() if inp2 in (u'y', u'Y'): user.save() break elif inp2 in (u'n', u'N'): break elif inp in (u'm', u'M') or (inp == term.KEY_ENTER and lightbar is not None and lightbar.selection[0] == u'm'): mesg = False if user.get('mesg', True) else True echo(u"\r\n\r\n%s iNStANt MESSAGiNG? [yn]" % ( 'ENAblE' if mesg else 'DiSAblE',)) while True: inp2 = getch() if inp2 in (u'y', u'Y'): user['mesg'] = mesg break elif inp2 in (u'n', u'N'): break elif inp in (u'x', u'X') or (inp == term.KEY_ENTER and lightbar is not None and lightbar.selection[0] == u'x'): expert = not user.get('expert', False) echo(u"\r\n\r\n%s EXPERt MOdE? [yn]" % ( 'ENAblE' if expert else 'DiSAblE',)) while True: inp2 = getch() if inp2 in (u'y', u'Y'): user['expert'] = expert break elif inp2 in (u'n', u'N'): break elif inp in (u'q', u'Q',) or (inp == term.KEY_ENTER and lightbar is not None and lightbar.selection[0] == u'q'): EXIT = True else: return False return True
def read_messages(msgs, new): """ Provide message reader UI given message list ``msgs``, with new messages in list ``new``. """ # pylint: disable=R0914,R0912,R0915 # Too many local variables # Too many branches # Too many statements from x84.bbs import timeago, get_msg, getterminal, echo, gosub from x84.bbs import ini, Pager, getsession, getch, Msg import x84.default.writemsg session, term = getsession(), getterminal() session.activity = 'reading msgs' # build header len_idx = max([len('%d' % (_idx, )) for _idx in msgs]) len_author = ini.CFG.getint('nua', 'max_user') len_ago = 9 len_subject = ini.CFG.getint('msg', 'max_subject') len_preview = min(len_idx + len_author + len_ago + len_subject + -1, term.width - 2) reply_depth = ini.CFG.getint('msg', 'max_depth') indent_start, indent, indent_end = u'\\', u'-', u'> ' def get_header(msgs_idx): """ Return list of tuples, (idx, unicodestring), suitable for Lightbar. """ import datetime msg_list = list() thread_indent = lambda depth: (term.red( (indent_start + (indent * depth) + indent_end)) if depth else u'') def head(msg, depth=0, maxdepth=reply_depth): """ This recursive routine finds the 'head' message of any relationship, up to maxdepth. """ if (depth <= maxdepth and hasattr(msg, 'parent') and msg.parent is not None): return head(get_msg(msg.parent), depth + 1, maxdepth) return msg.idx, depth for idx in msgs_idx: msg = get_msg(idx) author, subj = msg.author, msg.subject tm_ago = (datetime.datetime.now() - msg.stime).total_seconds() # pylint: disable=W0631 # Using possibly undefined loop variable 'idx' attr = lambda arg: (term.bold_green(arg) if (not idx in ALREADY_READ and msg.recipient == session.user.handle) else term.red(arg) if not idx in ALREADY_READ else term.yellow(arg )) status = [ u'U' if not idx in ALREADY_READ else u' ', u'D' if idx in DELETED else u' ', ] row_txt = u'%s %s %s %s %s%s ' % ( u''.join(status), attr(str(idx).rjust(len_idx)), attr(author.ljust(len_author)), (timeago(tm_ago)).rjust(len_ago), attr(u'ago'), term.bold_black(':'), ) msg_list.append((head(msg), idx, row_txt, subj)) msg_list.sort(reverse=True) return [(idx, row_txt + thread_indent(depth) + subj) for (_threadid, depth), idx, row_txt, subj in msg_list] def get_selector(mailbox, prev_sel=None): """ Provide Lightbar UI element given message mailbox returned from function get_header, and prev_sel as previously instantiated Lightbar. """ from x84.bbs import Lightbar pos = prev_sel.position if prev_sel is not None else (0, 0) sel = Lightbar(height=(term.height / 3 if term.width < 140 else term.height - 3), width=len_preview, yloc=2, xloc=0) sel.glyphs['top-horiz'] = u'' sel.glyphs['left-vert'] = u'' sel.colors['highlight'] = term.yellow_reverse sel.update(mailbox) sel.position = pos return sel def get_reader(): """ Provide Pager UI element for message reading. """ reader_height = (term.height - (term.height / 3) - 2) reader_indent = 2 reader_width = min(term.width - 1, min(term.width - reader_indent, 80)) reader_ypos = ((term.height - 1) - reader_height if (term.width - reader_width) < len_preview else 2) reader_height = term.height - reader_ypos - 1 msg_reader = Pager(height=reader_height, width=reader_width, yloc=reader_ypos, xloc=min(len_preview + 2, term.width - reader_width)) msg_reader.glyphs['top-horiz'] = u'' msg_reader.glyphs['right-vert'] = u'' return msg_reader def format_msg(reader, idx): """ Format message of index ``idx`` into Pager instance ``reader``. """ msg = get_msg(idx) sent = msg.stime.strftime(TIME_FMT) to_attr = term.bold_green if ( msg.recipient == session.user.handle) else term.underline ucs = u'\r\n'.join(( (u''.join(( term.yellow('fROM: '), (u'%s' % term.bold(msg.author, )).rjust(len_author), u' ' * (reader.visible_width - (len_author + len(sent))), sent, ))), u''.join(( term.yellow('tO: '), to_attr(( u'%s' % to_attr(msg.recipient, ) ).rjust(len_author) if msg.recipient is not None else u'All'), )), (u'\r\n'.join((term.wrap( term.yellow('tAGS: ') + (u'%s ' % (term.bold(','), )).join(([ term.bold_red(_tag) if _tag in SEARCH_TAGS else term.yellow(_tag) for _tag in msg.tags ])), reader.visible_width, subsequent_indent=u' ' * 6)))), (term.yellow_underline( (u'SUbj: %s' % (msg.subject, )).ljust(reader.visible_width))), u'', (msg.body), )) return ucs def get_selector_title(mbox, new): """ Returns unicode string suitable for displaying as title of mailbox. """ newmsg = (term.yellow(u' ]-[ ') + term.yellow_reverse(str(len(new))) + term.bold_underline(u' NEW')) if len(new) else u'' return u''.join(( term.yellow(u'[ '), term.bold_yellow(str(len(mbox))), term.bold(u' MSG%s' % (u's' if 1 != len(mbox) else u'', )), newmsg, term.yellow(u' ]'), )) dispcmd_mark = lambda idx: ((term.yellow_underline(u' ') + u':mark' + u' ') if idx not in ALREADY_READ else u'') dispcmd_delete = lambda idx: ( (term.yellow_underline(u'D') + u':elete' + u' ') if idx not in DELETED else u'') dispcmd_tag = lambda idx: ((term.yellow_underline(u't') + u':ag' + u' ') if allow_tag(idx) else u'') def get_selector_footer(idx): """ Returns unicode string suitable for displaying as footer of mailbox when window is active. """ return u''.join(( term.yellow(u'- '), u''.join(( term.yellow_underline(u'>') + u':read ', term.yellow_underline(u'r') + u':eply ', dispcmd_mark(idx), dispcmd_delete(idx), dispcmd_tag(idx), term.yellow_underline(u'q') + u':uit', )), term.yellow(u' -'), )) def get_reader_footer(idx): """ Returns unicode string suitable for displaying as footer of reader when window is active """ return u''.join(( term.yellow(u'- '), u' '.join(( term.yellow_underline(u'<') + u':back ', term.yellow_underline(u'r') + u':eply ', dispcmd_delete(idx), dispcmd_tag(idx), term.yellow_underline(u'q') + u':uit', )), term.yellow(u' -'), )) def refresh(reader, selector, mbox, new): """ Returns unicode string suitable for refreshing the screen. """ from x84.bbs import getsession session = getsession() if READING: reader.colors['border'] = term.bold_yellow selector.colors['border'] = term.bold_black else: reader.colors['border'] = term.bold_black selector.colors['border'] = term.bold_yellow title = get_selector_title(mbox, new) padd_attr = (term.bold_yellow if not READING else term.bold_black) sel_padd_right = padd_attr( u'-' + selector.glyphs['bot-horiz'] * (selector.visible_width - term.length(title) - 7) + u'-\u25a0-' if READING else u'- -') sel_padd_left = padd_attr(selector.glyphs['bot-horiz'] * 3) idx = selector.selection[0] return u''.join(( term.move(0, 0), term.clear, u'\r\n', u'// REAdiNG MSGS ..'.center(term.width).rstrip(), selector.refresh(), selector.border() if READING else reader.border(), reader.border() if READING else selector.border(), selector.title(sel_padd_left + title + sel_padd_right), selector.footer(get_selector_footer(idx)) if not READING else u'', reader.footer(get_reader_footer(idx)) if READING else u'', reader.refresh(), )) echo((u'\r\n' + term.clear_eol) * (term.height - 1)) dirty = 2 msg_selector = None msg_reader = None idx = None # pylint: disable=W0603 # Using the global statement global READING while (msg_selector is None and msg_reader is None) or not (msg_selector.quit or msg_reader.quit): if session.poll_event('refresh'): dirty = 2 if dirty: if dirty == 2: mailbox = get_header(msgs) msg_selector = get_selector(mailbox, msg_selector) idx = msg_selector.selection[0] msg_reader = get_reader() msg_reader.update(format_msg(msg_reader, idx)) echo(refresh(msg_reader, msg_selector, msgs, new)) dirty = 0 inp = getch(1) if inp in (u'r', u'R'): reply_to = get_msg(idx) reply_msg = Msg() reply_msg.recipient = reply_to.author reply_msg.tags = reply_to.tags reply_msg.subject = reply_to.subject reply_msg.parent = reply_to.idx # quote between 30 and 79, 'screen width - 4' as variable dist. reply_msg.body = quote_body(reply_to, max(30, min(79, term.width - 4))) echo(term.move(term.height, 0) + u'\r\n') if gosub('writemsg', reply_msg): reply_msg.save() dirty = 2 READING = False else: dirty = 1 mark_read(idx) # also mark as read # 't' uses writemsg.prompt_tags() routine, how confusing .. elif inp in (u't', ) and allow_tag(idx): echo(term.move(term.height, 0)) msg = get_msg(idx) if x84.default.writemsg.prompt_tags(msg): msg.save() session.user['msgs_sent'] = session.user.get('msgs_sent', 0) + 1 dirty = 2 # spacebar marks as read, goes to next message elif inp in (u' ', ): dirty = 2 if mark_read(idx) else 1 msg_selector.move_down() idx = msg_selector.selection[0] READING = False # D marks as deleted, goes to next message elif inp in (u'D', ): dirty = 2 if mark_delete(idx) else 1 msg_selector.move_down() idx = msg_selector.selection[0] READING = False # U undeletes, does not move. elif inp in (u'U', ): dirty = 2 if mark_undelete(idx) else 1 msg_selector.move_down() idx = msg_selector.selection[0] READING = False if READING: echo(msg_reader.process_keystroke(inp)) # left, <, or backspace moves UI if inp in (term.KEY_LEFT, u'<', u'h', '\b', term.KEY_BACKSPACE): READING = False dirty = 1 else: echo(msg_selector.process_keystroke(inp)) idx = msg_selector.selection[0] # right, >, or enter marks message read, moves UI if inp in (u'\r', term.KEY_ENTER, u'>', u'l', 'L', term.KEY_RIGHT): dirty = 2 if mark_read(idx) else 1 READING = True elif msg_selector.moved: dirty = 1 echo(term.move(term.height, 0) + u'\r\n') return
def main(handle=None): """ Main procedure. """ # pylint: disable=R0914,R0912,R0915 # Too many local variables # Too many branches # Too many statements from x84.bbs import getsession, getterminal, echo, getch from x84.bbs import goto, gosub, User, get_user, DBProxy import logging import time session, term = getsession(), getterminal() session.activity = 'top' logger = logging.getLogger() # 0. just a gimmicky example, # gosub('productive') # 1. determine & assign user record, if handle in (None, u'', 'anonymous',): logger.info('anonymous login by %s.', session.sid) session.user = User(u'anonymous') else: logger.debug('%r logged in.', handle) session.user = get_user(handle) timeout = session.user.get('timeout', None) if timeout is not None: echo(u'\r\n\r\nUsing preferred timeout of %ss.\r\n' % ( timeout,)) session.send_event('set-timeout', timeout) # 2. update call records session.user.calls += 1 session.user.lastcall = time.time() if session.user.handle != 'anonymous': session.user.save() # record into " last caller " record key = (session.user.handle) lcall = (session.user.lastcall, session.user.calls, session.user.location) db = DBProxy('lastcalls') db[key] = lcall # 3. if no preferred charset run charset.py selector if (session.user.get('charset', None) is None or session.user.handle == 'anonymous'): gosub('charset') session.activity = 'top' else: # load default charset session.encoding = session.user.get('charset') fun = term.bold_green(' (EXCEllENt!)') if session.encoding != 'utf8': fun = term.bold_red(u' (bUMMER!)') echo(u'\r\n\r\nUsing preferred charset, %s%s.\r\n' % ( session.encoding, fun)) echo(term.clear()) # 4. impress with art, prompt for quick login (goto 'main'), if session.user.get('expert', False): dirty = True while True: if session.poll_event('refresh'): dirty = True if dirty: session.activity = 'top' display_intro() echo(u'\r\n QUiCk lOGiN [yn] ?\b\b') dirty = False inp = getch(1) if inp in (u'y', u'Y'): goto('main') elif inp in (u'n', u'N'): break elif inp in (u'!',): gosub('charset') dirty = True else: ynbar = get_ynbar() dirty = True while not ynbar.selected: if session.poll_event('refresh'): dirty = True if dirty: # redraw yes/no session.activity = 'top' swp = ynbar.selection ynbar = get_ynbar() ynbar.selection = swp display_intro() echo(redraw_quicklogin(ynbar)) dirty = False inp = getch(1) if inp in (u'!',): gosub('charset') dirty = True elif inp is not None: echo(ynbar.process_keystroke(inp)) if ynbar.quit: goto('main') if ynbar.selection == ynbar.left: goto('main') # 5. last callers gosub('lc') session.activity = 'top' # 6. check for new public/private msgs, # gosub('readmsgs', set()) # session.activity = 'top' # 7. news gosub('news') session.activity = 'top' # 8. one-liners gosub('ol') session.activity = 'top' # 9. weather # if session.user.get('location', None): # gosub('weather') goto('main')
def main(handle=None): """ 主体程序""" session, term = getsession(), getterminal() session.activity = 'hick' ### 处理登录 # attempt to coerce encoding of terminal to match session. coerce_terminal_encoding(term, session.encoding) # fetch user record user = get_user_record(handle) # register call login(session, user) session = getsession() ### 处理键盘操作事件 inp = -1 dirty = True while True: if dirty or session.poll_event('refresh'): refresh() inp = getch(1) dirty = True if inp == u'*': goto('main') # reload main menu using hidden option '*' elif inp == u'$': gosub('bulletins') elif inp == u'b': gosub('bbslist') elif inp == u'l': gosub('lc') elif inp == u'o': gosub('ol') elif inp == u's': gosub('si') elif inp == u'u': gosub('userlist') elif inp == u'w': gosub('online') elif inp == u'n': gosub('news') elif inp == u'f': gosub('weather') elif inp == u'e': gosub('profile') elif inp == u'#': gosub('lord') ### 修改成 elif inp == u't': gosub('feeds') elif inp == u'c': gosub('chat') elif inp == u'i': gosub('ircchat') elif inp == u'p': gosub('writemsg') elif inp == u'r': gosub('readmsgs') elif inp == u'v': gosub('vote') elif inp == u'g': goto('logoff') elif inp == u'!': gosub('charset') elif inp == '\x1f' and 'sysop' in session.user.groups: # ctrl+_, run a debug script gosub('debug') else: handled = False try: for option in ini.CFG.options('sesame'): if option.endswith('_key'): door = option.replace('_key', '') key = ini.CFG.get('sesame', option) if inp == key: gosub('sesame', door) handled = True break except ConfigError: pass if not handled: dirty = False
def main(): """ Main procedure. """ # pylint: disable=R0912 # Too many branches from x84.bbs import getsession, getch, goto, gosub session = getsession() inp = -1 dirty = True while True: if dirty or session.poll_event('refresh'): refresh() inp = getch(1) dirty = True if inp == u'*': refresh() elif inp == u'b': gosub('bbslist') elif inp == u'l': gosub('lc') elif inp == u'o': gosub('ol') elif inp == u's': gosub('si') elif inp == u'w': gosub('online') elif inp == u'n': gosub('news') elif inp == u'f': gosub('weather') elif inp == u'e': gosub('profile') elif inp == u'#': gosub('lord') elif inp == u't': gosub('tetris') elif inp == u'c': gosub('chat') elif inp == u'p': gosub('writemsg') elif inp == u'r': gosub('readmsgs') elif inp == u'g': goto('logoff') elif inp == u'!': gosub('charset') elif inp == u'y': gosub('yosindex') elif inp == '\x1f' and 'sysop' in session.user.groups: # ctrl+_, run a debug script gosub('debug') elif inp == u'v' and 'sysop' in session.user.groups: # video cassette player gosub('ttyplay') else: dirty = False
def main(): """ Main menu entry point. """ import os, random, time from x84.bbs import showart session, term = getsession(), getterminal() global menutoggle global arttoggle global bgtoggle text, width, height, dirty = u'', -1, -1, 2 menu_items = get_menu_items(session) colors = {} if colored_menu_items: colors['backlight'] = getattr(term, color_backlight) colors['highlight'] = getattr(term, color_highlight) colors['lowlight'] = getattr(term, color_lowlight) editor = get_line_editor(term, menu_items) menumode = False tallmode = False widemode = False if term.width >= 132: widemode = True if term.height >= 43: tallmode = True #if session.user['bg'] is None: randombgset() starttime = time.time() while True: if dirty > 1: # set syncterm font, if any if syncterm_font and term.kind.startswith('ansi'): echo(syncterm_setfont(syncterm_font)) if dirty == 2: menutoggle, arttoggle, bgtoggle = True, True, True if dirty: session.activity = 'main menu' if width != term.width or height != term.height: width, height = term.width, term.height renderscreen(menutoggle, arttoggle, bgtoggle) echo(term.move(term.height, 2)) echo(u''.join((text, display_prompt(term, colors), editor.refresh()+term.normal))) dirty = 0 event, data = session.read_events(('input', 'refresh'), 0.1) if event == 'refresh': dirty = True continue elif event == 'input': session.buffer_input(data, pushback=True) # we must loop over inkey(0), we received a 'data' # event, though there may be many keystrokes awaiting for our # decoding -- or none at all (multibyte sequence not yet complete). inp = term.inkey(0) while inp: if inp == u'*': menutoggle = not menutoggle dirty = True break if inp.code == term.KEY_TAB: starttime = time.time() randombgset() dirty = True break if inp.code == term.KEY_ENTER: # find matching menu item, for item in menu_items: if item.inp_key == editor.content.strip(): echo(term.normal + u'\r\n') gosub(item.script, *item.args, **item.kwargs) editor.content = u'' dirty = 3 break else: if editor.content: # command not found, clear prompt. echo(u''.join(( (u'\b' * len(editor.content)), (u' ' * len(editor.content)), (u'\b' * len(editor.content)),))) editor.content = u'' echo(editor.refresh()+term.normal) elif inp.is_sequence: echo(editor.process_keystroke(inp.code)) else: echo(editor.process_keystroke(inp)) inp = term.inkey(0) if time.time() - starttime > 1800: dirty = True starttime = time.time() randombgset() continue
def main(): """ Main procedure. """ # pylint: disable=R0914,R0912,R0915 # Too many local variables # Too many branches # Too many statements from x84.bbs import getsession, getterminal, echo, ini, getch, gosub from x84.bbs import DBProxy session, term = getsession(), getterminal() pager, lightbar = get_ui(None) echo(u'\r\n\r\n') thread = None if ini.CFG.has_section('bbs-scene'): thread = FetchUpdates() thread.start() session.activity = u'bbs lister [bbs-scene.org]' echo(u'fetching bbs-scene.org updates ...') else: session.activity = u'bbs lister' dirty = True # session.buffer_event('refresh', ('init',)) leftright = 0 # 'left' while True: # check if screen requires refresh of any kind, if session.poll_event('refresh'): dirty = True if thread is not None: t_val = chk_thread(thread) if t_val != False: thread = None if t_val == 'dirty': dirty = True if session.poll_event('bbslist_update'): while session.read_event('bbslist_update', 0.15): # pylint: disable=W0104 # Statement seems to have no effect None dirty = True # refresh advanced screen with lightbar and pager if dirty: if session.user.get('expert', False): # provide dumb terminal with hotkey prompt if thread is not None: wait_for(thread) if chk_thread(thread) != False: thread = None return dummy_pager() else: pager, lightbar = get_ui(lightbar.position) echo(banner()) echo(u'\r\n' * lightbar.height) echo(redraw(pager, lightbar, leftright)) dirty = False # detect and process keyboard input for advanced screen inp = getch(1) if inp == term.KEY_LEFT: # full refresh for border chang ;/ leftright = 0 echo(redraw_pager( pager, lightbar.selection, active=(leftright == 1))) echo(redraw_lightbar( lightbar, active=(leftright == 0))) elif inp == term.KEY_RIGHT: # full refresh for border chang ;/ leftright = 1 echo(redraw_pager(pager, lightbar.selection, active=(leftright == 1))) echo(redraw_lightbar(lightbar, active=(leftright == 0))) elif inp is not None: # process as pager or lightbar keystroke, echo(lightbar.process_keystroke(inp) if leftright == 0 else pager.process_keystroke(inp)) # full refresh after rate/comment/elnet/view etc. if process_keystroke(inp, lightbar.selection[0]): session.buffer_event('refresh', ('redraw',)) continue # quit 'q' if (lightbar.quit or pager.quit): return # pressed return, telnet! if lightbar.selected and lightbar.selection[0] is not None: bbs = DBProxy('bbslist')[lightbar.selection[0]] gosub('telnet', bbs['address'], bbs['port']) # buffer full refresh after telnet session.buffer_event('refresh', ('redraw',)) # selected new entry, refresh entire pager, a little bit # bandwidth excessive as bbs name is part of border title. if lightbar.moved: echo(redraw_pager(pager, lightbar.selection, active=(leftright == 1))) lightbar.moved = False
def main(handle=None): """ Main procedure. """ # pylint: disable=R0914,R0912,R0915 # Too many local variables # Too many branches # Too many statements from x84.bbs import getsession, getterminal, echo, getch from x84.bbs import goto, gosub, User, get_user, DBProxy import logging import time session, term = getsession(), getterminal() session.activity = 'top' logger = logging.getLogger() # 0. just a gimmicky example, gosub('productive') # 1. determine & assign user record, if handle in (None, u'', 'anonymous',): logger.info('anonymous login by %s.', session.sid) session.user = User(u'anonymous') else: logger.debug('%r logged in.', handle) session.user = get_user(handle) timeout = session.user.get('timeout', None) if timeout is not None: echo(u'\r\n\r\nUsing preferred timeout of %ss.\r\n' % ( timeout,)) session.send_event('set-timeout', timeout) # 2. update call records session.user.calls += 1 session.user.lastcall = time.time() if session.user.handle != 'anonymous': session.user.save() # record into " last caller " record key = (session.user.handle) lcall = (session.user.lastcall, session.user.calls, session.user.location) db = DBProxy('lastcalls') db[key] = lcall # 3. if no preferred charset run charset.py selector if (session.user.get('charset', None) is None or session.user.handle == 'anonymous'): gosub('charset') session.activity = 'top' else: # load default charset session.encoding = session.user.get('charset') fun = term.bold_green(' (EXCEllENt!)') if session.encoding != 'utf8': fun = term.bold_red(u' (bUMMER!)') echo(u'\r\n\r\nUsing preferred charset, %s%s.\r\n' % ( session.encoding, fun)) # 4. impress with art, prompt for quick login (goto 'main'), if session.user.get('expert', False): dirty = True while True: if session.poll_event('refresh'): dirty = True if dirty: session.activity = 'top' display_intro() echo(u'\r\n QUiCk lOGiN [yn] ?\b\b') dirty = False inp = getch(1) if inp in (u'y', u'Y'): goto('main') elif inp in (u'n', u'N'): break elif inp in (u'!',): gosub('charset') dirty = True else: ynbar = get_ynbar() dirty = True while not ynbar.selected: if session.poll_event('refresh'): dirty = True if dirty: # redraw yes/no session.activity = 'top' swp = ynbar.selection ynbar = get_ynbar() ynbar.selection = swp display_intro() echo(redraw_quicklogin(ynbar)) dirty = False inp = getch(1) if inp in (u'!',): gosub('charset') dirty = True elif inp is not None: echo(ynbar.process_keystroke(inp)) if ynbar.quit: goto('main') if ynbar.selection == ynbar.left: goto('main') # 5. last callers gosub('lc') session.activity = 'top' # 6. check for new public/private msgs, gosub('readmsgs', set()) session.activity = 'top' # 7. news gosub('news') session.activity = 'top' # 8. one-liners gosub('ol') session.activity = 'top' # 9. weather if session.user.get('location', None): gosub('weather') session.activity = 'top' # 10. automsg gosub('automsg') goto('main')
def main(): """ Main procedure. """ # pylint: disable=R0912 # Too many branches from x84.bbs import getsession, getch, goto, gosub session = getsession() inp = -1 dirty = True while True: if dirty or session.poll_event('refresh'): refresh() inp = getch(1) dirty = True if inp == u'*': goto('main') # reload main menu using hidden option '*' elif inp == u'b': gosub('bbslist') elif inp == u'l': gosub('lc') elif inp == u'o': gosub('ol') elif inp == u's': gosub('si') elif inp == u'w': gosub('online') elif inp == u'n': gosub('news') elif inp == u'f': gosub('weather') elif inp == u'e': gosub('profile') elif inp == u't': gosub('tetris') elif inp == u'c': gosub('chat') elif inp == u'p': gosub('writemsg') elif inp == u'r': gosub('readmsgs') elif inp == u'g': goto('logoff') elif inp == u'!': gosub('charset') elif inp == '\x1f' and 'sysop' in session.user.groups: # ctrl+_, run a debug script gosub('debug') elif inp == u'v' and 'sysop' in session.user.groups: # video cassette player gosub('ttyplay') else: dirty = False
def main(): """ Main procedure. """ # pylint: disable=R0914,R0912,R0915 # Too many local variables # Too many branches # Too many statements from x84.bbs import getsession, getterminal, echo, ini, getch, gosub from x84.bbs import DBProxy session, term = getsession(), getterminal() pager, lightbar = get_ui(None) echo(u'\r\n\r\n') thread = None if ini.CFG.has_section('bbs-scene'): thread = FetchUpdates() thread.start() session.activity = u'bbs lister [bbs-scene.org]' echo(u'fetching bbs-scene.org updates ...') else: session.activity = u'bbs lister' dirty = True # session.buffer_event('refresh', ('init',)) leftright = 0 # 'left' while True: # check if screen requires refresh of any kind, if session.poll_event('refresh'): dirty = True if thread is not None: t_val = chk_thread(thread) if t_val != False: thread = None if t_val == 'dirty': dirty = True if session.poll_event('bbslist_update'): while session.read_event('bbslist_update', 0.15): # pylint: disable=W0104 # Statement seems to have no effect None dirty = True # refresh advanced screen with lightbar and pager if dirty: if session.user.get('expert', False): # provide dumb terminal with hotkey prompt if thread is not None: wait_for(thread) if chk_thread(thread) != False: thread = None return dummy_pager() else: pager, lightbar = get_ui(lightbar.position) echo(banner()) echo(u'\r\n' * lightbar.height) echo(redraw(pager, lightbar, leftright)) dirty = False # detect and process keyboard input for advanced screen inp = getch(1) if inp == term.KEY_LEFT: # full refresh for border chang ;/ leftright = 0 echo( redraw_pager(pager, lightbar.selection, active=(leftright == 1))) echo(redraw_lightbar(lightbar, active=(leftright == 0))) elif inp == term.KEY_RIGHT: # full refresh for border chang ;/ leftright = 1 echo( redraw_pager(pager, lightbar.selection, active=(leftright == 1))) echo(redraw_lightbar(lightbar, active=(leftright == 0))) elif inp is not None: # process as pager or lightbar keystroke, echo( lightbar.process_keystroke(inp) if leftright == 0 else pager.process_keystroke(inp)) # full refresh after rate/comment/elnet/view etc. if process_keystroke(inp, lightbar.selection[0]): session.buffer_event('refresh', ('redraw', )) continue # quit 'q' if (lightbar.quit or pager.quit): return # pressed return, telnet! if lightbar.selected and lightbar.selection[0] is not None: bbs = DBProxy('bbslist')[lightbar.selection[0]] gosub('telnet', bbs['address'], bbs['port']) # buffer full refresh after telnet session.buffer_event('refresh', ('redraw', )) # selected new entry, refresh entire pager, a little bit # bandwidth excessive as bbs name is part of border title. if lightbar.moved: echo( redraw_pager(pager, lightbar.selection, active=(leftright == 1))) lightbar.moved = False
def main(): """ Main procedure. """ # pylint: disable=R0912 # Too many branches from x84.bbs import getsession, getch, goto, gosub, ini from ConfigParser import Error as ConfigError session = getsession() inp = -1 dirty = True while True: if dirty or session.poll_event('refresh'): refresh() inp = getch(1) dirty = True if inp == u'*': goto('main') # reload main menu using hidden option '*' elif inp == u'$': gosub('bulletins') elif inp == u'b': gosub('bbslist') elif inp == u'l': gosub('lc') elif inp == u'o': gosub('ol') elif inp == u's': gosub('si') elif inp == u'u': gosub('userlist') elif inp == u'w': gosub('online') elif inp == u'n': gosub('news') elif inp == u'f': gosub('weather') elif inp == u'e': gosub('profile') elif inp == u'#': gosub('lord') elif inp == u't': gosub('tetris') elif inp == u'c': gosub('chat') elif inp == u'i': gosub('ircchat') elif inp == u'p': gosub('writemsg') elif inp == u'r': gosub('readmsgs') elif inp == u'v': gosub('vote') elif inp == u'g': goto('logoff') elif inp == u'!': gosub('charset') elif inp == '\x1f' and 'sysop' in session.user.groups: # ctrl+_, run a debug script gosub('debug') else: handled = False try: for option in ini.CFG.options('sesame'): if option.endswith('_key'): door = option.replace('_key', '') key = ini.CFG.get('sesame', option) if inp == key: gosub('sesame', door) handled = True break except ConfigError: pass if not handled: dirty = False
def main(): """ Main menu entry point. """ session, term = getsession(), getterminal() text, width, height, dirty = u'', -1, -1, 2 menu_items = get_menu_items(session) editor = get_line_editor(term, menu_items) colors = {} if colored_menu_items: colors['backlight'] = getattr(term, color_backlight) colors['highlight'] = getattr(term, color_highlight) colors['lowlight'] = getattr(term, color_lowlight) while True: if dirty == 2: # set syncterm font, if any if syncterm_font and term.kind.startswith('ansi'): echo(syncterm_setfont(syncterm_font)) if dirty: session.activity = 'main menu' top_margin = display_banner(art_file, encoding=art_encoding) + 1 echo(u'\r\n') if width != term.width or height != term.height: width, height = term.width, term.height text = render_menu_entries( term, top_margin, menu_items, colors) echo(u''.join((text, display_prompt(term, colors), editor.refresh()))) dirty = 0 event, data = session.read_events(('input', 'refresh')) if event == 'refresh': dirty = True continue elif event == 'input': session.buffer_input(data, pushback=True) # we must loop over inkey(0), we received a 'data' # event, though there may be many keystrokes awaiting for our # decoding -- or none at all (multibyte sequence not yet complete). inp = term.inkey(0) while inp: if inp.code == term.KEY_ENTER: # find matching menu item, for item in menu_items: if item.inp_key == editor.content.strip(): echo(term.normal + u'\r\n') gosub(item.script, *item.args, **item.kwargs) editor.content = u'' dirty = 2 break else: if editor.content: # command not found, clear prompt. echo(u''.join(( (u'\b' * len(editor.content)), (u' ' * len(editor.content)), (u'\b' * len(editor.content)),))) editor.content = u'' echo(editor.refresh()) elif inp.is_sequence: echo(editor.process_keystroke(inp.code)) else: echo(editor.process_keystroke(inp)) inp = term.inkey(0)