Example #1
0
def allow_tag(session, idx):
    """
    Whether user is allowed to tag a message.

    :rtype: bool

    A user can tag a message if the given session's user is:

    * the message author or recipient.
    * a member of sysop or moderator group.
    * a member of any existing tag-matching user group.
    """
    moderated = get_ini('msg', 'moderated_tags', getter='getboolean')
    tag_moderators = set(get_ini('msg', 'tag_moderators', split=True))
    if not moderated and 'sysop' in session.user.groups:
        return True

    elif moderated and (tag_moderators | session.user.groups):
        # tags are moderated, but user is one of the moderator groups
        return True

    msg = get_msg(idx)
    if session.user.handle in (msg.recipient, msg.author):
        return True

    for tag in msg.tags:
        if tag in session.user.groups:
            return True
    return False
Example #2
0
def server(urls, funcs):
    """ Main server thread for running the web server """
    from x84.bbs import get_ini
    from web.wsgiserver import CherryPyWSGIServer
    from web.wsgiserver.ssl_pyopenssl import pyOpenSSLAdapter

    log = logging.getLogger(__name__)

    addr = get_ini(section='web',
                   key='addr'
                   ) or '0.0.0.0'

    port = get_ini(section='web',
                   key='port',
                   getter='getint'
                   ) or 8443

    app = web.application(urls, funcs)

    web.config.debug = False

    log.info('https listening on {addr}:{port}/tcp'
             .format(addr=addr, port=port))

    # Runs CherryPy WSGI server hosting WSGI app.wsgifunc().
    web.httpserver.runsimple(app.wsgifunc(), (addr, port))  # blocking
Example #3
0
File: sysop.py Project: gofore/x84
def view_leaf_msgnet(server_tag=None, board_id=None):
    if server_tag is None:
        server_tags = get_ini(section="msg", key="server_tags", split=True)
        if not server_tags:
            raise ValueError("no `server_tags' defined in ini file, " "section [msg].")
        # RECURSION
        for _st in server_tags:
            view_leaf_msgnet(server_tag=_st, board_id=None)
        return

    if board_id is None:
        board_ids = DBProxy("{0}keys".format(server_tag)).keys()
        for _bid in board_ids:
            # RECURSION
            view_leaf_msgnet(server_tag=server_tag, board_id=_bid)
        return

    with DBProxy("{0}keys".format(server_tag)) as key_db:
        echo(u"\r\n[msgnet_{0}]".format(server_tag))
        echo(u"\r\nurl_base = https://{addr}:{port}/".format(addr=get_ini("web", "addr"), port=get_ini("web", "port")))
        echo(u"\r\nboard_id = {0}".format(board_id))
        echo(u"\r\ntoken = {0}".format(key_db[board_id]))
        echo(u"\r\npoll_interval = 300")
        echo(u"\r\n")
        echo(u"\r\n[msg]")
        echo(u"\r\nnetwork_tags = {0}".format(server_tag))
    echo(u"\r\n")
    echo(u"-" * 40)
Example #4
0
def get_sesame_menu_items(session):
    # there doesn't exist any documentation on how this works,
    # only the given examples in the generated default.ini file
    menu_items = []
    if ini.CFG.has_section('sesame'):
        for name in filter(lambda _name: '_' not in _name,
                           ini.CFG.options('sesame')):

            sesame_kwargs = {'name': name}

            door_cmd = ini.CFG.get('sesame', name).split(None, 1)[0]
            if door_cmd.lower() == 'no' or not os.path.exists(door_cmd):
                # skip entry if path does not resolve, or set to 'no'
                continue

            inp_key = get_ini(section='sesame', key='{0}_key'.format(name))
            if not inp_key:
                raise ValueError('sesame configuration for "{0}" requires '
                                 'complimenting value "{0}_key" for menu '
                                 'input key.'.format(name))

            if get_ini(section='sesame', key='{0}_sysop_only'.format(name),
                       getter='getboolean') and not session.user.is_sysop:
                continue

            text = get_ini(
                section='sesame', key='{0}_text'.format(name)
            ) or name

            menu_items.append(
                MenuItem(inp_key=inp_key, text=text, script='sesame',
                         args=(), kwargs=sesame_kwargs))

    return menu_items
Example #5
0
def translate_ttype(ttype):
    """
    Return preferred terminal type given the session-negotiation ttype.

    This provides a kind of coercion; we know some terminals, such as
    SyncTerm report a terminal type of 'ansi' -- however, the author
    publishes a termcap database for 'ansi-bbs' which he instructs
    should be used!  So an ``[system]`` configuration item
    of ``termcap-ansi`` may be set to ``'ansi-bbs'`` to coerce
    such terminals for Syncterm-centric telnet servers -- though I
    would not recommend it.

    Furthermore, if the ttype is (literally) 'unknown', then a
    system-wide default terminal type may be returned, also by
    ``[system]`` configuration option ``termcap-unknown``.
    """
    from x84.bbs import get_ini
    log = logging.getLogger(__name__)

    termcap_unknown = get_ini('system', 'termcap-unknown') or 'ansi'
    termcap_ansi = get_ini('system', 'termcap-ansi') or 'ansi'

    if termcap_unknown != 'no' and ttype == 'unknown':
        log.debug("terminal-type {0!r} => {1!r}"
                  .format(ttype, termcap_unknown))
        return termcap_unknown

    elif (termcap_ansi != 'no' and ttype.lower().startswith('ansi')
          and ttype != termcap_ansi):
        log.debug("terminal-type {0!r} => {1!r}"
                  .format(ttype, termcap_ansi))
        return termcap_ansi

    return ttype
Example #6
0
def translate_ttype(ttype):
    """
    Return preferred terminal type given the session-negotiation ttype.

    This provides a kind of coercion; we know some terminals, such as
    SyncTerm report a terminal type of 'ansi' -- however, the author
    publishes a termcap database for 'ansi-bbs' which he instructs
    should be used!  So an ``[system]`` configuration item
    of ``termcap-ansi`` may be set to ``'ansi-bbs'`` to coerce
    such terminals for Syncterm-centric telnet servers -- though I
    would not recommend it.

    Furthermore, if the ttype is (literally) 'unknown', then a
    system-wide default terminal type may be returned, also by
    ``[system]`` configuration option ``termcap-unknown``.
    """
    from x84.bbs import get_ini
    log = logging.getLogger(__name__)

    termcap_unknown = get_ini('system', 'termcap-unknown') or 'ansi'
    termcap_ansi = get_ini('system', 'termcap-ansi') or 'ansi'

    if termcap_unknown != 'no' and ttype == 'unknown':
        log.debug("terminal-type {0!r} => {1!r}"
                  .format(ttype, termcap_unknown))
        return termcap_unknown

    elif (termcap_ansi != 'no' and ttype.lower().startswith('ansi')
          and ttype != termcap_ansi):
        log.debug("terminal-type {0!r} => {1!r}"
                  .format(ttype, termcap_ansi))
        return termcap_ansi

    return ttype
Example #7
0
def get_network_tag_description(term, colors):
    """ Return description text of message networks, if any. """
    server_tags = get_ini("msg", "server_tags", split=True)
    network_tags = get_ini("msg", "network_tags", split=True)

    if not (network_tags or server_tags):
        return u""
    return u"".join(
        (
            u"\r\n\r\n",
            colors["text"](u"This board participates in intra-bbs " "messaging, "),
            u"".join(
                (
                    colors["text"](u"hosting network messages by tag "),
                    u", ".join(quote(tag, colors) for tag in server_tags),
                )
            )
            if server_tags
            else u"",
            (colors["text"](u" and ") if (server_tags and network_tags) else u""),
            u"".join(
                (
                    colors["text"](u"participating in network messages by tag "),
                    u", ".join(quote(tag, colors) for tag in network_tags),
                )
            )
            if network_tags
            else u"",
            u".",
        )
    )
Example #8
0
def allow_tag(session, idx):
    """
    Whether user is allowed to tag a message.

    :rtype: bool

    A user can tag a message if the given session's user is:

    * the message author or recipient.
    * a member of sysop or moderator group.
    * a member of any existing tag-matching user group.
    """
    moderated = get_ini('msg', 'moderated_tags', getter='getboolean')
    tag_moderators = set(get_ini('msg', 'tag_moderators', split=True))
    if not moderated and 'sysop' in session.user.groups:
        return True

    elif moderated and (tag_moderators | session.user.groups):
        # tags are moderated, but user is one of the moderator groups
        return True

    msg = get_msg(idx)
    if session.user.handle in (msg.recipient, msg.author):
        return True

    for tag in msg.tags:
        if tag in session.user.groups:
            return True
    return False
Example #9
0
def view_leaf_msgnet(server_tag=None, board_id=None):
    if server_tag is None:
        server_tags = get_ini(section='msg', key='server_tags', split=True)
        if not server_tags:
            raise ValueError("no `server_tags' defined in ini file, "
                             "section [msg].")
        # RECURSION
        for _st in server_tags:
            view_leaf_msgnet(server_tag=_st, board_id=None)
        return

    if board_id is None:
        board_ids = DBProxy('{0}keys'.format(server_tag)).keys()
        for _bid in board_ids:
            # RECURSION
            view_leaf_msgnet(server_tag=server_tag, board_id=_bid)
        return

    with DBProxy('{0}keys'.format(server_tag)) as key_db:
        echo(u'\r\n[msgnet_{0}]'.format(server_tag))
        echo(u'\r\nurl_base = https://{addr}:{port}/'.format(
            addr=get_ini('web', 'addr'), port=get_ini('web', 'port')))
        echo(u'\r\nboard_id = {0}'.format(board_id))
        echo(u'\r\ntoken = {0}'.format(key_db[board_id]))
        echo(u'\r\npoll_interval = 300')
        echo(u'\r\n')
        echo(u'\r\n[msg]')
        echo(u'\r\nnetwork_tags = {0}'.format(server_tag))
    echo(u'\r\n')
    echo(u'-' * 40)
Example #10
0
def prompt_tags(session, term, msg, colors, public=True):
    xpos = max(0, (term.width // 2) - (80 // 2))

    # conditionally enforce tag moderation
    moderated = get_ini("msg", "moderated_tags", getter="getboolean")
    tag_moderators = set(get_ini("msg", "tag_moderators", split=True))

    # enforce 'public' tag
    if public and "public" not in msg.tags:
        msg.tags.add("public")
    elif not public and "public" in msg.tags:
        msg.tags.remove("public")

    # describe all available tags, as we oft want to do.
    do_describe_available_tags(term, colors)

    # and remind ourselves of the available network tags,
    description = get_network_tag_description(term, colors)
    if description:
        show_description(term=term, color=None, description=description)

    echo(
        u"".join(
            (term.move_x(xpos), term.clear_eos, u"Enter tags, separated by commas.\r\n", term.move_x(xpos), u":: ")
        )
    )

    all_tags = list_tags()

    while True:
        inp = LineEditor(
            subject_max_length, u", ".join(sorted(msg.tags)), colors={"highlight": colors["backlight"]}
        ).read()
        if inp is None:
            echo(u"".join((term.move_x(xpos), colors["highlight"]("Message canceled."), term.clear_eol)))
            term.inkey(1)
            return False

        msg.tags = set(filter(None, set(map(unicode.strip, inp.split(",")))))
        if moderated and not (tag_moderators | session.user.groups):
            cannot_tag = [_tag for _tag in msg.tags if _tag not in all_tags]
            if cannot_tag:
                echo(
                    u"".join(
                        (
                            u"\r\n",
                            term.move_x(xpos),
                            u", ".join((quote(tag, colors) for tag in cannot_tag)),
                            u": not allowed; this system is moderated.",
                        )
                    )
                )
                term.inkey(2)
                echo(term.move_up)
                map(msg.tags.remove, cannot_tag)
                continue

        return True
Example #11
0
File: userbase.py Project: hick/x84
def check_anonymous_user(username):
    """ Boolean return when user is anonymous and is allowed. """
    from x84.bbs import get_ini
    matching = get_ini(section='matrix', key='anoncmds', split=True)
    allowed = get_ini(section='matrix',
                      key='enable_anonymous',
                      getter='getboolean',
                      split=False)
    return allowed and username in matching
Example #12
0
File: userbase.py Project: hick/x84
def check_new_user(username):
    """ Boolean return when username matches `newcmds' ini cfg. """
    from x84.bbs import get_ini
    matching = get_ini(section='matrix',
                       key='newcmds',
                       split=True)
    allowed = get_ini(section='nua',
                      key='allow_apply',
                      getter='getboolean')
    return allowed and username in matching
Example #13
0
File: userbase.py Project: hick/x84
def check_anonymous_user(username):
    """ Boolean return when user is anonymous and is allowed. """
    from x84.bbs import get_ini
    matching = get_ini(section='matrix',
                       key='anoncmds',
                       split=True)
    allowed = get_ini(section='matrix',
                      key='enable_anonymous',
                      getter='getboolean',
                      split=False)
    return allowed and username in matching
Example #14
0
File: engine.py Project: hick/x84
def main():
    """
    x84 main entry point. The system begins and ends here.

    Command line arguments to engine.py:
      --config= location of alternate configuration file
      --logger= location of alternate logging.ini file
    """
    import x84.bbs.ini

    # load existing .ini files or create default ones.
    x84.bbs.ini.init(*parse_args())
    from x84.bbs import get_ini
    from x84.bbs.ini import CFG

    if sys.maxunicode == 65535:
        import warnings
        warnings.warn('Python not built with wide unicode support!')

    # retrieve list of managed servers
    servers = get_servers(CFG)

    # begin unmanaged servers
    if get_ini(section='web', key='modules'):
        # start https server for one or more web modules.
        #
        # may raise an ImportError for systems where pyOpenSSL and etc. could
        # not be installed (due to any issues with missing python-dev, libffi,
        # cc, etc.).  Allow it to raise naturally, the curious user should
        # either discover and resolve the root issue, or disable web modules if
        # it cannot be resolved.
        from x84 import webserve
        webserve.main()

    if get_ini(section='msg', key='network_tags'):
        # start background timer to poll for new messages
        # of message networks we may be a member of.
        from x84 import msgpoll
        msgpoll.main()

    try:
        # begin main event loop
        _loop(servers)
    except KeyboardInterrupt:
        # exit on ^C, killing any client sessions.
        from x84.terminal import kill_session
        for server in servers:
            for idx, thread in enumerate(server.threads[:]):
                if not thread.stopped:
                    thread.stopped = True
                server.threads.remove(thread)
            for key, client in server.clients.items()[:]:
                kill_session(client, 'server shutdown')
                del server.clients[key]
Example #15
0
def prompt_tags(session, term, msg, colors, public=True):
    xpos = max(0, (term.width // 2) - (80 // 2))

    # conditionally enforce tag moderation
    moderated = get_ini('msg', 'moderated_tags', getter='getboolean')
    tag_moderators = set(get_ini('msg', 'tag_moderators', split=True))

    # enforce 'public' tag
    if public and 'public' not in msg.tags:
        msg.tags.add('public')
    elif not public and 'public' in msg.tags:
        msg.tags.remove('public')

    # describe all available tags, as we oft want to do.
    do_describe_available_tags(term, colors)

    # and remind ourselves of the available network tags,
    description = get_network_tag_description(term, colors)
    if description:
        show_description(term=term, color=None, description=description)

    echo(u''.join(
        (term.move_x(xpos), term.clear_eos,
         u'Enter tags, separated by commas.\r\n', term.move_x(xpos), u':: ')))

    all_tags = list_tags()

    while True:
        inp = LineEditor(subject_max_length,
                         u', '.join(sorted(msg.tags)),
                         colors={
                             'highlight': colors['backlight']
                         }).read()
        if inp is None:
            echo(u''.join(
                (term.move_x(xpos), colors['highlight']('Message canceled.'),
                 term.clear_eol)))
            term.inkey(1)
            return False

        msg.tags = set(filter(None, set(map(unicode.strip, inp.split(',')))))
        if moderated and not (tag_moderators | session.user.groups):
            cannot_tag = [_tag for _tag in msg.tags if _tag not in all_tags]
            if cannot_tag:
                echo(u''.join((u'\r\n', term.move_x(xpos), u', '.join(
                    (quote(tag, colors) for tag in cannot_tag)),
                               u': not allowed; this system is moderated.')))
                term.inkey(2)
                echo(term.move_up)
                map(msg.tags.remove, cannot_tag)
                continue

        return True
Example #16
0
def get_networks():
    " Get configured message networks. "
    from x84.bbs import get_ini

    log = logging.getLogger(__name__)

    # pull list of network-associated tags
    network_list = get_ini(section='msg',
                           key='network_tags',
                           split=True,
                           splitsep=',')

    # expected configuration options,
    net_options = ('url_base token board_id'.split())

    networks = list()
    for net_name in network_list:
        net = {'name': net_name}

        section = 'msgnet_{0}'.format(net_name)
        configured = True
        for option in net_options:
            if not get_ini(section=section, key=option):
                log.error('[{net_name}] Missing configuration, '
                          'section=[{section}], option={option}.'.format(
                              net_name=net_name,
                              section=section,
                              option=option))
                configured = False
            net[option] = get_ini(section=section, key=option)
        if not configured:
            continue

        # make last_file an absolute path, relative to `datapath`
        net['last_file'] = os.path.join(
            os.path.expanduser(get_ini(section='system', key='datapath')),
            '{net[name]}_last'.format(net=net))

        net['verify'] = True
        ca_path = get_ini(section=section, key='ca_path')
        if ca_path:
            ca_path = os.path.expanduser(ca_path)
            if not os.path.isfile(ca_path):
                log.warn("File not found for Config section [{section}], "
                         "option {key}, value={ca_path}.  default ca_verify "
                         "will be used. ".format(section=section,
                                                 key='ca_path',
                                                 value=ca_path))
            else:
                net['verify'] = ca_path

        networks.append(net)
    return networks
Example #17
0
File: msgpoll.py Project: hick/x84
def get_networks():
    " Get configured message networks. "
    from x84.bbs import get_ini

    log = logging.getLogger(__name__)

    # pull list of network-associated tags
    network_list = get_ini(section='msg',
                           key='network_tags',
                           split=True,
                           splitsep=',')

    # expected configuration options,
    net_options = ('url_base token board_id'.split())

    networks = list()
    for net_name in network_list:
        net = {'name': net_name}

        section = 'msgnet_{0}'.format(net_name)
        configured = True
        for option in net_options:
            if not get_ini(section=section, key=option):
                log.error('[{net_name}] Missing configuration, '
                          'section=[{section}], option={option}.'
                          .format(net_name=net_name,
                                  section=section,
                                  option=option))
                configured = False
            net[option] = get_ini(section=section, key=option)
        if not configured:
            continue

        # make last_file an absolute path, relative to `datapath`
        net['last_file'] = os.path.join(
            os.path.expanduser(get_ini(section='system', key='datapath')),
            '{net[name]}_last'.format(net=net))

        net['verify'] = True
        ca_path = get_ini(section=section, key='ca_path')
        if ca_path:
            ca_path = os.path.expanduser(ca_path)
            if not os.path.isfile(ca_path):
                log.warn("File not found for Config section [{section}], "
                         "option {key}, value={ca_path}.  default ca_verify "
                         "will be used. ".format(section=section,
                                                 key='ca_path',
                                                 value=ca_path))
            else:
                net['verify'] = ca_path

        networks.append(net)
    return networks
Example #18
0
def do_dropfile(name, node):
    dropfile_path = get_ini('sesame', '{0}_droppath'.format(name))
    dropfile_type = get_ini('sesame', '{0}_droptype'.format(name)) or 'doorsys'
    if not dropfile_path:
        return

    dropfile_type = dropfile_type.upper()

    if not hasattr(Dropfile, dropfile_type):
        raise ValueError('sesame configuration declares dropfile '
                         'format of {0!r} but value is not supported '
                         'by class Dropfile.'.format(dropfile_type))

    _dropfile_type = getattr(Dropfile, dropfile_type)
    Dropfile(_dropfile_type, node).save(dropfile_path)
Example #19
0
File: sysop.py Project: gofore/x84
def add_leaf_msgnet():
    import cryptography.fernet

    server_tags = get_ini(section="msg", key="server_tags", split=True)
    if not server_tags:
        raise ValueError(MSG_NO_SERVER_TAGS)

    if len(server_tags) == 1:
        server_tag = server_tags[0]
    else:
        while True:
            echo("chose a server tag: ")
            idx = 0
            for idx, tag in server_tags:
                echo(u"\r\n{0}. {1}".format(idx, tag))
            echo(u"\r\n: ")
            inp = LineEditor(width=len(str(idx)).read())
            if inp is None:
                return
            try:
                server_tag = server_tags[int(inp)]
                break
            except ValueError:
                pass

    with DBProxy("{0}keys".format(server_tag)) as key_db:
        board_id = max(map(int, key_db.keys()) or [-1]) + 1
        client_key = cryptography.fernet.Fernet.generate_key()
        key_db[board_id] = client_key
    echo(u"\r\n")
    echo(u"-" * 40)
    view_leaf_msgnet(server_tag, board_id)
Example #20
0
File: sesame.py Project: rostob/x84
def do_dropfile(name, node):
    dropfile_path = get_ini('sesame', '{0}_droppath'.format(name))
    dropfile_type = get_ini('sesame', '{0}_droptype'.format(name)
                            ) or 'doorsys'
    if not dropfile_path:
        return

    dropfile_type = dropfile_type.upper()

    if not hasattr(Dropfile, dropfile_type):
        raise ValueError('sesame configuration declares dropfile '
                         'format of {0!r} but value is not supported '
                         'by class Dropfile.'.format(dropfile_type))

    _dropfile_type = getattr(Dropfile, dropfile_type)
    Dropfile(_dropfile_type, node).save(dropfile_path)
Example #21
0
 def __init__(self, client, sid, master_pipes):
     """ Class constructor. """
     from x84.bbs import get_ini
     self.client = client
     self.sid = sid
     (self.master_write, self.master_read) = master_pipes
     self.timeout = get_ini('system', 'timeout') or 0
Example #22
0
def add_leaf_msgnet():
    import cryptography.fernet
    server_tags = get_ini(section='msg', key='server_tags', split=True)
    if not server_tags:
        raise ValueError(MSG_NO_SERVER_TAGS)

    if len(server_tags) == 1:
        server_tag = server_tags[0]
    else:
        while True:
            echo('chose a server tag: ')
            idx = 0
            for idx, tag in server_tags:
                echo(u'\r\n{0}. {1}'.format(idx, tag))
            echo(u'\r\n: ')
            inp = LineEditor(width=len(str(idx)).read())
            if inp is None:
                return
            try:
                server_tag = server_tags[int(inp)]
                break
            except ValueError:
                pass

    with DBProxy('{0}keys'.format(server_tag)) as key_db:
        board_id = max(map(int, key_db.keys()) or [-1]) + 1
        client_key = cryptography.fernet.Fernet.generate_key()
        key_db[board_id] = client_key
    echo(u'\r\n')
    echo(u'-' * 40)
    view_leaf_msgnet(server_tag, board_id)
Example #23
0
def main(background_daemon=True):
    """
    Entry point to configure and begin network message polling.

    Called by x84/engine.py, function main() as unmanaged thread.

    :param background_daemon: When True (default), this function returns and
      web modules are served in an unmanaged, background (daemon) thread.
      Otherwise, function call to ``main()`` is blocking.
    :type background_daemon: bool
    :rtype: None
    """
    from threading import Thread
    from x84.bbs import get_ini

    log = logging.getLogger(__name__)

    poll_interval = get_ini(
        section='msg', key='poll_interval', getter='getint') or 1984

    if background_daemon:
        t = Thread(target=poller, args=(poll_interval, ))
        t.daemon = True
        log.info('msgpoll at {0}s intervals.'.format(poll_interval))
        t.start()
    else:
        poller(poll_interval)
Example #24
0
def init_term(writer, env):
    """
    Determine the final TERM and encoding and return a Terminal.

    curses is initialized using the value of 'TERM' of dictionary env,
    as well as a starting window size of 'LINES' and 'COLUMNS'. If the
    terminal-type is of 'ansi' or 'ansi-bbs', then the cp437 encoding
    is assumed; otherwise 'utf8'.

    A blessed-abstracted curses terminal is returned.
    """
    from x84.bbs.ipc import IPCStream
    from x84.bbs import get_ini
    log = logging.getLogger(__name__)
    env['TERM'] = translate_ttype(env.get('TERM', 'unknown'))
    env['encoding'] = determine_encoding(env)
    term = Terminal(kind=env['TERM'],
                    stream=IPCStream(writer=writer),
                    rows=int(env.get('LINES', '24')),
                    columns=int(env.get('COLUMNS', '80')))

    if term.kind is None:
        # the given environment's TERM failed curses initialization
        # because, more than likely, the TERM type was not found.
        termcap_unknown = get_ini('system', 'termcap-unknown') or 'ansi'
        log.debug('terminal-type {0} failed, using {1} instead.'
                  .format(env['TERM'], termcap_unknown))
        term = Terminal(kind=termcap_unknown,
                        stream=IPCStream(writer=writer),
                        rows=int(env.get('LINES', '24')),
                        columns=int(env.get('COLUMNS', '80')))

    log.info("terminal type is {0!r}".format(term.kind))
    return term
Example #25
0
File: msgpoll.py Project: hick/x84
def main(background_daemon=True):
    """
    Entry point to configure and begin network message polling.

    Called by x84/engine.py, function main() as unmanaged thread.

    :param background_daemon: When True (default), this function returns and
      web modules are served in an unmanaged, background (daemon) thread.
      Otherwise, function call to ``main()`` is blocking.
    :type background_daemon: bool
    :rtype: None
    """
    from threading import Thread
    from x84.bbs import get_ini

    log = logging.getLogger(__name__)

    poll_interval = get_ini(section='msg',
                            key='poll_interval',
                            getter='getint'
                            ) or 1984

    if background_daemon:
        t = Thread(target=poller, args=(poll_interval,))
        t.daemon = True
        log.info('msgpoll at {0}s intervals.'.format(poll_interval))
        t.start()
    else:
        poller(poll_interval)
Example #26
0
def init_term(writer, env):
    """
    Determine the final TERM and encoding and return a Terminal.

    curses is initialized using the value of 'TERM' of dictionary env,
    as well as a starting window size of 'LINES' and 'COLUMNS'. If the
    terminal-type is of 'ansi' or 'ansi-bbs', then the cp437 encoding
    is assumed; otherwise 'utf8'.

    A blessed-abstracted curses terminal is returned.
    """
    from x84.bbs.ipc import IPCStream
    from x84.bbs import get_ini
    log = logging.getLogger(__name__)
    env['TERM'] = translate_ttype(env.get('TERM', 'unknown'))
    env['encoding'] = determine_encoding(env)
    term = Terminal(kind=env['TERM'],
                    stream=IPCStream(writer=writer),
                    rows=int(env.get('LINES', '24')),
                    columns=int(env.get('COLUMNS', '80')))

    if term.kind is None:
        # the given environment's TERM failed curses initialization
        # because, more than likely, the TERM type was not found.
        termcap_unknown = get_ini('system', 'termcap-unknown') or 'ansi'
        log.debug('terminal-type {0} failed, using {1} instead.'
                  .format(env['TERM'], termcap_unknown))
        term = Terminal(kind=termcap_unknown,
                        stream=IPCStream(writer=writer),
                        rows=int(env.get('LINES', '24')),
                        columns=int(env.get('COLUMNS', '80')))

    log.info("terminal type is {0!r}".format(term.kind))
    return term
Example #27
0
 def __init__(self, client, sid, master_pipes):
     """ Class constructor. """
     from x84.bbs import get_ini
     self.client = client
     self.sid = sid
     (self.master_write, self.master_read) = master_pipes
     self.timeout = get_ini('system', 'timeout') or 0
Example #28
0
def main(name):
    """ Sesame runs a named door. """
    session, term = getsession(), getterminal()

    # clear screen,
    echo(term.normal + u'\r\n' * term.height + term.move(0, 0))

    # set font,
    if term.kind.startswith('ansi'):
        syncterm_font = get_ini('sesame',
                                '{0}_syncterm_font'.format(name)) or 'cp437'
        echo(syncterm_setfont(syncterm_font))
        echo(term.move_x(0) + term.clear_eol)

    # pylint: disable=W0212
    #         Access to a protected member {_columns, _rows} of a client class
    store_columns, store_rows = term._columns, term._rows
    if not prompt_resize_term(session, term, name):
        return

    with acquire_node(session, name) as node:

        if node == -1:
            echo(
                term.bold_red('This door has reached the maximum number '
                              'of nodes and may not be played.\r\n\r\n'
                              'press any key.'))
            term.inkey()
            restore_screen(term, store_columns, store_rows)
            return

        do_dropfile(name, node)

        session.activity = u'Playing {}'.format(name)

        cmd, args = parse_command_args(session, name, node)
        env = get_env(session, name)
        cp437 = get_ini('sesame',
                        '{0}_cp437'.format(name),
                        getter='getboolean')

        _Door = DOSDoor if cmd.endswith('dosemu') else Door
        _Door(cmd=cmd, args=args, env=env, cp437=cp437).run()

    echo(term.bold_red + 'Press a key...')
    term.inkey()
    restore_screen(term, store_columns, store_rows)
Example #29
0
def main():
    """
    x84 main entry point. The system begins and ends here.

    Command line arguments to engine.py:

    - ``--config=`` location of alternate configuration file
    - ``--logger=`` location of alternate logging.ini file
    """
    import x84.bbs.ini

    # load existing .ini files or create default ones.
    x84.bbs.ini.init(*parse_args())
    from x84.bbs import get_ini
    from x84.bbs.ini import CFG

    if sys.maxunicode == 65535:
        # apple is the only known bastardized variant that does this;
        # presumably for memory/speed savings (UCS-2 strings are faster
        # than UCS-4).  Python 3 dynamically allocates string types by
        # their widest content, so such things aren't necessary ...
        import warnings
        warnings.warn('This python is built without wide unicode support. '
                      'some internationalized languages will not be possible.')

    # retrieve list of managed servers
    servers = get_servers(CFG)

    # begin unmanaged servers
    if (CFG.has_section('web') and
            (not CFG.has_option('web', 'enabled')
             or CFG.getboolean('web', 'enabled'))):
        # start https server for one or more web modules.
        from x84 import webserve
        webserve.main()

    if get_ini(section='msg', key='network_tags'):
        # start background timer to poll for new messages
        # of message networks we may be a member of.
        from x84 import msgpoll
        msgpoll.main()

    try:
        # begin main event loop
        _loop(servers)
    except KeyboardInterrupt:
        # exit on ^C, killing any client sessions.
        from x84.terminal import kill_session
        for server in servers:
            for idx, thread in enumerate(server.threads[:]):
                if not thread.stopped:
                    thread.stopped = True
                server.threads.remove(thread)
            for key, client in server.clients.items()[:]:
                kill_session(client, 'server shutdown')
                del server.clients[key]
    return 0
Example #30
0
def display_prompt(term, colors):
    """ Return string for displaying a system-wide command prompt. """
    colors['lowlight'] = colors.get('lowlight', lambda txt: txt)
    bbsname = get_ini(section='system', key='bbsname') or 'Unnamed'
    return (u'{user}{at}{bbsname}{colon} '.format(
        user=term.session.user.handle,
        at=colors['lowlight'](u'@'),
        bbsname=bbsname,
        colon=colors['lowlight'](u'::')))
Example #31
0
def main():
    """
    x84 main entry point. The system begins and ends here.

    Command line arguments to engine.py:

    - ``--config=`` location of alternate configuration file
    - ``--logger=`` location of alternate logging.ini file
    """
    # load existing .ini files or create default ones.
    import x84.bbs.ini
    x84.bbs.ini.init(*cmdline.parse_args())

    from x84.bbs import get_ini
    from x84.bbs.ini import CFG

    if sys.maxunicode == 65535:
        # apple is the only known bastardized variant that does this;
        # presumably for memory/speed savings (UCS-2 strings are faster
        # than UCS-4).  Python 3 dynamically allocates string types by
        # their widest content, so such things aren't necessary, there.
        import warnings
        warnings.warn('This python is built without wide unicode support. '
                      'some internationalized languages will not be possible.')

    # retrieve list of managed servers
    servers = get_servers(CFG)

    # begin unmanaged servers
    if (CFG.has_section('web') and
            (not CFG.has_option('web', 'enabled')
             or CFG.getboolean('web', 'enabled'))):
        # start https server for one or more web modules.
        from x84 import webserve
        webserve.main()

    if get_ini(section='msg', key='network_tags'):
        # start background timer to poll for new messages
        # of message networks we may be a member of.
        from x84 import msgpoll
        msgpoll.main()

    try:
        # begin main event loop
        _loop(servers)
    except KeyboardInterrupt:
        # exit on ^C, killing any client sessions.
        for server in servers:
            for thread in server.threads[:]:
                if not thread.stopped:
                    thread.stopped = True
                server.threads.remove(thread)
            for key, client in server.clients.items()[:]:
                kill_session(client, 'server shutdown')
                del server.clients[key]
    return 0
Example #32
0
    def queue_for_network(self):
        " Queue message for networks, hosting or sending. "
        from x84.bbs import get_ini

        log = logging.getLogger(__name__)

        # server networks this server is a member of,
        member_networks = get_ini(section='msg',
                                  key='network_tags',
                                  split=True,
                                  splitsep=',')

        # server networks offered by this server,
        my_networks = get_ini(section='msg',
                              key='server_tags',
                              split=True,
                              splitsep=',')

        # check all tags of message; if they match a message network,
        # either record for hosting servers, or schedule for delivery.
        for tag in self.tags:
            section = 'msgnet_{tag}'.format(tag=tag)

            # message is for a network we host
            if tag in my_networks:
                section = 'msgnet_{tag}'.format(tag=tag)
                transdb_name = CFG.get(section, 'trans_db_name')
                transdb = DBProxy(transdb_name)
                with transdb:
                    self.body = u''.join((self.body, format_origin_line()))
                    self.save()
                    transdb[self.idx] = self.idx
                log.info('[{tag}] Stored for network (msgid {self.idx}).'
                         .format(tag=tag, self=self))

            # message is for a another network, queue for delivery
            elif tag in member_networks:
                queuedb_name = CFG.get(section, 'queue_db_name')
                queuedb = DBProxy(queuedb_name)
                with queuedb:
                    queuedb[self.idx] = tag
                log.info('[{tag}] Message (msgid {self.idx}) queued '
                         'for delivery'.format(tag=tag, self=self))
Example #33
0
def translate_ttype(ttype):
    from x84.bbs import get_ini
    log = logging.getLogger(__name__)

    termcap_unknown = get_ini('system', 'termcap-unknown') or 'ansi'
    termcap_ansi = get_ini('system', 'termcap-ansi') or 'ansi'

    if termcap_unknown != 'no' and ttype == 'unknown':
        log.debug("terminal-type {0!r} => {1!r}"
                  .format(ttype, termcap_unknown))
        return termcap_unknown

    elif (termcap_ansi != 'no' and ttype.lower().startswith('ansi')
          and ttype != termcap_ansi):
        log.debug("terminal-type {0!r} => {1!r}"
                  .format(ttype, termcap_ansi))
        return termcap_ansi

    return ttype
Example #34
0
File: ssh.py Project: rostob/x84
    def check_channel_subsystem_request(self, channel, name):
        from x84.bbs import get_ini
        if name == 'sftp':
            if get_ini(section='sftp', key='enabled', getter='getboolean'):
                self.client.kind = 'sftp'
                self.sftp_requested.set()
                self.sftp = True

        return paramiko.ServerInterface.check_channel_subsystem_request(
            self, channel, name)
Example #35
0
    def check_channel_subsystem_request(self, channel, name):
        from x84.bbs import get_ini
        if name == 'sftp':
            if get_ini(section='sftp', key='enabled', getter='getboolean'):
                self.client.kind = 'sftp'
                self.sftp_requested.set()
                self.sftp = True

        return paramiko.ServerInterface.check_channel_subsystem_request(
            self, channel, name)
Example #36
0
File: sesame.py Project: rostob/x84
def main(name):
    """ Sesame runs a named door. """
    session, term = getsession(), getterminal()

    # clear screen,
    echo(term.normal + u'\r\n' * term.height + term.move(0, 0))

    # set font,
    if term.kind.startswith('ansi'):
        syncterm_font = get_ini(
            'sesame', '{0}_syncterm_font'.format(name)) or 'cp437'
        echo(syncterm_setfont(syncterm_font))
        echo(term.move_x(0) + term.clear_eol)

    # pylint: disable=W0212
    #         Access to a protected member {_columns, _rows} of a client class
    store_columns, store_rows = term._columns, term._rows
    if not prompt_resize_term(session, term, name):
        return

    with acquire_node(session, name) as node:

        if node == -1:
            echo(term.bold_red('This door has reached the maximum number '
                               'of nodes and may not be played.\r\n\r\n'
                               'press any key.'))
            term.inkey()
            restore_screen(term, store_columns, store_rows)
            return

        do_dropfile(name, node)

        session.activity = u'Playing {}'.format(name)

        cmd, args = parse_command_args(session, name, node)
        env = get_env(session, name)
        cp437 = get_ini('sesame', '{0}_cp437'.format(name),
                        getter='getboolean')

        _Door = DOSDoor if cmd.endswith('dosemu') else Door
        _Door(cmd=cmd, args=args, env=env, cp437=cp437).run()

    restore_screen(term, store_columns, store_rows)
Example #37
0
def main(background_daemon=True):
    """
    Entry point to configure and begin web server.

    Called by x84/engine.py, function main() as unmanaged thread.

    :param background_daemon: When True (default), this function returns and
      web modules are served in an unmanaged, background (daemon) thread.
      Otherwise, function call to ``main()`` is blocking.
    :type background_daemon: bool
    :rtype: None
    """
    from x84.bbs import get_ini

    log = logging.getLogger(__name__)

    SCRIPT_PATH = get_ini(section='system', key='scriptpath')

    # ensure the SCRIPT_PATH is in os environment PATH for module lookup.
    sys.path.insert(0, os.path.expanduser(SCRIPT_PATH))

    web_modules = get_ini(section='web',
                          key='modules',
                          split=True,
                          splitsep=',')

    if not web_modules:
        log.debug('No `modules` defined in section [web]')
        return

    log.info(u'Ready web modules: {0}'.format(web_modules))
    urls, funcs = get_urls_funcs(web_modules)

    if background_daemon:
        t = threading.Thread(target=server, args=(
            urls,
            funcs,
        ))
        t.daemon = True
        t.start()
    else:
        server(urls=urls, funcs=funcs)
Example #38
0
File: ssh.py Project: tehmaze/x84
    def check_channel_subsystem_request(self, channel, name):
        from x84.bbs import get_ini
        if name == 'sftp':
            if get_ini(section='sftp', key='enabled', getter='getboolean'):
                self.client.kind = 'sftp'
                self.sftp_requested.set()
                self.sftp = True
                # XXX not returning True ?!

        return (super(SshSessionServer, self)
                .check_channel_subsystem_request(channel, name))
Example #39
0
def prompt_resize_term(session, term, name):
    want_cols = get_ini('sesame', '{0}_cols'.format(name), getter='getint')
    want_rows = get_ini('sesame', '{0}_rows'.format(name), getter='getint')

    if want_cols and want_rows and not term.kind.startswith('ansi'):
        while not (term.width == want_cols and term.height == want_rows):
            resize_msg = (u'Please resize your window to {0} x {1} '
                          u'current size is {term.width} x {term.height} '
                          u'or press return.  Press escape to cancel.'.format(
                              want_cols, want_rows, term=term))
            echo(term.normal + term.home + term.clear_eos + term.home)
            pager = Pager(yloc=0,
                          xloc=0,
                          width=want_cols,
                          height=want_rows,
                          colors={'border': term.bold_red})
            echo(term.move(term.height - 1, term.width))

            echo(pager.refresh() + pager.border())

            width = min(70, term.width - 5)
            for yoff, line in enumerate(term.wrap(resize_msg, width)):
                echo(u''.join((term.move(yoff + 1, 5), line.rstrip())))

            event, data = session.read_events(('input', 'refresh'))
            if event == 'refresh':
                continue

            if event == 'input':
                session.buffer_input(data, pushback=True)
                inp = term.inkey(0)
                while inp:
                    if inp.code == term.KEY_ENTER:
                        echo(term.normal + term.home + term.clear_eos)
                        return True
                    if inp.code == term.KEY_ESCAPE:
                        return False
                    inp = term.inkey(0)
        return True
    # if terminal type is 'ansi', just pass-through
    return True
Example #40
0
def determine_encoding(env):
    """ Determine and return preferred encoding given session env. """
    from x84.bbs import get_ini
    default_encoding = get_ini(section='session',
                               key='default_encoding') or 'utf8'

    fallback_encoding = {
        'ansi': 'cp437',
        'ansi-bbs': 'cp437',
    }.get(env['TERM'], default_encoding)

    return env.get('encoding', fallback_encoding)
Example #41
0
    def queue_for_network(self):
        " Queue message for networks, hosting or sending. "
        from x84.bbs import get_ini

        log = logging.getLogger(__name__)

        # server networks this server is a member of,
        member_networks = get_ini(section='msg',
                                  key='network_tags',
                                  split=True,
                                  splitsep=',')

        # server networks offered by this server,
        my_networks = get_ini(section='msg',
                              key='server_tags',
                              split=True,
                              splitsep=',')

        # check all tags of message; if they match a message network,
        # either record for hosting servers, or schedule for delivery.
        for tag in self.tags:
            # message is for a network we host
            if tag in my_networks:
                transdb = DBProxy('{0}trans'.format(tag))
                with transdb:
                    self.body = u''.join((self.body, format_origin_line()))
                    self.save()
                    transdb[self.idx] = self.idx
                log.info(
                    '[{tag}] Stored for network (msgid {self.idx}).'.format(
                        tag=tag, self=self))

            # message is for a another network, queue for delivery
            elif tag in member_networks:
                queuedb = DBProxy('{0}queues'.format(tag))
                with queuedb:
                    queuedb[self.idx] = tag
                log.info('[{tag}] Message (msgid {self.idx}) queued '
                         'for delivery'.format(tag=tag, self=self))
Example #42
0
def prompt_resize_term(session, term, name):
    want_cols = get_ini('sesame', '{0}_cols'.format(name), getter='getint')
    want_rows = get_ini('sesame', '{0}_rows'.format(name), getter='getint')

    if want_cols and want_rows and not term.kind.startswith('ansi'):
        while not (term.width == want_cols and
                   term.height == want_rows):
            resize_msg = (u'Please resize your window to {0} x {1} '
                          u'current size is {term.width} x {term.height} '
                          u'or press return.  Press escape to cancel.'
                          .format(want_cols, want_rows, term=term))
            echo(term.normal + term.home + term.clear_eos + term.home)
            pager = Pager(yloc=0, xloc=0, width=want_cols, height=want_rows,
                          colors={'border': term.bold_red})
            echo(term.move(term.height - 1, term.width))

            echo(pager.refresh() + pager.border())

            width = min(70, term.width - 5)
            for yoff, line in enumerate(term.wrap(resize_msg, width)):
                echo(u''.join((term.move(yoff + 1, 5), line.rstrip())))

            event, data = session.read_events(('input', 'refresh'))
            if event == 'refresh':
                continue

            if event == 'input':
                session.buffer_input(data, pushback=True)
                inp = term.inkey(0)
                while inp:
                    if inp.code == term.KEY_ENTER:
                        echo(term.normal + term.home + term.clear_eos)
                        return True
                    if inp.code == term.KEY_ESCAPE:
                        return False
                    inp = term.inkey(0)
        return True
    # if terminal type is 'ansi', just pass-through
    return True
Example #43
0
def display_prompt(term, colors):
    """ Return string for displaying a system-wide command prompt. """
    colors['lowlight'] = colors.get('lowlight', lambda txt: txt)
    bbsname = get_ini(section='system', key='bbsname') or 'Unnamed'
    xpos = 0
    if term.width > 30:
        xpos = max(5, int((term.width / 2) - (80 / 2)))
    return (u'{xpos}{user}{at}{bbsname}{colon} '.format(
        xpos=term.move_x(xpos),
        user=term.session.user.handle,
        at=colors['lowlight'](u'@'),
        bbsname=bbsname,
        colon=colors['lowlight'](u'::')))
Example #44
0
    def __init__(self, *args, **kwargs):
        """ Class initializer. """
        from x84.bbs import get_ini
        self.log = logging.getLogger(__name__)

        # root file folder,
        self.root = get_ini(section='sftp', key='root')

        # default file mode for uploaded files,
        _base = 8  # (value is octal!)
        self.mode = int(
            get_ini(section='sftp', key='uploads_filemode') or '644', _base)

        # allow anonymous login where enabled, otherwise use the
        # given `username' authenticated by ssh
        from x84.bbs.userbase import get_user, User
        _ssh_session = kwargs.pop('ssh_session')
        self.user = (User(u'anonymous') if _ssh_session.anonymous else
                     get_user(_ssh_session.username))
        self.flagged = set()

        SFTPServerInterface.__init__(self, *args, **kwargs)
Example #45
0
def determine_encoding(env):
    """ Determine and return preferred encoding given session env. """
    from x84.bbs import get_ini
    default_encoding = get_ini(
        section='session', key='default_encoding'
    ) or 'utf8'

    fallback_encoding = {
        'ansi': 'cp437',
        'ansi-bbs': 'cp437',
    }.get(env['TERM'], default_encoding)

    return env.get('encoding', fallback_encoding)
Example #46
0
    def __init__(self, *args, **kwargs):
        """ Class initializer. """
        from x84.bbs import get_ini
        self.log = logging.getLogger(__name__)

        # root file folder,
        self.root = get_ini(section='sftp', key='root')

        # default file mode for uploaded files,
        _base = 8  # (value is octal!)
        self.mode = int(get_ini(
            section='sftp', key='uploads_filemode') or '644', _base)

        # allow anonymous login where enabled, otherwise use the
        # given `username' authenticated by ssh
        from x84.bbs.userbase import get_user, User
        _ssh_session = kwargs.pop('ssh_session')
        self.user = (User(u'anonymous') if _ssh_session.anonymous
                     else get_user(_ssh_session.username))
        self.flagged = set()

        SFTPServerInterface.__init__(self, *args, **kwargs)
Example #47
0
File: webserve.py Project: hick/x84
def main(background_daemon=True):
    """
    Entry point to configure and begin web server.

    Called by x84/engine.py, function main() as unmanaged thread.

    :param background_daemon: When True (default), this function returns and
      web modules are served in an unmanaged, background (daemon) thread.
      Otherwise, function call to ``main()`` is blocking.
    :type background_daemon: bool
    :rtype: None
    """
    from x84.bbs import get_ini

    log = logging.getLogger(__name__)

    SCRIPT_PATH = get_ini(section='system', key='scriptpath')

    # ensure the SCRIPT_PATH is in os environment PATH for module lookup.
    sys.path.insert(0, os.path.expanduser(SCRIPT_PATH))

    web_modules = get_ini(section='web',
                          key='modules',
                          split=True,
                          splitsep=',')

    if not web_modules:
        log.debug('No `modules` defined in section [web]')
        return

    log.info(u'Ready web modules: {0}'.format(web_modules))
    urls, funcs = get_urls_funcs(web_modules)

    if background_daemon:
        t = threading.Thread(target=server, args=(urls, funcs,))
        t.daemon = True
        t.start()
    else:
        server(urls=urls, funcs=funcs)
Example #48
0
def display_prompt(term, colors):
    """ Return string for displaying a system-wide command prompt. """
    colors['lowlight'] = colors.get('lowlight', lambda txt: txt)
    bbsname = get_ini(section='system', key='bbsname') or 'Unnamed'
    xpos = 0
    if term.width > 30:
        xpos = max(5, int((term.width / 2) - (80 / 2)))
    return (u'{xpos}{user}{at}{bbsname}{colon} '.format(
        xpos=term.move_x(xpos),
        user=term.session.user.handle,
        at=colors['lowlight'](u'@'),
        bbsname=bbsname,
        colon=colors['lowlight'](u'::')))
Example #49
0
def get_network_tag_description(term, colors):
    """ Return description text of message networks, if any. """
    server_tags = get_ini('msg', 'server_tags', split=True)
    network_tags = get_ini('msg', 'network_tags', split=True)

    if not (network_tags or server_tags):
        return u''
    return u''.join((
        u'\r\n\r\n',
        colors['text'](u'This board participates in intra-bbs '
                       'messaging, '),
        u''.join((
            colors['text'](u'hosting network messages by tag '),
            u', '.join(quote(tag, colors) for tag in server_tags),
        )) if server_tags else u'',
        (colors['text'](u' and ') if (server_tags and network_tags) else u''),
        u''.join((
            colors['text'](u'participating in network messages by tag '),
            u', '.join(quote(tag, colors) for tag in network_tags),
        )) if network_tags else u'',
        u'.',
    ))
Example #50
0
def get_network_tag_description(term, colors):
    """ Return description text of message networks, if any. """
    server_tags = get_ini('msg', 'server_tags', split=True)
    network_tags = get_ini('msg', 'network_tags', split=True)

    if not (network_tags or server_tags):
        return u''
    return u''.join((
        u'\r\n\r\n',
        colors['text'](u'This board participates in intra-bbs '
                       'messaging, '),
        u''.join((
            colors['text'](u'hosting network messages by tag '),
            u', '.join(quote(tag, colors) for tag in server_tags),
        )) if server_tags else u'',
        (colors['text'](
            u' and ') if (server_tags and network_tags) else u''),
        u''.join((
            colors['text'](u'participating in network messages by tag '),
            u', '.join(quote(tag, colors) for tag in network_tags),
        )) if network_tags else u'',
        u'.',
    ))
Example #51
0
File: sftp.py Project: tehmaze/x84
    def __init__(self, *args, **kwargs):
        from x84.bbs import get_ini
        self.log = logging.getLogger(__name__)

        # root file folder,
        self.root = get_ini(section='sftp', key='root')

        # default file mode for uploaded files,
        _base = 8  # (value is octal!)
        self.mode = int(get_ini(
            section='sftp', key='uploads_filemode') or '644', _base)

        # allow anonymous login where enabled, otherwise use the
        # given `username' authenticated by ssh
        from x84.bbs.userbase import get_user, User
        _ssh_session = kwargs.pop('ssh_session')
        self.user = (User(u'anonymous') if _ssh_session.anonymous
                     else get_user(_ssh_session.username))

        # XXX this means if a user interactively flags files, they have to
        # re-sftp login to see them, we should fix this
        self.flagged = self.user.get('flaggedfiles', set())

        super(X84SFTPServer, self).__init__(*args, **kwargs)
Example #52
0
File: ol.py Project: rostob/x84
def add_oneline(session, message):
    """ Add a oneliner to the local database. """
    udb = DBProxy('oneliner')
    with udb:
        key = max([int(key) for key in udb.keys()] or [0]) + 1
        udb[key] = {
            'oneliner': message,
            'alias': getsession().user.handle,
            'bbsname': get_ini('system', 'bbsname'),
            'timestamp': time.strftime('%Y-%m-%d %H:%M:%S'),
        }
    maybe_expunge_records()

    # tell everybody a new oneliner was posted, including our
    # -- allows it to work something like a chatroom.
    session.send_event('global', ('oneliner', True))
Example #53
0
def add_oneline(session, message):
    """ Add a oneliner to the local database. """
    udb = DBProxy('oneliner')
    with udb:
        key = max([int(key) for key in udb.keys()] or [0]) + 1
        udb[key] = {
            'oneliner': message,
            'alias': getsession().user.handle,
            'bbsname': get_ini('system', 'bbsname'),
            'timestamp': time.strftime('%Y-%m-%d %H:%M:%S'),
        }
    maybe_expunge_records()

    # tell everybody a new oneliner was posted, including our
    # -- allows it to work something like a chatroom.
    session.send_event('global', ('oneliner', True))
Example #54
0
def acquire_node(session, name):
    nodes = get_ini('sesame', '{0}_nodes'.format(name), getter='getint')
    if not nodes:
        yield None
        return

    for node in range(1, nodes + 1):
        event = 'lock-{name}/{node}'.format(name=name, node=node)
        session.send_event(event, ('acquire', None))
        if session.read_event(event):
            yield node
            session.send_event(event, ('release', None))
            return

    # node could not be acquired
    yield -1
Example #55
0
def _get_fp(section_key, optional=False):
    """ Return filepath of [web] option by ``section_key``. """
    from x84.bbs import get_ini
    value = get_ini(section='web', key=section_key) or None
    if value:
        value = os.path.expanduser(value)
    elif optional:
        return None
    assert value is not None and os.path.isfile(value), (
        'Configuration section [web], key `{section_key}`, '
        'must {optional_exist}identify a path to an '
        'SSL {section_key} file. '
        '(value is {value})'.format(
            section_key=section_key,
            optional_exist=not optional and 'exist and ' or '',
            value=value))
    return value
Example #56
0
def parse_command_args(session, name, node):
    # Parse command path and arguments
    command = get_ini('sesame', name)
    if ' ' in command:
        command, args = command.split(' ', 1)
        args = args.format(
            session=session.to_dict(),
            system=dict(ini.CFG.items('system')),
            node=node,
        )
        args = shlex.split(args)
    else:
        args = []

    if not os.path.exists(command):
        raise RuntimeError("The door {0} specified a command path of "
                           "{1!r}, but no such file exists."
                           .format(name, command))

    return command, args
Example #57
0
def get_response(request_data):
    """
    Serve one API server request and return.
    """
    # todo: The caller runs a while loop .. this should be a script
    # that does a while loop and imports x84.webserve.

    from x84.bbs import DBProxy, get_ini
    log = logging.getLogger(__name__)

    # validate primary json request keys
    for key in (_key for _key in VALIDATE_FIELDS if _key not in request_data):
        return server_error(log_func=log.warn,
                            log_msg='Missing field, {key!r}'.format(key=key))

    # validate this server offers such message network
    server_tags = get_ini(section='msg',
                          key='server_tags',
                          split=True,
                          splitsep=',')

    if not request_data['network'] in server_tags:
        return server_error(log_func=log.warn,
                            log_msg=('[{data[network]}] not in server_tags '
                                     '({server_tags})'.format(
                                         data=request_data,
                                         server_tags=server_tags)),
                            http_msg=u'Server error')
    tag = request_data['network']

    # validate authentication token
    try:
        board_id, token, auth_tmval = parse_auth(request_data)
    except ValueError, err:
        return server_error(
            log_func=log.warn,
            log_msg=('[{data[network]}] Bad token: {err}'.format(
                data=request_data, err=err)),
            http_msg=u'Invalid token')
Example #58
0
import collections
import urlparse
import textwrap
import math
import sys

# local
from x84.bbs import getsession, getterminal, echo, LineEditor, get_ini

# 3rd-party
import feedparser
import html2text
import requests

#: fontset for SyncTerm emulator
SYNCTERM_FONT = get_ini(section='hackernews', key='syncterm_font') or 'topaz'

#: color of titlebars when viewing article summary
COLOR_MAIN = get_ini(section='hackernews', key='color_main') or 'black_on_red'

#: color of titlebars when viewing article
COLOR_VIEW = get_ini(section='hackernews',
                     key='color_view') or "black_on_magenta"

USER_AGENT = 'Lynx/2.8.7rel.2 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/1.0.0a'
RSS_URL = 'https://news.ycombinator.com/rss'
RSS_TITLE = 'Hacker News'
ARTICLE_LIMIT = 100
REQUEST_TIMEOUT = 10

#: structure defines an article