Ejemplo n.º 1
0
def do_fetch(postal):
    """
    Given postal code, fetch and return xml root node of weather results.
    """
    from x84.bbs import echo, getch, getterminal
    import StringIO
    term = getterminal()
    disp_msg('fEtChiNG')
    resp = requests.get(u'http://apple.accuweather.com'
                        + u'/adcbin/apple/Apple_Weather_Data.asp',
                        params=(('zipcode', postal),))
    if resp is None:
        disp_notfound()
        return None
    if resp.status_code != 200:
        # todo: logger.error
        echo(u'\r\n')
        echo(term.bold_red(u'StAtUS COdE: %s' % (resp.status_code,)))
        echo(u'\r\n\r\n')
        echo(repr(resp.content))
        echo(u'\r\n\r\n' + 'PRESS ANY kEY')
        getch()
        return None
    xml_stream = StringIO.StringIO(resp.content)
    tree = ET.parse(xml_stream)
    return tree.getroot()
Ejemplo n.º 2
0
Archivo: si.py Proyecto: tehmaze/x84
 def refresh():
     """ Refresh screen and return top-left (x, y) location. """
     # set syncterm font to cp437
     if term.kind.startswith('ansi'):
         echo(syncterm_setfont('cp437'))
     echo(u'\r\n\r\n')
     if term.width < width:
         echo(u''.join((
             term.move(term.height, 0),
             u'\r\n\r\n',
             term.bold_red + 'screen too thin! (%s/%s)' % (
                 term.width, width,),
             u'\r\n\r\n',
             u'press any key...',)))
         getch()
         return (None, None)
     if term.height < height:
         echo(u''.join((
             term.move(term.height, 0),
             u'\r\n\r\n',
             term.bold_red + 'screen too short! (%s/%s)' % (
                 term.height, height),
             u'\r\n\r\n',
             u'press any key...',)))
         getch()
         return (None, None)
     xloc = (term.width / 2) - (width / 2)
     yloc = (term.height / 2) - (height / 2)
     echo(u''.join((
         term.normal,
         (u'\r\n' + term.clear_eol) * term.height,
         u''.join([term.move(yloc + abs_y, xloc) + line
                   for abs_y, line in enumerate(otxt)]),)))
     return xloc, yloc
Ejemplo n.º 3
0
def do_search(search):
    """
    Given any arbitrary string, return list of possible matching locations.
    """
    import StringIO
    from x84.bbs import echo, getch
    disp_msg(u'SEARChiNG')
    resp = requests.get(u'http://apple.accuweather.com'
                        + u'/adcbin/apple/Apple_find_city.asp',
                        params=(('location', search),))
    locations = list()
    if resp is None:
        disp_notfound()
    elif resp.status_code != 200:
        # todo: logger.error
        echo(u'\r\n' + u'Status Code: %s\r\n\r\n' % (resp.status_code,))
        echo(repr(resp.content))
        echo(u'\r\n\r\n' + 'Press any key')
        getch()
    else:
        # print resp.content
        xml_stream = StringIO.StringIO(resp.content)
        locations = list([dict(elem.attrib.items())
                          for _event, elem in ET.iterparse(xml_stream)
                          if elem.tag == 'location'])
        if 0 == len(locations):
            disp_notfound()
        else:
            disp_found(len(locations))
    return locations
Ejemplo n.º 4
0
def view_ansi(key):
    """ fetch and view a bbs ansi. They're not often very good ...
    """
    from x84.bbs import getterminal, echo, DBProxy, ini, getch, from_cp437
    term = getterminal()
    ansiurl = DBProxy('bbslist')[key]['ansi']
    logger = logging.getLogger()
    echo(u'\r\n\r\n')
    if ansiurl is not None and 0 != len(ansiurl) and ansiurl != 'NONE':
        usernm = ini.CFG.get('bbs-scene', 'user')
        passwd = ini.CFG.get('bbs-scene', 'pass')
        req = requests.get(ansiurl, auth=(usernm, passwd))
        if req.status_code != 200:
            echo(u'\r\n\r\nrequest failed,\r\n')
            echo(u'%r' % (req.content,))
            echo(u'\r\n\r\n(code : %s).\r\n' % (req.status_code,))
            echo(u'\r\nPress any key ..')
            logger.warn('ansiurl request failed: %s' % (ansiurl,))
            getch()
            return
        ansi_txt = from_cp437(sauce.SAUCE(data=req.content).__str__())
        echo(ansi_txt)
    else:
        echo('no ansi available (%s)' % (ansiurl,))
    # move to bottom of screen and getch
    echo(u''.join((
        term.move(term.height, 0),
        term.normal,
        u'\r\n\r\nPRESS ANY kEY ...'),))
    getch()
Ejemplo n.º 5
0
Archivo: lc.py Proyecto: quastdog/x84
def pak():
    """ Press any key prompt. """
    from x84.bbs import echo, getch
    msg_pak = u'PRESS ANY kEY'
    echo(u'\r\n%s ... ' % (msg_pak,))
    getch()
    return
Ejemplo n.º 6
0
def dummy_pager(user):
    """ A dummy selector for profile attributes """
    from x84.bbs import getsession, getterminal, echo, Ansi, getch
    session, term = getsession(), getterminal()
    plan = user.get('.plan', False)
    from x84.bbs.ini import CFG
    def_timeout = CFG.getint('system', 'timeout')
    menu = ['(c)%-20s - %s' % (u'hARACtER ENCOdiNG',
                               term.bold(session.encoding),),
            '(t)%-20s - %s' % (u'ERMiNAl tYPE',
                               term.bold(session.env.get('TERM', 'unknown')),),
            '(h)%-20s - %s' % (u'ERMiNAl hEiGht',
                               term.bold(str(term.height)),),
            '(w)%-20s - %s' % (u'ERMiNAl WidtH',
                               term.bold(str(term.width)),),
            '(l)%-20s - %s' % (u'OCAtiON',
                               term.bold(user.location),),
            '(p)%-20s - %s' % (u'ASSWORd',
                               term.bold_black(u'******'),),
            '(!)%-20s - %s' % (u'Set SA User Cookie',
                               term.bold(user['sausercookie']),),
            '(@)%-20s - %s' % (u'Set SA Pass Cookie',
                               term.bold_black(user['sapasscookie']),),
            '(e)%-20s - %s' % (u'-MAil AddRESS',
                               term.bold(user.email),),
#            '(!)%-20s - %s' % (u'SA User Cookie',
#                               term.bold(user['sausercookie']),),
#            '(@)%-70s - %s' % (u'SA Pass Cookie',
#                               term.bold(user['sapasscookie']),),
            (term.bold('t') +
                '(i)%-19s - %s' % (u'MEOUt', term.bold(
                    str(user.get('timeout', def_timeout))),)),
            '(s)%-20s - %s' % (u'YSOP ACCESS',
                               term.bold(u'ENAblEd'
                                         if 'sysop' in user.groups
                                         else 'diSAblEd')),
            '(m)%-20s - %s' % (u'ESG',
                               term.bold(u'[%s]' % ('y'
                                   if user.get(
                                       'mesg', True) else 'n',),)),
            '(.)%-20s - %s' % (u'PlAN filE', '%d bytes' % (
                len(plan),) if plan else '(NO PlAN.)'),
            '(x)%-20s - %s' % (u'PERt MOdE',
                               term.bold(u'ENAblEd'
                                         if user.get('expert', False)
                                         else 'diSAblEd')),
            '(q)Uit', ]
    echo(term.normal + term.clear() )
    lines = Ansi('\n'.join(menu)).wrap(term.width).splitlines()
    xpos = max(1, int(term.width / 2) - (40 / 2))
    for row, line in enumerate(lines):
        if row and (0 == row % (term.height - 2)):
            echo(term.reverse(u'\r\n-- More --'))
            getch()
        echo(u'\r\n' + ' ' * xpos + line)
    echo(u'\r\n\r\n Enter option [ctle.xq]: ')
    return process_keystroke(getch(), user)
Ejemplo n.º 7
0
def disp_notfound():
    """ Display 'bad request -/- not found in red. """
    from x84.bbs import getsession, getterminal, echo, getch
    term = getterminal()
    echo(u''.join((u'\r\n\r\n',
                   term.bold(u'bAd REQUESt'),
                   term.bold_red(' -/- '),
                   term.bold('NOt fOUNd.',),)))
    if not getsession().user.get('expert', False):
        getch(1.7)
Ejemplo n.º 8
0
Archivo: common.py Proyecto: hick/x84
def waitprompt():
    # Displays a simple "press enter to continue prompt". Very handy!
    from x84.bbs import echo, getch, getterminal
    term = getterminal()

    echo (term.normal+'\n\r'+term.magenta+'('+term.green+'..'+term.white+
          ' press any key to continue '+term.green+'..'+term.magenta+')')
    getch()
    echo(term.normal_cursor)
    return
Ejemplo n.º 9
0
def disp_notfound():
    """ Display 'bad request -/- not found in red. """
    from x84.bbs import getsession, getterminal, echo, getch
    term = getterminal()
    bad_req = term.bold(u'bAd REQUESt')
    decorator = term.bold_red(u'-/-')
    not_found = term.bold('NOt fOUNd.')
    echo('\r\n\r\n{bad_req} {decorator} {not_found}'.format(
        bad_req=bad_req, decorator=decorator, not_found=not_found))
    if not getsession().user.get('expert', False):
        getch(1.7)
Ejemplo n.º 10
0
def main():
    """ Main routine. """
    from x84.bbs import getsession, getterminal, echo, getch
    session, term = getsession(), getterminal()
    session.activity = 'Weather'

    echo(u'\r\n\r\n')
    location = session.user.get('location', dict())
    while True:
        search = location.get('postal', u'')
        disp_search_help()
        search = get_zipsearch(search)
        if search is None or 0 == len(search):
            return  # exit
        locations = do_search(search)
        if 0 != len(locations):
            location = (locations.pop() if 1 == len(locations)
                        else chose_location(locations) or dict())
        root = do_fetch(location.get('postal'))
        if root is None:
            return
        weather = parse_weather(root)
        #if False == location_prompt(location, 'WEAthER'):
        #    break
        disp_weather(weather)
        if False == location_prompt(location, 'fORECASt'):
            break
        forecast = parse_forecast(root)
        disp_forecast(forecast)
        echo(u'\r\n')
        echo(term.yellow_reverse('--ENd Of tRANSMiSSiON--'))
        getch()
        break

    if (sorted(location.items())
            != sorted(session.user.get('location', dict()).items())):
        echo(u''.join((u'\r\n\r\n',
                       term.yellow(u'SAVE lOCAtION'),
                       term.bold_yellow(' ('),
                       term.bold_black(u'PRiVAtE'),
                       term.bold_yellow(') '),
                       term.yellow('? '),
            term.bold_yellow(u'['),
            term.underline_yellow(u'yn'),
            term.bold_yellow(u']'),
            u': '),))
        while True:
            inp = getch()
            if inp is None or inp in (u'n', u'N', 'q', 'Q', term.KEY_EXIT):
                break
            if inp in (u'y', u'Y', u' ', term.KEY_ENTER):
                session.user['location'] = location
                break
Ejemplo n.º 11
0
def main(ttyfile=u'', peek=False):
    """ Main procedure. """
    from x84.bbs import Lightbar, getch, getsession, getterminal, ini, echo
    # pylint: disable=R0914,R0915
    #         Too many local variables
    #         Too many statements
    ttyplay_exe = ini.CFG.get('ttyplay', 'exe')
    if not os.path.exists(ttyplay_exe):
        echo(u'\r\n%s NOt iNStAllEd.\r\n' % (ttyplay_exe,))
        getch()
        return
    session, term = getsession(), getterminal()
    # pylint: disable=W0212
    #         Access to a protected member _record_tty of a client class
    resume_rec = session._record_tty and session.is_recording
    if resume_rec:
        session.stop_recording()
        session._record_tty = False

    if 'sysop' in session.user.groups and ttyfile == u'':
        # pylint: disable=W0212
        #         Access to a protected member _ttyrec_folder of a client class
        folder = os.path.dirname(ttyfile) or session._ttyrec_folder
        pos = None
        while True:
            files = sorted([fn for fn in os.listdir(session._ttyrec_folder)
                            if fn.endswith('.ttyrec')])
            echo(u'\r\n' * term.height)
            sel = Lightbar(term.height - 1, term.width - 1, 0, 0)
            sel.colors['border'] = term.bold_green
            echo(sel.border() + sel.title('-  SElECt A RECORdiNG  -'))
            sel.update([(fname, fname) for fname in files])
            if pos is not None:
                sel.position = pos

            x_ttyfile = sel.read()
            if x_ttyfile is None or sel.quit:
                break
            pos = sel.position
            ttyfile = os.path.join(folder, x_ttyfile)
            playfile(ttyplay_exe, ttyfile, peek)
    else:
        playfile(ttyplay_exe, ttyfile, peek)

    if not session.is_recording and resume_rec:
        session._record_tty = True
        session.start_recording()

    echo(term.move(term.height, 0))
    echo(u'\r\n')
Ejemplo n.º 12
0
Archivo: weather.py Proyecto: hick/x84
def get_centigrade():
    """
    Blocking prompt for setting C/F preference
    """
    from x84.bbs import getterminal, getsession, echo, getch
    term = getterminal()
    session = getsession()
    echo(u'\r\n\r\n')
    echo(term.yellow(u'Celcius'))
    echo(term.bold_yellow(u'('))
    echo(term.bold_yellow_reverse(u'C'))
    echo(term.bold_yellow(u')'))
    echo(u' or ')
    echo(term.yellow(u'Fahrenheit'))
    echo(term.bold_yellow(u'('))
    echo(term.bold_yellow_reverse(u'F'))
    echo(term.bold_yellow(u')'))
    echo(u'? ')
    anonymous = bool(session.user.handle == 'anonymous')
    while True:
        inp = getch()
        if inp in (u'c', u'C'):
            session.user['centigrade'] = True
            if not anonymous:
                session.user.save()
            break
        elif inp in (u'f', u'F'):
            session.user['centigrade'] = False
            if not anonymous:
                session.user.save()
            break
        elif inp in (u'q', u'Q', term.KEY_EXIT):
            break
Ejemplo n.º 13
0
def chk_save_location(location):
    """
    Prompt user to save location for quick re-use
    """
    from x84.bbs import getterminal, getsession, echo, getch
    session, term = getsession(), getterminal()
    stored_location = session.user.get('location', dict()).items()
    if (sorted(location.items()) == sorted(stored_location)):
        # location already saved
        return
    if session.user.handle == 'anonymous':
        # anonymous cannot save preferences
        return

    # prompt to store (unsaved/changed) location
    echo(u'\r\n\r\n')
    echo(term.yellow(u'Save Location'))
    echo(term.bold_yellow(u' ('))
    echo(term.bold_black(u'private'))
    echo(term.bold_yellow(u') '))
    echo(term.yellow(u'? '))
    echo(term.bold_yellow(u'['))
    echo(term.underline_yellow(u'yn'))
    echo(term.bold_yellow(u']'))
    echo(u': ')
    while True:
        inp = getch()
        if inp is None or inp in (u'n', u'N', u'q', u'Q', term.KEY_EXIT):
            break
        if inp in (u'y', u'Y', u' ', term.KEY_ENTER):
            session.user['location'] = location
            break
Ejemplo n.º 14
0
def disp_forecast(forecast):
    """ Display weather forecast.  """
    from x84.bbs import getterminal, echo, Ansi, getch
    term = getterminal()
    lno = 1
    echo(u'\r\n')
    for key in sorted(forecast.keys()):
        fcast = forecast[key]
        rstr = u''.join((
            term.bold_yellow_underline(fcast['DayCode']),
            u', ',
            u'/'.join(fcast['ObsDate'].split('/', 3)[0:2]),
            term.bold_underline(u':'), u' ',
            u'%s. ' % (
                term.bold(
                    fcast.get('TXT_Long', fcast.get('TXT_Short', u''))),),
            u'hiGH Of %sF, lOW Of %sF. ' % (
                term.bold(fcast.get('High_Temperature')),
                term.bold(fcast.get('Low_Temperature')),),))
        if 0.0 != float(fcast.get('Snow_Amount', '0.0')):
            rstr += u'SNOW AMOUNt %s iN., ' % (
                    term.yellow(fcast.get('Snow_Amount')),)
        if 0.0 != float(fcast.get('Rain_Amount', '0.0')):
            rstr += u'RAiN AMOUNt %s iN., ' % (
                    term.yellow(fcast.get('Snow_Amount')),)
        if 0.0 != float(fcast.get('Precip_Amount', '0.0')):
            rstr += u'PRECiPiTAtiON %s iN., ' % (
                    term.yellow(fcast.get('Precip_Amount')),)
        if 0 != int(fcast.get('TStorm_Prob', '0')):
            rstr += u'thUNdERStORM PRObAbilitY: %s, ' % (
                    term.yellow(fcast.get('TStorm_Prob')),)

        if 0 != len(fcast.get('WindDirection', u'')):
            rstr += u'WiNdS %s ' % (
                    term.yellow(fcast.get('WindDirection')),)
        if 0 != len(fcast.get('WindSpeed', u'')):
            rstr += u'At %sMPh, ' % (
                    term.yellow(fcast.get('WindSpeed')),)
        if 0 != len(fcast.get('WindGust', u'')):
            rstr += u'GUStS Of %sMPh. ' % (
                    term.yellow(fcast.get('WindGust')),)
            if 0 != len(fcast.get('Real_Feel_High', u'')):
                rstr += u'PROdUCiNG '
        if 0 != len(fcast.get('Real_Feel_High', u'')):
            rstr += u'A WiNdCHill HiGh Of %sF, lOW %sF. ' % (
                    term.yellow(
                        fcast.get('Real_Feel_High')),
                    term.yellow(
                        fcast.get('Real_Feel_Low', u'?')),)
        echo(u'\r\n')
        lno += 1
        lines = Ansi(rstr).wrap(min(60, int(term.width * .8))).splitlines()
        for line in lines:
            lno += 1
            echo(line + u'\r\n')
            if 0 == lno % (term.height - 1):
                echo(term.yellow_reverse('--MORE--'))
                if getch() is None:
                    return False
                echo(u'\r\n')
Ejemplo n.º 15
0
def get_centigrade():
    """
    Blocking prompt for setting C/F preference
    """
    from x84.bbs import getterminal, getsession, echo, getch
    term = getterminal()
    session = getsession()
    echo(u'\r\n\r\n')
    echo(term.yellow(u'CElCiUS'))
    echo(term.bold_yellow(u'('))
    echo(term.bold_yellow_reverse(u'C'))
    echo(term.bold_yellow(u')'))
    echo(u' or ')
    echo(term.yellow(u'fAhRENhEit'))
    echo(term.bold_yellow(u'('))
    echo(term.bold_yellow_reverse(u'F'))
    echo(term.bold_yellow(u')'))
    echo('? ')
    while True:
        inp = getch()
        if inp in (u'c', u'C'):
            session.user['centigrade'] = True
            session.user.save()
            break
        elif inp in (u'f', u'F'):
            session.user['centigrade'] = False
            session.user.save()
            break
        elif inp in (u'q', u'Q', term.KEY_EXIT):
            break
Ejemplo n.º 16
0
def displayfile(filename):
    term = getterminal()
    echo(term.clear + term.move(0, 0) + term.normal)

    text = {}
    counter = 0
    offset = 0
    keypressed = ''

    # the string array named text will be zerobased
    for line in showart(filename):
        text[counter] = line
        counter = counter + 1

    while True:
        echo(term.move(0, 0) + term.normal)
        # -2 om man vill spara en rad i botten
        for i in range(0, term.height - 1):
            if len(text) > i + offset:
                echo(term.clear_eol + u'\r' + text[i + offset])

        keypressed = getch()
        echo(term.hide_cursor)
        if keypressed == 'q' or keypressed == 'Q' or keypressed == term.KEY_ESCAPE or keypressed == term.KEY_ENTER:
            break

        if keypressed == term.KEY_HOME:
            offset = 0

        if keypressed == term.KEY_END:
            # if the textline has fewer lines than the screen..
            if len(text) < term.height:
                offset = 0
            else:
                offset = len(text) - term.height + 1

        if keypressed == term.KEY_DOWN:
            # offset < len(text) + term.height:
            if len(text) > offset + term.height - 1:
                offset = offset + 1

        if keypressed == term.KEY_UP:
            if offset > 0:
                offset = offset - 1

        if keypressed == term.KEY_LEFT or keypressed == term.KEY_PGUP:
            if offset > term.height:
                offset = offset - term.height + 2
            else:
                offset = 0

        if keypressed == term.KEY_RIGHT or keypressed == term.KEY_PGDOWN:
            if (offset + term.height * 2) - 1 < len(text):
                offset = offset + term.height - 2
            else:
                # if the textline has fewer lines than the screen..
                if len(text) < term.height:
                    offset = 0
                else:
                    offset = len(text) - term.height + 1
Ejemplo n.º 17
0
def chk_save_location(location):
    """
    Prompt user to save location for quick re-use
    """
    from x84.bbs import getterminal, getsession, echo, getch
    session, term = getsession(), getterminal()
    stored_location = session.user.get('location', dict()).items()
    if (sorted(location.items()) == sorted(stored_location)):
        return

    # prompt to store (unsaved/changed) location
    echo(u'\r\n\r\n')
    echo(term.yellow(u'SAVE lOCAtION'))
    echo(term.bold_yellow(' ('))
    echo(term.bold_black(u'PRiVAtE'))
    echo(term.bold_yellow(') '))
    echo(term.yellow('? '))
    echo(term.bold_yellow(u'['))
    echo(term.underline_yellow(u'yn'))
    echo(term.bold_yellow(u']'))
    echo(u': ')
    while True:
        inp = getch()
        if inp is None or inp in (u'n', u'N', u'q', u'Q', term.KEY_EXIT):
            break
        if inp in (u'y', u'Y', u' ', term.KEY_ENTER):
            session.user['location'] = location
            break
Ejemplo n.º 18
0
def add_comment(key):
    """ Prompt user to add a comment about a bbs. """
    # pylint: disable=R0914
    #        Too many local variables.
    from x84.bbs import getsession, getterminal, echo, DBProxy, LineEditor
    from x84.bbs import getch
    session, term = getsession(), getterminal()
    prompt_comment = u'\r\n\r\nWhAt YOU GOt tO SAY? '
    prompt_chg = u'\r\n\r\nChANGE EXiStiNG ? [yn] '
    echo(term.move(term.height, 0))
    echo(prompt_comment)
    comment = LineEditor(max(10, term.width - len(prompt_comment) - 5)).read()
    if comment is None or 0 == len(comment.strip()):
        return
    new_entry = (session.handle, comment)
    comments = DBProxy('bbslist', 'comments')
    comments.acquire()
    existing = comments[key]
    if session.handle in (_nick for (_nick, _cmt) in comments[key]):
        # change existing comment,
        echo(prompt_chg)
        if getch() not in (u'y', u'Y'):
            comments.release()
            return
        # re-define list without existing entry, + new entry
        comments[key] = [(_enick, _ecmt) for (_enick, _ecmt) in existing
                         if session.handle != _enick] + [new_entry]
        comments.release()
        return
    # re-define as existing list + new entry
    comments[key] = existing + [new_entry]
    comments.release()
Ejemplo n.º 19
0
def prompt_ok():
    """
    Prompt user to continue, True if they select yes.
    """
    from x84.bbs import getsession, getterminal, echo, getch, Selector
    session, term = getsession(), getterminal()
    prompt_confirm = u'EVERYthiNG lOOk Ok ?'
    prompt_continue = u'YES (CONtiNUE)'
    prompt_chg = u'NO! (ChANGE)'

    def prompt_ok_dumb():
        """ Dummy terminal prompt for confirm/cancel. """
        echo('\r\n\r\n%s\r\n' % (prompt_confirm,))
        echo('1 - %s\r\n' % (prompt_continue,))
        echo('2 - %s\r\n\r\n' % (prompt_chg,))
        echo('select (1, 2) --> ')
        while True:
            inp = getch()
            if inp == u'1':
                return True
            elif inp == u'2':
                return False
    if session.env.get('TERM') == 'unknown':
        return prompt_ok_dumb()
    sel = Selector(yloc=term.height - 1, xloc=5,
                   width=term.width - 10,
                   left=prompt_continue, right=prompt_chg)
    echo(term.normal)
    echo(term.move(term.height - 2, 0) + term.clear_eol)
    echo(prompt_confirm.center(term.width - 1) + '\r\n')
    echo(term.clear_eol + sel.refresh())
    while True:
        echo(sel.process_keystroke(getch()))
        if sel.selected:
            return True if sel.selection == prompt_continue else False
Ejemplo n.º 20
0
def yes_no(lightbar, msg, prompt_msg='are you sure? ', attr=None):
    """ Prompt user for yes/no, returns True for yes, False for no. """
    term = getterminal()
    keyset = {
        'yes': (u'y', u'Y'),
        'no': (u'n', u'N'),
    }
    echo(u''.join((
        lightbar.border(),
        lightbar.pos(lightbar.yloc + lightbar.height - 1, lightbar.xpadding),
        msg, u' ', prompt_msg,)))
    sel = Selector(yloc=lightbar.yloc + lightbar.height - 1,
                   xloc=term.width - 25, width=18,
                   left='Yes', right=' No ')
    sel.colors['selected'] = term.reverse_red if attr is None else attr
    sel.keyset['left'].extend(keyset['yes'])
    sel.keyset['right'].extend(keyset['no'])
    echo(sel.refresh())
    while True:
        inp = getch()
        echo(sel.process_keystroke(inp))
        if((sel.selected and sel.selection == sel.left)
                or inp in keyset['yes']):
            # selected 'yes',
            return True
        elif((sel.selected or sel.quit)
                or inp in keyset['no']):
            # selected 'no'
            return False
Ejemplo n.º 21
0
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'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'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
Ejemplo n.º 22
0
Archivo: pager.py Proyecto: hick/x84
 def read(self):
     """
     Reads input until ESCAPE key is pressed (Blocking).  Returns None.
     """
     from x84.bbs import getch
     from x84.bbs.output import echo
     self._quit = False
     echo(self.refresh())
     while not self.quit:
         echo(self.process_keystroke(getch()))
Ejemplo n.º 23
0
def main(file=None, invert=False, Showart=True):
    """ Main procedure. """
    if file != None:
        displayfile(file)
        return
    session = getsession()
    term = getterminal()
    session.activity = 'Reading text files'
    currentfolder = []
    stored_lbar_pos = []
    filelist = getfilelist(STARTFOLDER)
    dirty = True
    inp = None
    lbar = Lightbar(height = 0, width = 0, xloc = 0, yloc = 0, colors={'highlight': term.bold_white_on_red})
    # sets up a lightbar. update_lightbar will give it it's actual values.

    echo(term.clear+banner()+term.hide_cursor)
    while 1:
        if dirty:
            update_lightbar(lbar,term,filelist)
            dirty = False
        while not inp:
            inp = getch(0.2)
            if session.poll_event('refresh'):
                echo(term.clear)
                if term.width > 79: echo(banner())
                update_lightbar(lbar,term,filelist)
                dirty = True
        lbar.process_keystroke(inp)
        if lbar.quit: 
            echo(term.normal_cursor)
            return
        echo(lbar.refresh_quick())
        if inp == term.KEY_ENTER:
            if lbar.selection[1] == '( .. ) GO BACK' or os.path.isdir(STARTFOLDER+u''.join(currentfolder)+lbar.selection[0]):
                if lbar.selection[1] == '( .. ) GO BACK':
                    del currentfolder[-1]
                    filelist = getfilelist(STARTFOLDER+u''.join(currentfolder))
                    lbar.update(filelist)
                    lbar.goto(stored_lbar_pos[-1])
                    del stored_lbar_pos[-1]
                else:
                    currentfolder.append(lbar.selection[0]+u'/')
                    stored_lbar_pos.append(lbar.index)
                    filelist = getfilelist(STARTFOLDER+u''.join(currentfolder))                        
                    lbar.goto(0)
                if len(currentfolder) > 0:
                    filelist.insert(0,['( .. ) GO BACK','( .. ) GO BACK'])
                lbar.update(filelist)
            else:
                displayfile(STARTFOLDER+u''.join(currentfolder)+lbar.selection[0])
                echo(term.clear+banner())
            dirty = True
        inp = None
Ejemplo n.º 24
0
 def read(self):
     """ Reads input until the ENTER or ESCAPE key is pressed (Blocking). """
     from x84.bbs import getch
     from x84.bbs.output import echo
     self._selected = False
     self._quit = False
     echo(self.refresh())
     while not (self.selected or self.quit):
         echo(self.process_keystroke(getch()) or u'')
     if self.quit:
         return None
     return self.selection
Ejemplo n.º 25
0
 def prompt_ok_dumb():
     """ Dummy terminal prompt for confirm/cancel. """
     echo('\r\n\r\n%s\r\n' % (prompt_confirm,))
     echo('1 - %s\r\n' % (prompt_continue,))
     echo('2 - %s\r\n\r\n' % (prompt_chg,))
     echo('select (1, 2) --> ')
     while True:
         inp = getch()
         if inp == u'1':
             return True
         elif inp == u'2':
             return False
Ejemplo n.º 26
0
def chose_location_dummy(locations):
    """
    dummy pager for chosing a location
    """
    from x84.bbs import getterminal, echo, getch, LineEditor
    term = getterminal()
    msg_enteridx = (
        term.bold_yellow(u'('),
        term.underline_yellow(u'0'),
        term.yellow(u'-'),
        term.underline_yellow(u'%d' % (len(locations) - 1,)),
        term.yellow(u','),
        term.underline_yellow('Escape'),
        term.bold_white(u':'),
        term.yellow('EXit'),
        term.bold_yellow(u')'), u' ',
        term.reverse_yellow(':'),)
    max_nwidth = len('%d' % (len(locations) - 1,))

    def disp_entry(num, loc):
        """ Display City, State.  """
        return u''.join((
            term.bold_yellow(u'['),
            u'%*d' % (max_nwidth, num),
            term.bold_yellow(u']'), u' ',
            term.yellow(loc['city']), u', ',
            term.yellow(loc['state']), u'\r\n',))
    echo(u'\r\n\r\n')
    lno = 3
    for num, loc in enumerate(locations):
        echo(disp_entry(num, loc))
        lno += 1
        if lno != 0 and (0 == lno % (term.height)):
            echo(term.yellow_reverse('--MORE--'))
            if getch() is None:
                break
            echo(u'\r\n')
            lno += 1
    idx = u''
    while True:
        echo(u'\r\n' + u''.join(msg_enteridx))
        idx = LineEditor(width=max_nwidth, content=idx).read()
        if idx is None or len(idx) == 0:
            return None
        try:
            int_idx = int(idx)
        except ValueError as err:
            echo(term.bold_red(u'\r\n%s' % (err,)))
            continue
        if int_idx < 0 or int_idx > len(locations) - 1:
            echo(term.bold_red(u'\r\nValue out of range'))
            continue
        return locations[int_idx]
Ejemplo n.º 27
0
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
Ejemplo n.º 28
0
def warning(msg, cpsec=10.0, min_sec=3.0, split_loc=3):
    """
    Display a 2-tone warning to user with a dynamic pause
    """
    from x84.bbs import getterminal, echo, getch
    term = getterminal()
    echo(u''.join((term.clear_eol, term.normal, u'\r\n\r\n',
                   term.bold_red, msg[:-
                                      split_loc], term.normal, msg[
                                          -split_loc:],
                   term.bold_black, u'!')))
    inp = getch(max(min_sec, float(len(msg)) / cpsec))
    return inp
Ejemplo n.º 29
0
Archivo: debug.py Proyecto: rostob/x84
def merge_mystic():
    """ Example script to merge csv records into userbase. """
    # pylint: disable=R0914
    #         Too many local variables
    from x84.bbs import ini, echo, getch, User, get_user, find_user
    import os
    # you must modify variable ``do_write`` to commit changes,
    # csv format; 'user:pass:origin:email\n', in iso8859-1 encoding.
    do_write = False
    inp_file = os.path.join(
        ini.CFG.get('system', 'datapath'),
        'mystic_dat.csv')
    lno = 0
    for lno, line in enumerate(open(inp_file, 'r')):
        handle = line.split(':', 1)[0].strip().decode('iso8859-1')
        attrs = line.rstrip().split(':')[2:]
        (_password, _location, _email) = attrs
        (_password, _location, _email) = (
            _password.strip().decode('iso8859-1'),
            _location.strip().decode('iso8859-1'),
            _email.strip().decode('iso8859-1'))
        echo(u''.join((u'\r\n',
                       handle, u': ',
                       '%d ' % (len(_password)),
                       '%s ' % (_location),
                       '%s ' % (_email),)))
        match = find_user(handle)
        if match is None:
            user = User(handle)
            user.location = _location
            user.email = _email
            user.password = _password
        else:
            user = get_user(match)
        user.groups.add('old-school')
        if do_write:
            user.save()
    echo(u'\r\n\r\n%d lines processed.' % (lno,))
    getch()
Ejemplo n.º 30
0
Archivo: vote.py Proyecto: hick/x84
def ynprompt():
    term = getterminal()
    echo (term.magenta+' (' + term.cyan + 'yes'+term.magenta+'/'+term.cyan+'no' + term.magenta+')'+ term.white)
    while 1:
        svar = getch()
        if (svar == 'y') or (svar == 'Y'):
            yn = True
            echo (u' yes!')
            break
        if (svar == 'n') or (svar == 'N') or (svar == 'q') or (svar == 'Q'):
            yn = False
            echo (u' no')
            break
    return(yn)
Ejemplo n.º 31
0
def read_messages(msgs, title, currentpage, totalpages):
    """
    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 "YOSPOS"

    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',
            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))) 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_to = msgs[idx][1]
            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 = 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
Ejemplo n.º 32
0
def play():
    import time
    from random import randint
    import os
    from x84.bbs import getterminal, getch, from_cp437, AnsiWindow
    from x84.bbs import echo as echo_unbuffered
    term = getterminal()
    field = []
    global charcache
    charcache = u''
    field_width = 10
    field_height = 20
    # Access scheme looks like this:
    #   layout[p][r][ypox][xpos]
    # layoutcolor = [ 7,2,3,4,4,6,7 ]
    layout = [
        #  ##
        #  ##
        [
            [
                [
                    1,
                    1,
                ],
                [
                    1,
                    1,
                ],
            ],
        ],
        #  #
        #  #
        #  #
        #  #
        [[
            [0, 1, 0, 0],
            [0, 1, 0, 0],
            [0, 1, 0, 0],
            [0, 1, 0, 0],
        ], [
            [0, 0, 0, 0],
            [1, 1, 1, 1],
            [0, 0, 0, 0],
            [0, 0, 0, 0],
        ]],
        #  ###
        #   #
        [
            [
                [0, 0, 0],
                [1, 1, 1],
                [0, 1, 0],
            ],
            [
                [0, 1, 0],
                [0, 1, 1],
                [0, 1, 0],
            ],
            [
                [0, 1, 0],
                [1, 1, 1],
                [0, 0, 0],
            ],
            [
                [0, 1, 0],
                [1, 1, 0],
                [0, 1, 0],
            ],
        ],
        #  #
        #  #
        #  ##
        [
            [
                [0, 1, 0],
                [0, 1, 0],
                [0, 1, 1],
            ],
            [
                [0, 0, 1],
                [1, 1, 1],
                [0, 0, 0],
            ],
            [
                [1, 1, 0],
                [0, 1, 0],
                [0, 1, 0],
            ],
            [
                [0, 0, 0],
                [1, 1, 1],
                [1, 0, 0],
            ],
        ],
        #   #
        #   #
        #  ##
        [
            [
                [0, 1, 0],
                [0, 1, 0],
                [1, 1, 0],
            ],
            [
                [0, 0, 0],
                [1, 1, 1],
                [0, 0, 1],
            ],
            [
                [0, 1, 1],
                [0, 1, 0],
                [0, 1, 0],
            ],
            [
                [1, 0, 0],
                [1, 1, 1],
                [0, 0, 0],
            ],
        ],
        #  ##
        #   ##
        [
            [
                [0, 1, 0],
                [1, 1, 0],
                [1, 0, 0],
            ],
            [
                [0, 0, 0],
                [1, 1, 0],
                [0, 1, 1],
            ],
        ],
        #   ##
        #  ##
        [
            [
                [0, 1, 0],
                [0, 1, 1],
                [0, 0, 1],
            ],
            [
                [0, 0, 0],
                [0, 1, 1],
                [1, 1, 0],
            ],
        ],
    ]

    fieldx1 = 32
    fieldy1 = 10
    scorex1 = 11
    scorey1 = 11

    class RectRedraw:
        x1 = None
        y1 = None
        x2 = None
        y2 = None

        def max(r, val, valmax):
            if val > valmax:
                return valmax
            return val

        def min(r, val, valmin):
            if val < valmin:
                return valmin
            return val

        def merge(r, x1, y1, x2, y2):
            if r.x1 == None or r.x1 > x1:
                r.x1 = r.min(x1, 0)
            if r.y1 == None or r.y1 > y1:
                r.y1 = r.min(y1, 0)
            if r.x2 == None or r.x2 < x2:
                r.x2 = r.max(x2, field_width)
            if r.y2 == None or r.y2 < y2:
                r.y2 = r.max(y2, field_height)
            # print r.x1,r.y1,r.x2,r.y2

        def clean(r):
            r.x1 = None
            r.y1 = None
            r.x2 = None
            r.y2 = None

    rr = RectRedraw()
    for i in range(field_height):
        field.append([0] * field_width)

    def echo(s):
        global charcache
        charcache += s

    assert term.height > (field_height + 1)
    echo_unbuffered(u''.join((
        u'\r\n\r\n',
        u'REAdY YOUR tERMiNAl %s ' % (term.bold_blue('(!)'), ),
        u'\r\n\r\n',
        u'%s PRESS ANY kEY' % (term.bold_black('...'), ),
    )))
    getch()
    artfile = os.path.join(os.path.dirname(__file__), 'tetris.ans')
    echo_unbuffered(u'\r\n' * term.height)  # cls
    if os.path.exists(artfile):
        echo_unbuffered(from_cp437(open(artfile).read()).rstrip())

    def gotoxy(x, y):
        echo(term.move(y, x))

    def plotblock(color, lastcolor):
        if color:
            c = u'\u2588\u2588'  # '\xDB\xDB'
        else:  # both empty
            c = '  '
            color = 0
        # Output optimization
        if color % 8 == 0:
            color = color / 8
        if color == lastcolor:
            echo(c)
        else:
            if color:
                fg = str(30 + color % 8)
            else:
                fg = '37'
            if color >= 8:
                bg = ';%d' % (40 + color / 8)
            else:
                bg = ''
            echo('\33[0;' + fg + bg + 'm')
            echo(c)
            lastcolor = color
        return lastcolor

    def redrawfieldbig(rr):
        # rr.merge(0,0,field_width,field_height)
        lastcolor = ''
        if rr.x1 == None or rr.y1 == None:
            return
        # Only draw the parts which have been marked by the
        # redraw rectangle
        for y in range(rr.y1, rr.y2):
            gotoxy(field_width + rr.x1 * 2, 2 + y)
            for x in range(rr.x1, rr.x2):
                lastcolor = plotblock(field[y][x], lastcolor)
        echo(term.normal)
        rr.clean()

    def drawfieldbig():
        lastcolor = ''
        for y in range(0, field_height):
            gotoxy(field_width, 2 + y)
            for x in range(field_width):
                lastcolor = plotblock(field[y][x], lastcolor)
        echo(term.normal)

    def drawfield():
        lastcolor = ''
        for y in range(0, field_height, 2):
            # gotoxy(field_width,2+y/2)
            gotoxy(fieldx1 + 2, fieldy1 + 1 + y / 2)
            # Which block to show, full, half-up, half-down or empty.
            for x in range(field_width):
                color = field[y][x] + field[y + 1][x] * 8
                if field[y][x] and field[y + 1][x]:
                    c = u'\u2588'  # '\xDB'
                    if field[y][x] == field[y + 1][x]:
                        color = color % 8
                    else:
                        c = u'\u2580'  # '\xDF'
                elif field[y][x] and not field[y + 1][x]:
                    c = u'\u2580'  # '\xDF'
                elif not field[y][x] and field[y + 1][x]:
                    c = u'\u2584'  # '\xDC'
                else:  # both empty
                    c = ' '
                # Output optimization
                if color % 8 == 0:
                    color = color / 8
                if color == lastcolor:
                    echo(c)
                else:
                    if color:
                        fg = str(30 + color % 8)
                    else:
                        fg = '37'
                    if color >= 8:
                        bg = ';%d' % (40 + color / 8)
                    else:
                        bg = ''
                    echo('\33[0;' + fg + bg + 'm')
                    echo(c)
                    lastcolor = color
        echo(term.normal)

    layoutcolor = [7, 2, 7, 6, 3, 6, 3]
    # p    = -1  # Current piece type
    nextpiece = randint(0, len(layout) - 1)
    p = randint(0, len(layout) - 1)
    p = 1
    r = 0  # Current rotation
    xpos = 4  # X position
    # ypos = -2  # Y position
    ypos = -len(layout[p][0])
    level = 1
    score = 0
    lines = 0

    def flush():
        global charcache
        echo_unbuffered(charcache)
        charcache = u''

    def fillpiece(x, y, p, r, value):
        row = 0
        for line in layout[p][r]:
            col = 0
            for c in line:
                if c and (y + row) >= 0:
                    field[y + row][x + col] = value
                col += 1
            row += 1

    def showpiece(x, y, p, r):
        fillpiece(x, y, p, r, layoutcolor[p])

    def hidepiece():
        fillpiece(xpos, ypos, p, r, 0)

    def testpiece(x, y, newr):
        hidepiece()
        # Space at the new location?
        row = 0
        for line in layout[p][newr]:
            col = 0
            for c in line:
                try:
                    if c:
                        if ((y + row) >= 0 and field[y + row][x + col]
                                or (x + col) < 0 or (x + col) > 9):
                            return 0
                except IndexError:
                    return 0
                col += 1
            row += 1
        # Movement possible
        return 1

    def movepiece(x, y, newr):
        if testpiece(x, y, newr):
            # Build redraw rectangle
            rr.merge(xpos, ypos, xpos + len(layout[p][0][0]),
                     ypos + len(layout[p][0]))
            rr.merge(x, y, x + len(layout[p][0][0]), y + len(layout[p][0]))
            showpiece(x, y, p, newr)
            return (x, y, newr, 1)
        else:
            showpiece(xpos, ypos, p, r)
            return (xpos, ypos, r, 0)

    def shownext(p):
        r = 0
        lastcolor = ''
        for y in range(6):
            gotoxy(38, 1 + y)
            for x in range(6):
                if y == 0 or y == 5 or x == 0 or x == 5:
                    echo('\xB0\xB0')
                else:
                    echo('\33[0m  ')
                    lastcolor = ''
        for y in range(len(layout[p][r])):
            gotoxy(40, 2 + y)
            for x in range(len(layout[p][r][0])):
                # plotblock(layoutcolor[layout[p][r][y][x]],lastcolor)
                plotblock(layout[p][r][y][x], lastcolor)

    def drawstats():
        echo(term.move(scorey1, scorex1) + '%d' % level)
        echo(term.move(scorey1 + 2, scorex1) + '%d' % lines)
        echo(term.move(scorey1 + 3, scorex1) + '%d' % score)

    drawstats()
    ticksize = 0.4
    nexttick = time.time() + ticksize
    showpiece(xpos, ypos, p, r)
    # shownext(nextpiece)

    # Full redraw first frame
    rr.merge(0, 0, field_width, field_height)

    buf = ''
    while 1:
        drawfield()
        # gotoxy(0,0)
        # echo('\33[37mx: %d, y: %d, p: %d         '%(xpos,ypos,p))
        slice = nexttick - time.time()
        if slice < 0:
            slice = 0
        echo(buf)
        buf = ''
        flush()
        key = getch(slice + 0.01)
        now = time.time()
        # hidepiece()
        if key is not None:
            if key in (u'q', u'Q'):
                return (0, 0, 0)
            elif key in (
                    term.KEY_LEFT,
                    u'h',
            ):
                xpos, ypos, r, m = movepiece(xpos - 1, ypos, r)
            elif key in (
                    term.KEY_RIGHT,
                    u'l',
            ):
                xpos, ypos, r, m = movepiece(xpos + 1, ypos, r)
            elif key in (
                    term.KEY_UP,
                    u'k',
            ):
                xpos, ypos, r, m = movepiece(xpos, ypos,
                                             (r + 1) % len(layout[p]))
            elif key in (
                    term.KEY_DOWN,
                    u'j',
            ):
                xpos, ypos, r, m = movepiece(xpos, ypos + 1, r)
            elif key in (' ', ):
                m = True
                c = 0
                while m:
                    xpos, ypos, r, m = movepiece(xpos, ypos + 1, r)
                    if m:
                        c += 1
                if c:
                    nexttick = time.time() + ticksize
        # New tick?
        if now > nexttick:
            nexttick += ticksize
            # Move down piece
            xpos, ypos, r, moved = movepiece(xpos, ypos + 1, r)
            # Piece has touched down?
            if not moved:
                # Is the player dead?
                if ypos <= -len(layout[p][0]):
                    death_win = AnsiWindow(height=6,
                                           width=40,
                                           yloc=fieldy1 + 10 / 2,
                                           xloc=fieldx1 - 11)
                    death_win.colors['border'] = term.bold_black
                    echo_unbuffered(death_win.clear() + death_win.border())
                    echo_unbuffered(
                        term.move(fieldy1 + 10 / 2 + 1, fieldx1 - 11))
                    echo_unbuffered((u'!! gAME OVeR!! Score was: %i' %
                                     (score, )).center(40))
                    echo_unbuffered(
                        term.move(fieldy1 + 10 / 2 + 3, fieldx1 - 11))
                    echo_unbuffered(u'press RETURN'.center(40))
                    while True:
                        inp = getch()
                        if inp in (u'\r', term.KEY_ENTER):
                            break
                    return (score, level, lines)

                # Any complete rows to remove?
                complete = []
                for y in range(field_height):
                    x = 0
                    while x < field_width:
                        if field[y][x] == 0:
                            break
                        x += 1
                    if x == field_width:
                        complete.append(y)
                if len(complete) > 0:
                    # Add score
                    lines += len(complete)
                    score += len(complete) * len(complete) * 100
                    # Shrink field
                    for line in complete:
                        del field[line]
                        field.insert(0, [0] * field_width)

                    if lines >= level * 10:
                        level += 1
                        ticksize = 0.4 - level * 0.02
                    drawstats()

                    # Redraw complete field
                    rr.merge(0, 0, field_width, field_height)

                # Time for a new piece
                p = nextpiece
                nextpiece = randint(0, len(layout) - 1)
                r = 0
                xpos = 4
                ypos = -len(layout[p][0])
                showpiece(xpos, ypos, p, r)
Ejemplo n.º 33
0
def show_scores(my_score):
    from x84.bbs import DBProxy, Pager, getterminal
    from x84.bbs import getch, echo, getsession, ini
    session, term = getsession(), getterminal()
    allscores = DBProxy('tetris').items()
    if 0 == len(allscores):
        return
    # line up over tetris game, but logo & 'made by jojo' in view
    # -- since we have so much screen width, columize the scores,
    # the math brings it out to 2 columns, but fmt is adjustable
    pager_title = term.blue_reverse_underline('- hiGh SCOREs -')
    len_handle = ini.CFG.getint('nua', 'max_user')
    score_fmt = u'%s %s %s %s'
    len_pos = 2
    len_score = 10
    len_level = 3
    height, width = 11, 73
    yloc, xloc = 10, 3
    pager = Pager(height=height, width=width, yloc=yloc, xloc=xloc)
    pager.xpadding = 1
    pager.glyphs['left-vert'] = u''
    pager.glyphs['right-vert'] = u''
    pager.colors['border'] = term.blue_reverse
    pager.alignment = 'center'
    # pre-fesh pager border before fetch
    echo(pager.border() + pager.title(pager_title))
    highscores = sorted([(_score, _level, _handle.decode('utf8'))
                         for (_handle, (_score, _level, _lines)) in allscores],
                        reverse=True)
    pager.append(score_fmt %
                 (term.bold_blue_underline('No'.ljust(len_pos)),
                  term.bold_blue_underline('SCORE'.ljust(len_score)),
                  term.bold_blue_underline('lVl'.ljust(len_level)),
                  term.bold_blue_underline('hANdlE'.rjust(len_handle), )))
    for pos, (_score, _level, _handle) in enumerate(highscores):
        if _handle == session.user.handle:
            pager.append(score_fmt % (
                term.blue_reverse(str(pos + 1).ljust(len_pos)),
                term.blue_reverse(str(_score).ljust(len_score)),
                term.blue_reverse(str(_level).ljust(len_level)),
                term.blue_reverse(_handle.rjust(len_handle)),
            ))
        else:
            pager.append(score_fmt % (
                term.bold_blue(str(pos + 1).ljust(len_pos)),
                term.blue(str(_score).ljust(len_score)),
                term.blue(str(_level).ljust(len_level)),
                _handle.rjust(len_handle),
            ))
    # append additional empty slot rows
    while len(pager.content) < pager.visible_height:
        pos += 1
        pager.append(score_fmt % (
            term.bold_blue(str(pos + 1).ljust(len_pos)),
            term.bold_black(u'.'.ljust(len_score)),
            term.bold_black(u'.'.ljust(len_level)),
            term.bold_black(u'.'.rjust(len_handle)),
        ))

    dirty = 2  # 2=do not refresh border & title
    pager.move_home()
    while not pager.quit:
        # 1=full refresh
        dirty = 1 if session.poll_event('refresh') else dirty
        if dirty:
            echo(u''.join((
                term.normal,
                ((pager.border() +
                  pager.title(pager_title)) if dirty != 2 else u''),
                pager.refresh(),
                pager.footer(u''.join(
                    (term.underline_blue('q'), term.bold_blue('uit')))),
            )))
            dirty = 0
        echo(pager.process_keystroke(getch(1)))
Ejemplo n.º 34
0
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

    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,
    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
Ejemplo n.º 35
0
def main(host, port=None, encoding='cp437'):
    """
    Call script with argument host and optional argument port to connect to a
    telnet server. ctrl-^ to disconnect.
    """
    # pylint: disable=R0914,R0912,R0915
    #         Too many local variables
    #         Too many branches
    #         Too many statements
    import telnetlib
    from functools import partial
    from x84.bbs import getsession, getterminal, echo, getch, from_cp437, telnet
    import logging
    log = logging.getLogger()

    assert encoding in ('utf8', 'cp437')
    session, term = getsession(), getterminal()
    session.activity = 'connecting to %s' % (host,)
    port = int(port) if port is not None else 23
    telnet_client = telnetlib.Telnet()
    telnet_client.set_option_negotiation_callback(partial(
        telnet.callback_cmdopt, env_term=session.env['TERM'], height=term.height, width=term.width))
    echo(u"\r\n\r\nEscape character is 'ctrl-^.'")
    if not session.user.get('expert', False):
        getch(3)
    echo(u'\r\nTrying %s:%s... ' % (host, port,))
    # pylint: disable=W0703
    #         Catching too general exception Exception
    try:
        telnet_client.open(host, port)
    except Exception as err:
        echo(term.bold_red('\r\n%s\r\n' % (err,)))
        echo(u'\r\n press any key ..')
        getch()
        return

    echo(u'\r\n... ')
    inp = session.read_event('input', timeout=0)
    echo(u'\r\nConnected to %s.' % (host,))
    session.activity = 'connected to %s' % (host,)
    carriage_returned = False
    with term.fullscreen():
        while True:
            if encoding == 'cp437':
                try:
                    unistring = from_cp437(
                        telnet_client.read_very_eager().decode('iso8859-1'))
                except EOFError:
                    break
            else:
                unistring = telnet_client.read_very_eager().decode('utf8')
            if 0 != len(unistring):
                echo(unistring)
            if inp is not None:
                if inp == chr(30):  # ctrl-^
                    telnet_client.close()
                    echo(u'\r\n' + term.clear_el + term.normal)
                    break
                elif not carriage_returned and inp in (b'\x0d', b'\x0a'):
                    telnet_client.write(b'\x0d')
                    log.debug('send {!r}'.format(b'\x0d'))
                    carriage_returned = True
                elif carriage_returned and inp in (b'\x0a', b'\x00'):
                    carriage_returned = False
                elif inp is not None:
                    telnet_client.write(inp)
                    log.debug('send {!r}'.format(inp))
                    carriage_returned = False
            inp = session.read_event('input', timeout=KEY_POLL)
    echo(u'\r\nConnection closed.\r\n')
    echo(u''.join(('\r\n\r\n', term.clear_el, term.normal, 'press any key')))
    echo(u'\x1b[r')  # unset 'set scrolling region', sometimes set by BBS's
    session.flush_event('input')
    getch()
    return
Ejemplo n.º 36
0
def post_bbs_scene(oneliner, dumb=True):
    """
    Prompt for posting to bbs-scene.org oneliners API,
    returning thread if posting occured.
    """
    # pylint: disable=R0914
    #        Too many local variables
    import logging
    import xml.etree.ElementTree
    import requests
    from x84.bbs import echo, getch, getterminal, getsession, ini
    logger = logging.getLogger()
    session, term = getsession(), getterminal()
    prompt_api = u'MAkE AN ASS Of YOURSElf ON bbS-SCENE.ORG?!'
    heard_api = u'YOUR MESSAGE hAS bEEN brOAdCAStEd.'
    yloc = term.height - 3
    if dumb:
        # post to bbs-scene.org ?
        echo('\r\n\r\n' + term.bold_blue(prompt_api) + u' [yn]')
        inp = getch(1)
        while inp not in (u'y', u'Y', u'n', u'N'):
            inp = getch()
        if inp in (u'n', u'N'):
            #  no? then just post locally
            add_oneline(oneliner.strip())
            return None
    else:
        # fancy prompt, 'post to bbs-scene.org?'
        sel = get_selector()
        sel.colors['selected'] = term.red_reverse
        echo(term.move(sel.yloc - 1, sel.xloc) or ('\r\n\r\n'))
        echo(term.blue_reverse(prompt_api.center(sel.width)))
        echo(sel.refresh())
        while not sel.selected and not sel.quit:
            echo(sel.process_keystroke(getch()))
        session.buffer_event('refresh', 'dirty')
        if sel.quit or sel.selection == sel.right:
            echo(term.normal + term.move(yloc, 0) + term.clear_eol)
            echo(term.move(sel.yloc, 0) + term.clear_eol)
            return None

    # This is an AJAX effect.
    # Dispatch a thread to fetch updates, whose callback
    # will cause the database and pager to update.
    url = 'http://bbs-scene.org/api/onelinerz.xml'
    usernm = ini.CFG.get('bbs-scene', 'user')
    passwd = ini.CFG.get('bbs-scene', 'pass')
    data = {
        'bbsname': ini.CFG.get('system', 'bbsname'),
        'alias': session.user.handle,
        'oneliner': oneliner.strip(),
    }
    # post to bbs-scene.rog
    req = requests.post(url, auth=(usernm, passwd), data=data)
    if (req.status_code != 200 or (xml.etree.ElementTree.XML(
            req.content).find('success').text != 'true')):
        echo(u'\r\n\r\n%srequest failed,\r\n' % (term.clear_eol, ))
        echo(u'%r' % (req.content, ))
        echo(u'\r\n\r\n%s(code: %s).\r\n' % (
            term.clear_eol,
            req.status_code,
        ))
        echo(u'\r\n%sPress any key ..' % (term.clear_eol, ))
        logger.warn('bbs-scene.org api request failed')
        getch()
        return None
    logger.info('bbs-scene.org api (%d): %r/%r', req.status_code,
                session.user.handle, oneliner.strip())
    thread = FetchUpdates()
    thread.start()
    if not dumb:
        # clear line w/input bar,
        echo(term.normal + term.move(yloc, 0) + term.clear_eol)
        # clear line w/selector
        echo(term.move(sel.yloc, 0) + term.clear_eol)
    else:
        echo('\r\n\r\n' + heard_api)
        getch(2)
    return thread
Ejemplo n.º 37
0
def browse_dir(session, db_desc, term, lightbar, directory, sub=False):
    """ Browse a directory. """
    # build and sort directory listing
    reload_dir(session, directory, lightbar, sub)
    echo(lightbar.refresh())
    filename, _ = lightbar.selection
    browser.last_diz_len = 0
    diz = ''
    # force it to describe the very first file when browser loads
    inp = lightbar.keyset['home'][0]
    # prime our loop
    isdir = False
    filepath = ''

    while True:
        # read from lightbar
        while not inp:
            inp = getch(0.2)
            # respond to screen dimension change by redrawing
            if session.poll_event('refresh'):
                draw_interface(term, lightbar)
                describe_file(term, diz=diz, directory=directory,
                              filename=filename, isdir=isdir)

        idx = lightbar.vitem_idx
        shift = lightbar.vitem_shift

        # pass input to lightbar
        lightbar.process_keystroke(inp)
        filename, _ = lightbar.selection

        filepath = os.path.join(directory, filename)
        relativename = filepath[len(ROOT):]
        isdir = bool(filepath[-1:] == os.path.sep)
        _, ext = os.path.splitext(filename.lower())

        if inp in lightbar.keyset['home']:
            # lightbar 'home' keystroke bug; redraw current line
            echo(lightbar.refresh_row(idx))
            echo(lightbar.refresh_row(lightbar.vitem_idx))

        elif lightbar.quit:
            # 'exit' key pressed
            return False

        elif inp in (u' ',) and filename[-1:] != os.path.sep:
            # 'flag' key pressed; don't allow flagging directories
            if filepath in browser.flagged_files:
                # already flagged; un-flag
                browser.flagged_files.remove(filepath)
            else:
                browser.flagged_files.add(filepath)

            session.user['flaggedfiles'] = browser.flagged_files
            reload_dir(session, directory, lightbar, sub)

            if is_flagged_dir(directory):
                echo(lightbar.refresh())
            else:
                echo(lightbar.refresh_row(lightbar.vitem_idx))
                lightbar.move_down()

        elif inp in (u'-',):
            # 'unflag all' pressed
            session.user['flaggedfiles'] = browser.flagged_files = set()
            reload_dir(session, directory, lightbar, sub)
            echo(lightbar.refresh())

        elif inp in (u'd',) and len(browser.flagged_files):
            download_files(term, session)
            reload_dir(session, directory, lightbar, sub)
            draw_interface(term, lightbar)

        elif inp in (u'u',):
            upload_files(term)
            reload_dir(session, directory, lightbar, sub)
            draw_interface(term, lightbar)

        elif inp in (u'e',) and session.user.is_sysop and not isdir:
            edit_description(relativename, db_desc)
            reload_dir(session, directory, lightbar, sub)
            draw_interface(term, lightbar)

        clear_diz(term)
        save_diz = True

        if lightbar.selected or inp in (term.KEY_LEFT, term.KEY_RIGHT,):

            if sub and inp is term.KEY_LEFT:
                # term.KEY_LEFT backs up
                return True

            if (isdir or is_flagged_dir(filename) and (
                    lightbar.selected or inp is term.KEY_RIGHT)):
                # 'select' key pressed

                if filename == '..{0}'.format(os.path.sep):
                    # is directory and is a parent directory; back out
                    return True

                # RECURSION
                if not browse_dir(session, db_desc, term, lightbar,
                                  filepath, True):
                    # sub directory; jump in
                    return False

                reload_dir(session, directory, lightbar, sub)
                lightbar.vitem_shift = shift
                lightbar.vitem_idx = idx
                echo(lightbar.refresh())

        if relativename in db_desc:
            save_diz = False
            diz = db_desc[relativename]
            if ext in COLLY_EXTENSIONS:
                decoder = 'cp437_art'
                if session.encoding == 'utf8':
                    decoder = COLLY_DECODING
                try:
                    diz = [line.decode(decoder, errors='replace')
                           for line in diz]
                except UnicodeEncodeError:
                    diz = [u'Invalid characters in FILE_ID.DIZ']

        elif ext in browser.diz_extractors:
            # is (supported) archive
            diz = browser.diz_extractors[ext](filepath).splitlines()

        elif ext in COLLY_EXTENSIONS:
            # is ASCII colly, pull diz from between markers if available.
            diz = get_diz_from_colly(filepath=filepath) or diz
            # save diz in raw format, but display decoded
            save_diz = False
            db_desc[relativename] = diz
            decoder = 'cp437_art'
            if session.encoding == 'utf8':
                decoder = COLLY_DECODING
            try:
                diz = [line.decode(decoder, errors='replace') for line in diz]
            except UnicodeEncodeError:
                diz = [u'Invalid characters in FILE_ID.DIZ']
                db_desc[relativename] = diz

        elif is_flagged_dir(filename):
            # is pseudo-folder for flagged files
            save_diz = False
            diz = get_instructions(term, session.user.is_sysop)

        elif isdir:
            # is directory; don't give it a description
            save_diz = False
            diz = []

        else:
            # is normal file
            save_diz = False
            diz = [u'No description']

        if not UPLOADS_DIR.find(directory) and save_diz:
            # write description to diz db when save_diz is True
            with db_desc:
                db_desc[relativename] = diz

        browser.last_diz_len = len(diz)
        describe_file(term=term, diz=diz, directory=directory,
                      filename=filename, isdir=isdir)
        echo(lightbar.refresh_quick() + lightbar.fixate())
        inp = None
Ejemplo n.º 38
0
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, Ansi
    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'^',):
        user['sausercookie'] = u''
        user['sapasscookie'] = u''
    if is_self and inp in (u'c', u'C'):
        gosub('charset')

    elif is_self and inp in (u'@',):
        echo(u'\r\neNTER SA \'pass\' cookie: ')
        sapasscookie = LineEditor(50, session.user['sapasscookie']).read()
        echo(u"\r\n\r\nset SA pass cookie to '%s'? [yn]" % (sapasscookie,))
        while True:
            inp2 = getch()
            if inp2 in (u'y', u'Y'):
                session.user['sapasscookie'] = sapasscookie
                break
            elif inp2 in (u'n', u'N'):
                break

    elif is_self and inp in (u'!',):
        echo(u'\r\neNTER SA \'user\' cookie: ')
        sausercookie = LineEditor(30, session.user['sausercookie']).read()
        echo(u"\r\n\r\nset SA user cookie to '%s'? [yn]" % (sausercookie,))
        while True:
            inp2 = getch()
            if inp2 in (u'y', u'Y'):
                session.user['sausercookie'] = sausercookie
                break
            elif inp2 in (u'n', u'N'):
                break

    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'.',):
        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'):
        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
Ejemplo n.º 39
0
def main():
    """ Main procedure. """
    # pylint: disable=R0912
    #        Too many branches
    from x84.bbs import getsession, getterminal, ini, echo, getch
    session, term = getsession(), getterminal()
    pager, selector = get_pager(), get_selector()

    thread = None
    if ini.CFG.has_section('bbs-scene'):
        thread = FetchUpdates()
        thread.start()
        session.activity = u'one-liners [bbs-scene.org]'
    else:
        session.activity = u'one-liners'

    # flag a pager update,
    dirty = True
    # force screen clear on first loop,
    session.buffer_event('refresh', ('init', ))
    while True:
        # 1. calculate and redraw screen,
        # or enter dumb pager mode (no scrolling)
        if session.poll_event('refresh'):
            pager, selector = get_pager(), get_selector(selector.selection)
            echo(banner())
            dirty = True
        if chk_thread(thread):
            thread = None
        while session.read_event('oneliner_update', 0.15):
            dirty = True
        if dirty and (session.env.get('TERM') != 'unknown'
                      and not session.user.get('expert', False)
                      and term.width >= 78 and term.height >= 20):
            # smart terminal
            redraw(pager, selector)
            dirty = False
        elif dirty:
            # dumb terminal
            if thread is not None:
                wait_for(thread)
            if chk_thread(thread):
                thread = None
            echo(u'\r\n\r\n')
            return dummy_pager()

        # 2. detect and process keyboard input,
        inp = getch(1)
        if inp is not None:
            # input is multiplexed to both interfaces
            echo(pager.process_keystroke(inp))
            echo(selector.process_keystroke(inp))

            # selected 'yes' & return, 'say something'
            if (selector.selected and selector.selection == selector.left):
                # re-assign thread so that it is checked for updates
                thread = saysomething(dumb=False)
                # undo 'selected' state of yes/no bar,
                selector.selected = False

            # quit 'q', or selected 'no' & return
            elif (selector.selected and selector.selection == selector.right
                  or pager.quit):
                return
Ejemplo n.º 40
0
def nothing():
    """ Do nothing. """
    from x84.bbs import echo, getch
    echo(u'Nothing to do.')
    getch(3)
Ejemplo n.º 41
0
def prompt_tags(tags):
    """ Prompt for and return valid tags from TAGDB. """
    # pylint: disable=R0914,W0603
    #         Too many local variables
    #         Using the global statement
    from x84.bbs import DBProxy, echo, getterminal, getsession
    from x84.bbs import Ansi, LineEditor, getch
    session, term = getsession(), getterminal()
    tagdb = DBProxy('tags')
    global FILTER_PRIVATE
    while True:
        # Accept user input for a 'search tag', or /list command
        #
        echo(u"\r\n\r\nENtER SEARCh %s, COMMA-dEliMitEd. " %
             (term.red('TAG(s)'), ))
        echo(u"OR '/list', %s%s\r\n : " % (
            (term.yellow_underline('^x') +
             u':autoscan ' if session.user.get('autoscan', False) else u''),
            term.yellow_underline('^a') + u':ll msgs ' +
            term.yellow_underline('Esc') + u':quit',
        ))
        width = term.width - 6
        sel_tags = u', '.join(tags)
        while len(Ansi(sel_tags)) >= (width - 8):
            tags = tags[:-1]
            sel_tags = u', '.join(tags)
        lne = LineEditor(width, sel_tags)
        echo(lne.refresh())
        while not lne.carriage_returned:
            inp = getch()
            if inp in (unichr(27), term.KEY_EXIT):
                return None
            if inp in (unichr(24), ):  # ^A:all
                return set()
            if inp in (unichr(1), ):  # ^X:autoscan
                return session.user.get('autoscan', set())
            else:
                echo(lne.process_keystroke(inp))
        if lne.carriage_returned:
            inp_tags = lne.content
        if (inp_tags is None or 0 == len(inp_tags)
                or inp_tags.strip().lower() == '/quit'):
            return set()
        elif inp_tags.strip().lower() == '/list':
            # list all available tags, and number of messages
            echo(term.normal)
            echo(u'\r\n\r\nTags: \r\n')
            all_tags = sorted(tagdb.items())
            if 0 == len(all_tags):
                echo(u'None !'.center(term.width / 2))
            else:
                echo(
                    Ansi(u', '.join(([
                        u'%s(%s)' % (
                            term.red(tag),
                            term.yellow(str(len(msgs))),
                        ) for (tag, msgs) in all_tags
                    ]))).wrap(term.width - 2))
            continue
        elif (inp_tags.strip().lower() == '/nofilter'
              and 'sysop' in session.user.groups):
            # disable filtering private messages
            FILTER_PRIVATE = False
            continue

        echo(u'\r\n')
        # search input as valid tag(s)
        tags = set([_tag.strip().lower() for _tag in inp_tags.split(',')])
        for tag in tags.copy():
            if not tag in tagdb:
                tags.remove(tag)
                echo(u"\r\nNO MESSAGES With tAG '%s' fOUNd." %
                     (term.red(tag), ))
        return tags
Ejemplo n.º 42
0
def main(save_key=u'draft'):
    """ 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, Ansi, Pager
    session, term = getsession(), getterminal()

    movement = (term.KEY_UP, term.KEY_DOWN, term.KEY_NPAGE, term.KEY_PPAGE,
                term.KEY_HOME, term.KEY_END, u'\r', term.KEY_ENTER)
    keyset = {
        'edit': (term.KEY_ENTER, ),
        'command': (unichr(27), term.KEY_ESCAPE),
        'kill': (u'K', ),
        'undo': (
            u'u',
            'U',
        ),
        'goto': (u'G', ),
        'insert': (u'I', ),
        'insert-before': (u'O', ),
        'insert-after': (u'o', ),
        'join': (u'J', ),
        'rubout': (
            unichr(8),
            unichr(127),
            unichr(23),
            term.KEY_BACKSPACE,
        ),
    }

    def merge():
        """
        Merges line editor content as a replacement for the currently
        selected lightbar row. Returns True if text inserted caused
        additional rows to be appended, which is meaningful in a window
        refresh context.
        """
        lightbar.content[lightbar.index] = [
            lightbar.selection[0],
            softwrap_join(wrap_rstrip(lneditor.content)) + HARDWRAP
        ]
        prior_length = len(lightbar.content)
        prior_position = lightbar.position
        set_lbcontent(lightbar, get_lbcontent(lightbar))
        if len(lightbar.content) - prior_length == 0:
            echo(lightbar.refresh_row(prior_position[0]))
            return False
        while len(lightbar.content) - prior_length > 0:
            # hidden move-down for each appended line
            lightbar.move_down()
            prior_length += 1
        return True

    def statusline(lightbar):
        """
        Display status line and command help on ``lightbar`` borders
        """
        lightbar.colors['border'] = term.red if edit else term.yellow
        keyset_cmd = u''
        if not edit:
            keyset_cmd = u''.join((
                term.yellow(u'-( '),
                term.yellow_underline(u'S'),
                u':',
                term.bold(u'ave'),
                u' ',
                term.yellow_underline(u'A'),
                u':',
                term.bold(u'bort'),
                u' ',
                term.yellow_underline(u'?'),
                u':',
                term.bold(u'help'),
                term.yellow(u' )-'),
            ))
            keyset_cmd = lightbar.pos(
                lightbar.height - 1,
                max(0, lightbar.width -
                    (len(Ansi(keyset_cmd)) + 3))) + keyset_cmd
        return u''.join((
            lightbar.border(),
            keyset_cmd,
            lightbar.pos(lightbar.height, lightbar.xpadding),
            u''.join((
                term.red(u'-[ '),
                u'EditiNG liNE ',
                term.reverse_red('%d' % (lightbar.index + 1, )),
                term.red(u' ]-'),
            )) if edit else u''.join((
                term.yellow(u'-( '),
                u'liNE ',
                term.yellow('%d/%d ' % (
                    lightbar.index + 1,
                    len(lightbar.content),
                )),
                '%d%% ' % (int((float(lightbar.index + 1) /
                                max(1, len(lightbar.content))) * 100)),
                term.yellow(u' )-'),
            )),
            lightbar.title(u''.join((
                term.red('-] '),
                term.bold(u'Escape'),
                u':',
                term.bold_red(u'command mode'),
                term.red(' [-'),
            )) if edit else u''.join((
                term.yellow('-( '),
                term.bold(u'Enter'),
                u':',
                term.bold_yellow(u'edit mode'),
                term.yellow(' )-'),
            ))),
        ))

    def redraw_lneditor(lightbar, lneditor):
        """
        Return ucs suitable for refreshing line editor.
        """
        return ''.join((term.normal, statusline(lightbar), lneditor.border(),
                        lneditor.refresh()))

    def get_ui(ucs, lightbar=None):
        """
        Returns Lightbar and ScrollingEditor instance.
        """
        lbr = get_lightbar(ucs)
        lbr.position = (lightbar.position if lightbar is not None else (0, 0))
        lne = get_lneditor(lbr)
        return lbr, lne

    def banner():
        """
        Returns string suitable clearing screen
        """
        return u''.join((term.move(0, 0), term.normal, term.clear))

    def redraw(lightbar, lneditor):
        """
        Returns ucs suitable for redrawing Lightbar
        and ScrollingEditor UI elements.
        """
        return u''.join((
            term.normal,
            redraw_lightbar(lightbar),
            redraw_lneditor(lightbar, lneditor) if edit else u'',
        ))

    def redraw_lightbar(lightbar):
        """ Returns ucs suitable for redrawing Lightbar. """
        return u''.join((
            statusline(lightbar),
            lightbar.refresh(),
        ))

    def resize(lightbar):
        """ Resize Lightbar. """
        if edit:
            # always re-merge current line on resize,
            merge()
        lbr, lne = get_ui(get_lbcontent(lightbar), lightbar)
        echo(redraw(lbr, lne))
        return lbr, lne

    ucs = session.user.get(save_key, u'')
    lightbar, lneditor = get_ui(ucs, None)
    echo(banner())
    dirty = True
    edit = False
    digbuf, num_repeat = u'', -1
    count_repeat = lambda: range(num_repeat if num_repeat != -1 else 1)
    while True:
        # poll for refresh
        if session.poll_event('refresh'):
            echo(banner())
            lightbar, lneditor = resize(lightbar)
            dirty = True
        if dirty:
            session.activity = 'editing %s' % (save_key, )
            echo(redraw(lightbar, lneditor))
            dirty = False
        # poll for input
        inp = getch(1)

        # buffer keystrokes for repeat
        if (not edit and inp is not None and type(inp) is not int
                and inp.isdigit()):
            digbuf += inp
            if len(digbuf) > 10:
                # overflow,
                echo(u'\a')
                digbuf = inp
            try:
                num_repeat = int(digbuf)
            except ValueError:
                try:
                    num_repeat = int(inp)
                except ValueError:
                    pass
            continue
        else:
            digbuf = u''

        # toggle edit mode,
        if inp in keyset['command'] or not edit and inp in keyset['edit']:
            edit = not edit  # toggle
            if not edit:
                # switched to command mode, merge our lines

                echo(term.normal + lneditor.erase_border())

                merge()
                lightbar.colors['highlight'] = term.yellow_reverse
            else:
                # switched to edit mode, save draft,
                # instantiate new line editor
                save_draft(save_key, get_lbcontent(lightbar))
                lneditor = get_lneditor(lightbar)
                lightbar.colors['highlight'] = term.red_reverse
            dirty = True

        # command mode, kill line
        elif not edit and inp in keyset['kill']:
            # when 'killing' a line, make accomidations to clear
            # bottom-most row, otherwise a ghosting effect occurs
            for _count in count_repeat():
                del lightbar.content[lightbar.index]
                set_lbcontent(lightbar, get_lbcontent(lightbar))
                if lightbar.visible_bottom > len(lightbar.content):
                    echo(lightbar.refresh_row(lightbar.visible_bottom + 1))
                else:
                    dirty = True
            save_draft(save_key, get_lbcontent(lightbar))

        # command mode, insert line
        elif not edit and inp in keyset['insert']:
            for _count in count_repeat():
                lightbar.content.insert(lightbar.index, (
                    lightbar.index,
                    HARDWRAP,
                ))
                set_lbcontent(lightbar, get_lbcontent(lightbar))
            save_draft(save_key, get_lbcontent(lightbar))
            dirty = True

        # command mode; goto line
        elif not edit and inp in keyset['goto']:
            if num_repeat == -1:
                # 'G' alone goes to end of file,
                num_repeat = len(lightbar.content)
            echo(lightbar.goto((num_repeat or 1) - 1))
            echo(statusline(lightbar))

        # command mode; insert-before (switch to edit mode)
        elif not edit and inp in keyset['insert-before']:
            lightbar.content.insert(lightbar.index, (
                lightbar.index,
                HARDWRAP,
            ))
            set_lbcontent(lightbar, get_lbcontent(lightbar))
            edit = dirty = True
            # switched to edit mode, save draft,
            # instantiate new line editor
            lightbar.colors['highlight'] = term.red_reverse
            lneditor = get_lneditor(lightbar)
            save_draft(save_key, get_lbcontent(lightbar))

        # command mode; insert-after (switch to edit mode)
        elif not edit and inp in keyset['insert-after']:
            lightbar.content.insert(lightbar.index + 1, (
                lightbar.index + 1,
                HARDWRAP,
            ))
            set_lbcontent(lightbar, get_lbcontent(lightbar))
            edit = dirty = True
            # switched to edit mode, save draft,
            # instantiate new line editor
            lightbar.colors['highlight'] = term.red_reverse
            lightbar.move_down()
            lneditor = get_lneditor(lightbar)
            save_draft(save_key, get_lbcontent(lightbar))

        # command mode, undo
        elif not edit and inp in keyset['undo']:
            for _count in count_repeat():
                if len(UNDO):
                    set_lbcontent(lightbar, UNDO.pop())
                    dirty = True
                else:
                    echo(u'\a')
                    break

        # command mode, join line
        elif not edit and inp in keyset['join']:
            for _count in count_repeat():
                if lightbar.index + 1 < len(lightbar.content):
                    idx = lightbar.index
                    lightbar.content[idx] = (
                        idx,
                        WHITESPACE.join((
                            lightbar.content[idx][1].rstrip(),
                            lightbar.content[idx + 1][1].lstrip(),
                        )))
                    del lightbar.content[idx + 1]
                    prior_length = len(lightbar.content)
                    set_lbcontent(lightbar, get_lbcontent(lightbar))
                    if len(lightbar.content) - prior_length > 0:
                        lightbar.move_down()
                    dirty = True
                else:
                    echo(u'\a')
                    break
            if dirty:
                save_draft(save_key, get_lbcontent(lightbar))

        # command mode, basic cmds & movement
        elif not edit and inp is not None:
            if inp in (
                    u'a',
                    u'A',
            ):
                if yes_no(
                        lightbar,
                        term.yellow(u'- ') + term.bold_red(u'AbORt') +
                        term.yellow(u' -')):
                    return False
                dirty = True
            elif inp in (
                    u's',
                    u'S',
            ):
                if yes_no(
                        lightbar,
                        term.yellow(u'- ') + term.bold_green(u'SAVE') +
                        term.yellow(u' -'), term.reverse_green):
                    save(save_key, get_lbcontent(lightbar))
                    return True
                dirty = True
            elif inp in (u'?', ):
                pager = Pager(lightbar.height, lightbar.width, lightbar.yloc,
                              lightbar.xloc)
                pager.update(get_help())
                pager.colors['border'] = term.bold_blue
                echo(pager.border() + pager.title(u''.join((
                    term.bold_blue(u'-( '),
                    term.white_on_blue(u'r'),
                    u':',
                    term.bold(u'eturn'),
                    u' ',
                    term.bold_blue(u' )-'),
                ))))
                pager.keyset['exit'].extend([u'r', u'R'])
                pager.read()
                echo(pager.erase_border())
                dirty = True
            else:
                moved = False
                for _count in count_repeat():
                    echo(lightbar.process_keystroke(inp))
                    moved = lightbar.moved or moved
                if moved:
                    echo(statusline(lightbar))

        # edit mode; movement
        elif edit and inp in movement:
            dirty = merge()
            if inp in (
                    u'\r',
                    term.KEY_ENTER,
            ):
                lightbar.content.insert(lightbar.index + 1,
                                        [lightbar.selection[0] + 1, u''])
                inp = term.KEY_DOWN
                dirty = True
            ucs = lightbar.process_keystroke(inp)
            if lightbar.moved:
                echo(term.normal + lneditor.erase_border())
                echo(ucs)
                lneditor = get_lneditor(lightbar)
                save_draft(save_key, get_lbcontent(lightbar))
                echo(lneditor.refresh())
            else:
                dirty = True

        # edit mode -- append character / backspace
        elif edit and inp is not None:
            if (inp in keyset['rubout'] and len(lneditor.content) == 0
                    and lightbar.index > 0):
                # erase past margin,
                echo(term.normal + lneditor.erase_border())
                del lightbar.content[lightbar.index]
                lightbar.move_up()
                set_lbcontent(lightbar, get_lbcontent(lightbar))
                lneditor = get_lneditor(lightbar)
                dirty = True
            else:
                # edit mode, add/delete ch
                echo(lneditor.process_keystroke(inp))
                if lneditor.moved:
                    echo(statusline(lightbar))

        if inp is not None and type(inp) is not int and not inp.isdigit():
            # commands were processed, reset num_repeat to 1
            num_repeat = -1
Ejemplo n.º 43
0
def main():
    """ Main procedure. """
    # pylint: disable=R0914,W0141,R0912
    #         Too many local variables
    #         Used builtin function 'map'
    #         Too many branches
    from x84.bbs import getsession, getterminal, echo, getch, syncterm_setfont
    from x84.engine import __url__ as url
    import platform
    import random
    import sys
    import os
    session, term = getsession(), getterminal()
    session.activity = 'System Info'
    artfile = os.path.join(
        os.path.dirname(__file__),
        'art',
        'plant.ans',
    )
    # pylint: disable=W0633
    #         Attempting to unpack a non-sequence defined at line 1160 of
    #         platform
    system, _, release, _, machine, _ = platform.uname()

    body = [
        u'authors:',
        u'Johannes Lundberg',
        u'Jeffrey Quast',
        u'Wijnand Modderman-Lenstra',
        u'',
        u'artwork:',
        u'hellbeard!impure',
        u'\r\n',
        u'system: %s %s %s' % (system, release, machine),
        u'software: x/84',
        url,
        u'\r\n',
        (platform.python_implementation() + u' ' +
         '-'.join(map(str, sys.version_info[3:]))) + u' ' +
        (platform.python_version()
         if hasattr(platform, 'python_implementation') else u'.'.join(
             map(str, sys.version_info[:3]))),
    ]
    melt_colors = ([term.normal] + [term.bold_blue] * 3 + [term.red] * 4 +
                   [term.bold_red] + [term.bold_white] + [term.normal] * 6 +
                   [term.blue] * 2 + [term.bold_blue] + [term.bold_white] +
                   [term.normal])
    art = open(artfile).read().decode('cp437_art') \
        if os.path.exists(artfile) else u''
    otxt = list(art.splitlines())
    for num, line in enumerate(body):
        while num > len(otxt):
            otxt += [
                u'',
            ]
        otxt[num] = otxt[num][:int(term.width / 2.5)] + u' ' + line
    width = max([term.length(line) for line in otxt])
    height = len(otxt)
    num_stars = int((term.width * term.height) * .005)
    stars = dict([(n, (random.choice('\\|/-'),
                       float(random.choice(range(term.width))),
                       float(random.choice(range(term.height)))))
                  for n in range(num_stars)])
    melting = {}
    show_star = False
    tm_out, tm_min, tm_max, tm_step = 0.08, 0.01, 2.0, .01
    wind = (0.7, 0.1, 0.01, 0.01)

    def refresh():
        """ Refresh screen and return top-left (x, y) location. """
        # set syncterm font to cp437
        if term.kind.startswith('ansi'):
            echo(syncterm_setfont('cp437'))
        echo(u'\r\n\r\n')
        if term.width < width:
            echo(u''.join((
                term.move(term.height, 0),
                u'\r\n\r\n',
                term.bold_red + 'screen too thin! (%s/%s)' % (
                    term.width,
                    width,
                ),
                u'\r\n\r\n',
                u'press any key...',
            )))
            getch()
            return (None, None)
        if term.height < height:
            echo(u''.join((
                term.move(term.height, 0),
                u'\r\n\r\n',
                term.bold_red + 'screen too short! (%s/%s)' %
                (term.height, height),
                u'\r\n\r\n',
                u'press any key...',
            )))
            getch()
            return (None, None)
        xloc = (term.width / 2) - (width / 2)
        yloc = (term.height / 2) - (height / 2)
        echo(u''.join((
            term.normal,
            (u'\r\n' + term.clear_eol) * term.height,
            u''.join([
                term.move(yloc + abs_y, xloc) + line
                for abs_y, line in enumerate(otxt)
            ]),
        )))
        return xloc, yloc

    txt_x, txt_y = refresh()
    if (txt_x, txt_y) == (None, None):
        return

    def char_at_pos(yloc, xloc, txt_y, txt_x):
        """ Return art (y, x) for location """
        return (u' ' if yloc - txt_y < 0 or yloc - txt_y >= height
                or xloc - txt_x < 0 or xloc - txt_x >= len(otxt[yloc - txt_y])
                else otxt[yloc - txt_y][xloc - txt_x])

    def iter_wind(xslope, yslope, xdir, ydir):
        """ An easterly Wind """
        xslope += xdir
        yslope += ydir
        if xslope <= 0.5:
            xdir = random.choice([0.01, 0.015, 0.02])
        elif xslope >= 1:
            xdir = random.choice([-0.01, -0.015, -0.02])
        if yslope <= -0.1:
            ydir = random.choice([0.01, 0.015, 0.02, 0.02])
        elif yslope >= 0.1:
            ydir = random.choice([-0.01, -0.015, -0.02])
        return xslope, yslope, xdir, ydir

    def iter_star(char, xloc, yloc):
        """ Given char and current position, apply wind and return new
        char and new position. """
        if char == '\\':
            char = '|'
        elif char == '|':
            char = '/'
        elif char == '/':
            char = '-'
        elif char == '-':
            char = '\\'
        xloc += wind[0]
        yloc += wind[1]
        if xloc < 1 or xloc > term.width:
            xloc = (1.0 if xloc > term.width else float(term.width))
            yloc = (float(random.choice(range(term.height))))
        if yloc < 1 or yloc > term.height:
            yloc = (1.0 if yloc > term.height else float(term.height))
            xloc = (float(random.choice(range(term.width))))
        return char, xloc, yloc

    def erase(star_idx):
        """ erase old star before moving .. """
        if show_star:
            _, xloc, yloc = stars[star_idx]
            echo(u''.join((
                term.move(int(yloc), int(xloc)),
                term.normal,
                char_at_pos(int(yloc), int(xloc), txt_y, txt_x),
            )))

    def melt():
        """ Iterate through all stars and phase through melt sequence. """
        def melted(yloc, xloc):
            """ shift melt, delete if disappeared. """
            melting[(yloc, xloc)] -= 1
            if 0 == melting[(yloc, xloc)]:
                del melting[(yloc, xloc)]

        for (yloc, xloc), phase in melting.items():
            echo(u''.join((
                term.move(yloc, xloc),
                melt_colors[phase - 1],
                char_at_pos(yloc, xloc, txt_y, txt_x),
            )))
            melted(yloc, xloc)

    def draw_star(star, xloc, yloc):
        """ draw star a (x, y) location """
        char = char_at_pos(int(yloc), int(xloc), txt_y, txt_x)
        if char != ' ':
            melting[(int(yloc), int(xloc))] = len(melt_colors)
        if show_star:
            echo(term.move(int(yloc), int(xloc)) + melt_colors[-1] + star)

    with term.hidden_cursor():
        while txt_x is not None and txt_y is not None:
            if session.poll_event('refresh'):
                num_stars = int(num_stars)
                stars = dict([(n, (random.choice('\\|/-'),
                                   float(random.choice(range(term.width))),
                                   float(random.choice(range(term.height)))))
                              for n in range(num_stars)])
                otxt = list(art.splitlines())
                for num, line in enumerate(body):
                    while num > len(otxt):
                        otxt += [
                            u'',
                        ]
                    otxt[num] = (otxt[num][:int(term.width / 2.5)] + u' ' +
                                 line)
                txt_x, txt_y = refresh()
                continue
            inp = getch(tm_out)
            if inp in (term.KEY_UP, 'k'):
                if tm_out >= tm_min:
                    tm_out -= tm_step
            elif inp in (term.KEY_DOWN, 'j'):
                if tm_out <= tm_max:
                    tm_out += tm_step
            elif inp in (term.KEY_LEFT, 'h'):
                if num_stars > 2:
                    num_stars = int(num_stars * .5)
                    stars = dict([(n,
                                   (random.choice('\\|/-'),
                                    float(random.choice(range(term.width))),
                                    float(random.choice(range(term.height)))))
                                  for n in range(num_stars)])
            elif inp in (term.KEY_RIGHT, 'l'):
                if num_stars < (term.width * term.height) / 4:
                    num_stars = int(num_stars * 1.5)
                    stars = dict([(n,
                                   (random.choice('\\|/-'),
                                    float(random.choice(range(term.width))),
                                    float(random.choice(range(term.height)))))
                                  for n in range(num_stars)])
            elif inp in (u'*', ) and not show_star:
                show_star = True
            elif inp in (u'*', ) and show_star:
                for star in stars:
                    erase(star)
                show_star = False
            elif inp is not None:
                echo(term.move(term.height, 0))
                break
            melt()
            for star_key, star_val in stars.items():
                erase(star_key)
                # pylint: disable=W0142
                #         Used * or ** magic
                stars[star_key] = iter_star(*star_val)
                draw_star(*stars[star_key])
            # pylint: disable=W0142
            #         Used * or ** magic
            wind = iter_wind(*wind)
Ejemplo n.º 44
0
def main():
    """ Main procedure. """
    # pylint: disable=R0914,R0912
    #         Too many local variables
    #         Too many branches
    from x84.bbs import DBProxy, getsession, getterminal, echo
    from x84.bbs import ini, LineEditor, timeago, Ansi, showcp437
    from x84.bbs import disconnect, getch
    import time
    import os
    session, term = getsession(), getterminal()
    session.activity = 'logging off'
    handle = session.handle if (session.handle is not None) else 'anonymous'
    max_user = ini.CFG.getint('nua', 'max_user')
    prompt_msg = u'[spnG]: ' if session.user.get('expert', False) else (
        u'%s:AY SOMEthiNG %s:REViOUS %s:EXt %s:Et thE f**k Off !\b' % (
            term.bold_blue_underline(u's'),
            term.blue_underline(u'p'),
            term.blue_underline(u'n'),
            term.red_underline(u'Escape/g'),
        ))
    prompt_say = u''.join((
        term.bold_blue(handle),
        term.blue(u' SAYS WhAt'),
        term.bold(': '),
    ))
    boards = (
        (
            '1984.ws',
            'x/84 dEfAUlt bOARd',
            'dingo',
        ),
        (
            'htc.zapto.org',
            'Haunting the Chapel',
            'Mercyful',
        ),
        (
            'pharcyde.ath.cx',
            'Pharcyde BBS',
            'Access Denied',
        ),
        (
            'bloodisland.ph4.se',
            'Blood Island',
            'xzip',
        ),
        (
            'ssl.archaicbinary.net',
            'Archaic Binary',
            'Wayne Smith',
        ),
        (
            'bbs.godta.com',
            'godta',
            'sk-5',
        ),
    )
    board_fmt = u'%25s %-30s %-15s\r\n'
    goodbye_msg = u''.join((
        term.move(term.height, 0),
        u'\r\n' * 10,
        u'tRY ANOthER fiNE bOARd',
        term.bold(u':'),
        u'\r\n\r\n',
        board_fmt % (
            term.underline('host'.rjust(25)),
            term.underline('board'.ljust(30)),
            term.underline('sysop'.ljust(15)),
        ),
        u'\r\n'.join([
            board_fmt % (
                term.bold(host.rjust(25)),
                term.reverse(board.center(30)),
                term.bold_underline(sysop),
            ) for (host, board, sysop) in boards
        ]),
        u'\r\n\r\n',
        term.bold(u'back to the mundane world...'),
        u'\r\n',
    ))
    commit_msg = term.bold_blue(
        u'-- !  thANk YOU fOR YOUR CONtRibUtiON, bROthER  ! --')
    write_msg = term.red_reverse(u'bURNiNG tO ROM, PlEASE WAiT ...')
    db_firstrecord = ((time.time() - 1984, u'B. b.',
                       u'bEhAVE YOURSElVES ...'), )
    automsg_len = 40
    artfile = os.path.join(os.path.dirname(__file__), 'art', '1984.asc')

    def refresh_prompt(msg):
        """ Refresh automsg prompt using string msg. """
        echo(u''.join((u'\r\n\r\n', term.clear_eol, msg)))

    def refresh_automsg(idx):
        """ Refresh automsg database, display automsg of idx, return idx. """
        session.flush_event('automsg')
        autodb = DBProxy('automsg')
        automsgs = sorted(autodb.values()) if len(autodb) else db_firstrecord
        dblen = len(automsgs)
        # bounds check
        if idx < 0:
            idx = dblen - 1
        elif idx > dblen - 1:
            idx = 0
        tm_ago, handle, msg = automsgs[idx]
        asc_ago = u'%s ago' % (timeago(time.time() - tm_ago))
        disp = (u''.join((
            '\r\n\r\n',
            term.bold(handle.rjust(max_user)),
            term.bold_blue(u'/'),
            term.blue(u'%*d' % (
                len('%d' % (dblen, )),
                idx,
            )),
            term.bold_blue(u':'),
            term.blue_reverse(msg.ljust(automsg_len)),
            term.bold(u'\\'),
            term.blue(asc_ago),
        )))
        echo(u''.join((
            u'\r\n\r\n',
            Ansi(disp).wrap(term.width),
        )))
        return idx

    def refresh_all(idx=None):
        """
        refresh screen, database, and return database index
        """
        echo(u''.join((
            u'\r\n\r\n',
            term.clear_eol,
        )))
        for line in showcp437(artfile):
            echo(line)
        idx = refresh_automsg(-1 if idx is None else idx)
        refresh_prompt(prompt_msg)
        return idx

    idx = refresh_all()
    while True:
        if session.poll_event('refresh'):
            idx = refresh_all()
        elif session.poll_event('automsg'):
            refresh_automsg(-1)
            echo(u'\a')  # bel
            refresh_prompt(prompt_msg)
        inp = getch(1)
        if inp in (
                u'g',
                u'G',
                term.KEY_EXIT,
                unichr(27),
                unichr(3),
        ):
            # http://www.xfree86.org/4.5.0/ctlseqs.html
            # Restore xterm icon and window title from stack.
            echo(unichr(27) + u'[23;0t')
            echo(goodbye_msg)
            getch(1.5)
            disconnect('logoff.')
        elif inp in (
                u'n',
                u'N',
                term.KEY_DOWN,
                term.KEY_NPAGE,
        ):
            idx = refresh_automsg(idx + 1)
            refresh_prompt(prompt_msg)
        elif inp in (
                u'p',
                u'P',
                term.KEY_UP,
                term.KEY_PPAGE,
        ):
            idx = refresh_automsg(idx - 1)
            refresh_prompt(prompt_msg)
        elif inp in (u's', u'S'):
            # new prompt: say something !
            refresh_prompt(prompt_say)
            msg = LineEditor(width=automsg_len).read()
            if msg is not None and msg.strip():
                echo(u''.join((
                    u'\r\n\r\n',
                    write_msg,
                )))
                autodb = DBProxy('automsg')
                autodb.acquire()
                idx = max([int(ixx) for ixx in autodb.keys()] or [-1]) + 1
                autodb[idx] = (time.time(), handle, msg.strip())
                autodb.release()
                session.send_event('global', (
                    'automsg',
                    True,
                ))
                refresh_automsg(idx)
                echo(u''.join((
                    u'\r\n\r\n',
                    commit_msg,
                )))
                getch(0.5)  # for effect, LoL
            # display prompt
            refresh_prompt(prompt_msg)
Ejemplo n.º 45
0
def denied(msg):
    """ Display denied message, pause for input for 1s. """
    from x84.bbs import getterminal, echo, getch
    term = getterminal()
    echo(u'\r\n' + term.bold_red(msg))
    getch(1.0)
Ejemplo n.º 46
0
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
Ejemplo n.º 47
0
def main():
    """ Main procedure. """
    # pylint: disable=R0912
    #        Too many branches
    from x84.bbs import getsession, getterminal, echo, getch, Ansi, from_cp437
    session, term = getsession(), getterminal()
    session.activity = u'Selecting chracter set'
    artfile = os.path.join(
        os.path.dirname(__file__), 'art', (
            'plant-256.ans' if term.number_of_colors == 256
            else 'plant.ans'))
    enc_prompt = (
        u'Press left/right until artwork looks best. Clients should'
        ' select utf8 encoding and Andale Mono font. Older clients or'
        ' clients with appropriate 8-bit fontsets can select cp437, though'
        ' some characters may appear as "?".')
    save_msg = u"\r\n\r\n'%s' is now your preferred encoding ..\r\n"
    if session.user.get('expert', False):
        echo(u'\r\n\r\n(U) UTF-8 encoding or (C) CP437 encoding [uc] ?\b\b')
        while True:
            inp = getch()
            if inp in (u'u', u'U'):
                session.encoding = 'utf8'
                break
            elif inp in (u'c', u'C'):
                session.encoding = 'cp437'
                break
        session.user['charset'] = session.encoding
        echo(save_msg % (session.encoding,))
        getch(1.0)
        return

    art = (from_cp437(open(artfile).read()).splitlines()
           if os.path.exists(artfile) else [u''])

    def refresh(sel):
        """ Refresh art and yes/no prompt, ``sel``. """
        session.flush_event('refresh')
        session.encoding = selector.selection
        if sel.selection == 'utf8':
            # 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.
            echo(unichr(27) + u'%G')
        elif sel.selection == 'cp437':
            # ESC %@ returns to ISO 2022 in case UTF-8 had been entered.
            # ESC ) U Sets character set G1 to codepage 437 .. usually.
            echo(unichr(27) + u'%@')
            echo(unichr(27) + u')U')
        else:
            assert False, "Only encodings 'utf8' and 'cp437' supported."
        # display art, banner, paragraph, refresh selector refresh
        buf = [line for line in art]
        return u''.join((
            u'\r\n\r\n',
            u'\r\n'.join(buf),
            u'\r\n\r\n',
            Ansi(enc_prompt).wrap(int(term.width * .95)),
            u'\r\n\r\n',
            sel.refresh(),))

    selector = get_selector(session.encoding)
    echo(refresh(selector))
    while True:
        inp = getch(1)
        if inp == term.KEY_ENTER:
            session.user['charset'] = session.encoding
            echo(save_msg % (session.encoding,))
            getch(1.0)
            return
        elif inp is not None:
            selector.process_keystroke(inp)
            if selector.quit:
                # 'escape' quits without save, though the encoding
                # has been temporarily set for this session.
                return
            if selector.moved:
                # set and refresh art in new encoding
                echo(refresh(selector))
        if session.poll_event('refresh') is not None:
            # instantiate a new selector in case the window size has changed.
            selector = get_selector(session.encoding)
            echo(refresh(selector))
Ejemplo n.º 48
0
def main():
    """ Main procedure. """
    # pylint: disable=R0912,R0914,R0915
    #         Too many branches
    #         Too many local variables
    #         Too many statements
    from x84.bbs import getsession, getterminal, getch, echo
    session, term = getsession(), getterminal()
    ayt_lastfresh = 0

    def broadcast_ayt(last_update):
        """ Globally boradcast 'are-you-there' request. """
        if time.time() - last_update > POLL_AYT:
            session.send_event('global', ('AYT', session.sid,))
            last_update = time.time()
        return last_update

    sessions = dict()
    dirty = time.time()
    cur_row = 0
    while True:
        ayt_lastfresh = broadcast_ayt(ayt_lastfresh)
        inp = getch(POLL_KEY)
        if session.poll_event('refresh') or (
                inp in (u' ', term.KEY_REFRESH, unichr(12))):
            dirty = time.time()
            cur_row = 0
        elif inp in (u'q', 'Q', term.KEY_EXIT, unichr(27)):
            return
        elif inp in (u'c', 'C'):
            cur_row = 0 if chat(sessions) else cur_row
            dirty = time.time()
        elif inp in (u's', 'S'):
            cur_row = 0 if sendmsg(sessions) else cur_row
            dirty = time.time()
        elif inp is not None and 'sysop' in session.user.groups:
            if inp in (u'e', u'E'):
                cur_row = 0 if edit(sessions) else cur_row
                dirty = time.time()
            elif inp in (u'p', u'P'):
                cur_row = 0 if playback(sessions) else cur_row
                dirty = time.time()
            elif inp in (u'w', u'W'):
                cur_row = 0 if watch(sessions) else cur_row
                dirty = time.time()
            elif inp in (u'v', u'V'):
                cur_row = 0 if view(sessions) else cur_row + 3
                dirty = time.time()
            elif inp in (u'd', u'D'):
                disconnect(sessions)
                dirty = time.time()

        # add sessions that respond to AYT
        data = session.poll_event('ACK')
        if data is not None:
            sid, handle = data
            if sid in sessions:
                sessions[sid]['handle'] = handle
            else:
                sessions[sid] = dict((
                    ('handle', handle),
                    ('lastfresh', time.time()),
                    ('lastasked', time.time()),))
                dirty = time.time()
                echo(u'\a')

        # update sessions that respond to info-req
        data = session.poll_event('info-ack')
        if data is not None:
            sid, attrs = data
            if sessions.get(sid, dict()).get('activity') != attrs['activity']:
                # and refresh screen if activity changes
                dirty = time.time()
            sessions[sid] = attrs
            sessions[sid]['lastfresh'] = time.time()

        # update our own session
        sessions[SELF_ID] = session.info()
        sessions[SELF_ID]['lastfresh'] = time.time()

        # request that all sessions update if more stale than POLL_INF,
        # or is missing session info (only AYT replied so far!),
        # or has been displayed as 'Disconnected' (marked for deletion)
        for sid, attrs in sessions.items():
            if sid == SELF_ID:
                continue
            if attrs.get('idle', -1) == -1 or (
                    time.time() - attrs.get('lastfresh', 0) > POLL_INF
                    and time.time() - attrs.get('lastasked', 0) > POLL_INF):
                request_info(sid)
                attrs['lastasked'] = time.time()

        # prune users who haven't responded to AYT
        for sid, attrs in sessions.items():
            if time.time() - attrs['lastfresh'] > (POLL_AYT * 2):
                sessions[sid]['delete'] = 1
                dirty = time.time()

        if dirty is not None and time.time() - dirty > POLL_OUT:
            session.activity = u"Who's Online"
            otxt = describe(sessions)
            olen = len(otxt.splitlines())
            if 0 == cur_row or (cur_row + olen) >= term.height:
                otxt_b = banner()
                otxt_h = heading(sessions)
                cur_row = len(otxt_b.splitlines()) + len(otxt_h.splitlines())
                echo(u'\r\n'.join((u'\r\n\r\n', otxt_b, otxt_h, otxt)))
            else:
                echo(u''.join((
                    u'\r\n',
                    '-'.center(term.width).rstrip(),
                    u'\r\n')))
                echo(otxt)
            cur_row += olen
            dirty = None

        # delete disconnected sessions
        for sid, attrs in sessions.items()[:]:
            if attrs.get('delete', 0) == 1:
                del sessions[sid]
Ejemplo n.º 49
0
def main(autoscan_tags=None):
    """ Main procedure. """
    # pylint: disable=W0603,R0912
    #         Using the global statement
    #         Too many branches
    from x84.bbs import getsession, getterminal, echo, getch
    from x84.bbs import list_msgs
    session, term = getsession(), getterminal()
    session.activity = 'autoscan msgs'
    echo(banner())
    global ALREADY_READ, SEARCH_TAGS, DELETED
    if autoscan_tags is not None:
        SEARCH_TAGS = autoscan_tags
        echo(u''.join((term.bold_black('[ '), term.yellow('AUtOSCAN'),
                       term.bold_black(' ]'), u'\r\n')))
    else:
        SEARCH_TAGS = set(['public'])
        # also throw in user groups, maybe the top 3 .. ?
        SEARCH_TAGS.update(session.user.groups)
        SEARCH_TAGS = prompt_tags(SEARCH_TAGS)
        # user escape
        if SEARCH_TAGS is None:
            return

    echo(u'\r\n\r\n%s%s ' % (
        term.bold_yellow('SCANNiNG'),
        term.bold_black(':'),
    ))
    echo(u','.join([term.red(tag)
                    for tag in SEARCH_TAGS] if 0 != len(SEARCH_TAGS) else [
                        '<All>',
                    ]))

    if (SEARCH_TAGS != session.user.get('autoscan', None)):
        echo(u'\r\n\r\nSave tag list as autoscan on login [yn] ?\b\b')
        while True:
            inp = getch()
            if inp in (u'q', 'Q', unichr(27), u'n', u'N'):
                break
            elif inp in (u'y', u'Y'):
                session.user['autoscan'] = SEARCH_TAGS
                break

    # retrieve all matching messages,
    all_msgs = list_msgs(SEARCH_TAGS)
    echo(u'\r\n\r\n%s messages.' % (term.yellow_reverse(str(len(all_msgs), ))))
    if 0 == len(all_msgs):
        getch(0.5)
        return

    # filter messages public/private/group-tag/new
    ALREADY_READ = session.user.get('readmsgs', set())
    DELETED = session.user.get('trash', set())
    msgs, new = msg_filter(all_msgs)
    if 0 == len(msgs) and 0 == len(new):
        getch(0.5)
        return

    # prompt read 'a'll, 'n'ew, or 'q'uit
    echo(u'\r\n  REAd [%s]ll %d%s message%s [qa%s] ?\b\b' % (
        term.yellow_underline(u'a'),
        len(msgs),
        (u' or %d [%s]EW ' % (
            len(new),
            term.yellow_underline(u'n'),
        ) if new else u''),
        u's' if 1 != len(msgs) else u'',
        u'n' if new else u'',
    ))
    while True:
        inp = getch()
        if inp in (u'q', 'Q', unichr(27)):
            return
        elif inp in (u'n', u'N') and len(new):
            # read only new messages
            msgs = new
            break
        elif inp in (u'a', u'A'):
            break

    # read target messages
    read_messages(msgs, new)
Ejemplo n.º 50
0
def get_username(handle=u''):
    """
    Prompt for a login handle. If unfound, script change to 'nua' when
    allow_apply is enabled (default=yes). Also allow 'anonymous' when enabled
    (default=no). A unicode handle of non-zero length is returned when the
    login handle matches a userbase record.
    """
    # pylint: disable=R0914,R0911
    #         Too many local variables
    #         Too many return statements
    from x84.bbs import getterminal, ini, echo, LineEditor, gosub, goto
    from x84.bbs import find_user, getch
    term = getterminal()
    prompt_user = u'user: '******'\r\n\r\n  --> Create new account? [ynq]   <--' + '\b' * 5
    allow_apply = ini.CFG.getboolean('nua', 'allow_apply')
    enable_anonymous = ini.CFG.getboolean('matrix', 'enable_anonymous')
    # pylint: disable=E1103
    #         Instance of '_Chainmap' has no 'split' member
    #         (but some types could not be inferred)
    newcmds = ini.CFG.get('matrix', 'newcmds').split()
    byecmds = ini.CFG.get('matrix', 'byecmds').split()
    denied_msg = u'\r\n\r\nfiRSt, YOU MUSt AbANdON YOUR libERtIES.'
    badanon_msg = u"\r\n  " + term.bright_red + u"'%s' login denied."
    max_user = ini.CFG.getint('nua', 'max_user')
    nuascript = ini.CFG.get('nua', 'script')
    topscript = ini.CFG.get('matrix', 'topscript')

    echo(prompt_user)
    handle = LineEditor(max_user, handle).read()
    if handle is None or 0 == len(handle.strip()):
        echo(u'\r\n')
        return u''
    elif handle.lower() in newcmds:
        if allow_apply:
            gosub('nua', u'')
            return u''
        denied(denied_msg)
        return u''
    elif handle.lower() in byecmds:
        goto('logoff')
    elif handle.lower() == u'anonymous':
        if enable_anonymous:
            goto(topscript, 'anonymous')
        denied(badanon_msg % (handle, ))
        return u''
    u_handle = find_user(handle)
    if u_handle is not None:
        return u_handle  # matched
    if allow_apply is False:
        denied(denied_msg)
        return u''

    echo(apply_msg)
    ynq = getch()
    if ynq in (u'q', u'Q', term.KEY_EXIT):
        # goodbye
        goto('logoff')
    elif ynq in (u'y', u'Y'):
        # new user application
        goto(nuascript, handle)
    echo(u'\r\n')
    return u''