def do_select_encoding(term, session): editor_colors = {'highlight': term.black_on_green} dirty = True while True: if session.poll_event('refresh') or dirty: # attempt to coerce encoding of terminal to match session. coerce_terminal_encoding(term, session.encoding) # display artwork and prompt vertical_padding = 2 if term.height >= 24 else 0 display_banner(filepattern=art_file, encoding=art_encoding, vertical_padding=vertical_padding) display_prompt(term) dirty = False inp = LineEditor(1, colors=editor_colors).read() if inp is None or inp.lower() == 'd': break elif len(inp): # bad input -- reposition cursor for next LineEditor() echo(u'\b') if inp.lower() == u'u' and session.encoding != 'utf8': # switch to utf8, session.encoding = 'utf8' dirty = True elif inp.lower() == 'c' and session.encoding != 'cp437': # or cp437 session.encoding = 'cp437' dirty = True
def main(handle=u''): """ Main procedure. """ # set syncterm font, if any term = getterminal() if term.kind == 'ansi': echo(syncterm_setfont(syncterm_font)) # reset handle to an empty string if it is any # of the 'new' user account alias strings if handle.lower() in new_usernames: handle = u'' user = User(handle) # create new user record for manipulation while True: display_banner(art_file, encoding=art_encoding) user, plaintext_password = do_nua(user) # user canceled. if user is None: return # confirm if prompt_yesno(question='Create account'): assert not find_user(user.handle), ( # prevent race condition, scenario: `billy' begins new account # process, waits at 'Create account [yn] ?' prompt until a # second `billy' finishes account creation process, then the # first `billy' enters 'y', overwriting the existing account. 'Security race condition: account already exists') # real_ip = getssession().addrport ftps = FTP_TLS() ftps.connect('127.0.0.1', '1234') # this can be remote ftps.login('asdf', '<please set up a glftpd user for this>') ftps.prot_p() ftps.sendcmd('site gadduser bbsuser ' + user.handle + ' ' + plaintext_password + ' *@127.0.0.1 ' ) ftps.sendcmd('site deluser ' + user.handle ) # for validation reasons ftps.sendcmd('site msg sysop ' + user.handle + ' added, please validate them ' ) ftps.quit() user.save() goto(top_script, user.handle)
def main(): session, term = getsession(), getterminal() session.activity = 'Viewing Userlist' colors = { 'highlight': term.red, 'lowlight': term.green, } line_no = display_banner(filepattern=art_file, encoding=art_encoding) # get and format userlist userlist = (u'{sp}{handle} {location} {lastcall}'.format( sp=u' ' * 4, handle=ur.handle.ljust(username_max_length), location=colors['lowlight'](ur.location.ljust(location_max_length)), lastcall=timeago(ur.timeago)) for ur in iter_userlist()) echo(u'\r\n') # display users, using a command-prompt pager. prompt_pager(content=userlist, line_no=line_no + 1, colors={ 'highlight': term.red, 'lowlight': term.green, }, width=80, breaker=None)
def main(): session, term = getsession(), getterminal() session.activity = 'Viewing Userlist' colors = {'highlight': term.red, 'lowlight': term.green, } line_no = display_banner(filepattern=art_file, encoding=art_encoding) # get and format userlist userlist = ( u'{sp}{handle} {location} {lastcall}' .format(sp=u' ' * 4, handle=ur.handle.ljust(username_max_length), location=colors['lowlight']( ur.location.ljust(location_max_length)), lastcall=timeago(ur.timeago)) for ur in iter_userlist()) echo(u'\r\n') # display users, using a command-prompt pager. prompt_pager(content=userlist, line_no=line_no + 1, colors={'highlight': term.red, 'lowlight': term.green, }, width=80, breaker=None)
def main(handle=None): """ Main procedure. """ session, term = getsession(), getterminal() session.activity = u'resetting password' display_banner(art_file) # mix animation into art echo(term.move_up() * 5) # display banner animation display_banner_animation(banner_text=u'reset account password') return do_reset(term, handle)
def set_subscription_tags(session, term): """ This function is called to assign a new set of subscription tags for a user. If escape is pressed, the existing value is used, or '*' is used if not previously set. This should be called for first-time users, and optionally at any later time to change a subscription. """ line_no = display_banner(art_file, encoding=art_encoding) # introduce the user to the concept ... description = ( u"{term.yellow}You can think of tags as a system of providing " u"context to any message stored on this system. A tag might signify " u"that it was received on a particular message network, or it might " u"provide the topic of conversation, such as " u"{term.bold_yellow}python{term.normal}{term.yellow} or " u"{term.bold_yellow}rock music{term.normal}{term.yellow}. " u"This is similar to flicker's tags, or twitter hashtags. " u"Use glob expressions as a comma-delimited list, for example, " u"the expression {term.bold_yellow}x84net{term.normal}{term.yellow}, " u"{term.bold_yellow}sysop{term.normal}{term.yellow}, " u"{term.bold_yellow}python*{term.normal}{term.yellow} " u"will subscribe to all tags of the x84net message network, " u"sysop messages, and any topics that begin with the phrase " u"{term.bold_yellow}python{term.normal}{term.yellow}. You can " u"subscribe to all topics using the expression, " u"{term.bold_yellow}*{term.normal}{term.yellow}.".format(term=term) ) echo(u"\r\n") line_no += 1 line_no += show_description(description, color=None) description = u" ".join( [u"tags available:"] + ["{tag}{term.yellow},{term.normal}".format(tag=tag, term=term) for tag in list_tags()] ) echo(u"\r\n\r\n") line_no += 2 # display our prompt prefix, input_prefix: input_prefix = u" {sep} {key:>18}: ".format(sep=term.bright_yellow(u"::"), key="subscription tags") echo(input_prefix) xloc = term.length(input_prefix) # and prompt an editor on that row editor = ScrollingEditor( xloc=xloc, yloc=line_no, width=(term.width - xloc - 2), colors={"highlight": term.black_on_yellow} ) value = editor.read() or u"" echo(term.normal + u"\r\n\r\n") return map(unicode.strip, value.split(","))
def main(last=10): """ Script entry point. :param last: Number of last callers to display :type last: int """ session, term = getsession(), getterminal() session.activity = u'Viewing last callers' colors = [term.green, term.bright_blue, term.bold, term.cyan, term.bold_black] # set syncterm font, if any if syncterm_font and term._kind.startswith('ansi'): echo(syncterm_setfont(syncterm_font)) # display banner line_no = display_banner(filepattern=art_file, encoding=art_encoding) # get last callers last_callers = get_lastcallers(last=last) echo(u'\r\n\r\n') # format callers, header: callers_txt = [ '{handle} {location} {num_calls} {timeago}' .format( handle=term.bold_underline( term.ljust('handle', username_max_length + 1)), location=term.underline( term.ljust('location', location_max_length)), num_calls=term.bold_underline( term.ljust('# calls', numcalls_max_length)), timeago=term.underline('time ago')) ] # content: callers_txt.extend([ u'{handle} {location} {num_calls} {timeago}' .format(handle=lc.handle.ljust(username_max_length + 1), location=term.ljust(colors[idx % len(colors)]( lc.location or '-' * location_max_length), location_max_length), num_calls='{0}'.format( lc.num_calls).rjust(numcalls_max_length), timeago=colors[idx % len(colors)]( timeago(lc.timeago)) ) for idx, lc in enumerate(last_callers) ]) # display file contents, decoded, using a command-prompt pager. prompt_pager(content=callers_txt, line_no=line_no + 2, colors={'highlight': term.bright_green, 'lowlight': term.cyan, }, width=max(term.length(txt) for txt in callers_txt), breaker=None)
def main(last=10): """ Script entry point. :param int last: Number of last callers to display """ session, term = getsession(), getterminal() session.activity = u'Viewing last callers' colors = [term.green, term.bright_blue, term.bold, term.cyan, term.bold_black] # set syncterm font, if any if syncterm_font and term.kind.startswith('ansi'): echo(syncterm_setfont(syncterm_font)) # display banner line_no = display_banner(filepattern=art_file, encoding=art_encoding) # get last callers last_callers = get_lastcallers(last=last) echo(u'\r\n\r\n') # format callers, header: callers_txt = [ '{handle} {location} {num_calls} {timeago}' .format( handle=term.bold_underline( term.ljust('handle', username_max_length + 1)), location=term.underline( term.ljust('location', location_max_length)), num_calls=term.bold_underline( term.ljust('# calls', numcalls_max_length)), timeago=term.underline('time ago')) ] # content: callers_txt.extend([ u'{handle} {location} {num_calls} {timeago}' .format(handle=lc.handle.ljust(username_max_length + 1), location=term.ljust(colors[idx % len(colors)]( lc.location or '-' * location_max_length), location_max_length), num_calls='{0}'.format( lc.num_calls).rjust(numcalls_max_length), timeago=colors[idx % len(colors)]( timeago(lc.timeago)) ) for idx, lc in enumerate(last_callers) ]) # display file contents, decoded, using a command-prompt pager. prompt_pager(content=callers_txt, line_no=line_no + 2, colors={'highlight': term.bright_green, 'lowlight': term.cyan, }, width=max(term.length(txt) for txt in callers_txt), breaker=None)
def main(): session, term = getsession(), getterminal() session.activity = 'Viewing Userlist' colors = { 'highlight': term.red, 'lowlight': term.green, } line_no = display_banner(filepattern=art_file, encoding=art_encoding) def make_header(fmt): return fmt.format( handle=term.bold('handle'.ljust(username_max_length)), location=term.bold('location'.ljust(location_max_length)), lastcall=term.bold('time ago').ljust(8)) userlist_fmt = u'| {handle} | {location} | {lastcall} |' header = make_header(userlist_fmt) header_length = term.length(header) # for smaller screens, remove 'location' field. if header_length > term.width: userlist_fmt = u'| {handle} | {lastcall} |' header = make_header(userlist_fmt) header_length = term.length(header) userlist = [header] + ['-' * header_length] echo(u'Fetching ... ') for _ur in iter_userlist(): location_txt = u'' if 'location' in userlist_fmt: location_txt = colors['lowlight']( _ur.location.ljust(location_max_length)) timeago_txt = timeago(_ur.timeago).ljust(8) handle_txt = _ur.handle.ljust(username_max_length) userlist.append( userlist_fmt.format(handle=handle_txt, location=location_txt, lastcall=timeago_txt)) echo(term.move_x(0) + term.clear_eol + u'Processing ...' + term.move_x(0)) # display users, using a command-prompt pager. prompt_pager(content=userlist, line_no=line_no + 1, colors={ 'highlight': term.red, 'lowlight': term.green, }, width=80, breaker=None)
def show_banner(term): """ Display banner, calculate and return x/y coords as Point. """ if term.height >= 24: echo(term.move(term.height - 1, 0)) yloc = display_banner('art/ue.ans') + 1 else: echo(term.move(term.height - 1, 0)) # create a new, empty screen echo(u'\r\n' * (term.height + 1)) yloc = 1 return Point(y=yloc, x=max(5, (term.width // 2) - 30))
def main(): session, term = getsession(), getterminal() session.activity = 'Viewing Userlist' colors = {'highlight': term.red, 'lowlight': term.green, } line_no = display_banner(filepattern=art_file, encoding=art_encoding) def make_header(fmt): return fmt.format( handle=term.bold('handle'.ljust(username_max_length)), location=term.bold('location'.ljust(location_max_length)), lastcall=term.bold('time ago').ljust(8)) userlist_fmt = u'| {handle} | {location} | {lastcall} |' header = make_header(userlist_fmt) header_length = term.length(header) # for smaller screens, remove 'location' field. if header_length > term.width: userlist_fmt = u'| {handle} | {lastcall} |' header = make_header(userlist_fmt) header_length = term.length(header) userlist = [header] + ['-' * header_length] for _ur in iter_userlist(): location_txt = u'' if 'location' in userlist_fmt: location_txt = colors['lowlight']( _ur.location.ljust(location_max_length)) timeago_txt = timeago(_ur.timeago).ljust(8) handle_txt = _ur.handle.ljust(username_max_length) userlist.append(userlist_fmt.format( handle=handle_txt, location=location_txt, lastcall=timeago_txt)) echo(u'\r\n') # display users, using a command-prompt pager. prompt_pager(content=userlist, line_no=line_no + 1, colors={'highlight': term.red, 'lowlight': term.green, }, width=80, breaker=None)
def main(last_called=None): """ Main procedure. """ session, term = getsession(), getterminal() session.activity = "checking for new messages" # set syncterm font, if any if term._kind == "ansi": echo(syncterm_setfont(syncterm_font)) search_tags = session.user.get(key="msg_subscription", default=None) if search_tags is None: # prompt user for tag subscription search_tags = set_subscription_tags(session, term) if search_tags: session.user["msg_subscription"] = search_tags else: session.user["msg_subscription"] = ["public"] display_banner(art_file, encoding=art_encoding) display_subscription(session, term) term.inkey()
def main(handle=u''): """ Main procedure. """ # set syncterm font, if any term = getterminal() if term.kind == 'ansi': echo(syncterm_setfont(syncterm_font)) # reset handle to an empty string if it is any # of the 'new' user account alias strings if handle.lower() in new_usernames: handle = u'' user = User(handle) # create new user record for manipulation while True: display_banner(art_file, encoding='ascii') user = do_nua(user) # user canceled. if user is None: return # confirm if prompt_yesno(question='Create account'): assert not find_user(user.handle), ( # prevent race condition, scenario: `billy' begins new account # process, waits at 'Create account [yn] ?' prompt until a # second `billy' finishes account creation process, then the # first `billy' enters 'y', overwriting the existing account. 'Security race condition: account already exists') user.save() goto(top_script, user.handle)
def do_select_encoding(term, session): editor_colors = {'highlight': term.black_on_green} dirty = True while True: if session.poll_event('refresh') or dirty: vertical_padding = 2 if term.height >= 24 else 0 display_banner(filepattern=art_file, encoding=art_encoding, vertical_padding=vertical_padding) display_prompt(term) 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'')) dirty = False inp = LineEditor(1, colors=editor_colors).read() if inp is None or inp.lower() == 'd': break elif len(inp) == 1: # position cursor for next call to LineEditor() echo(u'\b') if inp.lower() == u'u' and session.encoding != 'utf8': session.encoding = 'utf8' dirty = True elif inp.lower() == 'c' and session.encoding != 'cp437': session.encoding = 'cp437' dirty = True
def main(handle=u''): """ Main procedure. """ # set syncterm font, if any term = getterminal() if term._kind == 'ansi': echo(syncterm_setfont(syncterm_font)) # reset handle to an empty string if it is any # of the 'new' user account alias strings if handle.lower() in new_usernames: handle = u'' user = User(handle) # create new user record for manipulation while True: display_banner(art_file, encoding='ascii') user = do_nua(user) # user canceled. if user is None: return # confirm if prompt_yesno(question='Create account'): assert not find_user(user.handle), ( # prevent race condition, scenario: `billy' begins new account # process, waits at 'Create account [yn] ?' prompt until a # second `billy' finishes account creation process, then the # first `billy' enters 'y', overwriting the existing account. 'Security race condition: account already exists') user.save() goto(top_script, user.handle)
def main(quick=False): """ Script entry point. :param quick: When True, returns early if this news has already been read. :type quick: bool """ session, term = getsession(), getterminal() if not os.path.exists(news_file): log.warn('No news file, {0}'.format(news_file)) echo(u'\r\n\r\n' + term.center(u'No news.').rstrip() + u'\r\n') return # return early if 'quick' is True and news is not new news_mtime = os.stat(news_file).st_mtime if quick and news_mtime < session.user.get('news_lastread', 0): return # set syncterm font, if any if syncterm_font and term._kind == 'ansi': echo(syncterm_setfont(syncterm_font)) session.activity = 'Reading news' # display banner line_no = display_banner(filepattern=art_file, encoding=art_encoding) # retrieve news_file contents (decoded as utf8) news = decode_pipe(codecs.open( news_file, 'rb', news_file_encoding).read() ).splitlines() echo(u'\r\n\r\n') # display file contents, decoded, using a command-prompt pager. prompt_pager(content=news, line_no=line_no + 2, colors={'highlight': term.yellow, 'lowlight': term.green, }, width=80) # update user's last-read time of news. session.user['news_lastread'] = time.time()
def main(quick=False): """ Script entry point. :param bool quick: When True, returns early if this news has already been read. """ session, term = getsession(), getterminal() if not os.path.exists(news_file): log.warn('No news file, {0}'.format(news_file)) echo(u'\r\n\r\n' + term.center(u'No news.').rstrip() + u'\r\n') return # return early if 'quick' is True and news is not new news_mtime = os.stat(news_file).st_mtime if quick and news_mtime < session.user.get('news_lastread', 0): return # set syncterm font, if any if syncterm_font and term.kind == 'ansi': echo(syncterm_setfont(syncterm_font)) session.activity = 'Reading news' # display banner line_no = display_banner(filepattern=art_file, encoding=art_encoding) # retrieve news_file contents (decoded as utf8) news = decode_pipe( codecs.open(news_file, 'rb', news_file_encoding).read()).splitlines() echo(u'\r\n\r\n') # display file contents, decoded, using a command-prompt pager. prompt_pager(content=news, line_no=line_no + 2, colors={ 'highlight': term.yellow, 'lowlight': term.green, }, width=min(80, term.width)) # update user's last-read time of news. session.user['news_lastread'] = time.time()
def do_prompt(term, session): thread = None if shroo_ms_enabled: # fetch shroo-ms api oneliners thread = FetchUpdatesShrooMs() thread.start() dirty = -1 top_margin = bot_margin = 0 offset = 0 do_quit = False while not do_quit: if dirty == -1: # re-display entire screen on-load, only. there # should never be any need to re-draw the art here-forward. top_margin = display_banner(art_file, encoding=art_encoding) echo(u'\r\n') top_margin += 1 dirty = 1 if dirty == 1: # re-display all oneliners on update, or dirty == 1 # if any shroo-ms oneliners were received, merge them # into the database from the main thread. if thread is not None and not thread.is_alive(): if thread.new_content: echo(term.move_x(0) + term.clear_eol) echo(term.center(term.bold_red('This just in!')).rstrip()) do_merge_shroo_ms(thread.new_content) thread = None with term.hidden_cursor(): bot_margin, offset = display_oneliners( term, top_margin, offset) dirty = 1 if dirty: # always re-prompt on any dirty flag session.activity = u'Viewing Oneliners' display_prompt(term, yloc=bot_margin) dirty = 0 event, data = session.read_events( ('input', 'oneliner', 'refresh')) if event == 'refresh': dirty = -1 continue elif event == 'oneliner': dirty = 1 continue elif event == 'input': session.buffer_input(data, pushback=True) inp = term.inkey(0) while inp: if inp.lower() in (u'y',): # say something, refresh after echo(inp) say_retval = say_something(term, session) if isinstance(say_retval, FetchUpdatesShrooMs): # a rather strange hack, we track the thread of # api calls so that we can merge its final content # into our local database. See __init__ for # bug id and description thread = say_retval elif say_retval: # user has said something to the local database, # refresh it so that they can beam with pride ... dirty = 1 continue # only redraw prompt (user canceled) dirty = 2 elif inp.lower() in (u'n', u'q', u'\r', u'\n'): echo(inp + u'\r\n') do_quit = True break elif len(inp): # maybe scroll, really quite convoluted ... height = bot_margin - top_margin sequence_keymap, keymap = get_keymap(term, offset, height) if ((inp.is_sequence and inp.code in sequence_keymap) or inp in keymap): _noff = sequence_keymap.get( keymap.get(inp, None), offset) n_offset = sequence_keymap.get( inp.code, _noff) if n_offset != offset: offset = n_offset dirty = 1 inp = term.inkey(0)
def main(quick=False): """ Main procedure. """ session, term = getsession(), getterminal() session.activity = 'checking for new messages' # set syncterm font, if any if term.kind.startswith('ansi'): echo(syncterm_setfont(syncterm_font)) colors = dict( highlight=lambda txt: txt, lowlight=lambda txt: txt, backlight=lambda txt: txt, text=lambda txt: txt ) if not colored_menu_items else dict( highlight=getattr(term, color_highlight), lowlight=getattr(term, color_lowlight), backlight=getattr(term, color_backlight), text=getattr(term, color_text)) yloc = top_margin = 0 subscription = session.user.get('msg_subscription', []) dirty = 2 while True: if dirty == 2: # display header art, yloc = display_banner(art_file, encoding=art_encoding, center=True) xloc = max(0, (term.width // 2) - 40) echo(u'\r\n') top_margin = yloc = (yloc + 1) elif dirty: echo(term.move(top_margin, 0) + term.normal + term.clear_eos) echo(term.move(top_margin, xloc)) if dirty: if not subscription: # prompt the user for a tag subscription, and loop # back again when completed to re-draw and show new messages. subscription = session.user['msg_subscription'] = ( prompt_subscription( session=session, term=term, yloc=top_margin, subscription=subscription, colors=colors)) continue messages, messages_bytags = get_messages_by_subscription( session, subscription) # When quick login ('y') selected in top.py, return immediately # when no new messages are matched any longer. if quick and not messages['new']: echo(term.move_x(xloc) + u'\r\nNo new messages.\r\n') return waitprompt(term) txt = describe_message_area( term=term, subscription=subscription, messages_bytags=messages_bytags, colors=colors) yloc = top_margin + show_description( term=term, description=txt, color=None, subsequent_indent=' ' * len('message area: ')) echo(render_menu_entries( term=term, top_margin=yloc, menu_items=get_menu(messages), colors=colors, max_cols=2)) echo(display_prompt(term=term, colors=colors)) echo(colors['backlight'](u' \b')) dirty = False event, data = session.read_events(('refresh', 'newmsg', 'input')) if event == 'refresh': # screen resized, redraw. dirty = 2 continue elif event == 'newmsg': # When a new message is sent, 'newmsg' event is broadcasted. session.flush_event('newmsg') nxt_msgs, nxt_bytags = get_messages_by_subscription( session, subscription) if nxt_msgs['new'] - messages['new']: # beep and re-display when a new message has arrived. echo(u'\b') messages, messages_bytags = nxt_msgs, nxt_bytags dirty = True continue elif event == 'input': # on input, block until carriage return session.buffer_input(data, pushback=True) given_inp = LineEditor( 1, colors={'highlight': colors['backlight']} ).read() if given_inp is None: # escape/cancel continue inp = given_inp.strip() if inp.lower() in (u'n', 'a', 'v'): # read new/all/private messages message_indices = sorted(list( {'n': messages['new'], 'a': messages['all'], 'v': messages['private'], }[inp.lower()])) if message_indices: dirty = 2 read_messages(session=session, term=term, message_indices=message_indices, colors=colors) elif inp.lower() == u'm' and messages['new']: # mark all messages as read dirty = 1 do_mark_as_read(session, messages['new']) elif inp.lower() in (u'p', u'w'): # write new public/private message dirty = 2 public = bool(inp.lower() == u'p') msg = Msg() if ( not prompt_recipient( term=term, msg=msg, colors=colors, public=public ) or not prompt_subject( term=term, msg=msg, colors=colors ) or not prompt_body( term=term, msg=msg, colors=colors ) or not prompt_tags( session=session, term=term, msg=msg, colors=colors, public=public )): continue do_send_message(session=session, term=term, msg=msg, colors=colors) elif inp.lower() == u'c': # prompt for new tag subscription (at next loop) subscription = [] dirty = 1 elif inp.lower() == u'?': # help echo(term.move(top_margin, 0) + term.clear_eos) do_describe_message_system(term, colors) waitprompt(term) dirty = 1 elif inp.lower() == u'q': return if given_inp: # clear out line editor prompt echo(colors['backlight'](u'\b \b'))
def do_prompt(term, session): thread = None if shroo_ms_enabled: # fetch shroo-ms api oneliners thread = FetchUpdatesShrooMs() thread.start() dirty = -1 top_margin = bot_margin = 0 offset = 0 do_quit = False while not do_quit: if dirty == -1: # re-display entire screen on-load, only. there # should never be any need to re-draw the art here-forward. top_margin = display_banner(art_file, encoding=art_encoding) echo(u'\r\n') top_margin += 1 dirty = 1 if dirty == 1: # re-display all oneliners on update, or dirty == 1 # if any shroo-ms oneliners were received, merge them # into the database from the main thread. if thread is not None and not thread.is_alive(): if thread.new_content: echo(term.move_x(0) + term.clear_eol) echo(term.center(term.bold_red('This just in!')).rstrip()) do_merge_shroo_ms(thread.new_content) thread = None with term.hidden_cursor(): bot_margin, offset = display_oneliners(term, top_margin, offset) dirty = 1 if dirty: # always re-prompt on any dirty flag session.activity = u'Viewing Oneliners' display_prompt(term, yloc=bot_margin) dirty = 0 event, data = session.read_events(('input', 'oneliner', 'refresh')) if event == 'refresh': dirty = -1 continue elif event == 'oneliner': dirty = 1 continue elif event == 'input': session.buffer_input(data, pushback=True) inp = term.inkey(0) while inp: if inp.lower() in (u'y', ): # say something, refresh after echo(inp) say_retval = say_something(term, session) if isinstance(say_retval, FetchUpdatesShrooMs): # a rather strange hack, we track the thread of # api calls so that we can merge its final content # into our local database. See __init__ for # bug id and description thread = say_retval elif say_retval: # user has said something to the local database, # refresh it so that they can beam with pride ... dirty = 1 break # only redraw prompt (user canceled) dirty = 2 elif inp.lower() in (u'n', u'q', u'\r', u'\n'): echo(inp + u'\r\n') do_quit = True break elif len(inp): # maybe scroll, really quite convoluted ... height = bot_margin - top_margin sequence_keymap, keymap = get_keymap(term, offset, height) if ((inp.is_sequence and inp.code in sequence_keymap) or inp in keymap): _noff = sequence_keymap.get(keymap.get(inp, None), offset) n_offset = sequence_keymap.get(inp.code, _noff) if n_offset != offset: offset = n_offset dirty = 1 inp = term.inkey(0)
def main(quick=False): """ Main procedure. """ session, term = getsession(), getterminal() session.activity = 'checking for new messages' # set syncterm font, if any if term.kind.startswith('ansi'): echo(syncterm_setfont(syncterm_font)) colors = dict(highlight=lambda txt: txt, lowlight=lambda txt: txt, backlight=lambda txt: txt, text=lambda txt: txt) if not colored_menu_items else dict( highlight=getattr(term, color_highlight), lowlight=getattr(term, color_lowlight), backlight=getattr(term, color_backlight), text=getattr(term, color_text)) yloc = top_margin = 0 subscription = session.user.get('msg_subscription', []) dirty = 2 while True: if dirty == 2: # display header art, yloc = display_banner(art_file, encoding=art_encoding, center=True) xloc = max(0, (term.width // 2) - 40) echo(u'\r\n') top_margin = yloc = (yloc + 1) elif dirty: echo(term.move(top_margin, 0) + term.normal + term.clear_eos) echo(term.move(top_margin, xloc)) if dirty: if not subscription: # prompt the user for a tag subscription, and loop # back again when completed to re-draw and show new messages. subscription = session.user['msg_subscription'] = ( prompt_subscription(session=session, term=term, yloc=top_margin, subscription=subscription, colors=colors)) continue messages, messages_bytags = get_messages_by_subscription( session, subscription) # When quick login ('y') selected in top.py, return immediately # when no new messages are matched any longer. if quick and not messages['new']: echo(term.move_x(xloc) + u'\r\nNo new messages.\r\n') return waitprompt(term) txt = describe_message_area(term=term, subscription=subscription, messages_bytags=messages_bytags, colors=colors) yloc = top_margin + show_description( term=term, description=txt, color=None, subsequent_indent=' ' * len('message area: ')) echo( render_menu_entries(term=term, top_margin=yloc, menu_items=get_menu(messages), colors=colors, max_cols=2)) echo(display_prompt(term=term, colors=colors)) echo(colors['backlight'](u' \b')) dirty = False event, data = session.read_events(('refresh', 'newmsg', 'input')) if event == 'refresh': # screen resized, redraw. dirty = 2 continue elif event == 'newmsg': # When a new message is sent, 'newmsg' event is broadcasted. session.flush_event('newmsg') nxt_msgs, nxt_bytags = get_messages_by_subscription( session, subscription) if nxt_msgs['new'] - messages['new']: # beep and re-display when a new message has arrived. echo(u'\b') messages, messages_bytags = nxt_msgs, nxt_bytags dirty = True continue elif event == 'input': # on input, block until carriage return session.buffer_input(data, pushback=True) given_inp = LineEditor(1, colors={ 'highlight': colors['backlight'] }).read() if given_inp is None: # escape/cancel continue inp = given_inp.strip() if inp.lower() in (u'n', 'a', 'v'): # read new/all/private messages message_indices = sorted( list({ 'n': messages['new'], 'a': messages['all'], 'v': messages['private'], }[inp.lower()])) if message_indices: dirty = 2 read_messages(session=session, term=term, message_indices=message_indices, colors=colors) elif inp.lower() == u'm' and messages['new']: # mark all messages as read dirty = 1 do_mark_as_read(session, messages['new']) elif inp.lower() in (u'p', u'w'): # write new public/private message dirty = 2 public = bool(inp.lower() == u'p') msg = Msg() if (not prompt_recipient( term=term, msg=msg, colors=colors, public=public) or not prompt_subject(term=term, msg=msg, colors=colors) or not prompt_body(term=term, msg=msg, colors=colors) or not prompt_tags(session=session, term=term, msg=msg, colors=colors, public=public)): continue do_send_message(session=session, term=term, msg=msg, colors=colors) elif inp.lower() == u'c': # prompt for new tag subscription (at next loop) subscription = [] dirty = 1 elif inp.lower() == u'?': # help echo(term.move(top_margin, 0) + term.clear_eos) do_describe_message_system(term, colors) waitprompt(term) dirty = 2 elif inp.lower() == u'q': return if given_inp: # clear out line editor prompt echo(colors['backlight'](u'\b \b'))
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)